From c6847df0d994d8f9c6adb9ac58f70959731aea16 Mon Sep 17 00:00:00 2001 From: philo Date: Thu, 25 Jan 2024 14:50:39 +0800 Subject: [PATCH 1/2] Add new platform m2-w6510-48v Signed-off-by: philo --- ...atform-m2-w6510-48v-on-202305-branch.patch | 91701 ++++++++++++++++ .../M2-W6510-48V8C/hwsku.json | 172 + .../M2-W6510-48V8C/port_config.ini | 57 + .../M2-W6510-48V8C/sai.profile | 1 + ...d3-m2-w6510-48v8c-48x25G+8x100G.config.bcm | 605 + .../custom_led.bin | Bin 0 -> 236 bytes .../default_sku | 1 + .../x86_64-micas_m2-w6510-48v8c-r0/dev.xml | 420 + .../dev_exhaust.xml | 420 + .../x86_64-micas_m2-w6510-48v8c-r0/fru.py | 961 + .../x86_64-micas_m2-w6510-48v8c-r0/hwsku.json | 172 + .../installer.conf | 2 + .../led_proc_init.soc | 7 + .../media_settings.json | 2020 + .../x86_64-micas_m2-w6510-48v8c-r0/monitor.py | 402 + .../x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml | 440 + .../platform.json | 819 + .../platform_asic | 1 + .../platform_components.json | 37 + .../plugins/sfputil.py | 243 + .../plugins/ssd_util.py | 311 + .../pmon_daemon_control.json | 3 + .../system_health_monitoring_config.json | 0 platform/broadcom/one-image.mk | 1 + platform/broadcom/platform-modules-micas.dep | 9 + platform/broadcom/platform-modules-micas.mk | 10 + platform/broadcom/rules.dep | 1 + platform/broadcom/rules.mk | 1 + .../sonic-platform-modules-micas/LICENSE | 14 + .../common/Makefile | 41 + .../common/app/Makefile | 25 + .../common/app/dev_util/Makefile | 30 + .../common/app/dev_util/dfd_debug.c | 43 + .../common/app/dev_util/dfd_utest.c | 2121 + .../common/app/dev_util/dfd_utest.h | 109 + .../common/app/fw_upgrade/Makefile | 18 + .../common/app/fw_upgrade/Rules.mk | 42 + .../common/app/fw_upgrade/fw_upgrade/Makefile | 39 + .../app/fw_upgrade/fw_upgrade/fw_upgrade.c | 1632 + .../fw_upgrade/fw_upgrade/fw_upgrade_debug.c | 51 + .../fw_upgrade/include/fw_upgrade.h | 230 + .../fw_upgrade/include/fw_upgrade_debug.h | 25 + .../common/lib/algorithm/__init__.py | 0 .../common/lib/algorithm/hysteresis.py | 169 + .../common/lib/algorithm/openloop.py | 104 + .../common/lib/algorithm/pid.py | 106 + .../common/lib/eepromutil/__init__.py | 0 .../common/lib/eepromutil/cust_fru.py | 135 + .../common/lib/eepromutil/fantlv.py | 192 + .../common/lib/eepromutil/fru.py | 961 + .../common/lib/eepromutil/onietlv.py | 441 + .../common/lib/plat_hal/__init__.py | 0 .../common/lib/plat_hal/baseutil.py | 164 + .../common/lib/plat_hal/chassisbase.py | 318 + .../common/lib/plat_hal/component.py | 33 + .../common/lib/plat_hal/cpld.py | 66 + .../common/lib/plat_hal/cpu.py | 48 + .../common/lib/plat_hal/dcdc.py | 11 + .../common/lib/plat_hal/devicebase.py | 351 + .../common/lib/plat_hal/fan.py | 417 + .../common/lib/plat_hal/interface.py | 1334 + .../common/lib/plat_hal/led.py | 52 + .../common/lib/plat_hal/onie_e2.py | 127 + .../common/lib/plat_hal/osutil.py | 440 + .../common/lib/plat_hal/psu.py | 701 + .../common/lib/plat_hal/rotor.py | 149 + .../common/lib/plat_hal/sensor.py | 274 + .../common/lib/plat_hal/temp.py | 139 + .../common/lib/wbutil/__init__.py | 0 .../common/lib/wbutil/baseutil.py | 38 + .../common/lib/wbutil/smbus.py | 772 + .../kernel_drivers_blacklist.conf | 7 + .../common/modules/COPYING | 20 + .../common/modules/GPL-2.0 | 359 + .../common/modules/Makefile | 62 + .../common/modules/dfd_tlveeprom.c | 516 + .../common/modules/dfd_tlveeprom.h | 121 + .../common/modules/fpga_i2c.h | 133 + .../common/modules/hw_test.c | 608 + .../common/modules/hw_test.h | 31 + .../common/modules/intel_spi/Makefile | 22 + .../modules/intel_spi/include/intel_spi.h | 23 + .../common/modules/intel_spi/intel_spi.c | 966 + .../common/modules/intel_spi/intel_spi_pci.c | 106 + .../modules/intel_spi/intel_spi_platform.c | 168 + .../common/modules/linux-5.10/Makefile | 37 + .../common/modules/linux-5.10/wb_at24.c | 861 + .../common/modules/linux-5.10/wb_csu550.c | 236 + .../modules/linux-5.10/wb_i2c_algo_bit.c | 725 + .../common/modules/linux-5.10/wb_i2c_gpio.c | 431 + .../modules/linux-5.10/wb_i2c_gpio_device.c | 133 + .../common/modules/linux-5.10/wb_i2c_i801.c | 2114 + .../common/modules/linux-5.10/wb_i2c_ismt.c | 1105 + .../modules/linux-5.10/wb_i2c_mux_pca954x.c | 1332 + .../modules/linux-5.10/wb_i2c_mux_pca954x.h | 67 + .../modules/linux-5.10/wb_i2c_mux_pca9641.c | 1396 + .../modules/linux-5.10/wb_i2c_mux_pca9641.h | 64 + .../common/modules/linux-5.10/wb_ina3221.c | 1031 + .../common/modules/linux-5.10/wb_isl68137.c | 572 + .../common/modules/linux-5.10/wb_lm75.c | 992 + .../common/modules/linux-5.10/wb_lm75.h | 40 + .../common/modules/linux-5.10/wb_pmbus.h | 535 + .../common/modules/linux-5.10/wb_pmbus_core.c | 2780 + .../common/modules/linux-5.10/wb_tmp401.c | 1010 + .../common/modules/linux-5.10/wb_tps53622.c | 265 + .../common/modules/linux-5.10/wb_ucd9000.c | 676 + .../common/modules/linux-5.10/wb_xdpe12284.c | 495 + .../modules/linux-5.10/wb_xdpe132g5c_pmbus.c | 277 + .../common/modules/phy/Makefile | 23 + .../common/modules/phy/mdio_bitbang.c | 232 + .../common/modules/phy/mdio_gpio.c | 217 + .../common/modules/phy/wb_mdio_gpio_device.c | 110 + .../common/modules/pinctrl/Makefile | 17 + .../common/modules/pinctrl/core.h | 249 + .../common/modules/pinctrl/wb_gpio_c3000.c | 452 + .../modules/pinctrl/wb_gpio_c3000_device.c | 69 + .../common/modules/pinctrl/wb_pinctrl_intel.c | 1829 + .../common/modules/pinctrl/wb_pinctrl_intel.h | 275 + .../common/modules/plat_sysfs/Makefile | 20 + .../modules/plat_sysfs/dev_cfg/Makefile | 25 + .../modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c | 815 + .../plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c | 351 + .../plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c | 236 + .../plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c | 771 + .../plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c | 82 + .../plat_sysfs/dev_cfg/dfd_fan_driver.c | 201 + .../modules/plat_sysfs/dev_cfg/dfd_module.c | 95 + .../plat_sysfs/dev_cfg/dfd_psu_driver.c | 70 + .../plat_sysfs/dev_cfg/dfd_sensors_driver.c | 149 + .../plat_sysfs/dev_cfg/dfd_sff_driver.c | 56 + .../plat_sysfs/dev_cfg/dfd_slot_driver.c | 27 + .../plat_sysfs/dev_cfg/include/dfd_cfg.h | 99 + .../dev_cfg/include/dfd_cfg_adapter.h | 46 + .../plat_sysfs/dev_cfg/include/dfd_cfg_file.h | 37 + .../plat_sysfs/dev_cfg/include/dfd_cfg_info.h | 119 + .../dev_cfg/include/dfd_cfg_listnode.h | 30 + .../dev_cfg/include/dfd_fan_driver.h | 18 + .../plat_sysfs/dev_cfg/include/dfd_module.h | 96 + .../dev_cfg/include/dfd_psu_driver.h | 10 + .../dev_cfg/include/dfd_sensors_driver.h | 10 + .../dev_cfg/include/dfd_sff_driver.h | 8 + .../dev_cfg/include/dfd_slot_driver.h | 6 + .../modules/plat_sysfs/dev_sysfs/Makefile | 21 + .../dev_sysfs/include/plat_switch.h | 86 + .../dev_sysfs/include/sysfs_common.h | 90 + .../modules/plat_sysfs/dev_sysfs/plat_fan.c | 501 + .../modules/plat_sysfs/dev_sysfs/plat_psu.c | 426 + .../plat_sysfs/dev_sysfs/plat_sensor.c | 452 + .../modules/plat_sysfs/dev_sysfs/plat_sff.c | 287 + .../modules/plat_sysfs/dev_sysfs/plat_slot.c | 663 + .../plat_sysfs/dev_sysfs/plat_switch.c | 131 + .../common/modules/platform_common.h | 74 + .../common/modules/platform_common_module.c | 210 + .../common/modules/sdhci/Makefile | 18 + .../common/modules/sdhci/cqhci.h | 242 + .../common/modules/sdhci/sdhci-pci-arasan.c | 331 + .../common/modules/sdhci/sdhci-pci-core.c | 2566 + .../common/modules/sdhci/sdhci-pci-dwc-mshc.c | 84 + .../common/modules/sdhci/sdhci-pci-gli.c | 865 + .../common/modules/sdhci/sdhci-pci-o2micro.c | 862 + .../common/modules/sdhci/sdhci-pci.h | 203 + .../common/modules/sdhci/sdhci.h | 811 + .../common/modules/spi-bitbang-txrx.h | 107 + .../common/modules/wb_eeprom_93xx46.c | 558 + .../common/modules/wb_fpga_i2c_bus_drv.c | 1120 + .../common/modules/wb_fpga_pca954x_drv.c | 534 + .../common/modules/wb_fpga_pcie.c | 164 + .../common/modules/wb_gpio_d1500.c | 367 + .../common/modules/wb_gpio_device.c | 54 + .../common/modules/wb_i2c_dev.c | 815 + .../common/modules/wb_i2c_dev.h | 20 + .../common/modules/wb_i2c_ocores.c | 1143 + .../common/modules/wb_i2c_ocores.h | 28 + .../common/modules/wb_io_dev.c | 571 + .../common/modules/wb_io_dev.h | 21 + .../common/modules/wb_lpc_drv.c | 166 + .../common/modules/wb_lpc_drv.h | 18 + .../common/modules/wb_mac_bsc.c | 845 + .../common/modules/wb_optoe.c | 1192 + .../common/modules/wb_pcie_dev.c | 770 + .../common/modules/wb_pcie_dev.h | 26 + .../common/modules/wb_platform_i2c_dev.c | 749 + .../common/modules/wb_platform_i2c_dev.h | 19 + .../common/modules/wb_spi_93xx46.c | 111 + .../common/modules/wb_spi_dev.c | 684 + .../common/modules/wb_spi_dev.h | 17 + .../common/modules/wb_spi_gpio.c | 477 + .../common/modules/wb_spi_gpio_device.c | 163 + .../common/modules/wb_spi_nor_device.c | 87 + .../common/modules/wb_spi_ocores.c | 1025 + .../common/modules/wb_spi_ocores.h | 21 + .../common/modules/wb_uio_irq.c | 282 + .../common/modules/wb_wdt.c | 1187 + .../common/modules/wb_wdt.h | 53 + .../common/modules/wb_xdpe132g5c.c | 574 + .../common/script/auto_update.py | 196 + .../common/script/avscontrol.py | 203 + .../common/script/dev_monitor.py | 303 + .../common/script/drv_update.py | 152 + .../common/script/generate_airflow.py | 254 + .../common/script/hal_fanctrl.py | 1135 + .../common/script/hal_ledctrl.py | 830 + .../common/script/hal_pltfm.py | 492 + .../common/script/intelligent_monitor.py | 144 + .../script/intelligent_monitor/monitor_fan.py | 284 + .../common/script/platform_common.py | 186 + .../common/script/platform_config.py | 192 + .../common/script/platform_driver.py | 258 + .../common/script/platform_e2.py | 439 + .../common/script/platform_intf.py | 384 + .../common/script/platform_ipmi.py | 92 + .../common/script/platform_manufacturer.py | 562 + .../common/script/platform_process.py | 413 + .../common/script/platform_sensors.py | 272 + .../common/script/platform_test.py | 142 + .../common/script/platform_util.py | 838 + .../common/script/pmon_syslog.py | 519 + .../common/script/reboot_cause.py | 183 + .../common/script/reboot_ctrl.py | 150 + .../common/script/sensors | 8 + .../common/script/set_eth_mac.py | 274 + .../common/script/sfp_highest_temperatue.py | 148 + .../common/script/slot_monitor.py | 253 + .../common/script/ssdmon | 82 + .../common/script/tty_console.py | 91 + .../common/script/upgrade.py | 991 + .../common/script/warm_upgrade.py | 514 + .../common/service/platform_driver.service | 15 + .../common/service/platform_process.service | 16 + .../common/sonic_platform/__init__.py | 2 + .../common/sonic_platform/chassis.py | 530 + .../common/sonic_platform/component.py | 226 + .../common/sonic_platform/dcdc.py | 85 + .../common/sonic_platform/eeprom.py | 92 + .../common/sonic_platform/fan.py | 314 + .../common/sonic_platform/fan_drawer.py | 167 + .../common/sonic_platform/pcie.py | 21 + .../common/sonic_platform/platform.py | 24 + .../common/sonic_platform/psu.py | 359 + .../common/sonic_platform/sfp.py | 634 + .../common/sonic_platform/thermal.py | 234 + .../common/sonic_platform/watchdog.py | 236 + .../debian/changelog | 5 + .../debian/compat | 1 + .../debian/control | 9 + .../debian/copyright | 15 + ...tform-modules-micas-m2-w6510-48v8c.install | 1 + ...form-modules-micas-m2-w6510-48v8c.postinst | 10 + .../debian/rule.mk | 5 + .../sonic-platform-modules-micas/debian/rules | 92 + .../.upgrade_test/cpld_test_header.vme | Bin 0 -> 406 bytes .../.upgrade_test/fpga_test_header.bin | 10 + .../m2-w6510-48v8c/Makefile | 28 + .../x86_64_micas_m2_w6510_48v8c_r0_config.py | 1106 + ..._64_micas_m2_w6510_48v8c_r0_port_config.py | 7 + .../x86_64_micas_m2_w6510_48v8c_r0_device.py | 1371 + ..._micas_m2_w6510_48v8c_r0_exhaust_device.py | 1371 + .../x86_64_micas_m2_w6510_48v8c_r0_monitor.py | 206 + .../m2-w6510-48v8c/modules/driver/Makefile | 12 + .../modules/driver/wb_i2c_dev_device.c | 140 + .../driver/wb_i2c_mux_pca954x_device.c | 296 + .../modules/driver/wb_i2c_ocores_device.c | 423 + .../modules/driver/wb_io_dev_device.c | 103 + .../modules/driver/wb_lpc_drv_device.c | 130 + .../modules/driver/wb_pcie_dev_device.c | 93 + .../plat_sysfs_cfg/WB_PLAT_CPLD.cfg | 41 + .../plat_sysfs_cfg/WB_PLAT_FAN.cfg | 304 + .../plat_sysfs_cfg/WB_PLAT_PSU.cfg | 64 + .../plat_sysfs_cfg/WB_PLAT_SFF.cfg | 521 + .../plat_sysfs_cfg/cfg_file_name | 4 + .../m2-w6510-48v8c/setup.py | 39 + src/sonic-device-data/tests/permitted_list | 6 + 272 files changed, 181188 insertions(+) create mode 100644 0001-Add-new-platform-m2-w6510-48v-on-202305-branch.patch create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/hwsku.json create mode 100755 device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/port_config.ini create mode 100755 device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/sai.profile create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/custom_led.bin create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/default_sku create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev.xml create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev_exhaust.xml create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/fru.py create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/hwsku.json create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/installer.conf create mode 100755 device/micas/x86_64-micas_m2-w6510-48v8c-r0/led_proc_init.soc create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/media_settings.json create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/monitor.py create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform.json create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_asic create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_components.json create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/sfputil.py create mode 100755 device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/ssd_util.py create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/pmon_daemon_control.json create mode 100755 device/micas/x86_64-micas_m2-w6510-48v8c-r0/system_health_monitoring_config.json create mode 100644 platform/broadcom/platform-modules-micas.dep create mode 100644 platform/broadcom/platform-modules-micas.mk create mode 100644 platform/broadcom/sonic-platform-modules-micas/LICENSE create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_debug.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Rules.mk create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade_debug.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade_debug.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/__init__.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/hysteresis.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/openloop.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/pid.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/__init__.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/cust_fru.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fantlv.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fru.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/onietlv.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/__init__.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/baseutil.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/chassisbase.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/component.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpld.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpu.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/dcdc.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/devicebase.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/fan.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/interface.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/led.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/onie_e2.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/osutil.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/psu.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/rotor.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/sensor.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/temp.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/__init__.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/baseutil.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/smbus.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modprobe_conf/kernel_drivers_blacklist.conf create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/COPYING create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/GPL-2.0 create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/fpga_i2c.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/include/intel_spi.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_pci.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_platform.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_at24.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_csu550.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_algo_bit.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio_device.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_i801.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_ismt.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ina3221.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_isl68137.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus_core.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tmp401.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tps53622.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ucd9000.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe12284.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe132g5c_pmbus.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/phy/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_bitbang.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_gpio.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/phy/wb_mdio_gpio_device.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/core.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000_device.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_fan_driver.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_module.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_psu_driver.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sensors_driver.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sff_driver.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_slot_driver.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_adapter.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_file.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_info.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_listnode.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_fan_driver.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_module.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_psu_driver.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sensors_driver.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sff_driver.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_slot_driver.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/plat_switch.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/sysfs_common.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_fan.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_psu.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sensor.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sff.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_slot.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_switch.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common_module.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/cqhci.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-arasan.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-core.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-dwc-mshc.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-gli.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-o2micro.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/spi-bitbang-txrx.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_eeprom_93xx46.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_i2c_bus_drv.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pca954x_drv.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pcie.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_d1500.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_device.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mac_bsc.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_optoe.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_93xx46.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio_device.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_nor_device.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_uio_irq.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.h create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_xdpe132g5c.c create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/auto_update.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/avscontrol.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/dev_monitor.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/drv_update.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/generate_airflow.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/hal_fanctrl.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/hal_ledctrl.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/hal_pltfm.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor/monitor_fan.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_common.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_config.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_driver.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_e2.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_intf.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_ipmi.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_manufacturer.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_process.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_sensors.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_test.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_util.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/pmon_syslog.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/reboot_cause.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/reboot_ctrl.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/sensors create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/set_eth_mac.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/sfp_highest_temperatue.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/slot_monitor.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/ssdmon create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/tty_console.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/upgrade.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/warm_upgrade.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/service/platform_driver.service create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/service/platform_process.service create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/__init__.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/chassis.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/component.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/dcdc.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/eeprom.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan_drawer.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/pcie.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/platform.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/psu.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/sfp.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/thermal.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/watchdog.py create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/changelog create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/compat create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/control create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/copyright create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.install create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.postinst create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/rule.mk create mode 100755 platform/broadcom/sonic-platform-modules-micas/debian/rules create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/cpld_test_header.vme create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/fpga_test_header.bin create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/Makefile create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_config.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_port_config.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_device.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_exhaust_device.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_monitor.py create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_dev_device.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_mux_pca954x_device.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_ocores_device.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_io_dev_device.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_lpc_drv_device.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_pcie_dev_device.c create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_CPLD.cfg create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_FAN.cfg create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_PSU.cfg create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_SFF.cfg create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/cfg_file_name create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/setup.py diff --git a/0001-Add-new-platform-m2-w6510-48v-on-202305-branch.patch b/0001-Add-new-platform-m2-w6510-48v-on-202305-branch.patch new file mode 100644 index 000000000000..24698e47beec --- /dev/null +++ b/0001-Add-new-platform-m2-w6510-48v-on-202305-branch.patch @@ -0,0 +1,91701 @@ +From ed74bb454407a5577bfe9c290527741ba48c4bf7 Mon Sep 17 00:00:00 2001 +From: philo +Date: Sun, 21 Jan 2024 19:25:16 -0800 +Subject: [PATCH] Add-new-platform-m2-w6510-48v-on-202305-branch + +Signed-off-by: philo +--- + .gitignore | 2 +- + .../M2-W6510-48V8C/hwsku.json | 172 + + .../M2-W6510-48V8C/port_config.ini | 57 + + .../M2-W6510-48V8C/sai.profile | 1 + + ...d3-m2-w6510-48v8c-48x25G+8x100G.config.bcm | 605 ++++ + .../custom_led.bin | Bin 0 -> 236 bytes + .../default_sku | 1 + + .../x86_64-micas_m2-w6510-48v8c-r0/dev.xml | 420 +++ + .../dev_exhaust.xml | 420 +++ + .../x86_64-micas_m2-w6510-48v8c-r0/fru.py | 961 ++++++ + .../x86_64-micas_m2-w6510-48v8c-r0/hwsku.json | 172 + + .../installer.conf | 2 + + .../led_proc_init.soc | 7 + + .../media_settings.json | 2020 ++++++++++++ + .../x86_64-micas_m2-w6510-48v8c-r0/monitor.py | 402 +++ + .../x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml | 440 +++ + .../platform.json | 819 +++++ + .../platform_asic | 1 + + .../platform_components.json | 37 + + .../plugins/sfputil.py | 243 ++ + .../plugins/ssd_util.py | 311 ++ + .../pmon_daemon_control.json | 3 + + .../system_health_monitoring_config.json | 0 + platform/broadcom/one-image.mk | 1 + + platform/broadcom/platform-modules-micas.dep | 9 + + platform/broadcom/platform-modules-micas.mk | 10 + + platform/broadcom/rules.dep | 1 + + platform/broadcom/rules.mk | 1 + + .../sonic-platform-modules-micas/LICENSE | 14 + + .../common/Makefile | 41 + + .../common/app/Makefile | 25 + + .../common/app/dev_util/Makefile | 30 + + .../common/app/dev_util/dfd_debug.c | 43 + + .../common/app/dev_util/dfd_utest.c | 2121 +++++++++++++ + .../common/app/dev_util/dfd_utest.h | 109 + + .../common/app/fw_upgrade/Makefile | 18 + + .../common/app/fw_upgrade/Rules.mk | 42 + + .../common/app/fw_upgrade/fw_upgrade/Makefile | 39 + + .../app/fw_upgrade/fw_upgrade/fw_upgrade.c | 1632 ++++++++++ + .../fw_upgrade/fw_upgrade/fw_upgrade_debug.c | 51 + + .../fw_upgrade/include/fw_upgrade.h | 230 ++ + .../fw_upgrade/include/fw_upgrade_debug.h | 25 + + .../common/lib/algorithm/__init__.py | 0 + .../common/lib/algorithm/hysteresis.py | 169 + + .../common/lib/algorithm/openloop.py | 104 + + .../common/lib/algorithm/pid.py | 106 + + .../common/lib/eepromutil/__init__.py | 0 + .../common/lib/eepromutil/cust_fru.py | 135 + + .../common/lib/eepromutil/fantlv.py | 192 ++ + .../common/lib/eepromutil/fru.py | 961 ++++++ + .../common/lib/eepromutil/onietlv.py | 441 +++ + .../common/lib/plat_hal/__init__.py | 0 + .../common/lib/plat_hal/baseutil.py | 164 + + .../common/lib/plat_hal/chassisbase.py | 318 ++ + .../common/lib/plat_hal/component.py | 33 + + .../common/lib/plat_hal/cpld.py | 66 + + .../common/lib/plat_hal/cpu.py | 48 + + .../common/lib/plat_hal/dcdc.py | 11 + + .../common/lib/plat_hal/devicebase.py | 351 +++ + .../common/lib/plat_hal/fan.py | 417 +++ + .../common/lib/plat_hal/interface.py | 1334 ++++++++ + .../common/lib/plat_hal/led.py | 52 + + .../common/lib/plat_hal/onie_e2.py | 127 + + .../common/lib/plat_hal/osutil.py | 440 +++ + .../common/lib/plat_hal/psu.py | 701 +++++ + .../common/lib/plat_hal/rotor.py | 149 + + .../common/lib/plat_hal/sensor.py | 274 ++ + .../common/lib/plat_hal/temp.py | 139 + + .../common/lib/wbutil/__init__.py | 0 + .../common/lib/wbutil/baseutil.py | 38 + + .../common/lib/wbutil/smbus.py | 772 +++++ + .../kernel_drivers_blacklist.conf | 7 + + .../common/modules/COPYING | 20 + + .../common/modules/GPL-2.0 | 359 +++ + .../common/modules/Makefile | 62 + + .../common/modules/dfd_tlveeprom.c | 516 +++ + .../common/modules/dfd_tlveeprom.h | 121 + + .../common/modules/fpga_i2c.h | 133 + + .../common/modules/hw_test.c | 608 ++++ + .../common/modules/hw_test.h | 31 + + .../common/modules/intel_spi/Makefile | 22 + + .../modules/intel_spi/include/intel_spi.h | 23 + + .../common/modules/intel_spi/intel_spi.c | 966 ++++++ + .../common/modules/intel_spi/intel_spi_pci.c | 106 + + .../modules/intel_spi/intel_spi_platform.c | 168 + + .../common/modules/linux-5.10/Makefile | 37 + + .../common/modules/linux-5.10/wb_at24.c | 861 +++++ + .../common/modules/linux-5.10/wb_csu550.c | 236 ++ + .../modules/linux-5.10/wb_i2c_algo_bit.c | 725 +++++ + .../common/modules/linux-5.10/wb_i2c_gpio.c | 431 +++ + .../modules/linux-5.10/wb_i2c_gpio_device.c | 133 + + .../common/modules/linux-5.10/wb_i2c_i801.c | 2114 +++++++++++++ + .../common/modules/linux-5.10/wb_i2c_ismt.c | 1105 +++++++ + .../modules/linux-5.10/wb_i2c_mux_pca954x.c | 1332 ++++++++ + .../modules/linux-5.10/wb_i2c_mux_pca954x.h | 67 + + .../modules/linux-5.10/wb_i2c_mux_pca9641.c | 1396 +++++++++ + .../modules/linux-5.10/wb_i2c_mux_pca9641.h | 64 + + .../common/modules/linux-5.10/wb_ina3221.c | 1031 ++++++ + .../common/modules/linux-5.10/wb_isl68137.c | 572 ++++ + .../common/modules/linux-5.10/wb_lm75.c | 992 ++++++ + .../common/modules/linux-5.10/wb_lm75.h | 40 + + .../common/modules/linux-5.10/wb_pmbus.h | 535 ++++ + .../common/modules/linux-5.10/wb_pmbus_core.c | 2780 +++++++++++++++++ + .../common/modules/linux-5.10/wb_tmp401.c | 1010 ++++++ + .../common/modules/linux-5.10/wb_tps53622.c | 265 ++ + .../common/modules/linux-5.10/wb_ucd9000.c | 676 ++++ + .../common/modules/linux-5.10/wb_xdpe12284.c | 495 +++ + .../modules/linux-5.10/wb_xdpe132g5c_pmbus.c | 277 ++ + .../common/modules/phy/Makefile | 23 + + .../common/modules/phy/mdio_bitbang.c | 232 ++ + .../common/modules/phy/mdio_gpio.c | 217 ++ + .../common/modules/phy/wb_mdio_gpio_device.c | 110 + + .../common/modules/pinctrl/Makefile | 17 + + .../common/modules/pinctrl/core.h | 249 ++ + .../common/modules/pinctrl/wb_gpio_c3000.c | 452 +++ + .../modules/pinctrl/wb_gpio_c3000_device.c | 69 + + .../common/modules/pinctrl/wb_pinctrl_intel.c | 1829 +++++++++++ + .../common/modules/pinctrl/wb_pinctrl_intel.h | 275 ++ + .../common/modules/plat_sysfs/Makefile | 20 + + .../modules/plat_sysfs/dev_cfg/Makefile | 25 + + .../modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c | 815 +++++ + .../plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c | 351 +++ + .../plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c | 236 ++ + .../plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c | 771 +++++ + .../plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c | 82 + + .../plat_sysfs/dev_cfg/dfd_fan_driver.c | 201 ++ + .../modules/plat_sysfs/dev_cfg/dfd_module.c | 95 + + .../plat_sysfs/dev_cfg/dfd_psu_driver.c | 70 + + .../plat_sysfs/dev_cfg/dfd_sensors_driver.c | 149 + + .../plat_sysfs/dev_cfg/dfd_sff_driver.c | 56 + + .../plat_sysfs/dev_cfg/dfd_slot_driver.c | 27 + + .../plat_sysfs/dev_cfg/include/dfd_cfg.h | 99 + + .../dev_cfg/include/dfd_cfg_adapter.h | 46 + + .../plat_sysfs/dev_cfg/include/dfd_cfg_file.h | 37 + + .../plat_sysfs/dev_cfg/include/dfd_cfg_info.h | 119 + + .../dev_cfg/include/dfd_cfg_listnode.h | 30 + + .../dev_cfg/include/dfd_fan_driver.h | 18 + + .../plat_sysfs/dev_cfg/include/dfd_module.h | 96 + + .../dev_cfg/include/dfd_psu_driver.h | 10 + + .../dev_cfg/include/dfd_sensors_driver.h | 10 + + .../dev_cfg/include/dfd_sff_driver.h | 8 + + .../dev_cfg/include/dfd_slot_driver.h | 6 + + .../modules/plat_sysfs/dev_sysfs/Makefile | 21 + + .../dev_sysfs/include/plat_switch.h | 86 + + .../dev_sysfs/include/sysfs_common.h | 90 + + .../modules/plat_sysfs/dev_sysfs/plat_fan.c | 501 +++ + .../modules/plat_sysfs/dev_sysfs/plat_psu.c | 426 +++ + .../plat_sysfs/dev_sysfs/plat_sensor.c | 452 +++ + .../modules/plat_sysfs/dev_sysfs/plat_sff.c | 287 ++ + .../modules/plat_sysfs/dev_sysfs/plat_slot.c | 663 ++++ + .../plat_sysfs/dev_sysfs/plat_switch.c | 131 + + .../common/modules/platform_common.h | 74 + + .../common/modules/platform_common_module.c | 210 ++ + .../common/modules/sdhci/Makefile | 18 + + .../common/modules/sdhci/cqhci.h | 242 ++ + .../common/modules/sdhci/sdhci-pci-arasan.c | 331 ++ + .../common/modules/sdhci/sdhci-pci-core.c | 2566 +++++++++++++++ + .../common/modules/sdhci/sdhci-pci-dwc-mshc.c | 84 + + .../common/modules/sdhci/sdhci-pci-gli.c | 865 +++++ + .../common/modules/sdhci/sdhci-pci-o2micro.c | 862 +++++ + .../common/modules/sdhci/sdhci-pci.h | 203 ++ + .../common/modules/sdhci/sdhci.h | 811 +++++ + .../common/modules/spi-bitbang-txrx.h | 107 + + .../common/modules/wb_eeprom_93xx46.c | 558 ++++ + .../common/modules/wb_fpga_i2c_bus_drv.c | 1120 +++++++ + .../common/modules/wb_fpga_pca954x_drv.c | 534 ++++ + .../common/modules/wb_fpga_pcie.c | 164 + + .../common/modules/wb_gpio_d1500.c | 367 +++ + .../common/modules/wb_gpio_device.c | 54 + + .../common/modules/wb_i2c_dev.c | 815 +++++ + .../common/modules/wb_i2c_dev.h | 20 + + .../common/modules/wb_i2c_ocores.c | 1143 +++++++ + .../common/modules/wb_i2c_ocores.h | 28 + + .../common/modules/wb_io_dev.c | 571 ++++ + .../common/modules/wb_io_dev.h | 21 + + .../common/modules/wb_lpc_drv.c | 166 + + .../common/modules/wb_lpc_drv.h | 18 + + .../common/modules/wb_mac_bsc.c | 845 +++++ + .../common/modules/wb_optoe.c | 1192 +++++++ + .../common/modules/wb_pcie_dev.c | 770 +++++ + .../common/modules/wb_pcie_dev.h | 26 + + .../common/modules/wb_platform_i2c_dev.c | 749 +++++ + .../common/modules/wb_platform_i2c_dev.h | 19 + + .../common/modules/wb_spi_93xx46.c | 111 + + .../common/modules/wb_spi_dev.c | 684 ++++ + .../common/modules/wb_spi_dev.h | 17 + + .../common/modules/wb_spi_gpio.c | 477 +++ + .../common/modules/wb_spi_gpio_device.c | 163 + + .../common/modules/wb_spi_nor_device.c | 87 + + .../common/modules/wb_spi_ocores.c | 1025 ++++++ + .../common/modules/wb_spi_ocores.h | 21 + + .../common/modules/wb_uio_irq.c | 282 ++ + .../common/modules/wb_wdt.c | 1187 +++++++ + .../common/modules/wb_wdt.h | 53 + + .../common/modules/wb_xdpe132g5c.c | 574 ++++ + .../common/script/auto_update.py | 196 ++ + .../common/script/avscontrol.py | 203 ++ + .../common/script/dev_monitor.py | 303 ++ + .../common/script/drv_update.py | 152 + + .../common/script/generate_airflow.py | 254 ++ + .../common/script/hal_fanctrl.py | 1135 +++++++ + .../common/script/hal_ledctrl.py | 830 +++++ + .../common/script/hal_pltfm.py | 492 +++ + .../common/script/intelligent_monitor.py | 144 + + .../script/intelligent_monitor/monitor_fan.py | 284 ++ + .../common/script/platform_common.py | 186 ++ + .../common/script/platform_config.py | 192 ++ + .../common/script/platform_driver.py | 258 ++ + .../common/script/platform_e2.py | 439 +++ + .../common/script/platform_intf.py | 384 +++ + .../common/script/platform_ipmi.py | 92 + + .../common/script/platform_manufacturer.py | 562 ++++ + .../common/script/platform_process.py | 413 +++ + .../common/script/platform_sensors.py | 272 ++ + .../common/script/platform_test.py | 142 + + .../common/script/platform_util.py | 838 +++++ + .../common/script/pmon_syslog.py | 519 +++ + .../common/script/reboot_cause.py | 183 ++ + .../common/script/reboot_ctrl.py | 150 + + .../common/script/sensors | 8 + + .../common/script/set_eth_mac.py | 274 ++ + .../common/script/sfp_highest_temperatue.py | 148 + + .../common/script/slot_monitor.py | 253 ++ + .../common/script/ssdmon | 82 + + .../common/script/tty_console.py | 91 + + .../common/script/upgrade.py | 991 ++++++ + .../common/script/warm_upgrade.py | 514 +++ + .../common/service/platform_driver.service | 15 + + .../common/service/platform_process.service | 16 + + .../common/sonic_platform/__init__.py | 2 + + .../common/sonic_platform/chassis.py | 530 ++++ + .../common/sonic_platform/component.py | 226 ++ + .../common/sonic_platform/dcdc.py | 85 + + .../common/sonic_platform/eeprom.py | 92 + + .../common/sonic_platform/fan.py | 314 ++ + .../common/sonic_platform/fan_drawer.py | 167 + + .../common/sonic_platform/pcie.py | 21 + + .../common/sonic_platform/platform.py | 24 + + .../common/sonic_platform/psu.py | 359 +++ + .../common/sonic_platform/sfp.py | 634 ++++ + .../common/sonic_platform/thermal.py | 234 ++ + .../common/sonic_platform/watchdog.py | 236 ++ + .../debian/changelog | 5 + + .../debian/compat | 1 + + .../debian/control | 9 + + .../debian/copyright | 15 + + ...tform-modules-micas-m2-w6510-48v8c.install | 1 + + ...form-modules-micas-m2-w6510-48v8c.postinst | 10 + + .../debian/rule.mk | 5 + + .../sonic-platform-modules-micas/debian/rules | 92 + + .../.upgrade_test/cpld_test_header.vme | Bin 0 -> 406 bytes + .../.upgrade_test/fpga_test_header.bin | 10 + + .../m2-w6510-48v8c/Makefile | 28 + + .../x86_64_micas_m2_w6510_48v8c_r0_config.py | 1106 +++++++ + ..._64_micas_m2_w6510_48v8c_r0_port_config.py | 7 + + .../x86_64_micas_m2_w6510_48v8c_r0_device.py | 1371 ++++++++ + ..._micas_m2_w6510_48v8c_r0_exhaust_device.py | 1371 ++++++++ + .../x86_64_micas_m2_w6510_48v8c_r0_monitor.py | 206 ++ + .../m2-w6510-48v8c/modules/driver/Makefile | 12 + + .../modules/driver/wb_i2c_dev_device.c | 140 + + .../driver/wb_i2c_mux_pca954x_device.c | 296 ++ + .../modules/driver/wb_i2c_ocores_device.c | 423 +++ + .../modules/driver/wb_io_dev_device.c | 103 + + .../modules/driver/wb_lpc_drv_device.c | 130 + + .../modules/driver/wb_pcie_dev_device.c | 93 + + .../plat_sysfs_cfg/WB_PLAT_CPLD.cfg | 41 + + .../plat_sysfs_cfg/WB_PLAT_FAN.cfg | 304 ++ + .../plat_sysfs_cfg/WB_PLAT_PSU.cfg | 64 + + .../plat_sysfs_cfg/WB_PLAT_SFF.cfg | 521 +++ + .../plat_sysfs_cfg/cfg_file_name | 4 + + .../m2-w6510-48v8c/setup.py | 39 + + src/sonic-device-data/tests/permitted_list | 6 + + 272 files changed, 89488 insertions(+), 1 deletion(-) + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/hwsku.json + create mode 100755 device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/port_config.ini + create mode 100755 device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/sai.profile + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/custom_led.bin + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/default_sku + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev.xml + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev_exhaust.xml + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/fru.py + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/hwsku.json + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/installer.conf + create mode 100755 device/micas/x86_64-micas_m2-w6510-48v8c-r0/led_proc_init.soc + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/media_settings.json + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/monitor.py + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform.json + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_asic + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_components.json + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/sfputil.py + create mode 100755 device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/ssd_util.py + create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/pmon_daemon_control.json + create mode 100755 device/micas/x86_64-micas_m2-w6510-48v8c-r0/system_health_monitoring_config.json + create mode 100644 platform/broadcom/platform-modules-micas.dep + create mode 100644 platform/broadcom/platform-modules-micas.mk + create mode 100644 platform/broadcom/sonic-platform-modules-micas/LICENSE + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/Makefile + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/Makefile + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/Makefile + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_debug.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Makefile + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Rules.mk + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/Makefile + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade_debug.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade_debug.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/__init__.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/hysteresis.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/openloop.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/pid.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/__init__.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/cust_fru.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fantlv.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fru.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/onietlv.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/__init__.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/baseutil.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/chassisbase.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/component.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpld.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpu.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/dcdc.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/devicebase.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/fan.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/interface.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/led.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/onie_e2.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/osutil.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/psu.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/rotor.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/sensor.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/temp.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/__init__.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/baseutil.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/smbus.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modprobe_conf/kernel_drivers_blacklist.conf + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/COPYING + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/GPL-2.0 + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/Makefile + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/fpga_i2c.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/Makefile + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/include/intel_spi.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_pci.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_platform.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/Makefile + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_at24.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_csu550.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_algo_bit.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio_device.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_i801.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_ismt.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ina3221.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_isl68137.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus_core.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tmp401.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tps53622.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ucd9000.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe12284.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe132g5c_pmbus.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/phy/Makefile + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_bitbang.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_gpio.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/phy/wb_mdio_gpio_device.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/Makefile + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/core.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000_device.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/Makefile + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/Makefile + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_fan_driver.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_module.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_psu_driver.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sensors_driver.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sff_driver.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_slot_driver.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_adapter.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_file.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_info.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_listnode.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_fan_driver.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_module.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_psu_driver.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sensors_driver.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sff_driver.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_slot_driver.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/Makefile + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/plat_switch.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/sysfs_common.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_fan.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_psu.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sensor.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sff.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_slot.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_switch.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common_module.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/Makefile + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/cqhci.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-arasan.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-core.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-dwc-mshc.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-gli.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-o2micro.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/spi-bitbang-txrx.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_eeprom_93xx46.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_i2c_bus_drv.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pca954x_drv.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pcie.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_d1500.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_device.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mac_bsc.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_optoe.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_93xx46.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio_device.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_nor_device.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_uio_irq.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.h + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_xdpe132g5c.c + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/auto_update.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/avscontrol.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/dev_monitor.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/drv_update.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/generate_airflow.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/hal_fanctrl.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/hal_ledctrl.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/hal_pltfm.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor/monitor_fan.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_common.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_config.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_driver.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_e2.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_intf.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_ipmi.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_manufacturer.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_process.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_sensors.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_test.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_util.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/pmon_syslog.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/reboot_cause.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/reboot_ctrl.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/sensors + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/set_eth_mac.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/sfp_highest_temperatue.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/slot_monitor.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/ssdmon + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/tty_console.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/upgrade.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/warm_upgrade.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/service/platform_driver.service + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/service/platform_process.service + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/__init__.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/chassis.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/component.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/dcdc.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/eeprom.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan_drawer.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/pcie.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/platform.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/psu.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/sfp.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/thermal.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/watchdog.py + create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/changelog + create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/compat + create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/control + create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/copyright + create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.install + create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.postinst + create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/rule.mk + create mode 100755 platform/broadcom/sonic-platform-modules-micas/debian/rules + create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/cpld_test_header.vme + create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/fpga_test_header.bin + create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/Makefile + create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_config.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_port_config.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_device.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_exhaust_device.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_monitor.py + create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/Makefile + create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_dev_device.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_mux_pca954x_device.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_ocores_device.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_io_dev_device.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_lpc_drv_device.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_pcie_dev_device.c + create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_CPLD.cfg + create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_FAN.cfg + create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_PSU.cfg + create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_SFF.cfg + create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/cfg_file_name + create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/setup.py + +diff --git a/.gitignore b/.gitignore +index 406b8038d..a23272e12 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -62,7 +62,7 @@ src/**/*.o + platform/**/*.egg-info + platform/**/*-none-any.whl + platform/**/.pybuild +-platform/**/debian/* ++#platform/**/debian/* + !platform/**/debian/control + !platform/**/debian/rules + !platform/**/debian/changelog +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/hwsku.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/hwsku.json +new file mode 100644 +index 000000000..9a5a4d2b6 +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/hwsku.json +@@ -0,0 +1,172 @@ ++{ ++ "interfaces": { ++ "Ethernet1": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet2": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet3": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet4": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet5": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet6": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet7": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet8": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet9": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet10": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet11": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet12": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet13": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet14": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet15": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet16": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet17": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet18": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet19": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet20": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet21": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet22": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet23": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet24": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet25": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet26": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet27": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet28": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet29": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet30": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet31": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet32": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet33": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet34": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet35": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet36": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet37": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet38": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet39": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet40": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet41": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet42": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet43": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet44": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet45": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet46": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet47": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet48": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet49": { ++ "default_brkout_mode": "1x100G" ++ }, ++ "Ethernet53": { ++ "default_brkout_mode": "1x100G" ++ }, ++ "Ethernet57": { ++ "default_brkout_mode": "1x100G" ++ }, ++ "Ethernet61": { ++ "default_brkout_mode": "1x100G" ++ }, ++ "Ethernet65": { ++ "default_brkout_mode": "1x100G" ++ }, ++ "Ethernet69": { ++ "default_brkout_mode": "1x100G" ++ }, ++ "Ethernet73": { ++ "default_brkout_mode": "1x100G" ++ }, ++ "Ethernet77": { ++ "default_brkout_mode": "1x100G" ++ } ++ } ++} +\ No newline at end of file +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/port_config.ini b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/port_config.ini +new file mode 100755 +index 000000000..57d6132aa +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/port_config.ini +@@ -0,0 +1,57 @@ ++# name lanes alias index speed admin_status ++Ethernet1 57 twentyfiveGigE0/1 1 25000 up ++Ethernet2 58 twentyfiveGigE0/2 2 25000 up ++Ethernet3 59 twentyfiveGigE0/3 3 25000 up ++Ethernet4 60 twentyfiveGigE0/4 4 25000 up ++Ethernet5 61 twentyfiveGigE0/5 5 25000 up ++Ethernet6 62 twentyfiveGigE0/6 6 25000 up ++Ethernet7 63 twentyfiveGigE0/7 7 25000 up ++Ethernet8 64 twentyfiveGigE0/8 8 25000 up ++Ethernet9 1 twentyfiveGigE0/9 9 25000 up ++Ethernet10 2 twentyfiveGigE0/10 10 25000 up ++Ethernet11 3 twentyfiveGigE0/11 11 25000 up ++Ethernet12 4 twentyfiveGigE0/12 12 25000 up ++Ethernet13 5 twentyfiveGigE0/13 13 25000 up ++Ethernet14 6 twentyfiveGigE0/14 14 25000 up ++Ethernet15 7 twentyfiveGigE0/15 15 25000 up ++Ethernet16 8 twentyfiveGigE0/16 16 25000 up ++Ethernet17 13 twentyfiveGigE0/17 17 25000 up ++Ethernet18 14 twentyfiveGigE0/18 18 25000 up ++Ethernet19 15 twentyfiveGigE0/19 19 25000 up ++Ethernet20 16 twentyfiveGigE0/20 20 25000 up ++Ethernet21 21 twentyfiveGigE0/21 21 25000 up ++Ethernet22 22 twentyfiveGigE0/22 22 25000 up ++Ethernet23 23 twentyfiveGigE0/23 23 25000 up ++Ethernet24 24 twentyfiveGigE0/24 24 25000 up ++Ethernet25 29 twentyfiveGigE0/25 25 25000 up ++Ethernet26 30 twentyfiveGigE0/26 26 25000 up ++Ethernet27 31 twentyfiveGigE0/27 27 25000 up ++Ethernet28 32 twentyfiveGigE0/28 28 25000 up ++Ethernet29 33 twentyfiveGigE0/29 29 25000 up ++Ethernet30 34 twentyfiveGigE0/30 30 25000 up ++Ethernet31 35 twentyfiveGigE0/31 31 25000 up ++Ethernet32 36 twentyfiveGigE0/32 32 25000 up ++Ethernet33 41 twentyfiveGigE0/33 33 25000 up ++Ethernet34 42 twentyfiveGigE0/34 34 25000 up ++Ethernet35 43 twentyfiveGigE0/35 35 25000 up ++Ethernet36 44 twentyfiveGigE0/36 36 25000 up ++Ethernet37 49 twentyfiveGigE0/37 37 25000 up ++Ethernet38 50 twentyfiveGigE0/38 38 25000 up ++Ethernet39 51 twentyfiveGigE0/39 39 25000 up ++Ethernet40 52 twentyfiveGigE0/40 40 25000 up ++Ethernet41 65 twentyfiveGigE0/41 41 25000 up ++Ethernet42 66 twentyfiveGigE0/42 42 25000 up ++Ethernet43 67 twentyfiveGigE0/43 43 25000 up ++Ethernet44 68 twentyfiveGigE0/44 44 25000 up ++Ethernet45 69 twentyfiveGigE0/45 45 25000 up ++Ethernet46 70 twentyfiveGigE0/46 46 25000 up ++Ethernet47 71 twentyfiveGigE0/47 47 25000 up ++Ethernet48 72 twentyfiveGigE0/48 48 25000 up ++Ethernet49 85,86,87,88 hundredGigE0/1 49 100000 up ++Ethernet53 77,78,79,80 hundredGigE0/2 50 100000 up ++Ethernet57 97,98,99,100 hundredGigE0/3 51 100000 up ++Ethernet61 93,94,95,96 hundredGigE0/4 52 100000 up ++Ethernet65 113,114,115,116 hundredGigE0/5 53 100000 up ++Ethernet69 105,106,107,108 hundredGigE0/6 54 100000 up ++Ethernet73 121,122,123,124 hundredGigE0/7 55 100000 up ++Ethernet77 125,126,127,128 hundredGigE0/8 56 100000 up +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/sai.profile b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/sai.profile +new file mode 100755 +index 000000000..9dffa1046 +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/sai.profile +@@ -0,0 +1 @@ ++SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm +new file mode 100644 +index 000000000..559a49f4c +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm +@@ -0,0 +1,605 @@ ++cancun_dir=/usr/share/sonic/platform/cancun/sdk_6.5.16/ ++l2_mem_entries=32768 ++l3_mem_entries=16384 ++l3_alpm_enable=2 ++ipv6_lpm_128b_enable=0x1 ++l2xmsg_mode=0 ++l3_max_ecmp_mode=1 ++svi_my_station_optimization=1 ++sai_nbr_bcast_ifp_optimized=2 ++sai_stats_support_mask=0x1 ++bcm_num_cos=8 ++bcm_stat_interval=2000000 ++cdma_timeout_usec=3000000 ++core_clock_frequency=1525 ++dpp_clock_ratio=2:3 ++help_cli_enable=1 ++ifp_inports_support_enable=1 ++#lpm_scaling_enable=1 ++max_vp_lags=0 ++mem_cache_enable=0 ++memlist_enable=1 ++miim_intr_enable=0 ++module_64ports=1 ++oversubscribe_mode=1 ++oversubscribe_mixed_sister_25_50_enable=1 ++parity_enable=1 ++parity_correction=1 ++pbmp_gport_stack.0=0x0000000000000000000000000000000000000000000000000000000000000000 ++#pbmp_xport_xe.0=0x00000000000000000000000000000000888ffffffffffff9fffffffffffffffe ++pbmp_xport_xe=0xffffffffffffffffffffffffffffffffffffffffe ++port_flex_enable=1 ++phy_chain_tx_lane_map_physical{57.0}=0x0123 ++phy_chain_tx_lane_map_physical{61.0}=0x0123 ++phy_chain_tx_lane_map_physical{1.0}=0x0123 ++phy_chain_tx_lane_map_physical{5.0}=0x0123 ++phy_chain_tx_lane_map_physical{13.0}=0x0123 ++phy_chain_tx_lane_map_physical{21.0}=0x0123 ++phy_chain_tx_lane_map_physical{29.0}=0x0123 ++phy_chain_tx_lane_map_physical{33.0}=0x0123 ++phy_chain_tx_lane_map_physical{41.0}=0x0123 ++phy_chain_tx_lane_map_physical{49.0}=0x0123 ++phy_chain_tx_lane_map_physical{65.0}=0x3210 ++phy_chain_tx_lane_map_physical{69.0}=0x3210 ++phy_chain_tx_lane_map_physical{85.0}=0x3210 ++phy_chain_tx_lane_map_physical{77.0}=0x0213 ++phy_chain_tx_lane_map_physical{97.0}=0x3210 ++phy_chain_tx_lane_map_physical{93.0}=0x0213 ++phy_chain_tx_lane_map_physical{113.0}=0x3210 ++phy_chain_tx_lane_map_physical{105.0}=0x0213 ++phy_chain_tx_lane_map_physical{121.0}=0x3120 ++phy_chain_tx_lane_map_physical{125.0}=0x1203 ++ ++phy_chain_rx_lane_map_physical{57.0}=0x1032 ++phy_chain_rx_lane_map_physical{61.0}=0x1032 ++phy_chain_rx_lane_map_physical{1.0}=0x1032 ++phy_chain_rx_lane_map_physical{5.0}=0x1032 ++phy_chain_rx_lane_map_physical{13.0}=0x1032 ++phy_chain_rx_lane_map_physical{21.0}=0x1032 ++phy_chain_rx_lane_map_physical{29.0}=0x1032 ++phy_chain_rx_lane_map_physical{33.0}=0x1032 ++phy_chain_rx_lane_map_physical{41.0}=0x1032 ++phy_chain_rx_lane_map_physical{49.0}=0x1032 ++phy_chain_rx_lane_map_physical{65.0}=0x2301 ++phy_chain_rx_lane_map_physical{69.0}=0x2301 ++phy_chain_rx_lane_map_physical{85.0}=0x1032 ++phy_chain_rx_lane_map_physical{77.0}=0x1032 ++phy_chain_rx_lane_map_physical{97.0}=0x1032 ++phy_chain_rx_lane_map_physical{93.0}=0x1032 ++phy_chain_rx_lane_map_physical{113.0}=0x1032 ++phy_chain_rx_lane_map_physical{105.0}=0x1032 ++phy_chain_rx_lane_map_physical{121.0}=0x2031 ++phy_chain_rx_lane_map_physical{125.0}=0x1023 ++ ++portmap_57=57:25 ++portmap_58=58:25 ++portmap_59=59:25 ++portmap_60=60:25 ++portmap_61=61:25 ++portmap_62=62:25 ++portmap_63=63:25 ++portmap_64=64:25 ++portmap_1=1:25 ++portmap_2=2:25 ++portmap_3=3:25 ++portmap_4=4:25 ++portmap_5=5:25 ++portmap_6=6:25 ++portmap_7=7:25 ++portmap_8=8:25 ++portmap_13=13:25 ++portmap_14=14:25 ++portmap_15=15:25 ++portmap_16=16:25 ++portmap_21=21:25 ++portmap_22=22:25 ++portmap_23=23:25 ++portmap_24=24:25 ++portmap_29=29:25 ++portmap_30=30:25 ++portmap_31=31:25 ++portmap_32=32:25 ++portmap_33=33:25 ++portmap_34=34:25 ++portmap_35=35:25 ++portmap_36=36:25 ++portmap_41=41:25 ++portmap_42=42:25 ++portmap_43=43:25 ++portmap_44=44:25 ++portmap_49=49:25 ++portmap_50=50:25 ++portmap_51=51:25 ++portmap_52=52:25 ++portmap_67=65:25 ++portmap_68=66:25 ++portmap_69=67:25 ++portmap_70=68:25 ++portmap_71=69:25 ++portmap_72=70:25 ++portmap_73=71:25 ++portmap_74=72:25 ++portmap_87=85:100 ++portmap_79=77:100 ++portmap_99=97:100 ++portmap_95=93:100 ++portmap_115=113:100 ++portmap_107=105:100 ++portmap_123=121:100 ++portmap_127=125:100 ++ ++dport_map_port_57=1 ++dport_map_port_58=2 ++dport_map_port_59=3 ++dport_map_port_60=4 ++dport_map_port_61=5 ++dport_map_port_62=6 ++dport_map_port_63=7 ++dport_map_port_64=8 ++dport_map_port_1=9 ++dport_map_port_2=10 ++dport_map_port_3=11 ++dport_map_port_4=12 ++dport_map_port_5=13 ++dport_map_port_6=14 ++dport_map_port_7=15 ++dport_map_port_8=16 ++dport_map_port_13=17 ++dport_map_port_14=18 ++dport_map_port_15=19 ++dport_map_port_16=20 ++dport_map_port_21=21 ++dport_map_port_22=22 ++dport_map_port_23=23 ++dport_map_port_24=24 ++dport_map_port_29=25 ++dport_map_port_30=26 ++dport_map_port_31=27 ++dport_map_port_32=28 ++dport_map_port_33=29 ++dport_map_port_34=30 ++dport_map_port_35=31 ++dport_map_port_36=32 ++dport_map_port_41=33 ++dport_map_port_42=34 ++dport_map_port_43=35 ++dport_map_port_44=36 ++dport_map_port_49=37 ++dport_map_port_50=38 ++dport_map_port_51=39 ++dport_map_port_52=40 ++dport_map_port_67=41 ++dport_map_port_68=42 ++dport_map_port_69=43 ++dport_map_port_70=44 ++dport_map_port_71=45 ++dport_map_port_72=46 ++dport_map_port_73=47 ++dport_map_port_74=48 ++dport_map_port_87=49 ++dport_map_port_79=50 ++dport_map_port_99=51 ++dport_map_port_95=52 ++dport_map_port_115=53 ++dport_map_port_107=54 ++dport_map_port_123=55 ++dport_map_port_127=56 ++ ++phy_chain_tx_polarity_flip_physical{57.0}=0x1 ++phy_chain_tx_polarity_flip_physical{58.0}=0x0 ++phy_chain_tx_polarity_flip_physical{59.0}=0x1 ++phy_chain_tx_polarity_flip_physical{60.0}=0x0 ++phy_chain_tx_polarity_flip_physical{61.0}=0x1 ++phy_chain_tx_polarity_flip_physical{62.0}=0x0 ++phy_chain_tx_polarity_flip_physical{63.0}=0x1 ++phy_chain_tx_polarity_flip_physical{64.0}=0x0 ++phy_chain_tx_polarity_flip_physical{1.0}=0x0 ++phy_chain_tx_polarity_flip_physical{2.0}=0x0 ++phy_chain_tx_polarity_flip_physical{3.0}=0x0 ++phy_chain_tx_polarity_flip_physical{4.0}=0x0 ++phy_chain_tx_polarity_flip_physical{5.0}=0x0 ++phy_chain_tx_polarity_flip_physical{6.0}=0x0 ++phy_chain_tx_polarity_flip_physical{7.0}=0x0 ++phy_chain_tx_polarity_flip_physical{8.0}=0x0 ++phy_chain_tx_polarity_flip_physical{13.0}=0x0 ++phy_chain_tx_polarity_flip_physical{14.0}=0x0 ++phy_chain_tx_polarity_flip_physical{15.0}=0x0 ++phy_chain_tx_polarity_flip_physical{16.0}=0x0 ++phy_chain_tx_polarity_flip_physical{21.0}=0x0 ++phy_chain_tx_polarity_flip_physical{22.0}=0x0 ++phy_chain_tx_polarity_flip_physical{23.0}=0x0 ++phy_chain_tx_polarity_flip_physical{24.0}=0x0 ++phy_chain_tx_polarity_flip_physical{29.0}=0x0 ++phy_chain_tx_polarity_flip_physical{30.0}=0x0 ++phy_chain_tx_polarity_flip_physical{31.0}=0x0 ++phy_chain_tx_polarity_flip_physical{32.0}=0x0 ++phy_chain_tx_polarity_flip_physical{33.0}=0x0 ++phy_chain_tx_polarity_flip_physical{34.0}=0x0 ++phy_chain_tx_polarity_flip_physical{35.0}=0x0 ++phy_chain_tx_polarity_flip_physical{36.0}=0x0 ++phy_chain_tx_polarity_flip_physical{41.0}=0x0 ++phy_chain_tx_polarity_flip_physical{42.0}=0x0 ++phy_chain_tx_polarity_flip_physical{43.0}=0x0 ++phy_chain_tx_polarity_flip_physical{44.0}=0x0 ++phy_chain_tx_polarity_flip_physical{49.0}=0x0 ++phy_chain_tx_polarity_flip_physical{50.0}=0x0 ++phy_chain_tx_polarity_flip_physical{51.0}=0x0 ++phy_chain_tx_polarity_flip_physical{52.0}=0x0 ++phy_chain_tx_polarity_flip_physical{65.0}=0x0 ++phy_chain_tx_polarity_flip_physical{66.0}=0x0 ++phy_chain_tx_polarity_flip_physical{67.0}=0x0 ++phy_chain_tx_polarity_flip_physical{68.0}=0x0 ++phy_chain_tx_polarity_flip_physical{69.0}=0x0 ++phy_chain_tx_polarity_flip_physical{70.0}=0x0 ++phy_chain_tx_polarity_flip_physical{71.0}=0x0 ++phy_chain_tx_polarity_flip_physical{72.0}=0x0 ++phy_chain_tx_polarity_flip_physical{85.0}=0x0 ++phy_chain_tx_polarity_flip_physical{86.0}=0x0 ++phy_chain_tx_polarity_flip_physical{87.0}=0x1 ++phy_chain_tx_polarity_flip_physical{88.0}=0x0 ++phy_chain_tx_polarity_flip_physical{77.0}=0x1 ++phy_chain_tx_polarity_flip_physical{78.0}=0x0 ++phy_chain_tx_polarity_flip_physical{79.0}=0x1 ++phy_chain_tx_polarity_flip_physical{80.0}=0x0 ++phy_chain_tx_polarity_flip_physical{97.0}=0x0 ++phy_chain_tx_polarity_flip_physical{98.0}=0x0 ++phy_chain_tx_polarity_flip_physical{99.0}=0x1 ++phy_chain_tx_polarity_flip_physical{100.0}=0x0 ++phy_chain_tx_polarity_flip_physical{93.0}=0x0 ++phy_chain_tx_polarity_flip_physical{94.0}=0x1 ++phy_chain_tx_polarity_flip_physical{95.0}=0x1 ++phy_chain_tx_polarity_flip_physical{96.0}=0x0 ++phy_chain_tx_polarity_flip_physical{113.0}=0x0 ++phy_chain_tx_polarity_flip_physical{114.0}=0x0 ++phy_chain_tx_polarity_flip_physical{115.0}=0x1 ++phy_chain_tx_polarity_flip_physical{116.0}=0x0 ++phy_chain_tx_polarity_flip_physical{105.0}=0x0 ++phy_chain_tx_polarity_flip_physical{106.0}=0x1 ++phy_chain_tx_polarity_flip_physical{107.0}=0x1 ++phy_chain_tx_polarity_flip_physical{108.0}=0x0 ++phy_chain_tx_polarity_flip_physical{121.0}=0x1 ++phy_chain_tx_polarity_flip_physical{122.0}=0x0 ++phy_chain_tx_polarity_flip_physical{123.0}=0x1 ++phy_chain_tx_polarity_flip_physical{124.0}=0x0 ++phy_chain_tx_polarity_flip_physical{125.0}=0x1 ++phy_chain_tx_polarity_flip_physical{126.0}=0x0 ++phy_chain_tx_polarity_flip_physical{127.0}=0x1 ++phy_chain_tx_polarity_flip_physical{128.0}=0x1 ++ ++phy_chain_rx_polarity_flip_physical{57.0}=0x0 ++phy_chain_rx_polarity_flip_physical{58.0}=0x0 ++phy_chain_rx_polarity_flip_physical{59.0}=0x0 ++phy_chain_rx_polarity_flip_physical{60.0}=0x0 ++phy_chain_rx_polarity_flip_physical{61.0}=0x1 ++phy_chain_rx_polarity_flip_physical{62.0}=0x1 ++phy_chain_rx_polarity_flip_physical{63.0}=0x1 ++phy_chain_rx_polarity_flip_physical{64.0}=0x1 ++phy_chain_rx_polarity_flip_physical{1.0}=0x1 ++phy_chain_rx_polarity_flip_physical{2.0}=0x1 ++phy_chain_rx_polarity_flip_physical{3.0}=0x1 ++phy_chain_rx_polarity_flip_physical{4.0}=0x1 ++phy_chain_rx_polarity_flip_physical{5.0}=0x0 ++phy_chain_rx_polarity_flip_physical{6.0}=0x0 ++phy_chain_rx_polarity_flip_physical{7.0}=0x0 ++phy_chain_rx_polarity_flip_physical{8.0}=0x0 ++phy_chain_rx_polarity_flip_physical{13.0}=0x0 ++phy_chain_rx_polarity_flip_physical{14.0}=0x0 ++phy_chain_rx_polarity_flip_physical{15.0}=0x0 ++phy_chain_rx_polarity_flip_physical{16.0}=0x0 ++phy_chain_rx_polarity_flip_physical{21.0}=0x0 ++phy_chain_rx_polarity_flip_physical{22.0}=0x0 ++phy_chain_rx_polarity_flip_physical{23.0}=0x0 ++phy_chain_rx_polarity_flip_physical{24.0}=0x0 ++phy_chain_rx_polarity_flip_physical{29.0}=0x0 ++phy_chain_rx_polarity_flip_physical{30.0}=0x1 ++phy_chain_rx_polarity_flip_physical{31.0}=0x0 ++phy_chain_rx_polarity_flip_physical{32.0}=0x0 ++phy_chain_rx_polarity_flip_physical{33.0}=0x1 ++phy_chain_rx_polarity_flip_physical{34.0}=0x1 ++phy_chain_rx_polarity_flip_physical{35.0}=0x1 ++phy_chain_rx_polarity_flip_physical{36.0}=0x1 ++phy_chain_rx_polarity_flip_physical{41.0}=0x1 ++phy_chain_rx_polarity_flip_physical{42.0}=0x1 ++phy_chain_rx_polarity_flip_physical{43.0}=0x1 ++phy_chain_rx_polarity_flip_physical{44.0}=0x1 ++phy_chain_rx_polarity_flip_physical{49.0}=0x1 ++phy_chain_rx_polarity_flip_physical{50.0}=0x1 ++phy_chain_rx_polarity_flip_physical{51.0}=0x1 ++phy_chain_rx_polarity_flip_physical{52.0}=0x1 ++phy_chain_rx_polarity_flip_physical{65.0}=0x1 ++phy_chain_rx_polarity_flip_physical{66.0}=0x1 ++phy_chain_rx_polarity_flip_physical{67.0}=0x1 ++phy_chain_rx_polarity_flip_physical{68.0}=0x1 ++phy_chain_rx_polarity_flip_physical{69.0}=0x0 ++phy_chain_rx_polarity_flip_physical{70.0}=0x0 ++phy_chain_rx_polarity_flip_physical{71.0}=0x0 ++phy_chain_rx_polarity_flip_physical{72.0}=0x0 ++phy_chain_rx_polarity_flip_physical{85.0}=0x1 ++phy_chain_rx_polarity_flip_physical{86.0}=0x1 ++phy_chain_rx_polarity_flip_physical{87.0}=0x1 ++phy_chain_rx_polarity_flip_physical{88.0}=0x1 ++phy_chain_rx_polarity_flip_physical{77.0}=0x0 ++phy_chain_rx_polarity_flip_physical{78.0}=0x0 ++phy_chain_rx_polarity_flip_physical{79.0}=0x0 ++phy_chain_rx_polarity_flip_physical{80.0}=0x0 ++phy_chain_rx_polarity_flip_physical{97.0}=0x0 ++phy_chain_rx_polarity_flip_physical{98.0}=0x0 ++phy_chain_rx_polarity_flip_physical{99.0}=0x0 ++phy_chain_rx_polarity_flip_physical{100.0}=0x0 ++phy_chain_rx_polarity_flip_physical{93.0}=0x0 ++phy_chain_rx_polarity_flip_physical{94.0}=0x0 ++phy_chain_rx_polarity_flip_physical{95.0}=0x0 ++phy_chain_rx_polarity_flip_physical{96.0}=0x0 ++phy_chain_rx_polarity_flip_physical{113.0}=0x1 ++phy_chain_rx_polarity_flip_physical{114.0}=0x1 ++phy_chain_rx_polarity_flip_physical{115.0}=0x1 ++phy_chain_rx_polarity_flip_physical{116.0}=0x1 ++phy_chain_rx_polarity_flip_physical{105.0}=0x0 ++phy_chain_rx_polarity_flip_physical{106.0}=0x0 ++phy_chain_rx_polarity_flip_physical{107.0}=0x0 ++phy_chain_rx_polarity_flip_physical{108.0}=0x0 ++phy_chain_rx_polarity_flip_physical{121.0}=0x1 ++phy_chain_rx_polarity_flip_physical{122.0}=0x1 ++phy_chain_rx_polarity_flip_physical{123.0}=0x0 ++phy_chain_rx_polarity_flip_physical{124.0}=0x1 ++phy_chain_rx_polarity_flip_physical{125.0}=0x1 ++phy_chain_rx_polarity_flip_physical{126.0}=0x0 ++phy_chain_rx_polarity_flip_physical{127.0}=0x0 ++phy_chain_rx_polarity_flip_physical{128.0}=0x0 ++ ++serdes_preemphasis_lane0_57=0x0f480d ++serdes_preemphasis_lane1_57=0x0f480d ++serdes_preemphasis_lane2_57=0x0f480d ++serdes_preemphasis_lane3_57=0x0f480d ++serdes_preemphasis_lane0_58=0x0f480d ++serdes_preemphasis_lane1_58=0x0f480d ++serdes_preemphasis_lane2_58=0x0f480d ++serdes_preemphasis_lane3_58=0x0f480d ++serdes_preemphasis_lane0_59=0x0f480d ++serdes_preemphasis_lane1_59=0x0f480d ++serdes_preemphasis_lane2_59=0x0f480d ++serdes_preemphasis_lane3_59=0x0f480d ++serdes_preemphasis_lane0_60=0x0f480d ++serdes_preemphasis_lane1_60=0x0f480d ++serdes_preemphasis_lane2_60=0x0f480d ++serdes_preemphasis_lane3_60=0x0f480d ++serdes_preemphasis_lane0_61=0x0f480d ++serdes_preemphasis_lane1_61=0x0f480d ++serdes_preemphasis_lane2_61=0x0f480d ++serdes_preemphasis_lane3_61=0x0f480d ++serdes_preemphasis_lane0_62=0x0f480d ++serdes_preemphasis_lane1_62=0x0f480d ++serdes_preemphasis_lane2_62=0x0f480d ++serdes_preemphasis_lane3_62=0x0f480d ++serdes_preemphasis_lane0_63=0x0f480d ++serdes_preemphasis_lane1_63=0x0f480d ++serdes_preemphasis_lane2_63=0x0f480d ++serdes_preemphasis_lane3_63=0x0f480d ++serdes_preemphasis_lane0_64=0x0f480d ++serdes_preemphasis_lane1_64=0x0f480d ++serdes_preemphasis_lane2_64=0x0f480d ++serdes_preemphasis_lane3_64=0x0f480d ++serdes_preemphasis_lane0_1=0x0f480d ++serdes_preemphasis_lane1_1=0x0f480d ++serdes_preemphasis_lane2_1=0x0f480d ++serdes_preemphasis_lane3_1=0x0f480d ++serdes_preemphasis_lane0_2=0x0d4b0c ++serdes_preemphasis_lane1_2=0x0d4b0c ++serdes_preemphasis_lane2_2=0x0d4b0c ++serdes_preemphasis_lane3_2=0x0d4b0c ++serdes_preemphasis_lane0_3=0x0f480d ++serdes_preemphasis_lane1_3=0x0f480d ++serdes_preemphasis_lane2_3=0x0f480d ++serdes_preemphasis_lane3_3=0x0f480d ++serdes_preemphasis_lane0_4=0x0d4b0c ++serdes_preemphasis_lane1_4=0x0d4b0c ++serdes_preemphasis_lane2_4=0x0d4b0c ++serdes_preemphasis_lane3_4=0x0d4b0c ++serdes_preemphasis_lane0_5=0x0f480d ++serdes_preemphasis_lane1_5=0x0f480d ++serdes_preemphasis_lane2_5=0x0f480d ++serdes_preemphasis_lane3_5=0x0f480d ++serdes_preemphasis_lane0_6=0x0d4b0c ++serdes_preemphasis_lane1_6=0x0d4b0c ++serdes_preemphasis_lane2_6=0x0d4b0c ++serdes_preemphasis_lane3_6=0x0d4b0c ++serdes_preemphasis_lane0_7=0x0f480d ++serdes_preemphasis_lane1_7=0x0f480d ++serdes_preemphasis_lane2_7=0x0f480d ++serdes_preemphasis_lane3_7=0x0f480d ++serdes_preemphasis_lane0_8=0x0d4b0c ++serdes_preemphasis_lane1_8=0x0d4b0c ++serdes_preemphasis_lane2_8=0x0d4b0c ++serdes_preemphasis_lane3_8=0x0d4b0c ++serdes_preemphasis_lane0_13=0x0f480d ++serdes_preemphasis_lane1_13=0x0f480d ++serdes_preemphasis_lane2_13=0x0f480d ++serdes_preemphasis_lane3_13=0x0f480d ++serdes_preemphasis_lane0_14=0x0d4b0c ++serdes_preemphasis_lane1_14=0x0d4b0c ++serdes_preemphasis_lane2_14=0x0d4b0c ++serdes_preemphasis_lane3_14=0x0d4b0c ++serdes_preemphasis_lane0_15=0x0f480d ++serdes_preemphasis_lane1_15=0x0f480d ++serdes_preemphasis_lane2_15=0x0f480d ++serdes_preemphasis_lane3_15=0x0f480d ++serdes_preemphasis_lane0_16=0x0d4b0c ++serdes_preemphasis_lane1_16=0x0d4b0c ++serdes_preemphasis_lane2_16=0x0d4b0c ++serdes_preemphasis_lane3_16=0x0d4b0c ++serdes_preemphasis_lane0_21=0x0d4b0c ++serdes_preemphasis_lane1_21=0x0d4b0c ++serdes_preemphasis_lane2_21=0x0d4b0c ++serdes_preemphasis_lane3_21=0x0d4b0c ++serdes_preemphasis_lane0_22=0x0d4b0c ++serdes_preemphasis_lane1_22=0x0d4b0c ++serdes_preemphasis_lane2_22=0x0d4b0c ++serdes_preemphasis_lane3_22=0x0d4b0c ++serdes_preemphasis_lane0_23=0x0d4b0c ++serdes_preemphasis_lane1_23=0x0d4b0c ++serdes_preemphasis_lane2_23=0x0d4b0c ++serdes_preemphasis_lane3_23=0x0d4b0c ++serdes_preemphasis_lane0_24=0x0d4b0c ++serdes_preemphasis_lane1_24=0x0d4b0c ++serdes_preemphasis_lane2_24=0x0d4b0c ++serdes_preemphasis_lane3_24=0x0d4b0c ++serdes_preemphasis_lane0_29=0x0d4b0c ++serdes_preemphasis_lane1_29=0x0d4b0c ++serdes_preemphasis_lane2_29=0x0d4b0c ++serdes_preemphasis_lane3_29=0x0d4b0c ++serdes_preemphasis_lane0_30=0x0d4b0c ++serdes_preemphasis_lane1_30=0x0d4b0c ++serdes_preemphasis_lane2_30=0x0d4b0c ++serdes_preemphasis_lane3_30=0x0d4b0c ++serdes_preemphasis_lane0_31=0x0d4b0c ++serdes_preemphasis_lane1_31=0x0d4b0c ++serdes_preemphasis_lane2_31=0x0d4b0c ++serdes_preemphasis_lane3_31=0x0d4b0c ++serdes_preemphasis_lane0_32=0x0d4b0c ++serdes_preemphasis_lane1_32=0x0d4b0c ++serdes_preemphasis_lane2_32=0x0d4b0c ++serdes_preemphasis_lane3_32=0x0d4b0c ++serdes_preemphasis_lane0_33=0x0d4b0c ++serdes_preemphasis_lane1_33=0x0d4b0c ++serdes_preemphasis_lane2_33=0x0d4b0c ++serdes_preemphasis_lane3_33=0x0d4b0c ++serdes_preemphasis_lane0_34=0x0d4b0c ++serdes_preemphasis_lane1_34=0x0d4b0c ++serdes_preemphasis_lane2_34=0x0d4b0c ++serdes_preemphasis_lane3_34=0x0d4b0c ++serdes_preemphasis_lane0_35=0x0d4b0c ++serdes_preemphasis_lane1_35=0x0d4b0c ++serdes_preemphasis_lane2_35=0x0d4b0c ++serdes_preemphasis_lane3_35=0x0d4b0c ++serdes_preemphasis_lane0_36=0x0d4b0c ++serdes_preemphasis_lane1_36=0x0d4b0c ++serdes_preemphasis_lane2_36=0x0d4b0c ++serdes_preemphasis_lane3_36=0x0d4b0c ++serdes_preemphasis_lane0_41=0x0d4b0c ++serdes_preemphasis_lane1_41=0x0d4b0c ++serdes_preemphasis_lane2_41=0x0d4b0c ++serdes_preemphasis_lane3_41=0x0d4b0c ++serdes_preemphasis_lane0_42=0x0d4b0c ++serdes_preemphasis_lane1_42=0x0d4b0c ++serdes_preemphasis_lane2_42=0x0d4b0c ++serdes_preemphasis_lane3_42=0x0d4b0c ++serdes_preemphasis_lane0_43=0x0d4b0c ++serdes_preemphasis_lane1_43=0x0d4b0c ++serdes_preemphasis_lane2_43=0x0d4b0c ++serdes_preemphasis_lane3_43=0x0d4b0c ++serdes_preemphasis_lane0_44=0x0d4b0c ++serdes_preemphasis_lane1_44=0x0d4b0c ++serdes_preemphasis_lane2_44=0x0d4b0c ++serdes_preemphasis_lane3_44=0x0d4b0c ++serdes_preemphasis_lane0_49=0x0f480d ++serdes_preemphasis_lane1_49=0x0f480d ++serdes_preemphasis_lane2_49=0x0f480d ++serdes_preemphasis_lane3_49=0x0f480d ++serdes_preemphasis_lane0_50=0x0d4b0c ++serdes_preemphasis_lane1_50=0x0d4b0c ++serdes_preemphasis_lane2_50=0x0d4b0c ++serdes_preemphasis_lane3_50=0x0d4b0c ++serdes_preemphasis_lane0_51=0x0f480d ++serdes_preemphasis_lane1_51=0x0f480d ++serdes_preemphasis_lane2_51=0x0f480d ++serdes_preemphasis_lane3_51=0x0f480d ++serdes_preemphasis_lane0_52=0x0d4b0c ++serdes_preemphasis_lane1_52=0x0d4b0c ++serdes_preemphasis_lane2_52=0x0d4b0c ++serdes_preemphasis_lane3_52=0x0d4b0c ++serdes_preemphasis_lane0_67=0x0d4b0c ++serdes_preemphasis_lane1_67=0x0d4b0c ++serdes_preemphasis_lane2_67=0x0d4b0c ++serdes_preemphasis_lane3_67=0x0d4b0c ++serdes_preemphasis_lane0_68=0x0d4b0c ++serdes_preemphasis_lane1_68=0x0d4b0c ++serdes_preemphasis_lane2_68=0x0d4b0c ++serdes_preemphasis_lane3_68=0x0d4b0c ++serdes_preemphasis_lane0_69=0x0d4b0c ++serdes_preemphasis_lane1_69=0x0d4b0c ++serdes_preemphasis_lane2_69=0x0d4b0c ++serdes_preemphasis_lane3_69=0x0d4b0c ++serdes_preemphasis_lane0_70=0x0d4b0c ++serdes_preemphasis_lane1_70=0x0d4b0c ++serdes_preemphasis_lane2_70=0x0d4b0c ++serdes_preemphasis_lane3_70=0x0d4b0c ++serdes_preemphasis_lane0_71=0x0d4b0c ++serdes_preemphasis_lane1_71=0x0d4b0c ++serdes_preemphasis_lane2_71=0x0d4b0c ++serdes_preemphasis_lane3_71=0x0d4b0c ++serdes_preemphasis_lane0_72=0x0d4b0c ++serdes_preemphasis_lane1_72=0x0d4b0c ++serdes_preemphasis_lane2_72=0x0d4b0c ++serdes_preemphasis_lane3_72=0x0d4b0c ++serdes_preemphasis_lane0_73=0x0d4b0c ++serdes_preemphasis_lane1_73=0x0d4b0c ++serdes_preemphasis_lane2_73=0x0d4b0c ++serdes_preemphasis_lane3_73=0x0d4b0c ++serdes_preemphasis_lane0_74=0x0d4b0c ++serdes_preemphasis_lane1_74=0x0d4b0c ++serdes_preemphasis_lane2_74=0x0d4b0c ++serdes_preemphasis_lane3_74=0x0d4b0c ++serdes_preemphasis_lane0_87=0x0d4b0c ++serdes_preemphasis_lane1_87=0x0d4b0c ++serdes_preemphasis_lane2_87=0x0d4b0c ++serdes_preemphasis_lane3_87=0x0d4b0c ++serdes_preemphasis_lane0_79=0x0d4b0c ++serdes_preemphasis_lane1_79=0x0d4b0c ++serdes_preemphasis_lane2_79=0x0d4b0c ++serdes_preemphasis_lane3_79=0x0d4b0c ++serdes_preemphasis_lane0_99=0x0d4b0c ++serdes_preemphasis_lane1_99=0x0d4b0c ++serdes_preemphasis_lane2_99=0x0d4b0c ++serdes_preemphasis_lane3_99=0x0d4b0c ++serdes_preemphasis_lane0_95=0x0d4b0c ++serdes_preemphasis_lane1_95=0x0d4b0c ++serdes_preemphasis_lane2_95=0x0d4b0c ++serdes_preemphasis_lane3_95=0x0d4b0c ++serdes_preemphasis_lane0_115=0x0d4b0c ++serdes_preemphasis_lane1_115=0x0d4b0c ++serdes_preemphasis_lane2_115=0x0d4b0c ++serdes_preemphasis_lane3_115=0x0d4b0c ++serdes_preemphasis_lane0_107=0x0d4b0c ++serdes_preemphasis_lane1_107=0x0d4b0c ++serdes_preemphasis_lane2_107=0x0d4b0c ++serdes_preemphasis_lane3_107=0x0d4b0c ++serdes_preemphasis_lane0_123=0x14460a ++serdes_preemphasis_lane1_123=0x14460a ++serdes_preemphasis_lane2_123=0x14460a ++serdes_preemphasis_lane3_123=0x14460a ++serdes_preemphasis_lane0_127=0x14460a ++serdes_preemphasis_lane1_127=0x14460a ++serdes_preemphasis_lane2_127=0x14460a ++serdes_preemphasis_lane3_127=0x14460a ++ ++ ++reglist_enable=1 ++scache_filename=/var/warmboot/wbscache ++schan_intr_enable=0 ++stable_size=0x55000000 ++stable_location=3 ++warmboot_knet_shutdown_mode=1 ++tdma_timeout_usec=3000000 ++ ++#vxlan flex flow mode ++flow_init_mode=1 ++ ++riot_enable=1 ++riot_overlay_l3_intf_mem_size=4096 ++riot_overlay_l3_egress_mem_size=32768 ++riot_overlay_ecmp_resilient_hash_size=16384 ++ ++l3_ecmp_levels=2 ++ ++use_all_splithorizon_groups=1 ++sai_tunnel_support=1 ++ ++#This property allows to enable L2 FDB entry to discard based on Source Mac ++sai_fdb_entry_l2_discard_src_enable=1 ++ ++#RDMA ++sai_pfc_defaults_disable=1 ++sai_optimized_mmu=1 ++ ++#ACL wb count ++ctr_evict_enable=0 +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/custom_led.bin b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/custom_led.bin +new file mode 100644 +index 0000000000000000000000000000000000000000..e02f94e7ed87ffe60524721f4aec68d661880e7c +GIT binary patch +literal 236 +zcmWN~%}N4M7=YpT%$NoC2ayV4HjWWfZN?-t`f=LVkf$CZeDzh_uF%kr>I`FYKD`eLmXf;U;{tHuD;Ze7>$f@av% +zgCSlz(c*=6Vg!#wxw@UXuqvtQF#P>drO^$pZE}t_Ju@=OS5eW|Q7?+4_%^r@%5rR&XfcQvT1^* ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev_exhaust.xml b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev_exhaust.xml +new file mode 100644 +index 000000000..86851af90 +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev_exhaust.xml +@@ -0,0 +1,420 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/fru.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/fru.py +new file mode 100644 +index 000000000..f95164e03 +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/fru.py +@@ -0,0 +1,961 @@ ++#!/usr/bin/python3 ++import collections ++from datetime import datetime, timedelta ++from bitarray import bitarray ++ ++ ++__DEBUG__ = "N" ++ ++ ++class FruException(Exception): ++ def __init__(self, message='fruerror', code=-100): ++ err = 'errcode: {0} message:{1}'.format(code, message) ++ Exception.__init__(self, err) ++ self.code = code ++ self.message = message ++ ++ ++def e_print(err): ++ print("ERROR: " + err) ++ ++ ++def d_print(debug_info): ++ if __DEBUG__ == "Y": ++ print(debug_info) ++ ++ ++class FruUtil(): ++ @staticmethod ++ def decodeLength(value): ++ a = bitarray(8) ++ a.setall(True) ++ a[0:1] = 0 ++ a[1:2] = 0 ++ x = ord(a.tobytes()) ++ return x & ord(value) ++ ++ @staticmethod ++ def minToData(): ++ starttime = datetime(1996, 1, 1, 0, 0, 0) ++ endtime = datetime.now() ++ seconds = (endtime - starttime).total_seconds() ++ mins = seconds // 60 ++ m = int(round(mins)) ++ return m ++ ++ @staticmethod ++ def getTimeFormat(): ++ return datetime.now().strftime('%Y-%m-%d') ++ ++ @staticmethod ++ def getTypeLength(value): ++ if value is None or len(value) == 0: ++ return 0 ++ a = bitarray(8) ++ a.setall(False) ++ a[0:1] = 1 ++ a[1:2] = 1 ++ x = ord(a.tobytes()) ++ return x | len(value) ++ ++ @staticmethod ++ def checksum(b): ++ result = 0 ++ for item in b: ++ result += ord(item) ++ return (0x100 - (result & 0xff)) & 0xff ++ ++ ++class BaseArea(object): ++ SUGGESTED_SIZE_COMMON_HEADER = 8 ++ SUGGESTED_SIZE_INTERNAL_USE_AREA = 72 ++ SUGGESTED_SIZE_CHASSIS_INFO_AREA = 32 ++ SUGGESTED_SIZE_BOARD_INFO_AREA = 80 ++ SUGGESTED_SIZE_PRODUCT_INFO_AREA = 80 ++ ++ INITVALUE = b'\x00' ++ resultvalue = INITVALUE * 256 ++ COMMON_HEAD_VERSION = b'\x01' ++ __childList = None ++ ++ def __init__(self, name="", size=0, offset=0): ++ self.__childList = [] ++ self._offset = offset ++ self.name = name ++ self._size = size ++ self._isPresent = False ++ self._data = b'\x00' * size ++ ++ @property ++ def childList(self): ++ return self.__childList ++ ++ @childList.setter ++ def childList(self, value): ++ self.__childList = value ++ ++ @property ++ def offset(self): ++ return self._offset ++ ++ @offset.setter ++ def offset(self, value): ++ self._offset = value ++ ++ @property ++ def size(self): ++ return self._size ++ ++ @size.setter ++ def size(self, value): ++ self._size = value ++ ++ @property ++ def data(self): ++ return self._data ++ ++ @data.setter ++ def data(self, value): ++ self._data = value ++ ++ @property ++ def isPresent(self): ++ return self._isPresent ++ ++ @isPresent.setter ++ def isPresent(self, value): ++ self._isPresent = value ++ ++ ++class InternalUseArea(BaseArea): ++ pass ++ ++ ++class ChassisInfoArea(BaseArea): ++ pass ++ ++ ++class BoardInfoArea(BaseArea): ++ _boardTime = None ++ _fields = None ++ _mfg_date = None ++ areaversion = None ++ _boardversion = None ++ _language = None ++ ++ def __str__(self): ++ formatstr = "version : %x\n" \ ++ "length : %d \n" \ ++ "language : %x \n" \ ++ "mfg_date : %s \n" \ ++ "boardManufacturer : %s \n" \ ++ "boardProductName : %s \n" \ ++ "boardSerialNumber : %s \n" \ ++ "boardPartNumber : %s \n" \ ++ "fruFileId : %s \n" ++ ++ tmpstr = formatstr % (ord(self.boardversion), self.size, ++ self.language, self.getMfgRealData(), ++ self.boardManufacturer, self.boardProductName, ++ self.boardSerialNumber, self.boardPartNumber, ++ self.fruFileId) ++ for i in range(1, 11): ++ valtmp = "boardextra%d" % i ++ if hasattr(self, valtmp): ++ valtmpval = getattr(self, valtmp) ++ tmpstr += "boardextra%d : %s \n" % (i, valtmpval) ++ else: ++ break ++ ++ return tmpstr ++ ++ def todict(self): ++ dic = collections.OrderedDict() ++ dic["boardversion"] = ord(self.boardversion) ++ dic["boardlength"] = self.size ++ dic["boardlanguage"] = self.language ++ dic["boardmfg_date"] = self.getMfgRealData() ++ dic["boardManufacturer"] = self.boardManufacturer ++ dic["boardProductName"] = self.boardProductName ++ dic["boardSerialNumber"] = self.boardSerialNumber ++ dic["boardPartNumber"] = self.boardPartNumber ++ dic["boardfruFileId"] = self.fruFileId ++ for i in range(1, 11): ++ valtmp = "boardextra%d" % i ++ if hasattr(self, valtmp): ++ valtmpval = getattr(self, valtmp) ++ dic[valtmp] = valtmpval ++ else: ++ break ++ return dic ++ ++ def decodedata(self): ++ index = 0 ++ self.areaversion = self.data[index] ++ index += 1 ++ d_print("decode length :%d class size:%d" % ++ ((ord(self.data[index]) * 8), self.size)) ++ index += 2 ++ ++ timetmp = self.data[index: index + 3] ++ self.mfg_date = ord(timetmp[0]) | ( ++ ord(timetmp[1]) << 8) | (ord(timetmp[2]) << 16) ++ d_print("decode getMfgRealData :%s" % self.getMfgRealData()) ++ index += 3 ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.boardManufacturer = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode boardManufacturer:%s" % self.boardManufacturer) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.boardProductName = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode boardProductName:%s" % self.boardProductName) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.boardSerialNumber = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode boardSerialNumber:%s" % self.boardSerialNumber) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.boardPartNumber = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode boardPartNumber:%s" % self.boardPartNumber) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.fruFileId = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode fruFileId:%s" % self.fruFileId) ++ ++ for i in range(1, 11): ++ valtmp = "boardextra%d" % i ++ if self.data[index] != chr(0xc1): ++ templen = FruUtil.decodeLength(self.data[index]) ++ tmpval = self.data[index + 1: index + templen + 1] ++ setattr(self, valtmp, tmpval) ++ index += templen + 1 ++ d_print("decode boardextra%d:%s" % (i, tmpval)) ++ else: ++ break ++ ++ def fruSetValue(self, field, value): ++ tmp_field = getattr(self, field, None) ++ if tmp_field is not None: ++ setattr(self, field, value) ++ ++ def recalcute(self): ++ d_print("boardInfoArea version:%x" % ord(self.boardversion)) ++ d_print("boardInfoArea length:%d" % self.size) ++ d_print("boardInfoArea language:%x" % self.language) ++ self.mfg_date = FruUtil.minToData() ++ d_print("boardInfoArea mfg_date:%x" % self.mfg_date) ++ ++ self.data = chr(ord(self.boardversion)) + \ ++ chr(self.size // 8) + chr(self.language) ++ ++ self.data += chr(self.mfg_date & 0xFF) ++ self.data += chr((self.mfg_date >> 8) & 0xFF) ++ self.data += chr((self.mfg_date >> 16) & 0xFF) ++ ++ d_print("boardInfoArea boardManufacturer:%s" % self.boardManufacturer) ++ typelength = FruUtil.getTypeLength(self.boardManufacturer) ++ self.data += chr(typelength) ++ self.data += self.boardManufacturer ++ ++ d_print("boardInfoArea boardProductName:%s" % self.boardProductName) ++ self.data += chr(FruUtil.getTypeLength(self.boardProductName)) ++ self.data += self.boardProductName ++ ++ d_print("boardInfoArea boardSerialNumber:%s" % self.boardSerialNumber) ++ self.data += chr(FruUtil.getTypeLength(self.boardSerialNumber)) ++ self.data += self.boardSerialNumber ++ ++ d_print("boardInfoArea boardPartNumber:%s" % self.boardPartNumber) ++ self.data += chr(FruUtil.getTypeLength(self.boardPartNumber)) ++ self.data += self.boardPartNumber ++ ++ d_print("boardInfoArea fruFileId:%s" % self.fruFileId) ++ self.data += chr(FruUtil.getTypeLength(self.fruFileId)) ++ self.data += self.fruFileId ++ ++ for i in range(1, 11): ++ valtmp = "boardextra%d" % i ++ if hasattr(self, valtmp): ++ valtmpval = getattr(self, valtmp) ++ d_print("boardInfoArea boardextra%d:%s" % (i, valtmpval)) ++ self.data += chr(FruUtil.getTypeLength(valtmpval)) ++ if valtmpval is not None: ++ self.data += valtmpval ++ else: ++ break ++ ++ self.data += chr(0xc1) ++ ++ if len(self.data) > (self.size - 1): ++ incr = (len(self.data) - self.size) // 8 + 1 ++ self.size += incr * 8 ++ ++ self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] ++ d_print("self data:%d" % len(self.data)) ++ d_print("self size:%d" % self.size) ++ d_print("adjust size:%d" % (self.size - len(self.data) - 1)) ++ self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) ++ ++ # checksum ++ checksum = FruUtil.checksum(self.data) ++ d_print("board info checksum:%x" % checksum) ++ self.data += chr(checksum) ++ ++ def getMfgRealData(self): ++ starttime = datetime(1996, 1, 1, 0, 0, 0) ++ mactime = starttime + timedelta(minutes=self.mfg_date) ++ return mactime ++ ++ @property ++ def language(self): ++ self._language = 25 ++ return self._language ++ ++ @property ++ def mfg_date(self): ++ return self._mfg_date ++ ++ @mfg_date.setter ++ def mfg_date(self, val): ++ self._mfg_date = val ++ ++ @property ++ def boardversion(self): ++ self._boardversion = self.COMMON_HEAD_VERSION ++ return self._boardversion ++ ++ @property ++ def fruFileId(self): ++ return self._FRUFileID ++ ++ @fruFileId.setter ++ def fruFileId(self, val): ++ self._FRUFileID = val ++ ++ @property ++ def boardPartNumber(self): ++ return self._boardPartNumber ++ ++ @boardPartNumber.setter ++ def boardPartNumber(self, val): ++ self._boardPartNumber = val ++ ++ @property ++ def boardSerialNumber(self): ++ return self._boardSerialNumber ++ ++ @boardSerialNumber.setter ++ def boardSerialNumber(self, val): ++ self._boardSerialNumber = val ++ ++ @property ++ def boardProductName(self): ++ return self._boradProductName ++ ++ @boardProductName.setter ++ def boardProductName(self, val): ++ self._boradProductName = val ++ ++ @property ++ def boardManufacturer(self): ++ return self._boardManufacturer ++ ++ @boardManufacturer.setter ++ def boardManufacturer(self, val): ++ self._boardManufacturer = val ++ ++ @property ++ def boardTime(self): ++ return self._boardTime ++ ++ @boardTime.setter ++ def boardTime(self, val): ++ self._boardTime = val ++ ++ @property ++ def fields(self): ++ return self._fields ++ ++ @fields.setter ++ def fields(self, val): ++ self._fields = val ++ ++ ++class ProductInfoArea(BaseArea): ++ _productManufacturer = None ++ _productAssetTag = None ++ _FRUFileID = None ++ _language = None ++ ++ def __str__(self): ++ formatstr = "version : %x\n" \ ++ "length : %d \n" \ ++ "language : %x \n" \ ++ "productManufacturer : %s \n" \ ++ "productName : %s \n" \ ++ "productPartModelName: %s \n" \ ++ "productVersion : %s \n" \ ++ "productSerialNumber : %s \n" \ ++ "productAssetTag : %s \n" \ ++ "fruFileId : %s \n" ++ ++ tmpstr = formatstr % (ord(self.areaversion), self.size, ++ self.language, self.productManufacturer, ++ self.productName, self.productPartModelName, ++ self.productVersion, self.productSerialNumber, ++ self.productAssetTag, self.fruFileId) ++ ++ for i in range(1, 11): ++ valtmp = "productextra%d" % i ++ if hasattr(self, valtmp): ++ valtmpval = getattr(self, valtmp) ++ tmpstr += "productextra%d : %s \n" % (i, valtmpval) ++ else: ++ break ++ ++ return tmpstr ++ ++ def todict(self): ++ dic = collections.OrderedDict() ++ dic["productversion"] = ord(self.areaversion) ++ dic["productlength"] = self.size ++ dic["productlanguage"] = self.language ++ dic["productManufacturer"] = self.productManufacturer ++ dic["productName"] = self.productName ++ dic["productPartModelName"] = self.productPartModelName ++ dic["productVersion"] = int(self.productVersion, 16) ++ dic["productSerialNumber"] = self.productSerialNumber ++ dic["productAssetTag"] = self.productAssetTag ++ dic["productfruFileId"] = self.fruFileId ++ for i in range(1, 11): ++ valtmp = "productextra%d" % i ++ if hasattr(self, valtmp): ++ valtmpval = getattr(self, valtmp) ++ dic[valtmp] = valtmpval ++ else: ++ break ++ return dic ++ ++ def decodedata(self): ++ index = 0 ++ self.areaversion = self.data[index] # 0 ++ index += 1 ++ d_print("decode length %d" % (ord(self.data[index]) * 8)) ++ d_print("class size %d" % self.size) ++ index += 2 ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.productManufacturer = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode productManufacturer:%s" % self.productManufacturer) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.productName = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode productName:%s" % self.productName) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.productPartModelName = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode productPartModelName:%s" % self.productPartModelName) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.productVersion = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode productVersion:%s" % self.productVersion) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.productSerialNumber = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode productSerialNumber:%s" % self.productSerialNumber) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.productAssetTag = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode productAssetTag:%s" % self.productAssetTag) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.fruFileId = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode fruFileId:%s" % self.fruFileId) ++ ++ for i in range(1, 11): ++ valtmp = "productextra%d" % i ++ if self.data[index] != chr(0xc1) and index < self.size - 1: ++ templen = FruUtil.decodeLength(self.data[index]) ++ if templen == 0: ++ break ++ tmpval = self.data[index + 1: index + templen + 1] ++ d_print("decode boardextra%d:%s" % (i, tmpval)) ++ setattr(self, valtmp, tmpval) ++ index += templen + 1 ++ else: ++ break ++ ++ @property ++ def productVersion(self): ++ return self._productVersion ++ ++ @productVersion.setter ++ def productVersion(self, name): ++ self._productVersion = name ++ ++ @property ++ def areaversion(self): ++ self._areaversion = self.COMMON_HEAD_VERSION ++ return self._areaversion ++ ++ @areaversion.setter ++ def areaversion(self, name): ++ self._areaversion = name ++ ++ @property ++ def language(self): ++ self._language = 25 ++ return self._language ++ ++ @property ++ def productManufacturer(self): ++ return self._productManufacturer ++ ++ @productManufacturer.setter ++ def productManufacturer(self, name): ++ self._productManufacturer = name ++ ++ @property ++ def productName(self): ++ return self._productName ++ ++ @productName.setter ++ def productName(self, name): ++ self._productName = name ++ ++ @property ++ def productPartModelName(self): ++ return self._productPartModelName ++ ++ @productPartModelName.setter ++ def productPartModelName(self, name): ++ self._productPartModelName = name ++ ++ @property ++ def productSerialNumber(self): ++ return self._productSerialNumber ++ ++ @productSerialNumber.setter ++ def productSerialNumber(self, name): ++ self._productSerialNumber = name ++ ++ @property ++ def productAssetTag(self): ++ return self._productAssetTag ++ ++ @productAssetTag.setter ++ def productAssetTag(self, name): ++ self._productAssetTag = name ++ ++ @property ++ def fruFileId(self): ++ return self._FRUFileID ++ ++ @fruFileId.setter ++ def fruFileId(self, name): ++ self._FRUFileID = name ++ ++ def fruSetValue(self, field, value): ++ tmp_field = getattr(self, field, None) ++ if tmp_field is not None: ++ setattr(self, field, value) ++ ++ def recalcute(self): ++ d_print("product version:%x" % ord(self.areaversion)) ++ d_print("product length:%d" % self.size) ++ d_print("product language:%x" % self.language) ++ self.data = chr(ord(self.areaversion)) + \ ++ chr(self.size // 8) + chr(self.language) ++ ++ typelength = FruUtil.getTypeLength(self.productManufacturer) ++ self.data += chr(typelength) ++ self.data += self.productManufacturer ++ ++ self.data += chr(FruUtil.getTypeLength(self.productName)) ++ self.data += self.productName ++ ++ self.data += chr(FruUtil.getTypeLength(self.productPartModelName)) ++ self.data += self.productPartModelName ++ ++ self.data += chr(FruUtil.getTypeLength(self.productVersion)) ++ self.data += self.productVersion ++ ++ self.data += chr(FruUtil.getTypeLength(self.productSerialNumber)) ++ self.data += self.productSerialNumber ++ ++ self.data += chr(FruUtil.getTypeLength(self.productAssetTag)) ++ if self.productAssetTag is not None: ++ self.data += self.productAssetTag ++ ++ self.data += chr(FruUtil.getTypeLength(self.fruFileId)) ++ self.data += self.fruFileId ++ ++ for i in range(1, 11): ++ valtmp = "productextra%d" % i ++ if hasattr(self, valtmp): ++ valtmpval = getattr(self, valtmp) ++ d_print("boardInfoArea productextra%d:%s" % (i, valtmpval)) ++ self.data += chr(FruUtil.getTypeLength(valtmpval)) ++ if valtmpval is not None: ++ self.data += valtmpval ++ else: ++ break ++ ++ self.data += chr(0xc1) ++ if len(self.data) > (self.size - 1): ++ incr = (len(self.data) - self.size) // 8 + 1 ++ self.size += incr * 8 ++ d_print("self.data:%d" % len(self.data)) ++ d_print("self.size:%d" % self.size) ++ ++ self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] ++ self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) ++ checksum = FruUtil.checksum(self.data) ++ d_print("board info checksum:%x" % checksum) ++ self.data += chr(checksum) ++ ++ ++class MultiRecordArea(BaseArea): ++ pass ++ ++ ++class Field(object): ++ ++ def __init__(self, fieldType="ASCII", fieldData=""): ++ self.fieldData = fieldData ++ self.fieldType = fieldType ++ ++ @property ++ def fieldType(self): ++ return self.fieldType ++ ++ @property ++ def fieldData(self): ++ return self.fieldData ++ ++ ++class ipmifru(BaseArea): ++ _BoardInfoArea = None ++ _ProductInfoArea = None ++ _InternalUseArea = None ++ _ChassisInfoArea = None ++ _multiRecordArea = None ++ _productinfoAreaOffset = BaseArea.INITVALUE ++ _boardInfoAreaOffset = BaseArea.INITVALUE ++ _internalUserAreaOffset = BaseArea.INITVALUE ++ _chassicInfoAreaOffset = BaseArea.INITVALUE ++ _multiRecordAreaOffset = BaseArea.INITVALUE ++ _bindata = None ++ _bodybin = None ++ _version = BaseArea.COMMON_HEAD_VERSION ++ _zeroCheckSum = None ++ _frusize = 256 ++ ++ def __str__(self): ++ tmpstr = "" ++ if self.boardInfoArea.isPresent: ++ tmpstr += "\nboardinfoarea: \n" ++ tmpstr += self.boardInfoArea.__str__() ++ if self.productInfoArea.isPresent: ++ tmpstr += "\nproductinfoarea: \n" ++ tmpstr += self.productInfoArea.__str__() ++ return tmpstr ++ ++ def decodeBin(self, eeprom): ++ commonHead = eeprom[0:8] ++ d_print("decode version %x" % ord(commonHead[0])) ++ if ord(self.COMMON_HEAD_VERSION) != ord(commonHead[0]): ++ raise FruException("HEAD VERSION error,not Fru format!", -10) ++ if FruUtil.checksum(commonHead[0:7]) != ord(commonHead[7]): ++ strtemp = "check header checksum error [cal:%02x data:%02x]" % ( ++ FruUtil.checksum(commonHead[0:7]), ord(commonHead[7])) ++ raise FruException(strtemp, -3) ++ if ord(commonHead[1]) != ord(self.INITVALUE): ++ d_print("Internal Use Area is present") ++ self.internalUseArea = InternalUseArea( ++ name="Internal Use Area", size=self.SUGGESTED_SIZE_INTERNAL_USE_AREA) ++ self.internalUseArea.isPresent = True ++ self.internalUserAreaOffset = ord(commonHead[1]) ++ self.internalUseArea.data = eeprom[self.internalUserAreaOffset * 8: ( ++ self.internalUserAreaOffset * 8 + self.internalUseArea.size)] ++ if ord(commonHead[2]) != ord(self.INITVALUE): ++ d_print("Chassis Info Area is present") ++ self.chassisInfoArea = ChassisInfoArea( ++ name="Chassis Info Area", size=self.SUGGESTED_SIZE_CHASSIS_INFO_AREA) ++ self.chassisInfoArea.isPresent = True ++ self.chassicInfoAreaOffset = ord(commonHead[2]) ++ self.chassisInfoArea.data = eeprom[self.chassicInfoAreaOffset * 8: ( ++ self.chassicInfoAreaOffset * 8 + self.chassisInfoArea.size)] ++ if ord(commonHead[3]) != ord(self.INITVALUE): ++ self.boardInfoArea = BoardInfoArea( ++ name="Board Info Area", size=self.SUGGESTED_SIZE_BOARD_INFO_AREA) ++ self.boardInfoArea.isPresent = True ++ self.boardInfoAreaOffset = ord(commonHead[3]) ++ self.boardInfoArea.size = ord( ++ eeprom[self.boardInfoAreaOffset * 8 + 1]) * 8 ++ d_print("Board Info Area is present size:%d" % ++ (self.boardInfoArea.size)) ++ self.boardInfoArea.data = eeprom[self.boardInfoAreaOffset * 8: ( ++ self.boardInfoAreaOffset * 8 + self.boardInfoArea.size)] ++ if FruUtil.checksum(self.boardInfoArea.data[:-1]) != ord(self.boardInfoArea.data[-1:]): ++ strtmp = "check boardInfoArea checksum error[cal:%02x data:%02x]" % \ ++ (FruUtil.checksum( ++ self.boardInfoArea.data[:-1]), ord(self.boardInfoArea.data[-1:])) ++ raise FruException(strtmp, -3) ++ self.boardInfoArea.decodedata() ++ if ord(commonHead[4]) != ord(self.INITVALUE): ++ d_print("Product Info Area is present") ++ self.productInfoArea = ProductInfoArea( ++ name="Product Info Area ", size=self.SUGGESTED_SIZE_PRODUCT_INFO_AREA) ++ self.productInfoArea.isPresent = True ++ self.productinfoAreaOffset = ord(commonHead[4]) ++ d_print("length offset value: %02x" % ++ ord(eeprom[self.productinfoAreaOffset * 8 + 1])) ++ self.productInfoArea.size = ord( ++ eeprom[self.productinfoAreaOffset * 8 + 1]) * 8 ++ d_print("Product Info Area is present size:%d" % ++ (self.productInfoArea.size)) ++ ++ self.productInfoArea.data = eeprom[self.productinfoAreaOffset * 8: ( ++ self.productinfoAreaOffset * 8 + self.productInfoArea.size)] ++ if FruUtil.checksum(self.productInfoArea.data[:-1]) != ord(self.productInfoArea.data[-1:]): ++ strtmp = "check productInfoArea checksum error [cal:%02x data:%02x]" % ( ++ FruUtil.checksum(self.productInfoArea.data[:-1]), ord(self.productInfoArea.data[-1:])) ++ raise FruException(strtmp, -3) ++ self.productInfoArea.decodedata() ++ if ord(commonHead[5]) != ord(self.INITVALUE): ++ self.multiRecordArea = MultiRecordArea( ++ name="MultiRecord record Area ") ++ d_print("MultiRecord record present") ++ self.multiRecordArea.isPresent = True ++ self.multiRecordAreaOffset = ord(commonHead[5]) ++ self.multiRecordArea.data = eeprom[self.multiRecordAreaOffset * 8: ( ++ self.multiRecordAreaOffset * 8 + self.multiRecordArea.size)] ++ ++ def initDefault(self): ++ self.version = self.COMMON_HEAD_VERSION ++ self.internalUserAreaOffset = self.INITVALUE ++ self.chassicInfoAreaOffset = self.INITVALUE ++ self.boardInfoAreaOffset = self.INITVALUE ++ self.productinfoAreaOffset = self.INITVALUE ++ self.multiRecordAreaOffset = self.INITVALUE ++ self.zeroCheckSum = self.INITVALUE ++ self.offset = self.SUGGESTED_SIZE_COMMON_HEADER ++ self.productInfoArea = None ++ self.internalUseArea = None ++ self.boardInfoArea = None ++ self.chassisInfoArea = None ++ self.multiRecordArea = None ++ # self.recalcute() ++ ++ @property ++ def version(self): ++ return self._version ++ ++ @version.setter ++ def version(self, name): ++ self._version = name ++ ++ @property ++ def internalUserAreaOffset(self): ++ return self._internalUserAreaOffset ++ ++ @internalUserAreaOffset.setter ++ def internalUserAreaOffset(self, obj): ++ self._internalUserAreaOffset = obj ++ ++ @property ++ def chassicInfoAreaOffset(self): ++ return self._chassicInfoAreaOffset ++ ++ @chassicInfoAreaOffset.setter ++ def chassicInfoAreaOffset(self, obj): ++ self._chassicInfoAreaOffset = obj ++ ++ @property ++ def productinfoAreaOffset(self): ++ return self._productinfoAreaOffset ++ ++ @productinfoAreaOffset.setter ++ def productinfoAreaOffset(self, obj): ++ self._productinfoAreaOffset = obj ++ ++ @property ++ def boardInfoAreaOffset(self): ++ return self._boardInfoAreaOffset ++ ++ @boardInfoAreaOffset.setter ++ def boardInfoAreaOffset(self, obj): ++ self._boardInfoAreaOffset = obj ++ ++ @property ++ def multiRecordAreaOffset(self): ++ return self._multiRecordAreaOffset ++ ++ @multiRecordAreaOffset.setter ++ def multiRecordAreaOffset(self, obj): ++ self._multiRecordAreaOffset = obj ++ ++ @property ++ def zeroCheckSum(self): ++ return self._zeroCheckSum ++ ++ @zeroCheckSum.setter ++ def zeroCheckSum(self, obj): ++ self._zeroCheckSum = obj ++ ++ @property ++ def productInfoArea(self): ++ return self._ProductInfoArea ++ ++ @productInfoArea.setter ++ def productInfoArea(self, obj): ++ self._ProductInfoArea = obj ++ ++ @property ++ def internalUseArea(self): ++ return self._InternalUseArea ++ ++ @internalUseArea.setter ++ def internalUseArea(self, obj): ++ self.internalUseArea = obj ++ ++ @property ++ def boardInfoArea(self): ++ return self._BoardInfoArea ++ ++ @boardInfoArea.setter ++ def boardInfoArea(self, obj): ++ self._BoardInfoArea = obj ++ ++ @property ++ def chassisInfoArea(self): ++ return self._ChassisInfoArea ++ ++ @chassisInfoArea.setter ++ def chassisInfoArea(self, obj): ++ self._ChassisInfoArea = obj ++ ++ @property ++ def multiRecordArea(self): ++ return self._multiRecordArea ++ ++ @multiRecordArea.setter ++ def multiRecordArea(self, obj): ++ self._multiRecordArea = obj ++ ++ @property ++ def bindata(self): ++ return self._bindata ++ ++ @bindata.setter ++ def bindata(self, obj): ++ self._bindata = obj ++ ++ @property ++ def bodybin(self): ++ return self._bodybin ++ ++ @bodybin.setter ++ def bodybin(self, obj): ++ self._bodybin = obj ++ ++ def recalcuteCommonHead(self): ++ self.bindata = "" ++ self.offset = self.SUGGESTED_SIZE_COMMON_HEADER ++ d_print("common Header %d" % self.offset) ++ d_print("fru eeprom size %d" % self._frusize) ++ if self.internalUseArea is not None and self.internalUseArea.isPresent: ++ self.internalUserAreaOffset = self.offset // 8 ++ self.offset += self.internalUseArea.size ++ d_print("internalUseArea is present offset:%d" % self.offset) ++ ++ if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: ++ self.chassicInfoAreaOffset = self.offset // 8 ++ self.offset += self.chassisInfoArea.size ++ d_print("chassisInfoArea is present offset:%d" % self.offset) ++ ++ if self.boardInfoArea is not None and self.boardInfoArea.isPresent: ++ self.boardInfoAreaOffset = self.offset // 8 ++ self.offset += self.boardInfoArea.size ++ d_print("boardInfoArea is present offset:%d" % self.offset) ++ d_print("boardInfoArea is present size:%d" % ++ self.boardInfoArea.size) ++ ++ if self.productInfoArea is not None and self.productInfoArea.isPresent: ++ self.productinfoAreaOffset = self.offset // 8 ++ self.offset += self.productInfoArea.size ++ d_print("productInfoArea is present offset:%d" % self.offset) ++ ++ if self.multiRecordArea is not None and self.multiRecordArea.isPresent: ++ self.multiRecordAreaOffset = self.offset // 8 ++ d_print("multiRecordArea is present offset:%d" % self.offset) ++ ++ if self.internalUserAreaOffset == self.INITVALUE: ++ self.internalUserAreaOffset = 0 ++ if self.productinfoAreaOffset == self.INITVALUE: ++ self.productinfoAreaOffset = 0 ++ if self.chassicInfoAreaOffset == self.INITVALUE: ++ self.chassicInfoAreaOffset = 0 ++ if self.boardInfoAreaOffset == self.INITVALUE: ++ self.boardInfoAreaOffset = 0 ++ if self.multiRecordAreaOffset == self.INITVALUE: ++ self.multiRecordAreaOffset = 0 ++ ++ self.zeroCheckSum = (0x100 - ord(self.version) - self.internalUserAreaOffset - self.chassicInfoAreaOffset - self.productinfoAreaOffset ++ - self.boardInfoAreaOffset - self.multiRecordAreaOffset) & 0xff ++ d_print("zerochecksum:%x" % self.zeroCheckSum) ++ self.data = "" ++ self.data += chr(self.version[0]) + chr(self.internalUserAreaOffset) + chr(self.chassicInfoAreaOffset) + chr( ++ self.boardInfoAreaOffset) + chr(self.productinfoAreaOffset) + chr(self.multiRecordAreaOffset) + chr(self.INITVALUE[0]) + chr(self.zeroCheckSum) ++ ++ self.bindata = self.data + self.bodybin ++ totallen = len(self.bindata) ++ d_print("totallen %d" % totallen) ++ if totallen < self._frusize: ++ self.bindata = self.bindata.ljust(self._frusize, chr(self.INITVALUE[0])) ++ else: ++ raise FruException('bin data more than %d' % self._frusize, -2) ++ ++ def recalcutebin(self): ++ self.bodybin = "" ++ if self.internalUseArea is not None and self.internalUseArea.isPresent: ++ d_print("internalUseArea present") ++ self.bodybin += self.internalUseArea.data ++ if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: ++ d_print("chassisInfoArea present") ++ self.bodybin += self.chassisInfoArea.data ++ if self.boardInfoArea is not None and self.boardInfoArea.isPresent: ++ d_print("boardInfoArea present") ++ self.boardInfoArea.recalcute() ++ self.bodybin += self.boardInfoArea.data ++ if self.productInfoArea is not None and self.productInfoArea.isPresent: ++ d_print("productInfoAreapresent") ++ self.productInfoArea.recalcute() ++ self.bodybin += self.productInfoArea.data ++ if self.multiRecordArea is not None and self.multiRecordArea.isPresent: ++ d_print("multiRecordArea present") ++ self.bodybin += self.productInfoArea.data ++ ++ def recalcute(self, fru_eeprom_size=256): ++ self._frusize = fru_eeprom_size ++ self.recalcutebin() ++ self.recalcuteCommonHead() ++ ++ def setValue(self, area, field, value): ++ tmp_area = getattr(self, area, None) ++ if tmp_area is not None: ++ tmp_area.fruSetValue(field, value) +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/hwsku.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/hwsku.json +new file mode 100644 +index 000000000..9a5a4d2b6 +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/hwsku.json +@@ -0,0 +1,172 @@ ++{ ++ "interfaces": { ++ "Ethernet1": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet2": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet3": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet4": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet5": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet6": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet7": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet8": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet9": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet10": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet11": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet12": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet13": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet14": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet15": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet16": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet17": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet18": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet19": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet20": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet21": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet22": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet23": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet24": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet25": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet26": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet27": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet28": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet29": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet30": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet31": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet32": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet33": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet34": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet35": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet36": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet37": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet38": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet39": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet40": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet41": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet42": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet43": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet44": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet45": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet46": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet47": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet48": { ++ "default_brkout_mode": "1x25G" ++ }, ++ "Ethernet49": { ++ "default_brkout_mode": "1x100G" ++ }, ++ "Ethernet53": { ++ "default_brkout_mode": "1x100G" ++ }, ++ "Ethernet57": { ++ "default_brkout_mode": "1x100G" ++ }, ++ "Ethernet61": { ++ "default_brkout_mode": "1x100G" ++ }, ++ "Ethernet65": { ++ "default_brkout_mode": "1x100G" ++ }, ++ "Ethernet69": { ++ "default_brkout_mode": "1x100G" ++ }, ++ "Ethernet73": { ++ "default_brkout_mode": "1x100G" ++ }, ++ "Ethernet77": { ++ "default_brkout_mode": "1x100G" ++ } ++ } ++} +\ No newline at end of file +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/installer.conf b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/installer.conf +new file mode 100644 +index 000000000..7a9fec8cc +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/installer.conf +@@ -0,0 +1,2 @@ ++CONSOLE_SPEED=115200 ++ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="intel_idle.max_cstate=0 idle=poll" +\ No newline at end of file +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/led_proc_init.soc b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/led_proc_init.soc +new file mode 100755 +index 000000000..59238f5cd +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/led_proc_init.soc +@@ -0,0 +1,7 @@ ++m0 load 0 0x3800 /usr/share/sonic/platform/custom_led.bin ++ ++led auto on ++ ++led start ++ ++linkscan SwPortBitMap=xe,ce +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/media_settings.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/media_settings.json +new file mode 100644 +index 000000000..e848307fd +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/media_settings.json +@@ -0,0 +1,2020 @@ ++{ ++ "PORT_MEDIA_SETTINGS": { ++ "49": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C", ++ "lane1": "0x0000000C", ++ "lane2": "0x0000000C", ++ "lane3": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B", ++ "lane1": "0x0000004B", ++ "lane2": "0x0000004B", ++ "lane3": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D", ++ "lane1": "0x0000000D", ++ "lane2": "0x0000000D", ++ "lane3": "0x0000000D" ++ } ++ }, ++ "QSFP+-": { ++ "pre1": { ++ "lane0": "0x00000000", ++ "lane1": "0x00000000", ++ "lane2": "0x00000000", ++ "lane3": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C", ++ "lane1": "0x0000003C", ++ "lane2": "0x0000003C", ++ "lane3": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004", ++ "lane1": "0x00000004", ++ "lane2": "0x00000004", ++ "lane3": "0x00000004" ++ } ++ } ++ }, ++ "50": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C", ++ "lane1": "0x0000000C", ++ "lane2": "0x0000000C", ++ "lane3": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B", ++ "lane1": "0x0000004B", ++ "lane2": "0x0000004B", ++ "lane3": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D", ++ "lane1": "0x0000000D", ++ "lane2": "0x0000000D", ++ "lane3": "0x0000000D" ++ } ++ }, ++ "QSFP+-": { ++ "pre1": { ++ "lane0": "0x00000000", ++ "lane1": "0x00000000", ++ "lane2": "0x00000000", ++ "lane3": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C", ++ "lane1": "0x0000003C", ++ "lane2": "0x0000003C", ++ "lane3": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004", ++ "lane1": "0x00000004", ++ "lane2": "0x00000004", ++ "lane3": "0x00000004" ++ } ++ } ++ }, ++ "51": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C", ++ "lane1": "0x0000000C", ++ "lane2": "0x0000000C", ++ "lane3": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B", ++ "lane1": "0x0000004B", ++ "lane2": "0x0000004B", ++ "lane3": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D", ++ "lane1": "0x0000000D", ++ "lane2": "0x0000000D", ++ "lane3": "0x0000000D" ++ } ++ }, ++ "QSFP+-": { ++ "pre1": { ++ "lane0": "0x00000000", ++ "lane1": "0x00000000", ++ "lane2": "0x00000000", ++ "lane3": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C", ++ "lane1": "0x0000003C", ++ "lane2": "0x0000003C", ++ "lane3": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004", ++ "lane1": "0x00000006", ++ "lane2": "0x00000006", ++ "lane3": "0x00000004" ++ } ++ } ++ }, ++ "52": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C", ++ "lane1": "0x0000000C", ++ "lane2": "0x0000000C", ++ "lane3": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B", ++ "lane1": "0x0000004B", ++ "lane2": "0x0000004B", ++ "lane3": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D", ++ "lane1": "0x0000000D", ++ "lane2": "0x0000000D", ++ "lane3": "0x0000000D" ++ } ++ }, ++ "QSFP+-": { ++ "pre1": { ++ "lane0": "0x00000000", ++ "lane1": "0x00000000", ++ "lane2": "0x00000000", ++ "lane3": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C", ++ "lane1": "0x0000003C", ++ "lane2": "0x0000003C", ++ "lane3": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004", ++ "lane1": "0x00000005", ++ "lane2": "0x00000005", ++ "lane3": "0x00000005" ++ } ++ } ++ }, ++ "53": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C", ++ "lane1": "0x0000000C", ++ "lane2": "0x0000000C", ++ "lane3": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B", ++ "lane1": "0x0000004B", ++ "lane2": "0x0000004B", ++ "lane3": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D", ++ "lane1": "0x0000000D", ++ "lane2": "0x0000000D", ++ "lane3": "0x0000000D" ++ } ++ }, ++ "QSFP+-": { ++ "pre1": { ++ "lane0": "0x00000000", ++ "lane1": "0x00000000", ++ "lane2": "0x00000000", ++ "lane3": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C", ++ "lane1": "0x0000003C", ++ "lane2": "0x0000003C", ++ "lane3": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004", ++ "lane1": "0x00000006", ++ "lane2": "0x00000006", ++ "lane3": "0x00000006" ++ } ++ } ++ }, ++ "54": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C", ++ "lane1": "0x0000000C", ++ "lane2": "0x0000000C", ++ "lane3": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B", ++ "lane1": "0x0000004B", ++ "lane2": "0x0000004B", ++ "lane3": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D", ++ "lane1": "0x0000000D", ++ "lane2": "0x0000000D", ++ "lane3": "0x0000000D" ++ } ++ }, ++ "QSFP+-": { ++ "pre1": { ++ "lane0": "0x00000000", ++ "lane1": "0x00000000", ++ "lane2": "0x00000000", ++ "lane3": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C", ++ "lane1": "0x0000003C", ++ "lane2": "0x0000003C", ++ "lane3": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000005", ++ "lane1": "0x00000005", ++ "lane2": "0x00000005", ++ "lane3": "0x00000005" ++ } ++ } ++ }, ++ "55": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000A", ++ "lane1": "0x0000000A", ++ "lane2": "0x0000000A", ++ "lane3": "0x0000000A" ++ }, ++ "main": { ++ "lane0": "0x00000046", ++ "lane1": "0x00000046", ++ "lane2": "0x00000046", ++ "lane3": "0x00000046" ++ }, ++ "post1": { ++ "lane0": "0x00000014", ++ "lane1": "0x00000014", ++ "lane2": "0x00000014", ++ "lane3": "0x00000014" ++ } ++ }, ++ "QSFP+-": { ++ "pre1": { ++ "lane0": "0x00000000", ++ "lane1": "0x00000000", ++ "lane2": "0x00000001", ++ "lane3": "0x00000001" ++ }, ++ "main": { ++ "lane0": "0x0000003C", ++ "lane1": "0x0000003C", ++ "lane2": "0x0000003C", ++ "lane3": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000006", ++ "lane1": "0x00000006", ++ "lane2": "0x00000006", ++ "lane3": "0x00000006" ++ } ++ } ++ }, ++ "56": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000A", ++ "lane1": "0x0000000A", ++ "lane2": "0x0000000A", ++ "lane3": "0x0000000A" ++ }, ++ "main": { ++ "lane0": "0x00000046", ++ "lane1": "0x00000046", ++ "lane2": "0x00000046", ++ "lane3": "0x00000046" ++ }, ++ "post1": { ++ "lane0": "0x00000014", ++ "lane1": "0x00000014", ++ "lane2": "0x00000014", ++ "lane3": "0x00000014" ++ } ++ }, ++ "QSFP+-": { ++ "pre1": { ++ "lane0": "0x00000000", ++ "lane1": "0x00000000", ++ "lane2": "0x00000000", ++ "lane3": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C", ++ "lane1": "0x0000003C", ++ "lane2": "0x0000003C", ++ "lane3": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000006", ++ "lane1": "0x00000006", ++ "lane2": "0x00000006", ++ "lane3": "0x00000006" ++ } ++ } ++ }, ++ "1": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000006" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "2": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000006" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "3": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000006" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "4": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000005" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "5": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000005" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "6": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000005" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "7": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000005" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "8": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "9": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "10": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "11": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "12": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "13": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "14": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "15": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "16": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "17": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "18": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "19": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "20": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "21": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "22": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "23": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "24": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000002" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "25": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "26": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000002" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "27": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "28": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000002" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "29": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "30": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000002" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "31": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "32": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "33": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "34": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "35": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "36": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "37": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "38": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "39": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000D" ++ }, ++ "main": { ++ "lane0": "0x00000048" ++ }, ++ "post1": { ++ "lane0": "0x0000000F" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "40": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "41": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "42": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "43": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "44": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "45": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "46": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "47": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ }, ++ "48": { ++ "Default": { ++ "pre1": { ++ "lane0": "0x0000000C" ++ }, ++ "main": { ++ "lane0": "0x0000004B" ++ }, ++ "post1": { ++ "lane0": "0x0000000D" ++ } ++ }, ++ "SFP-10G-": { ++ "pre1": { ++ "lane0": "0x00000000" ++ }, ++ "main": { ++ "lane0": "0x0000003C" ++ }, ++ "post1": { ++ "lane0": "0x00000004" ++ } ++ }, ++ "SFP-GB-": { ++ "pre1": { ++ "lane0": "0x00000002" ++ }, ++ "main": { ++ "lane0": "0x0000005F" ++ }, ++ "post1": { ++ "lane0": "0x00000003" ++ } ++ } ++ } ++ } ++} +\ No newline at end of file +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/monitor.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/monitor.py +new file mode 100644 +index 000000000..bdeaf190f +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/monitor.py +@@ -0,0 +1,402 @@ ++#!/usr/bin/python3 ++# * onboard temperature sensors ++# * FAN trays ++# * PSU ++# ++import os ++import xml.etree.ElementTree as ET ++import glob ++import json ++from decimal import Decimal ++from fru import ipmifru ++ ++ ++MAILBOX_DIR = "/sys/bus/i2c/devices/" ++BOARD_ID_PATH = "/sys/module/platform_common/parameters/dfd_my_type" ++BOARD_AIRFLOW_PATH = "/etc/sonic/.airflow" ++ ++ ++CONFIG_NAME = "dev.xml" ++ ++ ++def byteTostr(val): ++ strtmp = '' ++ for value in val: ++ strtmp += chr(value) ++ return strtmp ++ ++ ++def typeTostr(val): ++ if isinstance(val, bytes): ++ strtmp = byteTostr(val) ++ return strtmp ++ return val ++ ++ ++def get_board_id(): ++ if not os.path.exists(BOARD_ID_PATH): ++ return "NA" ++ with open(BOARD_ID_PATH) as fd: ++ id_str = fd.read().strip() ++ return "0x%x" % (int(id_str, 10)) ++ ++ ++def getboardairflow(): ++ if not os.path.exists(BOARD_AIRFLOW_PATH): ++ return "NA" ++ with open(BOARD_AIRFLOW_PATH) as fd: ++ airflow_str = fd.read().strip() ++ data = json.loads(airflow_str) ++ airflow = data.get("board", "NA") ++ return airflow ++ ++ ++boardid = get_board_id() ++boardairflow = getboardairflow() ++ ++ ++DEV_XML_FILE_LIST = [ ++ "dev_" + boardid + "_" + boardairflow + ".xml", ++ "dev_" + boardid + ".xml", ++ "dev_" + boardairflow + ".xml", ++] ++ ++ ++def dev_file_read(path, offset, read_len): ++ retval = "ERR" ++ val_list = [] ++ msg = "" ++ ret = "" ++ fd = -1 ++ ++ if not os.path.exists(path): ++ return False, "%s %s not found" % (retval, path) ++ ++ try: ++ fd = os.open(path, os.O_RDONLY) ++ os.lseek(fd, offset, os.SEEK_SET) ++ ret = os.read(fd, read_len) ++ for item in ret: ++ val_list.append(item) ++ except Exception as e: ++ msg = str(e) ++ return False, "%s %s" % (retval, msg) ++ finally: ++ if fd > 0: ++ os.close(fd) ++ return True, val_list ++ ++ ++def getPMCreg(location): ++ retval = 'ERR' ++ if not os.path.isfile(location): ++ return "%s %s notfound" % (retval, location) ++ try: ++ with open(location, 'r') as fd: ++ retval = fd.read() ++ except Exception as error: ++ return "ERR %s" % str(error) ++ ++ retval = retval.rstrip('\r\n') ++ retval = retval.lstrip(" ") ++ return retval ++ ++ ++# Get a mailbox register ++def get_pmc_register(reg_name): ++ retval = 'ERR' ++ mb_reg_file = reg_name ++ filepath = glob.glob(mb_reg_file) ++ if len(filepath) == 0: ++ return "%s %s notfound" % (retval, mb_reg_file) ++ mb_reg_file = filepath[0] ++ if not os.path.isfile(mb_reg_file): ++ # print mb_reg_file, 'not found !' ++ return "%s %s notfound" % (retval, mb_reg_file) ++ try: ++ with open(mb_reg_file, 'rb') as fd: ++ retval = fd.read() ++ retval = typeTostr(retval) ++ except Exception as error: ++ retval = "%s %s read failed, msg: %s" % (retval, mb_reg_file, str(error)) ++ ++ retval = retval.rstrip('\r\n') ++ retval = retval.lstrip(" ") ++ return retval ++ ++ ++class checktype(): ++ def __init__(self, test1): ++ self.test1 = test1 ++ ++ @staticmethod ++ def getValue(location, bit, data_type, coefficient=1, addend=0): ++ try: ++ value_t = get_pmc_register(location) ++ if value_t.startswith("ERR") or value_t.startswith("NA"): ++ return value_t ++ if data_type == 1: ++ return float('%.1f' % ((float(value_t) / 1000) + addend)) ++ if data_type == 2: ++ return float('%.1f' % (float(value_t) / 100)) ++ if data_type == 3: ++ psu_status = int(value_t, 16) ++ return (psu_status & (1 << bit)) >> bit ++ if data_type == 4: ++ return int(value_t, 10) ++ if data_type == 5: ++ return float('%.1f' % (float(value_t) / 1000 / 1000)) ++ if data_type == 6: ++ return Decimal(float(value_t) * coefficient / 1000).quantize(Decimal('0.000')) ++ return value_t ++ except Exception as e: ++ value_t = "ERR %s" % str(e) ++ return value_t ++ ++ # fanFRU ++ @staticmethod ++ def decodeBinByValue(retval): ++ fru = ipmifru() ++ fru.decodeBin(retval) ++ return fru ++ ++ @staticmethod ++ def getfruValue(prob_t, root, val): ++ try: ++ ret, binval_bytes = dev_file_read(val, 0, 256) ++ if ret is False: ++ return binval_bytes ++ binval = byteTostr(binval_bytes) ++ fanpro = {} ++ ret = checktype.decodeBinByValue(binval) ++ fanpro['fan_type'] = ret.productInfoArea.productName ++ fanpro['hw_version'] = str(int(ret.productInfoArea.productVersion, 16)) ++ fanpro['sn'] = ret.productInfoArea.productSerialNumber ++ fan_display_name_dict = status.getDecodValue(root, "fan_display_name") ++ fan_name = fanpro['fan_type'].strip() ++ if len(fan_display_name_dict) == 0: ++ return fanpro ++ if fan_name not in fan_display_name_dict: ++ prob_t['errcode'] = -1 ++ prob_t['errmsg'] = '%s' % ("ERR fan name: %s not support" % fan_name) ++ else: ++ fanpro['fan_type'] = fan_display_name_dict[fan_name] ++ return fanpro ++ except Exception as error: ++ return "ERR " + str(error) ++ ++ @staticmethod ++ def getslotfruValue(val): ++ try: ++ binval = checktype.getValue(val, 0, 0) ++ if binval.startswith("ERR"): ++ return binval ++ slotpro = {} ++ ret = checktype.decodeBinByValue(binval) ++ slotpro['slot_type'] = ret.boardInfoArea.boardProductName ++ slotpro['hw_version'] = ret.boardInfoArea.boardextra1 ++ slotpro['sn'] = ret.boardInfoArea.boardSerialNumber ++ return slotpro ++ except Exception as error: ++ return "ERR " + str(error) ++ ++ @staticmethod ++ def getpsufruValue(prob_t, root, val): ++ try: ++ psu_match = False ++ binval = checktype.getValue(val, 0, 0) ++ if binval.startswith("ERR"): ++ return binval ++ psupro = {} ++ ret = checktype.decodeBinByValue(binval) ++ psupro['type1'] = ret.productInfoArea.productPartModelName ++ psupro['sn'] = ret.productInfoArea.productSerialNumber ++ psupro['hw_version'] = ret.productInfoArea.productVersion ++ psu_dict = status.getDecodValue(root, "psutype") ++ psupro['type1'] = psupro['type1'].strip() ++ if len(psu_dict) == 0: ++ return psupro ++ for psu_name, display_name in psu_dict.items(): ++ if psu_name.strip() == psupro['type1']: ++ psupro['type1'] = display_name ++ psu_match = True ++ break ++ if psu_match is not True: ++ prob_t['errcode'] = -1 ++ prob_t['errmsg'] = '%s' % ("ERR psu name: %s not support" % psupro['type1']) ++ return psupro ++ except Exception as error: ++ return "ERR " + str(error) ++ ++ ++class status(): ++ def __init__(self, productname): ++ self.productname = productname ++ ++ @staticmethod ++ def getETroot(filename): ++ tree = ET.parse(filename) ++ root = tree.getroot() ++ return root ++ ++ @staticmethod ++ def getDecodValue(collection, decode): ++ decodes = collection.find('decode') ++ testdecode = decodes.find(decode) ++ test = {} ++ if testdecode is None: ++ return test ++ for neighbor in testdecode.iter('code'): ++ test[neighbor.attrib["key"]] = neighbor.attrib["value"] ++ return test ++ ++ @staticmethod ++ def getfileValue(location): ++ return checktype.getValue(location, " ", " ") ++ ++ @staticmethod ++ def getETValue(a, filename, tagname): ++ root = status.getETroot(filename) ++ for neighbor in root.iter(tagname): ++ prob_t = {} ++ prob_t = neighbor.attrib ++ prob_t['errcode'] = 0 ++ prob_t['errmsg'] = '' ++ for pros in neighbor.iter("property"): ++ ret = dict(list(neighbor.attrib.items()) + list(pros.attrib.items())) ++ if ret.get('e2type') == 'fru' and ret.get("name") == "fru": ++ fruval = checktype.getfruValue(prob_t, root, ret["location"]) ++ if isinstance(fruval, str) and fruval.startswith("ERR"): ++ prob_t['errcode'] = -1 ++ prob_t['errmsg'] = fruval ++ break ++ prob_t.update(fruval) ++ continue ++ ++ if ret.get("name") == "psu" and ret.get('e2type') == 'fru': ++ psuval = checktype.getpsufruValue(prob_t, root, ret["location"]) ++ if isinstance(psuval, str) and psuval.startswith("ERR"): ++ prob_t['errcode'] = -1 ++ prob_t['errmsg'] = psuval ++ break ++ prob_t.update(psuval) ++ continue ++ ++ if ret.get("gettype") == "config": ++ prob_t[ret["name"]] = ret["value"] ++ continue ++ ++ if 'type' not in ret.keys(): ++ val = "0" ++ else: ++ val = ret["type"] ++ if 'bit' not in ret.keys(): ++ bit = "0" ++ else: ++ bit = ret["bit"] ++ if 'coefficient' not in ret.keys(): ++ coefficient = 1 ++ else: ++ coefficient = float(ret["coefficient"]) ++ if 'addend' not in ret.keys(): ++ addend = 0 ++ else: ++ addend = float(ret["addend"]) ++ ++ s = checktype.getValue(ret["location"], int(bit), int(val), coefficient, addend) ++ if isinstance(s, str) and s.startswith("ERR"): ++ prob_t['errcode'] = -1 ++ prob_t['errmsg'] = s ++ break ++ if 'default' in ret.keys(): ++ rt = status.getDecodValue(root, ret['decode']) ++ prob_t['errmsg'] = rt[str(s)] ++ if str(s) != ret["default"]: ++ prob_t['errcode'] = -1 ++ break ++ else: ++ if 'decode' in ret.keys(): ++ rt = status.getDecodValue(root, ret['decode']) ++ if (ret['decode'] == "psutype" and s.replace("\x00", "").rstrip() not in rt): ++ prob_t['errcode'] = -1 ++ prob_t['errmsg'] = '%s' % ("ERR psu name: %s not support" % ++ (s.replace("\x00", "").rstrip())) ++ else: ++ s = rt[str(s).replace("\x00", "").rstrip()] ++ name = ret["name"] ++ prob_t[name] = str(s) ++ a.append(prob_t) ++ ++ @staticmethod ++ def getCPUValue(a, filename, tagname): ++ root = status.getETroot(filename) ++ for neighbor in root.iter(tagname): ++ location = neighbor.attrib["location"] ++ L = [] ++ for dirpath, dirnames, filenames in os.walk(location): ++ for file in filenames: ++ if file.endswith("input"): ++ L.append(os.path.join(dirpath, file)) ++ L = sorted(L, reverse=False) ++ for i in range(len(L)): ++ prob_t = {} ++ prob_t["name"] = getPMCreg("%s/temp%d_label" % (location, i + 1)) ++ prob_t["temp"] = float(getPMCreg("%s/temp%d_input" % (location, i + 1))) / 1000 ++ prob_t["alarm"] = float(getPMCreg("%s/temp%d_crit_alarm" % (location, i + 1))) / 1000 ++ prob_t["crit"] = float(getPMCreg("%s/temp%d_crit" % (location, i + 1))) / 1000 ++ prob_t["max"] = float(getPMCreg("%s/temp%d_max" % (location, i + 1))) / 1000 ++ a.append(prob_t) ++ ++ @staticmethod ++ def getFileName(): ++ fpath = os.path.dirname(os.path.realpath(__file__)) ++ for file in DEV_XML_FILE_LIST: ++ xml = fpath + "/" + file ++ if os.path.exists(xml): ++ return xml ++ return fpath + "/" + CONFIG_NAME ++ ++ @staticmethod ++ def checkFan(ret): ++ _filename = status.getFileName() ++ # _filename = "/usr/local/bin/" + status.getFileName() ++ _tagname = "fan" ++ status.getETValue(ret, _filename, _tagname) ++ ++ @staticmethod ++ def getTemp(ret): ++ _filename = status.getFileName() ++ # _filename = "/usr/local/bin/" + status.getFileName() ++ _tagname = "temp" ++ status.getETValue(ret, _filename, _tagname) ++ ++ @staticmethod ++ def getPsu(ret): ++ _filename = status.getFileName() ++ # _filename = "/usr/local/bin/" + status.getFileName() ++ _tagname = "psu" ++ status.getETValue(ret, _filename, _tagname) ++ ++ @staticmethod ++ def getcputemp(ret): ++ _filename = status.getFileName() ++ _tagname = "cpus" ++ status.getCPUValue(ret, _filename, _tagname) ++ ++ @staticmethod ++ def getDcdc(ret): ++ _filename = status.getFileName() ++ _tagname = "dcdc" ++ status.getETValue(ret, _filename, _tagname) ++ ++ @staticmethod ++ def getmactemp(ret): ++ _filename = status.getFileName() ++ _tagname = "mactemp" ++ status.getETValue(ret, _filename, _tagname) ++ ++ @staticmethod ++ def getmacpower(ret): ++ _filename = status.getFileName() ++ _tagname = "macpower" ++ status.getETValue(ret, _filename, _tagname) +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml +new file mode 100644 +index 000000000..7b026cec3 +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml +@@ -0,0 +1,440 @@ ++- bus: '00' ++ dev: '00' ++ fn: '0' ++ id: 6f00 ++ name: 'Host bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DMI2 ++ (rev 03)' ++- bus: '00' ++ dev: '01' ++ fn: '0' ++ id: 6f02 ++ name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI ++ Express Root Port 1 (rev 03)' ++- bus: '00' ++ dev: '01' ++ fn: '1' ++ id: 6f03 ++ name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI ++ Express Root Port 1 (rev 03)' ++- bus: '00' ++ dev: '02' ++ fn: '0' ++ id: 6f04 ++ name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI ++ Express Root Port 2 (rev 03)' ++- bus: '00' ++ dev: '02' ++ fn: '2' ++ id: 6f06 ++ name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI ++ Express Root Port 2 (rev 03)' ++- bus: '00' ++ dev: '03' ++ fn: '0' ++ id: 6f08 ++ name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI ++ Express Root Port 3 (rev 03)' ++- bus: '00' ++ dev: '05' ++ fn: '0' ++ id: 6f28 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Map/VTd_Misc/System Management (rev 03)' ++- bus: '00' ++ dev: '05' ++ fn: '1' ++ id: 6f29 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D IIO Hot Plug (rev 03)' ++- bus: '00' ++ dev: '05' ++ fn: '2' ++ id: 6f2a ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D IIO RAS/Control Status/Global Errors (rev 03)' ++- bus: '00' ++ dev: '05' ++ fn: '4' ++ id: 6f2c ++ name: 'PIC: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D I/O APIC (rev ++ 03)' ++- bus: '00' ++ dev: '14' ++ fn: '0' ++ id: 8c31 ++ name: 'USB controller: Intel Corporation 8 Series/C220 Series Chipset Family USB ++ xHCI (rev 05)' ++- bus: '00' ++ dev: '16' ++ fn: '0' ++ id: 8c3a ++ name: 'Communication controller: Intel Corporation 8 Series/C220 Series Chipset ++ Family MEI Controller #1 (rev 04)' ++- bus: '00' ++ dev: '16' ++ fn: '1' ++ id: 8c3b ++ name: 'Communication controller: Intel Corporation 8 Series/C220 Series Chipset ++ Family MEI Controller #2 (rev 04)' ++- bus: '00' ++ dev: 1c ++ fn: '0' ++ id: 8c10 ++ name: 'PCI bridge: Intel Corporation 8 Series/C220 Series Chipset Family PCI Express ++ Root Port #1 (rev d5)' ++- bus: '00' ++ dev: 1c ++ fn: '1' ++ id: 8c12 ++ name: 'PCI bridge: Intel Corporation 8 Series/C220 Series Chipset Family PCI Express ++ Root Port #2 (rev d5)' ++- bus: '00' ++ dev: 1d ++ fn: '0' ++ id: 8c26 ++ name: 'USB controller: Intel Corporation 8 Series/C220 Series Chipset Family USB ++ EHCI #1 (rev 05)' ++- bus: '00' ++ dev: 1f ++ fn: '0' ++ id: 8c54 ++ name: 'ISA bridge: Intel Corporation C224 Series Chipset Family Server Standard ++ SKU LPC Controller (rev 05)' ++- bus: '00' ++ dev: 1f ++ fn: '2' ++ id: 8c02 ++ name: 'SATA controller: Intel Corporation 8 Series/C220 Series Chipset Family 6-port ++ SATA Controller 1 [AHCI mode] (rev 05)' ++- bus: '00' ++ dev: 1f ++ fn: '3' ++ id: 8c22 ++ name: 'SMBus: Intel Corporation 8 Series/C220 Series Chipset Family SMBus Controller ++ (rev 05)' ++- bus: '01' ++ dev: '00' ++ fn: '0' ++ id: b873 ++ name: 'Ethernet controller: Broadcom Inc. and subsidiaries Device b873 (rev 01)' ++- bus: '03' ++ dev: '00' ++ fn: '0' ++ id: 6f50 ++ name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology ++ Register DMA Channel 0' ++- bus: '03' ++ dev: '00' ++ fn: '1' ++ id: 6f51 ++ name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology ++ Register DMA Channel 1' ++- bus: '03' ++ dev: '00' ++ fn: '2' ++ id: 6f52 ++ name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology ++ Register DMA Channel 2' ++- bus: '03' ++ dev: '00' ++ fn: '3' ++ id: 6f53 ++ name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology ++ Register DMA Channel 3' ++- bus: '04' ++ dev: '00' ++ fn: '0' ++ id: 15ab ++ name: 'Ethernet controller: Intel Corporation Ethernet Connection X552 10 GbE Backplane' ++- bus: '04' ++ dev: '00' ++ fn: '1' ++ id: 15ab ++ name: 'Ethernet controller: Intel Corporation Ethernet Connection X552 10 GbE Backplane' ++- bus: '07' ++ dev: '00' ++ fn: '0' ++ id: '1537' ++ name: 'Ethernet controller: Intel Corporation I210 Gigabit Backplane Connection ++ (rev 03)' ++- bus: 08 ++ dev: '00' ++ fn: '0' ++ id: '7022' ++ name: 'Memory controller: Xilinx Corporation Device 7022' ++- bus: ff ++ dev: 0b ++ fn: '0' ++ id: 6f81 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D R3 QPI Link 0/1 (rev 03)' ++- bus: ff ++ dev: 0b ++ fn: '1' ++ id: 6f36 ++ name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D R3 QPI Link 0/1 (rev 03)' ++- bus: ff ++ dev: 0b ++ fn: '2' ++ id: 6f37 ++ name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D R3 QPI Link 0/1 (rev 03)' ++- bus: ff ++ dev: 0b ++ fn: '3' ++ id: 6f76 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D R3 QPI Link Debug (rev 03)' ++- bus: ff ++ dev: 0c ++ fn: '0' ++ id: 6fe0 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Caching Agent (rev 03)' ++- bus: ff ++ dev: 0c ++ fn: '1' ++ id: 6fe1 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Caching Agent (rev 03)' ++- bus: ff ++ dev: 0c ++ fn: '2' ++ id: 6fe2 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Caching Agent (rev 03)' ++- bus: ff ++ dev: 0c ++ fn: '3' ++ id: 6fe3 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Caching Agent (rev 03)' ++- bus: ff ++ dev: 0f ++ fn: '0' ++ id: 6ff8 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Caching Agent (rev 03)' ++- bus: ff ++ dev: 0f ++ fn: '4' ++ id: 6ffc ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Caching Agent (rev 03)' ++- bus: ff ++ dev: 0f ++ fn: '5' ++ id: 6ffd ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Caching Agent (rev 03)' ++- bus: ff ++ dev: 0f ++ fn: '6' ++ id: 6ffe ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Caching Agent (rev 03)' ++- bus: ff ++ dev: '10' ++ fn: '0' ++ id: 6f1d ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D R2PCIe Agent (rev 03)' ++- bus: ff ++ dev: '10' ++ fn: '1' ++ id: 6f34 ++ name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D R2PCIe Agent (rev 03)' ++- bus: ff ++ dev: '10' ++ fn: '5' ++ id: 6f1e ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Ubox (rev 03)' ++- bus: ff ++ dev: '10' ++ fn: '6' ++ id: 6f7d ++ name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Ubox (rev 03)' ++- bus: ff ++ dev: '10' ++ fn: '7' ++ id: 6f1f ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Ubox (rev 03)' ++- bus: ff ++ dev: '12' ++ fn: '0' ++ id: 6fa0 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Home Agent 0 (rev 03)' ++- bus: ff ++ dev: '12' ++ fn: '1' ++ id: 6f30 ++ name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Home Agent 0 (rev 03)' ++- bus: ff ++ dev: '13' ++ fn: '0' ++ id: 6fa8 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Memory Controller 0 - Target Address/Thermal/RAS (rev 03)' ++- bus: ff ++ dev: '13' ++ fn: '1' ++ id: 6f71 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Memory Controller 0 - Target Address/Thermal/RAS (rev 03)' ++- bus: ff ++ dev: '13' ++ fn: '2' ++ id: 6faa ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Memory Controller 0 - Channel Target Address Decoder (rev 03)' ++- bus: ff ++ dev: '13' ++ fn: '3' ++ id: 6fab ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Memory Controller 0 - Channel Target Address Decoder (rev 03)' ++- bus: ff ++ dev: '13' ++ fn: '4' ++ id: 6fac ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Memory Controller 0 - Channel Target Address Decoder (rev 03)' ++- bus: ff ++ dev: '13' ++ fn: '5' ++ id: 6fad ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Memory Controller 0 - Channel Target Address Decoder (rev 03)' ++- bus: ff ++ dev: '13' ++ fn: '6' ++ id: 6fae ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D DDRIO Channel 0/1 Broadcast (rev 03)' ++- bus: ff ++ dev: '13' ++ fn: '7' ++ id: 6faf ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D DDRIO Global Broadcast (rev 03)' ++- bus: ff ++ dev: '14' ++ fn: '0' ++ id: 6fb0 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Memory Controller 0 - Channel 0 Thermal Control (rev 03)' ++- bus: ff ++ dev: '14' ++ fn: '1' ++ id: 6fb1 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Memory Controller 0 - Channel 1 Thermal Control (rev 03)' ++- bus: ff ++ dev: '14' ++ fn: '2' ++ id: 6fb2 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Memory Controller 0 - Channel 0 Error (rev 03)' ++- bus: ff ++ dev: '14' ++ fn: '3' ++ id: 6fb3 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Memory Controller 0 - Channel 1 Error (rev 03)' ++- bus: ff ++ dev: '14' ++ fn: '4' ++ id: 6fbc ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D DDRIO Channel 0/1 Interface (rev 03)' ++- bus: ff ++ dev: '14' ++ fn: '5' ++ id: 6fbd ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D DDRIO Channel 0/1 Interface (rev 03)' ++- bus: ff ++ dev: '14' ++ fn: '6' ++ id: 6fbe ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D DDRIO Channel 0/1 Interface (rev 03)' ++- bus: ff ++ dev: '14' ++ fn: '7' ++ id: 6fbf ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D DDRIO Channel 0/1 Interface (rev 03)' ++- bus: ff ++ dev: '15' ++ fn: '0' ++ id: 6fb4 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Memory Controller 0 - Channel 2 Thermal Control (rev 03)' ++- bus: ff ++ dev: '15' ++ fn: '1' ++ id: 6fb5 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Memory Controller 0 - Channel 3 Thermal Control (rev 03)' ++- bus: ff ++ dev: '15' ++ fn: '2' ++ id: 6fb6 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Memory Controller 0 - Channel 2 Error (rev 03)' ++- bus: ff ++ dev: '15' ++ fn: '3' ++ id: 6fb7 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Memory Controller 0 - Channel 3 Error (rev 03)' ++- bus: ff ++ dev: 1e ++ fn: '0' ++ id: 6f98 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Power Control Unit (rev 03)' ++- bus: ff ++ dev: 1e ++ fn: '1' ++ id: 6f99 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Power Control Unit (rev 03)' ++- bus: ff ++ dev: 1e ++ fn: '2' ++ id: 6f9a ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Power Control Unit (rev 03)' ++- bus: ff ++ dev: 1e ++ fn: '3' ++ id: 6fc0 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Power Control Unit (rev 03)' ++- bus: ff ++ dev: 1e ++ fn: '4' ++ id: 6f9c ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Power Control Unit (rev 03)' ++- bus: ff ++ dev: 1f ++ fn: '0' ++ id: 6f88 ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Power Control Unit (rev 03)' ++- bus: ff ++ dev: 1f ++ fn: '2' ++ id: 6f8a ++ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon ++ D Power Control Unit (rev 03)' +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform.json +new file mode 100644 +index 000000000..0fe70dd14 +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform.json +@@ -0,0 +1,819 @@ ++{ ++ "chassis": { ++ "name": "M2-W6510-48V8C", ++ "thermal_manager": false, ++ "status_led": { ++ "controllable": false, ++ "colors": ["green", "blinking_green", "amber", "blinking_amber"] ++ }, ++ "components": [ ++ { ++ "name": "CPU_CPLD" ++ }, ++ { ++ "name": "CONNECT_CPLD" ++ }, ++ { ++ "name": "CONNECT_CPLD-FAN" ++ }, ++ { ++ "name": "MAC_CPLD1" ++ }, ++ { ++ "name": "MAC_CPLD2" ++ }, ++ { ++ "name": "FPGA" ++ }, ++ { ++ "name": "BIOS" ++ } ++ ], ++ "fans": [ ++ { ++ "name": "Fantray1_1", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false, ++ "colors": ["off", "red", "amber", "green"] ++ } ++ }, ++ { ++ "name": "Fantray1_2", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false, ++ "colors": ["off", "red", "amber", "green"] ++ } ++ }, ++ { ++ "name": "Fantray2_1", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false, ++ "colors": ["off", "red", "amber", "green"] ++ } ++ }, ++ { ++ "name": "Fantray2_2", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false, ++ "colors": ["off", "red", "amber", "green"] ++ } ++ }, ++ { ++ "name": "Fantray3_1", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false, ++ "colors": ["off", "red", "amber", "green"] ++ } ++ }, ++ { ++ "name": "Fantray3_2", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false, ++ "colors": ["off", "red", "amber", "green"] ++ } ++ }, ++ { ++ "name": "Fantray4_1", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false, ++ "colors": ["off", "red", "amber", "green"] ++ } ++ }, ++ { ++ "name": "Fantray4_2", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false, ++ "colors": ["off", "red", "amber", "green"] ++ } ++ } ++ ], ++ "fan_drawers":[ ++ { ++ "name": "Fantray1", ++ "num_fans" : 2, ++ "status_led": { ++ "controllable": false, ++ "colors": ["amber", "green", "off"] ++ }, ++ "fans": [ ++ { ++ "name": "Fantray1_1", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false ++ } ++ }, ++ { ++ "name": "Fantray1_2", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false ++ } ++ } ++ ] ++ }, ++ { ++ "name": "Fantray2", ++ "num_fans" : 2, ++ "status_led": { ++ "controllable": false, ++ "colors": ["amber", "green", "off"] ++ }, ++ "fans": [ ++ { ++ "name": "Fantray2_1", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false ++ } ++ }, ++ { ++ "name": "Fantray2_2", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false ++ } ++ } ++ ] ++ }, ++ { ++ "name": "Fantray3", ++ "num_fans" : 2, ++ "status_led": { ++ "controllable": false, ++ "colors": ["amber", "green", "off"] ++ }, ++ "fans": [ ++ { ++ "name": "Fantray3_1", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false ++ } ++ }, ++ { ++ "name": "Fantray3_2", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false ++ } ++ } ++ ] ++ }, ++ { ++ "name": "Fantray4", ++ "num_fans" : 2, ++ "status_led": { ++ "controllable": false, ++ "colors": ["amber", "green", "off"] ++ }, ++ "fans": [ ++ { ++ "name": "Fantray4_1", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false ++ } ++ }, ++ { ++ "name": "Fantray4_2", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false ++ } ++ } ++ ] ++ } ++ ], ++ "psus": [ ++ { ++ "name": "Psu1", ++ "voltage": true, ++ "current": true, ++ "power": true, ++ "max_power": false, ++ "voltage_high_threshold": true, ++ "voltage_low_threshold": true, ++ "temperature": true, ++ "fans_target_speed": true, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "PSU1_FAN1", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false ++ } ++ } ++ ] ++ }, ++ { ++ "name": "Psu2", ++ "voltage": true, ++ "current": true, ++ "power": true, ++ "max_power": false, ++ "voltage_high_threshold": true, ++ "voltage_low_threshold": true, ++ "temperature": true, ++ "fans_target_speed": true, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "PSU2_FAN1", ++ "speed": { ++ "controllable": true, ++ "minimum": 50, ++ "maximum": 100 ++ }, ++ "status_led": { ++ "available": false ++ } ++ } ++ ] ++ } ++ ], ++ "thermals": [ ++ { ++ "name": "ASIC_TEMP", ++ "controllable": false, ++ "low-crit-threshold": true, ++ "high-crit-threshold": true, ++ "low-threshold": true, ++ "high-threshold": true, ++ "minimum-recorded": true, ++ "maximum-recorded": true ++ }, ++ { ++ "name": "CPU_TEMP", ++ "controllable": false, ++ "low-crit-threshold": true, ++ "high-crit-threshold": true, ++ "low-threshold": true, ++ "high-threshold": true, ++ "minimum-recorded": true, ++ "maximum-recorded": true ++ }, ++ { ++ "name": "INLET_TEMP", ++ "controllable": false, ++ "low-crit-threshold": true, ++ "high-crit-threshold": true, ++ "low-threshold": true, ++ "high-threshold": true, ++ "minimum-recorded": true, ++ "maximum-recorded": true ++ }, ++ { ++ "name": "OUTLET_TEMP", ++ "controllable": false, ++ "low-crit-threshold": true, ++ "high-crit-threshold": true, ++ "low-threshold": true, ++ "high-threshold": true, ++ "minimum-recorded": true, ++ "maximum-recorded": true ++ }, ++ { ++ "name": "MAC_OUT_TEMP", ++ "controllable": false, ++ "low-crit-threshold": true, ++ "high-crit-threshold": true, ++ "low-threshold": true, ++ "high-threshold": true, ++ "minimum-recorded": true, ++ "maximum-recorded": true ++ }, ++ { ++ "name": "MAC_IN_TEMP", ++ "controllable": false, ++ "low-crit-threshold": true, ++ "high-crit-threshold": true, ++ "low-threshold": true, ++ "high-threshold": true, ++ "minimum-recorded": true, ++ "maximum-recorded": true ++ }, ++ { ++ "name": "PSU1_TEMP", ++ "controllable": false, ++ "low-crit-threshold": true, ++ "high-crit-threshold": true, ++ "low-threshold": true, ++ "high-threshold": true, ++ "minimum-recorded": true, ++ "maximum-recorded": true ++ }, ++ { ++ "name": "PSU2_TEMP", ++ "controllable": false, ++ "low-crit-threshold": true, ++ "high-crit-threshold": true, ++ "low-threshold": true, ++ "high-threshold": true, ++ "minimum-recorded": true, ++ "maximum-recorded": true ++ } ++ ], ++ "modules": [], ++ "sfps": [] ++ }, ++ "interfaces": { ++ "Ethernet1": { ++ "index": "1", ++ "lanes": "57", ++ "breakout_modes": { ++ "1x25G": ["Eth1"] ++ } ++ }, ++ "Ethernet2": { ++ "index": "2", ++ "lanes": "58", ++ "breakout_modes": { ++ "1x25G": ["Eth2"] ++ } ++ }, ++ "Ethernet3": { ++ "index": "3", ++ "lanes": "59", ++ "breakout_modes": { ++ "1x25G": ["Eth3"] ++ } ++ }, ++ "Ethernet4": { ++ "index": "4", ++ "lanes": "60", ++ "breakout_modes": { ++ "1x25G": ["Eth4"] ++ } ++ }, ++ "Ethernet5": { ++ "index": "5", ++ "lanes": "61", ++ "breakout_modes": { ++ "1x25G": ["Eth5"] ++ } ++ }, ++ "Ethernet6": { ++ "index": "6", ++ "lanes": "62", ++ "breakout_modes": { ++ "1x25G": ["Eth6"] ++ } ++ }, ++ "Ethernet7": { ++ "index": "7", ++ "lanes": "63", ++ "breakout_modes": { ++ "1x25G": ["Eth7"] ++ } ++ }, ++ "Ethernet8": { ++ "index": "8", ++ "lanes": "64", ++ "breakout_modes": { ++ "1x25G": ["Eth8"] ++ } ++ }, ++ "Ethernet9": { ++ "index": "9", ++ "lanes": "1", ++ "breakout_modes": { ++ "1x25G": ["Eth9"] ++ } ++ }, ++ "Ethernet10": { ++ "index": "10", ++ "lanes": "2", ++ "breakout_modes": { ++ "1x25G": ["Eth10"] ++ } ++ }, ++ "Ethernet11": { ++ "index": "11", ++ "lanes": "3", ++ "breakout_modes": { ++ "1x25G": ["Eth11"] ++ } ++ }, ++ "Ethernet12": { ++ "index": "12", ++ "lanes": "4", ++ "breakout_modes": { ++ "1x25G": ["Eth12"] ++ } ++ }, ++ "Ethernet13": { ++ "index": "13", ++ "lanes": "5", ++ "breakout_modes": { ++ "1x25G": ["Eth13"] ++ } ++ }, ++ "Ethernet14": { ++ "index": "14", ++ "lanes": "6", ++ "breakout_modes": { ++ "1x25G": ["Eth14"] ++ } ++ }, ++ "Ethernet15": { ++ "index": "15", ++ "lanes": "7", ++ "breakout_modes": { ++ "1x25G": ["Eth15"] ++ } ++ }, ++ "Ethernet16": { ++ "index": "16", ++ "lanes": "8", ++ "breakout_modes": { ++ "1x25G": ["Eth16"] ++ } ++ }, ++ "Ethernet17": { ++ "index": "17", ++ "lanes": "13", ++ "breakout_modes": { ++ "1x25G": ["Eth17"] ++ } ++ }, ++ "Ethernet18": { ++ "index": "18", ++ "lanes": "14", ++ "breakout_modes": { ++ "1x25G": ["Eth18"] ++ } ++ }, ++ "Ethernet19": { ++ "index": "19", ++ "lanes": "15", ++ "breakout_modes": { ++ "1x25G": ["Eth19"] ++ } ++ }, ++ "Ethernet20": { ++ "index": "20", ++ "lanes": "16", ++ "breakout_modes": { ++ "1x25G": ["Eth20"] ++ } ++ }, ++ "Ethernet21": { ++ "index": "21", ++ "lanes": "21", ++ "breakout_modes": { ++ "1x25G": ["Eth21"] ++ } ++ }, ++ "Ethernet22": { ++ "index": "22", ++ "lanes": "22", ++ "breakout_modes": { ++ "1x25G": ["Eth22"] ++ } ++ }, ++ "Ethernet23": { ++ "index": "23", ++ "lanes": "23", ++ "breakout_modes": { ++ "1x25G": ["Eth23"] ++ } ++ }, ++ "Ethernet24": { ++ "index": "24", ++ "lanes": "24", ++ "breakout_modes": { ++ "1x25G": ["Eth24"] ++ } ++ }, ++ "Ethernet25": { ++ "index": "25", ++ "lanes": "29", ++ "breakout_modes": { ++ "1x25G": ["Eth25"] ++ } ++ }, ++ "Ethernet26": { ++ "index": "26", ++ "lanes": "30", ++ "breakout_modes": { ++ "1x25G": ["Eth26"] ++ } ++ }, ++ "Ethernet27": { ++ "index": "27", ++ "lanes": "31", ++ "breakout_modes": { ++ "1x25G": ["Eth27"] ++ } ++ }, ++ "Ethernet28": { ++ "index": "28", ++ "lanes": "32", ++ "breakout_modes": { ++ "1x25G": ["Eth28"] ++ } ++ }, ++ "Ethernet29": { ++ "index": "29", ++ "lanes": "33", ++ "breakout_modes": { ++ "1x25G": ["Eth29"] ++ } ++ }, ++ "Ethernet30": { ++ "index": "30", ++ "lanes": "34", ++ "breakout_modes": { ++ "1x25G": ["Eth30"] ++ } ++ }, ++ "Ethernet31": { ++ "index": "31", ++ "lanes": "35", ++ "breakout_modes": { ++ "1x25G": ["Eth31"] ++ } ++ }, ++ "Ethernet32": { ++ "index": "32", ++ "lanes": "36", ++ "breakout_modes": { ++ "1x25G": ["Eth32"] ++ } ++ }, ++ "Ethernet33": { ++ "index": "33", ++ "lanes": "41", ++ "breakout_modes": { ++ "1x25G": ["Eth33"] ++ } ++ }, ++ "Ethernet34": { ++ "index": "34", ++ "lanes": "42", ++ "breakout_modes": { ++ "1x25G": ["Eth34"] ++ } ++ }, ++ "Ethernet35": { ++ "index": "35", ++ "lanes": "43", ++ "breakout_modes": { ++ "1x25G": ["Eth35"] ++ } ++ }, ++ "Ethernet36": { ++ "index": "36", ++ "lanes": "44", ++ "breakout_modes": { ++ "1x25G": ["Eth36"] ++ } ++ }, ++ "Ethernet37": { ++ "index": "37", ++ "lanes": "49", ++ "breakout_modes": { ++ "1x25G": ["Eth37"] ++ } ++ }, ++ "Ethernet38": { ++ "index": "38", ++ "lanes": "50", ++ "breakout_modes": { ++ "1x25G": ["Eth38"] ++ } ++ }, ++ "Ethernet39": { ++ "index": "39", ++ "lanes": "51", ++ "breakout_modes": { ++ "1x25G": ["Eth39"] ++ } ++ }, ++ "Ethernet40": { ++ "index": "40", ++ "lanes": "52", ++ "breakout_modes": { ++ "1x25G": ["Eth40"] ++ } ++ }, ++ "Ethernet41": { ++ "index": "41", ++ "lanes": "65", ++ "breakout_modes": { ++ "1x25G": ["Eth41"] ++ } ++ }, ++ "Ethernet42": { ++ "index": "42", ++ "lanes": "66", ++ "breakout_modes": { ++ "1x25G": ["Eth42"] ++ } ++ }, ++ "Ethernet43": { ++ "index": "43", ++ "lanes": "67", ++ "breakout_modes": { ++ "1x25G": ["Eth43"] ++ } ++ }, ++ "Ethernet44": { ++ "index": "44", ++ "lanes": "68", ++ "breakout_modes": { ++ "1x25G": ["Eth44"] ++ } ++ }, ++ "Ethernet45": { ++ "index": "45", ++ "lanes": "69", ++ "breakout_modes": { ++ "1x25G": ["Eth45"] ++ } ++ }, ++ "Ethernet46": { ++ "index": "46", ++ "lanes": "70", ++ "breakout_modes": { ++ "1x25G": ["Eth46"] ++ } ++ }, ++ "Ethernet47": { ++ "index": "47", ++ "lanes": "71", ++ "breakout_modes": { ++ "1x25G": ["Eth47"] ++ } ++ }, ++ "Ethernet48": { ++ "index": "48", ++ "lanes": "72", ++ "breakout_modes": { ++ "1x25G": ["Eth48"] ++ } ++ }, ++ "Ethernet49": { ++ "index": "49,49,49,49", ++ "lanes": "85,86,87,88", ++ "breakout_modes": { ++ "1x100G": ["Eth49"], ++ "2x50G": ["Eth49/1", "Eth49/2"], ++ "4x25G[10G]": ["Eth49/1", "Eth49/2", "Eth49/3", "Eth49/4"], ++ "4x10G": ["Eth49/1", "Eth49/2", "Eth49/3", "Eth49/4"] ++ } ++ }, ++ "Ethernet53": { ++ "index": "50,50,50,50", ++ "lanes": "77,78,79,80", ++ "breakout_modes": { ++ "1x100G": ["Eth50"], ++ "2x50G": ["Eth50/1", "Eth50/2"], ++ "4x25G[10G]": ["Eth50/1", "Eth50/2", "Eth50/3", "Eth50/4"], ++ "4x10G": ["Eth50/1", "Eth50/2", "Eth50/3", "Eth50/4"] ++ } ++ }, ++ "Ethernet57": { ++ "index": "51,51,51,51", ++ "lanes": "97,98,99,100", ++ "breakout_modes": { ++ "1x100G": ["Eth51"], ++ "2x50G": ["Eth51/1", "Eth51/2"], ++ "4x25G[10G]": ["Eth51/1", "Eth51/2", "Eth51/3", "Eth51/4"], ++ "4x10G": ["Eth51/1", "Eth51/2", "Eth51/3", "Eth51/4"] ++ } ++ }, ++ "Ethernet61": { ++ "index": "52,52,52,52", ++ "lanes": "93,94,95,96", ++ "breakout_modes": { ++ "1x100G": ["Eth52"], ++ "2x50G": ["Eth52/1", "Eth52/2"], ++ "4x25G[10G]": ["Eth52/1", "Eth52/2", "Eth52/3", "Eth52/4"], ++ "4x10G": ["Eth52/1", "Eth52/2", "Eth52/3", "Eth52/4"] ++ } ++ }, ++ "Ethernet65": { ++ "index": "53,53,53,53", ++ "lanes": "113,114,115,116", ++ "breakout_modes": { ++ "1x100G": ["Eth53"], ++ "2x50G": ["Eth53/1", "Eth53/2"], ++ "4x25G[10G]": ["Eth53/1", "Eth53/2", "Eth53/3", "Eth53/4"], ++ "4x10G": ["Eth53/1", "Eth53/2", "Eth53/3", "Eth53/4"] ++ } ++ }, ++ "Ethernet69": { ++ "index": "54,54,54,54", ++ "lanes": "105,106,107,108", ++ "breakout_modes": { ++ "1x100G": ["Eth54"], ++ "2x50G": ["Eth54/1","Eth54/2"], ++ "4x25G[10G]": ["Eth54/1", "Eth54/2", "Eth54/3", "Eth54/4"], ++ "4x10G": ["Eth54/1", "Eth54/2", "Eth54/3", "Eth54/4"] ++ } ++ }, ++ "Ethernet73": { ++ "index": "55,55,55,55", ++ "lanes": "121,122,123,124", ++ "breakout_modes": { ++ "1x100G": ["Eth55"], ++ "2x50G": ["Eth55/1", "Eth55/2"], ++ "4x25G[10G]": ["Eth55/1", "Eth55/2", "Eth55/3", "Eth55/4"], ++ "4x10G": ["Eth55/1", "Eth55/2", "Eth55/3", "Eth55/4"] ++ } ++ }, ++ "Ethernet77": { ++ "index": "56,56,56,56", ++ "lanes": "125,126,127,128", ++ "breakout_modes": { ++ "1x100G": ["Eth56"], ++ "2x50G": ["Eth56/1", "Eth56/2"], ++ "4x25G[10G]": ["Eth56/1", "Eth56/2", "Eth56/3", "Eth56/4"], ++ "4x10G": ["Eth56/1", "Eth56/2", "Eth56/3", "Eth56/4"] ++ } ++ } ++ } ++} +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_asic b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_asic +new file mode 100644 +index 000000000..960467652 +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_asic +@@ -0,0 +1 @@ ++broadcom +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_components.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_components.json +new file mode 100644 +index 000000000..7986fe321 +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_components.json +@@ -0,0 +1,37 @@ ++{ ++ "chassis": { ++ "M2-W6510-48V8C": { ++ "component": { ++ "CPU_CPLD": { ++ "firmware": "", ++ "version": "27190516" ++ }, ++ "CONNECT_CPLD": { ++ "firmware": "", ++ "version": "49191230" ++ }, ++ "CONNECT_CPLD-FAN": { ++ "firmware": "", ++ "version": "49191230" ++ }, ++ "MAC_CPLD1": { ++ "firmware" : "", ++ "version" : "16190108" ++ }, ++ "MAC_CPLD2": { ++ "firmware" : "", ++ "version" : "17200110" ++ }, ++ "FPGA": { ++ "firmware": "", ++ "version": "7a150016" ++ }, ++ "BIOS": { ++ "firmware" : "", ++ "version" : "5.11(3BARB029)" ++ } ++ } ++ } ++ } ++} ++ +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/sfputil.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/sfputil.py +new file mode 100644 +index 000000000..3e195a36f +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/sfputil.py +@@ -0,0 +1,243 @@ ++# sfputil.py ++# ++# Platform-specific SFP transceiver interface for SONiC ++# ++ ++try: ++ import time ++ import os ++ import traceback ++ from sonic_sfp.sfputilbase import SfpUtilBase ++except ImportError as e: ++ raise ImportError("%s - required module not found" % str(e)) ++ ++class SfpUtil(SfpUtilBase): ++ """Platform-specific SfpUtil class""" ++ ++ PORT_START = 1 ++ PORT_END = 56 ++ PORTS_IN_BLOCK = 57 ++ ++ EEPROM_OFFSET = 32 ++ SFP_DEVICE_TYPE = "optoe2" ++ QSFP_DEVICE_TYPE = "optoe1" ++ I2C_MAX_ATTEMPT = 3 ++ ++ _port_to_eeprom_mapping = {} ++ port_to_i2cbus_mapping ={} ++ ++ @property ++ def port_start(self): ++ return self.PORT_START ++ ++ @property ++ def port_end(self): ++ return self.PORT_END ++ ++ @property ++ def qsfp_ports(self): ++ return range(49, self.PORTS_IN_BLOCK) ++ ++ @property ++ def port_to_eeprom_mapping(self): ++ return self._port_to_eeprom_mapping ++ ++ def __init__(self): ++ for x in range(self.PORT_START, self.PORTS_IN_BLOCK): ++ self.port_to_i2cbus_mapping[x] = x + self.EEPROM_OFFSET - 1 ++ SfpUtilBase.__init__(self) ++ ++ def _sfp_read_file_path(self, file_path, offset, num_bytes): ++ attempts = 0 ++ while attempts < self.I2C_MAX_ATTEMPT: ++ try: ++ file_path.seek(offset) ++ read_buf = file_path.read(num_bytes) ++ except Exception: ++ attempts += 1 ++ time.sleep(0.05) ++ return True, read_buf ++ return False, None ++ ++ def _sfp_eeprom_present(self, sysfs_sfp_i2c_client_eeprompath, offset): ++ """Tries to read the eeprom file to determine if the ++ device/sfp is present or not. If sfp present, the read returns ++ valid bytes. If not, read returns error 'Connection timed out""" ++ ++ if not os.path.exists(sysfs_sfp_i2c_client_eeprompath): ++ return False ++ with open(sysfs_sfp_i2c_client_eeprompath, "rb", buffering=0) as sysfsfile: ++ rv, buf = self._sfp_read_file_path(sysfsfile, offset, 1) ++ return rv ++ ++ def _add_new_sfp_device(self, sysfs_sfp_i2c_adapter_path, devaddr, devtype): ++ try: ++ sysfs_nd_path = "%s/new_device" % sysfs_sfp_i2c_adapter_path ++ ++ # Write device address to new_device file ++ nd_str = "%s %s" % (devtype, hex(devaddr)) ++ with open(sysfs_nd_path, "w") as nd_file: ++ nd_file.write(nd_str) ++ ++ except Exception as err: ++ print("Error writing to new device file: %s" % str(err)) ++ return 1 ++ else: ++ return 0 ++ ++ def _get_port_eeprom_path(self, port_num, devid): ++ sysfs_i2c_adapter_base_path = "" ++ ++ if port_num in self.port_to_eeprom_mapping: ++ sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[port_num] ++ else: ++ sysfs_i2c_adapter_base_path = "/sys/class/i2c-adapter" ++ ++ i2c_adapter_id = self._get_port_i2c_adapter_id(port_num) ++ if i2c_adapter_id is None: ++ print("Error getting i2c bus num") ++ return None ++ ++ # Get i2c virtual bus path for the sfp ++ sysfs_sfp_i2c_adapter_path = "%s/i2c-%s" % (sysfs_i2c_adapter_base_path, ++ str(i2c_adapter_id)) ++ ++ # If i2c bus for port does not exist ++ if not os.path.exists(sysfs_sfp_i2c_adapter_path): ++ print("Could not find i2c bus %s. Driver not loaded?" % sysfs_sfp_i2c_adapter_path) ++ return None ++ ++ sysfs_sfp_i2c_client_path = "%s/%s-00%s" % (sysfs_sfp_i2c_adapter_path, ++ str(i2c_adapter_id), ++ hex(devid)[-2:]) ++ ++ # If sfp device is not present on bus, Add it ++ if not os.path.exists(sysfs_sfp_i2c_client_path): ++ if port_num in self.qsfp_ports: ++ ret = self._add_new_sfp_device( ++ sysfs_sfp_i2c_adapter_path, devid, self.QSFP_DEVICE_TYPE) ++ else: ++ ret = self._add_new_sfp_device( ++ sysfs_sfp_i2c_adapter_path, devid, self.SFP_DEVICE_TYPE) ++ if ret != 0: ++ print("Error adding sfp device") ++ return None ++ ++ sysfs_sfp_i2c_client_eeprom_path = "%s/eeprom" % sysfs_sfp_i2c_client_path ++ ++ return sysfs_sfp_i2c_client_eeprom_path ++ ++ def _read_eeprom_specific_bytes(self, sysfsfile_eeprom, offset, num_bytes): ++ eeprom_raw = [] ++ for i in range(0, num_bytes): ++ eeprom_raw.append("0x00") ++ ++ rv, raw = self._sfp_read_file_path(sysfsfile_eeprom, offset, num_bytes) ++ if rv is False: ++ return None ++ ++ try: ++ for n in range(0, num_bytes): ++ eeprom_raw[n] = hex(raw[n])[2:].zfill(2) ++ except Exception: ++ return None ++ ++ return eeprom_raw ++ ++ def get_eeprom_dom_raw(self, port_num): ++ if port_num in self.qsfp_ports: ++ # QSFP DOM EEPROM is also at addr 0x50 and thus also stored in eeprom_ifraw ++ return None ++ # Read dom eeprom at addr 0x51 ++ return self._read_eeprom_devid(port_num, self.IDENTITY_EEPROM_ADDR, 256) ++ ++ def get_presence(self, port_num): ++ # Check for invalid port_num ++ if port_num < self.port_start or port_num > self.port_end: ++ return False ++ ++ presence_path = "/sys/wb_plat/sff/sff%d/present" % port_num ++ ++ try: ++ with open(presence_path, "rb") as data: ++ presence_data = data.read(2) ++ if presence_data == "": ++ return False ++ result = int(presence_data, 16) ++ except IOError: ++ return False ++ ++ if result == 1: ++ return True ++ return False ++ ++ def get_low_power_mode(self, port_num): ++ # Check for invalid port_num ++ ++ return True ++ ++ def set_low_power_mode(self, port_num, lpmode): ++ # Check for invalid port_num ++ ++ return True ++ ++ def reset(self, port_num): ++ # Check for invalid port_num ++ if port_num < self.port_start or port_num > self.port_end: ++ return False ++ ++ return True ++ ++ def get_transceiver_change_event(self, timeout=0): ++ return False, {} ++ ++ def get_highest_temperature(self): ++ offset = 0 ++ hightest_temperature = -9999 ++ ++ presence_flag = False ++ read_eeprom_flag = False ++ temperature_valid_flag = False ++ ++ for port in range(49, self.PORTS_IN_BLOCK): ++ if self.get_presence(port) is False: ++ continue ++ ++ presence_flag = True ++ ++ if port in self.qsfp_ports: ++ offset = 22 ++ else: ++ offset = 96 ++ ++ eeprom_path = self._get_port_eeprom_path(port, 0x50) ++ try: ++ with open(eeprom_path, mode="rb", buffering=0) as eeprom: ++ read_eeprom_flag = True ++ eeprom_raw = self._read_eeprom_specific_bytes(eeprom, offset, 2) ++ msb = int(eeprom_raw[0], 16) ++ lsb = int(eeprom_raw[1], 16) ++ ++ result = (msb << 8) | (lsb & 0xff) ++ result = float(result / 256.0) ++ if -50 <= result <= 200: ++ temperature_valid_flag = True ++ hightest_temperature = max(hightest_temperature, result) ++ except Exception: ++ print(traceback.format_exc()) ++ ++ # all port not presence ++ if presence_flag is False: ++ hightest_temperature = -10000 ++ ++ # all port read eeprom fail ++ elif read_eeprom_flag is False: ++ hightest_temperature = -9999 ++ ++ # all port temperature invalid ++ elif read_eeprom_flag is True and temperature_valid_flag is False: ++ hightest_temperature = -10000 ++ ++ hightest_temperature = round(hightest_temperature, 2) ++ ++ return hightest_temperature +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/ssd_util.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/ssd_util.py +new file mode 100755 +index 000000000..89d3ccd77 +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/ssd_util.py +@@ -0,0 +1,311 @@ ++# ++# ssd_util.py ++# ++# Generic implementation of the SSD health API ++# SSD models supported: ++# - InnoDisk ++# - StorFly ++# - Virtium ++ ++try: ++ import re ++ import os ++ import subprocess ++ from sonic_platform_base.sonic_ssd.ssd_base import SsdBase ++except ImportError as e: ++ raise ImportError (str(e) + "- required module not found") ++ ++SMARTCTL = "smartctl {} -a" ++INNODISK = "iSmart -d {}" ++VIRTIUM = "SmartCmd -m {}" ++DISK_LIST_CMD = "fdisk -l -o Device" ++DISK_FREE_CMD = "df -h" ++MOUNT_CMD = "mount" ++ ++NOT_AVAILABLE = "N/A" ++PE_CYCLE = 3000 ++FAIL_PERCENT = 95 ++ ++# Set Vendor Specific IDs ++INNODISK_HEALTH_ID = 169 ++INNODISK_TEMPERATURE_ID = 194 ++ ++class SsdUtil(SsdBase): ++ """ ++ Generic implementation of the SSD health API ++ """ ++ model = NOT_AVAILABLE ++ serial = NOT_AVAILABLE ++ firmware = NOT_AVAILABLE ++ temperature = NOT_AVAILABLE ++ health = NOT_AVAILABLE ++ remaining_life = NOT_AVAILABLE ++ sata_rate = NOT_AVAILABLE ++ ssd_info = NOT_AVAILABLE ++ vendor_ssd_info = NOT_AVAILABLE ++ ++ def __init__(self, diskdev): ++ self.vendor_ssd_utility = { ++ "Generic" : { "utility" : SMARTCTL, "parser" : self.parse_generic_ssd_info }, ++ "InnoDisk" : { "utility" : INNODISK, "parser" : self.parse_innodisk_info }, ++ "M.2" : { "utility" : INNODISK, "parser" : self.parse_innodisk_info }, ++ "StorFly" : { "utility" : VIRTIUM, "parser" : self.parse_virtium_info }, ++ "Virtium" : { "utility" : VIRTIUM, "parser" : self.parse_virtium_info } ++ } ++ ++ """ ++ The dict model_attr keys relate the vendors ++ LITEON : "ER2-GD","AF2MA31DTDLT" ++ Intel : "SSDSCKKB" ++ SMI : "SM619GXC" ++ samsung: "MZNLH" ++ ADATA : "IM2S3134N" ++ """ ++ self.model_attr = { ++ "ER2-GD" : { "temperature" : "\n190\s+(.+?)\n", "remainingLife" : "\n202\s+(.+?)\n" }, ++ "AF2MA31DTDLT" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n202\s+(.+?)\n" }, ++ "SSDSCK" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n233\s+(.+?)\n" }, ++ "SM619GXC" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n169\s+(.+?)\n" }, ++ "MZNLH" : { "temperature" : "\n190\s+(.+?)\n", "remainingLife" : "\n245\s+(.+?)\n" }, ++ "IM2S3134N" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n231\s+(.+?)\n" } ++ } ++ ++ self.key_list = list(self.model_attr.keys()) ++ self.attr_info_rule = "[\s\S]*SMART Attributes Data Structure revision number: 1|SMART Error Log Version[\s\S]*" ++ self.dev = diskdev ++ # Generic part ++ self.fetch_generic_ssd_info(diskdev) ++ self.parse_generic_ssd_info() ++ self.fetch_vendor_ssd_info(diskdev, "Generic") ++ ++ # Known vendor part ++ if self.model: ++ model_short = self.model.split()[0] ++ if model_short in self.vendor_ssd_utility: ++ self.fetch_vendor_ssd_info(diskdev, model_short) ++ self.parse_vendor_ssd_info(model_short) ++ else: ++ # No handler registered for this disk model ++ pass ++ else: ++ # Failed to get disk model ++ self.model = "Unknown" ++ ++ def _execute_shell(self, cmd): ++ process = subprocess.Popen(cmd.split(), universal_newlines=True, stdout=subprocess.PIPE) ++ output, error = process.communicate() ++ exit_code = process.returncode ++ if exit_code: ++ return None ++ return output ++ ++ def _parse_re(self, pattern, buffer): ++ res_list = re.findall(pattern, str(buffer)) ++ return res_list[0] if res_list else NOT_AVAILABLE ++ ++ def fetch_generic_ssd_info(self, diskdev): ++ self.ssd_info = self._execute_shell(self.vendor_ssd_utility["Generic"]["utility"].format(diskdev)) ++ ++ # Health and temperature values may be overwritten with vendor specific data ++ def parse_generic_ssd_info(self): ++ if "nvme" in self.dev: ++ self.model = self._parse_re('Model Number:\s*(.+?)\n', self.ssd_info) ++ ++ health_raw = self._parse_re('Percentage Used\s*(.+?)\n', self.ssd_info) ++ if health_raw == NOT_AVAILABLE: ++ self.health = NOT_AVAILABLE ++ else: ++ health_raw = health_raw.split()[-1] ++ self.health = 100 - float(health_raw.strip('%')) ++ ++ temp_raw = self._parse_re('Temperature\s*(.+?)\n', self.ssd_info) ++ if temp_raw == NOT_AVAILABLE: ++ self.temperature = NOT_AVAILABLE ++ else: ++ temp_raw = temp_raw.split()[-2] ++ self.temperature = float(temp_raw) ++ else: ++ self.model = self._parse_re('Device Model:\s*(.+?)\n', self.ssd_info) ++ model_key = "" ++ for key in self.key_list: ++ if re.search(key, self.model): ++ model_key = key ++ break ++ if model_key != "": ++ self.remaining_life = self._parse_re(self.model_attr[model_key]["remainingLife"], re.sub(self.attr_info_rule,"",self.ssd_info)).split()[2] ++ self.temperature = self._parse_re(self.model_attr[model_key]["temperature"], re.sub(self.attr_info_rule,"",self.ssd_info)).split()[8] ++ self.health = self.remaining_life ++ # Get the LITEON ssd health value by (PE CYCLE - AVG ERASE CYCLE )/(PE CYCLE) ++ if model_key in ["ER2-GD", "AF2MA31DTDLT"]: ++ avg_erase = int(self._parse_re('\n173\s+(.+?)\n' ,re.sub(self.attr_info_rule,"",self.ssd_info)).split()[-1]) ++ self.health = int(round((PE_CYCLE - avg_erase)/PE_CYCLE*100,0)) ++ if self.remaining_life != NOT_AVAILABLE and int(self.remaining_life) < FAIL_PERCENT: ++ self.remaining_life = "Fail" ++ self.sata_rate = self._parse_re('SATA Version is:.*current: (.+?)\)\n', self.ssd_info) ++ self.serial = self._parse_re('Serial Number:\s*(.+?)\n', self.ssd_info) ++ self.firmware = self._parse_re('Firmware Version:\s*(.+?)\n', self.ssd_info) ++ ++ def parse_innodisk_info(self): ++ if self.vendor_ssd_info: ++ self.health = self._parse_re('Health:\s*(.+?)%', self.vendor_ssd_info) ++ self.temperature = self._parse_re('Temperature\s*\[\s*(.+?)\]', self.vendor_ssd_info) ++ else: ++ if self.health == NOT_AVAILABLE: ++ health_raw = self.parse_id_number(INNODISK_HEALTH_ID) ++ self.health = health_raw.split()[-1] ++ if self.temperature == NOT_AVAILABLE: ++ temp_raw = self.parse_id_number(INNODISK_TEMPERATURE_ID) ++ self.temperature = temp_raw.split()[-6] ++ ++ def parse_virtium_info(self): ++ if self.vendor_ssd_info: ++ self.temperature = self._parse_re('Temperature_Celsius\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info) ++ nand_endurance = self._parse_re('NAND_Endurance\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info) ++ avg_erase_count = self._parse_re('Average_Erase_Count\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info) ++ try: ++ self.health = 100 - (float(avg_erase_count) * 100 / float(nand_endurance)) ++ except (ValueError, ZeroDivisionError): ++ # Invalid avg_erase_count or nand_endurance. ++ pass ++ ++ def fetch_vendor_ssd_info(self, diskdev, model): ++ self.vendor_ssd_info = self._execute_shell(self.vendor_ssd_utility[model]["utility"].format(diskdev)) ++ ++ def parse_vendor_ssd_info(self, model): ++ self.vendor_ssd_utility[model]["parser"]() ++ ++ def check_readonly2(self, partition, filesystem): ++ # parse mount cmd output info ++ mount_info = self._execute_shell(MOUNT_CMD) ++ for line in mount_info.split('\n'): ++ column_list = line.split() ++ if line == '': ++ continue ++ if column_list[0] == partition and column_list[2] == filesystem: ++ if column_list[5].split(',')[0][1:] == "ro": ++ return partition ++ else: ++ return NOT_AVAILABLE ++ return NOT_AVAILABLE ++ ++ def check_readonly(self, partition, filesystem): ++ ret = os.access(filesystem, os.W_OK) ++ if ret == False: ++ return partition ++ else: ++ return NOT_AVAILABLE ++ ++ def get_health(self): ++ """ ++ Retrieves current disk health in percentages ++ ++ Returns: ++ A float number of current ssd health ++ e.g. 83.5 ++ """ ++ return float(self.health) ++ ++ def get_temperature(self): ++ """ ++ Retrieves current disk temperature in Celsius ++ ++ Returns: ++ A float number of current temperature in Celsius ++ e.g. 40.1 ++ """ ++ return float(self.temperature) ++ ++ def get_model(self): ++ """ ++ Retrieves model for the given disk device ++ ++ Returns: ++ A string holding disk model as provided by the manufacturer ++ """ ++ return self.model ++ ++ def get_firmware(self): ++ """ ++ Retrieves firmware version for the given disk device ++ ++ Returns: ++ A string holding disk firmware version as provided by the manufacturer ++ """ ++ return self.firmware ++ ++ def get_serial(self): ++ """ ++ Retrieves serial number for the given disk device ++ ++ Returns: ++ A string holding disk serial number as provided by the manufacturer ++ """ ++ return self.serial ++ def get_sata_rate(self): ++ """ ++ Retrieves SATA rate for the given disk device ++ Returns: ++ A string holding current SATA rate as provided by the manufacturer ++ """ ++ return self.sata_rate ++ def get_remaining_life(self): ++ """ ++ Retrieves remaining life for the given disk device ++ Returns: ++ A string holding disk remaining life as provided by the manufacturer ++ """ ++ return self.remaining_life ++ def get_vendor_output(self): ++ """ ++ Retrieves vendor specific data for the given disk device ++ ++ Returns: ++ A string holding some vendor specific disk information ++ """ ++ return self.vendor_ssd_info ++ ++ def parse_id_number(self, id): ++ return self._parse_re('{}\s*(.+?)\n'.format(id), self.ssd_info) ++ ++ def get_readonly_partition(self): ++ """ ++ Check the partition mount filesystem is readonly status,then output the result. ++ Returns: ++ The readonly partition list ++ """ ++ ++ ro_partition_list = [] ++ partition_list = [] ++ ++ # parse fdisk cmd output info ++ disk_info = self._execute_shell(DISK_LIST_CMD) ++ begin_flag = False ++ for line in disk_info.split('\n'): ++ if line == "Device": ++ begin_flag = True ++ continue ++ if begin_flag: ++ if line != "": ++ partition_list.append(line) ++ else: ++ break ++ ++ # parse df cmd output info ++ disk_free = self._execute_shell(DISK_FREE_CMD) ++ disk_dict = {} ++ line_num = 0 ++ for line in disk_free.split('\n'): ++ line_num = line_num + 1 ++ if line_num == 1 or line == "": ++ continue ++ column_list = line.split() ++ disk_dict[column_list[0]] = column_list[5] ++ ++ # get partition which is readonly ++ for partition in partition_list: ++ if partition in disk_dict: ++ ret = self.check_readonly(partition, disk_dict[partition]) ++ if (ret != NOT_AVAILABLE): ++ ro_partition_list.append(ret) ++ ++ return ro_partition_list +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pmon_daemon_control.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pmon_daemon_control.json +new file mode 100644 +index 000000000..94592fa8c +--- /dev/null ++++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pmon_daemon_control.json +@@ -0,0 +1,3 @@ ++{ ++ "skip_ledd": true ++} +diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/system_health_monitoring_config.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/system_health_monitoring_config.json +new file mode 100755 +index 000000000..e69de29bb +diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk +index 6c668ee68..44a722e47 100755 +--- a/platform/broadcom/one-image.mk ++++ b/platform/broadcom/one-image.mk +@@ -81,6 +81,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ + $(RAGILE_RA_B6910_64C_PLATFORM_MODULE) \ + $(RAGILE_RA_B6510_32C_PLATFORM_MODULE) \ + $(RAGILE_RA_B6920_4S_PLATFORM_MODULE) \ ++ $(MICAS_M2_W6510_48V8C_PLATFORM_MODULE) \ + $(NOKIA_IXR7250_PLATFORM_MODULE) \ + $(TENCENT_TCS8400_PLATFORM_MODULE) \ + $(TENCENT_TCS9400_PLATFORM_MODULE) +diff --git a/platform/broadcom/platform-modules-micas.dep b/platform/broadcom/platform-modules-micas.dep +new file mode 100644 +index 000000000..6ae59a668 +--- /dev/null ++++ b/platform/broadcom/platform-modules-micas.dep +@@ -0,0 +1,9 @@ ++MPATH := $($(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_SRC_PATH) ++DEP_FILES := $(SONIC_COMMON_FILES_LIST) platform/broadcom/platform-modules-micas.mk platform/broadcom/platform-modules-micas.dep ++DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) ++DEP_FILES += $(addprefix $(MPATH)/,$(shell cd $(MPATH) && git ls-files)) ++ ++ ++$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_CACHE_MODE := GIT_CONTENT_SHA ++$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) ++$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_DEP_FILES := $(DEP_FILES) +diff --git a/platform/broadcom/platform-modules-micas.mk b/platform/broadcom/platform-modules-micas.mk +new file mode 100644 +index 000000000..7f2a95cad +--- /dev/null ++++ b/platform/broadcom/platform-modules-micas.mk +@@ -0,0 +1,10 @@ ++## M2-W6510-48V8C ++MICAS_M2_W6510_48V8C_PLATFORM_MODULE_VERSION = 1.0 ++export MICAS_M2_W6510_48V8C_PLATFORM_MODULE_VERSION ++ ++MICAS_M2_W6510_48V8C_PLATFORM_MODULE = platform-modules-micas-m2-w6510-48v8c_$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE_VERSION)_amd64.deb ++$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-micas ++$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) $(PDDF_PLATFORM_MODULE) ++$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_PLATFORM = x86_64-micas_m2-w6510-48v8c-r0 ++SONIC_DPKG_DEBS += $(MICAS_M2_W6510_48V8C_PLATFORM_MODULE) ++SONIC_STRETCH_DEBS += $(MICAS_M2_W6510_48V8C_PLATFORM_MODULE) +diff --git a/platform/broadcom/rules.dep b/platform/broadcom/rules.dep +index 47f7f849e..2c8a29bf4 100644 +--- a/platform/broadcom/rules.dep ++++ b/platform/broadcom/rules.dep +@@ -15,6 +15,7 @@ include $(PLATFORM_PATH)/platform-modules-quanta.dep + include $(PLATFORM_PATH)/platform-modules-juniper.dep + include $(PLATFORM_PATH)/platform-modules-ragile.dep + include $(PLATFORM_PATH)/platform-modules-ruijie.dep ++include $(PLATFORM_PATH)/platform-modules-micas.dep + include $(PLATFORM_PATH)/platform-modules-brcm-xlr-gts.dep + include $(PLATFORM_PATH)/docker-syncd-brcm.dep + include $(PLATFORM_PATH)/docker-syncd-brcm-rpc.dep +diff --git a/platform/broadcom/rules.mk b/platform/broadcom/rules.mk +index 5fa7bfca7..df56a0c8d 100755 +--- a/platform/broadcom/rules.mk ++++ b/platform/broadcom/rules.mk +@@ -17,6 +17,7 @@ include $(PLATFORM_PATH)/platform-modules-juniper.mk + include $(PLATFORM_PATH)/platform-modules-ragile.mk + #include $(PLATFORM_PATH)/platform-modules-tencent.mk + include $(PLATFORM_PATH)/docker-syncd-brcm.mk ++include $(PLATFORM_PATH)/platform-modules-micas.mk + include $(PLATFORM_PATH)/docker-syncd-brcm-rpc.mk + include $(PLATFORM_PATH)/docker-saiserver-brcm.mk + ifeq ($(INCLUDE_PDE), y) +diff --git a/platform/broadcom/sonic-platform-modules-micas/LICENSE b/platform/broadcom/sonic-platform-modules-micas/LICENSE +new file mode 100644 +index 000000000..5681cac34 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/LICENSE +@@ -0,0 +1,14 @@ ++Copyright (C) 2016 Microsoft, Inc ++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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/Makefile +new file mode 100755 +index 000000000..385dae088 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/Makefile +@@ -0,0 +1,41 @@ ++PWD = $(shell pwd) ++CC ?=gcc ++INSTALL_MOD_DIR ?=extra ++KVERSION ?= $(shell uname -r) ++KERNEL_SRC ?= /lib/modules/$(KVERSION) ++EXTRA_CFLAGS:= -I$(M)/include ++EXTRA_CFLAGS+= -Wall ++SUB_BUILD_DIR = $(PWD)/build ++DIR_KERNEL_SRC = $(PWD)/modules ++SCRIPT_DIR = $(PWD)/script ++SERVICE_DIR = $(PWD)/service ++BLACK_DRIVER_CONF_DIR = $(PWD)/modprobe_conf ++ ++app_dir = $(PWD)/app ++app_build_dir = $(app_dir)/build ++modules_build_dir = $(DIR_KERNEL_SRC)/build ++ ++INSTALL_MODULE_DIR = $(SUB_BUILD_DIR)/$(KERNEL_SRC)/$(INSTALL_MOD_DIR) ++INSTALL_SCRIPT_DIR = $(SUB_BUILD_DIR)/usr/local/bin ++INSTALL_SERVICE_DIR = $(SUB_BUILD_DIR)/lib/systemd/system ++INSTALL_LIB_DIR = $(SUB_BUILD_DIR)/usr/lib/python3/dist-packages ++INSTALL_BLACK_DRIVER = $(SUB_BUILD_DIR)/etc/modprobe.d ++ ++all: ++ $(MAKE) -C $(app_dir) ++ $(MAKE) -C $(DIR_KERNEL_SRC) ++ @if [ ! -d ${INSTALL_MODULE_DIR} ]; then mkdir -p ${INSTALL_MODULE_DIR} ;fi ++ @if [ ! -d ${INSTALL_SCRIPT_DIR} ]; then mkdir -p ${INSTALL_SCRIPT_DIR} ;fi ++ @if [ ! -d ${INSTALL_SERVICE_DIR} ]; then mkdir -p ${INSTALL_SERVICE_DIR} ;fi ++ @if [ ! -d ${INSTALL_LIB_DIR} ]; then mkdir -p ${INSTALL_LIB_DIR} ;fi ++ @if [ -d $(PWD)/lib/ ]; then cp -r $(PWD)/lib/* ${INSTALL_LIB_DIR} ;fi ++ @if [ -d $(PWD)/sonic_platform/ ]; then cp -rf $(PWD)/sonic_platform ${INSTALL_LIB_DIR} ;fi ++ cp -r $(modules_build_dir)/*.ko $(INSTALL_MODULE_DIR) ++ cp -r $(app_dir)/build/app/* $(INSTALL_SCRIPT_DIR) ++ cp -r $(SCRIPT_DIR)/* $(INSTALL_SCRIPT_DIR) ++ cp -r $(SERVICE_DIR)/* $(INSTALL_SERVICE_DIR) ++ @if [ -d $(INSTALL_SCRIPT_DIR) ]; then chmod +x $(INSTALL_SCRIPT_DIR)/* ;fi ++ @if [ ! -d ${INSTALL_BLACK_DRIVER} ]; then mkdir -p ${INSTALL_BLACK_DRIVER} ;fi ++ cp -r $(BLACK_DRIVER_CONF_DIR)/* $(INSTALL_BLACK_DRIVER) ++clean: ++ rm -rf $(SUB_BUILD_DIR) +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/Makefile +new file mode 100644 +index 000000000..25ba3c5a9 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/app/Makefile +@@ -0,0 +1,25 @@ ++pes_parent_dir:=$(shell pwd)/$(lastword $(MAKEFILE_LIST)) ++pes_parent_dir:=$(shell dirname $(pes_parent_dir)) ++ ++SUBDIRS=$(shell ls -l | grep ^d | awk '{if($$9 != "build") print $$9}') ++INC = -I./inc ++ ++COMMON_OUT_PUT := $(shell pwd)/build ++common_out_put_dir := $(COMMON_OUT_PUT)/app ++common_module_dir := $(COMMON_OUT_PUT)/module/ ++export common_out_put_dir common_module_dir ++ ++all : CHECK $(SUBDIRS) ++CHECK : ++ @echo $(pes_parent_dir) ++ ++$(SUBDIRS):ECHO ++ #@echo $@ ++ make -C $@ ++ ++ECHO: ++ @echo $(SUBDIRS) ++ ++.PHONY : clean ++clean : ++ -rm -rf $(COMMON_OUT_PUT) +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/Makefile +new file mode 100644 +index 000000000..e4078716e +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/Makefile +@@ -0,0 +1,30 @@ ++top_srcdir:=$(shell pwd) ++#include $(top_srcdir)/Rules.mk ++DIR=$(shell pwd) ++BUILD_OUTPUT=$(DIR)/tmp ++SRCS=$(wildcard *.c) ++OBJS=$(patsubst %.c, $(BUILD_OUTPUT)/%.o, $(SRCS)) ++DEPS=$(patsubst %.o, %.d, $(OBJS)) ++CFLAGS+=-Wall -W -g -I$(DIR)/include ++LDFLAGS= ++PROGRAM=dfd_debug ++ ++.PHONY: all ++ ++all:$(OBJS) ++ $(CC) $(OBJS) $(LDFLAGS) -o $(BUILD_OUTPUT)/$(PROGRAM) ++ @if [ ! -d ${common_out_put_dir} ]; then mkdir -p ${common_out_put_dir} ;fi ++ cp -p $(BUILD_OUTPUT)/$(PROGRAM) $(common_out_put_dir) ++ ++$(OBJS):$(SRCS) ++ @if [ ! -d ${BUILD_OUTPUT} ]; then mkdir -p ${BUILD_OUTPUT} ;fi ++ $(CC) -c $(CFLAGS) $(INCLUDE) $(*F).c -o $@ ++ ++.PHONY: install ++install: ++ @mkdir -p $(common_out_put_dir) ++ cp -p $(BUILD_OUTPUT)/$(PROGRAM) $(common_out_put_dir) ++ ++rebuild: clean all ++clean: ++ @rm -rf $(BUILD_OUTPUT)/* +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_debug.c b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_debug.c +new file mode 100644 +index 000000000..93ed6066e +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_debug.c +@@ -0,0 +1,43 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "dfd_utest.h" ++ ++int g_dfd_debug_sw = 0; ++int g_dfd_debugpp_sw = 0; ++ ++void dfd_debug_set_init(void) ++{ ++ FILE *fp; ++ char buf[10]; ++ ++ mem_clear(buf, sizeof(buf)); ++ fp = fopen(DFD_DEBUGP_DEBUG_FILE, "r"); ++ if (fp != NULL) { ++ ++ g_dfd_debug_sw = 1; ++ fclose(fp); ++ } ++ ++ fp = fopen(DFD_DEBUGPP_DEBUG_FILE, "r"); ++ if (fp != NULL) { ++ ++ g_dfd_debugpp_sw = 1; ++ fclose(fp); ++ } ++ ++ return; ++} ++ ++int main(int argc, char* argv[]) ++{ ++ dfd_debug_set_init(); ++ dfd_utest_cmd_main(argc, argv); ++ ++ return 0; ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.c b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.c +new file mode 100644 +index 000000000..c82b0baad +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.c +@@ -0,0 +1,2121 @@ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "dfd_utest.h" ++ ++#define DFD_UTEST_MAX_RDWR_NUM (256) ++#define DFD_UTEST_DEFAULT_WR_NUM (1) ++ ++#define DEV_MEM_NAME "/dev/mem" ++#define DEV_KMEM_NAME "/dev/kmem" ++ ++#define WIDTH_1Byte (1) ++#define WIDTH_2Byte (2) ++#define WIDTH_4Byte (4) ++#define DFD_UTEST_MAX_BIT_WIDTH (4) ++ ++struct phydev_user_info { ++ int phy_index; ++ uint32_t regnum; ++ uint32_t regval; ++}; ++ ++#define CMD_PHY_LIST _IOR('P', 0, struct phydev_user_info) ++#define CMD_PHY_READ _IOR('P', 1, struct phydev_user_info) ++#define CMD_PHY_WRITE _IOR('P', 2, struct phydev_user_info) ++ ++struct mdio_dev_user_info { ++ int mdio_index; ++ int phyaddr; ++ uint32_t regnum; ++ uint32_t regval; ++}; ++ ++#define CMD_MDIO_LIST _IOR('M', 0, struct mdio_dev_user_info) ++#define CMD_MDIO_READ _IOR('M', 1, struct mdio_dev_user_info) ++#define CMD_MDIO_WRITE _IOR('M', 2, struct mdio_dev_user_info) ++ ++#ifdef DFD_UTEST_ITEM ++#undef DFD_UTEST_ITEM ++#endif ++#define DFD_UTEST_ITEM(_id, _type_str, _help_info, _help_info_detail) {_id, #_type_str, dfd_utest_##_type_str, _help_info, _help_info_detail}, ++static dfd_utest_t g_dfd_unit_test[] = { ++ DFD_UTEST_ITEM_ALL ++}; ++ ++static int g_sys_page_size; ++#define SYS_PAGE_SIZE g_sys_page_size ++#define SYS_PAGE_MASK (~(SYS_PAGE_SIZE - 1)) ++ ++void dfd_utest_print_cmd(int argc, char* argv[]) ++{ ++ int i; ++ ++ for (i = 1; i < argc; i++) { ++ if (i != 1) { ++ printf(" "); ++ } ++ printf("%s", argv[i]); ++ } ++ return; ++} ++ ++void dfd_utest_print_all_help(void) ++{ ++ int i, tbl_size; ++ ++ tbl_size = sizeof(g_dfd_unit_test) / sizeof(g_dfd_unit_test[0]); ++ ++ for (i = 0; i < tbl_size; i++) { ++ printf("%-20s\t\t\t%s\r\n", g_dfd_unit_test[i].type_str, g_dfd_unit_test[i].help_info); ++ } ++ ++ return; ++} ++ ++void dfd_utest_printf_single_help(int utest_type) ++{ ++ int i, tbl_size; ++ ++ tbl_size = sizeof(g_dfd_unit_test) / sizeof(g_dfd_unit_test[0]); ++ for (i = 0; i < tbl_size; i++) { ++ if (g_dfd_unit_test[i].utest_type == utest_type) { ++ printf("%-20s\t\t\t%s\r\n", g_dfd_unit_test[i].type_str, g_dfd_unit_test[i].help_info_detail); ++ return; ++ } ++ } ++ ++ DFD_DEBUG_DBG("type: %d not match.\n", utest_type); ++ return; ++ ++} ++ ++void dfd_utest_printf_reg(uint8_t *buf, int buf_len, uint32_t offset_addr) ++{ ++ int i, j, tmp; ++ ++ j = offset_addr % 16; ++ tmp = j; ++ offset_addr -= j; ++ printf("\n "); ++ ++ for (i = 0; i < 16; i++) { ++ printf("%2x ", i); ++ } ++ ++ for (i = 0; i < buf_len + j; i++) { ++ if ((i % 16) == 0) { ++ printf("\n0x%08x ", offset_addr); ++ offset_addr = offset_addr + 16; ++ } ++ if (tmp) { ++ printf(" "); ++ tmp--; ++ } else { ++ printf("%02x ", buf[i-j]); ++ } ++ } ++ ++ printf("\n"); ++ return; ++} ++ ++#define I2C_RETRIES 0x0701 ++#define I2C_TIMEOUT 0x0702 ++#define I2C_RDWR 0x0707 ++ ++#define I2C_SLAVE 0x0703 /* Use this slave address */ ++ ++#define I2C_SLAVE_FORCE 0x0706 /* Use this slave address, even if it ++ is already in use by a driver! */ ++#define I2C_PEC 0x0708 /* != 0 to use PEC with SMBus */ ++#define I2C_SMBUS 0x0720 /* SMBus transfer */ ++ ++struct i2c_msg ++{ ++ unsigned short addr; ++ unsigned short flags; ++#define I2C_M_TEN 0x0010 ++#define I2C_M_RD 0x0001 ++ unsigned short len; ++ unsigned char *buf; ++}; ++ ++struct i2c_rdwr_ioctl_data ++{ ++ struct i2c_msg *msgs; ++ int nmsgs; ++ ++}; ++ ++#define DFD_I2C_SHORT_ADDR_TYPE 0 ++#define DFD_I2C_RETRY_SLEEP_TIME (10000) /* 10ms */ ++#define DFD_I2C_RETRY_TIME (50000 / DFD_I2C_RETRY_SLEEP_TIME) ++/* i2c_smbus_xfer read or write markers */ ++#define I2C_SMBUS_READ 1 ++#define I2C_SMBUS_WRITE 0 ++ ++/* SMBus transaction types (size parameter in the above functions) ++ Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */ ++#define I2C_SMBUS_QUICK 0 ++#define I2C_SMBUS_BYTE 1 ++#define I2C_SMBUS_BYTE_DATA 2 ++#define I2C_SMBUS_WORD_DATA 3 ++#define I2C_SMBUS_PROC_CALL 4 ++#define I2C_SMBUS_BLOCK_DATA 5 ++#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 ++#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ ++#define I2C_SMBUS_I2C_BLOCK_DATA 8 ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,36) ++/* fix tjm */ ++ ++#ifndef __ASSEMBLY__ ++/* ++ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the ++ * header files exported to user space ++ */ ++typedef __signed__ char __s8; ++typedef unsigned char __u8; ++ ++typedef __signed__ short __s16; ++typedef unsigned short __u16; ++ ++typedef __signed__ int __s32; ++typedef unsigned int __u32; ++ ++typedef __signed__ long __s64; ++typedef unsigned long __u64; ++ ++#endif /* __ASSEMBLY__ */ ++ ++#else ++/* do noting add tjm */ ++#endif ++ ++/* ++ * Data for SMBus Messages ++ */ ++#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ ++union i2c_smbus_data { ++ __u8 byte; ++ __u16 word; ++ __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */ ++ /* and one more for user-space compatibility */ ++}; ++ ++/* This is the structure as used in the I2C_SMBUS ioctl call */ ++struct i2c_smbus_ioctl_data { ++ __u8 read_write; ++ __u8 command; ++ __u32 size; ++ union i2c_smbus_data *data; ++}; ++int32_t dfd_read_port_i2c_one_time_smbus(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, ++ uint8_t *recv_buf, int32_t size, int addr_type) ++{ ++ union i2c_smbus_data data; ++ struct i2c_smbus_ioctl_data ioctl_data; ++ unsigned long addr = dev_addr; ++ int fd; ++ int rc; ++ int rv; ++ int i; ++ ++ mem_clear(&ioctl_data, sizeof(struct i2c_smbus_ioctl_data)); ++ if (i2c_name == NULL || recv_buf == NULL) { ++ DFD_DEBUG_ERROR("i2c_num = NULL, recv_buf = NULL\r\n"); ++ return -1; ++ } ++ ++ DFD_DEBUG_DBG("i2c name: %s, dev_addr: 0x%x, offset_addr: 0x%x, size: %d, addr_type: %d.\n", i2c_name, dev_addr, ++ offset_addr, size, addr_type); ++ ++ rv = 0; ++ fd = open(i2c_name, O_RDWR | O_SYNC); ++ if (fd < 0) { ++ DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); ++ rv = fd; ++ goto err; ++ } ++ if (ioctl(fd, I2C_SLAVE_FORCE , addr) < 0) { ++ DFD_DEBUG_ERROR("ioctl 2C_SLAVE_FORCE %d.\n", errno); ++ rv =-1; ++ goto fail; ++ } ++ for (i = 0 ;i < size; i++) { ++ data.byte = 0; ++ ioctl_data.read_write = I2C_SMBUS_READ; ++ ioctl_data.command = (offset_addr + i); ++ ioctl_data.size = I2C_SMBUS_BYTE_DATA; ++ ioctl_data.data= &data; ++ ++ rc = ioctl(fd, I2C_SMBUS, &ioctl_data); ++ if (rc < 0) { ++ DFD_DEBUG_ERROR("read, I2C_SMBUS failed: %d.\n", errno); ++ rv = -1; ++ goto fail; ++ } ++ *(recv_buf + i) = data.byte; ++ } ++ fail: ++ close(fd); ++ err: ++ return rv; ++ ++} ++ ++int32_t dfd_read_port_i2c_one_time(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, ++ uint8_t *recv_buf, int32_t size, int addr_type) ++{ ++ ++ int32_t fd, rv; ++ struct i2c_rdwr_ioctl_data ioctl_data; ++ struct i2c_msg msgs[2]; ++ uint8_t buf[2]; ++ ++ if (i2c_name == NULL || recv_buf == NULL) { ++ DFD_DEBUG_ERROR("i2c_num = NULL, recv_buf = NULL\r\n"); ++ return -1; ++ } ++ ++ DFD_DEBUG_DBG("i2c name %s, dev_addr 0x%x, offset_addr 0x%x, size %d, addr_type %d.\n", i2c_name, dev_addr, ++ offset_addr, size, addr_type); ++ ++ rv = 0; ++ fd = open(i2c_name, O_RDWR | O_SYNC); ++ if (fd < 0) { ++ DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); ++ return -1; ++ } ++ mem_clear(&ioctl_data, sizeof(ioctl_data)); ++ mem_clear(msgs, sizeof(msgs)); ++ mem_clear(buf, sizeof(buf)); ++ if (ioctl(fd, I2C_SLAVE, dev_addr) < 0) { ++ ++ DFD_DEBUG_ERROR("%s %dioctl fail(ret:%d, errno:%s)!\r\n", __func__ , __LINE__, rv, strerror(errno)); ++ rv = -1; ++ goto fail; ++ } ++ ++ buf[0] = (uint8_t)(offset_addr); ++ msgs[0].addr= dev_addr; ++ msgs[0].len= 2; ++ msgs[0].buf= buf; ++ msgs[1].addr= dev_addr; ++ msgs[1].flags|= I2C_M_RD; ++ msgs[1].len= 1; ++ msgs[1].buf= recv_buf; ++ ioctl_data.nmsgs= 1; ++ ioctl_data.msgs= msgs; ++ ++ rv = ioctl(fd, I2C_RDWR, &ioctl_data); ++ if(rv < 0) { ++ DFD_DEBUG_ERROR("%s %dioctl fail(ret:%d, errno:%s)!\r\n", __func__ , __LINE__, rv, strerror(errno)); ++ goto fail; ++ } ++ ioctl_data.msgs= &msgs[1]; ++ DFD_DEBUG_DBG("ioctlread, return :%d/n", ioctl(fd, I2C_RDWR, &ioctl_data)); ++ DFD_DEBUG_DBG("dfd_read_port_i2c addr: 0x%X, offset: 0x%X, value: 0x%X\n", dev_addr, offset_addr, *recv_buf); ++ fail: ++ close(fd); ++ return rv; ++ ++} ++ ++int32_t dfd_read_port_i2c(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, ++ uint8_t *recv_buf, int32_t size) ++{ ++ int i; ++ int rv; ++ ++ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { ++ rv = dfd_read_port_i2c_one_time_smbus(i2c_name, dev_addr, offset_addr, recv_buf, size, DFD_I2C_SHORT_ADDR_TYPE); ++ if (rv < 0) { ++ DFD_DEBUG_ERROR("(read times %d)i2c name %s, dev_addr 0x%X, offset_addr 0x%X, addr_type %d\n", i, i2c_name, dev_addr, offset_addr, DFD_I2C_SHORT_ADDR_TYPE); ++ usleep(DFD_I2C_RETRY_SLEEP_TIME); ++ continue; ++ } ++ break; ++ } ++ ++ return rv; ++} ++ ++int32_t dfd_write_port_i2c_one_time(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, ++ uint8_t *write_buf, int32_t size,int addr_type) ++{ ++ int32_t fd, rv; ++ int index; ++ struct i2c_smbus_ioctl_data ioctl_data; ++ union i2c_smbus_data data; ++ uint8_t addr_buf[2]; ++ uint8_t write_buf_tmp[256]; ++ ++ if (i2c_name == NULL || write_buf == NULL ) { ++ DFD_DEBUG_ERROR("i2c_num = NULL \r\n"); ++ return -1; ++ } ++ ++ if (size <= 0) { ++ DFD_DEBUG_ERROR("error:size\n"); ++ return -1; ++ } ++ DFD_DEBUG_DBG("i2c name %s, dev_addr 0x%x, offset_addr 0x%x, size %d, addr_type %d\n",i2c_name, dev_addr, ++ offset_addr, size, addr_type); ++ mem_clear(&ioctl_data, sizeof(ioctl_data)); ++ mem_clear(addr_buf, sizeof(addr_buf)); ++ mem_clear(write_buf_tmp, sizeof(write_buf_tmp)); ++ ++ rv = 0; ++ ++ fd = open(i2c_name, O_RDWR | O_SYNC); ++ if (fd < 0) { ++ DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); ++ return -1; ++ } ++ ++ if (ioctl(fd, I2C_SLAVE_FORCE, dev_addr) < 0) { ++ DFD_DEBUG_ERROR("ioctl, I2C_SLAVE failed: %d.\n", errno); ++ rv = -1; ++ goto fail; ++ } ++ ++ for (index = 0; index < size; index++) { ++ data.byte = *(write_buf + index); ++ ioctl_data.read_write = I2C_SMBUS_WRITE; ++ ioctl_data.command = (offset_addr + index); ++ ioctl_data.size = I2C_SMBUS_BYTE_DATA; ++ ioctl_data.data= &data; ++ rv = ioctl(fd, I2C_SMBUS, (unsigned long)&ioctl_data); ++ if(rv < 0) { ++ DFD_DEBUG_ERROR("ioctl fail(ret:%d, errno:%s %d) !\r\n", rv, strerror(errno),errno); ++ break; ++ } ++ DFD_DEBUG_DBG("ret:%d value:0x%02x\n", rv, data.byte); ++ usleep(5000); ++ } ++ ++fail: ++ close(fd); ++ return rv; ++} ++ ++int32_t dfd_write_port_i2c(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, ++ uint8_t *write_buf, int32_t size) ++{ ++ int i; ++ int rv; ++ ++ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { ++ rv = dfd_write_port_i2c_one_time(i2c_name, dev_addr, offset_addr, write_buf,size, DFD_I2C_SHORT_ADDR_TYPE); ++ if (rv < 0) { ++ DFD_DEBUG_ERROR("(write times %d)i2c name %s, dev_addr 0x%X, offset_addr 0x%X, addr_type %d\n", ++ i, i2c_name, dev_addr, offset_addr, DFD_I2C_SHORT_ADDR_TYPE); ++ usleep(DFD_I2C_RETRY_SLEEP_TIME); ++ continue; ++ } ++ break; ++ } ++ ++ return rv; ++} ++ ++static int dfd_read_io_port(uint16_t offset_addr, uint8_t *recv_buf, int32_t size) ++{ ++ int fd; ++ int ret; ++ ++ fd = open("/dev/port", O_RDWR); ++ if (fd < 0) { ++ printf("open failed ret %d.\n", fd); ++ return -1; ++ } ++ ++ ret = lseek(fd, offset_addr, SEEK_SET); ++ if (ret < 0) { ++ printf("lseek failed ret %d.\n", ret); ++ goto exit; ++ } ++ ++ ret = read(fd, recv_buf, size); ++ if (ret != size) { ++ printf("read failed ret %d size %d.\n", ret, size); ++ ret = -1; ++ goto exit; ++ } ++ ++exit: ++ close(fd); ++ return ret; ++} ++ ++static int dfd_write_io_port(uint16_t offset_addr, uint8_t *write_buf, int32_t size) ++{ ++ int fd; ++ int ret; ++ ++ fd = open("/dev/port", O_RDWR); ++ if (fd < 0) { ++ printf("open failed ret %d.\n", fd); ++ return -1; ++ } ++ ++ ret = lseek(fd, offset_addr, SEEK_SET); ++ if (ret < 0) { ++ printf("lseek failed ret %d.\n", ret); ++ goto exit; ++ } ++ ++ ret = write(fd, write_buf, size); ++ if (ret != size) { ++ printf("write failed ret %d size %d.\n", ret, size); ++ ret = -1; ++ goto exit; ++ } ++ ++exit: ++ close(fd); ++ return ret; ++} ++ ++static int dfd_process_mem(char *dev_name, char is_wr, char width, off_t offset, uint8_t *buf, int32_t size) ++{ ++ int mfd, ret = 0; ++ void *base; ++ int i, j; ++ unsigned int val; ++ off_t map_offset; ++ size_t map_size; ++ ++ if (size & (width - 1)) { ++ printf("size %d invalid.\n", size); ++ return -1; ++ } ++ ++ mfd = open(dev_name, O_RDWR); ++ if (mfd < 0) { ++ printf("Cannot open %s.\n", dev_name); ++ return -1; ++ } ++ ++ g_sys_page_size = getpagesize(); ++ map_offset = offset & SYS_PAGE_MASK; ++ map_size = size + offset - map_offset; ++ base = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, mfd, map_offset); ++ if (base == MAP_FAILED) { ++ printf("mmap offset 0x%lx failed error(%s).\n", map_offset, strerror(errno)); ++ close(mfd); ++ return -1; ++ } ++ printf("width %d map_offset 0x%lx, offset 0x%lx, mmap base %p, g_sys_page_size %d\n", ++ width, map_offset, offset, base, g_sys_page_size); ++ ++ if (is_wr) { ++ for (i = 0; i < size; i = i + width) { ++ val = 0; ++ for (j = 0; j < width; j++) { ++ val |= buf[i + j] << (8 * j); ++ } ++ switch (width) { ++ case 1: ++ *((volatile unsigned char*)(base + i + offset - map_offset)) = val; ++ break; ++ case 2: ++ *((volatile unsigned short*)(base + i + offset - map_offset)) = val; ++ break; ++ case 4: ++ *((volatile unsigned int*)(base + i + offset - map_offset)) = val; ++ break; ++ default: ++ ret = -1; ++ printf("Not support width %d.\n", width); ++ goto exit; ++ } ++ } ++ } else { ++ for (i = 0; i < size; i = i + width) { ++ switch (width) { ++ case 1: ++ val = *((volatile unsigned char*)(base + i + offset - map_offset)); ++ break; ++ case 2: ++ val = *((volatile unsigned short*)(base + i + offset - map_offset)); ++ break; ++ case 4: ++ val = *((volatile unsigned int*)(base + i + offset - map_offset)); ++ break; ++ default: ++ ret = -1; ++ printf("Not support width %d.\n", width); ++ goto exit; ++ } ++ for (j = 0; j < width; j++) { ++ buf[i + j] = (val >> (8 * j)) & 0xff; ++ } ++ } ++ } ++exit: ++ munmap(base, map_size); ++ close(mfd); ++ return ret; ++} ++ ++int32_t dfd_i2c_gen_read_one_time(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, ++ uint32_t offset_addr, uint8_t *recv_buf, int32_t rd_len) ++{ ++ int32_t fd, rv, i; ++ struct i2c_rdwr_ioctl_data ioctl_data; ++ struct i2c_msg msgs[2]; ++ uint8_t buf[DFD_UTEST_MAX_BIT_WIDTH]; ++ ++ fd = open(i2c_path, O_RDWR | O_SYNC); ++ if (fd < 0) { ++ DFD_DEBUG_ERROR("i2c open fail fd:%d\n", fd); ++ return -1; ++ } ++ mem_clear(&ioctl_data, sizeof(ioctl_data)); ++ mem_clear(msgs, sizeof(msgs)); ++ mem_clear(buf, sizeof(buf)); ++ ++ i = 0; ++ ++ switch (addr_bitwidth) { ++ case WIDTH_4Byte: ++ buf[i++] = (offset_addr >> 24) & 0xFF; ++ buf[i++] = (offset_addr >> 16) & 0xFF; ++ buf[i++] = (offset_addr >> 8) & 0xFF; ++ buf[i++] = offset_addr & 0xFF; ++ break; ++ case WIDTH_2Byte: ++ buf[i++] = (offset_addr >> 8) & 0xFF; ++ buf[i++] = offset_addr & 0xFF; ++ break; ++ case WIDTH_1Byte: ++ buf[i++] = offset_addr & 0xFF; ++ break; ++ default: ++ DFD_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set %u addr_bitwidth \n", addr_bitwidth); ++ rv = -1; ++ goto fail; ++ } ++ ++ msgs[0].addr = dev_addr; ++ msgs[0].flags = 0; ++ msgs[0].len = addr_bitwidth; ++ msgs[0].buf = buf; ++ msgs[1].addr = dev_addr; ++ msgs[1].flags |= I2C_M_RD; ++ msgs[1].len = rd_len; ++ msgs[1].buf = recv_buf; ++ ioctl_data.nmsgs = 2; ++ ioctl_data.msgs = msgs; ++ ++ rv = ioctl(fd, I2C_RDWR, &ioctl_data); ++ if(rv < 0) { ++ DFD_DEBUG_ERROR("%s %d Error: Sending messages failed:(ret:%d, errno:%s)!\n", __func__ , __LINE__, rv, strerror(errno)); ++ goto fail; ++ } ++ ++fail: ++ close(fd); ++ return rv; ++} ++ ++int32_t dfd_i2c_gen_read(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, ++ uint32_t offset_addr, uint8_t *recv_buf, int32_t rd_len) ++{ ++ int i; ++ int rv; ++ ++ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { ++ rv = dfd_i2c_gen_read_one_time(i2c_path, dev_addr, addr_bitwidth, offset_addr, recv_buf, rd_len); ++ if (rv < 0) { ++ DFD_DEBUG_ERROR("(read times:%d) i2c_path:%s, dev_addr:0x%x, addr_bitwidth:%u, offset_addr:0x%x, rd_len:%u\n", ++ i, i2c_path, dev_addr, addr_bitwidth, offset_addr, rd_len); ++ usleep(DFD_I2C_RETRY_SLEEP_TIME); ++ continue; ++ } ++ break; ++ } ++ ++ return rv; ++} ++ ++int dfd_utest_i2c_gen_rd(int argc, char* argv[]) ++{ ++ int ret; ++ uint32_t i2c_bus, dev_addr, addr_bitwidth, offset_addr, data_bitwidth, rd_len, i, j; ++ char *stopstring; ++ char i2c_path[32]; ++ uint8_t tmp_value[DFD_UTEST_MAX_RDWR_NUM]; ++ uint8_t rd_value[DFD_UTEST_MAX_RDWR_NUM]; ++ ++ if (argc != 8) { ++ DFD_DEBUG_ERROR("params error\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_RD); ++ goto exit; ++ } ++ ++ i2c_bus = strtol(argv[2], &stopstring, 10); ++ dev_addr = strtol(argv[3], &stopstring, 16); ++ addr_bitwidth = strtol(argv[4], &stopstring, 10); ++ offset_addr = strtol(argv[5], &stopstring, 16); ++ data_bitwidth = strtol(argv[6], &stopstring, 10); ++ rd_len = strtol(argv[7], &stopstring, 10); ++ ++ if (rd_len > DFD_UTEST_MAX_RDWR_NUM) { ++ DFD_DEBUG_ERROR("Input num %d exceed max.\n", rd_len); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_RD); ++ goto exit; ++ } ++ ++ dfd_utest_print_cmd(argc, argv); ++ printf(":\n"); ++ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); ++ mem_clear(tmp_value, sizeof(tmp_value)); ++ ret = dfd_i2c_gen_read(i2c_path, dev_addr, addr_bitwidth, offset_addr, tmp_value, rd_len); ++ if (ret < 0) { ++ printf("read failed. ret:%d\n", ret); ++ goto exit; ++ } ++ ++ mem_clear(rd_value, sizeof(rd_value)); ++ if (data_bitwidth == WIDTH_1Byte) { ++ memcpy(rd_value, tmp_value, rd_len); ++ } else { ++ for (i = 0; i < rd_len; i += data_bitwidth) { ++ for (j = 0; (j < data_bitwidth) && (i + j < rd_len); j++) { ++ rd_value[i + data_bitwidth - j - 1] = tmp_value[i + j]; ++ } ++ } ++ } ++ ++ dfd_utest_printf_reg(rd_value, rd_len, offset_addr); ++ ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++} ++ ++int32_t dfd_i2c_gen_write_one_time(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, ++ uint32_t offset_addr, uint8_t *wr_value, uint32_t wr_len) ++{ ++ int32_t fd, rv, i; ++ struct i2c_rdwr_ioctl_data ioctl_data; ++ struct i2c_msg msgs[1]; ++ uint8_t buf[DFD_UTEST_MAX_BIT_WIDTH + DFD_UTEST_MAX_RDWR_NUM]; ++ ++ fd = open(i2c_path, O_RDWR | O_SYNC); ++ if (fd < 0) { ++ DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); ++ return -1; ++ } ++ mem_clear(&ioctl_data, sizeof(ioctl_data)); ++ mem_clear(msgs, sizeof(msgs)); ++ mem_clear(buf, sizeof(buf)); ++ ++ i = 0; ++ ++ switch (addr_bitwidth) { ++ case WIDTH_4Byte: ++ buf[i++] = (offset_addr >> 24) & 0xFF; ++ buf[i++] = (offset_addr >> 16) & 0xFF; ++ buf[i++] = (offset_addr >> 8) & 0xFF; ++ buf[i++] = offset_addr & 0xFF; ++ break; ++ case WIDTH_2Byte: ++ buf[i++] = (offset_addr >> 8) & 0xFF; ++ buf[i++] = offset_addr & 0xFF; ++ break; ++ case WIDTH_1Byte: ++ buf[i++] = offset_addr & 0xFF; ++ break; ++ default: ++ DFD_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set %u addr_bitwidth \r\n", addr_bitwidth); ++ rv = -1; ++ goto fail; ++ } ++ ++ memcpy(buf + addr_bitwidth, wr_value, wr_len); ++ ++ msgs[0].addr= dev_addr; ++ msgs[0].flags = 0; ++ msgs[0].len= addr_bitwidth + wr_len; ++ msgs[0].buf= buf; ++ ++ ioctl_data.nmsgs= 1; ++ ioctl_data.msgs= msgs; ++ ++ rv = ioctl(fd, I2C_RDWR, &ioctl_data); ++ if(rv < 0) { ++ DFD_DEBUG_ERROR("%s %dError: Sending messages failed:(ret:%d, errno:%s)!\n", __func__ , __LINE__, rv, strerror(errno)); ++ goto fail; ++ } else if (rv < ioctl_data.nmsgs) { ++ DFD_DEBUG_ERROR("%s %dWarning: only %d/%d messages were sent\n", __func__ , __LINE__, rv, ioctl_data.nmsgs); ++ } ++ ++fail: ++ close(fd); ++ return rv; ++} ++ ++int32_t dfd_i2c_gen_write(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, ++ uint32_t offset_addr, uint8_t *wr_value, uint32_t wr_len) ++{ ++ int i; ++ int rv; ++ ++ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { ++ rv = dfd_i2c_gen_write_one_time(i2c_path, dev_addr, addr_bitwidth, offset_addr, wr_value, wr_len); ++ if (rv < 0) { ++ DFD_DEBUG_ERROR("(write times:%d)i2c_path:%s, dev_addr:0x%x, addr_bitwidth:%u, offset_addr:0x%x, wr_len:%u\n", ++ i, i2c_path, dev_addr, addr_bitwidth, offset_addr, wr_len); ++ usleep(DFD_I2C_RETRY_SLEEP_TIME); ++ continue; ++ } ++ break; ++ } ++ ++ return rv; ++} ++ ++int dfd_utest_i2c_gen_wr(int argc, char* argv[]) ++{ ++ int ret; ++ uint32_t i2c_bus, dev_addr, addr_bitwidth, offset_addr, data_bitwidth, wr_len, tmp_data, para_len, i, j; ++ char *stopstring; ++ char i2c_path[32]; ++ uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; ++ ++ if (argc < 8) { ++ DFD_DEBUG_ERROR("Input invalid.\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_WR); ++ goto exit; ++ } ++ ++ i2c_bus = strtol(argv[2], &stopstring, 10); ++ dev_addr = strtol(argv[3], &stopstring, 16); ++ addr_bitwidth = strtol(argv[4], &stopstring, 10); ++ offset_addr = strtol(argv[5], &stopstring, 16); ++ data_bitwidth = strtol(argv[6], &stopstring, 10); ++ ++ para_len = argc - 7; ++ wr_len = para_len * data_bitwidth; ++ ++ if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { ++ DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_WR); ++ goto exit; ++ } ++ ++ if (data_bitwidth == WIDTH_1Byte) { ++ for (i = 0; i < para_len; i++) { ++ wr_value[i] = strtol(argv[7 + i], &stopstring, 16); ++ DFD_DEBUG_DBG(" index :%d value 0x%x\n", i , wr_value[i]); ++ } ++ } else { ++ for (i = 0; i < para_len; i++) { ++ tmp_data = strtol(argv[7 + i], &stopstring, 16); ++ DFD_DEBUG_DBG(" index :%d value 0x%x\n", i , tmp_data); ++ for (j = 0; j < data_bitwidth; j++) { ++ tmp_data = strtol(argv[7 + i], &stopstring, 16); ++ wr_value[j + i * data_bitwidth] = (tmp_data >> (24 - 8 * j)) & 0xFF; ++ } ++ } ++ } ++ ++ dfd_utest_print_cmd(argc, argv); ++ ++ printf(":\n"); ++ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); ++ ++ ret = dfd_i2c_gen_write(i2c_path, dev_addr, addr_bitwidth, offset_addr, wr_value, wr_len); ++ if (ret < 0) { ++ printf("write failed. ret:%d\n", ret); ++ } else { ++ printf("write success\n"); ++ } ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++} ++ ++int dfd_utest_i2c_rd(int argc, char* argv[]) ++{ ++ int ret; ++ uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; ++ uint16_t dev_addr, offset_addr; ++ char *stopstring; ++ int num, i2c_bus; ++ char i2c_path[32]; ++ ++ if (argc != 6) { ++ DFD_DEBUG_ERROR("params error\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_RD); ++ goto exit; ++ } ++ ++ i2c_bus = strtol(argv[2], &stopstring, 10); ++ dev_addr = strtol(argv[3], &stopstring, 16); ++ offset_addr = strtol(argv[4], &stopstring, 16); ++ num = strtol(argv[5], &stopstring, 10); ++ ++ if (num > DFD_UTEST_MAX_RDWR_NUM) { ++ DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_RD); ++ goto exit; ++ } ++ ++ dfd_utest_print_cmd(argc, argv); ++ printf(":\n"); ++ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); ++ mem_clear(value, sizeof(value)); ++ ret = dfd_read_port_i2c(i2c_path, dev_addr, offset_addr, value, num); ++ if (ret < 0) { ++ printf("failed ret %d\n", ret); ++ goto exit; ++ } ++ ++ dfd_utest_printf_reg(value, num, offset_addr); ++ ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++ ++} ++ ++int dfd_utest_i2c_wr(int argc, char* argv[]) ++{ ++ int ret; ++ uint16_t dev_addr, offset_addr; ++ char *stopstring; ++ int i2c_bus; ++ char i2c_path[32]; ++ uint8_t wr_len,i; ++ uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; ++ ++ if (argc < 6) { ++ DFD_DEBUG_ERROR("Input invalid.\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_WR); ++ goto exit; ++ } ++ ++ wr_len = argc - 5; ++ i2c_bus = strtol(argv[2], &stopstring, 10); ++ dev_addr = strtol(argv[3], &stopstring, 16); ++ offset_addr = strtol(argv[4], &stopstring, 16); ++ ++ for (i = 0; i < wr_len; i++) { ++ wr_value[i] = strtol(argv[5+i], &stopstring, 16); ++ DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); ++ } ++ ++ dfd_utest_print_cmd(argc, argv); ++ ++ printf(":\n"); ++ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); ++ ++ ret = dfd_write_port_i2c(i2c_path, dev_addr, offset_addr, wr_value, wr_len); ++ if (ret < 0) { ++ printf("failed ret %d\n", ret); ++ } else { ++ printf("success\n"); ++ } ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++} ++ ++int dfd_utest_io_rd(int argc, char* argv[]) ++{ ++ int ret; ++ uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; ++ uint16_t offset_addr; ++ char *stopstring; ++ int num; ++ ++ if (argc != 4) { ++ DFD_DEBUG_ERROR("params error\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_RD); ++ goto exit; ++ } ++ ++ offset_addr = strtol(argv[2], &stopstring, 16); ++ num = strtol(argv[3], &stopstring, 10); ++ ++ if (num > DFD_UTEST_MAX_RDWR_NUM) { ++ DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_RD); ++ goto exit; ++ } ++ ++ dfd_utest_print_cmd(argc, argv); ++ printf(":\n"); ++ mem_clear(value, sizeof(value)); ++ ret = dfd_read_io_port(offset_addr, value, num); ++ if (ret < 0) { ++ printf("failed ret %d\n", ret); ++ goto exit; ++ } ++ ++ dfd_utest_printf_reg(value, num, offset_addr); ++ ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++} ++ ++int dfd_utest_io_wr(int argc, char* argv[]) ++{ ++ int ret; ++ uint16_t offset_addr; ++ char *stopstring; ++ int32_t wr_len,i; ++ uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; ++ ++ if (argc < 4) { ++ DFD_DEBUG_ERROR("Input invalid.\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_WR); ++ goto exit; ++ } ++ ++ wr_len = argc - 3; ++ if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { ++ DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_WR); ++ goto exit; ++ } ++ ++ offset_addr = strtol(argv[2], &stopstring, 16); ++ ++ for (i = 0; i < wr_len; i++) { ++ wr_value[i] = strtol(argv[3 + i], &stopstring, 16); ++ DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); ++ } ++ ++ dfd_utest_print_cmd(argc, argv); ++ ++ printf(":\n"); ++ ret = dfd_write_io_port(offset_addr, wr_value, wr_len); ++ if (ret < 0) { ++ printf("failed ret %d\n", ret); ++ } else { ++ printf("success\n"); ++ } ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++} ++ ++int dfd_utest_phymem_rd(int argc, char* argv[]) ++{ ++ int ret, width; ++ uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; ++ off_t offset_addr; ++ char *stopstring; ++ int num; ++ ++ if (argc != 5) { ++ DFD_DEBUG_ERROR("params error\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_RD); ++ goto exit; ++ } ++ ++ width = strtol(argv[2], &stopstring, 10); ++ offset_addr = strtol(argv[3], &stopstring, 16); ++ num = strtol(argv[4], &stopstring, 10); ++ ++ if (num > DFD_UTEST_MAX_RDWR_NUM) { ++ DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_RD); ++ goto exit; ++ } ++ ++ dfd_utest_print_cmd(argc, argv); ++ printf(":\n"); ++ mem_clear(value, sizeof(value)); ++ ret = dfd_process_mem(DEV_MEM_NAME, 0, width, offset_addr, value, num); ++ if (ret < 0) { ++ printf("failed ret %d\n", ret); ++ goto exit; ++ } ++ ++ dfd_utest_printf_reg(value, num, offset_addr); ++ ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++} ++ ++int dfd_utest_phymem_wr(int argc, char* argv[]) ++{ ++ int ret, width; ++ off_t offset_addr; ++ char *stopstring; ++ int32_t wr_len,i; ++ uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; ++ ++ if (argc < 5) { ++ DFD_DEBUG_ERROR("Input invalid.\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_WR); ++ goto exit; ++ } ++ ++ wr_len = argc - 4; ++ if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { ++ DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_WR); ++ goto exit; ++ } ++ ++ width = strtol(argv[2], &stopstring, 10); ++ offset_addr = strtol(argv[3], &stopstring, 16); ++ ++ for (i = 0; i < wr_len; i++) { ++ wr_value[i] = strtol(argv[4 + i], &stopstring, 16); ++ DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); ++ } ++ ++ dfd_utest_print_cmd(argc, argv); ++ ++ printf(":\n"); ++ ret = dfd_process_mem(DEV_MEM_NAME, 1, width, offset_addr, wr_value, wr_len); ++ if (ret < 0) { ++ printf("failed ret %d\n", ret); ++ } else { ++ printf("success\n"); ++ } ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++} ++ ++int dfd_utest_kmem_rd(int argc, char* argv[]) ++{ ++ int ret, width; ++ uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; ++ uint16_t offset_addr; ++ char *stopstring; ++ int num; ++ ++ if (argc != 5) { ++ DFD_DEBUG_ERROR("params error\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_RD); ++ goto exit; ++ } ++ ++ width = strtol(argv[2], &stopstring, 10); ++ offset_addr = strtol(argv[3], &stopstring, 16); ++ num = strtol(argv[4], &stopstring, 10); ++ ++ if (num > DFD_UTEST_MAX_RDWR_NUM) { ++ DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_RD); ++ goto exit; ++ } ++ ++ dfd_utest_print_cmd(argc, argv); ++ printf(":\n"); ++ mem_clear(value, sizeof(value)); ++ ret = dfd_process_mem(DEV_KMEM_NAME, 0, width, offset_addr, value, num); ++ if (ret < 0) { ++ printf("failed ret %d\n", ret); ++ goto exit; ++ } ++ ++ dfd_utest_printf_reg(value, num, offset_addr); ++ ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++} ++ ++int dfd_utest_kmem_wr(int argc, char* argv[]) ++{ ++ int ret; ++ uint16_t offset_addr, width; ++ char *stopstring; ++ int32_t wr_len,i; ++ uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; ++ ++ if (argc < 5) { ++ DFD_DEBUG_ERROR("Input invalid.\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_WR); ++ goto exit; ++ } ++ ++ wr_len = argc - 4; ++ if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { ++ DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_WR); ++ goto exit; ++ } ++ ++ width = strtol(argv[2], &stopstring, 10); ++ offset_addr = strtol(argv[3], &stopstring, 16); ++ ++ for (i = 0; i < wr_len; i++) { ++ wr_value[i] = strtol(argv[4 + i], &stopstring, 16); ++ DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); ++ } ++ ++ dfd_utest_print_cmd(argc, argv); ++ ++ printf(":\n"); ++ ret = dfd_process_mem(DEV_KMEM_NAME, 1, width, offset_addr, wr_value, wr_len); ++ if (ret < 0) { ++ printf("failed ret %d\n", ret); ++ } else { ++ printf("success\n"); ++ } ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++} ++ ++static unsigned long dfd_utest_get_file_size(const char *path) ++{ ++ unsigned long filesize; ++ struct stat statbuff; ++ ++ if (stat(path, &statbuff) < 0) { ++ filesize = -1; ++ } else { ++ filesize = statbuff.st_size; ++ } ++ ++ return filesize; ++} ++ ++int dfd_utest_i2c_file_wr(int argc, char* argv[]) ++{ ++ int ret; ++ uint16_t dev_addr, offset_addr; ++ char *stopstring; ++ int i2c_bus; ++ char i2c_path[32]; ++ char *file_name; ++ unsigned long filesize; ++ int fd; ++ uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; ++ int len; ++ int bpt; /* byte per times*/ ++ int page_left; ++ ++ if (argc != 7) { ++ printf("Input invalid.\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_FILE_WR); ++ goto exit; ++ } ++ ++ i2c_bus = strtol(argv[2], &stopstring, 10); ++ dev_addr = strtol(argv[3], &stopstring, 16); ++ offset_addr = strtol(argv[4], &stopstring, 16); ++ bpt = strtol(argv[5], &stopstring, 10); ++ file_name = argv[6]; ++ ++ if ((bpt <= 0) || (bpt > DFD_UTEST_MAX_RDWR_NUM)) { ++ bpt = DFD_UTEST_MAX_RDWR_NUM; ++ } ++ ++ if ((bpt & (bpt - 1)) != 0) { ++ printf("Bytes per times %d isn't power of two.\n",bpt); ++ goto exit; ++ } ++ ++ filesize = dfd_utest_get_file_size(file_name); ++ if (filesize <= 0) { ++ printf("Input invalid file %s, filesize %lu.\n", file_name, filesize); ++ goto exit; ++ } ++ ++ fd = open(file_name, O_RDONLY); ++ if (fd < 0) { ++ printf("open file[%s] fail.\n", file_name); ++ goto exit; ++ } ++ ++ dfd_utest_print_cmd(argc, argv); ++ ++ printf(":\n"); ++ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); ++ ++ while (filesize > 0) { ++ mem_clear(wr_buf, DFD_UTEST_MAX_RDWR_NUM); ++ len = bpt; ++ if (offset_addr & (bpt - 1)) { ++ page_left = bpt - (offset_addr & (bpt - 1)); ++ len = len > page_left ? page_left : len; ++ } ++ ++ len = read(fd, wr_buf, len); ++ ++ ret = dfd_write_port_i2c(i2c_path, dev_addr, offset_addr, wr_buf, len); ++ if (ret < 0) { ++ break; ++ } ++ offset_addr += len; ++ filesize -= len; ++ } ++ ++ close(fd); ++ ++ if (ret < 0) { ++ printf("failed ret %d\n", ret); ++ } else { ++ printf("success\n"); ++ } ++ ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++ ++} ++ ++/* compare with sys_flie_wr, One more step is read back verification */ ++int dfd_utest_sysfs_file_upg(int argc, char* argv[]) ++{ ++ int ret = 0; ++ uint32_t offset_addr; ++ char *file_name; ++ char *sysfs_loc; ++ char *stopstring; ++ unsigned long filesize; ++ int fd, file_fd; ++ uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; ++ int len, write_len, per_wr_len; ++ int i; ++ uint8_t reread_buf[DFD_UTEST_MAX_RDWR_NUM]; ++ int reback_len, reread_len; ++ int j = 0; ++ ++ if (argc != 5 && argc != 6) { ++ printf("Input invalid.\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_FILE_UPG); ++ goto exit; ++ } ++ ++ sysfs_loc = argv[2]; ++ offset_addr = strtol(argv[3], &stopstring, 16); ++ file_name = argv[4]; ++ ++ if (argc == 6) { ++ per_wr_len = strtol(argv[5], &stopstring, 10); ++ if (per_wr_len > DFD_UTEST_MAX_RDWR_NUM || per_wr_len <= 0) { ++ printf("per_wr_byte %d invalid, not in range (0, 256]\n", per_wr_len); ++ goto exit; ++ } ++ } else { ++ per_wr_len = DFD_UTEST_DEFAULT_WR_NUM; ++ } ++ DFD_DEBUG_DBG("per_wr_byte: %d\n", per_wr_len); ++ filesize = dfd_utest_get_file_size(file_name); ++ if (filesize <= 0) { ++ printf("Input invalid file %s, filesize %lu.\n", file_name, filesize); ++ goto exit; ++ } ++ ++ fd = open(sysfs_loc, O_RDWR | O_SYNC); ++ if (fd < 0) { ++ printf("open file[%s] fail.\n", sysfs_loc); ++ goto exit; ++ } ++ ++ file_fd = open(file_name, O_RDONLY); ++ if (file_fd < 0) { ++ printf("open file[%s] fail.\n", file_name); ++ goto open_dev_err; ++ } ++ ++ dfd_utest_print_cmd(argc, argv); ++ ++ ret = lseek(fd, offset_addr, SEEK_SET); ++ if (ret < 0) { ++ printf("lseek file[%s offset=%d] fail,\n", sysfs_loc, offset_addr); ++ goto fail; ++ } ++ ++ printf(":\n"); ++ while (filesize > 0) { ++ if (filesize > (unsigned long)per_wr_len) { ++ len = per_wr_len; ++ } else { ++ len = filesize; ++ } ++ ++ mem_clear(wr_buf, DFD_UTEST_MAX_RDWR_NUM); ++ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { ++ len = read(file_fd, wr_buf, len); ++ if (len < 0) { ++ DFD_DEBUG_ERROR("read file[%s] fail, offset = 0x%x retrytimes = %d ret = %d\n", ++ sysfs_loc, offset_addr, i ,len); ++ usleep(DFD_I2C_RETRY_SLEEP_TIME); ++ continue; ++ } ++ break; ++ } ++ if (i == DFD_I2C_RETRY_TIME) { ++ printf("read file[%s] fail, offset = 0x%x, ret = %d\n", sysfs_loc, offset_addr, len); ++ goto fail; ++ } ++ ++ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { ++ write_len = write(fd, wr_buf, len); ++ if (write_len != len) { ++ DFD_DEBUG_ERROR("write file[%s] fail,offset = 0x%x retrytimes = %d len = %d,write_len =%d\n", ++ sysfs_loc, offset_addr, i ,len, write_len); ++ usleep(DFD_I2C_RETRY_SLEEP_TIME); ++ continue; ++ } ++ break; ++ } ++ if (i == DFD_I2C_RETRY_TIME) { ++ printf("write file[%s] fail, offset = 0x%x, len = %d,write_len =%d\n", ++ sysfs_loc, offset_addr, len, write_len); ++ goto fail; ++ } ++ ++ reback_len = write_len; ++ ret = lseek(fd, -reback_len, SEEK_CUR); ++ if (ret < 0) { ++ printf("reread lseek file[%s offset=%d] fail,lseek len=%d\n", ++ sysfs_loc, offset_addr, reback_len); ++ goto fail; ++ } ++ ++ mem_clear(reread_buf, DFD_UTEST_MAX_RDWR_NUM); ++ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { ++ reread_len = read(fd, reread_buf, reback_len); ++ if (reread_len != reback_len) { ++ DFD_DEBUG_ERROR("reread file[%s] fail,offset = 0x%x retrytimes = %d reread_len = %d,reback_len =%d\n", ++ sysfs_loc, offset_addr, i ,reread_len, reback_len); ++ usleep(DFD_I2C_RETRY_SLEEP_TIME); ++ continue; ++ } ++ break; ++ } ++ if (i == DFD_I2C_RETRY_TIME) { ++ printf("reread file[%s] fail, offset = 0x%x, reread_len = %d,reback_len = %d\n", ++ sysfs_loc, offset_addr, reread_len, reback_len); ++ goto fail; ++ } ++ ++ if (memcmp(reread_buf, wr_buf, reread_len) != 0) { ++ if (j < DFD_I2C_RETRY_TIME) { ++ DFD_DEBUG_ERROR("memcmp file[%s] fail,offset = 0x%x retrytimes = %d\n", ++ sysfs_loc, offset_addr, j); ++ j++; ++ ret = lseek(file_fd, -len, SEEK_CUR); ++ if (ret < 0) { ++ printf("retry file_fd lseek fail,lseek len=%d\n", len); ++ goto fail; ++ } ++ ret = lseek(fd, -write_len, SEEK_CUR); ++ if (ret < 0) { ++ printf("retry fd lseek fail,lseek len=%d\n", write_len); ++ goto fail; ++ } ++ continue; ++ } ++ ++ printf("upgrade file[%s] fail, offset = 0x%x.\n", sysfs_loc, offset_addr); ++ printf("want to write buf :\n"); ++ for (i = 0; i < reread_len; i++) { ++ printf("0x%x ", wr_buf[i]); ++ } ++ printf("\n"); ++ ++ printf("actually reread buf :\n"); ++ for (i = 0; i < reread_len; i++) { ++ printf("0x%x ", reread_buf[i]); ++ } ++ printf("\n"); ++ ++ goto fail; ++ } ++ ++ offset_addr += len; ++ filesize -= len; ++ usleep(5000); ++ } ++ ++ printf("success\n"); ++ close(file_fd); ++ close(fd); ++ return DFD_RV_OK; ++ ++fail: ++ close(file_fd); ++open_dev_err: ++ close(fd); ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++} ++ ++int dfd_utest_sysfs_file_wr(int argc, char* argv[]) ++{ ++ int ret = 0; ++ uint32_t offset_addr; ++ char *file_name; ++ char *sysfs_loc; ++ char *stopstring; ++ unsigned long filesize; ++ int fd, file_fd; ++ uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; ++ int len, write_len, per_wr_len; ++ int i; ++ ++ if (argc != 5 && argc != 6) { ++ printf("Input invalid.\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_FILE_WR); ++ goto exit; ++ } ++ ++ sysfs_loc = argv[2]; ++ offset_addr = strtol(argv[3], &stopstring, 16); ++ file_name = argv[4]; ++ ++ if (argc == 6) { ++ per_wr_len = strtol(argv[5], &stopstring, 10); ++ if (per_wr_len > DFD_UTEST_MAX_RDWR_NUM || per_wr_len <= 0) { ++ printf("per_wr_byte %d invalid, not in range (0, 256]\n", per_wr_len); ++ goto exit; ++ } ++ } else { ++ per_wr_len = DFD_UTEST_DEFAULT_WR_NUM; ++ } ++ DFD_DEBUG_DBG("per_wr_byte: %d\n", per_wr_len); ++ filesize = dfd_utest_get_file_size(file_name); ++ if (filesize <= 0) { ++ printf("Input invalid file %s, filesize %lu.\n", file_name, filesize); ++ goto exit; ++ } ++ ++ fd = open(sysfs_loc, O_RDWR | O_SYNC); ++ if (fd < 0) { ++ printf("open file[%s] fail.\n", sysfs_loc); ++ goto exit; ++ } ++ ++ file_fd = open(file_name, O_RDONLY); ++ if (file_fd < 0) { ++ printf("open file[%s] fail.\n", file_name); ++ goto open_dev_err; ++ } ++ ++ dfd_utest_print_cmd(argc, argv); ++ ++ ret = lseek(fd, offset_addr, SEEK_SET); ++ if (ret < 0) { ++ printf("lseek file[%s offset=%d] fail,\n", sysfs_loc, offset_addr); ++ goto fail; ++ } ++ ++ printf(":\n"); ++ while (filesize > 0) { ++ if (filesize > (unsigned long)per_wr_len) { ++ len = per_wr_len; ++ } else { ++ len = filesize; ++ } ++ ++ mem_clear(wr_buf, DFD_UTEST_MAX_RDWR_NUM); ++ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { ++ len = read(file_fd, wr_buf, len); ++ if (len < 0) { ++ DFD_DEBUG_ERROR("read file[%s] fail, offset = 0x%x retrytimes = %d ret = %d\n", ++ sysfs_loc, offset_addr, i ,len); ++ usleep(DFD_I2C_RETRY_SLEEP_TIME); ++ continue; ++ } ++ break; ++ } ++ if (i == DFD_I2C_RETRY_TIME) { ++ printf("read file[%s] fail, offset = 0x%x, ret = %d\n", sysfs_loc, offset_addr, len); ++ goto fail; ++ } ++ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { ++ write_len = write(fd, wr_buf, len); ++ if (write_len != len) { ++ DFD_DEBUG_ERROR("write file[%s] fail,offset = 0x%x retrytimes = %d len = %d,write_len =%d\n", sysfs_loc, offset_addr, i ,len, write_len); ++ usleep(DFD_I2C_RETRY_SLEEP_TIME); ++ continue; ++ } ++ break; ++ } ++ ++ if(i == DFD_I2C_RETRY_TIME) { ++ printf("write file[%s] fail, offset = 0x%x, len = %d,write_len =%d\n", sysfs_loc, offset_addr, len, write_len); ++ ret = -1; ++ goto fail; ++ } ++ offset_addr += len; ++ filesize -= len; ++ usleep(5000); ++ } ++ ++ printf("success\n"); ++ close(file_fd); ++ close(fd); ++ return DFD_RV_OK; ++ ++fail: ++ close(file_fd); ++open_dev_err: ++ close(fd); ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++} ++ ++int dfd_utest_sysfs_file_rd(int argc, char* argv[]) ++{ ++ int ret = 0; ++ uint32_t offset_addr; ++ char *sysfs_loc; ++ char *stopstring; ++ int fd; ++ uint8_t rd_buf[DFD_UTEST_MAX_RDWR_NUM]; ++ int len, read_len;; ++ ++ if (argc != 5) { ++ printf("Input invalid.\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_FILE_RD); ++ goto exit; ++ } ++ ++ sysfs_loc = argv[2]; ++ offset_addr = strtol(argv[3], &stopstring, 16); ++ len = strtol(argv[4], &stopstring, 10); ++ ++ if (len > DFD_UTEST_MAX_RDWR_NUM) { ++ printf("Input num %d exceed max 256.\n", len); ++ goto exit; ++ } ++ ++ fd = open(sysfs_loc, O_RDONLY); ++ if (fd < 0) { ++ printf("open file[%s] fail.\n", sysfs_loc); ++ goto exit; ++ } ++ dfd_utest_print_cmd(argc, argv); ++ ++ printf(":\n"); ++ ++ ret = lseek(fd, offset_addr, SEEK_SET); ++ if (ret < 0) { ++ printf("lseek failed ret %d.\n", ret); ++ goto fail; ++ } ++ ++ mem_clear(rd_buf, DFD_UTEST_MAX_RDWR_NUM); ++ read_len = read(fd, rd_buf, len); ++ if (read_len != len) { ++ printf("read failed read_len %d len %d.\n", read_len, len); ++ goto fail; ++ } ++ dfd_utest_printf_reg(rd_buf, read_len, offset_addr); ++ close(fd); ++ return DFD_RV_OK; ++ ++fail: ++ close(fd); ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++} ++ ++int dfd_utest_msr_rd(int argc, char* argv[]) ++{ ++ int fd; ++ char msr_file_name[64]; ++ uint64_t data; ++ uint64_t read_result; ++ char *stopstring; ++ uint8_t cpu_index, width; ++ uint64_t offset; ++ ++ if (argc != 5) { ++ printf("rdmsr failed: Input invalid.\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_MSR_RD); ++ goto exit; ++ } ++ ++ cpu_index = strtol(argv[2], &stopstring, 10); ++ offset = strtol(argv[3], &stopstring, 16); ++ width = strtol(argv[4], &stopstring, 10); ++ ++ if (width != 8 && width != 16 && width != 32 && width != 64) { ++ printf("rdmsr failed: width:%u Input invalid.only support 8 16 32 64\n", width); ++ goto exit; ++ } ++ ++ mem_clear(msr_file_name, sizeof(msr_file_name)); ++ sprintf(msr_file_name, "/dev/cpu/%u/msr", cpu_index); ++ ++ fd = open(msr_file_name, O_RDONLY); ++ if (fd < 0) { ++ if (errno == ENXIO) { ++ fprintf(stderr, "rdmsr failed: No CPU %u\n", cpu_index); ++ } else if (errno == EIO) { ++ fprintf(stderr, "rdmsr failed: CPU %u doesn't support MSRs\n", cpu_index); ++ } else if (errno == ENOENT) { ++ fprintf(stderr, "rdmsr failed: can't find %s file, Please check if modprobe msr driver already\n", msr_file_name); ++ } else { ++ printf("rdmsr failed: %s open failed. errno:%d\n", msr_file_name, errno); ++ } ++ goto exit; ++ } ++ ++ if (pread(fd, &data, sizeof(data), offset) != sizeof(data)) { ++ fprintf(stderr, "rdmsr failed: CPU:%u offset:0x%lx read failed\n", cpu_index, offset); ++ goto fail; ++ } ++ ++ switch (width) { ++ case 8: ++ read_result = (volatile uint8_t)data; ++ break; ++ case 16: ++ read_result = (volatile uint16_t)data; ++ break; ++ case 32: ++ read_result = (volatile uint32_t)data; ++ break; ++ case 64: ++ read_result = (volatile uint64_t)data; ++ break; ++ default: ++ printf("rdmsr failed: width:%u illegal width.\n", width); ++ goto fail; ++ } ++ ++ printf("0x%lx\n", read_result); ++ close(fd); ++ return DFD_RV_OK; ++ ++fail: ++ close(fd); ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++} ++ ++int dfd_utest_sysfs_data_wr(int argc, char* argv[]) ++{ ++ uint32_t offset; ++ char *sysfs_loc; ++ char *stopstring; ++ uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; ++ int ret, i; ++ int fd, len, write_len, index; ++ ++ if (argc < 5) { ++ DFD_DEBUG_ERROR("Input invalid.\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_DATA_WR); ++ goto exit; ++ } ++ ++ dfd_utest_print_cmd(argc, argv); ++ printf(":\n"); ++ ++ sysfs_loc = argv[2]; ++ offset = strtol(argv[3], &stopstring, 16); ++ len = argc - 4; ++ mem_clear(wr_buf, sizeof(wr_buf)); ++ for (i = 0; i < len; i++) { ++ wr_buf[i] = strtol(argv[4 + i], &stopstring, 16); ++ DFD_DEBUG_DBG("index :%d value %x\n", i , wr_buf[i]); ++ } ++ ++ fd = open(sysfs_loc, O_RDWR | O_SYNC); ++ if (fd < 0) { ++ printf("open file[%s] fail.\n", sysfs_loc); ++ goto exit; ++ } ++ ++ ret = lseek(fd, offset, SEEK_SET); ++ if (ret < 0) { ++ printf("lseek file[%s offset=%d] fail,\n", sysfs_loc, offset); ++ goto fail; ++ } ++ index = 0; ++ while (len > 0) { ++ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { ++ write_len = write(fd, &wr_buf[index], len); ++ if (write_len < 0) { ++ DFD_DEBUG_ERROR("write file[%s] fail, retrytimes: %d, offset: 0x%x, len: %d, write_len: %d\n", ++ sysfs_loc, offset, i, len, write_len); ++ usleep(DFD_I2C_RETRY_SLEEP_TIME); ++ continue; ++ } ++ if (write_len == 0) { ++ DFD_DEBUG_ERROR("write file[%s] EOF, offset: 0x%x, len: %d, write_len: %d\n", ++ sysfs_loc, offset, len, write_len); ++ goto fail; ++ } ++ break; ++ } ++ if(i == DFD_I2C_RETRY_TIME) { ++ printf("write file[%s] fail, offset: 0x%x, len: %d, write_len: %d\n", ++ sysfs_loc, offset, len, write_len); ++ goto fail; ++ } ++ offset += write_len; ++ index += write_len; ++ len -= write_len; ++ usleep(5000); ++ } ++ printf("success\n"); ++ close(fd); ++ return DFD_RV_OK; ++fail: ++ close(fd); ++exit: ++ return DFD_RV_MODE_NOTSUPPORT; ++} ++ ++static void phy_help(char *name) ++{ ++ fprintf(stderr, ++ "Usage: %s phy_index(dec) regnum(hex) [regval(hex)] \n" ++ " phy_index phydev index \n" ++ " regnum phydev register address \n" ++ " regval phydev register value \n", ++ name); ++ return; ++} ++ ++static void mdio_help(char *name) ++{ ++ fprintf(stderr, ++ "Usage: %s mdio_index(dec) phyaddr(hex) regnum(hex) [regval(hex)] \n" ++ " mdio_index mdiodev index \n" ++ " phyaddr phydev address \n" ++ " regnum phydev register address \n" ++ " regval phydev register value \n", ++ name); ++ return; ++} ++ ++static int phydev_arg_parse(int argc, char* argv[], int *phy_index, uint32_t *regnum, uint32_t *regval, ++ int num_arg) ++{ ++ ++ unsigned long index, regaddr, value; ++ char *end; ++ ++ if (argc != num_arg) { ++ return -EINVAL; ++ } ++ ++ index = strtoul(argv[2], &end, 0); ++ if (*end) { ++ fprintf(stderr, "Error: index invalid!\n"); ++ return -EINVAL; ++ } ++ ++ regaddr = strtoul(argv[3], &end, 0); ++ if (*end || regaddr > 0xffff) { ++ fprintf(stderr, "Error: regaddr invalid!\n"); ++ return -EINVAL; ++ } ++ ++ if (argc > 4) { ++ value = strtoul(argv[4], &end, 0); ++ if (*end || value > 0xffff) { ++ fprintf(stderr, "Error: reg data invalid!\n"); ++ return -EINVAL; ++ } ++ ++ *regval = (uint32_t)value; ++ } ++ ++ *phy_index = (uint32_t)index; ++ *regnum = (uint32_t)regaddr; ++ ++ return 0; ++} ++ ++static int mdiodev_arg_parse(int argc, char* argv[], int *mdio_index, int *phyaddr, uint32_t *regnum, ++ uint32_t *regval, int num_arg) ++{ ++ ++ unsigned long index, addr, regaddr, value; ++ char *end; ++ ++ if (argc != num_arg) { ++ return -EINVAL; ++ } ++ ++ index = strtoul(argv[2], &end, 0); ++ if (*end) { ++ fprintf(stderr, "Error: index invalid!\n"); ++ return -EINVAL; ++ } ++ ++ addr = strtoul(argv[3], &end, 0); ++ if (*end || addr > 0x1f) { ++ fprintf(stderr, "Error: phyaddr invalid!\n"); ++ return -EINVAL; ++ } ++ ++ regaddr = strtoul(argv[4], &end, 0); ++ if (*end || regaddr > 0xffff) { ++ fprintf(stderr, "Error: regaddr invalid!\n"); ++ return -EINVAL; ++ } ++ ++ if (argc > 5) { ++ value = strtoul(argv[5], &end, 0); ++ if (*end || value > 0xffff) { ++ fprintf(stderr, "Error: reg data invalid!\n"); ++ return -EINVAL; ++ } ++ ++ *regval = (uint32_t)value; ++ } ++ ++ *mdio_index = (uint32_t)index; ++ *phyaddr = (int)addr; ++ *regnum = (uint32_t)regaddr; ++ ++ return 0; ++} ++ ++int dfd_utest_phydev_list(int argc, char* argv[]) ++{ ++ int fd; ++ ++ if (argc != 2) { ++ printf("Input invalid.\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYDEV_LIST); ++ return DFD_RV_MODE_NOTSUPPORT; ++ } ++ ++ argv = argv; ++ fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); ++ if (fd < 0) { ++ fprintf(stderr, "Error: Could not open file " ++ "/dev/dram: %s\n", strerror(errno)); ++ return -1; ++ } ++ ++ (void)ioctl(fd, CMD_PHY_LIST, NULL); ++ ++ close(fd); ++ ++ return 0; ++} ++ ++int dfd_utest_phydev_rd(int argc, char* argv[]) ++{ ++ struct phydev_user_info phy_info; ++ int fd; ++ long int ret; ++ ++ ret = phydev_arg_parse(argc, argv, &phy_info.phy_index, &phy_info.regnum, &phy_info.regval, 4); ++ if (ret < 0) { ++ phy_help("phydev_rd"); ++ return -1; ++ } ++ ++ fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); ++ if (fd < 0) { ++ fprintf(stderr, "Error: Could not open file " ++ "/dev/dram: %s\n", strerror(errno)); ++ return -1; ++ } ++ ++ ret = ioctl(fd, CMD_PHY_READ, &phy_info); ++ if (ret < 0) { ++ fprintf(stderr, "Error: phy read error : %s\n", strerror(errno)); ++ close(fd); ++ return -1; ++ } ++ ++ close(fd); ++ ++ printf("Read success --- phydev%d regnum: 0x%x, value: 0x%x\n",phy_info.phy_index, ++ phy_info.regnum, phy_info.regval); ++ ++ return 0; ++} ++ ++int dfd_utest_phydev_wr(int argc, char* argv[]) ++{ ++ struct phydev_user_info phy_info; ++ int fd; ++ long int ret; ++ ++ ret = phydev_arg_parse(argc, argv, &phy_info.phy_index, &phy_info.regnum, &phy_info.regval, 5); ++ if (ret < 0) { ++ phy_help("phydev_wr"); ++ return -1; ++ } ++ ++ fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); ++ if (fd < 0) { ++ fprintf(stderr, "Error: Could not open file " ++ "/dev/dram: %s\n", strerror(errno)); ++ return -1; ++ } ++ ++ ret = ioctl(fd, CMD_PHY_WRITE, &phy_info); ++ if (ret < 0) { ++ fprintf(stderr, "Error: phy write error : %s\n", strerror(errno)); ++ close(fd); ++ return -1; ++ } ++ ++ close(fd); ++ ++ printf("write success --- phydev%d regnum: 0x%x, value: 0x%x\n",phy_info.phy_index, ++ phy_info.regnum, phy_info.regval); ++ ++ return 0; ++} ++ ++int dfd_utest_mdiodev_list(int argc, char* argv[]) ++{ ++ int fd; ++ ++ if (argc != 2) { ++ printf("Input invalid.\n"); ++ dfd_utest_printf_single_help(DFD_UTEST_ITEM_MDIODEV_LIST); ++ return DFD_RV_MODE_NOTSUPPORT; ++ } ++ ++ argv = argv; ++ fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); ++ if (fd < 0) { ++ fprintf(stderr, "Error: Could not open file " ++ "/dev/dram: %s\n", strerror(errno)); ++ return -1; ++ } ++ ++ (void)ioctl(fd, CMD_MDIO_LIST, NULL); ++ ++ close(fd); ++ ++ return 0; ++} ++ ++int dfd_utest_mdiodev_rd(int argc, char* argv[]) ++{ ++ struct mdio_dev_user_info mdio_info; ++ int fd; ++ long int ret; ++ ++ ret = mdiodev_arg_parse(argc, argv, &mdio_info.mdio_index, &mdio_info.phyaddr, ++ &mdio_info.regnum, &mdio_info.regval, 5); ++ if (ret < 0) { ++ mdio_help("mdiodev_rd"); ++ return -1; ++ } ++ ++ fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); ++ if (fd < 0) { ++ fprintf(stderr, "Error: Could not open file " ++ "/dev/dram: %s\n", strerror(errno)); ++ return -1; ++ } ++ ++ ret = ioctl(fd, CMD_MDIO_READ, &mdio_info); ++ if (ret < 0) { ++ fprintf(stderr, "Error: mdio read error : %s\n", strerror(errno)); ++ close(fd); ++ return -1; ++ } ++ ++ close(fd); ++ ++ printf("Read success\n mdio_index phyaddr regnum value\n"); ++ printf(" %-10d %#-10x %#-10x %#-10x\n", mdio_info.mdio_index, mdio_info.phyaddr, ++ mdio_info.regnum, mdio_info.regval); ++ ++ return 0; ++} ++ ++int dfd_utest_mdiodev_wr(int argc, char* argv[]) ++{ ++ struct mdio_dev_user_info mdio_info; ++ int fd; ++ long int ret; ++ ++ ret = mdiodev_arg_parse(argc, argv, &mdio_info.mdio_index, &mdio_info.phyaddr, ++ &mdio_info.regnum, &mdio_info.regval, 6); ++ if (ret < 0) { ++ mdio_help("mdiodev_wr"); ++ return -1; ++ } ++ ++ fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); ++ if (fd < 0) { ++ fprintf(stderr, "Error: Could not open file " ++ "/dev/dram: %s\n", strerror(errno)); ++ return -1; ++ } ++ ++ ret = ioctl(fd, CMD_MDIO_WRITE, &mdio_info); ++ if (ret < 0) { ++ fprintf(stderr, "Error: mdio write error : %s\n", strerror(errno)); ++ close(fd); ++ return -1; ++ } ++ ++ close(fd); ++ ++ printf("write success\n mdio_index phyaddr regnum value\n"); ++ printf(" %-10d %#-10x %#-10x %#-10x\n", mdio_info.mdio_index, mdio_info.phyaddr, ++ mdio_info.regnum, mdio_info.regval); ++ ++ return 0; ++} ++ ++dfd_utest_proc_fun dfd_utest_get_proc_func(char *type_str) ++{ ++ int i, tbl_size; ++ ++ tbl_size = sizeof(g_dfd_unit_test) / sizeof(g_dfd_unit_test[0]); ++ ++ for (i = 0; i < tbl_size; i++) { ++ if (!strncmp(g_dfd_unit_test[i].type_str, type_str, strlen(g_dfd_unit_test[i].type_str))) { ++ return g_dfd_unit_test[i].utest_func; ++ } ++ } ++ DFD_DEBUG_DBG("type: %s not match.\n", type_str); ++ return NULL; ++} ++ ++void dfd_utest_cmd_main(int argc, char* argv[]) ++{ ++ dfd_utest_proc_fun pfunc; ++ int ret; ++ ++ if (argc < 2) { ++ dfd_utest_print_all_help(); ++ return; ++ } ++ ++ pfunc = dfd_utest_get_proc_func(argv[1]); ++ if (pfunc == NULL) { ++ DFD_DEBUG_DBG("utest type %s in not support.\n", argv[1]); ++ dfd_utest_print_all_help(); ++ return; ++ } ++ ret = pfunc(argc, argv); ++ if ((ret != DFD_RV_MODE_NOTSUPPORT) && (ret != DFD_RV_INDEX_INVALID)) { ++ if (ret == DFD_RV_OK) { ++ DFD_DEBUG_DBG(" [SUCCESS]\n"); ++ } else { ++ DFD_DEBUG_DBG(" [FAIL(%d)]\n", ret); ++ } ++ } ++ ++ return; ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.h b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.h +new file mode 100644 +index 000000000..1ae65148e +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.h +@@ -0,0 +1,109 @@ ++/* monitor_utest.h */ ++#ifndef __DFD_UTEST_H__ ++#define __DFD_UTEST_H__ ++ ++#include ++ ++extern int g_dfd_debug_sw; ++extern int g_dfd_debugpp_sw; ++ ++#define DFD_UTEST_TRUE_FALSE_STRING(flag) ((flag == true) ? "true" : "false") ++ ++#define DFD_DEBUG_DBG(fmt, args...) do { \ ++ if (g_dfd_debug_sw) { \ ++ printf("" fmt,\ ++ ##args); \ ++ } \ ++} while (0) ++ ++#define DFD_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_dfd_debugpp_sw) { \ ++ printf("" fmt,\ ++ ##args); \ ++ } \ ++} while (0) ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++ ++typedef enum dfd_rv_s { ++ DFD_RV_OK = 0, ++ DFD_RV_INIT_ERR = 1, ++ DFD_RV_SLOT_INVALID = 2, ++ DFD_RV_MODE_INVALID = 3, ++ DFD_RV_MODE_NOTSUPPORT = 4, ++ DFD_RV_TYPE_ERR = 5, ++ DFD_RV_DEV_NOTSUPPORT = 6, ++ DFD_RV_DEV_FAIL = 7, ++ DFD_RV_INDEX_INVALID = 8, ++ DFD_RV_NO_INTF = 9, ++ DFD_RV_NO_NODE = 10, ++ DFD_RV_NODE_FAIL = 11, ++} dfd_rv_t; ++ ++#define DFD_DEBUG_BUF_LEN (32) ++#define DFD_DEBUGP_DEBUG_FILE "/sbin/.dfd_debugp_flag" ++#define DFD_DEBUGPP_DEBUG_FILE "/sbin/.dfd_debugpp_flag" ++ ++#define DFD_UTEST_MAX_PARA_NUM (4) ++#define DFD_UTEST_TYPE_STRING_LEN (64) ++#define DFD_UTEST_MATCH_STRING_LEN (64) ++#define DFD_UTEST_HELP_STRING_LEN (256) ++#define DFD_UTEST_INVALID_PARA (-1) ++#define DFD_UTEST_BUFF_LEN (64) ++ ++typedef enum dfd_fpga_cpld_flag_e { ++ DFD_CPLD_RW_FLAG = 0x00, ++ DFD_FPGA_RW_FLAG = 0x01, ++} dfd_fpga_cpld_flag_t; ++ ++typedef int (* dfd_utest_proc_fun)(int argc, char* argv[]); ++ ++#define DFD_UTEST_ITEM_ALL \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_RD, i2c_rd, "i2c_rd [i2c_bus] [slave_addr] [offset] [len]", "i2c_rd [i2c_bus] [slave_addr] [offset] [len]") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_WR, i2c_wr, "i2c_wr [i2c_bus] [slave_addr] [offset] [data0] ... [dataN]", "i2c_wr [i2c_bus] [slave_addr] [offset] [data0] ... [dataN]") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_IO_RD, io_rd, "io_rd [offset] [len]", "io_rd [offset] [len]") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_IO_WR, io_wr, "io_wr [offset] [data0]... [dataN]", "io_wr [offset] [data0]... [dataN]") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYMEM_RD, phymem_rd, "phymem_rd [bit_width] [offset] [len]", "phymem_rd [bit_width] [offset] [len]") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYMEM_WR, phymem_wr, "phymem_wr [bit_width] [offset] [data0]... [dataN]", "phymem_wr [bit_width] [offset] [data0]... [dataN]") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_KMEM_RD, kmem_rd, "kmem_rd [bit_width] [offset] [len]", "kmem_rd [bit_width] [offset] [len]") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_KMEM_WR, kmem_wr, "kmem_wr [bit_width][offset] [data0]... [dataN]", "kmem_wr [bit_width] [offset] [data0]... [dataN]") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_FILE_WR, i2c_file_wr, "i2c_file_wr [i2c_bus] [slave_addr] [offset] [bpt] [filename]", "i2c_file_wr [i2c_bus] [slave_addr] [offset] [bpt] [filename]\nbpt:bytes per times") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_FILE_WR, sysfs_file_wr, "sysfs_file_wr [sysfs_loc] [offset] [filename] [per_wr_byte]", "sysfs_file_wr [sysfs_loc] [offset] [filename] [per_wr_byte]") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_FILE_RD, sysfs_file_rd, "sysfs_file_rd [sysfs_loc] [offset] [len]", "sysfs_file_rd [sysfs_loc] [offset] [len]") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_FILE_UPG, sysfs_file_upg, "sysfs_file_upg [sysfs_loc] [offset] [filename] [per_wr_byte]", "sysfs_file_upg [sysfs_loc] [offset] [filename] [per_wr_byte]") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_GEN_RD, i2c_gen_rd, "i2c_gen_rd [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [len]", "i2c_gen_rd [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [len]") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_GEN_WR, i2c_gen_wr, "i2c_gen_wr [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [data0]... [dataN]", "i2c_gen_wr [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [data0]... [dataN]") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_MSR_RD, msr_rd, "msr_rd [cpu_index] [offset] [width]", "msr_rd [cpu_index] [offset] [width]") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_DATA_WR, sysfs_data_wr, "sysfs_data_wr [sysfs_loc] [offset] [data0] ... [dataN]", "sysfs_data_wr [sysfs_loc] [offset] [data0] ... [dataN]]") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYDEV_LIST, phydev_list, "phydev_list", "phydev_list") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYDEV_RD, phydev_rd, "phydev_rd phy_index reg_addr", "phydev_rd phy_index reg_addr") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYDEV_WR, phydev_wr, "phydev_wr phy_index reg_addr reg_data", "phydev_wr phy_index reg_addr reg_data") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_MDIODEV_LIST, mdiodev_list, "mdiodev_list", "mdiodev_list") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_MDIODEV_RD, mdiodev_rd, "mdiodev_rd mdio_index phyaddr reg_addr", "mdiodev_rd mdio_index phyaddr reg_addr") \ ++ DFD_UTEST_ITEM(DFD_UTEST_ITEM_MDIODEV_WR, mdiodev_wr, "mdiodev_wr mdio_index phyaddr reg_addr reg_data", "mdiodev_wr mdio_index phyaddr reg_addr reg_data") \ ++ ++#ifdef DFD_UTEST_ITEM ++#undef DFD_UTEST_ITEM ++#endif ++#define DFD_UTEST_ITEM(_id, _type_str, _help_info, _help_info_detail) _id, ++typedef enum dfd_utest_item_id_s { ++ DFD_UTEST_ITEM_ALL ++} dfd_utest_item_id_t; ++ ++typedef struct { ++ int utest_type; ++ char type_str[DFD_UTEST_TYPE_STRING_LEN]; ++ dfd_utest_proc_fun utest_func; ++ char help_info[DFD_UTEST_HELP_STRING_LEN]; ++ char help_info_detail[DFD_UTEST_HELP_STRING_LEN]; ++} dfd_utest_t; ++ ++void dfd_utest_cmd_main(int argc, char* argv[]); ++ ++#ifdef DFD_UTEST_ITEM ++#undef DFD_UTEST_ITEM ++#endif ++#define DFD_UTEST_ITEM(_id, _type_str, _help_info, _help_info_detail) int dfd_utest_##_type_str(int argc, char* argv[]); ++DFD_UTEST_ITEM_ALL ++ ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Makefile +new file mode 100644 +index 000000000..1701b5f62 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Makefile +@@ -0,0 +1,18 @@ ++top_srcdir:=$(shell pwd) ++include $(top_srcdir)/Rules.mk ++ ++firmware-y:= ++firmware-y += fw_upgrade ++ ++.PHONY: all ++all: build ++ ++.PHONY: build ++build: $(firmware-y) ++$(foreach dir,$(firmware-y),$(eval $(call compile_dirs,$(dir)))) ++ ++.PHONY: rpmpkg ++rpmpkg: ++ifeq ("$(CONFIG_CPLD_UPGRADE_ISPVME)", "y") ++ #$(RPMPKG) $(install_cpld_dir) firmware-cpld-ispvme.spec git ++endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Rules.mk b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Rules.mk +new file mode 100644 +index 000000000..5fb5a09d3 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Rules.mk +@@ -0,0 +1,42 @@ ++CC ?= $(CROSS)gcc ++AR ?= $(CROSS)ar ++AS ?= $(CROSS)as ++LD ?= $(CROSS)ld ++STRIP ?= $(CROSS)strip ++ ++install_root:=${top_srcdir}/images ++ ++install_header_dir:=${install_root}/header ++install_adir:=$(install_root)/lib ++install_symbol_dir:=$(install_root)/symbol ++symbol_files:=$(shell find $(EXPORT_SYMBOL) -name 'Module.symvers') ++# ++# symbol_files += $(shell find $(install_symbol_dir) -name 'Module.symvers') ++# KBUILD_EXTRA_SYMBOLS += $(symbol_files) ++# export KBUILD_EXTRA_SYMBOLS ++ ++# top root: install_rootfs_dir ++install_rootfs_dir:=$(install_root)/rootfs ++ ++install_sodir:=$(install_rootfs_dir)/$(INSTALL_SODIR) ++ ++install_usr_bin_dir:=$(install_rootfs_dir)/usr/bin ++install_sbin_dir:=$(install_rootfs_dir)/sbin ++install_etc_dir:=$(install_rootfs_dir)/etc ++ ++export INSTALL_MOD_PATH:=$(ROOT) ++ ++BUILD_CFLAGS:=$(CFLAGS) -I$(install_header_dir) ++BUILD_LDFLAGS:=$(LDFLAGS) -L/$(install_sodir) -L/$(install_adir) ++ ++define compile_dirs ++.PHONY: $(1) ++$(1): ++ @echo;echo "building $(1)..." ++ @$(MAKE) -C ${1} ++endef ++ ++compile.c = $(CC) $(BUILD_CFLAGS) -d -c -o $@ $< ++%.o: %.c ++ $(compile.c) ++ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/Makefile +new file mode 100644 +index 000000000..8b4bca739 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/Makefile +@@ -0,0 +1,39 @@ ++include ../Rules.mk ++ ++OBJ = fw_upgrade.o fw_upgrade_debug.o ++ ++LIB += $(BUILD_CFALGS) $(BUILD_LDFLAGS) -lpthread ++ifdef ENABLE_GCOV ++ifeq ($(ENABLE_GCOV), y) ++LIB += -fprofile-arcs ++endif ++endif # ENABLE_GCOV ++ ++APP = fw_upgrade ++BUILD_DIR = tmp ++ELF_FILE = $(BUILD_DIR)/$(APP) ++MAP_FILE = $(BUILD_DIR)/$(APP).map.sym ++INCLUDE = -Iinclude ++CFLAGS+=-Wall -W -g ++ ++.PHONY: build ++build:make-dir $(addprefix $(BUILD_DIR)/,$(OBJ)) ++ $(CC) -o $(ELF_FILE) $(addprefix $(BUILD_DIR)/,$(OBJ)) $(LINKFLAGS) $(LIB) ++ ++ cp -p $(ELF_FILE) $(common_out_put_dir) ++ ++.PHONY: make-dir ++make-dir: ++ @mkdir -p $(BUILD_DIR) ++ ++$(BUILD_DIR)/%.o:%.c ++ $(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@ ++ ++.PHONY: install ++install: ++ echo "fw_upgrade install success." ++ cp -p $(ELF_FILE) $(common_out_put_dir) ++ ++.PHONY: clean ++clean: ++ rm -rf $(BUILD_DIR) +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade.c b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade.c +new file mode 100644 +index 000000000..2045608d5 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade.c +@@ -0,0 +1,1632 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "fw_upgrade.h" ++ ++static flash_info_t flash_info[] = { ++ { ++ .flash_name = "M25L6433F", ++ .flash_size = M32, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = MX25L6433F, ++ .block_size = STEP_64, ++ .full_erase = 1, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++ { ++ .flash_name = "S25FL512S", ++ .flash_size = M64, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = S25FL512S, ++ .block_size = STEP_256, ++ .full_erase = 0, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++ { ++ .flash_name = "MX25l512", ++ .flash_size = M64, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = MX25l512, ++ .block_size = STEP_64, ++ .full_erase = 1, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++ { ++ .flash_name = "STM25P64", ++ .flash_size = M12, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = STM25P64, ++ .block_size = STEP_256, ++ .full_erase = 1, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++ { ++ .flash_name = "STM25P128", ++ .flash_size = M16, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = STM25P128, ++ .block_size = STEP_256, ++ .full_erase = 1, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++ { ++ .flash_name = "N25Q256", ++ .flash_size = M16, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = N25Q256, ++ .block_size = STEP_256, ++ .full_erase = 1, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++ { ++ .flash_name = "N25Q512", ++ .flash_size = M16, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = N25Q512, ++ .block_size = STEP_256, ++ .full_erase = 1, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++ { ++ .flash_name = "W25X16", ++ .flash_size = M3, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = W25X16, ++ .block_size = STEP_256, ++ .full_erase = 1, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++ { ++ .flash_name = "W25X64", ++ .flash_size = M12, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = W25X64, ++ .block_size = STEP_256, ++ .full_erase = 1, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++ { ++ .flash_name = "W25Q64BV", ++ .flash_size = M12, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = W25Q64BV, ++ .block_size = STEP_256, ++ .full_erase = 1, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++ { ++ .flash_name = "W25Q128BV", ++ .flash_size = M16, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = W25Q128BV, ++ .block_size = STEP_256, ++ .full_erase = 1, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++ { ++ .flash_name = "W25Q256FV", ++ .flash_size = M16, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = W25Q256FV, ++ .block_size = STEP_256, ++ .full_erase = 1, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++ { ++ .flash_name = "MX25L1605D", ++ .flash_size = M32, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = MX25L1605D, ++ .block_size = STEP_256, ++ .full_erase = 1, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++ { ++ .flash_name = "MX25L12805D", ++ .flash_size = M32, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = MX25L12805D, ++ .block_size = STEP_256, ++ .full_erase = 1, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++ { ++ .flash_name = "MX66L1G45G", ++ .flash_size = M128, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = MX66L1G45G, ++ .block_size = STEP_256, ++ .full_erase = 1, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++ { ++ .flash_name = "GD25Q256", ++ .flash_size = M16, ++ .flash_type = SPI, ++ .page_size = BYTE_256, ++ .flash_id = GD25Q256, ++ .block_size = STEP_256, ++ .full_erase = 1, ++ .erase_block_command = BLOCK_ERASE_64, ++ .page_program = COMMON_PAGE_PROGRAM, ++ }, ++}; ++ ++static int debug_on; ++ ++static void help(void) ++{ ++ printf("------------------------------BMC Upgrade Tool--------------------------------\n"); ++ printf("Program Flash:\n"); ++ printf("\tfw_upgrade upgrade [file name] [chip select: 0 | 1 | 2] "); ++ printf("[erase type: full | block]\n"); ++ printf("\t[file name] if file is not located at /home/admin, path should be added\n"); ++ printf("\t[chip select] 0:master, 1:slave, 2:both\n"); ++ printf("\t[erase type] choose a way to erase chip, full erase would be faster\n"); ++ printf("Read BMC Reg:\n"); ++ printf("\tfw_upgrade rd [address] [length]\n"); ++ printf("\t[address(Hexadecimal)] register address of BMC\n"); ++ printf("\t[length(decimal)] length of read data, should be times of 4\n"); ++ ++ return; ++} ++ ++static int set_ioport_rw_access(void) ++{ ++ ++ if ( iopl(3) < 0) { ++ printf("Can't get access to /dev/port \n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int get_file_size(char *file_name) ++{ ++ FILE * pFile; ++ int size; ++ ++ pFile = fopen(file_name,"rb"); ++ if (pFile == NULL) { ++ printf("Error opening file\n"); ++ return -1; ++ } ++ fseek (pFile, 0, SEEK_END); ++ size = ftell(pFile); ++ fclose (pFile); ++ return size; ++} ++ ++static uint8_t _read(uint16_t addr) ++{ ++ return inb(addr); ++} ++ ++static void _write(uint16_t addr, uint8_t val) ++{ ++ outb(val, addr); ++ ++ return; ++} ++ ++static void write_addr_port(uint8_t addr_val, uint16_t addr_port) ++{ ++ _write(addr_port, addr_val); ++ ++ return; ++} ++ ++static void write_data_port(uint8_t val, uint16_t data_port) ++{ ++ _write(data_port, val); ++ ++ return; ++} ++ ++static uint8_t read_data_port(uint16_t data_port) ++{ ++ return _read(data_port); ++} ++ ++static void write_ilpc2ahb_addr(uint32_t addr) ++{ ++ int i; ++ ++ for (i = 0; i < 4; i++) { ++ write_addr_port(SUPERIO_REG0 + i, LPC_ADDR_PORT); ++ write_data_port((addr >> (8 * (3 - i))) & MASK, LPC_DATA_PORT); ++ } ++ ++ return; ++} ++ ++static void write_ilpc2ahb_data(uint32_t data) ++{ ++ int i; ++ ++ for (i = 0; i < 4; i++) { ++ write_addr_port(SUPERIO_REG4 + i, LPC_ADDR_PORT); ++ write_data_port((data >> (8 * (3 - i))) & MASK, LPC_DATA_PORT); ++ } ++ ++ return; ++} ++ ++static uint32_t read_ilpc2ahb_data(void) ++{ ++ int i, tmp; ++ uint32_t res; ++ ++ res = 0; ++ for (i = 0; i < 4; i++) { ++ write_addr_port(SUPERIO_REG4 + i, LPC_ADDR_PORT); ++ tmp = read_data_port(LPC_DATA_PORT); ++ res |= (tmp << (8 * (3 - i))); ++ } ++ ++ return res; ++} ++ ++static void trigger_ilpc2ahb_read(void) ++{ ++ write_addr_port(SUPERIO_FE, LPC_ADDR_PORT); ++ read_data_port(LPC_DATA_PORT); ++ ++ return; ++} ++ ++static void trigger_ilpc2ahb_write(void) ++{ ++ write_addr_port(SUPERIO_FE, LPC_ADDR_PORT); ++ write_data_port(TOGGLE_WRITE, LPC_DATA_PORT); ++ ++ return; ++} ++ ++static uint32_t read_bmc_reg(uint32_t addr) ++{ ++ uint32_t res; ++ ++ write_ilpc2ahb_addr(addr); ++ trigger_ilpc2ahb_read(); ++ res = read_ilpc2ahb_data(); ++ ++ return res; ++} ++ ++static void write_bmc_reg(uint32_t addr, uint32_t val) ++{ ++ write_ilpc2ahb_addr(addr); ++ write_ilpc2ahb_data(val); ++ trigger_ilpc2ahb_write(); ++ ++ return; ++} ++ ++static uint32_t read_bmc_flash_data(void) ++{ ++ uint32_t res; ++ ++ trigger_ilpc2ahb_read(); ++ res = read_ilpc2ahb_data(); ++ ++ return res; ++} ++ ++static void write_bmc_flash_data(uint32_t data) ++{ ++ write_ilpc2ahb_data(data); ++ trigger_ilpc2ahb_write(); ++ ++ return; ++} ++ ++static void write_bmc_flash_addr(uint32_t addr) ++{ ++ int i; ++ ++ for (i = 0; i < 4; i++) { ++ write_addr_port(SUPERIO_REG4 + i, LPC_ADDR_PORT); ++ write_data_port((addr >> (8 * i)) & MASK, LPC_DATA_PORT); ++ } ++ ++ trigger_ilpc2ahb_write(); ++ ++ return; ++} ++ ++static void enable_bytes(int byte) ++{ ++ write_addr_port(SUPERIO_REG8, LPC_ADDR_PORT); ++ switch (byte) { ++ case BYTE1: ++ write_data_port(SUPERIO_A0 + BYTE1_VAL, LPC_DATA_PORT); ++ break; ++ case BYTE2: ++ write_data_port(SUPERIO_A0 + BYTE2_VAL, LPC_DATA_PORT); ++ break; ++ case BYTE4: ++ write_data_port(SUPERIO_A0 + BYTE4_VAL, LPC_DATA_PORT); ++ break; ++ default: ++ write_data_port(SUPERIO_A0 + BYTE_RESERVED, LPC_DATA_PORT); ++ break; ++ } ++ ++ return; ++} ++ ++static void pull_ce_down(flash_info_t* info) ++{ ++ write_bmc_reg(info->ce_control_reg, USER_MODE_PULL_CE_DOWN); ++ ++ return; ++} ++ ++static void pull_ce_up(flash_info_t* info) ++{ ++ write_bmc_reg(info->ce_control_reg, USER_MODE_PULL_CE_UP); ++ ++ return; ++} ++ ++static void send_cmd(uint32_t flash_base_addr, int cmd) ++{ ++ write_ilpc2ahb_addr(flash_base_addr); ++ enable_bytes(1); ++ write_addr_port(SUPERIO_REG7, LPC_ADDR_PORT); ++ write_data_port(cmd & MASK, LPC_DATA_PORT); ++ trigger_ilpc2ahb_write(); ++ enable_bytes(4); ++ ++ return; ++} ++ ++static void send_cmd_to_flash(flash_info_t* info, int cmd) ++{ ++ pull_ce_down(info); ++ send_cmd(info->flash_base_addr, cmd); ++ pull_ce_up(info); ++ ++ return; ++} ++ ++static void check_data_length(void) ++{ ++ uint8_t tmp; ++ /* Data length check, 4 bytes */ ++ write_addr_port(SUPERIO_REG8, LPC_ADDR_PORT); ++ tmp = read_data_port(LPC_DATA_PORT); ++ if (tmp != SUPERIO_A2) { ++ write_data_port(SUPERIO_A2, LPC_DATA_PORT); ++ } ++ ++ return; ++} ++ ++static void enable_ilpc2ahb(void) ++{ ++ /* Write 0xAA then write 0xA5 twice to enable super IO*/ ++ write_addr_port(DISABLE_LPC, LPC_ADDR_PORT); ++ write_addr_port(ENABLE_LPC, LPC_ADDR_PORT); ++ write_addr_port(ENABLE_LPC, LPC_ADDR_PORT); ++ ++ /* Enable iLPC2AHB */ ++ write_addr_port(SUPERIO_07, LPC_ADDR_PORT); ++ write_data_port(LPC_TO_AHB, LPC_DATA_PORT); ++ write_addr_port(SUPERIO_30, LPC_ADDR_PORT); ++ write_data_port(ENABLE_LPC_TO_AHB, LPC_DATA_PORT); ++ ++ /* Data length */ ++ check_data_length(); ++ ++ return; ++} ++ ++static void disable_ilpc2ahb(void) ++{ ++ /* disable ilpc2ahb */ ++ write_addr_port(SUPERIO_30, LPC_ADDR_PORT); ++ write_data_port(DISABLE_LPC_TO_AHB, LPC_DATA_PORT); ++ /* disable super IO */ ++ write_addr_port(DISABLE_LPC, LPC_ADDR_PORT); ++ ++ return; ++} ++ ++/* Enable CPU */ ++static void enable_cpu(void) ++{ ++ /* unlock SCU register */ ++ write_bmc_reg(SCU_ADDR, UNLOCK_SCU_KEY); ++ /* enable ARM */ ++ write_bmc_reg(REBOOT_CPU_REGISTER, SET_BMC_CPU_BOOT); ++ /* lock SCU register */ ++ write_bmc_reg(SCU_ADDR, LOCK_SCU_KEY); ++ ++ return; ++} ++ ++/* diasble CPU */ ++static void disable_cpu(void) ++{ ++ uint32_t scu_hw_strap_val; ++ ++ /* unlock SCU register */ ++ write_bmc_reg(SCU_ADDR, UNLOCK_SCU_KEY); ++ /* disable ARM */ ++ scu_hw_strap_val = read_bmc_reg(HARDWARE_STRAP_REGISTER); ++ write_bmc_reg(HARDWARE_STRAP_REGISTER, scu_hw_strap_val |0x01); ++ /* lock SCU register */ ++ write_bmc_reg(SCU_ADDR, LOCK_SCU_KEY); ++ ++ return; ++} ++ ++static void enable_upgrade(void) ++{ ++ ++ enable_ilpc2ahb(); ++ /* diasble CPU */ ++ disable_cpu(); ++ /* init CE control register */ ++ write_bmc_reg(CE0_CONTROL_REGISTER, 0); ++ write_bmc_reg(CE1_CONTROL_REGISTER, 0); ++ /* disable WDT2 */ ++ write_bmc_reg(WATCHDOG2_CONTROL, DISABLE_WATCHDOG); ++ ++ return; ++} ++ ++static void disable_upgrade(void) ++{ ++ enable_cpu(); ++ dbg_print(debug_on, "DEBUG 0x%x\n", read_bmc_reg(HARDWARE_STRAP_REGISTER)); ++ disable_ilpc2ahb(); ++ ++ return; ++} ++ ++static void watchdog_status_debug(void) ++{ ++ uint32_t watchdog_reg; ++ ++ /* Watchdog Control Register */ ++ watchdog_reg = read_bmc_reg(WATCHDOG2_CONTROL); ++ dbg_print(debug_on,"Watchdog Control Register: 0x%x\n", watchdog_reg); ++ dbg_print(debug_on,"Watchdog Enable Signal: 0x%x\n", watchdog_reg & BIT1); ++ dbg_print(debug_on,"Watchdog Reset SyS En: 0x%x\n", (watchdog_reg & BIT2) >> 1); ++ dbg_print(debug_on,"Watchdog Reset Mode: 0x%x\n", (watchdog_reg & (BIT6 | BIT7)) >> 5); ++ switch (watchdog_reg & (BIT6 | BIT7)) { ++ case SOC_SYS: ++ dbg_print(debug_on,"\tReset Mode En: SoC System\n"); ++ break; ++ case FULL_CHIP: ++ dbg_print(debug_on,"\tReset Mode En: Full Chip\n"); ++ break; ++ case ARM_CPU: ++ dbg_print(debug_on,"\tReset Mode En: ARM Cpu\n"); ++ break; ++ default: ++ break; ++ } ++ ++ /* Watchdog Timeout Status Register */ ++ watchdog_reg = read_bmc_reg(WATCHDOG2_TSR); ++ dbg_print(debug_on,"Watchdog Timeout Occur: 0x%x\n", watchdog_reg & BIT1); ++ dbg_print(debug_on,"Watchdog Boot from: CD%d\n", watchdog_reg & BIT2); ++ dbg_print(debug_on,"Watchdog Interrupt Occur: 0x%x\n", watchdog_reg & BIT3); ++ ++ return; ++} ++ ++/* CE Type Setting Register */ ++static void ce_type_setting_debug(void) ++{ ++ uint32_t fmc_reg; ++ ++ fmc_reg = read_bmc_reg(FMC_CE_TYPE_SETTING_REG); ++ if ((fmc_reg & CE0_SPI_TYPE) == SPI) { ++ dbg_print(debug_on,"CE0 Type Seeting: 0x%x, Type: SPI\n", fmc_reg & CE0_SPI_TYPE); ++ } else { ++ dbg_print(debug_on,"CE0 Type Seeting: 0x%x, Type: Unknown\n", fmc_reg & CE0_SPI_TYPE); ++ } ++ if (((fmc_reg & CE1_SPI_TYPE) >> BIT2) == SPI) { ++ dbg_print(debug_on,"CE1 Type Seeting: 0x%x, Type: SPI\n", (fmc_reg & CE1_SPI_TYPE) >> BIT2); ++ } else { ++ dbg_print(debug_on,"CE1 Type Seeting: 0x%x, Type: Unknown\n", (fmc_reg & CE1_SPI_TYPE) >> BIT2); ++ } ++ ++ return; ++} ++/* CE Control Register */ ++static void ce_control_debug(void) ++{ ++ uint32_t fmc_reg; ++ ++ fmc_reg = read_bmc_reg(CE_CONTROL_REGISTER); ++ dbg_print(debug_on,"CE0 Address Mode: 0x%x, Mode: %d Bytes\n", ++ fmc_reg & BIT1, (fmc_reg & BIT1) + 3); ++ dbg_print(debug_on,"CE1 Address Mode: 0x%x, Mode: %d Bytes\n", ++ (fmc_reg & BIT2) >> 1, ((fmc_reg & BIT2) >> 1) + 3); ++ ++ return; ++} ++ ++/* Interrupt Control & Status Register */ ++static void irq_control_status_debug(void) ++{ ++ uint32_t fmc_reg; ++ ++ fmc_reg = read_bmc_reg(INR_STATUS_CONTROL_REGISTER); ++ dbg_print(debug_on,"SPI Write Address Protected Interrupt EN: 0x%x\n", fmc_reg & BIT2); ++ dbg_print(debug_on,"SPI Command Abort Interrupt EN: 0x%x\n", fmc_reg & BIT3); ++ dbg_print(debug_on,"SPI Write Address Protected Status: 0x%x, Status: %s\n", ++ RIGHT_SHIFT_8(fmc_reg) & BIT2, (RIGHT_SHIFT_8(fmc_reg) & BIT2) == BIT2 ? "Occur" : "Normal"); ++ dbg_print(debug_on,"SPI Command Abort Status: 0x%x, Status: %s\n", ++ RIGHT_SHIFT_8(fmc_reg) & BIT3, (RIGHT_SHIFT_8(fmc_reg) & BIT3) == BIT3 ? "Occur" : "Normal"); ++ /*Clear Abnormal Status*/ ++ if ((RIGHT_SHIFT_8(fmc_reg) & BIT3) || (RIGHT_SHIFT_8(fmc_reg) & BIT2)) { ++ write_bmc_reg(INR_STATUS_CONTROL_REGISTER, CLEAR_INR_STATUS_CONTROL); ++ } ++ ++ return; ++} ++ ++/* Command Control Register */ ++static void command_control_debug(void) ++{ ++ uint32_t fmc_reg; ++ ++ fmc_reg = read_bmc_reg(COMMAND_CONTROL_REGISTER); ++ dbg_print(debug_on,"Data Byte Line 0: %s\n", ((fmc_reg & BIT4) != 0) ? "Disable" : "Enable"); ++ dbg_print(debug_on,"Data Byte Line 1: %s\n", ((fmc_reg & BIT3) != 0) ? "Disable" : "Enable"); ++ dbg_print(debug_on,"Data Byte Line 2: %s\n", ((fmc_reg & BIT2) != 0) ? "Disable" : "Enable"); ++ dbg_print(debug_on,"Data Byte Line 3: %s\n", ((fmc_reg & BIT1) != 0) ? "Disable" : "Enable"); ++ ++ dbg_print(debug_on,"Address Byte Line 0: %s\n", ((fmc_reg & BIT8) != 0) ? "Disable" : "Enable"); ++ dbg_print(debug_on,"Address Byte Line 1: %s\n", ((fmc_reg & BIT7) != 0) ? "Disable" : "Enable"); ++ dbg_print(debug_on,"Address Byte Line 2: %s\n", ((fmc_reg & BIT6) != 0) ? "Disable" : "Enable"); ++ dbg_print(debug_on,"Address Byte Line 3: %s\n", ((fmc_reg & BIT5) != 0) ? "Disable" : "Enable"); ++ ++ return; ++} ++ ++static void ce_control_reg_debug(void) ++{ ++ uint32_t fmc_reg; ++ ++ /* CE0 Control Register */ ++ fmc_reg = read_bmc_reg(CE0_CONTROL_REGISTER); ++ switch (fmc_reg & (BIT1 | BIT2)){ ++ case NORMAL_READ: ++ dbg_print(debug_on,"CE0 Command Mode: Normal Read\n"); ++ break; ++ case READ_MODE: ++ dbg_print(debug_on,"CE0 Command Mode: Read Command\n"); ++ break; ++ case WRITE_MODE: ++ dbg_print(debug_on,"CE0 Command Mode: Write Command\n"); ++ break; ++ case USER_MODE: ++ dbg_print(debug_on,"CE0 Command Mode: User Mode\n"); ++ break; ++ default: ++ break; ++ } ++ switch((RIGHT_SHIFT_24(fmc_reg) & (BIT5 | BIT6 | BIT7))){ ++ case 0: ++ dbg_print(debug_on,"CE0 IO Mode: Single Mode\n"); ++ break; ++ case 2: ++ case 3: ++ dbg_print(debug_on,"CE0 IO Mode: Dual Mode\n"); ++ break; ++ default: ++ break; ++ } ++ ++ dbg_print(debug_on,"CE0 Inactive Pulse Width: %d HCLK\n", ++ DEFAULT_WIDTH - (RIGHT_SHIFT_24(fmc_reg) & (BIT1 | BIT2 | BIT3 | BIT4))); ++ dbg_print(debug_on,"CE0 Data Input Mode: %s Mode\n", (fmc_reg & BIT4) == 0 ? "Single" : "Dual"); ++ dbg_print(debug_on,"CE0 MSB | LSB: %s First\n", (fmc_reg & BIT6) == 0 ? "MSB" : "LSB"); ++ ++ /* CE1 Control Register */ ++ fmc_reg = read_bmc_reg(CE1_CONTROL_REGISTER); ++ switch (fmc_reg & (BIT1 | BIT2)){ ++ case NORMAL_READ: ++ dbg_print(debug_on,"CE1 Command Mode: Normal Read\n"); ++ break; ++ case READ_MODE: ++ dbg_print(debug_on,"CE1 Command Mode: Read Command\n"); ++ break; ++ case WRITE_MODE: ++ dbg_print(debug_on,"CE1 Command Mode: Write Command\n"); ++ break; ++ case USER_MODE: ++ dbg_print(debug_on,"CE1 Command Mode: User Mode\n"); ++ break; ++ default: ++ break; ++ } ++ switch((RIGHT_SHIFT_24(fmc_reg) & (BIT5 | BIT6 | BIT7))){ ++ case 0: ++ dbg_print(debug_on,"CE1 IO Mode: Single Mode\n"); ++ break; ++ case 2: ++ case 3: ++ dbg_print(debug_on,"CE1 IO Mode: Dual Mode\n"); ++ break; ++ default: ++ break; ++ } ++ ++ dbg_print(debug_on,"CE1 Inactive Pulse Width: %d HCLK\n", ++ DEFAULT_WIDTH - (RIGHT_SHIFT_24(fmc_reg) & (BIT1 | BIT2 | BIT3 | BIT4))); ++ dbg_print(debug_on,"CE1 Data Input Mode: %s Mode\n", (fmc_reg & BIT4) == 0 ? "Single" : "Dual"); ++ dbg_print(debug_on,"CE1 MSB | LSB: %s First\n", (fmc_reg & BIT6) == 0 ? "MSB" : "LSB"); ++ ++ return; ++} ++ ++static void fmc_debug(void) ++{ ++ ce_type_setting_debug(); ++ ce_control_debug(); ++ irq_control_status_debug(); ++ command_control_debug(); ++ ce_control_reg_debug(); ++ ++ return; ++} ++ ++/* Enable WatchDog to reset BMC*/ ++static void enable_watchdog(int cs) ++{ ++ uint32_t enable_watch_cmd; ++ ++ enable_watch_cmd = (cs == CE0) ? ENABLE_WATCHDOG : ENABLE_WATCHDOG | BOOT_DEFAULT_MASK; ++ write_bmc_reg(WATCHDOG2_CLEAR_STATUS, CLEAR_WATCHDOG_STATUS); ++ write_bmc_reg(WATCHDOG2_RESET_FUN_MASK, WATCHDOG_GATEMASK); ++ write_bmc_reg(WATCHDOG2_RELOAD_VALUE, WATCHDOG_NEW_COUNT); ++ write_bmc_reg(WATCHDOG2_COUNTER_RST, WATCHDOG_RELOAD_COUNTER); ++ write_bmc_reg(WATCHDOG2_CONTROL, enable_watch_cmd); ++ ++ return; ++} ++ ++static void bmc_reboot(int cs) ++{ ++ enable_watchdog(cs); ++ watchdog_status_debug(); ++ disable_upgrade(); ++ printf("Upgrade-Complete, BMC rebooting...\n"); ++ ++ return; ++} ++ ++static int get_current_bmc(void) ++{ ++ return (read_bmc_reg(WATCHDOG2_TSR) & 0x02) >> 1; ++} ++ ++static void get_flash_base_and_ce_ctrl(int current_bmc, int cs, uint32_t *flash_base_addr, uint32_t *ce_ctrl_addr) ++{ ++ uint32_t ce0_addr_range_reg_val, ce0_decode_addr; ++ uint32_t ce1_addr_range_reg_val, ce1_decode_addr; ++ ++ ce0_addr_range_reg_val = read_bmc_reg(CE0_ADDRESS_RANGE_REGISTER); ++ ce0_decode_addr = SEGMENT_ADDR_START(ce0_addr_range_reg_val); ++ ce1_addr_range_reg_val = read_bmc_reg(CE1_ADDRESS_RANGE_REGISTER); ++ ce1_decode_addr = SEGMENT_ADDR_START(ce1_addr_range_reg_val); ++ dbg_print(debug_on,"CE0 addr decode range reg value:0x%08x, decode addr:0x%08x.\n", ++ ce0_addr_range_reg_val, ce0_decode_addr); ++ dbg_print(debug_on,"CE1 addr decode range reg value:0x%08x, decode addr:0x%08x.\n", ++ ce1_addr_range_reg_val, ce1_decode_addr); ++ ++ if (((current_bmc == CURRENT_MASTER) && (cs ==CE0)) || ((current_bmc == CURRENT_SLAVE) && (cs ==CE1))) { ++ *ce_ctrl_addr = CE0_CONTROL_REGISTER; ++ *flash_base_addr = ce0_decode_addr; ++ } else { ++ *ce_ctrl_addr = CE1_CONTROL_REGISTER; ++ *flash_base_addr = ce1_decode_addr; ++ } ++ ++ return; ++} ++ ++static int get_flash_id(uint32_t flash_base_addr, uint32_t ce_ctrl_addr) ++{ ++ uint32_t origin_flash_id, flash_id; ++ ++ write_bmc_reg(ce_ctrl_addr, USER_MODE_PULL_CE_DOWN); ++ send_cmd(flash_base_addr, READID); ++ origin_flash_id = read_bmc_flash_data(); ++ write_bmc_reg(ce_ctrl_addr, USER_MODE_PULL_CE_UP); ++ flash_id = origin_flash_id & 0xFFFFFF; ++ dbg_print(debug_on,"origin flash id:0x%x, flash id:0x%x\n", origin_flash_id, flash_id); ++ ++ return flash_id; ++} ++ ++static uint8_t get_flash_status(flash_info_t* info) ++{ ++ uint8_t flash_status; ++ ++ pull_ce_down(info); ++ ++ send_cmd(info->flash_base_addr, READ_FLASH_STATUS); ++ ++ flash_status = read_bmc_flash_data() & MASK; ++ pull_ce_up(info); ++ ++ dbg_print(debug_on,"get_flash_status:0x%x\n", flash_status); ++ return flash_status; ++} ++ ++static int check_flash_write_enable(flash_info_t* info) ++{ ++ uint8_t flash_status; ++ int i, count; ++ ++ count = FLASH_WEL_TIMEOUT / FLASH_WEL_SLEEP_TIME; ++ for (i = 0; i <= count; i++) { ++ flash_status = get_flash_status(info); ++ if ((flash_status & FLASH_WRITE_ENABLE_MASK) != FLASH_WRITE_ENABLE_MASK) { ++ usleep(FLASH_WEL_SLEEP_TIME); ++ } else { ++ dbg_print(debug_on,"Check flash WEL success, RDSR:0x%x\n", flash_status); ++ return 0; ++ } ++ } ++ printf("Check flash WEL timeout, RDSR:0x%x\n", flash_status); ++ return -1; ++} ++ ++static int check_flash_write_process(flash_info_t* info, int timeout, int sleep_time) ++{ ++ int i, count; ++ uint8_t flash_status; ++ ++ count = timeout / sleep_time; ++ for (i = 0; i <= count; i++) { ++ flash_status = get_flash_status(info); ++ if ((flash_status & FLASH_WIP_MASK) != 0) { ++ usleep(sleep_time); ++ } else { ++ dbg_print(debug_on,"Check flash WIP success, RDSR:0x%x\n", flash_status); ++ return 0; ++ } ++ } ++ printf("Check flash WIP timeout, RDSR:0x%x.\n", flash_status); ++ return -1; ++} ++ ++static int flash_write_enable(flash_info_t* info) ++{ ++ int ret; ++ ++ send_cmd_to_flash(info, WRITE_ENABLE_FLASH); ++ ret = check_flash_write_enable(info); ++ if (ret < 0) { ++ return -1; ++ } ++ return 0; ++} ++ ++static void send_block_erase_cmd(flash_info_t* info, uint32_t block_addr) ++{ ++ pull_ce_down(info); ++ send_cmd(info->flash_base_addr, info->erase_block_command); ++ write_bmc_flash_addr(block_addr); /* Erase Block addr */ ++ pull_ce_up(info); ++ ++ return; ++} ++ ++static void send_chip_erase_cmd(flash_info_t* info) ++{ ++ send_cmd_to_flash(info, CHIP_ERASE_FLASH); ++ ++ return; ++} ++ ++static int write_bmc_flash_page(flash_info_t* info, uint32_t page_addr, uint8_t *p, int len) ++{ ++ int pos; ++ ++ if (len % 4) { ++ printf("Page size %d invalid.\n", len); ++ return -1; ++ } ++ ++ pos = 0; ++ pull_ce_down(info); ++ send_cmd(info->flash_base_addr, info->page_program); ++ write_bmc_flash_addr(page_addr); /* page address */ ++ while (len) { ++ write_bmc_flash_data((*(uint32_t *)(p + pos))); ++ pos += 4; ++ len -= 4; ++ } ++ pull_ce_up(info); ++ ++ return 0; ++} ++ ++static int erase_chip_full(flash_info_t* info) ++{ ++ time_t timep; ++ int ret; ++ ++ if (info->full_erase == 0) { ++ printf("Flash not support full erase function.\n"); ++ return -1; ++ } ++ ++ ret = flash_write_enable(info); ++ if(ret < 0) { ++ printf("Chip erase, enable flash write error.\n"); ++ return -1; ++ } ++ ++ time(&timep); ++ printf("Full chip erasing, please wait...\n"); ++ dbg_print(debug_on,"Erase Start-%s\n",asctime(gmtime(&timep))); ++ send_chip_erase_cmd(info); ++ ret = check_flash_write_process(info, CHIP_ERASE_TIMEOUT, CHIP_ERASE_SLEEP_TIME); ++ if (ret < 0) { ++ printf("Chip erase timeout.\n"); ++ return -1; ++ } ++ time(&timep); ++ dbg_print(debug_on,"Erase Finish-%s\n",asctime(gmtime(&timep))); ++ printf("Erase Finish\n"); ++ printf("=========================================\n"); ++ return 0; ++} ++ ++static int erase_chip_block(flash_info_t* info) ++{ ++ uint32_t block_addr, end_addr; ++ time_t timep; ++ int ret; ++ ++ printf("Block erasing...\n"); ++ time (&timep); ++ dbg_print(debug_on,"Erase-Start-%s\n", asctime(gmtime(&timep))); ++ end_addr = info->flash_base_addr + info->flash_size; ++ block_addr = info->flash_base_addr; ++ while (1) { ++ /* Enable write */ ++ ret = flash_write_enable(info); ++ if(ret < 0) { ++ printf("Block erase, enable flash write error, block addr:0x%x\n", block_addr); ++ return -1; ++ } ++ ++ send_block_erase_cmd(info, block_addr); ++ /* Erase Block(64KB) MAX time 650ms*/ ++ ret = check_flash_write_process(info, BLOCK_ERASE_TIMEOUT, BLOCK_ERASE_SLEEP_TIME); ++ if (ret < 0) { ++ printf("Block erase, check write status error, block addr:0x%x\n", block_addr); ++ return -1; ++ } ++ printf("\r0x%x", block_addr); ++ fflush(stdout); ++ if (block_addr >= end_addr) { ++ time(&timep); ++ printf("\r\nErase Finish\n"); ++ printf("=========================================\n"); ++ dbg_print(debug_on,"\nEnd-Earse-%s\n",asctime(gmtime(&timep))); ++ break; ++ } ++ block_addr += info->block_size; ++ } ++ return 0; ++} ++ ++static int program_chip(uint32_t file_size, uint8_t *p, flash_info_t* info) ++{ ++ time_t timep; ++ uint32_t page_addr, end_addr; ++ int ret, page_size; ++ ++ page_addr = info->flash_base_addr; ++ page_size = info->page_size; ++ end_addr = file_size + info->flash_base_addr; ++ time (&timep); ++ printf("Programming...\n"); ++ dbg_print(debug_on,"Program Start-%s\n",asctime(gmtime(&timep))); ++ /* Debug info */ ++ fmc_debug(); ++ while (1) { ++ /* Write enable */ ++ ret = flash_write_enable(info); ++ if(ret < 0) { ++ printf("Page program, enable flash write error, page addr:0x%x\n", page_addr); ++ return -1; ++ } ++ ret = write_bmc_flash_page(info, page_addr, p, page_size); ++ if (ret < 0) { ++ printf("Page program, write bmc flash page error, page addr:0x%x\n", page_addr); ++ return -1; ++ } ++ /* page program MAX time 1.5ms */ ++ ret = check_flash_write_process(info, PAGE_PROGRAM_TIMEOUT, PAGE_PROGRAM_SLEEP_TIME); ++ if (ret < 0) { ++ printf("Page program, check write status error, page addr:0x%x\n", page_addr); ++ return -1; ++ } ++ page_addr += page_size; ++ p += page_size; ++ if ((page_addr % 0x10000) == 0) { ++ printf("\r0x%x", page_addr); ++ fflush(stdout); ++ } ++ ++ if (page_addr >= end_addr) { ++ printf("\nProgram Finish\n"); ++ printf("=========================================\n"); ++ time(&timep); ++ dbg_print(debug_on,"\nProgram-End-%s\n",asctime(gmtime(&timep))); ++ break; ++ } ++ } /* End of while (1) */ ++ return 0; ++} ++ ++static int check_chip(uint32_t file_size, uint8_t *p, flash_info_t* info) ++{ ++ time_t timep; ++ uint32_t offset_addr, rd_val, end_addr; ++ int pos; ++ ++ offset_addr = info->flash_base_addr; ++ end_addr = file_size + info->flash_base_addr; ++ pos=0; ++ /* Checking */ ++ time(&timep); ++ printf("Checking...\n"); ++ dbg_print(debug_on,"Checking-Start-%s\n",asctime(gmtime(&timep))); ++ ++ pull_ce_down(info); ++ send_cmd(info->flash_base_addr, COMMON_FLASH_READ); ++ write_bmc_flash_addr(info->flash_base_addr); ++ while (1) { ++ if (offset_addr >= end_addr) { ++ break; ++ } ++ rd_val = read_bmc_flash_data(); ++ if (rd_val != (*(uint32_t *)(p + pos))) { ++ printf("Check Error at 0x%08x\n", offset_addr); ++ printf("READ:0x%08x VALUE:0x%08x\n", rd_val, (*(uint32_t *)(p + pos))); ++ pull_ce_up(info); ++ return -1; ++ } ++ if ((offset_addr % 0x10000) == 0) { ++ printf("\r0x%x ", offset_addr); ++ fflush(stdout); ++ } ++ offset_addr += 4; ++ pos += 4; ++ } ++ pull_ce_up(info); ++ printf("\r\nFlash Checked\n"); ++ printf("=========================================\n"); ++ time(&timep); ++ dbg_print(debug_on,"Checking-End-%s\n",asctime(gmtime(&timep))); ++ return 0; ++} ++ ++flash_info_t* get_flash_info(int current_bmc, int cs) ++{ ++ int i, size; ++ uint32_t flash_base_addr, ce_ctrl_addr, flash_id; ++ ++ get_flash_base_and_ce_ctrl(current_bmc, cs, &flash_base_addr, &ce_ctrl_addr); ++ ++ size = (sizeof(flash_info) / sizeof((flash_info)[0])); ++ ++ flash_id = get_flash_id(flash_base_addr, ce_ctrl_addr); ++ for (i = 0; i < size; i++) { ++ if (flash_info[i].flash_id == flash_id) { ++ flash_info[i].flash_base_addr = flash_base_addr; ++ flash_info[i].ce_control_reg = ce_ctrl_addr; ++ flash_info[i].cs = cs; ++ return &flash_info[i]; ++ } ++ } ++ printf("Cannot get flash info, cs:%d, flash base addr:0x%x, ce control addr:0x%x, flash_id:0x%x.\n", ++ cs, flash_base_addr, ce_ctrl_addr, flash_id); ++ return NULL; ++} ++ ++static void init_flash(flash_info_t* info) ++{ ++ send_cmd_to_flash(info, RSTEN); ++ send_cmd_to_flash(info, RST); ++ send_cmd_to_flash(info, EXIT_OTP); ++ send_cmd_to_flash(info, ENABLE_BYTE4); ++ ++ return; ++} ++ ++static int upgrade_bmc_core(char *file_name, int erase_type, flash_info_t* info) ++{ ++ int file_size, fp, ret; ++ uint8_t *p; ++ ++ file_size = get_file_size(file_name); ++ if (file_size < 0) { ++ printf("file size %d Error\n", file_size); ++ return -1; ++ } ++ ++ fp = open(file_name, O_RDWR); ++ if (fp < 0) { ++ printf("Cannot open %s.\n", file_name); ++ return -1; ++ } ++ ++ p = mmap(NULL, file_size, PROT_READ, MAP_SHARED, fp, 0); ++ if (p == MAP_FAILED) { ++ printf("Could not mmap %s, error(%s).\n", file_name, strerror(errno)); ++ close(fp); ++ return -1; ++ } ++ ++ printf("* CE%d FLASH TYPE: SPI FLASH\n", info->cs); ++ printf("* FLASH NAME: %s\n", info->flash_name); ++ printf("* File Size:%d, 0x%x\n", file_size, file_size); ++ printf("=========================================\n"); ++ ++ /* Select erase type */ ++ switch (erase_type) { ++ case FULL_ERASE: ++ ret = erase_chip_full(info); ++ break; ++ case BLOCK_ERASE: ++ ret = erase_chip_block(info); ++ break; ++ default: ++ printf("Unsupport earse type:%d\n", erase_type); ++ goto exit; ++ break; ++ } ++ ++ if (ret < 0) { ++ printf("Erase Chip Error\n"); ++ goto exit; ++ } ++ ++ /* Program the flash */ ++ ret = program_chip(file_size, p, info); ++ if(ret < 0) { ++ printf("Program Chip Error\n"); ++ goto exit; ++ } ++ /* Check */ ++ ret = check_chip(file_size, p, info); ++ if(ret < 0) { ++ printf("Check Chip Error\n"); ++ goto exit; ++ } ++ ++ munmap(p, file_size); ++ close(fp); ++ return 0; ++exit: ++ munmap(p, file_size); ++ close(fp); ++ return -1; ++} ++ ++static int upgrade_bmc_flash(char *filename, int current_bmc, int cs, int erase_type) ++{ ++ int ret; ++ flash_info_t* info; ++ ++ info = get_flash_info(current_bmc, cs); ++ if(info == NULL) { ++ return -1; ++ } ++ ++ init_flash(info); ++ ++ ret = upgrade_bmc_core(filename, erase_type, info); ++ ++ return ret; ++} ++ ++static int upgrade_both_flash(char *filename, int erase_type) ++{ ++ int ret, current_bmc; ++ ++ enable_upgrade(); ++ ++ current_bmc = get_current_bmc(); ++ if (current_bmc == CURRENT_MASTER) { ++ printf("* Current Bmc Default Boot: CE0\n"); ++ } else { ++ printf("* Current Bmc Default Boot: CE1\n"); ++ } ++ ++ ret = upgrade_bmc_flash(filename, current_bmc, CE0, erase_type); ++ if (ret < 0) { ++ printf("Upgrade master bmc flash failed, stop upgrade.\n"); ++ goto err; ++ } ++ printf("Upgrade master bmc flash success.\n"); ++ ++ ret = upgrade_bmc_flash(filename, current_bmc, CE1, erase_type); ++ if (ret < 0) { ++ printf("Upgrade slave bmc flash failed.\n"); ++ goto err; ++ } ++ printf("Upgrade slave bmc flash success.\n"); ++ ++ bmc_reboot(CE0); ++ return 0; ++err: ++ disable_upgrade(); ++ return -1; ++} ++ ++static int upgrade_single_flash(char *filename, int cs, int erase_type) ++{ ++ int ret, current_bmc; ++ ++ enable_upgrade(); ++ ++ current_bmc = get_current_bmc(); ++ if (current_bmc == CURRENT_MASTER) { ++ printf("* Current Bmc Default Boot: CE0\n"); ++ } else { ++ printf("* Current Bmc Default Boot: CE1\n"); ++ } ++ ++ ret = upgrade_bmc_flash(filename, current_bmc, cs, erase_type); ++ if (ret < 0) { ++ printf("Upgrade %s bmc flash failed.\n", cs == 0 ? "master":"slave"); ++ goto err; ++ } ++ printf("Upgrade %s bmc flash success.\n", cs == 0 ? "master":"slave"); ++ ++ bmc_reboot(cs); ++ return 0; ++err: ++ disable_upgrade(); ++ return -1; ++} ++ ++static int upgrade_bmc(char *filename, int cs, int erase_type) ++{ ++ int ret; ++ ++ if (access(filename, F_OK) < 0) { ++ printf("Can't find file\n"); ++ help(); ++ return -1; ++ } ++ ++ ret = set_ioport_rw_access(); ++ if (ret < 0) { ++ printf("IO ERROR\n"); ++ return -1; ++ } ++ ++ switch(cs) { ++ /* Single */ ++ case CE0: ++ case CE1: ++ ret = upgrade_single_flash(filename, cs, erase_type); ++ break; ++ /* Both */ ++ case BOTHFLASH: ++ ret = upgrade_both_flash(filename, erase_type); ++ break; ++ default: ++ ret = -1; ++ printf("Unsupport cs:%d\n", cs); ++ break; ++ } ++ ++ return ret; ++} ++ ++static int read_single_bmc_flash(flash_info_t* info, uint32_t start_addr, int read_size, int is_print) ++{ ++ uint32_t res, flash_start_addr, flash_end_addr; ++ char filename[MAX_FILENAME_LENGTH]; ++ int fd, ret; ++ ++ flash_start_addr = info->flash_base_addr + start_addr; ++ flash_end_addr = flash_start_addr + read_size; ++ ret = 0; ++ fd = 0; ++ if (!is_print) { ++ mem_clear(filename, MAX_FILENAME_LENGTH); ++ snprintf(filename, MAX_FILENAME_LENGTH, "/tmp/image-bmc%d", info->cs); ++ fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRWXG|S_IRWXU|S_IRWXO); ++ if (fd < 0) { ++ printf("open file %s fail(err:%d)!\r\n", filename, errno); ++ return -1; ++ } ++ } ++ ++ printf("* CE%d FLASH TYPE: SPI FLASH\n", info->cs); ++ printf("* FLASH NAME: %s\n", info->flash_name); ++ printf("* Read flash addr:0x%x, size:0x%x\n", flash_start_addr, read_size); ++ printf("=========================================\n"); ++ printf("Reading...\n"); ++ ++ pull_ce_down(info); ++ send_cmd(info->flash_base_addr, COMMON_FLASH_READ); ++ write_bmc_flash_addr(flash_start_addr); ++ while (1) { ++ if (flash_start_addr >= flash_end_addr) { ++ break; ++ } ++ res = read_bmc_flash_data(); ++ if (is_print) { ++ printf("addr:0x%08x, val:0x%08x\n", flash_start_addr, res); ++ } else { ++ ret = write(fd, &res, sizeof(res)); ++ if (ret < 0) { ++ printf("write failed (errno: %d).\n", errno); ++ ret = -1; ++ goto exit; ++ } ++ } ++ if (((flash_start_addr % 0x10000) == 0) && (!is_print)) { ++ printf("\r0x%x ", flash_start_addr); ++ fflush(stdout); ++ } ++ flash_start_addr += 4; ++ } ++ printf("\r\nRead Finish\n"); ++ printf("=========================================\n"); ++exit: ++ pull_ce_up(info); ++ if (fd > 0) { ++ close(fd); ++ } ++ return ret; ++} ++ ++static int read_bmc_flash(int cs, uint32_t start_addr, int read_size, int is_print) ++{ ++ int ret, current_bmc; ++ flash_info_t* info; ++ ++ ret = set_ioport_rw_access(); ++ if (ret < 0) { ++ printf("IO ERROR\n"); ++ return -1; ++ } ++ ++ enable_upgrade(); ++ ++ current_bmc = get_current_bmc(); ++ if (current_bmc == CURRENT_MASTER) { ++ printf("* Current Bmc Default Boot: CE0\n"); ++ } else { ++ printf("* Current Bmc Default Boot: CE1\n"); ++ } ++ ++ info = get_flash_info(current_bmc, cs); ++ if(info == NULL) { ++ goto err; ++ } ++ ++ if (start_addr >= info->flash_size) { ++ printf("start_addr 0x%x out of range.\n", start_addr); ++ goto err; ++ } ++ ++ if ((start_addr + read_size) > info->flash_size) { ++ printf("read size %d exceed flash size.\n", read_size); ++ read_size = info->flash_size - start_addr; ++ } ++ ++ init_flash(info); ++ ++ ret = read_single_bmc_flash(info, start_addr, read_size, is_print); ++ if (ret < 0) { ++ printf("Read %s bmc flash failed.\n", cs == 0 ? "master" : "slave"); ++ goto err; ++ } ++ disable_upgrade(); ++ return 0; ++err: ++ disable_upgrade(); ++ return -1; ++} ++ ++static int read_bmc_reg_main(int argc, char* argv[]) ++{ ++ uint32_t start_addr, read_val; ++ int read_size, ret; ++ char *stopstring; ++ ++ if (argc != 4) { ++ printf("Input invalid.\n"); ++ help(); ++ return -1; ++ } ++ ++ start_addr = strtoul(argv[2], &stopstring, 16); ++ read_size = strtol(argv[3], &stopstring, 10); ++ ++ if (read_size <= 0) { ++ printf("read length %d invalid\n", read_size); ++ return -1; ++ } ++ ++ if (((start_addr % 4) != 0) || ((read_size % 4) != 0)) { ++ printf("Params invalid, start_addr:0x%08x, read_size:%d\n", start_addr, read_size); ++ printf("Please input address/length times of 4\n"); ++ return -1; ++ } ++ ++ ret = set_ioport_rw_access(); ++ if (ret < 0) { ++ printf("IO ERROR\n"); ++ return -1; ++ } ++ ++ enable_ilpc2ahb(); ++ ++ printf("read bcm reg, start_addr:0x%08x, read length:%d\n", start_addr, read_size); ++ printf("===Addr=== | ===Cont===\n"); ++ while (read_size) { ++ read_val = read_bmc_reg(start_addr); ++ printf("0x%08x | 0x%08x\n", start_addr, read_val); ++ start_addr += 4; ++ read_size -= 4; ++ } ++ ++ disable_ilpc2ahb(); ++ return 0; ++} ++ ++static int write_bmc_reg_main(int argc, char* argv[]) ++{ ++ uint32_t addr, wr_val; ++ int ret; ++ char *stopstring; ++ ++ if (argc != 4) { ++ printf("Input invalid.\n"); ++ help(); ++ return -1; ++ } ++ ++ addr = strtoul(argv[2], &stopstring, 16); ++ wr_val = strtoul(argv[3], &stopstring, 16); ++ ++ if (((addr & MASK_BYTE) != REGISTER_HEAD) || ((addr % 4) != 0)) { ++ printf("Address[0x%08x] invalid, address should be register address and times of 4.\n", addr); ++ return -1; ++ } ++ ++ ret = set_ioport_rw_access(); ++ if (ret < 0) { ++ printf("IO ERROR\n"); ++ return -1; ++ } ++ ++ printf("write bcm reg, addr:0x%08x, val:0x%08x\n", addr, wr_val); ++ ++ enable_ilpc2ahb(); ++ write_bmc_reg(addr, wr_val); ++ disable_ilpc2ahb(); ++ ++ return 0; ++} ++ ++static int get_fmc_info_main(void) ++{ ++ int ret; ++ ++ ret = set_ioport_rw_access(); ++ if (ret < 0) { ++ printf("IO ERROR\n"); ++ return -1; ++ } ++ ++ enable_ilpc2ahb(); ++ ++ debug_on = 3; ++ fmc_debug(); ++ debug_on = 0; ++ ++ disable_ilpc2ahb(); ++ return 0; ++} ++ ++static int program_flash_main(int argc, char* argv[]) ++{ ++ int cs, erase_way, ret; ++ char *stopstring; ++ char tmp[128]; ++ ++ if (argc != 5) { ++ printf("Input invalid.\n"); ++ help(); ++ return -1; ++ } ++ ++ cs = strtol(argv[3], &stopstring, 10); ++ if ((strlen(stopstring) != 0) || cs < 0 || cs > 2) { ++ snprintf(tmp, sizeof(tmp), "%s", argv[3]); ++ printf("Incorrect chip select %s\n", tmp); ++ help(); ++ return -1; ++ } ++ ++ if (strcmp(argv[4], "full") == 0) { ++ erase_way = FULL_ERASE; ++ } else if (strcmp(argv[4], "block") == 0) { ++ erase_way = BLOCK_ERASE; ++ } else { ++ snprintf(tmp, sizeof(tmp), "%s", argv[4]); ++ printf("Incorrect erase type %s\n", tmp); ++ help(); ++ return -1; ++ } ++ ++ printf("============BMC Upgrade Tool=============\n"); ++ ret = upgrade_bmc(argv[2], cs, erase_way); ++ return ret; ++} ++ ++static int read_bmc_flash_main(int argc, char* argv[]) ++{ ++ int cs, ret, read_size, is_print; ++ uint32_t start_addr; ++ char *stopstring; ++ char tmp[128]; ++ ++ if (argc != 6) { ++ printf("Input invalid.\n"); ++ help(); ++ return -1; ++ } ++ ++ cs = strtol(argv[2], &stopstring, 10); ++ if ((strlen(stopstring) != 0) || cs < 0 || cs > 1) { ++ snprintf(tmp, sizeof(tmp), "%s", argv[2]); ++ printf("Incorrect chip select %s\n", tmp); ++ help(); ++ return -1; ++ } ++ ++ start_addr = strtoul(argv[3], &stopstring, 16); ++ read_size = strtol(argv[4], &stopstring, 10); ++ ++ if (read_size <= 0) { ++ printf("read length %d invalid\n", read_size); ++ return -1; ++ } ++ ++ if (((start_addr % 4) != 0) || ((read_size % 4) != 0)) { ++ printf("Params invalid, start_addr:0x%08x, read_size:%d\n", start_addr, read_size); ++ printf("Please input address/length times of 4\n"); ++ return -1; ++ } ++ ++ if (strcmp(argv[5], "print") == 0) { ++ is_print = 1; ++ } else { ++ is_print = 0; ++ } ++ ++ printf("============READ BMC FLASH=============\n"); ++ ret = read_bmc_flash(cs, start_addr, read_size, is_print); ++ return ret; ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int ret; ++ ++ debug_on = fw_upgrade_debug(); ++ ++ if (argc < 2) { ++ help(); ++ return -1; ++ } ++ ++ if (argc == 2) { ++ if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { ++ help(); ++ return 0; ++ } ++ } ++ ++ if (strcmp(argv[1], "rd") == 0) { ++ ret = read_bmc_reg_main(argc, argv); ++ if (ret < 0) { ++ printf("Read Failed\n"); ++ } ++ return ret; ++ } ++ ++ if (strcmp(argv[1], "wr") == 0 && debug_on == 3) { ++ ret = write_bmc_reg_main(argc, argv); ++ if (ret < 0) { ++ printf("Write Failed\n"); ++ } ++ return ret; ++ } ++ ++ if (strcmp(argv[1], "info") == 0) { ++ ret = get_fmc_info_main(); ++ if (ret < 0) { ++ printf("Get fmc info Failed\n"); ++ } ++ return ret; ++ } ++ ++ if (strcmp(argv[1], "upgrade") == 0) { ++ ret = program_flash_main(argc, argv); ++ if (ret < 0) { ++ printf("Upgrade BMC failed.\n"); ++ } ++ return ret; ++ } ++ ++ if (strcmp(argv[1], "read_bmc_flash") == 0) { ++ ret = read_bmc_flash_main(argc, argv); ++ if (ret < 0) { ++ printf("Read BMC flash failed.\n"); ++ } ++ return ret; ++ } ++ ++ printf("Input invalid.\n"); ++ help(); ++ ++ return -1; ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade_debug.c b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade_debug.c +new file mode 100644 +index 000000000..a7a78d011 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade_debug.c +@@ -0,0 +1,51 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "fw_upgrade_debug.h" ++ ++int fw_upgrade_debug(void) ++{ ++ int size; ++ FILE *fp; ++ char debug_info[DEBUG_INFO_LEN]; ++ ++ fp = fopen(DEBUG_FILE, "r"); ++ if (fp == NULL) { ++ return DEBUG_IGNORE; ++ } ++ ++ mem_clear(debug_info, DEBUG_INFO_LEN); ++ size = fread(debug_info, DEBUG_INFO_LEN - 1, 1, fp); ++ if (size < 0) { ++ fclose(fp); ++ return DEBUG_IGNORE; ++ } ++ ++ if (strncmp(debug_info, DEBUG_ON_INFO, 1) == 0) { ++ fclose(fp); ++ return DEBUG_APP_ON; ++ } ++ ++ if (strncmp(debug_info, DEBUG_ON_KERN, 1) == 0) { ++ fclose(fp); ++ return DEBUG_KERN_ON; ++ } ++ ++ if (strncmp(debug_info, DEBUG_ON_ALL, 1) == 0) { ++ fclose(fp); ++ return DEBUG_ALL_ON; ++ } ++ ++ if (strncmp(debug_info, DEBUG_OFF_INFO, 1) == 0) { ++ fclose(fp); ++ return DEBUG_OFF; ++ } ++ ++ fclose(fp); ++ return DEBUG_IGNORE; ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade.h b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade.h +new file mode 100644 +index 000000000..bd806a94b +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade.h +@@ -0,0 +1,230 @@ ++#ifndef _FW_UPGRADE_H_ ++#define _FW_UPGRADE_H_ ++ ++#include "fw_upgrade_debug.h" ++ ++#define dbg_print(debug, fmt, arg...) \ ++ if (debug == DEBUG_APP_ON || debug == DEBUG_ALL_ON) \ ++ { do{printf(fmt,##arg);} while(0); } ++ ++/* LPC Interface */ ++#define LPC_ADDR_PORT (0x4E) ++#define LPC_DATA_PORT (0x4F) ++ ++/* FMC REGISTER ADDR */ ++#define FMC_BASE_ADDR (0x1E620000) ++#define FMC_CE_TYPE_SETTING_REG (FMC_BASE_ADDR + 0x00) ++#define CE_CONTROL_REGISTER (FMC_BASE_ADDR + 0x04) ++#define INR_STATUS_CONTROL_REGISTER (FMC_BASE_ADDR + 0x08) ++#define COMMAND_CONTROL_REGISTER (FMC_BASE_ADDR + 0x0C) ++#define CE0_CONTROL_REGISTER (FMC_BASE_ADDR + 0x10) ++#define CE1_CONTROL_REGISTER (FMC_BASE_ADDR + 0x14) ++#define CE0_ADDRESS_RANGE_REGISTER (FMC_BASE_ADDR + 0x30) ++#define CE1_ADDRESS_RANGE_REGISTER (FMC_BASE_ADDR + 0x34) ++ ++/* SCU REGISTER ADDR */ ++#define SCU_ADDR (0x1E6E2000) ++#define HARDWARE_STRAP_REGISTER (SCU_ADDR + 0x70) ++#define REBOOT_CPU_REGISTER (SCU_ADDR + 0x7C) ++ ++/* SCU KEY */ ++#define UNLOCK_SCU_KEY (0x1688A8A8) ++#define LOCK_SCU_KEY (0x11111111) ++ ++/* WATCHDOG REGISTER ADDR */ ++#define WATCHDOG_ADDR (0x1E785000) ++#define WATCHDOG1_RELOAD_VALUE (WATCHDOG_ADDR + 0x04) ++#define WATCHDOG1_COUNTER_RST (WATCHDOG_ADDR + 0x08) ++#define WATCHDOG1_CONTROL (WATCHDOG_ADDR + 0x0C) ++#define WATCHDOG1_TSR (WATCHDOG_ADDR + 0x10) ++#define WATCHDOG1_CLEAR_STATUS (WATCHDOG_ADDR + 0x14) ++#define WATCHDOG1_RESET_FUN_MASK (WATCHDOG_ADDR + 0x1C) ++ ++#define WATCHDOG2_RELOAD_VALUE (WATCHDOG_ADDR + 0x24) ++#define WATCHDOG2_COUNTER_RST (WATCHDOG_ADDR + 0x28) ++#define WATCHDOG2_CONTROL (WATCHDOG_ADDR + 0x2C) ++#define WATCHDOG2_TSR (WATCHDOG_ADDR + 0x30) ++#define WATCHDOG2_CLEAR_STATUS (WATCHDOG_ADDR + 0x34) ++#define WATCHDOG2_RESET_FUN_MASK (WATCHDOG_ADDR + 0x3C) ++ ++/* User Mode Command */ ++#define WRITE_STATUS (0x01) ++#define COMMON_PAGE_PROGRAM (0x02) ++#define COMMON_FLASH_READ (0x03) ++#define WRITE_DISABLE_FLASH (0x04) ++#define READ_FLASH_STATUS (0x05) ++#define WRITE_ENABLE_FLASH (0x06) ++#define PAGE_PROGRAM_FLASH (0x12) ++#define SECTOR_ERASE (0x20) ++#define CLEAR_FLAG (0x50) ++#define SUBBLOCK_ERASE (0x52) ++#define CHIP_ERASE_FLASH (0x60) ++#define BLOCK_ERASE_64 (0xD8) ++#define READID (0x9F) ++#define ENABLE_BYTE4 (0xB7) ++#define EXIT_OTP (0xC1) ++#define RSTEN (0x66) ++#define RST (0x99) ++ ++#define BIT1 (0x01) ++#define BIT2 (0x02) ++#define BIT3 (0x04) ++#define BIT4 (0x08) ++#define BIT5 (0x10) ++#define BIT6 (0x20) ++#define BIT7 (0x40) ++#define BIT8 (0x80) ++#define RIGHT_SHIFT_8(reg) (reg >> 8) ++#define RIGHT_SHIFT_16(reg) (reg >> 16) ++#define RIGHT_SHIFT_24(reg) (reg >> 24) ++#define MASK (0xFF) ++#define FLASH_TYPE_MASK (BIT1 | BIT2) ++#define BOOT_DEFAULT_MASK (BIT8) ++#define HEAD_MASK (0x00FFFF00) ++#define MASK_BYTE (0xFF000000) ++#define BYTE1 (1) ++#define BYTE2 (2) ++#define BYTE4 (4) ++#define BYTE1_VAL (0) ++#define BYTE2_VAL (1) ++#define BYTE4_VAL (2) ++#define BYTE_RESERVED (3) ++ ++/* SuperIO */ ++#define SUPERIO_07 (0x07) ++#define SUPERIO_30 (0x30) ++#define SUPERIO_A0 (0xA0) ++#define SUPERIO_A2 (0xA2) ++#define SUPERIO_REG0 (0xF0) ++#define SUPERIO_REG1 (0xF1) ++#define SUPERIO_REG2 (0xF2) ++#define SUPERIO_REG3 (0xF3) ++#define SUPERIO_REG4 (0xF4) ++#define SUPERIO_REG5 (0xF5) ++#define SUPERIO_REG6 (0xF6) ++#define SUPERIO_REG7 (0xF7) ++#define SUPERIO_REG8 (0xF8) ++#define SUPERIO_FE (0xFE) ++ ++/* SPI Command */ ++#define HIGH_CLOCK (0x00000000) ++#define NORMAL_READ (0x00000000) ++#define READ_MODE (0x00000001) ++#define WRITE_MODE (0x00000002) ++#define USER_MODE (0x00000003) ++#define PULL_DOWN (0x00000000) ++#define PULL_UP (0x00000004) ++ ++#define CHIP_ERASE_TIME (60) ++#define CHIP_ERASE_TIMEOUT (300 * 1000 * 1000) ++#define CHIP_ERASE_SLEEP_TIME (5 * 1000 * 1000) ++#define BLOCK_ERASE_TIMEOUT (10 * 1000 * 1000) ++#define BLOCK_ERASE_SLEEP_TIME (100 * 1000) ++#define PAGE_PROGRAM_TIMEOUT (100 * 1000) ++#define PAGE_PROGRAM_SLEEP_TIME (1000) ++#define FLASH_WEL_TIMEOUT (100 * 1000) ++#define FLASH_WEL_SLEEP_TIME (1000) ++#define FLASH_WIP_MASK (0x00000001) ++#define FLASH_WRITE_ENABLE_MASK (0x00000002) ++ ++#define DATA_LENGTH_MASK (0xA2) ++#define TOGGLE_WRITE (0xCF) ++#define DISABLE_LPC (0xAA) ++#define ENABLE_LPC (0xA5) ++#define LPC_TO_AHB (0x0D) ++#define ENABLE_LPC_TO_AHB (0x01) ++#define DISABLE_LPC_TO_AHB (0x00) ++#define ENABLE_BMC_CPU_BOOT (0xF10BD286) ++#define DISABLE_BMC_CPU_BOOT (0xF10BD287) ++#define SET_BMC_CPU_BOOT (0x01) ++#define CLEAR_WATCHDOG_STATUS (0x01) ++#define DISABLE_WATCHDOG (0x00000030) ++#define ENABLE_WATCHDOG (0x00000033) ++#define WATCHDOG_GATEMASK (0x033FFFF3) ++#define WATCHDOG_NEW_COUNT (0x00050000) ++#define WATCHDOG_RELOAD_COUNTER (0x4755) ++ ++#define CE0_SPI_TYPE (0x00000002) ++#define CE1_SPI_TYPE (0x00000008) ++#define ERROR_COMMAND (0x00000400) ++#define ADDRESS_PROTECT (0x00000200) ++#define CLEAR_INR_STATUS_CONTROL (ERROR_COMMAND | ADDRESS_PROTECT) ++#define USER_MODE_PULL_CE_DOWN (HIGH_CLOCK | USER_MODE | PULL_DOWN) ++#define USER_MODE_PULL_CE_UP (HIGH_CLOCK | USER_MODE | PULL_UP) ++ ++#define STEP_64 (64 * 1024) ++#define STEP_256 (256 * 1024) ++#define BYTE_256 (256) ++ ++#define CE0 (0) ++#define CE1 (1) ++#define BOTHFLASH (2) ++#define SOC_SYS (0) ++#define FULL_CHIP (1) ++#define ARM_CPU (2) ++#define FULL_ERASE (0) ++#define BLOCK_ERASE (1) ++#define READ_ALL (2) ++#define CURRENT_SLAVE (1) ++#define CURRENT_MASTER (0) ++#define REGISTER_HEAD (0x1e000000) ++#define DEFAULT_WIDTH (16) ++#define MAX_FILENAME_LENGTH (64) ++#define SEGMENT_ADDR_START(_r) ((((_r) >> 16) & 0xFF) << 23) ++ ++typedef struct flash_info { ++ uint32_t flash_size; ++ int cs; ++ int flash_type; ++ uint32_t flash_id; ++ int page_size; ++ char flash_name[64]; ++ int erase_block_command; ++ int page_program; ++ int block_size; ++ int full_erase; ++ uint32_t ce_control_reg; ++ uint32_t flash_base_addr; ++} flash_info_t; ++ ++typedef enum flash_id { ++ MX25L6433F = 0x1920c2, ++ S25FL512S = 0x200201, ++ MX25l512 = 0x1a20c2, ++ STM25P64 = 0x172020, ++ STM25P128 = 0x182020, ++ N25Q256 = 0x19ba20, ++ N25Q512 = 0x20ba20, ++ W25X16 = 0x1530ef, ++ W25X64 = 0x1730ef, ++ W25Q64BV = 0x1740ef, ++ W25Q128BV = 0x1840ef, ++ W25Q256FV = 0x1940ef, ++ MX25L1605D = 0x1520C2, ++ MX25L12805D = 0x1820C2, ++ MX66L1G45G = 0x1B20C2, ++ SST25VF016B = 0x4125bf, ++ SST25VF064C = 0x4b25bf, ++ SST25VF040B = 0x8d25bf, ++ AT25DF161 = 0x02461F, ++ AT25DF321 = 0x01471F, ++ GD25Q256 = 0X1940c8, ++} flash_id_t; ++ ++typedef enum flash_type { ++ NOR = 0, ++ SPI = 2, ++} flash_type_t; ++ ++typedef enum flash_size { ++ M1 = 0x00080000, ++ M3 = 0x00200000, /* 3M */ ++ M6 = 0x00400000, /* 6M */ ++ M12 = 0x00800000, /* 12M */ ++ M16 = 0x01000000, /* 16M */ ++ M32 = 0x02000000, /* 32M */ ++ M64 = 0x04000000, /* 64M */ ++ M128 = 0x08000000, /* 128M */ ++} flash_size_t; ++ ++#endif /*_FW_UPGRADE_H_*/ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade_debug.h b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade_debug.h +new file mode 100644 +index 000000000..05911da62 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade_debug.h +@@ -0,0 +1,25 @@ ++#ifndef __FW_UPGRADE_DEBUG_H__ ++#define __FW_UPGRADE_DEBUG_H__ ++ ++#include ++ ++#define DEBUG_INFO_LEN 20 ++#define DEBUG_FILE "/tmp/.fw_upgrade_debug" ++#define DEBUG_ON_ALL "3" ++#define DEBUG_ON_KERN "2" ++#define DEBUG_ON_INFO "1" ++#define DEBUG_OFF_INFO "0" ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++ ++enum debug_s { ++ DEBUG_OFF = 0, ++ DEBUG_APP_ON, ++ DEBUG_KERN_ON, ++ DEBUG_ALL_ON, ++ DEBUG_IGNORE, ++}; ++ ++extern int fw_upgrade_debug(void); ++ ++#endif /* End of __FW_UPGRADE_DEBUG_H__ */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/__init__.py +new file mode 100644 +index 000000000..e69de29bb +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/hysteresis.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/hysteresis.py +new file mode 100644 +index 000000000..81fd596e7 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/hysteresis.py +@@ -0,0 +1,169 @@ ++#!/usr/bin/env python3 ++import os ++import syslog ++import copy ++ ++from plat_hal.baseutil import baseutil ++ ++HYST_DEBUG_FILE = "/etc/.hysteresis_debug_flag" ++ ++HYSTERROR = 1 ++HYSTDEBUG = 2 ++ ++debuglevel = 0 ++ ++ ++def hyst_debug(s): ++ if HYSTDEBUG & debuglevel: ++ syslog.openlog("FANCONTROL-HYST", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def hyst_error(s): ++ if HYSTERROR & debuglevel: ++ syslog.openlog("FANCONTROL-HYST", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++class hysteresis(object): ++ __config = None ++ __hyst_config = None ++ ++ def __init__(self): ++ self.__config = baseutil.get_monitor_config() ++ self.__hyst_config = copy.deepcopy(self.__config.get("hyst", {})) ++ # init check ++ errcnt = 0 ++ errmsg = "" ++ self.debug_init() ++ for temp_hyst_conf in self.__hyst_config.values(): ++ if temp_hyst_conf["flag"] == 0: ++ continue ++ for i in range(temp_hyst_conf["temp_min"], temp_hyst_conf["temp_max"] + 1): ++ if i not in temp_hyst_conf["rising"]: ++ errcnt -= 1 ++ msg = "%s hyst config error, temp value %d not in rising curve;" % (temp_hyst_conf["name"], i) ++ hyst_error(msg) ++ errmsg += msg ++ if i not in temp_hyst_conf["descending"]: ++ errcnt -= 1 ++ msg = "%s hyst config error, temp value %d not in descending curve;" % (temp_hyst_conf["name"], i) ++ hyst_error(msg) ++ errmsg += msg ++ if errcnt < 0: ++ raise KeyError(errmsg) ++ ++ def debug_init(self): ++ global debuglevel ++ if os.path.exists(HYST_DEBUG_FILE): ++ debuglevel = debuglevel | HYSTDEBUG | HYSTERROR ++ else: ++ debuglevel = debuglevel & ~(HYSTDEBUG | HYSTERROR) ++ ++ def get_temp_hyst_conf(self, temp_name): ++ temp_hyst_conf = self.__hyst_config.get(temp_name) ++ return temp_hyst_conf ++ ++ def get_temp_update(self, hyst_para, current_temp): ++ temp = hyst_para["value"] ++ if temp is None: ++ return None ++ temp.append(current_temp) ++ del temp[0] ++ return temp ++ ++ def duty_to_pwm(self, duty): ++ pwm = int(round(float(duty) * 255 / 100)) ++ return pwm ++ ++ def pwm_to_duty(self, pwm): ++ duty = int(round(float(pwm) * 100 / 255)) ++ return duty ++ ++ def calc_hyst_val(self, temp_name, temp_list): ++ ++ temp_hyst_conf = self.get_temp_hyst_conf(temp_name) ++ hyst_min = temp_hyst_conf["hyst_min"] ++ hyst_max = temp_hyst_conf["hyst_max"] ++ temp_min = temp_hyst_conf["temp_min"] ++ temp_max = temp_hyst_conf["temp_max"] ++ rising = temp_hyst_conf["rising"] ++ descending = temp_hyst_conf["descending"] ++ last_hyst_value = temp_hyst_conf["last_hyst_value"] ++ current_temp = temp_list[1] ++ last_temp = temp_list[0] ++ ++ hyst_debug("calc_hyst_val, temp_name: %s, current_temp: %s, last_temp: %s, last_hyst_value: %s" % ++ (temp_name, current_temp, last_temp, last_hyst_value)) ++ ++ if current_temp < temp_min: ++ hyst_debug("%s current_temp %s less than temp_min %s, set min hyst value: %s" % ++ (temp_name, current_temp, temp_min, hyst_min)) ++ return hyst_min ++ ++ if current_temp > temp_max: ++ hyst_debug("%s current_temp %s more than temp_max %s, set max hyst value: %s" % ++ (temp_name, current_temp, temp_max, hyst_max)) ++ return hyst_max ++ ++ if last_temp is None: # first time ++ hyst_value = rising[current_temp] ++ hyst_debug("last_temp is None, it's first hysteresis, using rising hyst value: %s" % hyst_value) ++ return hyst_value ++ ++ if current_temp == last_temp: # temp unchanging ++ hyst_debug("current_temp equal last_temp, keep last hyst value: %s" % last_hyst_value) ++ return last_hyst_value ++ ++ if current_temp > last_temp: ++ calc_hyst_value = rising[current_temp] ++ if calc_hyst_value < last_hyst_value: ++ hyst_value = last_hyst_value ++ else: ++ hyst_value = calc_hyst_value ++ hyst_debug("temp rising, last_hyst_value: %s, calc_hyst_value: %s, set hyst value: %s" % ++ (last_hyst_value, calc_hyst_value, hyst_value)) ++ return hyst_value ++ ++ calc_hyst_value = descending[current_temp] ++ if calc_hyst_value > last_hyst_value: ++ hyst_value = last_hyst_value ++ else: ++ hyst_value = calc_hyst_value ++ hyst_debug("temp descending, last_hyst_value: %s, calc_hyst_value: %s, set hyst value: %s" % ++ (last_hyst_value, calc_hyst_value, hyst_value)) ++ return hyst_value ++ ++ def cacl(self, temp_name, current_temp): ++ self.debug_init() ++ try: ++ temp_hyst_conf = self.get_temp_hyst_conf(temp_name) ++ if temp_hyst_conf is None: ++ hyst_debug("get %s hysteresis config failed" % temp_name) ++ return None ++ ++ flag = temp_hyst_conf["flag"] ++ if flag != 1: ++ hyst_debug("%s hysteresis flag == 0, skip" % temp_name) ++ return None ++ ++ temp = self.get_temp_update(temp_hyst_conf, current_temp) ++ if temp is None: ++ hyst_debug("get %s update failed" % temp_name) ++ return None ++ ++ value = self.calc_hyst_val(temp_name, temp) ++ ++ temp_hyst_conf["last_hyst_value"] = value ++ ++ speed_type = temp_hyst_conf["type"] ++ if speed_type == "duty": ++ pwm = self.duty_to_pwm(value) ++ else: ++ pwm = value ++ ++ hyst_debug("temp_name: %s, current_temp: %s, set pwm 0x%x" % (temp_name, current_temp, pwm)) ++ return pwm ++ except Exception as e: ++ hyst_error("temp_name: %s calc hysteresis pwm error, msg: %s" % (temp_name, str(e))) ++ return None +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/openloop.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/openloop.py +new file mode 100644 +index 000000000..6ff731fa7 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/openloop.py +@@ -0,0 +1,104 @@ ++#!/usr/bin/env python3 ++import os ++import syslog ++ ++from plat_hal.baseutil import baseutil ++ ++OPENLOOP_DEBUG_FILE = "/etc/.openloop_debug_flag" ++ ++OPENLOOPERROR = 1 ++OPENLOOPDEBUG = 2 ++ ++debuglevel = 0 ++ ++ ++def openloop_debug(s): ++ if OPENLOOPDEBUG & debuglevel: ++ syslog.openlog("FANCONTROL-OPENLOOP", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def openloop_error(s): ++ if OPENLOOPERROR & debuglevel: ++ syslog.openlog("FANCONTROL-OPENLOOP", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++class openloop(object): ++ __config = None ++ __openloop_config = None ++ ++ def __init__(self): ++ self.__config = baseutil.get_monitor_config() ++ self.__openloop_config = self.__config["openloop"] ++ ++ def debug_init(self): ++ global debuglevel ++ if os.path.exists(OPENLOOP_DEBUG_FILE): ++ debuglevel = debuglevel | OPENLOOPDEBUG | OPENLOOPERROR ++ else: ++ debuglevel = debuglevel & ~(OPENLOOPDEBUG | OPENLOOPERROR) ++ ++ def get_para(self, t): ++ para = self.__openloop_config.get(t) ++ return para ++ ++ def linear_cacl(self, temp): ++ self.debug_init() ++ openloop_para = self.get_para("linear") ++ if openloop_para is None: ++ openloop_debug("linear openloop: get para failed") ++ return None ++ ++ K = openloop_para["K"] ++ tin_min = openloop_para["tin_min"] ++ pwm_min = openloop_para["pwm_min"] ++ pwm_max = openloop_para["pwm_max"] ++ flag = openloop_para["flag"] ++ ++ if flag != 1: ++ openloop_debug("linear openloop: flag == 0") ++ return None ++ ++ if temp <= tin_min: ++ openloop_debug("linear openloop: temp = %d less than tin_min[%d]" % (temp, tin_min)) ++ return pwm_min ++ ++ pwm = int(pwm_min + (temp - tin_min) * K) ++ openloop_debug("linear openloop: cacl_pwm = 0x%x" % pwm) ++ ++ pwm = min(pwm, pwm_max) ++ pwm = max(pwm, pwm_min) ++ openloop_debug("linear openloop: temp = %d, pwm = 0x%x" % (temp, pwm)) ++ return pwm ++ ++ def curve_cacl(self, temp): ++ self.debug_init() ++ openloop_para = self.get_para("curve") ++ if openloop_para is None: ++ openloop_debug("curve openloop: get para failed") ++ return None ++ ++ a = openloop_para["a"] ++ b = openloop_para["b"] ++ c = openloop_para["c"] ++ tin_min = openloop_para["tin_min"] ++ pwm_min = openloop_para["pwm_min"] ++ pwm_max = openloop_para["pwm_max"] ++ flag = openloop_para["flag"] ++ ++ if flag != 1: ++ openloop_debug("curve openloop: flag == 0") ++ return None ++ ++ if temp <= tin_min: ++ openloop_debug("curve openloop: temp = %d less than tin_min[%d]" % (temp, tin_min)) ++ return pwm_min ++ ++ pwm = int(a * temp * temp + b * temp + c) ++ openloop_debug("curve openloop: cacl_pwm = 0x%x" % pwm) ++ ++ pwm = min(pwm, pwm_max) ++ pwm = max(pwm, pwm_min) ++ openloop_debug("curve openloop: temp = %d, pwm = 0x%x" % (temp, pwm)) ++ return pwm +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/pid.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/pid.py +new file mode 100644 +index 000000000..c33c1df33 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/pid.py +@@ -0,0 +1,106 @@ ++#!/usr/bin/env python3 ++import os ++import syslog ++import copy ++ ++from plat_hal.baseutil import baseutil ++ ++PID_DEBUG_FILE = "/etc/.pid_debug_flag" ++ ++PIDERROR = 1 ++PIDDEBUG = 2 ++ ++debuglevel = 0 ++ ++ ++def pid_debug(s): ++ if PIDDEBUG & debuglevel: ++ syslog.openlog("FANCONTROL-PID", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def pid_error(s): ++ if PIDERROR & debuglevel: ++ syslog.openlog("FANCONTROL-PID", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++class pid(object): ++ __config = None ++ __pid_config = None ++ ++ def __init__(self): ++ self.__config = baseutil.get_monitor_config() ++ self.__pid_config = copy.deepcopy(self.__config["pid"]) ++ ++ def debug_init(self): ++ global debuglevel ++ if os.path.exists(PID_DEBUG_FILE): ++ debuglevel = debuglevel | PIDDEBUG | PIDERROR ++ else: ++ debuglevel = debuglevel & ~(PIDDEBUG | PIDERROR) ++ ++ def get_para(self, name): ++ para = self.__pid_config.get(name) ++ return para ++ ++ def get_temp_update(self, pid_para, current_temp): ++ temp = pid_para["value"] ++ if temp is None: ++ return None ++ temp.append(current_temp) ++ del temp[0] ++ return temp ++ ++ def cacl(self, last_pwm, name, current_temp): ++ delta_pwm = 0 ++ self.debug_init() ++ pid_debug("last_pwm = %d" % last_pwm) ++ ++ pid_para = self.get_para(name) ++ if pid_para is None: ++ pid_debug("get %s pid para failed" % name) ++ return None ++ ++ temp = self.get_temp_update(pid_para, current_temp) ++ if temp is None: ++ pid_debug("get %s update failed" % name) ++ return None ++ ++ speed_type = pid_para["type"] ++ Kp = pid_para["Kp"] ++ Ki = pid_para["Ki"] ++ Kd = pid_para["Kd"] ++ target = pid_para["target"] ++ pwm_min = pid_para["pwm_min"] ++ pwm_max = pid_para["pwm_max"] ++ flag = pid_para["flag"] ++ ++ if flag != 1: ++ pid_debug("%s pid flag == 0" % name) ++ return None ++ ++ if speed_type == "duty": ++ current_pwm = round(last_pwm * 100 / 255) ++ else: ++ current_pwm = last_pwm ++ ++ if temp[2] is None: ++ tmp_pwm = current_pwm ++ elif ((temp[0] is None) or (temp[1] is None)): ++ delta_pwm = Ki * (temp[2] - target) ++ tmp_pwm = current_pwm + delta_pwm ++ else: ++ delta_pwm = Kp * (temp[2] - temp[1]) + Ki * (temp[2] - target) + Kd * (temp[2] - 2 * temp[1] + temp[0]) ++ tmp_pwm = current_pwm + delta_pwm ++ ++ pid_debug("delta_pwm = %d" % delta_pwm) ++ if speed_type == "duty": ++ pwm = round(tmp_pwm * 255 / 100) ++ else: ++ pwm = int(tmp_pwm) ++ ++ pwm = min(pwm, pwm_max) ++ pwm = max(pwm, pwm_min) ++ pid_debug("last_pwm = 0x%x, pwm = 0x%x" % (last_pwm, pwm)) ++ return pwm +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/__init__.py +new file mode 100644 +index 000000000..e69de29bb +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/cust_fru.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/cust_fru.py +new file mode 100644 +index 000000000..940c722ce +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/cust_fru.py +@@ -0,0 +1,135 @@ ++#!/usr/bin/python ++# -*- coding: utf-8 -*- ++import sys ++import os ++ ++ ++class CustFruException(Exception): ++ def __init__(self, message='custfrueerror', code=-100): ++ err = 'errcode: {0} message:{1}'.format(code, message) ++ Exception.__init__(self, err) ++ self.code = code ++ self.message = message ++ ++ ++class CustFru(): ++ MAGIC_HEAD_INFO = 0x7a ++ ++ _CUST_MAGIC_OFFSET = 0 ++ _CUST_MAGIC_LEN = 1 ++ _CUST_VERSION_OFFSET = 1 ++ _CUST_VERSION_LEN = 6 ++ _CUST_CRC_OFFSET = 7 ++ _CUST_CRC_LEN = 1 ++ _CUST_PRODUCT_NAME_OFFSET = 10 ++ _CUST_PRODUCT_NAME_LEN = 17 ++ _CUST_MANUFACTURER_OFFSET = 27 ++ _CUST_MANUFACTURER_LEN = 7 ++ _CUST_SERIAL_NUMBER_OFFSET = 34 ++ _CUST_SERIAL_NUMBER_LEN = 25 ++ _CUST_INPUT_TYPE_OFFSET = 78 ++ _CUST_INPUT_TYPE_LEN = 2 ++ _CUST_INPUT_OFFSET = 86 ++ _CUST_INPUT_LEN = 15 ++ _CUST_OUTPUT_OFFSET = 108 ++ _CUST_OUTPUT_LEN = 11 ++ _CUST_POWER_OFFSET = 200 ++ _CUST_POWER_LEN = 10 ++ _CUST_MANUFACTURER_DATE_OFFSET = 210 ++ _CUST_MANUFACTURER_DATE_LEN = 3 ++ ++ def __init__(self): ++ self.magic = "" ++ self.version = "" ++ self.crc = "" ++ self.product_name = "" ++ self.manufacturer = "" ++ self.serial_number = "" ++ self.input_type = "" ++ self.input = "" ++ self.output = "" ++ self.power = "" ++ self.manufacturer_date = "" ++ ++ def checksum(self, v): ++ result = 0 ++ for item in v: ++ result += ord(item) ++ return (result & 0xff) ++ ++ def decode(self, e2): ++ # header ++ e2_index = 0 ++ head = ord(e2[0]) ++ if head != self.MAGIC_HEAD_INFO: ++ raise CustFruException("Customization fru eeprom head info error, head:0x%x" % head, -10) ++ self.magic = "0x%02x" % self.MAGIC_HEAD_INFO ++ ++ # version ++ version = "%s" % (e2[self._CUST_VERSION_OFFSET:self._CUST_VERSION_OFFSET + self._CUST_VERSION_LEN]) ++ self.version = version.replace("\xff", "").strip() ++ ++ # crc ++ crc_calc = self.checksum(e2[0:self._CUST_CRC_OFFSET]) ++ if crc_calc != ord(e2[self._CUST_CRC_OFFSET]): ++ raise CustFruException("Customization fru eeprom crc check error, calc: 0x%x, read: 0x%x" % (crc_calc, ord(e2[self._CUST_CRC_OFFSET])), -10) ++ self.crc = crc_calc ++ ++ # Product Name ++ product_name = "%s" % (e2[self._CUST_PRODUCT_NAME_OFFSET:self._CUST_PRODUCT_NAME_OFFSET + self._CUST_PRODUCT_NAME_LEN]) ++ self.product_name = product_name.replace("\xff", "").strip() ++ ++ # manufacturer ++ manufacturer = "%s" % (e2[self._CUST_MANUFACTURER_OFFSET:self._CUST_MANUFACTURER_OFFSET + self._CUST_MANUFACTURER_LEN]) ++ self.manufacturer = manufacturer.strip() ++ ++ # serial_number ++ serial_number = "%s" % (e2[self._CUST_SERIAL_NUMBER_OFFSET:self._CUST_SERIAL_NUMBER_OFFSET + self._CUST_SERIAL_NUMBER_LEN]) ++ self.serial_number = serial_number.strip() ++ ++ # input_type ++ input_type = "%s" % (e2[self._CUST_INPUT_TYPE_OFFSET:self._CUST_INPUT_TYPE_OFFSET + self._CUST_INPUT_TYPE_LEN]) ++ self.input_type = input_type.strip() ++ ++ # input ++ input = "%s" % (e2[self._CUST_INPUT_OFFSET:self._CUST_INPUT_OFFSET + self._CUST_INPUT_LEN]) ++ self.input = input.strip() ++ ++ # output ++ output = "%s" % (e2[self._CUST_OUTPUT_OFFSET:self._CUST_OUTPUT_OFFSET + self._CUST_OUTPUT_LEN]) ++ self.output = output.strip() ++ ++ # power ++ power = "%s" % (e2[self._CUST_POWER_OFFSET:self._CUST_POWER_OFFSET + self._CUST_POWER_LEN]) ++ self.power = power.replace("\xff", "").strip() ++ ++ # manufacturer_date ++ manufacturer_year = ord(e2[self._CUST_MANUFACTURER_DATE_OFFSET]) + 2000 ++ manufacturer_month = ord(e2[self._CUST_MANUFACTURER_DATE_OFFSET + 1]) ++ manufacturer_day = ord(e2[self._CUST_MANUFACTURER_DATE_OFFSET + 2]) ++ self.manufacturer_date = "%04d-%02d-%02d" % (manufacturer_year, manufacturer_month, manufacturer_day) ++ ++ return ++ ++ ++ def __str__(self): ++ formatstr = "Version : %s \n" \ ++ "Product Name : %s \n" \ ++ "Manufacturer : %s \n" \ ++ "Serial Number : %s \n" \ ++ "AC/DC Power Module : %s \n" \ ++ "INPUT : %s \n" \ ++ "OUTPUT : %s \n" \ ++ "POWER : %s \n" \ ++ "Manufacturer Date : %s \n" ++ str_tmp = formatstr % (self.version, ++ self.product_name, ++ self.manufacturer, ++ self.serial_number, ++ self.input_type, ++ self.input, ++ self.output, ++ self.power, ++ self.manufacturer_date) ++ return str_tmp.replace("\x00","") ++ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fantlv.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fantlv.py +new file mode 100644 +index 000000000..4be78e7fd +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fantlv.py +@@ -0,0 +1,192 @@ ++#!/usr/bin/python3 ++# -*- coding: utf-8 -*- ++ ++class FantlvException(Exception): ++ def __init__(self, message='fantlverror', code=-100): ++ err = 'errcode: {0} message:{1}'.format(code, message) ++ Exception.__init__(self, err) ++ self.code = code ++ self.message = message ++ ++ ++class fan_tlv(): ++ HEAD_INFO = "\x01\x7e\x01\xf1" ++ VERSION = 0x01 ++ FLAG = 0x7E ++ HW_VER = 0X01 ++ TYPE = 0xf1 ++ TLV_LEN = 00 ++ _FAN_TLV_HDR_LEN = 6 ++ _FAN_TLV_CRC_LEN = 2 ++ ++ _FAN_TLV_TYPE_NAME = 0x02 ++ _FAN_TLV_TYPE_SN = 0x03 ++ _FAN_TLV_TYPE_HW_INFO = 0x05 ++ _FAN_TLV_TYPE_DEV_TYPE = 0x06 ++ ++ @property ++ def dstatus(self): ++ return self._dstatus ++ ++ @property ++ def typename(self): ++ return self._typename ++ ++ @property ++ def typesn(self): ++ return self._typesn ++ ++ @property ++ def typehwinfo(self): ++ return self._typehwinfo ++ ++ @property ++ def typedevtype(self): ++ return self._typedevtype ++ ++ def __init__(self): ++ self._typename = "" ++ self._typesn = "" ++ self._typehwinfo = "" ++ self._typedevtype = "" ++ self._dstatus = 0 ++ ++ def strtoarr(self, val): ++ s = [] ++ if not isinstance(val, str): ++ return s ++ for index in val: ++ s.append(index) ++ return s ++ ++ def hex_to_str(self, s): ++ len_t = len(s) ++ if len_t % 2 != 0: ++ return 0 ++ ret = "" ++ for t in range(0, len_t / 2): ++ ret += chr(int(s[2 * t:2 * t + 2], 16)) ++ return ret ++ ++ def generate_fan_value(self): ++ bin_buffer = [chr(0xff)] * 256 ++ bin_buffer[0] = chr(self.VERSION) ++ bin_buffer[1] = chr(self.FLAG) ++ bin_buffer[2] = chr(self.HW_VER) ++ bin_buffer[3] = chr(self.TYPE) ++ ++ temp_t = "%08x" % self.typedevtype ++ typedevtype_t = self.hex_to_str(temp_t) ++ total_len = len(self.typename) + len(self.typesn) + \ ++ len(self.typehwinfo) + len(typedevtype_t) + 8 ++ ++ bin_buffer[4] = chr(total_len >> 8) ++ bin_buffer[5] = chr(total_len & 0x00FF) ++ ++ index_start = 6 ++ bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_NAME) ++ bin_buffer[index_start + 1] = chr(len(self.typename)) ++ bin_buffer[index_start + 2: index_start + 2 + ++ len(self.typename)] = self.strtoarr(self.typename) ++ index_start = index_start + 2 + len(self.typename) ++ ++ bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_SN) ++ bin_buffer[index_start + 1] = chr(len(self.typesn)) ++ bin_buffer[index_start + 2:index_start + 2 + ++ len(self.typesn)] = self.strtoarr(self.typesn) ++ index_start = index_start + 2 + len(self.typesn) ++ ++ bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_HW_INFO) ++ bin_buffer[index_start + 1] = chr(len(self.typehwinfo)) ++ bin_buffer[index_start + 2:index_start + 2 + ++ len(self.typehwinfo)] = self.strtoarr(self.typehwinfo) ++ index_start = index_start + 2 + len(self.typehwinfo) ++ ++ bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_DEV_TYPE) ++ bin_buffer[index_start + 1] = chr(len(typedevtype_t)) ++ bin_buffer[index_start + 2:index_start + 2 + ++ len(typedevtype_t)] = self.strtoarr(typedevtype_t) ++ index_start = index_start + 2 + len(typedevtype_t) ++ ++ crcs = fan_tlv.fancrc(''.join(bin_buffer[0:index_start])) ++ bin_buffer[index_start] = chr(crcs >> 8) ++ bin_buffer[index_start + 1] = chr(crcs & 0x00ff) ++ return bin_buffer ++ ++ def decode(self, e2): ++ if e2[0:4] != self.HEAD_INFO: ++ raise FantlvException("Fan tlv head info error,not fan tlv type", -10) ++ ret = [] ++ self.VERSION = ord(e2[0]) ++ self.FLAG = ord(e2[1]) ++ self.HW_VER = ord(e2[2]) ++ self.TYPE = ord(e2[3]) ++ self.TLV_LEN = (ord(e2[4]) << 8) | ord(e2[5]) ++ ++ tlv_index = self._FAN_TLV_HDR_LEN ++ tlv_end = self._FAN_TLV_HDR_LEN + self.TLV_LEN ++ ++ if len(e2) < self._FAN_TLV_HDR_LEN + self.TLV_LEN + 2: ++ raise FantlvException("Fan tlv eeprom len error!", -2) ++ sumcrc = fan_tlv.fancrc(e2[0:self._FAN_TLV_HDR_LEN + self.TLV_LEN]) ++ readcrc = ord(e2[self._FAN_TLV_HDR_LEN + self.TLV_LEN] ++ ) << 8 | ord(e2[self._FAN_TLV_HDR_LEN + self.TLV_LEN + 1]) ++ if sumcrc != readcrc: ++ raise FantlvException("Fan tlv eeprom checksum error!", -1) ++ self._dstatus = 0 ++ while (tlv_index + 2) < len(e2) and tlv_index < tlv_end: ++ s = self.decoder( ++ e2[tlv_index:tlv_index + 2 + ord(e2[tlv_index + 1])]) ++ tlv_index += ord(e2[tlv_index + 1]) + 2 ++ ret.append(s) ++ ++ return ret ++ ++ @staticmethod ++ def fancrc(t): ++ crc = 0 ++ for item in t: ++ crc += ord(item) ++ return crc ++ ++ def decoder(self, t): ++ try: ++ name = "" ++ value = "" ++ _len = 0 ++ if ord(t[0]) == self._FAN_TLV_TYPE_NAME: ++ name = "Product Name" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._typename = value ++ elif ord(t[0]) == self._FAN_TLV_TYPE_SN: ++ name = "serial Number" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._typesn = value ++ elif ord(t[0]) == self._FAN_TLV_TYPE_HW_INFO: ++ name = "hardware info" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._typehwinfo = value ++ elif ord(t[0]) == self._FAN_TLV_TYPE_DEV_TYPE: ++ name = "dev type" ++ _len = ord(t[1]) ++ value = "0x" ++ for c in t[2:2 + ord(t[1])]: ++ value += "%02X" % (ord(c),) ++ self._typedevtype = int(value, 16) ++ except Exception as e: ++ print(e) ++ return {"name": name, "code": ord(t[0]), "value": value, "lens": _len} ++ ++ def __str__(self): ++ formatstr = "VERSION : 0x%02x \n" \ ++ " FLAG : 0x%02x \n" \ ++ " HW_VER : 0x%02x \n" \ ++ " TYPE : 0x%02x \n" \ ++ "typename : %s \n" \ ++ "typesn : %s \n" \ ++ "typehwinfo : %s \n" ++ return formatstr % (self.VERSION, self.FLAG, self.HW_VER, self.TYPE, ++ self.typename, self.typesn, self.typehwinfo) +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fru.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fru.py +new file mode 100644 +index 000000000..f95164e03 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fru.py +@@ -0,0 +1,961 @@ ++#!/usr/bin/python3 ++import collections ++from datetime import datetime, timedelta ++from bitarray import bitarray ++ ++ ++__DEBUG__ = "N" ++ ++ ++class FruException(Exception): ++ def __init__(self, message='fruerror', code=-100): ++ err = 'errcode: {0} message:{1}'.format(code, message) ++ Exception.__init__(self, err) ++ self.code = code ++ self.message = message ++ ++ ++def e_print(err): ++ print("ERROR: " + err) ++ ++ ++def d_print(debug_info): ++ if __DEBUG__ == "Y": ++ print(debug_info) ++ ++ ++class FruUtil(): ++ @staticmethod ++ def decodeLength(value): ++ a = bitarray(8) ++ a.setall(True) ++ a[0:1] = 0 ++ a[1:2] = 0 ++ x = ord(a.tobytes()) ++ return x & ord(value) ++ ++ @staticmethod ++ def minToData(): ++ starttime = datetime(1996, 1, 1, 0, 0, 0) ++ endtime = datetime.now() ++ seconds = (endtime - starttime).total_seconds() ++ mins = seconds // 60 ++ m = int(round(mins)) ++ return m ++ ++ @staticmethod ++ def getTimeFormat(): ++ return datetime.now().strftime('%Y-%m-%d') ++ ++ @staticmethod ++ def getTypeLength(value): ++ if value is None or len(value) == 0: ++ return 0 ++ a = bitarray(8) ++ a.setall(False) ++ a[0:1] = 1 ++ a[1:2] = 1 ++ x = ord(a.tobytes()) ++ return x | len(value) ++ ++ @staticmethod ++ def checksum(b): ++ result = 0 ++ for item in b: ++ result += ord(item) ++ return (0x100 - (result & 0xff)) & 0xff ++ ++ ++class BaseArea(object): ++ SUGGESTED_SIZE_COMMON_HEADER = 8 ++ SUGGESTED_SIZE_INTERNAL_USE_AREA = 72 ++ SUGGESTED_SIZE_CHASSIS_INFO_AREA = 32 ++ SUGGESTED_SIZE_BOARD_INFO_AREA = 80 ++ SUGGESTED_SIZE_PRODUCT_INFO_AREA = 80 ++ ++ INITVALUE = b'\x00' ++ resultvalue = INITVALUE * 256 ++ COMMON_HEAD_VERSION = b'\x01' ++ __childList = None ++ ++ def __init__(self, name="", size=0, offset=0): ++ self.__childList = [] ++ self._offset = offset ++ self.name = name ++ self._size = size ++ self._isPresent = False ++ self._data = b'\x00' * size ++ ++ @property ++ def childList(self): ++ return self.__childList ++ ++ @childList.setter ++ def childList(self, value): ++ self.__childList = value ++ ++ @property ++ def offset(self): ++ return self._offset ++ ++ @offset.setter ++ def offset(self, value): ++ self._offset = value ++ ++ @property ++ def size(self): ++ return self._size ++ ++ @size.setter ++ def size(self, value): ++ self._size = value ++ ++ @property ++ def data(self): ++ return self._data ++ ++ @data.setter ++ def data(self, value): ++ self._data = value ++ ++ @property ++ def isPresent(self): ++ return self._isPresent ++ ++ @isPresent.setter ++ def isPresent(self, value): ++ self._isPresent = value ++ ++ ++class InternalUseArea(BaseArea): ++ pass ++ ++ ++class ChassisInfoArea(BaseArea): ++ pass ++ ++ ++class BoardInfoArea(BaseArea): ++ _boardTime = None ++ _fields = None ++ _mfg_date = None ++ areaversion = None ++ _boardversion = None ++ _language = None ++ ++ def __str__(self): ++ formatstr = "version : %x\n" \ ++ "length : %d \n" \ ++ "language : %x \n" \ ++ "mfg_date : %s \n" \ ++ "boardManufacturer : %s \n" \ ++ "boardProductName : %s \n" \ ++ "boardSerialNumber : %s \n" \ ++ "boardPartNumber : %s \n" \ ++ "fruFileId : %s \n" ++ ++ tmpstr = formatstr % (ord(self.boardversion), self.size, ++ self.language, self.getMfgRealData(), ++ self.boardManufacturer, self.boardProductName, ++ self.boardSerialNumber, self.boardPartNumber, ++ self.fruFileId) ++ for i in range(1, 11): ++ valtmp = "boardextra%d" % i ++ if hasattr(self, valtmp): ++ valtmpval = getattr(self, valtmp) ++ tmpstr += "boardextra%d : %s \n" % (i, valtmpval) ++ else: ++ break ++ ++ return tmpstr ++ ++ def todict(self): ++ dic = collections.OrderedDict() ++ dic["boardversion"] = ord(self.boardversion) ++ dic["boardlength"] = self.size ++ dic["boardlanguage"] = self.language ++ dic["boardmfg_date"] = self.getMfgRealData() ++ dic["boardManufacturer"] = self.boardManufacturer ++ dic["boardProductName"] = self.boardProductName ++ dic["boardSerialNumber"] = self.boardSerialNumber ++ dic["boardPartNumber"] = self.boardPartNumber ++ dic["boardfruFileId"] = self.fruFileId ++ for i in range(1, 11): ++ valtmp = "boardextra%d" % i ++ if hasattr(self, valtmp): ++ valtmpval = getattr(self, valtmp) ++ dic[valtmp] = valtmpval ++ else: ++ break ++ return dic ++ ++ def decodedata(self): ++ index = 0 ++ self.areaversion = self.data[index] ++ index += 1 ++ d_print("decode length :%d class size:%d" % ++ ((ord(self.data[index]) * 8), self.size)) ++ index += 2 ++ ++ timetmp = self.data[index: index + 3] ++ self.mfg_date = ord(timetmp[0]) | ( ++ ord(timetmp[1]) << 8) | (ord(timetmp[2]) << 16) ++ d_print("decode getMfgRealData :%s" % self.getMfgRealData()) ++ index += 3 ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.boardManufacturer = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode boardManufacturer:%s" % self.boardManufacturer) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.boardProductName = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode boardProductName:%s" % self.boardProductName) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.boardSerialNumber = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode boardSerialNumber:%s" % self.boardSerialNumber) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.boardPartNumber = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode boardPartNumber:%s" % self.boardPartNumber) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.fruFileId = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode fruFileId:%s" % self.fruFileId) ++ ++ for i in range(1, 11): ++ valtmp = "boardextra%d" % i ++ if self.data[index] != chr(0xc1): ++ templen = FruUtil.decodeLength(self.data[index]) ++ tmpval = self.data[index + 1: index + templen + 1] ++ setattr(self, valtmp, tmpval) ++ index += templen + 1 ++ d_print("decode boardextra%d:%s" % (i, tmpval)) ++ else: ++ break ++ ++ def fruSetValue(self, field, value): ++ tmp_field = getattr(self, field, None) ++ if tmp_field is not None: ++ setattr(self, field, value) ++ ++ def recalcute(self): ++ d_print("boardInfoArea version:%x" % ord(self.boardversion)) ++ d_print("boardInfoArea length:%d" % self.size) ++ d_print("boardInfoArea language:%x" % self.language) ++ self.mfg_date = FruUtil.minToData() ++ d_print("boardInfoArea mfg_date:%x" % self.mfg_date) ++ ++ self.data = chr(ord(self.boardversion)) + \ ++ chr(self.size // 8) + chr(self.language) ++ ++ self.data += chr(self.mfg_date & 0xFF) ++ self.data += chr((self.mfg_date >> 8) & 0xFF) ++ self.data += chr((self.mfg_date >> 16) & 0xFF) ++ ++ d_print("boardInfoArea boardManufacturer:%s" % self.boardManufacturer) ++ typelength = FruUtil.getTypeLength(self.boardManufacturer) ++ self.data += chr(typelength) ++ self.data += self.boardManufacturer ++ ++ d_print("boardInfoArea boardProductName:%s" % self.boardProductName) ++ self.data += chr(FruUtil.getTypeLength(self.boardProductName)) ++ self.data += self.boardProductName ++ ++ d_print("boardInfoArea boardSerialNumber:%s" % self.boardSerialNumber) ++ self.data += chr(FruUtil.getTypeLength(self.boardSerialNumber)) ++ self.data += self.boardSerialNumber ++ ++ d_print("boardInfoArea boardPartNumber:%s" % self.boardPartNumber) ++ self.data += chr(FruUtil.getTypeLength(self.boardPartNumber)) ++ self.data += self.boardPartNumber ++ ++ d_print("boardInfoArea fruFileId:%s" % self.fruFileId) ++ self.data += chr(FruUtil.getTypeLength(self.fruFileId)) ++ self.data += self.fruFileId ++ ++ for i in range(1, 11): ++ valtmp = "boardextra%d" % i ++ if hasattr(self, valtmp): ++ valtmpval = getattr(self, valtmp) ++ d_print("boardInfoArea boardextra%d:%s" % (i, valtmpval)) ++ self.data += chr(FruUtil.getTypeLength(valtmpval)) ++ if valtmpval is not None: ++ self.data += valtmpval ++ else: ++ break ++ ++ self.data += chr(0xc1) ++ ++ if len(self.data) > (self.size - 1): ++ incr = (len(self.data) - self.size) // 8 + 1 ++ self.size += incr * 8 ++ ++ self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] ++ d_print("self data:%d" % len(self.data)) ++ d_print("self size:%d" % self.size) ++ d_print("adjust size:%d" % (self.size - len(self.data) - 1)) ++ self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) ++ ++ # checksum ++ checksum = FruUtil.checksum(self.data) ++ d_print("board info checksum:%x" % checksum) ++ self.data += chr(checksum) ++ ++ def getMfgRealData(self): ++ starttime = datetime(1996, 1, 1, 0, 0, 0) ++ mactime = starttime + timedelta(minutes=self.mfg_date) ++ return mactime ++ ++ @property ++ def language(self): ++ self._language = 25 ++ return self._language ++ ++ @property ++ def mfg_date(self): ++ return self._mfg_date ++ ++ @mfg_date.setter ++ def mfg_date(self, val): ++ self._mfg_date = val ++ ++ @property ++ def boardversion(self): ++ self._boardversion = self.COMMON_HEAD_VERSION ++ return self._boardversion ++ ++ @property ++ def fruFileId(self): ++ return self._FRUFileID ++ ++ @fruFileId.setter ++ def fruFileId(self, val): ++ self._FRUFileID = val ++ ++ @property ++ def boardPartNumber(self): ++ return self._boardPartNumber ++ ++ @boardPartNumber.setter ++ def boardPartNumber(self, val): ++ self._boardPartNumber = val ++ ++ @property ++ def boardSerialNumber(self): ++ return self._boardSerialNumber ++ ++ @boardSerialNumber.setter ++ def boardSerialNumber(self, val): ++ self._boardSerialNumber = val ++ ++ @property ++ def boardProductName(self): ++ return self._boradProductName ++ ++ @boardProductName.setter ++ def boardProductName(self, val): ++ self._boradProductName = val ++ ++ @property ++ def boardManufacturer(self): ++ return self._boardManufacturer ++ ++ @boardManufacturer.setter ++ def boardManufacturer(self, val): ++ self._boardManufacturer = val ++ ++ @property ++ def boardTime(self): ++ return self._boardTime ++ ++ @boardTime.setter ++ def boardTime(self, val): ++ self._boardTime = val ++ ++ @property ++ def fields(self): ++ return self._fields ++ ++ @fields.setter ++ def fields(self, val): ++ self._fields = val ++ ++ ++class ProductInfoArea(BaseArea): ++ _productManufacturer = None ++ _productAssetTag = None ++ _FRUFileID = None ++ _language = None ++ ++ def __str__(self): ++ formatstr = "version : %x\n" \ ++ "length : %d \n" \ ++ "language : %x \n" \ ++ "productManufacturer : %s \n" \ ++ "productName : %s \n" \ ++ "productPartModelName: %s \n" \ ++ "productVersion : %s \n" \ ++ "productSerialNumber : %s \n" \ ++ "productAssetTag : %s \n" \ ++ "fruFileId : %s \n" ++ ++ tmpstr = formatstr % (ord(self.areaversion), self.size, ++ self.language, self.productManufacturer, ++ self.productName, self.productPartModelName, ++ self.productVersion, self.productSerialNumber, ++ self.productAssetTag, self.fruFileId) ++ ++ for i in range(1, 11): ++ valtmp = "productextra%d" % i ++ if hasattr(self, valtmp): ++ valtmpval = getattr(self, valtmp) ++ tmpstr += "productextra%d : %s \n" % (i, valtmpval) ++ else: ++ break ++ ++ return tmpstr ++ ++ def todict(self): ++ dic = collections.OrderedDict() ++ dic["productversion"] = ord(self.areaversion) ++ dic["productlength"] = self.size ++ dic["productlanguage"] = self.language ++ dic["productManufacturer"] = self.productManufacturer ++ dic["productName"] = self.productName ++ dic["productPartModelName"] = self.productPartModelName ++ dic["productVersion"] = int(self.productVersion, 16) ++ dic["productSerialNumber"] = self.productSerialNumber ++ dic["productAssetTag"] = self.productAssetTag ++ dic["productfruFileId"] = self.fruFileId ++ for i in range(1, 11): ++ valtmp = "productextra%d" % i ++ if hasattr(self, valtmp): ++ valtmpval = getattr(self, valtmp) ++ dic[valtmp] = valtmpval ++ else: ++ break ++ return dic ++ ++ def decodedata(self): ++ index = 0 ++ self.areaversion = self.data[index] # 0 ++ index += 1 ++ d_print("decode length %d" % (ord(self.data[index]) * 8)) ++ d_print("class size %d" % self.size) ++ index += 2 ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.productManufacturer = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode productManufacturer:%s" % self.productManufacturer) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.productName = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode productName:%s" % self.productName) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.productPartModelName = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode productPartModelName:%s" % self.productPartModelName) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.productVersion = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode productVersion:%s" % self.productVersion) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.productSerialNumber = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode productSerialNumber:%s" % self.productSerialNumber) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.productAssetTag = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode productAssetTag:%s" % self.productAssetTag) ++ ++ templen = FruUtil.decodeLength(self.data[index]) ++ self.fruFileId = self.data[index + 1: index + templen + 1] ++ index += templen + 1 ++ d_print("decode fruFileId:%s" % self.fruFileId) ++ ++ for i in range(1, 11): ++ valtmp = "productextra%d" % i ++ if self.data[index] != chr(0xc1) and index < self.size - 1: ++ templen = FruUtil.decodeLength(self.data[index]) ++ if templen == 0: ++ break ++ tmpval = self.data[index + 1: index + templen + 1] ++ d_print("decode boardextra%d:%s" % (i, tmpval)) ++ setattr(self, valtmp, tmpval) ++ index += templen + 1 ++ else: ++ break ++ ++ @property ++ def productVersion(self): ++ return self._productVersion ++ ++ @productVersion.setter ++ def productVersion(self, name): ++ self._productVersion = name ++ ++ @property ++ def areaversion(self): ++ self._areaversion = self.COMMON_HEAD_VERSION ++ return self._areaversion ++ ++ @areaversion.setter ++ def areaversion(self, name): ++ self._areaversion = name ++ ++ @property ++ def language(self): ++ self._language = 25 ++ return self._language ++ ++ @property ++ def productManufacturer(self): ++ return self._productManufacturer ++ ++ @productManufacturer.setter ++ def productManufacturer(self, name): ++ self._productManufacturer = name ++ ++ @property ++ def productName(self): ++ return self._productName ++ ++ @productName.setter ++ def productName(self, name): ++ self._productName = name ++ ++ @property ++ def productPartModelName(self): ++ return self._productPartModelName ++ ++ @productPartModelName.setter ++ def productPartModelName(self, name): ++ self._productPartModelName = name ++ ++ @property ++ def productSerialNumber(self): ++ return self._productSerialNumber ++ ++ @productSerialNumber.setter ++ def productSerialNumber(self, name): ++ self._productSerialNumber = name ++ ++ @property ++ def productAssetTag(self): ++ return self._productAssetTag ++ ++ @productAssetTag.setter ++ def productAssetTag(self, name): ++ self._productAssetTag = name ++ ++ @property ++ def fruFileId(self): ++ return self._FRUFileID ++ ++ @fruFileId.setter ++ def fruFileId(self, name): ++ self._FRUFileID = name ++ ++ def fruSetValue(self, field, value): ++ tmp_field = getattr(self, field, None) ++ if tmp_field is not None: ++ setattr(self, field, value) ++ ++ def recalcute(self): ++ d_print("product version:%x" % ord(self.areaversion)) ++ d_print("product length:%d" % self.size) ++ d_print("product language:%x" % self.language) ++ self.data = chr(ord(self.areaversion)) + \ ++ chr(self.size // 8) + chr(self.language) ++ ++ typelength = FruUtil.getTypeLength(self.productManufacturer) ++ self.data += chr(typelength) ++ self.data += self.productManufacturer ++ ++ self.data += chr(FruUtil.getTypeLength(self.productName)) ++ self.data += self.productName ++ ++ self.data += chr(FruUtil.getTypeLength(self.productPartModelName)) ++ self.data += self.productPartModelName ++ ++ self.data += chr(FruUtil.getTypeLength(self.productVersion)) ++ self.data += self.productVersion ++ ++ self.data += chr(FruUtil.getTypeLength(self.productSerialNumber)) ++ self.data += self.productSerialNumber ++ ++ self.data += chr(FruUtil.getTypeLength(self.productAssetTag)) ++ if self.productAssetTag is not None: ++ self.data += self.productAssetTag ++ ++ self.data += chr(FruUtil.getTypeLength(self.fruFileId)) ++ self.data += self.fruFileId ++ ++ for i in range(1, 11): ++ valtmp = "productextra%d" % i ++ if hasattr(self, valtmp): ++ valtmpval = getattr(self, valtmp) ++ d_print("boardInfoArea productextra%d:%s" % (i, valtmpval)) ++ self.data += chr(FruUtil.getTypeLength(valtmpval)) ++ if valtmpval is not None: ++ self.data += valtmpval ++ else: ++ break ++ ++ self.data += chr(0xc1) ++ if len(self.data) > (self.size - 1): ++ incr = (len(self.data) - self.size) // 8 + 1 ++ self.size += incr * 8 ++ d_print("self.data:%d" % len(self.data)) ++ d_print("self.size:%d" % self.size) ++ ++ self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] ++ self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) ++ checksum = FruUtil.checksum(self.data) ++ d_print("board info checksum:%x" % checksum) ++ self.data += chr(checksum) ++ ++ ++class MultiRecordArea(BaseArea): ++ pass ++ ++ ++class Field(object): ++ ++ def __init__(self, fieldType="ASCII", fieldData=""): ++ self.fieldData = fieldData ++ self.fieldType = fieldType ++ ++ @property ++ def fieldType(self): ++ return self.fieldType ++ ++ @property ++ def fieldData(self): ++ return self.fieldData ++ ++ ++class ipmifru(BaseArea): ++ _BoardInfoArea = None ++ _ProductInfoArea = None ++ _InternalUseArea = None ++ _ChassisInfoArea = None ++ _multiRecordArea = None ++ _productinfoAreaOffset = BaseArea.INITVALUE ++ _boardInfoAreaOffset = BaseArea.INITVALUE ++ _internalUserAreaOffset = BaseArea.INITVALUE ++ _chassicInfoAreaOffset = BaseArea.INITVALUE ++ _multiRecordAreaOffset = BaseArea.INITVALUE ++ _bindata = None ++ _bodybin = None ++ _version = BaseArea.COMMON_HEAD_VERSION ++ _zeroCheckSum = None ++ _frusize = 256 ++ ++ def __str__(self): ++ tmpstr = "" ++ if self.boardInfoArea.isPresent: ++ tmpstr += "\nboardinfoarea: \n" ++ tmpstr += self.boardInfoArea.__str__() ++ if self.productInfoArea.isPresent: ++ tmpstr += "\nproductinfoarea: \n" ++ tmpstr += self.productInfoArea.__str__() ++ return tmpstr ++ ++ def decodeBin(self, eeprom): ++ commonHead = eeprom[0:8] ++ d_print("decode version %x" % ord(commonHead[0])) ++ if ord(self.COMMON_HEAD_VERSION) != ord(commonHead[0]): ++ raise FruException("HEAD VERSION error,not Fru format!", -10) ++ if FruUtil.checksum(commonHead[0:7]) != ord(commonHead[7]): ++ strtemp = "check header checksum error [cal:%02x data:%02x]" % ( ++ FruUtil.checksum(commonHead[0:7]), ord(commonHead[7])) ++ raise FruException(strtemp, -3) ++ if ord(commonHead[1]) != ord(self.INITVALUE): ++ d_print("Internal Use Area is present") ++ self.internalUseArea = InternalUseArea( ++ name="Internal Use Area", size=self.SUGGESTED_SIZE_INTERNAL_USE_AREA) ++ self.internalUseArea.isPresent = True ++ self.internalUserAreaOffset = ord(commonHead[1]) ++ self.internalUseArea.data = eeprom[self.internalUserAreaOffset * 8: ( ++ self.internalUserAreaOffset * 8 + self.internalUseArea.size)] ++ if ord(commonHead[2]) != ord(self.INITVALUE): ++ d_print("Chassis Info Area is present") ++ self.chassisInfoArea = ChassisInfoArea( ++ name="Chassis Info Area", size=self.SUGGESTED_SIZE_CHASSIS_INFO_AREA) ++ self.chassisInfoArea.isPresent = True ++ self.chassicInfoAreaOffset = ord(commonHead[2]) ++ self.chassisInfoArea.data = eeprom[self.chassicInfoAreaOffset * 8: ( ++ self.chassicInfoAreaOffset * 8 + self.chassisInfoArea.size)] ++ if ord(commonHead[3]) != ord(self.INITVALUE): ++ self.boardInfoArea = BoardInfoArea( ++ name="Board Info Area", size=self.SUGGESTED_SIZE_BOARD_INFO_AREA) ++ self.boardInfoArea.isPresent = True ++ self.boardInfoAreaOffset = ord(commonHead[3]) ++ self.boardInfoArea.size = ord( ++ eeprom[self.boardInfoAreaOffset * 8 + 1]) * 8 ++ d_print("Board Info Area is present size:%d" % ++ (self.boardInfoArea.size)) ++ self.boardInfoArea.data = eeprom[self.boardInfoAreaOffset * 8: ( ++ self.boardInfoAreaOffset * 8 + self.boardInfoArea.size)] ++ if FruUtil.checksum(self.boardInfoArea.data[:-1]) != ord(self.boardInfoArea.data[-1:]): ++ strtmp = "check boardInfoArea checksum error[cal:%02x data:%02x]" % \ ++ (FruUtil.checksum( ++ self.boardInfoArea.data[:-1]), ord(self.boardInfoArea.data[-1:])) ++ raise FruException(strtmp, -3) ++ self.boardInfoArea.decodedata() ++ if ord(commonHead[4]) != ord(self.INITVALUE): ++ d_print("Product Info Area is present") ++ self.productInfoArea = ProductInfoArea( ++ name="Product Info Area ", size=self.SUGGESTED_SIZE_PRODUCT_INFO_AREA) ++ self.productInfoArea.isPresent = True ++ self.productinfoAreaOffset = ord(commonHead[4]) ++ d_print("length offset value: %02x" % ++ ord(eeprom[self.productinfoAreaOffset * 8 + 1])) ++ self.productInfoArea.size = ord( ++ eeprom[self.productinfoAreaOffset * 8 + 1]) * 8 ++ d_print("Product Info Area is present size:%d" % ++ (self.productInfoArea.size)) ++ ++ self.productInfoArea.data = eeprom[self.productinfoAreaOffset * 8: ( ++ self.productinfoAreaOffset * 8 + self.productInfoArea.size)] ++ if FruUtil.checksum(self.productInfoArea.data[:-1]) != ord(self.productInfoArea.data[-1:]): ++ strtmp = "check productInfoArea checksum error [cal:%02x data:%02x]" % ( ++ FruUtil.checksum(self.productInfoArea.data[:-1]), ord(self.productInfoArea.data[-1:])) ++ raise FruException(strtmp, -3) ++ self.productInfoArea.decodedata() ++ if ord(commonHead[5]) != ord(self.INITVALUE): ++ self.multiRecordArea = MultiRecordArea( ++ name="MultiRecord record Area ") ++ d_print("MultiRecord record present") ++ self.multiRecordArea.isPresent = True ++ self.multiRecordAreaOffset = ord(commonHead[5]) ++ self.multiRecordArea.data = eeprom[self.multiRecordAreaOffset * 8: ( ++ self.multiRecordAreaOffset * 8 + self.multiRecordArea.size)] ++ ++ def initDefault(self): ++ self.version = self.COMMON_HEAD_VERSION ++ self.internalUserAreaOffset = self.INITVALUE ++ self.chassicInfoAreaOffset = self.INITVALUE ++ self.boardInfoAreaOffset = self.INITVALUE ++ self.productinfoAreaOffset = self.INITVALUE ++ self.multiRecordAreaOffset = self.INITVALUE ++ self.zeroCheckSum = self.INITVALUE ++ self.offset = self.SUGGESTED_SIZE_COMMON_HEADER ++ self.productInfoArea = None ++ self.internalUseArea = None ++ self.boardInfoArea = None ++ self.chassisInfoArea = None ++ self.multiRecordArea = None ++ # self.recalcute() ++ ++ @property ++ def version(self): ++ return self._version ++ ++ @version.setter ++ def version(self, name): ++ self._version = name ++ ++ @property ++ def internalUserAreaOffset(self): ++ return self._internalUserAreaOffset ++ ++ @internalUserAreaOffset.setter ++ def internalUserAreaOffset(self, obj): ++ self._internalUserAreaOffset = obj ++ ++ @property ++ def chassicInfoAreaOffset(self): ++ return self._chassicInfoAreaOffset ++ ++ @chassicInfoAreaOffset.setter ++ def chassicInfoAreaOffset(self, obj): ++ self._chassicInfoAreaOffset = obj ++ ++ @property ++ def productinfoAreaOffset(self): ++ return self._productinfoAreaOffset ++ ++ @productinfoAreaOffset.setter ++ def productinfoAreaOffset(self, obj): ++ self._productinfoAreaOffset = obj ++ ++ @property ++ def boardInfoAreaOffset(self): ++ return self._boardInfoAreaOffset ++ ++ @boardInfoAreaOffset.setter ++ def boardInfoAreaOffset(self, obj): ++ self._boardInfoAreaOffset = obj ++ ++ @property ++ def multiRecordAreaOffset(self): ++ return self._multiRecordAreaOffset ++ ++ @multiRecordAreaOffset.setter ++ def multiRecordAreaOffset(self, obj): ++ self._multiRecordAreaOffset = obj ++ ++ @property ++ def zeroCheckSum(self): ++ return self._zeroCheckSum ++ ++ @zeroCheckSum.setter ++ def zeroCheckSum(self, obj): ++ self._zeroCheckSum = obj ++ ++ @property ++ def productInfoArea(self): ++ return self._ProductInfoArea ++ ++ @productInfoArea.setter ++ def productInfoArea(self, obj): ++ self._ProductInfoArea = obj ++ ++ @property ++ def internalUseArea(self): ++ return self._InternalUseArea ++ ++ @internalUseArea.setter ++ def internalUseArea(self, obj): ++ self.internalUseArea = obj ++ ++ @property ++ def boardInfoArea(self): ++ return self._BoardInfoArea ++ ++ @boardInfoArea.setter ++ def boardInfoArea(self, obj): ++ self._BoardInfoArea = obj ++ ++ @property ++ def chassisInfoArea(self): ++ return self._ChassisInfoArea ++ ++ @chassisInfoArea.setter ++ def chassisInfoArea(self, obj): ++ self._ChassisInfoArea = obj ++ ++ @property ++ def multiRecordArea(self): ++ return self._multiRecordArea ++ ++ @multiRecordArea.setter ++ def multiRecordArea(self, obj): ++ self._multiRecordArea = obj ++ ++ @property ++ def bindata(self): ++ return self._bindata ++ ++ @bindata.setter ++ def bindata(self, obj): ++ self._bindata = obj ++ ++ @property ++ def bodybin(self): ++ return self._bodybin ++ ++ @bodybin.setter ++ def bodybin(self, obj): ++ self._bodybin = obj ++ ++ def recalcuteCommonHead(self): ++ self.bindata = "" ++ self.offset = self.SUGGESTED_SIZE_COMMON_HEADER ++ d_print("common Header %d" % self.offset) ++ d_print("fru eeprom size %d" % self._frusize) ++ if self.internalUseArea is not None and self.internalUseArea.isPresent: ++ self.internalUserAreaOffset = self.offset // 8 ++ self.offset += self.internalUseArea.size ++ d_print("internalUseArea is present offset:%d" % self.offset) ++ ++ if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: ++ self.chassicInfoAreaOffset = self.offset // 8 ++ self.offset += self.chassisInfoArea.size ++ d_print("chassisInfoArea is present offset:%d" % self.offset) ++ ++ if self.boardInfoArea is not None and self.boardInfoArea.isPresent: ++ self.boardInfoAreaOffset = self.offset // 8 ++ self.offset += self.boardInfoArea.size ++ d_print("boardInfoArea is present offset:%d" % self.offset) ++ d_print("boardInfoArea is present size:%d" % ++ self.boardInfoArea.size) ++ ++ if self.productInfoArea is not None and self.productInfoArea.isPresent: ++ self.productinfoAreaOffset = self.offset // 8 ++ self.offset += self.productInfoArea.size ++ d_print("productInfoArea is present offset:%d" % self.offset) ++ ++ if self.multiRecordArea is not None and self.multiRecordArea.isPresent: ++ self.multiRecordAreaOffset = self.offset // 8 ++ d_print("multiRecordArea is present offset:%d" % self.offset) ++ ++ if self.internalUserAreaOffset == self.INITVALUE: ++ self.internalUserAreaOffset = 0 ++ if self.productinfoAreaOffset == self.INITVALUE: ++ self.productinfoAreaOffset = 0 ++ if self.chassicInfoAreaOffset == self.INITVALUE: ++ self.chassicInfoAreaOffset = 0 ++ if self.boardInfoAreaOffset == self.INITVALUE: ++ self.boardInfoAreaOffset = 0 ++ if self.multiRecordAreaOffset == self.INITVALUE: ++ self.multiRecordAreaOffset = 0 ++ ++ self.zeroCheckSum = (0x100 - ord(self.version) - self.internalUserAreaOffset - self.chassicInfoAreaOffset - self.productinfoAreaOffset ++ - self.boardInfoAreaOffset - self.multiRecordAreaOffset) & 0xff ++ d_print("zerochecksum:%x" % self.zeroCheckSum) ++ self.data = "" ++ self.data += chr(self.version[0]) + chr(self.internalUserAreaOffset) + chr(self.chassicInfoAreaOffset) + chr( ++ self.boardInfoAreaOffset) + chr(self.productinfoAreaOffset) + chr(self.multiRecordAreaOffset) + chr(self.INITVALUE[0]) + chr(self.zeroCheckSum) ++ ++ self.bindata = self.data + self.bodybin ++ totallen = len(self.bindata) ++ d_print("totallen %d" % totallen) ++ if totallen < self._frusize: ++ self.bindata = self.bindata.ljust(self._frusize, chr(self.INITVALUE[0])) ++ else: ++ raise FruException('bin data more than %d' % self._frusize, -2) ++ ++ def recalcutebin(self): ++ self.bodybin = "" ++ if self.internalUseArea is not None and self.internalUseArea.isPresent: ++ d_print("internalUseArea present") ++ self.bodybin += self.internalUseArea.data ++ if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: ++ d_print("chassisInfoArea present") ++ self.bodybin += self.chassisInfoArea.data ++ if self.boardInfoArea is not None and self.boardInfoArea.isPresent: ++ d_print("boardInfoArea present") ++ self.boardInfoArea.recalcute() ++ self.bodybin += self.boardInfoArea.data ++ if self.productInfoArea is not None and self.productInfoArea.isPresent: ++ d_print("productInfoAreapresent") ++ self.productInfoArea.recalcute() ++ self.bodybin += self.productInfoArea.data ++ if self.multiRecordArea is not None and self.multiRecordArea.isPresent: ++ d_print("multiRecordArea present") ++ self.bodybin += self.productInfoArea.data ++ ++ def recalcute(self, fru_eeprom_size=256): ++ self._frusize = fru_eeprom_size ++ self.recalcutebin() ++ self.recalcuteCommonHead() ++ ++ def setValue(self, area, field, value): ++ tmp_area = getattr(self, area, None) ++ if tmp_area is not None: ++ tmp_area.fruSetValue(field, value) +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/onietlv.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/onietlv.py +new file mode 100644 +index 000000000..a90f8f845 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/onietlv.py +@@ -0,0 +1,441 @@ ++#!/usr/bin/python3 ++import binascii ++ ++ ++class OnietlvException(Exception): ++ def __init__(self, message='onietlverror', code=-100): ++ err = 'errcode: {0} message:{1}'.format(code, message) ++ Exception.__init__(self, err) ++ self.code = code ++ self.message = message ++ ++ ++class onie_tlv(object): ++ TLV_INFO_ID_STRING = "TlvInfo\x00" ++ TLV_INFO_INIA_ID = "\x00\x00\x13\x11" ++ TLV_INFO_VERSION = 0x01 ++ TLV_INFO_LENGTH = 0x00 ++ TLV_INFO_LENGTH_VALUE = 0xba ++ ++ TLV_CODE_PRODUCT_NAME = 0x21 ++ TLV_CODE_PART_NUMBER = 0x22 ++ TLV_CODE_SERIAL_NUMBER = 0x23 ++ TLV_CODE_MAC_BASE = 0x24 ++ TLV_CODE_MANUF_DATE = 0x25 ++ TLV_CODE_DEVICE_VERSION = 0x26 ++ TLV_CODE_LABEL_REVISION = 0x27 ++ TLV_CODE_PLATFORM_NAME = 0x28 ++ TLV_CODE_ONIE_VERSION = 0x29 ++ TLV_CODE_MAC_SIZE = 0x2A ++ TLV_CODE_MANUF_NAME = 0x2B ++ TLV_CODE_MANUF_COUNTRY = 0x2C ++ TLV_CODE_VENDOR_NAME = 0x2D ++ TLV_CODE_DIAG_VERSION = 0x2E ++ TLV_CODE_SERVICE_TAG = 0x2F ++ TLV_CODE_VENDOR_EXT = 0xFD ++ TLV_CODE_CRC_32 = 0xFE ++ _TLV_DISPLAY_VENDOR_EXT = 1 ++ TLV_CODE_WB_CARID = 0x01 ++ _TLV_INFO_HDR_LEN = 11 ++ TLV_CODE_PRODUCT_ID = 0x40 ++ TLV_CODE_HW_VERSION = 0x41 ++ TLV_CODE_MAIN_FILENAME = 0x42 ++ TLV_CODE_DTS_FINENAME = 0x43 ++ TLV_CODE_SY_SERIAL0 = 0x44 ++ TLV_CODE_SY_SERIAL1 = 0x45 ++ TLV_CODE_SY_SERIAL2 = 0x46 ++ TLV_CODE_SY_SERIAL3 = 0x47 ++ TLV_CODE_PROJECT_ID = 0x48 ++ TLV_CODE_SETMAC_VERSION = 0x49 ++ TLV_CODE_EEPROM_TYPE = 0x4A ++ ++ @property ++ def dstatus(self): ++ return self._dstatus ++ ++ @property ++ def cardid(self): ++ return self._cardid ++ ++ @property ++ def productname(self): ++ return self._productname ++ ++ @property ++ def partnum(self): ++ return self._partnum ++ ++ @property ++ def serialnum(self): ++ return self._serialnum ++ ++ @property ++ def macbase(self): ++ return self._macbase ++ ++ @property ++ def manufdate(self): ++ return self._manufdate ++ ++ @property ++ def deviceversion(self): ++ return self._deviceversion ++ ++ @property ++ def labelrevision(self): ++ return self._labelrevision ++ ++ @property ++ def platformname(self): ++ return self._platformname ++ ++ @property ++ def onieversion(self): ++ return self._onieversion ++ ++ @property ++ def macsize(self): ++ return self._macsize ++ ++ @property ++ def manufname(self): ++ return self._manufname ++ ++ @property ++ def manufcountry(self): ++ return self._manufcountry ++ ++ @property ++ def vendorname(self): ++ return self._vendorname ++ ++ @property ++ def diagname(self): ++ return self._diagname ++ ++ @property ++ def servicetag(self): ++ return self._servicetag ++ ++ @property ++ def vendorext(self): ++ return self._vendorext ++ ++ def __init__(self): ++ self._cardid = "" ++ self._productname = "" ++ self._partnum = "" ++ self._serialnum = "" ++ self._macbase = "" ++ self._manufdate = "" ++ self._deviceversion = "" ++ self._labelrevision = "" ++ self._platformname = "" ++ self._onieversion = "" ++ self._macsize = "" ++ self._manufname = "" ++ self._manufcountry = "" ++ self._vendorname = "" ++ self._diagname = "" ++ self._servicetag = "" ++ self._vendorext = "" ++ self._productid = "" ++ self._hwversion = "" ++ self._mainfilename = "" ++ self._dtsfilename = "" ++ self._syserial0 = "" ++ self._syserial1 = "" ++ self._syserial2 = "" ++ self._syserial3 = "" ++ self._projectid = "" ++ self._setmacversion = "" ++ self._eepromtype = "" ++ self._crc32 = "" ++ self._dstatus = 0 ++ ++ def oniecrc32(self, v): ++ data_array = bytearray() ++ for x in v: ++ data_array.append(ord(x)) ++ return '0x%08x' % (binascii.crc32(bytes(data_array)) & 0xffffffff) ++ ++ def getTLV_BODY(self, tlv_type, value): ++ x = [] ++ temp_t = "" ++ if tlv_type == self.TLV_CODE_MAC_BASE: ++ arr = value.split(':') ++ for tt in arr: ++ temp_t += chr(int(tt, 16)) ++ elif tlv_type == self.TLV_CODE_DEVICE_VERSION: ++ temp_t = chr(value) ++ elif tlv_type == self.TLV_CODE_MAC_SIZE: ++ temp_t = chr(value >> 8) + chr(value & 0x00ff) ++ else: ++ temp_t = value ++ x.append(chr(tlv_type)) ++ x.append(chr(len(temp_t))) ++ for i in temp_t: ++ x.append(i) ++ return x ++ ++ def generate_ext(self, cardid): ++ s = "%08x" % cardid ++ ret = "" ++ for t in range(0, 4): ++ ret += chr(int(s[2 * t:2 * t + 2], 16)) ++ ret = chr(0x01) + chr(len(ret)) + ret ++ return ret ++ ++ def generate_value(self, _t): ++ ret = [] ++ for i in self.TLV_INFO_ID_STRING: ++ ret.append(i) ++ ret.append(chr(self.TLV_INFO_VERSION)) ++ ret.append(chr(self.TLV_INFO_LENGTH)) ++ ret.append(chr(self.TLV_INFO_LENGTH_VALUE)) ++ ++ total_len = 0 ++ for key in _t: ++ x = self.getTLV_BODY(key, _t[key]) ++ ret += x ++ total_len += len(x) ++ ret[10] = chr(total_len + 6) ++ ++ ret.append(chr(0xFE)) ++ ret.append(chr(0x04)) ++ s = self.oniecrc32(''.join(ret)) ++ for t in range(0, 4): ++ ret.append(chr(int(s[2 * t + 2:2 * t + 4], 16))) ++ totallen = len(ret) ++ if totallen < 256: ++ for left_t in range(0, 256 - totallen): ++ ret.append(chr(0x00)) ++ return (ret, True) ++ ++ def decode_tlv(self, e): ++ tlv_index = 0 ++ tlv_end = len(e) ++ ret = [] ++ while tlv_index < tlv_end and (tlv_index + 2 + ord(e[tlv_index + 1])) <= len(e): ++ rt = self.decoder(e[tlv_index:tlv_index + 2 + ord(e[tlv_index + 1])]) ++ ret.append(rt) ++ if ord(e[tlv_index]) == self.TLV_CODE_CRC_32: ++ break ++ tlv_index += ord(e[tlv_index + 1]) + 2 ++ return ret ++ ++ def decode(self, e): ++ if e[0:8] != self.TLV_INFO_ID_STRING: ++ raise OnietlvException("ONIE tlv head info error,not onie tlv type", -1) ++ total_len = (ord(e[9]) << 8) | ord(e[10]) ++ tlv_index = self._TLV_INFO_HDR_LEN ++ tlv_end = self._TLV_INFO_HDR_LEN + total_len ++ if tlv_end > len(e): ++ raise OnietlvException("ONIE tlv length error", -2) ++ ret = [] ++ ret = self.decode_tlv(e[tlv_index:tlv_end]) ++ for item in ret: ++ if item['code'] == self.TLV_CODE_VENDOR_EXT: ++ if item["value"][0:4] == self.TLV_INFO_INIA_ID: ++ rt = self.decode_tlv(item["value"][4:]) ++ else: ++ rt = self.decode_tlv(item["value"][0:]) ++ ret.extend(rt) ++ return ret ++ ++ def decoder(self, t): ++ if ord(t[0]) == self.TLV_CODE_PRODUCT_NAME: ++ name = "Product Name" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._productname = value ++ elif ord(t[0]) == self.TLV_CODE_PART_NUMBER: ++ name = "Part Number" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._partnum = value ++ elif ord(t[0]) == self.TLV_CODE_SERIAL_NUMBER: ++ name = "Serial Number" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._serialnum = value ++ elif ord(t[0]) == self.TLV_CODE_MAC_BASE: ++ name = "Base MAC Address" ++ _len = ord(t[1]) ++ value = ":".join(['%02X' % ord(T) for T in t[2:8]]).upper() ++ self._macbase = value ++ elif ord(t[0]) == self.TLV_CODE_MANUF_DATE: ++ name = "Manufacture Date" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._manufdate = value ++ elif ord(t[0]) == self.TLV_CODE_DEVICE_VERSION: ++ name = "Device Version" ++ _len = ord(t[1]) ++ value = ord(t[2]) ++ self._deviceversion = value ++ elif ord(t[0]) == self.TLV_CODE_LABEL_REVISION: ++ name = "Label Revision" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._labelrevision = value ++ elif ord(t[0]) == self.TLV_CODE_PLATFORM_NAME: ++ name = "Platform Name" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._platformname = value ++ elif ord(t[0]) == self.TLV_CODE_ONIE_VERSION: ++ name = "ONIE Version" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._onieversion = value ++ elif ord(t[0]) == self.TLV_CODE_MAC_SIZE: ++ name = "MAC Addresses" ++ _len = ord(t[1]) ++ value = str((ord(t[2]) << 8) | ord(t[3])) ++ self._macsize = value ++ elif ord(t[0]) == self.TLV_CODE_MANUF_NAME: ++ name = "Manufacturer" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._manufname = value ++ elif ord(t[0]) == self.TLV_CODE_MANUF_COUNTRY: ++ name = "Manufacture Country" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._manufcountry = value ++ elif ord(t[0]) == self.TLV_CODE_VENDOR_NAME: ++ name = "Vendor Name" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._vendorname = value ++ elif ord(t[0]) == self.TLV_CODE_DIAG_VERSION: ++ name = "Diag Version" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._diagname = value ++ elif ord(t[0]) == self.TLV_CODE_SERVICE_TAG: ++ name = "Service Tag" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._servicetag = value ++ elif ord(t[0]) == self.TLV_CODE_VENDOR_EXT: ++ name = "Vendor Extension" ++ _len = ord(t[1]) ++ value = "" ++ if self._TLV_DISPLAY_VENDOR_EXT: ++ value = t[2:2 + ord(t[1])] ++ self._vendorext = value ++ elif ord(t[0]) == self.TLV_CODE_CRC_32 and len(t) == 6: ++ name = "CRC-32" ++ _len = ord(t[1]) ++ value = "0x%08X" % (((ord(t[2]) << 24) | ( ++ ord(t[3]) << 16) | (ord(t[4]) << 8) | ord(t[5])),) ++ self._crc32 = value ++ elif ord(t[0]) == self.TLV_CODE_WB_CARID: ++ name = "Card id" ++ _len = ord(t[1]) ++ value = "" ++ for c in t[2:2 + ord(t[1])]: ++ value += "%02X" % (ord(c),) ++ self._cardid = value ++ elif ord(t[0]) == self.TLV_CODE_PRODUCT_ID: ++ name = "Product id" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._productid = value ++ elif ord(t[0]) == self.TLV_CODE_HW_VERSION: ++ name = "Hardware Version" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._hwversion = value ++ elif ord(t[0]) == self.TLV_CODE_MAIN_FILENAME: ++ name = "Main File Name" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._mainfilename = value ++ elif ord(t[0]) == self.TLV_CODE_DTS_FINENAME: ++ name = "DTS File Name" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._dtsfilename = value ++ elif ord(t[0]) == self.TLV_CODE_SY_SERIAL0: ++ name = "SY Serial 0" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._syserial0 = value ++ elif ord(t[0]) == self.TLV_CODE_SY_SERIAL1: ++ name = "SY Serial 1" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._syserial1 = value ++ elif ord(t[0]) == self.TLV_CODE_SY_SERIAL2: ++ name = "SY Serial 2" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._syserial2 = value ++ elif ord(t[0]) == self.TLV_CODE_SY_SERIAL3: ++ name = "SY Serial 3" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._syserial3 = value ++ elif ord(t[0]) == self.TLV_CODE_PROJECT_ID: ++ name = "Project id" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._projectid = value ++ elif ord(t[0]) == self.TLV_CODE_SETMAC_VERSION: ++ name = "Setmac Version" ++ _len = ord(t[1]) ++ value = t[2:2 + ord(t[1])] ++ self._setmacversion = value ++ elif ord(t[0]) == self.TLV_CODE_EEPROM_TYPE: ++ name = "EEPROM Type" ++ _len = ord(t[1]) ++ value = "" ++ for c in t[2:2 + ord(t[1])]: ++ value += "%02X" % (ord(c),) ++ self._eepromtype = value ++ else: ++ name = "Unknown" ++ _len = ord(t[1]) ++ value = "" ++ for c in t[2:2 + ord(t[1])]: ++ value += "0x%02X " % (ord(c),) ++ return {"name": name, "code": ord(t[0]), "value": value, "lens": _len} ++ ++ def __str__(self): ++ formatstr = "Card id : %s \n" \ ++ "Product Name : %s \n" \ ++ "Part Number : %s \n" \ ++ "Serial Number : %s \n" \ ++ "Base MAC Address : %s \n" \ ++ "Manufacture Date : %s \n" \ ++ "Device Version : %s \n" \ ++ "Label Revision : %s \n" \ ++ "Platform Name : %s \n" \ ++ "ONIE Version : %s \n" \ ++ "MAC Addresses : %s \n" \ ++ "Manufacturer : %s \n" \ ++ "Manufacture Country : %s \n" \ ++ "Vendor Name : %s \n" \ ++ "Diag Version : %s \n" \ ++ "Service Tag : %s \n" \ ++ "CRC-32 : %s \n" ++ return formatstr % (self._cardid, ++ self._productname, ++ self._partnum, ++ self._serialnum, ++ self._macbase, ++ self._manufdate, ++ self._deviceversion, ++ self._labelrevision, ++ self._platformname, ++ self._onieversion, ++ self._macsize, ++ self._manufname, ++ self._manufcountry, ++ self._vendorname, ++ self._diagname, ++ self._servicetag, ++ self._crc32) +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/__init__.py +new file mode 100644 +index 000000000..e69de29bb +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/baseutil.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/baseutil.py +new file mode 100644 +index 000000000..5260107c9 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/baseutil.py +@@ -0,0 +1,164 @@ ++#!/usr/bin/env python3 ++####################################################### ++# ++# baseutil.py ++# Python implementation of the Class baseutil ++# ++####################################################### ++import importlib.machinery ++import os ++import syslog ++import json ++from plat_hal.osutil import osutil ++ ++SYSLOG_IDENTIFIER = "HAL" ++ ++CONFIG_DB_PATH = "/etc/sonic/config_db.json" ++BOARD_ID_PATH = "/sys/module/platform_common/parameters/dfd_my_type" ++BOARD_AIRFLOW_PATH = "/etc/sonic/.airflow" ++ ++ ++def getonieplatform(path): ++ if not os.path.isfile(path): ++ return "" ++ machine_vars = {} ++ with open(path) as machine_file: ++ for line in machine_file: ++ tokens = line.split('=') ++ if len(tokens) < 2: ++ continue ++ machine_vars[tokens[0]] = tokens[1].strip() ++ return machine_vars.get("onie_platform") ++ ++ ++def getboardid(): ++ if not os.path.exists(BOARD_ID_PATH): ++ return "NA" ++ with open(BOARD_ID_PATH) as fd: ++ id_str = fd.read().strip() ++ return "0x%x" % (int(id_str, 10)) ++ ++ ++def getboardairflow(): ++ if not os.path.exists(BOARD_AIRFLOW_PATH): ++ return "NA" ++ with open(BOARD_AIRFLOW_PATH) as fd: ++ airflow_str = fd.read().strip() ++ data = json.loads(airflow_str) ++ airflow = data.get("board", "NA") ++ return airflow ++ ++ ++def getplatform_config_db(): ++ if not os.path.isfile(CONFIG_DB_PATH): ++ return "" ++ val = os.popen("sonic-cfggen -j %s -v DEVICE_METADATA.localhost.platform" % CONFIG_DB_PATH).read().strip() ++ if len(val) <= 0: ++ return "" ++ return val ++ ++ ++def getplatform_name(): ++ if os.path.isfile('/host/machine.conf'): ++ return getonieplatform('/host/machine.conf') ++ if os.path.isfile('/etc/sonic/machine.conf'): ++ return getonieplatform('/etc/sonic/machine.conf') ++ return getplatform_config_db() ++ ++ ++platform = (getplatform_name()).replace("-", "_") ++boardid = getboardid() ++boardairflow = getboardairflow() ++ ++ ++CONFIG_FILE_PATH_LIST = [ ++ "/usr/local/bin/", ++ "/usr/lib/python3/dist-packages/", ++ "/usr/local/lib/python3.7/dist-packages/hal-config/", ++ "/usr/local/lib/python3.9/dist-packages/hal-config/" ++] ++ ++ ++DEVICE_CONFIG_FILE_LIST = [ ++ platform + "_" + boardid + "_" + boardairflow + "_device.py", ++ platform + "_" + boardid + "_device.py", ++ platform + "_" + boardairflow + "_device.py", ++ platform + "_device.py" ++] ++ ++ ++MONITOR_CONFIG_FILE_LIST = [ ++ platform + "_" + boardid + "_" + boardairflow + "_monitor.py", ++ platform + "_" + boardid + "_monitor.py", ++ platform + "_" + boardairflow + "_monitor.py", ++ platform + "_monitor.py" ++] ++ ++ ++class baseutil: ++ ++ CONFIG_NAME = 'devices' ++ MONITOR_CONFIG_NAME = 'monitor' ++ UBOOT_ENV_URL = '/etc/device/uboot_env' ++ ++ @staticmethod ++ def get_config(): ++ real_path = None ++ for configfile_path in CONFIG_FILE_PATH_LIST: ++ for config_file in DEVICE_CONFIG_FILE_LIST: ++ file = configfile_path + config_file ++ if os.path.exists(file): ++ real_path = file ++ break ++ if real_path is not None: ++ break ++ ++ if real_path is None: ++ raise Exception("get hal device config error") ++ devices = importlib.machinery.SourceFileLoader(baseutil.CONFIG_NAME, real_path).load_module() ++ return devices.devices ++ ++ @staticmethod ++ def get_monitor_config(): ++ real_path = None ++ for configfile_path in CONFIG_FILE_PATH_LIST: ++ for config_file in MONITOR_CONFIG_FILE_LIST: ++ file = configfile_path + config_file ++ if os.path.exists(file): ++ real_path = file ++ break ++ if real_path is not None: ++ break ++ ++ if real_path is None: ++ raise Exception("get hal monitor config error") ++ monitor = importlib.machinery.SourceFileLoader(baseutil.MONITOR_CONFIG_NAME, real_path).load_module() ++ return monitor.monitor ++ ++ @staticmethod ++ def get_productname(): ++ ret, val = osutil.command("cat %s |grep productname | awk -F\"=\" '{print $2;}'" % baseutil.UBOOT_ENV_URL) ++ tmp = val.lower().replace('-', '_') ++ if ret != 0 or len(val) <= 0: ++ raise Exception("get productname error") ++ return tmp ++ ++ @staticmethod ++ def get_platform(): ++ ret, val = osutil.command("cat %s |grep conffitname | awk -F\"=\" '{print $2;}'" % baseutil.UBOOT_ENV_URL) ++ if ret != 0 or len(val) <= 0: ++ raise Exception("get platform error") ++ return val ++ ++ @staticmethod ++ def get_product_fullname(): ++ ret, val = osutil.command("cat %s |grep productname | awk -F\"=\" '{print $2;}'" % baseutil.UBOOT_ENV_URL) ++ if ret != 0 or len(val) <= 0: ++ raise Exception("get productname error") ++ return val ++ ++ @staticmethod ++ def logger_debug(msg): ++ syslog.openlog(SYSLOG_IDENTIFIER) ++ syslog.syslog(syslog.LOG_DEBUG, msg) ++ syslog.closelog() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/chassisbase.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/chassisbase.py +new file mode 100644 +index 000000000..767d6da34 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/chassisbase.py +@@ -0,0 +1,318 @@ ++#!/usr/bin/env python3 ++####################################################### ++# ++# chassisbase.py ++# Python implementation of the Class chassisbase ++# ++####################################################### ++from plat_hal.dcdc import dcdc ++from plat_hal.onie_e2 import onie_e2 ++from plat_hal.psu import psu ++from plat_hal.led import led ++from plat_hal.temp import temp ++from plat_hal.fan import fan ++from plat_hal.cpld import cpld ++from plat_hal.component import component ++from plat_hal.cpu import cpu ++from plat_hal.baseutil import baseutil ++ ++ ++class chassisbase(object): ++ __onie_e2_list = [] ++ __psu_list = [] ++ __led_list = [] ++ __temp_list = [] ++ __fan_list = [] ++ __card_list = [] ++ __sensor_list = [] ++ __dcdc_list = [] ++ __cpld_list = [] ++ __comp_list = [] ++ __bios_list = [] ++ __bmc_list = [] ++ __cpu = None ++ ++ def __init__(self, conftype=0, conf=None): ++ # type: (object, object, object) -> object ++ """ ++ init chassisbase as order ++ ++ type = 0 use default conf, maybe auto find by platform ++ type = 1 use given conf, conf is not None ++ ++ BITMAP ++ bit 16 ++ bit 0 PSU ++ bit 1 LED ++ bit 2 TEMP ++ bit 3 fan ++ bit 4 card ++ bit 5 sensor ++ """ ++ __confTemp = None ++ ++ if conftype == 0: ++ # user ++ __confTemp = baseutil.get_config() ++ elif conftype == 1: ++ __confTemp = conf ++ ++ # onie_e2 ++ onie_e2temp = [] ++ onie_e2config = __confTemp.get('onie_e2', []) ++ for item in onie_e2config: ++ onie_e2_1 = onie_e2(item) ++ onie_e2temp.append(onie_e2_1) ++ self.onie_e2_list = onie_e2temp ++ ++ # psu ++ psutemp = [] ++ psuconfig = __confTemp.get('psus', []) ++ for item in psuconfig: ++ psu1 = psu(item) ++ psutemp.append(psu1) ++ self.psu_list = psutemp ++ ++ # led ++ ledtemp = [] ++ ledconfig = __confTemp.get('leds', []) ++ for item in ledconfig: ++ led1 = led(item) ++ ledtemp.append(led1) ++ self.led_list = ledtemp ++ ++ # temp ++ temptemp = [] ++ tempconfig = __confTemp.get('temps', []) ++ for item in tempconfig: ++ temp1 = temp(item) ++ temptemp.append(temp1) ++ self.temp_list = temptemp ++ ++ # fan ++ fantemp = [] ++ fanconfig = __confTemp.get('fans', []) ++ for item in fanconfig: ++ fan1 = fan(item) ++ fantemp.append(fan1) ++ self.fan_list = fantemp ++ ++ # dcdc ++ dcdctemp = [] ++ dcdcconfig = __confTemp.get('dcdc', []) ++ for item in dcdcconfig: ++ dcdc1 = dcdc(item) ++ dcdctemp.append(dcdc1) ++ self.dcdc_list = dcdctemp ++ ++ # cpld ++ cpldtemp = [] ++ cpldconfig = __confTemp.get('cplds', []) ++ for item in cpldconfig: ++ cpld1 = cpld(item) ++ cpldtemp.append(cpld1) ++ self.cpld_list = cpldtemp ++ ++ # compoment: cpld/fpga/bios ++ comptemp = [] ++ compconfig = __confTemp.get('comp_cpld', []) ++ for item in compconfig: ++ comp1 = component(item) ++ comptemp.append(comp1) ++ self.comp_list = comptemp ++ ++ compconfig = __confTemp.get('comp_fpga', []) ++ for item in compconfig: ++ comp1 = component(item) ++ self.comp_list.append(comp1) ++ ++ compconfig = __confTemp.get('comp_bios', []) ++ for item in compconfig: ++ comp1 = component(item) ++ self.comp_list.append(comp1) ++ ++ # cpu ++ cpuconfig = __confTemp.get('cpu', []) ++ if len(cpuconfig): ++ self.cpu = cpu(cpuconfig[0]) ++ ++ # dcdc ++ @property ++ def dcdc_list(self): ++ return self.__dcdc_list ++ ++ @dcdc_list.setter ++ def dcdc_list(self, val): ++ self.__dcdc_list = val ++ ++ # sensor ++ @property ++ def sensor_list(self): ++ return self.__sensor_list ++ ++ @sensor_list.setter ++ def sensor_list(self, val): ++ self.__sensor_list = val ++ ++ def get_sensor_byname(self, name): ++ tmp = self.sensor_list ++ for item in tmp: ++ if name == item.name: ++ return item ++ return None ++ ++ # onie_e2 ++ @property ++ def onie_e2_list(self): ++ return self.__onie_e2_list ++ ++ @onie_e2_list.setter ++ def onie_e2_list(self, val): ++ self.__onie_e2_list = val ++ ++ def get_onie_e2_byname(self, name): ++ tmp = self.onie_e2_list ++ for item in tmp: ++ if name == item.name: ++ return item ++ return None ++ ++ # psu ++ @property ++ def psu_list(self): ++ return self.__psu_list ++ ++ @psu_list.setter ++ def psu_list(self, val): ++ self.__psu_list = val ++ ++ def get_psu_byname(self, name): ++ tmp = self.psu_list ++ for item in tmp: ++ if name == item.name: ++ return item ++ return None ++ ++ # fan ++ @property ++ def fan_list(self): ++ return self.__fan_list ++ ++ @fan_list.setter ++ def fan_list(self, val): ++ self.__fan_list = val ++ ++ def get_fan_byname(self, name): ++ tmp = self.fan_list ++ for item in tmp: ++ if name == item.name: ++ return item ++ return None ++ ++ # led ++ ++ @property ++ def led_list(self): ++ return self.__led_list ++ ++ @led_list.setter ++ def led_list(self, val): ++ self.__led_list = val ++ ++ def get_led_byname(self, name): ++ tmp = self.led_list ++ for item in tmp: ++ if name == item.name: ++ return item ++ return None ++ ++ # temp ++ @property ++ def temp_list(self): ++ return self.__temp_list ++ ++ @temp_list.setter ++ def temp_list(self, val): ++ self.__temp_list = val ++ ++ def get_temp_byname(self, name): ++ tmp = self.temp_list ++ for item in tmp: ++ if name == item.name: ++ return item ++ return None ++ ++ # cpld ++ @property ++ def cpld_list(self): ++ return self.__cpld_list ++ ++ @cpld_list.setter ++ def cpld_list(self, val): ++ self.__cpld_list = val ++ ++ def get_cpld_byname(self, name): ++ tmp = self.cpld_list ++ for item in tmp: ++ if name == item.name: ++ return item ++ return None ++ ++ @property ++ def comp_list(self): ++ return self.__comp_list ++ ++ @comp_list.setter ++ def comp_list(self, val): ++ self.__comp_list = val ++ ++ def get_comp_byname(self, name): ++ tmp = self.comp_list ++ for item in tmp: ++ if name == item.name: ++ return item ++ return None ++ ++ # bios ++ @property ++ def bios_list(self): ++ return self.__bios_list ++ ++ @bios_list.setter ++ def bios_list(self, val): ++ self.__bios_list = val ++ ++ def get_bios_byname(self, name): ++ tmp = self.bios_list ++ for item in tmp: ++ if name == item.name: ++ return item ++ return None ++ ++ # bmc ++ @property ++ def bmc_list(self): ++ return self.__bmc_list ++ ++ @bmc_list.setter ++ def bmc_list(self, val): ++ self.__bmc_list = val ++ ++ def get_bmc_byname(self, name): ++ tmp = self.bmc_list ++ for item in tmp: ++ if name == item.name: ++ return item ++ return None ++ ++ # cpu ++ @property ++ def cpu(self): ++ return self.__cpu ++ ++ @cpu.setter ++ def cpu(self, val): ++ self.__cpu = val ++ ++ def get_cpu_byname(self, name): ++ return self.cpu +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/component.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/component.py +new file mode 100644 +index 000000000..0f2ad2167 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/component.py +@@ -0,0 +1,33 @@ ++#!/usr/bin/env python3 ++####################################################### ++# ++# component.py ++# Python implementation of the Class fan ++# ++####################################################### ++from plat_hal.devicebase import devicebase ++from plat_hal.osutil import osutil ++ ++ ++class component(devicebase): ++ __user_reg = None ++ ++ def __init__(self, conf=None): ++ if conf is not None: ++ self.name = conf.get('name', None) ++ self.version_file = conf.get('VersionFile', None) ++ self.comp_id = conf.get("comp_id", None) ++ self.desc = conf.get("desc", None) ++ self.slot = conf.get("slot", None) ++ ++ def get_version(self): ++ version = "NA" ++ try: ++ ret, version = self.get_value(self.version_file) ++ if ret is False: ++ return version ++ pattern = self.version_file.get('pattern', None) ++ version = osutil.std_match(version, pattern) ++ except Exception: ++ return version ++ return version +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpld.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpld.py +new file mode 100644 +index 000000000..09eed5f97 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpld.py +@@ -0,0 +1,66 @@ ++#!/usr/bin/env python3 ++####################################################### ++# ++# fan.py ++# Python implementation of the Class fan ++# ++####################################################### ++from plat_hal.devicebase import devicebase ++ ++ ++class cpld(devicebase): ++ __user_reg = None ++ ++ def __init__(self, conf=None): ++ if conf is not None: ++ self.name = conf.get('name', None) ++ self.user_reg = conf.get('UserReg', None) ++ self.console_reg = conf.get('ConsoleReg', None) ++ self.console_reg_attrs = conf.get('ConsoleRegAttrs', None) ++ self.version_file = conf.get('VersionFile', None) ++ self.cpld_id = conf.get("cpld_id", None) ++ self.desc = conf.get("desc", None) ++ self.slot = conf.get("slot", None) ++ self.format = conf.get("format", "big_endian") ++ self.warm = conf.get("warm", None) ++ self.type = conf.get("type", None) ++ ++ def get_user_reg(self): ++ if self.user_reg is None: ++ return False ++ ret, val = self.get_value(self.user_reg) ++ return val ++ ++ def set_user_reg(self, value): ++ if self.user_reg is None: ++ return False ++ byte = value & 0xFF ++ ret, val = self.set_value(self.user_reg, byte) ++ return ret ++ ++ def set_console_owner(self, owner): ++ ret = False ++ ++ if self.console_reg is None: ++ return False ++ tmpattr = self.console_reg_attrs.get(owner, None) ++ if tmpattr is not None: ++ ret, val = self.set_value(self.console_reg, tmpattr) ++ return ret ++ ++ def get_version(self): ++ ret, val = self.get_value(self.version_file) ++ if ret is False: ++ val = "N/A" ++ return val ++ if self.type == "str": ++ return val.strip('\n') ++ val = val.strip('\n').split(" ") ++ if len(val) < 4: ++ val = "N/A" ++ return val ++ if self.format == "little_endian": ++ cpld_version = "%s%s%s%s" % (val[3], val[2], val[1], val[0]) ++ else: ++ cpld_version = "%s%s%s%s" % (val[0], val[1], val[2], val[3]) ++ return cpld_version +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpu.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpu.py +new file mode 100644 +index 000000000..c6bec1abd +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpu.py +@@ -0,0 +1,48 @@ ++#!/usr/bin/env python3 ++############################################################################### ++# ++# Hardware Abstraction Layer APIs -- CPU APIs. ++# ++############################################################################### ++from plat_hal.devicebase import devicebase ++ ++ ++class cpu(devicebase): ++ ++ def __init__(self, conf=None): ++ if conf is not None: ++ self.name = conf.get('name', None) ++ self.cpu_reset_cnt_reg = conf.get('CpuResetCntReg', None) ++ self.reboot_cause_path = conf.get('reboot_cause_path', "/etc/sonic/.reboot/.previous-reboot-cause.txt") ++ ++ def get_cpu_reset_num(self): ++ """ ++ get cpu reset num. ++ @return cpu reset number, -1 for failure ++ """ ++ ret = -1 ++ if self.cpu_reset_cnt_reg is None: ++ self.logger_debug("ERR: no support get cpu reset num") ++ return ret ++ ret, reset_num = self.get_value(self.cpu_reset_cnt_reg) ++ if ret is False or reset_num is None: ++ self.logger_debug("ERR: i2c read cpu_reset_cnt_reg,result:%s" % reset_num) ++ else: ++ if isinstance(reset_num, str): ++ ret = int(reset_num, 16) ++ else: ++ ret = reset_num ++ return ret ++ ++ def get_cpu_reboot_cause(self): ++ """ ++ get_cpu_reboot_cause ++ @return cpu reset number, -1 for failure ++ """ ++ try: ++ with open(self.reboot_cause_path) as fd: ++ reboot_cause = fd.read().strip() ++ return reboot_cause ++ except Exception: ++ return "Unknown reboot cause" ++ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/dcdc.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/dcdc.py +new file mode 100644 +index 000000000..ba6049950 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/dcdc.py +@@ -0,0 +1,11 @@ ++#!/usr/bin/env python3 ++from plat_hal.devicebase import devicebase ++from plat_hal.sensor import sensor ++ ++ ++class dcdc(devicebase): ++ def __init__(self, conf=None): ++ if conf is not None: ++ self.name = conf.get('name', None) ++ self.dcdc_id = conf.get("dcdc_id", None) ++ self.sensor = sensor(conf) +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/devicebase.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/devicebase.py +new file mode 100644 +index 000000000..001b4ee23 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/devicebase.py +@@ -0,0 +1,351 @@ ++#!/usr/bin/env python3 ++####################################################### ++# ++# devicebase.py ++# Python implementation of the Class devicebase ++# ++####################################################### ++import subprocess ++import shlex ++import ast ++from plat_hal.osutil import osutil ++from plat_hal.baseutil import baseutil ++ ++class CodeVisitor(ast.NodeVisitor): ++ ++ def __init__(self): ++ self.value = None ++ ++ def get_value(self): ++ return self.value ++ ++ def get_op_value(self, node): ++ if isinstance(node, ast.Call): # node is func call ++ value = self.visit_Call(node) ++ elif isinstance(node, ast.BinOp): # node is BinOp ++ value = self.visit_BinOp(node) ++ elif isinstance(node, ast.UnaryOp): # node is UnaryOp ++ value = self.visit_UnaryOp(node) ++ elif isinstance(node, ast.Num): # node is Num Constant ++ value = node.n ++ elif isinstance(node, ast.Str): # node is Str Constant ++ value = node.s ++ else: ++ raise NotImplementedError("Unsupport operand type: %s" % type(node)) ++ return value ++ ++ def visit_UnaryOp(self, node): ++ ''' ++ node.op: operand type, only support ast.UAdd/ast.USub ++ node.operand: only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.UnaryOp ++ ''' ++ ++ operand_value = self.get_op_value(node.operand) ++ if isinstance(node.op, ast.UAdd): ++ self.value = operand_value ++ elif isinstance(node.op, ast.USub): ++ self.value = 0 - operand_value ++ else: ++ raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) ++ return self.value ++ ++ def visit_BinOp(self, node): ++ ''' ++ node.left: left operand, only support ast.Call/ast.Constant(ast.Num)/ast.BinOp ++ node.op: operand type, only support ast.Add/ast.Sub/ast.Mult/ast.Div ++ node.right: right operan, only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp ++ ''' ++ left_value = self.get_op_value(node.left) ++ right_value = self.get_op_value(node.right) ++ ++ if isinstance(node.op, ast.Add): ++ self.value = left_value + right_value ++ elif isinstance(node.op, ast.Sub): ++ self.value = left_value - right_value ++ elif isinstance(node.op, ast.Mult): ++ self.value = left_value * right_value ++ elif isinstance(node.op, ast.Div): ++ self.value = left_value / right_value ++ else: ++ raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) ++ return self.value ++ ++ def visit_Call(self, node): ++ ''' ++ node.func.id: func name, only support 'float', 'int', 'str' ++ node.args: func args list,only support ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.Call ++ str/float only support one parameter, eg: float(XXX), str(xxx) ++ int support one or two parameters, eg: int(xxx) or int(xxx, 16) ++ xxx can be ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp ++ ''' ++ calc_tuple = ("float", "int", "str") ++ ++ if node.func.id not in calc_tuple: ++ raise NotImplementedError("Unsupport function call type: %s" % node.func.id) ++ ++ args_val_list = [] ++ for item in node.args: ++ ret = self.get_op_value(item) ++ args_val_list.append(ret) ++ ++ if node.func.id == "str": ++ if len(args_val_list) != 1: ++ raise TypeError("str() takes 1 positional argument but %s were given" % len(args_val_list)) ++ value = str(args_val_list[0]) ++ self.value = value ++ return value ++ ++ if node.func.id == "float": ++ if len(args_val_list) != 1: ++ raise TypeError("float() takes 1 positional argument but %s were given" % len(args_val_list)) ++ value = float(args_val_list[0]) ++ self.value = value ++ return value ++ # int ++ if len(args_val_list) == 1: ++ value = int(args_val_list[0]) ++ self.value = value ++ return value ++ if len(args_val_list) == 2: ++ value = int(args_val_list[0], args_val_list[1]) ++ self.value = value ++ return value ++ raise TypeError("int() takes 1 or 2 arguments (%s given)" % len(args_val_list)) ++ ++ ++class devicebase(object): ++ _name = None ++ __error_ret = -99999 ++ ++ @property ++ def name(self): ++ return self._name ++ ++ @name.setter ++ def name(self, val): ++ self._name = val ++ ++ def dumpValueByI2c(self, bus, loc): ++ value = "" ++ for i in range(256): ++ ret, val = self.get_i2c(bus, loc, i) ++ value += chr(val) ++ return value ++ ++ def byteTostr(self, val): ++ strtmp = '' ++ for value in val: ++ strtmp += chr(value) ++ return strtmp ++ ++ def get_eeprom_info(self, conf): ++ eeprom = "" ++ if conf.get('way') == 'sysfs': ++ ret, eeprom = self.get_value(conf) ++ if ret is False: ++ return None ++ elif conf.get('way') == 'devfile': ++ ret, eeprom_list = self.get_value(conf) ++ if ret is False: ++ return None ++ for item in eeprom_list: ++ eeprom += chr(item) ++ else: ++ eeprom = self.dumpValueByI2c(conf.get('bus'), conf.get('addr')) ++ return eeprom ++ ++ def exec_os_cmd(self, cmd): ++ status, output = subprocess.getstatusoutput(cmd) ++ return status, output ++ ++ def get_value(self, config): ++ ''' ++ get value by config way ++ way i2c/sysfs/lpc ++ ''' ++ way = config.get("way") ++ if way == 'sysfs': ++ return self.get_sysfs(config.get("loc"), config.get("flock_path")) ++ if way == "i2c": ++ bus = config.get("bus") ++ addr = config.get("addr") ++ offset = config.get("offset") ++ return self.get_i2c(bus, addr, offset) ++ if way == "io": ++ io_addr = config.get('io_addr') ++ read_len = config.get('read_len', 1) ++ return self.get_io(io_addr, read_len) ++ if way == "i2cword": ++ bus = config.get("bus") ++ addr = config.get("addr") ++ offset = config.get("offset") ++ return self.get_i2cword(bus, addr, offset) ++ if way == "devmem": ++ addr = config.get("addr") ++ digit = config.get("digit") ++ mask = config.get("mask", None) ++ return self.get_devmem(addr, digit, mask) ++ if way == "sdk": ++ get_type = config.get("type") ++ if get_type == "bcm_temp": ++ return self.getbcmtemp() ++ if get_type == "bcm_reg": ++ reg = config.get("reg") ++ return self.getbcmreg(reg) ++ raise Exception("cannot found sdk type deal") ++ if way == "devfile": ++ loc = config.get("loc") ++ offset = config.get("offset") ++ length = config.get("len") ++ ret, val_list = self.devfile_read(loc, offset, length) ++ if ret is True: ++ if length == 1: ++ val = val_list[0] ++ return True, val ++ return True, val_list ++ return False, ("devfile read failed. path:%s, offset:0x%x, read_len:%d" % (loc, offset, length)) ++ if way == "devfile_ascii": ++ loc = config.get("loc") ++ offset = config.get("offset") ++ length = config.get("len") ++ return self.devfile_read_ascii(loc, offset, length) ++ if way == 'cmd': ++ cmd = config.get("cmd") ++ ret, log = self.exec_os_cmd(cmd) ++ if ret: ++ return False, ("cmd write exec %s failed, log: %s" % (cmd, log)) ++ return True, log ++ if way == 'config': ++ value = config.get("value") ++ return True, value ++ raise Exception("cannot found way deal") ++ ++ def devfile_read(self, loc, offset, length): ++ return osutil.readdevfile(loc, offset, length) ++ ++ def devfile_read_ascii(self, loc, offset, length): ++ return osutil.readdevfile_ascii(loc, offset, length) ++ ++ def get_sysfs(self, loc, flock_path=None): ++ return self.getsysfs(loc, flock_path) ++ ++ def getsysfs(self, loc, flock_path=None): ++ ret, val = osutil.readsysfs(loc, flock_path) ++ return ret, val ++ ++ def get_devmem(self, addr, digit, mask): ++ return osutil.getdevmem(addr, digit, mask) ++ ++ def get_i2cword(self, bus, addr, offset): ++ return self.geti2cword(bus, addr, offset) ++ ++ def geti2cword(self, bus, addr, offset): ++ ret, val = osutil.geti2cword(bus, addr, offset) ++ return ret, val ++ ++ def get_io(self, reg_addr, read_len): ++ return self.getio(reg_addr, read_len) ++ ++ def getio(self, reg_addr, read_len): ++ ret, val = osutil.io_rd(reg_addr, read_len) ++ return ret, val ++ ++ def get_i2c(self, bus, addr, offset): ++ return self.geti2c(bus, addr, offset) ++ ++ def geti2c(self, bus, addr, offset): ++ ret, val = osutil.wbi2cget(bus, addr, offset) ++ return ret, val ++ ++ def set_value(self, config, val): ++ ''' ++ get value by config way ++ way i2c/sysfs/lpc ++ ''' ++ way = config.get("way") ++ if way == 'sysfs': ++ return self.set_sysfs(config.get("loc"), "0x%02x" % val) ++ if way == "i2c": ++ bus = config.get("bus") ++ addr = config.get("addr") ++ offset = config.get("offset") ++ return self.set_i2c(bus, addr, offset, val) ++ if way == "i2cpec": ++ bus = config.get("bus") ++ addr = config.get("addr") ++ offset = config.get("offset") ++ return self.seti2c_byte_pec(bus, addr, offset, val) ++ if way == 'i2cword': ++ bus = config.get("bus") ++ addr = config.get("addr") ++ offset = config.get("offset") ++ return self.set_i2cword(bus, addr, offset, val) ++ if way == "i2cwordpec": ++ bus = config.get("bus") ++ addr = config.get("addr") ++ offset = config.get("offset") ++ return self.set_i2cwordpec(bus, addr, offset, val) ++ if way == "devfile": ++ loc = config.get("loc") ++ offset = config.get("offset") ++ return self.devfile_write(loc, offset, val) ++ return False, "unsupport way: %s" % way ++ ++ def set_sysfs(self, loc, value): ++ return self.setsysfs(loc, value) ++ ++ def setsysfs(self, loc, value): ++ return osutil.writesysfs(loc, value) ++ ++ def set_i2cword(self, bus, addr, offset, byte): ++ return self.seti2cword(bus, addr, offset, byte) ++ ++ def seti2cword(self, bus, addr, offset, byte): ++ return osutil.seti2cword(bus, addr, offset, byte) ++ ++ def set_i2cwordpec(self, bus, addr, offset, val): ++ return osutil.seti2cwordpec(bus, addr, offset, val) ++ ++ def seti2c_byte_pec(self, bus, addr, offset, val): ++ return osutil.seti2c_byte_pec(bus, addr, offset, val) ++ ++ def set_i2c(self, bus, addr, offset, byte): ++ return self.seti2c(bus, addr, offset, byte) ++ ++ def seti2c(self, bus, addr, offset, byte): ++ ret, val = osutil.wbi2cset(bus, addr, offset, byte) ++ return ret, val ++ ++ def devfile_write(self, loc, offset, val): ++ ret, val = osutil.writedevfile(loc, offset, val) ++ return ret, val ++ ++ def getbcmtemp(self): ++ try: ++ sta, ret = osutil.getmactemp() ++ if sta is True: ++ mac_aver = float(ret.get("average", self.__error_ret)) ++ mac_aver = mac_aver * 1000 ++ else: ++ return False, ret ++ except AttributeError as e: ++ return False, str(e) ++ return True, mac_aver ++ ++ def getbcmreg(self, reg): ++ ret, val = osutil.getsdkreg(reg) ++ return ret, val ++ ++ def logger_debug(self, msg): ++ baseutil.logger_debug(msg) ++ ++ def command(self, cmd): ++ ret, output = osutil.command(cmd) ++ return ret, output ++ ++ def get_format_value(self, format_str): ++ ast_obj = ast.parse(format_str, mode='eval') ++ visitor = CodeVisitor() ++ visitor.visit(ast_obj) ++ ret = visitor.get_value() ++ return ret +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/fan.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/fan.py +new file mode 100644 +index 000000000..1424c14a4 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/fan.py +@@ -0,0 +1,417 @@ ++#!/usr/bin/env python3 ++####################################################### ++# ++# fan.py ++# Python implementation of the Class fan ++# ++####################################################### ++from eepromutil.fru import ipmifru ++from eepromutil.fantlv import fan_tlv ++from plat_hal.devicebase import devicebase ++from plat_hal.rotor import rotor ++ ++ ++class fan(devicebase): ++ __rotor_list = [] ++ __pn = None ++ __raweeprom = None ++ __sn = None ++ __hw_version = None ++ __e2loc = None ++ __rotors = None ++ __AirFlow = None ++ __SpeedMin = None ++ __SpeedMax = None ++ __PowerMax = None ++ __productName = None ++ __productSerialNumber = None ++ __WatchdogStatus = None ++ __led_attrs_config = None ++ __led_config = None ++ __WatchdogStatus_config = None ++ __AirFlowconifg = None ++ __EnableWatchdogConf = None ++ __Rotor_config = None ++ __fan_display_name = None # 'N/A' ++ __fan_display_name_conifg = None ++ ++ def __init__(self, conf=None): ++ if conf is not None: ++ self.name = conf.get('name', None) ++ self.sn = conf.get('sn', None) ++ self.present = conf.get('present', None) ++ self.e2loc = conf.get('e2loc', None) ++ self.e2_type = conf.get('e2_type', "fru") ++ self.SpeedMin = conf.get('SpeedMin', None) ++ self.SpeedMax = conf.get('SpeedMax', None) ++ self.PowerMax = conf.get('PowerMax', None) ++ self.AirFlowconifg = conf.get("airflow", None) ++ self.WatchdogStatus_config = conf.get('WatchdogStatus', None) ++ self.EnableWatchdogConf = conf.get('EnableWatchdogConf', None) ++ self.led_attrs_config = conf.get('led_attrs', None) ++ self.led_config = conf.get('led', None) ++ self.Rotor_config = conf.get('Rotor', None) ++ self.fan_display_name_conifg = conf.get("fan_display_name", None) ++ rotor_tmp = [] ++ for value in self.Rotor_config.values(): ++ rotor_tmp.append(rotor(value)) ++ rotor_tmp.sort(key=lambda x: x.name, reverse=False) ++ self.rotor_list = rotor_tmp ++ self.rotors = len(self.rotor_list) ++ ++ @property ++ def EnableWatchdogConf(self): ++ return self.__EnableWatchdogConf ++ ++ @EnableWatchdogConf.setter ++ def EnableWatchdogConf(self, val): ++ self.__EnableWatchdogConf = val ++ ++ @property ++ def rotor_list(self): ++ return self.__rotor_list ++ ++ @rotor_list.setter ++ def rotor_list(self, val): ++ self.__rotor_list = val ++ ++ @property ++ def Rotor_config(self): ++ return self.__Rotor_config ++ ++ @Rotor_config.setter ++ def Rotor_config(self, val): ++ self.__Rotor_config = val ++ ++ @property ++ def productName(self): ++ return self.__productName ++ ++ @productName.setter ++ def productName(self, val): ++ self.__productName = val ++ ++ @property ++ def productSerialNumber(self): ++ return self.__productSerialNumber ++ ++ @productSerialNumber.setter ++ def productSerialNumber(self, val): ++ self.__productSerialNumber = val ++ ++ @property ++ def hw_version(self): ++ return self.__hw_version ++ ++ @hw_version.setter ++ def hw_version(self, val): ++ self.__hw_version = val ++ ++ @property ++ def sn(self): ++ return self.__sn ++ ++ @sn.setter ++ def sn(self, val): ++ self.__sn = val ++ ++ @property ++ def pn(self): ++ return self.__pn ++ ++ @pn.setter ++ def pn(self, val): ++ self.__pn = val ++ ++ @property ++ def raweeprom(self): ++ return self.__raweeprom ++ ++ @raweeprom.setter ++ def raweeprom(self, val): ++ self.__raweeprom = val ++ ++ @property ++ def SpeedMax(self): ++ return self.__SpeedMax ++ ++ @SpeedMax.setter ++ def SpeedMax(self, val): ++ self.__SpeedMax = val ++ ++ @property ++ def SpeedMin(self): ++ return self.__SpeedMin ++ ++ @SpeedMin.setter ++ def SpeedMin(self, val): ++ self.__SpeedMin = val ++ ++ @property ++ def PowerMax(self): ++ return self.__PowerMax ++ ++ @PowerMax.setter ++ def PowerMax(self, val): ++ self.__PowerMax = val ++ ++ @property ++ def rotors(self): ++ return self.__rotors ++ ++ @property ++ def AirFlow(self): ++ return self.__AirFlow ++ ++ @AirFlow.setter ++ def AirFlow(self, val): ++ self.__AirFlow = val ++ ++ @rotors.setter ++ def rotors(self, val): ++ self.__rotors = val ++ ++ @property ++ def fan_display_name_conifg(self): ++ return self.__fan_display_name_conifg ++ ++ @fan_display_name_conifg.setter ++ def fan_display_name_conifg(self, val): ++ self.__fan_display_name_conifg = val ++ ++ @property ++ def fan_display_name(self): ++ return self.__fan_display_name ++ ++ @fan_display_name.setter ++ def fan_display_name(self, val): ++ self.__fan_display_name = val ++ ++ def getspeed(self, conf): ++ tmp = None ++ if conf is None: ++ return -1 ++ ret, val = self.get_value(conf) ++ if ret is True: ++ tmp = int(str(val), 10) ++ else: ++ val = None ++ if val is not None: ++ return int(15000000 / tmp) ++ return -1 ++ ++ def get_speed(self, rotor_index): ++ rotor_item = self.get_rotor_index(rotor_index) ++ if rotor_item is None: ++ return None ++ speed = rotor_item.rotor_Speed.Value ++ if speed is None: ++ return None ++ return int(speed) ++ ++ def set_led(self, color): ++ status = self.led_attrs_config.get(color, None) ++ if status is None: ++ return False ++ ++ mask = self.led_attrs_config.get('mask', 0xff) ++ ret, value = self.get_value(self.led_config) ++ if ret is False or value is None: ++ return False ++ setval = (int(value) & ~mask) | (status) ++ ret, val = self.set_value(self.led_config, setval) ++ return ret ++ ++ def get_led(self): ++ mask = self.led_attrs_config.get('mask', 0xff) ++ ret, value = self.get_value(self.led_config) ++ if ret is False or value is None: ++ return False, 'N/A' ++ ledval = int(value) & mask ++ for key, val in self.led_attrs_config.items(): ++ if (ledval == val) and (key != "mask"): ++ return True, key ++ return False, 'N/A' ++ ++ def set_speed(self, rotor_index, level): ++ if level > 255 or level < 0: ++ return False ++ rotor_item = self.get_rotor_index(rotor_index) ++ if rotor_item is None: ++ return False ++ ret, val = self.set_value(rotor_item.Speedconfig, int(level)) ++ return ret ++ ++ def get_rotor_index(self, rotor_index): ++ if rotor_index > len(self.rotor_list): ++ return None ++ rotor_item = self.rotor_list[rotor_index - 1] ++ return rotor_item ++ ++ def get_rotor_byname(self, rotor_index): ++ for rotor_item in self.rotor_list: ++ if rotor_item.name == rotor_index: ++ return rotor_item ++ return None ++ ++ def get_presence(self): ++ ret, val = self.get_value(self.present) ++ if ret is False or val is None: ++ return -1 ++ if isinstance(val, str): ++ value = int(val, 16) ++ else: ++ value = val ++ mask = self.present.get("mask") ++ flag = value & mask ++ okval = self.present.get("okval", 0) ++ if flag == okval: ++ return True ++ return False ++ ++ def get_speed_pwm(self, rotor_index): ++ rotor_item = self.get_rotor_index(rotor_index) ++ if rotor_item is None: ++ return False ++ if rotor_item.i2c_speed is None: ++ return False ++ val = round(rotor_item.i2c_speed * 100 / 255) ++ return val ++ ++ def feed_watchdog(self): ++ ret = False ++ for rotor_item in self.rotor_list: ++ ret, val = rotor_item.feed_watchdog() ++ if ret is False: ++ return ret ++ return ret ++ ++ def get_fru_info(self): ++ try: ++ if self.get_presence() is False: ++ raise Exception("%s: not present" % self.name) ++ eeprom = self.get_eeprom_info(self.e2loc) ++ if eeprom is None: ++ raise Exception("%s: value is none" % self.name) ++ fru = ipmifru() ++ if isinstance(eeprom, bytes): ++ eeprom = self.byteTostr(eeprom) ++ fru.decodeBin(eeprom) ++ self.productName = fru.productInfoArea.productName.strip() # PN ++ self.productSerialNumber = fru.productInfoArea.productSerialNumber.strip() # SN ++ self.hw_version = fru.productInfoArea.productVersion.strip() # HW ++ except Exception: ++ self.productName = None ++ self.productSerialNumber = None ++ self.hw_version = None ++ return False ++ return True ++ ++ def get_tlv_info(self): ++ try: ++ if self.get_presence() is False: ++ raise Exception("%s: not present" % self.name) ++ eeprom = self.get_eeprom_info(self.e2loc) ++ if eeprom is None: ++ raise Exception("%s: value is none" % self.name) ++ tlv = fan_tlv() ++ rets = tlv.decode(eeprom) ++ for item in rets: ++ if item["name"] == "Product Name": ++ self.productName = item["value"].replace("\x00", "").strip() ++ elif item["name"] == "serial Number": ++ self.productSerialNumber = item["value"].replace("\x00", "").strip() ++ elif item["name"] == "hardware info": ++ self.hw_version = item["value"].replace("\x00", "").strip() ++ except Exception: ++ self.productName = None ++ self.productSerialNumber = None ++ self.hw_version = None ++ return False ++ return True ++ ++ def decode_eeprom_info(self): ++ '''get fan name, hw version, sn''' ++ if self.e2_type == "fru": ++ return self.get_fru_info() ++ ++ if self.e2_type == "fantlv": ++ return self.get_tlv_info() ++ ++ return False ++ ++ def get_AirFlow(self): ++ if self.productName is None: ++ ret = self.decode_eeprom_info() ++ if ret is False: ++ self.AirFlow = None ++ return False ++ if self.AirFlowconifg is None: ++ self.AirFlow = None ++ return False ++ for i in self.AirFlowconifg: ++ if self.productName in self.AirFlowconifg[i]: ++ self.AirFlow = i ++ return True ++ self.AirFlow = None ++ return False ++ ++ def enable_watchdog(self, enable): ++ ret = False ++ if enable is True: ++ byte = self.EnableWatchdogConf.get("enable_byte", None) ++ ret, val = self.set_value(self.EnableWatchdogConf, byte) ++ elif enable is False: ++ byte = self.EnableWatchdogConf.get("disable_byte", None) ++ ret, val = self.set_value(self.EnableWatchdogConf, byte) ++ return ret ++ ++ def get_watchdog_status(self): ++ dic = {"support": None, "open": None, "work_full": None, "work_allow_set": None} ++ if self.WatchdogStatus_config is None: ++ return None ++ ret, val = self.get_value(self.WatchdogStatus_config) ++ if ret is False or val is None: ++ return None ++ support_watchdog_off = self.WatchdogStatus_config.get("support_watchdog_off", None) ++ is_open_off = self.WatchdogStatus_config.get("is_open_off", None) ++ full_running_off = self.WatchdogStatus_config.get("full_running_off", None) ++ running_setting_off = self.WatchdogStatus_config.get("running_setting_off", None) ++ if support_watchdog_off is not None: ++ if support_watchdog_off & val == self.WatchdogStatus_config.get("support_watchdog_mask", None): ++ dic["support"] = True ++ else: ++ dic["support"] = False ++ return dic ++ if is_open_off is not None: ++ if is_open_off & val == self.WatchdogStatus_config.get("is_open_mask", None): ++ dic["open"] = True ++ else: ++ dic["open"] = False ++ if full_running_off is not None: ++ if full_running_off & val == self.WatchdogStatus_config.get("full_running_mask", None): ++ dic["work_full"] = True ++ else: ++ dic["work_full"] = False ++ if running_setting_off is not None: ++ if running_setting_off & val == self.WatchdogStatus_config.get("running_setting_mask", None): ++ dic["work_allow_set"] = True ++ else: ++ dic["work_allow_set"] = False ++ return dic ++ ++ def get_fan_display_name(self): ++ if self.productName is None: ++ ret = self.decode_eeprom_info() ++ if ret is False: ++ self.fan_display_name = None ++ return False ++ if self.fan_display_name_conifg is None: ++ self.fan_display_name = self.productName ++ return False ++ for i in self.fan_display_name_conifg: ++ if self.productName in self.fan_display_name_conifg[i]: ++ self.fan_display_name = i ++ return True ++ self.fan_display_name = self.productName ++ return False +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/interface.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/interface.py +new file mode 100644 +index 000000000..7092f555c +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/interface.py +@@ -0,0 +1,1334 @@ ++#!/usr/bin/env python3 ++####################################################### ++# ++# interface.py ++# Python implementation of the Class interface ++# ++####################################################### ++import collections ++from plat_hal.chassisbase import chassisbase ++from plat_hal.baseutil import baseutil ++from plat_hal.osutil import osutil ++ ++ ++def Singleton(cls): ++ _instance = {} ++ ++ def _singleton(*args, **kargs): ++ if cls not in _instance: ++ _instance[cls] = cls(*args, **kargs) ++ return _instance[cls] ++ ++ return _singleton ++ ++ ++@Singleton ++class interface(object): ++ __chas = None ++ __error_ret = None ++ ++ def __init__(self): ++ self.chas = chassisbase() ++ self.__error_ret = -99999 ++ self.__na_ret = 'N/A' ++ ++ @property ++ def na_ret(self): ++ return self.__na_ret ++ ++ @na_ret.setter ++ def na_ret(self, val): ++ self.__na_ret = val ++ ++ @property ++ def error_ret(self): ++ return self.__error_ret ++ ++ @error_ret.setter ++ def error_ret(self, val): ++ self.__error_ret = val ++ ++ @property ++ def chas(self): ++ return self.__chas ++ ++ @chas.setter ++ def chas(self, val): ++ self.__chas = val ++ ++ # onie_e2 ++ def get_onie_e2(self): ++ onie_e2_list = self.chas.onie_e2_list ++ return onie_e2_list ++ ++ def get_onie_e2_path(self, name): ++ onie_e2 = self.chas.get_onie_e2_byname(name) ++ if onie_e2 is None: ++ return None ++ return onie_e2.e2_path ++ ++ def get_device_airflow(self, name): ++ onie_e2 = self.chas.get_onie_e2_byname(name) ++ if onie_e2 is None: ++ return None ++ return onie_e2.airflow ++ ++ def get_onie_e2_obj(self, name): ++ onie_e2 = self.chas.get_onie_e2_byname(name) ++ if onie_e2 is None: ++ return None ++ onie_e2.get_onie_e2_info() ++ return onie_e2 ++ ++ # temp ++ def get_temps(self): ++ templist = self.chas.temp_list ++ return templist ++ ++ def get_temp_total_number(self): ++ templist = self.chas.temp_list ++ return len(templist) ++ ++ def check_temp_id_exist(self, temp_id): ++ templist = self.chas.temp_list ++ for temp in templist: ++ if temp.temp_id == temp_id: ++ return True ++ return False ++ ++ def get_temp_id_number(self): ++ templist = self.chas.temp_list ++ temp_num = 0 ++ for i in range(len(templist)): ++ temp_id = "TEMP" + str(i + 1) ++ ret = self.check_temp_id_exist(temp_id) ++ if ret is True: ++ temp_num = temp_num + 1 ++ else: ++ return temp_num ++ return temp_num ++ ++ def get_temp_location(self, temp_name): ++ temp = self.chas.get_temp_byname(temp_name) ++ return temp.get_location() ++ ++ def set_temp_location(self, temp_name, location): ++ temp = self.chas.get_temp_byname(temp_name) ++ return temp.set_location(location) ++ ++ def set_temp_name(self, temp_name, name): ++ temp = self.chas.get_temp_byname(temp_name) ++ return temp.set_name(name) ++ ++ def get_appoint_temp(self, temp_name): ++ temp = self.chas.get_led_byname(temp_name) ++ return temp.get_temp() ++ ++ def set_appoint_temp(self, temp_name, val): ++ temp = self.chas.get_temp_byname(temp_name) ++ return temp.set_temp(val) ++ ++ def get_temp_mintemp(self, temp_name): ++ temp = self.chas.get_temp_byname(temp_name) ++ return temp.get_mintemp() ++ ++ def set_temp_mintemp(self, temp_name, val): ++ temp = self.chas.get_temp_byname(temp_name) ++ return temp.set_mintemp(val) ++ ++ # led ++ def get_leds(self): ++ ledlist = self.chas.led_list ++ return ledlist ++ ++ def get_led_total_number(self): ++ ledlist = self.chas.led_list ++ return len(ledlist) ++ ++ def get_led_color(self, led_name): ++ led = self.chas.get_led_byname(led_name) ++ if led is None: ++ return -1 ++ return led.get_color() ++ ++ def get_led_color_by_type(self, led_type): ++ ledlist = self.chas.led_list ++ ledtmp = None ++ for temp in ledlist: ++ if temp.led_type == led_type: ++ ledtmp = temp ++ break ++ if ledtmp is None: ++ return -1 ++ return ledtmp.get_color() ++ ++ def set_led_color(self, led_name, color): ++ led = self.chas.get_led_byname(led_name) ++ if led is None: ++ return -1 ++ return led.set_color(color) ++ ++ # psu ++ def get_psu_total_number(self): ++ psulist = self.chas.psu_list ++ if psulist is None: ++ return -1 ++ return len(psulist) ++ ++ def get_psus(self): ++ psulist = self.chas.psu_list ++ return psulist ++ ++ def get_psu_presence(self, psu_name): ++ psu = self.chas.get_psu_byname(psu_name) ++ if psu is None: ++ return -1 ++ return psu.present ++ ++ def get_psu_fru_info(self, psu_name): ++ ''' ++ { ++ "Name": "PSU1", ++ "SN": "serial_number_example", # 'N/A' ++ "PN": "part_number_example", # 'N/A' ++ "AirFlow": "B2F" # 'N/A' ++ } ++ ''' ++ psu = self.chas.get_psu_byname(psu_name) ++ if psu is None: ++ return -1 ++ psu.get_fru_info() ++ psu.get_AirFlow() ++ psu.get_psu_display_name() ++ ++ dic = collections.OrderedDict() ++ dic["Name"] = psu.name ++ dic["SN"] = psu.productSerialNumber if (psu.productSerialNumber is not None) else self.na_ret ++ dic["PN"] = psu.productPartModelName if (psu.productPartModelName is not None) else self.na_ret ++ dic["DisplayName"] = psu.psu_display_name if (psu.psu_display_name is not None) else self.na_ret ++ dic["VENDOR"] = psu.productManufacturer if (psu.productManufacturer is not None) else self.na_ret ++ dic["HW"] = psu.productVersion if (psu.productVersion is not None) else self.na_ret ++ dic["AirFlow"] = psu.AirFlow if (psu.AirFlow is not None) else self.na_ret ++ return dic ++ ++ def get_psu_input_output_status(self, psu_name): ++ psu = self.chas.get_psu_byname(psu_name) ++ if psu is None: ++ return -1 ++ psu.InputsCurrent.Value # just for clear faults ++ if psu.InputStatus is True and psu.OutputStatus is True: ++ return True ++ # only has outputstatus ++ if psu.InputStatus is None and psu.OutputStatus is True: ++ return True ++ return False ++ ++ def get_psu_status(self, psu_name): ++ """ ++ Get status of a specific PSU ++ @return dict of the specific PSU's status, None for failure ++ Example return value(all keys are mandatory) ++ { ++ "Name": "PSU1", ++ "InputType": "DC", # "AC" or 'N/A' ++ "InputStatus": True, # H/W status bit ++ "OutputStatus": True # H/W status bit ++ "FanSpeed": { ++ "Value": 4000, # -99999 ++ "Min": 2000, # -99999 ++ "Max": 10000 # -99999 ++ }, ++ "Temperature": { ++ "Value": 40.0, # -99999.0 ++ "Min": -30.0, # -99999.0 ++ "Max": 50.0 # -99999.0 ++ } ++ } ++ """ ++ psu = self.chas.get_psu_byname(psu_name) ++ if psu is None: ++ return -1 ++ ++ if psu.get_threshold_by_model == 1: ++ psu.get_fru_info() ++ ++ dic = collections.OrderedDict() ++ # psu.get_Temperature() ++ temp_dict = collections.OrderedDict() ++ temp_dict['Min'] = psu.Temperature.Min ++ temp_dict['Max'] = psu.Temperature.Max ++ temp_dict['Value'] = psu.Temperature.Value ++ temp_dict['Unit'] = psu.Temperature.Unit ++ dic["Temperature"] = temp_dict ++ ++ # psu.get_FanSpeed() ++ fan_speed_dict = collections.OrderedDict() ++ fan_speed_dict['Min'] = psu.FanSpeed.Min ++ fan_speed_dict['Max'] = psu.FanSpeed.Max ++ fan_speed_dict['Tolerance'] = psu.FanSpeedTolerance ++ fan_speed_dict['Value'] = psu.FanSpeed.Value ++ fan_speed_dict['Unit'] = psu.FanSpeed.Unit ++ dic["FanSpeed"] = fan_speed_dict ++ ++ dic["Name"] = psu.name ++ dic["InputType"] = psu.InputsType ++ dic["InputStatus"] = psu.InputStatus ++ dic["OutputStatus"] = psu.OutputStatus ++ dic["TempStatus"] = psu.TempStatus ++ dic["FanStatus"] = psu.FanStatus ++ return dic ++ ++ def get_psu_power_status(self, psu_name): ++ """ ++ Get power status of a specific PSU ++ @return dict of the specific PSU's power status, None for failure ++ Example return value ++ { ++ "Name": "PSU1", ++ "Inputs": { ++ "Status": True, # H/W status bit ++ "Type": "DC", # or "AC" or "N/A" ++ "Voltage": { ++ "Value": 220, # -1 ++ "LowAlarm": 200, # -1 ++ "HighAlarm": 240, # -1 ++ "Unit": "V" ++ }, ++ "Current": { ++ "Value": 6.0, # -99999.0 ++ "LowAlarm": 0.2, # -99999.0 ++ "HighAlarm": 7.0, # -99999.0 ++ "Unit": "A" ++ }, ++ "Power": { ++ "Value": 1000, # -99999 ++ "LowAlarm": -1, # -99999 ++ "HighAlarm": 1400, # -99999 ++ "Unit": "W" ++ } ++ }, ++ "Outputs": { ++ "Status": True, ++ "Voltage": { ++ "Value": 220, ++ "LowAlarm": 200, ++ "HighAlarm": 240, ++ "Unit": "V" ++ }, ++ "Current": { ++ "Value": 6.0, ++ "LowAlarm": 0.2, ++ "HighAlarm": 7.0, ++ "Unit": "A" ++ }, ++ "Power": { ++ "Value": 1000, ++ "LowAlarm": -1, # Don't care ++ "HighAlarm": 1400, ++ "Unit": "W" ++ } ++ } ++ } ++ """ ++ psu = self.chas.get_psu_byname(psu_name) ++ if psu is None: ++ return -1 ++ if psu.get_threshold_by_model == 1: ++ psu.get_fru_info() ++ dic = collections.OrderedDict() ++ inputdic = collections.OrderedDict() ++ Outputsdic = collections.OrderedDict() ++ dic["Name"] = psu.name ++ inputdic["Status"] = psu.InputStatus ++ inputdic["Type"] = psu.InputsType ++ ++ # psu.get_InputsVoltage() ++ inputdic_voltage = collections.OrderedDict() ++ ++ inputdic_voltage["Value"] = psu.InputsVoltage.Value ++ inputdic_voltage["LowAlarm"] = psu.InputsVoltage.Min ++ inputdic_voltage["HighAlarm"] = psu.InputsVoltage.Max ++ inputdic_voltage["Unit"] = psu.InputsVoltage.Unit ++ ++ inputdic["Voltage"] = inputdic_voltage ++ inputdic_current = collections.OrderedDict() ++ inputdic_current["Value"] = psu.InputsCurrent.Value ++ inputdic_current["LowAlarm"] = psu.InputsCurrent.Min ++ inputdic_current["HighAlarm"] = psu.InputsCurrent.Max ++ inputdic_current["Unit"] = psu.InputsCurrent.Unit ++ inputdic["Current"] = inputdic_current ++ ++ inputdic_power = collections.OrderedDict() ++ inputdic_power["Value"] = psu.InputsPower.Value ++ inputdic_power["LowAlarm"] = psu.InputsPower.Min ++ inputdic_power["HighAlarm"] = psu.InputsPower.Max ++ inputdic_power["Unit"] = psu.InputsPower.Unit ++ inputdic["Power"] = inputdic_power ++ Outputsdic["Status"] = psu.InputStatus ++ ++ outputdic_voltage = collections.OrderedDict() ++ outputdic_current = collections.OrderedDict() ++ outputdic_power = collections.OrderedDict() ++ ++ outputdic_voltage["Value"] = psu.OutputsVoltage.Value ++ outputdic_voltage["LowAlarm"] = psu.OutputsVoltage.Min ++ outputdic_voltage["HighAlarm"] = psu.OutputsVoltage.Max ++ outputdic_voltage["Unit"] = psu.OutputsVoltage.Unit ++ ++ outputdic_current["Value"] = psu.OutputsCurrent.Value ++ outputdic_current["LowAlarm"] = psu.OutputsCurrent.Min ++ outputdic_current["HighAlarm"] = psu.OutputsCurrent.Max ++ outputdic_current["Unit"] = psu.OutputsCurrent.Unit ++ ++ outputdic_power["Value"] = psu.OutputsPower.Value ++ outputdic_power["LowAlarm"] = psu.OutputsPower.Min ++ outputdic_power["HighAlarm"] = psu.OutputsPower.Max ++ outputdic_power["Unit"] = psu.OutputsPower.Unit ++ ++ Outputsdic["Voltage"] = outputdic_voltage ++ Outputsdic["Current"] = outputdic_current ++ Outputsdic["Power"] = outputdic_power ++ ++ dic["Inputs"] = inputdic ++ dic["Outputs"] = Outputsdic ++ ++ return dic ++ ++ def set_psu_fan_speed_pwm(self, psu_name, pwm): ++ psu = self.chas.get_psu_byname(psu_name) ++ if psu is None: ++ return -1 ++ return psu.set_fan_speed_pwm(pwm) ++ ++ def get_psu_fan_speed_pwm(self, psu_name): ++ psu = self.chas.get_psu_byname(psu_name) ++ if psu is None: ++ return -1 ++ return psu.get_fan_speed_pwm() ++ ++ def get_psu_info_all(self): ++ """ ++ { ++ "Number": 2, ++ "PSU1": { ++ "SN": "serial_number_example", # 'N/A' ++ "PN": "part_number_example", # 'N/A' ++ "AirFlow": "intake", # 'N/A' ++ ++ "FanSpeed": { ++ "Value": 4000, ++ "Min": 2000, ++ "Max": 30000 ++ }, ++ "Temperature": { ++ "Value": 35.0, ++ "Min": -20.0, ++ "Max": 45.0 ++ }, ++ "Inputs": { ++ "Status": True, # H/W status bit ++ "Type": "DC", # or "AC" ++ "Voltage": { ++ "Value": 220, ++ "LowAlarm": 200, ++ "HighAlarm": 240, ++ "Unit": "V" ++ }, ++ "Current": { ++ "Value": 6.0, ++ "LowAlarm": 0.2, ++ "HighAlarm": 7.0, ++ "Unit": "A" ++ }, ++ "Power": { ++ "Value": 1000, ++ "LowAlarm": -1, ++ "HighAlarm": 1400, ++ "Unit": "W" ++ } ++ }, ++ "Outputs": { ++ "Status": True, ++ "Voltage": { ++ "Value": 220, ++ "LowAlarm": 200, ++ "HighAlarm": 240, ++ "Unit": "V" ++ }, ++ "Current": { ++ "Value": 6.0, ++ "LowAlarm": 0.2, ++ "HighAlarm": 7.0, ++ "Unit": "A" ++ }, ++ "Power": { ++ "Value": 1000, ++ "LowAlarm": -1, # Don't care ++ "HighAlarm": 1400, ++ "Unit": "W" ++ } ++ } ++ } ++ } ++ """ ++ ++ psus = self.get_psus() ++ psu_dict = collections.OrderedDict() ++ psu_dict['Number'] = len(psus) ++ for psu in psus: ++ dicttmp = self.get_psu_fru_info(psu.name) ++ dicttmp.update(self.get_psu_status(psu.name)) ++ dicttmp.update(self.get_psu_power_status(psu.name)) ++ if self.get_psu_presence(psu.name) is True: ++ dicttmp['Present'] = 'yes' ++ else: ++ dicttmp['Present'] = 'no' ++ psu_dict[psu.name] = dicttmp ++ return psu_dict ++ ++ def get_fans(self): ++ fanlist = self.chas.fan_list ++ return fanlist ++ ++ # fan ++ def get_fan_total_number(self): ++ fanlist = self.chas.fan_list ++ if fanlist is None: ++ return -1 ++ return len(fanlist) ++ ++ def get_fan_rotor_number(self, fan_name): ++ fan = self.chas.get_fan_byname(fan_name) ++ if fan is None: ++ return -1 ++ ret = fan.rotors ++ if ret is None: ++ return -1 ++ return ret ++ ++ def get_fan_speed(self, fan_name, rotor_index): ++ fan = self.chas.get_fan_byname(fan_name) ++ if fan is None: ++ return -1 ++ ret = fan.get_speed(rotor_index) ++ if ret is None: ++ return -1 ++ return ret ++ ++ def fan_speed_set_level(self, fan_name, rotor_index, level): ++ fan = self.chas.get_fan_byname(fan_name) ++ if fan is None: ++ return -1 ++ ret = fan.set_speed(rotor_index, level) ++ if ret is True: ++ return 0 ++ return -1 ++ ++ def get_fan_speed_pwm(self, fan_name, rotor_index): ++ fan = self.chas.get_fan_byname(fan_name) ++ if fan is None: ++ return -1 ++ val = fan.get_speed_pwm(rotor_index) ++ if val is False: ++ return -1 ++ return val ++ ++ def set_fan_speed_pwm(self, fan_name, rotor_index, pwm): ++ fan = self.chas.get_fan_byname(fan_name) ++ if fan is None: ++ return -1 ++ if isinstance(pwm, str): ++ rate = float(pwm.strip('%s')) ++ speed = round(rate * 255 / 100) ++ elif isinstance(pwm, int): ++ speed = round(pwm * 255 / 100) ++ elif isinstance(pwm, float): ++ speed = round(pwm * 255 / 100) ++ else: ++ return -1 ++ ret = self.fan_speed_set_level(fan.name, rotor_index, speed) ++ if ret == 0: ++ return 0 ++ return -1 ++ ++ def get_fan_watchdog_status(self): ++ fan = self.chas.fan_list[0] ++ dic = fan.get_watchdog_status() ++ if dic is None or dic["support"] is False: ++ return self.na_ret ++ if dic["open"] is False or dic["work_allow_set"] is True: ++ return "Normal" ++ if dic["work_full"] is True: ++ return "Abnormal" ++ return "Abnormal" ++ ++ def enable_fan_watchdog(self, enable=True): ++ fan = self.chas.fan_list[0] ++ ret = fan.enable_watchdog(enable) ++ if ret is True: ++ return 0 ++ return -1 ++ ++ def feed_fan_watchdog(self): ++ fan_list = self.chas.fan_list ++ if fan_list is None: ++ return -1 ++ for fan in fan_list: ++ ret = fan.feed_watchdog() ++ if ret is False: ++ return -1 ++ return 0 ++ ++ def set_fan_led(self, fan_name, color): ++ fan = self.chas.get_fan_byname(fan_name) ++ if fan is None: ++ return -1 ++ ret = fan.set_led(color) ++ if ret is True: ++ return 0 ++ return -1 ++ ++ def get_fan_led(self, fan_name): ++ fan = self.chas.get_fan_byname(fan_name) ++ if fan is None: ++ return False, 'N/A' ++ return fan.get_led() ++ ++ def get_fan_presence(self, fan_name): ++ fan = self.chas.get_fan_byname(fan_name) ++ if fan is None: ++ return -1 ++ return fan.get_presence() ++ ++ def get_fan_fru_info(self, fan_name): ++ """ ++ Get specific fan's information ++ # Properties ++ "Name": "FAN1", ++ "SN": "serial_number_example", # 'N/A' ++ "PN": "part_number_exampple", # 'N/A' ++ "Rotors": 2, # -1 ++ "AirFlow": "intake", # 'N/A' ++ "SpeedMin": 2000, # -1 ++ "SpeedMax": 30000 # -1 ++ """ ++ fan = self.chas.get_fan_byname(fan_name) ++ fan.decode_eeprom_info() ++ fan.get_AirFlow() ++ fan.get_fan_display_name() ++ ++ dic = collections.OrderedDict() ++ dic["Name"] = fan.name ++ dic["SN"] = fan.productSerialNumber ++ if dic["SN"] is None: ++ dic["SN"] = self.na_ret ++ dic["PN"] = fan.productName ++ if dic["PN"] is None: ++ dic["PN"] = self.na_ret ++ dic["DisplayName"] = fan.fan_display_name ++ if dic["DisplayName"] is None: ++ dic["DisplayName"] = self.na_ret ++ ++ dic["Rotors"] = fan.rotors ++ dic["AirFlow"] = fan.AirFlow ++ if dic["AirFlow"] is None: ++ dic["AirFlow"] = self.na_ret ++ dic["SpeedMin"] = fan.SpeedMin ++ dic["SpeedMax"] = fan.SpeedMax ++ return dic ++ ++ def get_fan_eeprom_info(self, fan_name): ++ """ ++ Get specific fan's information ++ # Properties ++ "Name": "M6510-FAN-F", # 'N/A' ++ "SN": "serial_number_example", # 'N/A' ++ "HW": "hw_version_exampple", # 'N/A' ++ """ ++ fan = self.chas.get_fan_byname(fan_name) ++ fan.decode_eeprom_info() ++ fan.get_fan_display_name() ++ dic = collections.OrderedDict() ++ dic["NAME"] = fan.productName ++ if dic["NAME"] is None: ++ dic["NAME"] = self.na_ret ++ dic["SN"] = fan.productSerialNumber ++ if dic["SN"] is None: ++ dic["SN"] = self.na_ret ++ dic["HW"] = fan.hw_version ++ if dic["HW"] is None: ++ dic["HW"] = self.na_ret ++ dic["DisplayName"] = fan.fan_display_name ++ if dic["DisplayName"] is None: ++ dic["DisplayName"] = self.na_ret ++ return dic ++ ++ def get_product_fullname(self): ++ return baseutil.get_product_fullname() ++ ++ def get_fan_status(self, fan_name): ++ fan = self.chas.get_fan_byname(fan_name) ++ if fan is None: ++ return -1 ++ rotorlist = fan.rotor_list ++ dic = collections.OrderedDict() ++ for rotor in rotorlist: ++ dic_val = collections.OrderedDict() ++ if rotor.rotor_Running is True: ++ dic_val['Running'] = 'yes' ++ else: ++ dic_val['Running'] = 'no' ++ if rotor.rotor_HwAlarm is True: ++ dic_val['HwAlarm'] = 'yes' ++ else: ++ dic_val['HwAlarm'] = 'no' ++ dic_val['Speed'] = int(rotor.rotor_Speed.Value) ++ dic[rotor.name] = dic_val ++ return dic ++ ++ def get_fan_rotor_status(self, fan_name, rotor_name): ++ fan = self.chas.get_fan_byname(fan_name) ++ if fan is None: ++ return -1 ++ rotorlist = fan.rotor_list ++ for rotor in rotorlist: ++ if rotor_name == rotor.name: ++ if rotor.rotor_Running is True: ++ return True ++ return False ++ return -1 ++ ++ def get_fan_roll_status(self, fan_name, rotor_index): ++ fan = self.chas.get_fan_byname(fan_name) ++ if fan is None: ++ return -1 ++ rotor = fan.get_rotor_index(rotor_index) ++ if rotor is None: ++ return -1 ++ if rotor.rotor_Running is True: ++ return True ++ return False ++ ++ def get_fan_info_fru(self, fan_name): ++ fan = self.chas.get_fan_byname(fan_name) ++ fan.get_fru_info() ++ fan.get_AirFlow() ++ dic = collections.OrderedDict() ++ dic["Name"] = fan.name ++ dic["SN"] = fan.productSerialNumber ++ if dic["SN"] is None: ++ dic["SN"] = self.na_ret ++ dic["PN"] = fan.productPartModelName ++ if dic["PN"] is None: ++ dic["PN"] = self.na_ret ++ flag = self.get_fan_presence(fan_name) ++ if flag is True: ++ dic["Present"] = "yes" ++ elif flag is False: ++ dic["Present"] = "no" ++ else: ++ dic["Present"] = self.na_ret ++ dic["Rotors"] = fan.rotors ++ dic["AirFlow"] = fan.AirFlow ++ if dic["AirFlow"] is None: ++ dic["AirFlow"] = self.na_ret ++ return dic ++ ++ # support TLV and FRU FAN E2 ++ def get_fan_info(self, fan_name): ++ fan = self.chas.get_fan_byname(fan_name) ++ if fan is None: ++ return None ++ fan.get_AirFlow() ++ dic = self.get_fan_eeprom_info(fan_name) ++ flag = self.get_fan_presence(fan_name) ++ if flag is True: ++ dic["Present"] = "yes" ++ elif flag is False: ++ dic["Present"] = "no" ++ else: ++ dic["Present"] = self.na_ret ++ dic["Rotors"] = fan.rotors ++ dic["AirFlow"] = fan.AirFlow ++ if dic["AirFlow"] is None: ++ dic["AirFlow"] = self.na_ret ++ dic["PowerMax"] = fan.PowerMax ++ if dic["PowerMax"] is None: ++ dic["PowerMax"] = self.na_ret ++ return dic ++ ++ def get_fan_info_rotor(self, fan_name): ++ fan = self.chas.get_fan_byname(fan_name) ++ if fan is None: ++ return -1 ++ rotorlist = fan.rotor_list ++ dic = collections.OrderedDict() ++ for rotor in rotorlist: ++ dic_val = collections.OrderedDict() ++ if rotor.rotor_Running is True: ++ dic_val['Running'] = 'yes' ++ else: ++ dic_val['Running'] = 'no' ++ if rotor.rotor_HwAlarm is True: ++ dic_val['HwAlarm'] = 'yes' ++ else: ++ dic_val['HwAlarm'] = 'no' ++ speed_value = rotor.rotor_Speed.Value ++ if speed_value is None: ++ dic_val['Speed'] = self.error_ret ++ else: ++ dic_val['Speed'] = int(speed_value) ++ if rotor.SpeedMin is None: ++ dic_val['SpeedMin'] = self.error_ret ++ else: ++ dic_val['SpeedMin'] = rotor.SpeedMin ++ if rotor.SpeedMax is None: ++ dic_val['SpeedMax'] = self.error_ret ++ else: ++ dic_val['SpeedMax'] = rotor.SpeedMax ++ if rotor.Tolerance is None: ++ dic_val['Tolerance'] = self.error_ret ++ else: ++ dic_val['Tolerance'] = rotor.Tolerance ++ ++ dic[rotor.name] = dic_val ++ return dic ++ ++ def get_fan_info_all(self): ++ fanlist = self.chas.fan_list ++ dic = collections.OrderedDict() ++ dic['Number'] = len(fanlist) ++ dic['WatchdogStatus'] = self.get_fan_watchdog_status() ++ for fan in fanlist: ++ dic[fan.name] = self.get_fan_info(fan.name) ++ dic[fan.name].update(self.get_fan_info_rotor(fan.name)) ++ return dic ++ ++ def temp_test(self): ++ templist = self.chas.temp_list ++ dicret = collections.OrderedDict() ++ ++ for temp in templist: ++ dic = collections.OrderedDict() ++ temp_value = temp.Value ++ dic["Value"] = temp_value if (temp_value is not None) else self.error_ret ++ dic["LowAlarm"] = temp.Min ++ dic["HighAlarm"] = temp.Max ++ dicret[temp.name] = dic ++ return dicret ++ ++ # dcdc ++ def get_dcdc_total_number(self): ++ dcdclist = self.chas.dcdc_list ++ if dcdclist is None: ++ return -1 ++ return len(dcdclist) ++ ++ def get_dcdc_by_id(self, dcdc_id): ++ dcdclist = self.chas.dcdc_list ++ dcdctmp = None ++ for dcdc in dcdclist: ++ if dcdc.dcdc_id == dcdc_id: ++ dcdctmp = dcdc ++ dic = collections.OrderedDict() ++ if dcdctmp is None: ++ dic["Name"] = self.error_ret ++ dic["Min"] = self.error_ret ++ dic["Max"] = self.error_ret ++ dic["Low"] = self.error_ret ++ dic["High"] = self.error_ret ++ dic["Value"] = self.error_ret ++ dic["Unit"] = self.error_ret ++ else: ++ dic["Name"] = dcdctmp.name ++ dic["Min"] = dcdctmp.sensor.Min ++ dic["Max"] = dcdctmp.sensor.Max ++ dic["Low"] = dcdctmp.sensor.Low ++ dic["High"] = dcdctmp.sensor.High ++ tmp = dcdctmp.sensor.Value ++ if tmp is not None: ++ dic['Value'] = tmp ++ else: ++ dic['Value'] = self.error_ret ++ dic["Unit"] = dcdctmp.sensor.Unit ++ return dic ++ ++ def get_dcdc_all_info(self): ++ val_list = collections.OrderedDict() ++ dcdclist = self.chas.dcdc_list ++ for dcdc in dcdclist: ++ dicttmp = {} ++ sensorname = "%s" % (dcdc.name) ++ dicttmp['Min'] = dcdc.sensor.Min ++ dicttmp['Max'] = dcdc.sensor.Max ++ tmp = dcdc.sensor.Value ++ if tmp is not None: ++ dicttmp['Value'] = tmp ++ else: ++ dicttmp['Value'] = self.error_ret ++ dicttmp['Unit'] = dcdc.sensor.Unit ++ val_list[sensorname] = dicttmp ++ return val_list ++ ++ # sensors ++ def get_monitor_temp(self, name): ++ templist = self.chas.temp_list ++ temptmp = None ++ for temp in templist: ++ if temp.name == name: ++ temptmp = temp ++ ++ dic = collections.OrderedDict() ++ if temptmp is None: ++ dic["Min"] = self.error_ret ++ dic["Max"] = self.error_ret ++ dic["Value"] = self.error_ret ++ dic["Unit"] = self.error_ret ++ else: ++ dic["Min"] = temptmp.Min ++ dic["Max"] = temptmp.Max ++ temp_value = temptmp.Value ++ dic["Value"] = temp_value if (temp_value is not None) else self.error_ret ++ dic["Unit"] = temptmp.Unit ++ return dic ++ ++ def get_monitor_temp_by_id(self, temp_id): ++ templist = self.chas.temp_list ++ temptmp = None ++ for temp in templist: ++ if temp.temp_id == temp_id: ++ temptmp = temp ++ ++ dic = collections.OrderedDict() ++ if temptmp is None: ++ dic["Name"] = self.error_ret ++ dic["Api_name"] = self.error_ret ++ dic["Min"] = self.error_ret ++ dic["Max"] = self.error_ret ++ dic["Low"] = self.error_ret ++ dic["High"] = self.error_ret ++ dic["Value"] = self.error_ret ++ dic["Unit"] = self.error_ret ++ else: ++ dic["Name"] = temptmp.name ++ dic["Api_name"] = temptmp.api_name ++ dic["Min"] = temptmp.Min ++ dic["Max"] = temptmp.Max ++ dic["Low"] = temptmp.Low ++ dic["High"] = temptmp.High ++ temp_value = temptmp.Value ++ dic["Value"] = temp_value if (temp_value is not None) else self.error_ret ++ dic["Unit"] = temptmp.Unit ++ return dic ++ ++ def get_temp_info(self): ++ val_list = collections.OrderedDict() ++ # temp ++ templist = self.chas.temp_list ++ for temp in templist: ++ dic = collections.OrderedDict() ++ dic["Min"] = temp.Min ++ dic["Max"] = temp.Max ++ dic["Low"] = temp.Low ++ dic["High"] = temp.High ++ temp_value = temp.Value ++ dic["Value"] = temp_value if (temp_value is not None) else self.error_ret ++ dic["Unit"] = temp.Unit ++ val_list[temp.name] = dic ++ return val_list ++ ++ def get_sensor_info(self): ++ val_list = collections.OrderedDict() ++ # temp ++ templist = self.chas.temp_list ++ for temp in templist: ++ dic = collections.OrderedDict() ++ dic["Min"] = temp.Min ++ dic["Max"] = temp.Max ++ dic["Low"] = temp.Low ++ dic["High"] = temp.High ++ temp_value = temp.Value ++ dic["Value"] = temp_value if (temp_value is not None) else self.error_ret ++ dic["Unit"] = temp.Unit ++ val_list[temp.name] = dic ++ # fan ++ fanlist = self.chas.fan_list ++ for fan in fanlist: ++ for rotor in fan.rotor_list: ++ sensorname = "%s%s" % (fan.name, rotor.name) ++ speed = collections.OrderedDict() ++ speed['Min'] = rotor.rotor_Speed.Min ++ speed['Max'] = rotor.rotor_Speed.Max ++ rotor_speed_Value = rotor.rotor_Speed.Value ++ speed['Value'] = rotor_speed_Value if (rotor_speed_Value is not None) else self.error_ret ++ speed['Unit'] = rotor.rotor_Speed.Unit ++ val_list[sensorname] = speed ++ ++ val_list.update(self.get_dcdc_all_info()) ++ ++ # psu ++ psulist = self.chas.psu_list ++ for psu in psulist: ++ inputdic_voltage = collections.OrderedDict() ++ inputdic_current = collections.OrderedDict() ++ inputdic_power = collections.OrderedDict() ++ outputdic_voltage = collections.OrderedDict() ++ outputdic_current = collections.OrderedDict() ++ outputdic_power = collections.OrderedDict() ++ temperature = collections.OrderedDict() ++ fanspeed = collections.OrderedDict() ++ ++ psu_temp_value = psu.Temperature.Value ++ temperature["Value"] = psu_temp_value if (psu_temp_value is not None) else self.error_ret ++ temperature["Min"] = psu.Temperature.Min ++ temperature["Max"] = psu.Temperature.Max ++ temperature["Unit"] = psu.Temperature.Unit ++ ++ fanspeed["Value"] = psu.FanSpeed.Value ++ fanspeed["Min"] = psu.FanSpeed.Min ++ fanspeed["Max"] = psu.FanSpeed.Max ++ fanspeed["Unit"] = psu.FanSpeed.Unit ++ ++ psu_inputvoltage_value = psu.InputsVoltage.Value ++ inputdic_voltage["Value"] = psu_inputvoltage_value if ( ++ psu_inputvoltage_value is not None) else self.error_ret ++ inputdic_voltage["Min"] = psu.InputsVoltage.Min ++ inputdic_voltage["Max"] = psu.InputsVoltage.Max ++ inputdic_voltage["Unit"] = psu.InputsVoltage.Unit ++ ++ psu_inputcurrent_value = psu.InputsCurrent.Value ++ inputdic_current["Value"] = psu_inputcurrent_value if ( ++ psu_inputcurrent_value is not None) else self.error_ret ++ inputdic_current["Min"] = psu.InputsCurrent.Min ++ inputdic_current["Max"] = psu.InputsCurrent.Max ++ inputdic_current["Unit"] = psu.InputsCurrent.Unit ++ ++ psu_inputpower_value = psu.InputsPower.Value ++ inputdic_power["Value"] = psu_inputpower_value if (psu_inputpower_value is not None) else self.error_ret ++ inputdic_power["Min"] = psu.InputsPower.Min ++ inputdic_power["Max"] = psu.InputsPower.Max ++ inputdic_power["Unit"] = psu.InputsPower.Unit ++ ++ psu_outputvoltage_value = psu.OutputsVoltage.Value ++ outputdic_voltage["Value"] = psu_outputvoltage_value if ( ++ psu_outputvoltage_value is not None) else self.error_ret ++ outputdic_voltage["Min"] = psu.OutputsVoltage.Min ++ outputdic_voltage["Max"] = psu.OutputsVoltage.Max ++ outputdic_voltage["Unit"] = psu.OutputsVoltage.Unit ++ ++ psu_outputcurrent_value = psu.OutputsCurrent.Value ++ outputdic_current["Value"] = psu_outputcurrent_value if ( ++ psu_outputcurrent_value is not None) else self.error_ret ++ outputdic_current["Min"] = psu.OutputsCurrent.Min ++ outputdic_current["Max"] = psu.OutputsCurrent.Max ++ outputdic_current["Unit"] = psu.OutputsCurrent.Unit ++ ++ psu_outputpower_value = psu.OutputsPower.Value ++ outputdic_power["Value"] = psu_outputpower_value if ( ++ psu_outputpower_value is not None) else self.error_ret ++ outputdic_power["Min"] = psu.OutputsPower.Min ++ outputdic_power["Max"] = psu.OutputsPower.Max ++ outputdic_power["Unit"] = psu.OutputsPower.Unit ++ ++ val_list["%s%s" % (psu.name, "Vol_I")] = inputdic_voltage ++ val_list["%s%s" % (psu.name, "Curr_I")] = inputdic_current ++ val_list["%s%s" % (psu.name, "Power_I")] = inputdic_power ++ val_list["%s%s" % (psu.name, "Vol_O")] = outputdic_voltage ++ val_list["%s%s" % (psu.name, "Curr_O")] = outputdic_current ++ val_list["%s%s" % (psu.name, "Power_O")] = outputdic_power ++ val_list["%s%s" % (psu.name, "Fan")] = fanspeed ++ val_list["%s%s" % (psu.name, "Temp")] = temperature ++ ++ return val_list ++ ++ # cpld ++ def get_cpld_total_number(self): ++ cpldlist = self.chas.cpld_list ++ return len(cpldlist) ++ ++ def get_cpld_user_reg(self): ++ cpld = self.chas.get_cpld_byname("BASE_CPLD") ++ if cpld is None: ++ return None ++ return cpld.get_user_reg() ++ ++ def set_cpld_user_reg(self, value): ++ if isinstance(value, int) is False: ++ baseutil.logger_debug("value must int %s" % type(value)) ++ return -1 ++ if (int(value) < 0 or int(value) > 255): ++ baseutil.logger_debug("value must [0 - 255]") ++ return -1 ++ cpld = self.chas.get_cpld_byname("BASE_CPLD") ++ if cpld is None: ++ baseutil.logger_debug("name BASE_CPLD not find") ++ return -1 ++ if cpld.set_user_reg(value) is True: ++ return 0 ++ return -1 ++ ++ def set_cpld_console_owner(self, owner): ++ """ ++ Set console I/O owner ++ ++ @param owner I/O owner of the console, either "cpu" or "bmc" ++ ++ @return 0 for success, -1 for failure ++ """ ++ if owner is None: ++ baseutil.logger_debug("owner is None") ++ return -1 ++ owner_tuple = ("cpu", "bmc") ++ if owner not in owner_tuple: ++ baseutil.logger_debug("owner is %s, must cpu or bmc" % owner) ++ return -1 ++ cpld = self.chas.get_cpld_byname("BASE_CPLD") ++ if cpld is None: ++ baseutil.logger_debug("name BASE_CPLD not find") ++ return -1 ++ if cpld.set_console_owner(owner) is True: ++ return 0 ++ return -1 ++ ++ def get_cpld_version_by_id(self, cpld_id): ++ cpldlist = self.chas.cpld_list ++ cpldtmp = None ++ for cpld in cpldlist: ++ if cpld.cpld_id == cpld_id: ++ cpldtmp = cpld ++ ++ dic = collections.OrderedDict() ++ if cpldtmp is None: ++ dic["Name"] = self.na_ret ++ dic["Version"] = self.na_ret ++ dic["Desc"] = self.na_ret ++ dic["Slot"] = None ++ dic["Warm"] = None ++ else: ++ dic["Name"] = cpldtmp.name ++ dic["Version"] = cpldtmp.get_version() ++ dic["Desc"] = cpldtmp.desc ++ dic["Slot"] = cpldtmp.slot ++ dic["Warm"] = cpldtmp.warm ++ return dic ++ ++ def get_cpld_all_version(self): ++ """ ++ Get version of all CPLDs' that can be read from BMC ++ ++ @return dict of CPLDs' version or None for failure. ++ example outputs: ++ { ++ "BASE_CPLD": "0.1", # or "N/A" for read failure ++ "FAN_CPLD": "0.2" ++ } ++ """ ++ cpld_version = { ++ "BASE_CPLD": "N/A", ++ "FAN_CPLD": "N/A" ++ } ++ for cpld_name in cpld_version: ++ cpld = self.chas.get_cpld_byname(cpld_name) ++ if cpld is None: ++ baseutil.logger_debug("name %s not find" % cpld_name) ++ continue ++ cpld_version[cpld_name] = cpld.get_version() ++ return cpld_version ++ ++ # comp ++ def get_comp_total_number(self): ++ complist = self.chas.comp_list ++ return len(complist) ++ ++ def get_comp_list(self): ++ return self.chas.comp_list ++ ++ def get_comp_id(self, comp): ++ return comp.comp_id ++ ++ def get_comp_version_by_id(self, comp_id): ++ comp_list = self.chas.comp_list ++ comptmp = None ++ for comp in comp_list: ++ if comp.comp_id == comp_id: ++ comptmp = comp ++ break ++ ++ dic = collections.OrderedDict() ++ if comptmp is None: ++ dic["Name"] = self.na_ret ++ dic["Version"] = self.na_ret ++ dic["Desc"] = self.na_ret ++ dic["Slot"] = None ++ else: ++ dic["Name"] = comptmp.name ++ dic["Version"] = comptmp.get_version() ++ dic["Desc"] = comptmp.desc ++ dic["Slot"] = comptmp.slot ++ return dic ++ ++ def get_bmc_productname(self): ++ """ ++ Get product name ++ ++ @return product name string, e.g. $(device name)-F-$(VENDOR_NAME), if error return "N/A" ++ """ ++ bmc = self.chas.get_bmc_byname("master") ++ if bmc is None: ++ baseutil.logger_debug("name bmc(master) not find") ++ return self.na_ret ++ return bmc.get_productname() ++ ++ def call_bmc_diagcmd(self, cmdstr): ++ """ ++ Call BMC diag comman func ++ ++ @return ret: 0 sucess , -1 fail ++ outmsg: if success is out msg, or fail is err msg ++ """ ++ if (cmdstr is None or cmdstr == ""): ++ outmsg = "cmdstr is empty" ++ baseutil.logger_debug(outmsg) ++ return -1, outmsg ++ bmc = self.chas.get_bmc_byname("master") ++ if bmc is None: ++ outmsg = "name bmc(master) not find" ++ baseutil.logger_debug(outmsg) ++ return -1, outmsg ++ baseutil.logger_debug("call cmdstr %s" % cmdstr) ++ return bmc.call_diagcmd(cmdstr) ++ ++ def write_bios_version(self, flash, version): ++ bios = self.chas.get_bios_byname("master") ++ if bios is None: ++ baseutil.logger_debug("name bios(master) not find") ++ return -1 ++ return bios.set_bios_version(flash, version) ++ ++ def get_bios_version(self): ++ bios = self.chas.get_bios_byname("master") ++ if bios is None: ++ baseutil.logger_debug("name bios(master) not find") ++ return -1 ++ return bios.get_bios_version() ++ ++ def get_bios_status(self): ++ bios = self.chas.get_bios_byname("master") ++ if bios is None: ++ baseutil.logger_debug("name bios(master) not find") ++ return -1 ++ return bios.get_bios_boot_status() ++ ++ def get_bmc_mac_rov(self): ++ """ ++ Get BMC mac rov ++ ++ @return ret: 0 sucess , -1 fail ++ outmsg: if success is out msg, or fail is err msg ++ """ ++ bmc = self.chas.get_bmc_byname("master") ++ if bmc is None: ++ msg = "name master not find" ++ baseutil.logger_debug(msg) ++ return -1, msg ++ return bmc.get_mac_rov() ++ ++ def get_bmc_next_boot(self): ++ """ ++ Get next booting flash of BMC ++ ++ @return 'master'/'slave' on success, "N/A" for failure ++ """ ++ bmc = self.chas.get_bmc_byname("master") ++ if bmc is None: ++ baseutil.logger_debug("name master not find") ++ return self.na_ret ++ return bmc.get_next_boot() ++ ++ def set_bmc_next_boot(self, flash): ++ """ ++ Set flash from which next BMC boot ++ ++ @param flash Booting flash of BMC, "master" or "slave" ++ ++ @return 0 on success, -1 for failure ++ """ ++ flash_status = ("master", "slave") ++ if flash is None or flash not in flash_status: ++ baseutil.logger_debug("parameter flash illegal, should be [master|slave]") ++ return -1 ++ bmc = self.chas.get_bmc_byname("master") ++ if bmc is None: ++ baseutil.logger_debug("name master not find") ++ return -1 ++ return bmc.set_next_boot(flash) ++ ++ def reboot_bmc(self): ++ """ ++ Reboot running BMC ++ """ ++ bmc = self.chas.get_bmc_byname("master") ++ if bmc is None: ++ baseutil.logger_debug("name master not find") ++ return -1 ++ return bmc.reboot() ++ ++ def get_bmc_info(self): ++ """ ++ Get BMC info ++ ++ @return dict of BMC info or None for failure ++ "Version": "1.1.1", # "N/A" ++ "Flash": "master", # "N/A" ++ "Next": "master" # "N/A" ++ """ ++ bmc = self.chas.get_bmc_byname("master") ++ if bmc is None: ++ baseutil.logger_debug("name master not find") ++ return self.na_ret ++ return bmc.get_info() ++ ++ def get_bmc_version_all(self): ++ """ ++ @return dict of BMCs ++ { ++ "MasterVersion": "1.1.1", # "N/A" ++ "SlaveVersion": "1.1.1" # "N/A" ++ } ++ """ ++ bmc = self.chas.get_bmc_byname("master") ++ if bmc is None: ++ baseutil.logger_debug("name master not find") ++ return self.na_ret ++ return bmc.get_version_all() ++ ++ def bmc_execute_command(self, cmd_str): ++ ret, output = osutil.command(cmd_str) ++ if ret: ++ baseutil.logger_debug("execute %s command failed" % (cmd_str)) ++ return ret, output ++ ++ def get_cpu_reset_num(self): ++ """ ++ Get CPU reset num ++ @return CPU reset num on success, -1 for failure ++ """ ++ cpu = self.chas.get_cpu_byname("cpu") ++ if cpu is None: ++ msg = "name cpu not find" ++ baseutil.logger_debug(msg) ++ return -1 ++ return cpu.get_cpu_reset_num() ++ ++ def get_cpu_reboot_cause(self): ++ """ ++ Get CPU reboot cause ++ @return string of cpu reboot reason ++ """ ++ cpu = self.chas.get_cpu_byname("cpu") ++ if cpu is None: ++ msg = "name cpu not find" ++ baseutil.logger_debug(msg) ++ return "Unknown reboot cause" ++ return cpu.get_cpu_reboot_cause() ++ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/led.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/led.py +new file mode 100644 +index 000000000..7fb869c74 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/led.py +@@ -0,0 +1,52 @@ ++#!/usr/bin/env python3 ++####################################################### ++# ++# led.py ++# Python implementation of the Class led ++# ++####################################################### ++from plat_hal.devicebase import devicebase ++ ++ ++class led(devicebase): ++ def __init__(self, conf=None): ++ if conf is not None: ++ self.name = conf.get('name', None) ++ self.led_type = conf.get('led_type', None) ++ self.led_attrs_config = conf.get('led_attrs', None) ++ self.led_config = conf.get('led', None) ++ ++ def set_color(self, color): ++ status = self.led_attrs_config.get(color, None) ++ if status is None: ++ return False ++ ++ mask = self.led_attrs_config.get('mask', 0xff) ++ ++ if isinstance(self.led_config, list): ++ for led_config_index in self.led_config: ++ ret, value = self.get_value(led_config_index) ++ if (ret is False) or (value is None): ++ return False ++ setval = (int(value) & ~mask) | (status) ++ ret, val = self.set_value(led_config_index, setval) ++ if ret is False: ++ return ret ++ else: ++ ret, value = self.get_value(self.led_config) ++ if (ret is False) or (value is None): ++ return False ++ setval = (int(value) & ~mask) | (status) ++ ret, val = self.set_value(self.led_config, setval) ++ return ret ++ ++ def get_color(self): ++ mask = self.led_attrs_config.get('mask', 0xff) ++ ret, value = self.get_value(self.led_config) ++ if ret is False or value is None: ++ return False, 'N/A' ++ ledval = int(value) & mask ++ for key, val in self.led_attrs_config.items(): ++ if (ledval == val) and (key != "mask"): ++ return True, key ++ return False, 'N/A' +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/onie_e2.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/onie_e2.py +new file mode 100644 +index 000000000..9ac32cace +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/onie_e2.py +@@ -0,0 +1,127 @@ ++#!/usr/bin/env python3 ++####################################################### ++# ++# onie_e2.py ++# Python implementation of the Class onie_e2 ++# ++####################################################### ++from plat_hal.devicebase import devicebase ++from eepromutil.onietlv import onie_tlv ++ ++ ++class onie_e2(devicebase): ++ ++ def __init__(self, conf=None): ++ self._cardid = "" ++ self._productname = "" ++ self._partnum = "" ++ self._serialnum = "" ++ self._macbase = "" ++ self._manufdate = "" ++ self._deviceversion = "" ++ self._labelrevision = "" ++ self._platformname = "" ++ self._onieversion = "" ++ self._macsize = "" ++ self._manufname = "" ++ self._manufcountry = "" ++ self._vendorname = "" ++ self._diagname = "" ++ self._servicetag = "" ++ ++ if conf is not None: ++ self.name = conf.get('name', None) ++ self.e2loc = conf.get('e2loc', None) ++ self.e2_path = self.e2loc.get('loc', None) ++ self.airflow = conf.get('airflow', "intake") ++ ++ @property ++ def cardid(self): ++ return self._cardid ++ ++ @property ++ def productname(self): ++ return self._productname ++ ++ @property ++ def partnum(self): ++ return self._partnum ++ ++ @property ++ def serialnum(self): ++ return self._serialnum ++ ++ @property ++ def macbase(self): ++ return self._macbase ++ ++ @property ++ def manufdate(self): ++ return self._manufdate ++ ++ @property ++ def deviceversion(self): ++ return self._deviceversion ++ ++ @property ++ def labelrevision(self): ++ return self._labelrevision ++ ++ @property ++ def platformname(self): ++ return self._platformname ++ ++ @property ++ def onieversion(self): ++ return self._onieversion ++ ++ @property ++ def macsize(self): ++ return self._macsize ++ ++ @property ++ def manufname(self): ++ return self._manufname ++ ++ @property ++ def manufcountry(self): ++ return self._manufcountry ++ ++ @property ++ def vendorname(self): ++ return self._vendorname ++ ++ @property ++ def diagname(self): ++ return self._diagname ++ ++ @property ++ def servicetag(self): ++ return self._servicetag ++ ++ def get_onie_e2_info(self): ++ try: ++ eeprom = self.get_eeprom_info(self.e2loc) ++ if eeprom is None: ++ raise Exception("%s: value is none" % self.name) ++ onietlv = onie_tlv() ++ onietlv.decode(eeprom) ++ self._cardid = onietlv.cardid ++ self._productname = onietlv.productname ++ self._partnum = onietlv.partnum ++ self._serialnum = onietlv.serialnum ++ self._macbase = onietlv.macbase ++ self._manufdate = onietlv.manufdate ++ self._deviceversion = onietlv.deviceversion ++ self._labelrevision = onietlv.labelrevision ++ self._platformname = onietlv.platformname ++ self._onieversion = onietlv.onieversion ++ self._macsize = onietlv.macsize ++ self._manufname = onietlv.manufname ++ self._manufcountry = onietlv.manufcountry ++ self._vendorname = onietlv.vendorname ++ self._diagname = onietlv.diagname ++ self._servicetag = onietlv.servicetag ++ except Exception: ++ return False ++ return True +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/osutil.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/osutil.py +new file mode 100644 +index 000000000..684e26bb9 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/osutil.py +@@ -0,0 +1,440 @@ ++#!/usr/bin/env python3 ++####################################################### ++# ++# osutil.py ++# Python implementation of the Class osutil ++# ++####################################################### ++ ++import os ++import glob ++import re ++import time ++import subprocess ++import fcntl ++import syslog ++from functools import wraps ++from wbutil.smbus import SMBus ++ ++ ++PLATFORM_HAL_DEBUG_FILE = "/etc/.platform_hal_debug_flag" ++ ++ ++def platform_hal_debug(s): ++ if os.path.exists(PLATFORM_HAL_DEBUG_FILE): ++ syslog.openlog("PLATFORM_HAL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def retry(maxretry=6, delay=0.01): ++ ''' ++ maxretry: max retry times ++ delay : interval after last retry ++ ''' ++ def decorator(f): ++ @wraps(f) ++ def wrapper(*args, **kwargs): ++ time_retry = maxretry ++ time_delay = delay ++ result_msg = "" ++ while time_retry: ++ try: ++ val, result_msg = f(*args, **kwargs) ++ if val is True: ++ return val, result_msg ++ time_retry -= 1 ++ time.sleep(time_delay) ++ except Exception as e: ++ time_retry -= 1 ++ result_msg = str(e) ++ time.sleep(time_delay) ++ return False, "max time retry last errmsg is {}".format(result_msg) ++ return wrapper ++ return decorator ++ ++ ++pidfile = None ++ ++ ++def file_rw_lock(file_path): ++ global pidfile ++ pidfile = open(file_path, "r") ++ try: ++ fcntl.flock(pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB) ++ platform_hal_debug("file_rw_lock success") ++ return True ++ except Exception: ++ if pidfile is not None: ++ pidfile.close() ++ pidfile = None ++ return False ++ ++ ++def file_rw_unlock(): ++ try: ++ global pidfile ++ ++ if pidfile is not None: ++ fcntl.flock(pidfile, fcntl.LOCK_UN) ++ pidfile.close() ++ pidfile = None ++ platform_hal_debug("file_rw_unlock success") ++ else: ++ platform_hal_debug("pidfile is invalid, do nothing") ++ return True ++ except Exception as e: ++ platform_hal_debug("file_rw_unlock err, msg: %s" % (str(e))) ++ return False ++ ++ ++def take_file_rw_lock(file_path): ++ loop = 1000 ++ ret = False ++ for i in range(0, loop): ++ ret = file_rw_lock(file_path) ++ if ret is True: ++ break ++ time.sleep(0.001) ++ return ret ++ ++ ++class osutil(object): ++ """ ++ osutil ++ """ ++ ++ @staticmethod ++ @retry(maxretry=6) ++ def wbi2cget_python(bus, addr, reg): ++ with SMBus(bus) as y: ++ val, ind = y.read_byte_data(addr, reg, True) ++ return val, ind ++ ++ @staticmethod ++ @retry(maxretry=6) ++ def wbi2cset_python(bus, addr, reg, value): ++ with SMBus(bus) as y: ++ val, ind = y.write_byte_data(addr, reg, value, True) ++ return val, ind ++ ++ @staticmethod ++ @retry(maxretry=6) ++ def wbi2cgetword_python(bus, addr, reg): ++ with SMBus(bus) as y: ++ val, ind = y.read_word_data(addr, reg, True) ++ return val, ind ++ ++ @staticmethod ++ @retry(maxretry=6) ++ def wbi2csetword_python(bus, addr, reg, value): ++ with SMBus(bus) as y: ++ val, ind = y.write_word_data(addr, reg, value, True) ++ return val, ind ++ ++ @staticmethod ++ @retry(maxretry=6) ++ def wbi2csetwordpec_python(bus, addr, reg, value): ++ with SMBus(bus) as y: ++ val, ind = y.write_word_data_pec(addr, reg, value, True) ++ return val, ind ++ ++ @staticmethod ++ @retry(maxretry=6) ++ def wbi2cset_byte_pec_python(bus, addr, reg, value): ++ with SMBus(bus) as y: ++ val, ind = y.write_byte_data_pec(addr, reg, value, True) ++ return val, ind ++ ++ @staticmethod ++ def command(cmdstr): ++ retcode, output = subprocess.getstatusoutput(cmdstr) ++ return retcode, output ++ ++ @staticmethod ++ def geti2cword_i2ctool(bus, addr, offset): ++ command_line = "i2cget -f -y %d 0x%02x 0x%02x wp" % (bus, addr, offset) ++ retrytime = 6 ++ ret_t = "" ++ for i in range(retrytime): ++ ret, ret_t = osutil.command(command_line) ++ if ret == 0: ++ return True, int(ret_t, 16) ++ time.sleep(0.1) ++ return False, ret_t ++ ++ @staticmethod ++ def seti2cword_i2ctool(bus, addr, offset, val): ++ command_line = "i2cset -f -y %d 0x%02x 0x%0x 0x%04x wp" % (bus, addr, offset, val) ++ retrytime = 6 ++ ret_t = "" ++ for i in range(retrytime): ++ ret, ret_t = osutil.command(command_line) ++ if ret == 0: ++ return True, ret_t ++ time.sleep(0.1) ++ return False, ret_t ++ ++ @staticmethod ++ def wbi2cget_i2ctool(bus, devno, address): ++ command_line = "i2cget -f -y %d 0x%02x 0x%02x " % (bus, devno, address) ++ retrytime = 6 ++ ret_t = "" ++ for i in range(retrytime): ++ ret, ret_t = osutil.command(command_line) ++ if ret == 0: ++ return True, int(ret_t, 16) ++ time.sleep(0.1) ++ return False, ret_t ++ ++ @staticmethod ++ def wbi2cset_i2ctool(bus, devno, address, byte): ++ command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x" % ( ++ bus, devno, address, byte) ++ retrytime = 6 ++ ret_t = "" ++ for i in range(retrytime): ++ ret, ret_t = osutil.command(command_line) ++ if ret == 0: ++ return True, ret_t ++ return False, ret_t ++ ++ @staticmethod ++ def geti2cword(bus, addr, offset): ++ return osutil.wbi2cgetword_python(bus, addr, offset) ++ ++ @staticmethod ++ def seti2cword(bus, addr, offset, val): ++ return osutil.wbi2csetword_python(bus, addr, offset, val) ++ ++ @staticmethod ++ def seti2cwordpec(bus, addr, offset, val): ++ return osutil.wbi2csetwordpec_python(bus, addr, offset, val) ++ ++ @staticmethod ++ def seti2c_byte_pec(bus, addr, offset, val): ++ return osutil.wbi2cset_byte_pec_python(bus, addr, offset, val) ++ ++ @staticmethod ++ def wbi2cget(bus, devno, address): ++ return osutil.wbi2cget_python(bus, devno, address) ++ ++ @staticmethod ++ def wbi2cset(bus, devno, address, byte): ++ return osutil.wbi2cset_python(bus, devno, address, byte) ++ ++ @staticmethod ++ def byteTostr(val): ++ strtmp = '' ++ for value in val: ++ strtmp += chr(value) ++ return strtmp ++ ++ @staticmethod ++ def io_rd(reg_addr, read_len=1): ++ try: ++ regaddr = 0 ++ if isinstance(reg_addr, int): ++ regaddr = reg_addr ++ else: ++ regaddr = int(reg_addr, 16) ++ devfile = "/dev/port" ++ fd = os.open(devfile, os.O_RDWR | os.O_CREAT) ++ os.lseek(fd, regaddr, os.SEEK_SET) ++ val = os.read(fd, read_len) ++ return True, "".join(["%02x" % item for item in val]) ++ except ValueError as e: ++ return False, str(e) ++ except Exception as e: ++ return False, str(e) ++ finally: ++ os.close(fd) ++ ++ @staticmethod ++ def readsysfs(location, flock_path=None): ++ flock_path_tmp = None ++ platform_hal_debug("readsysfs, location:%s, flock_path:%s" % (location, flock_path)) ++ try: ++ if flock_path is not None: ++ flock_paths = glob.glob(flock_path) ++ if len(flock_paths) != 0: ++ flock_path_tmp = flock_paths[0] ++ platform_hal_debug("try to get file lock, path:%s" % flock_path_tmp) ++ ret = take_file_rw_lock(flock_path_tmp) ++ if ret is False: ++ platform_hal_debug("take file lock timeout, path:%s" % flock_path_tmp) ++ return False, ("take file rw lock timeout, path:%s" % flock_path_tmp) ++ else: ++ platform_hal_debug("config error, can't find flock_path:%s" % flock_path) ++ ++ locations = glob.glob(location) ++ with open(locations[0], 'rb') as fd1: ++ retval = fd1.read() ++ retval = osutil.byteTostr(retval) ++ if flock_path_tmp is not None: ++ file_rw_unlock() ++ ++ retval = retval.rstrip('\r\n') ++ retval = retval.lstrip(" ") ++ except Exception as e: ++ if flock_path_tmp is not None: ++ file_rw_unlock() ++ platform_hal_debug("readsysfs error, msg:%s" % str(e)) ++ return False, (str(e) + " location[%s]" % location) ++ return True, retval ++ ++ @staticmethod ++ def writesysfs(location, value): ++ try: ++ if not os.path.isfile(location): ++ print(location, 'not found !') ++ return False, ("location[%s] not found !" % location) ++ with open(location, 'w') as fd1: ++ fd1.write(value) ++ except Exception as e: ++ return False, (str(e) + " location[%s]" % location) ++ return True, ("set location[%s] %s success !" % (location, value)) ++ ++ @staticmethod ++ def getdevmem(addr, digit, mask): ++ command_line = "devmem 0x%02x %d" % (addr, digit) ++ retrytime = 6 ++ ret_t = "" ++ for i in range(retrytime): ++ ret, ret_t = osutil.command(command_line) ++ if ret == 0: ++ if mask is not None: ++ ret_t = str(int(ret_t, 16) & mask) ++ return True, ret_t ++ return False, ret_t ++ ++ @staticmethod ++ def readdevfile_ascii(path, offset, length): ++ msg = "" ++ ret = "" ++ joinstr = '' ++ fd = -1 ++ ++ if not os.path.exists(path): ++ msg = path + " not found !" ++ return False, msg ++ ++ try: ++ fd = os.open(path, os.O_RDONLY) ++ os.lseek(fd, offset, os.SEEK_SET) ++ ret = os.read(fd, length) ++ for item in ret: ++ joinstr += '%02x ' % item # like sysfs, display in hex ++ except Exception as e: ++ msg = str(e) ++ return False, msg ++ finally: ++ if fd > 0: ++ os.close(fd) ++ return True, joinstr ++ ++ @staticmethod ++ def readdevfile(path, offset, length): ++ msg = "" ++ ret = "" ++ fd = -1 ++ val_list = [] ++ ++ if not os.path.exists(path): ++ msg = path + " not found !" ++ return False, msg ++ ++ try: ++ fd = os.open(path, os.O_RDONLY) ++ os.lseek(fd, offset, os.SEEK_SET) ++ ret = os.read(fd, length) ++ for item in ret: ++ val_list.append(item) ++ except Exception as e: ++ msg = str(e) ++ return False, msg ++ finally: ++ if fd > 0: ++ os.close(fd) ++ return True, val_list ++ ++ @staticmethod ++ def writedevfile(path, offset, buf): ++ msg = "" ++ fd = -1 ++ ++ if not os.path.exists(path): ++ msg = path + " not found !" ++ return False, msg ++ ++ if isinstance(buf, list): ++ if len(buf) == 0: ++ msg = "buf:%s is NONE !" % buf ++ return False, msg ++ elif isinstance(buf, int): ++ buf = [buf] ++ else: ++ msg = "buf:%s is not list type or not int type !" % buf ++ return False, msg ++ ++ try: ++ fd = os.open(path, os.O_WRONLY) ++ os.lseek(fd, offset, os.SEEK_SET) ++ ret = os.write(fd, bytes(buf)) ++ except Exception as e: ++ msg = str(e) ++ return False, msg ++ finally: ++ if fd > 0: ++ os.close(fd) ++ ++ return True, ret ++ ++ @staticmethod ++ def wb_os_system(cmd): ++ status, output = subprocess.getstatusoutput(cmd) ++ return status, output ++ ++ @staticmethod ++ def getsdkreg(reg): ++ try: ++ cmd = "bcmcmd -t 1 'getr %s ' < /dev/null" % reg ++ ret, result = osutil.wb_os_system(cmd) ++ result_t = result.strip().replace("\r", "").replace("\n", "") ++ if ret != 0 or "Error:" in result_t: ++ return False, result ++ patt = r"%s.(.*):(.*)>drivshell" % reg ++ rt = re.findall(patt, result_t, re.S) ++ test = re.findall("=(.*)", rt[0][0])[0] ++ except Exception as e: ++ return False, 'get sdk register error, msg: %s' % str(e) ++ return True, test ++ ++ @staticmethod ++ def getmactemp(): ++ try: ++ result = {} ++ # need to exec twice ++ osutil.wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") ++ ret, log = osutil.wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") ++ if ret: ++ return False, result ++ logs = log.splitlines() ++ for line in logs: ++ if "average" in line: ++ b = re.findall(r'\d+.\d+', line) ++ result["average"] = b[0] ++ elif "maximum" in line: ++ b = re.findall(r'\d+.\d+', line) ++ result["maximum"] = b[0] ++ except Exception as e: ++ return False, str(e) ++ return True, result ++ ++ @staticmethod ++ def std_match(stdout, pattern): ++ if pattern is None: ++ return stdout.strip() ++ for line in stdout.splitlines(): ++ if re.match(pattern, line): ++ return line.strip() ++ return None +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/psu.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/psu.py +new file mode 100644 +index 000000000..a5fc3bf77 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/psu.py +@@ -0,0 +1,701 @@ ++#!/usr/bin/env python3 ++####################################################### ++# ++# psu.py ++# Python implementation of the Class psu ++# ++####################################################### ++from eepromutil.fru import ipmifru ++from eepromutil.cust_fru import CustFru ++from plat_hal.devicebase import devicebase ++from plat_hal.sensor import sensor ++ ++ ++class psu(devicebase): ++ __pmbus = None ++ __e2loc = None ++ __productManufacturer = None # : ARTESYN ++ __productName = None # : CRPS550W ++ __productPartModelName = None # : CSU550AP-3-300 ++ __productVersion = None # : AB ++ __productSerialNumber = None # : M623UZ00JYABL ++ __AirFlow = None # 'N/A' ++ __AirFlowconifg = None ++ __psu_display_name = None # 'N/A' ++ __psu_display_name_conifg = None ++ __psu_not_present_pwm = None ++ __InputStatus_config = None ++ __OutputStatus_config = None ++ __FanSpeed_config = None ++ __Temperature_config = None ++ __InputStatus = None ++ __OutputStatus = None ++ __FanSpeed = None ++ __Temperature = None ++ __FanSpeedMin = None ++ __FanSpeedMax = None ++ __FanSpeedTolerance = None ++ __InputsVoltage_config = None ++ __InputsCurrent_config = None ++ __InputsPower_config = None ++ __OutputsVoltage_config = None ++ __OutputsCurrent_config = None ++ __OutputsPower_config = None ++ __InputsVoltage = {} ++ __InputsCurrent = None ++ __InputsPower = None ++ __OutputsVoltage = None ++ __OutputsCurrent = None ++ __OutputsPower = None ++ __InputsType_config = None ++ __InputsType = None ++ __psu_sn_config = None ++ __psu_hw_config = None ++ __psu_pn_config = None ++ __psu_vendor_config = None ++ __TempStatus_config = None ++ __FanStatus_config = None ++ __TempStatus = None ++ __FanStatus = None ++ ++ def __init__(self, conf=None): ++ self.pmbus = conf.get("pmbusloc", None) ++ self.e2loc = conf.get("e2loc", None) ++ self.e2_type = conf.get('e2_type', "fru") ++ self.__presentconfig = conf.get("present", None) ++ self.name = conf.get("name", None) ++ self.get_threshold_by_model = conf.get("get_threshold_by_model", 0) ++ self.AirFlowconifg = conf.get("airflow", None) ++ self.psu_display_name_conifg = conf.get("psu_display_name", None) ++ self.psu_not_present_pwm = conf.get("psu_not_present_pwm", 100) ++ self.Temperature_config = conf.get("Temperature", None) ++ self.Temperature = sensor(self.Temperature_config, self.get_psu_model) ++ ++ self.FanSpeedTolerance = conf.get('psu_fan_tolerance', 30) ++ self.FanSpeed_config = conf.get("FanSpeed", None) ++ self.FanSpeed = sensor(self.FanSpeed_config, self.get_psu_model) ++ ++ self.__InputsVoltage_config = conf.get("InputsVoltage", None) ++ self.generate_psu_input_vol(self.__InputsVoltage_config) ++ self.__InputsCurrent_config = conf.get("InputsCurrent", None) ++ self.InputsCurrent = sensor(self.__InputsCurrent_config, self.get_psu_model) ++ self.__InputsPower_config = conf.get("InputsPower", None) ++ self.InputsPower = sensor(self.__InputsPower_config, self.get_psu_model) ++ self.__OutputsVoltage_config = conf.get("OutputsVoltage", None) ++ self.OutputsVoltage = sensor(self.__OutputsVoltage_config, self.get_psu_model) ++ self.__OutputsCurrent_config = conf.get("OutputsCurrent", None) ++ self.OutputsCurrent = sensor(self.__OutputsCurrent_config, self.get_psu_model) ++ self.__OutputsPower_config = conf.get("OutputsPower", None) ++ self.OutputsPower = sensor(self.__OutputsPower_config, self.get_psu_model) ++ ++ self.__InputStatus_config = conf.get("InputsStatus", None) ++ self.__OutputStatus_config = conf.get("OutputsStatus", None) ++ self.__InputsType_config = conf.get('InputsType', None) ++ self.__psu_sn_config = conf.get('psu_sn', None) ++ self.__psu_hw_config = conf.get('psu_hw', None) ++ self.__psu_pn_config = conf.get('psu_pn', None) ++ self.__psu_vendor_config = conf.get('psu_vendor', None) ++ self.__TempStatus_config = conf.get("TempStatus", None) ++ self.__FanStatus_config = conf.get("FanStatus", None) ++ ++ def get_psu_model(self): ++ if self.productPartModelName is None: ++ ret = self.get_fru_info() ++ if ret is False: ++ return None ++ return self.productPartModelName ++ ++ def generate_psu_input_vol(self, config): ++ tmp = {} ++ for (key, item) in config.items(): ++ tmp.setdefault(key, sensor(item, self.get_psu_model)) ++ self.__InputsVoltage = tmp ++ ++ def get_psu_sensor_by_name(self, psutype): ++ return self.__InputsVoltage.get(psutype) or self.__InputsVoltage.get('other') ++ ++ @property ++ def InputsVoltage(self): ++ psutype = self.InputsType ++ input_sensor = self.get_psu_sensor_by_name(psutype) ++ if input_sensor is None: ++ return None ++ return input_sensor ++ ++ @InputsVoltage.setter ++ def InputsVoltage(self, val): ++ self.__InputsVoltage = val ++ ++ @property ++ def InputsCurrent(self): ++ return self.__InputsCurrent ++ ++ @InputsCurrent.setter ++ def InputsCurrent(self, val): ++ self.__InputsCurrent = val ++ ++ @property ++ def InputsPower(self): ++ return self.__InputsPower ++ ++ @InputsPower.setter ++ def InputsPower(self, val): ++ self.__InputsPower = val ++ ++ @property ++ def OutputsVoltage(self): ++ return self.__OutputsVoltage ++ ++ @OutputsVoltage.setter ++ def OutputsVoltage(self, val): ++ self.__OutputsVoltage = val ++ ++ @property ++ def OutputsCurrent(self): ++ return self.__OutputsCurrent ++ ++ @OutputsCurrent.setter ++ def OutputsCurrent(self, val): ++ self.__OutputsCurrent = val ++ ++ @property ++ def OutputsPower(self): ++ return self.__OutputsPower ++ ++ @OutputsPower.setter ++ def OutputsPower(self, val): ++ self.__OutputsPower = val ++ ++ @property ++ def InputStatus(self): ++ if self.__InputStatus_config is None: ++ return None ++ if self.present is False: ++ self.__InputStatus = False ++ else: ++ ret, val = self.get_value(self.__InputStatus_config) ++ mask = self.__InputStatus_config.get("mask") ++ if ret is True: ++ if isinstance(val, str): ++ value = int(val, 16) ++ else: ++ value = val ++ ttt = value & mask ++ okval = self.__InputStatus_config.get("okval", 0) ++ if ttt == okval: ++ self.__InputStatus = True ++ else: ++ self.__InputStatus = False ++ else: ++ self.__InputStatus = False ++ return self.__InputStatus ++ ++ @InputStatus.setter ++ def InputStatus(self, val): ++ self.__InputStatus = val ++ ++ @property ++ def TempStatus(self): ++ if self.__TempStatus_config is None: ++ return None ++ if self.present is False: ++ self.__TempStatus = False ++ else: ++ ret, val = self.get_value(self.__TempStatus_config) ++ mask = self.__TempStatus_config.get("mask") ++ if ret is True: ++ if isinstance(val, str): ++ value = int(val, 16) ++ else: ++ value = val ++ ttt = value & mask ++ okval = self.__TempStatus_config.get("okval", 0) ++ if ttt == okval: ++ self.__TempStatus = True ++ else: ++ self.__TempStatus = False ++ else: ++ self.__TempStatus = False ++ return self.__TempStatus ++ ++ @TempStatus.setter ++ def TempStatus(self, val): ++ self.__TempStatus = val ++ ++ @property ++ def FanStatus(self): ++ if self.__FanStatus_config is None: ++ return None ++ if self.present is False: ++ self.__FanStatus = False ++ else: ++ ret, val = self.get_value(self.__FanStatus_config) ++ mask = self.__FanStatus_config.get("mask") ++ if ret is True: ++ if isinstance(val, str): ++ value = int(val, 16) ++ else: ++ value = val ++ ttt = value & mask ++ okval = self.__FanStatus_config.get("okval", 0) ++ if ttt == okval: ++ self.__FanStatus = True ++ else: ++ self.__FanStatus = False ++ else: ++ self.__FanStatus = False ++ return self.__FanStatus ++ ++ @FanStatus.setter ++ def FanStatus(self, val): ++ self.__FanStatus = val ++ ++ def get_input_type_pmbus(self): ++ psutypedecode = self.__InputsType_config.get('psutypedecode', {}) ++ if self.present is False: ++ self.__InputsType = psutypedecode.get(0x00) ++ else: ++ ret, val = self.get_value(self.__InputsType_config) ++ self.__InputsType = self.__InputsType_config.get(val, None) ++ if self.__InputsType is not None: ++ return self.__InputsType ++ if ret is True and val in psutypedecode: ++ self.__InputsType = psutypedecode.get(val) ++ else: ++ self.__InputsType = psutypedecode.get(0x00) ++ return self.__InputsType ++ ++ def get_input_type_fru(self): ++ self.__InputsType = 'N/A' ++ if self.productPartModelName is None: ++ ret = self.get_fru_info() ++ if ret is False: ++ return self.__InputsType ++ psutypedecode = self.__InputsType_config.get('psutypedecode', {}) ++ for key, value in psutypedecode.items(): ++ if self.productPartModelName in value: ++ self.__InputsType = key ++ return self.__InputsType ++ ++ @property ++ def InputsType(self): ++ gettype = self.__InputsType_config.get('gettype', "pmbus") ++ if gettype == "pmbus": ++ return self.get_input_type_pmbus() ++ ++ if gettype == "fru": ++ return self.get_input_type_fru() ++ ++ self.__InputsType = 'N/A' ++ return self.__InputsType ++ ++ @InputsType.setter ++ def InputsType(self, val): ++ self.__InputsType = val ++ ++ @property ++ def FanSpeedMin(self): ++ return self.__FanSpeedMin ++ ++ @FanSpeedMin.setter ++ def FanSpeedMin(self, val): ++ self.__FanSpeedMin = val ++ ++ @property ++ def FanSpeedMax(self): ++ return self.__FanSpeedMax ++ ++ @FanSpeedMax.setter ++ def FanSpeedMax(self, val): ++ self.__FanSpeedMax = val ++ ++ @property ++ def FanSpeedTolerance(self): ++ return self.__FanSpeedTolerance ++ ++ @FanSpeedTolerance.setter ++ def FanSpeedTolerance(self, val): ++ self.__FanSpeedTolerance = val ++ ++ @property ++ def OutputStatus(self): ++ if self.__OutputStatus_config is None: ++ return None ++ if self.present is False: ++ self.__OutputStatus = False ++ else: ++ ret, val = self.get_value(self.__OutputStatus_config) ++ mask = self.__OutputStatus_config.get("mask") ++ if ret is True: ++ if isinstance(val, str): ++ value = int(val, 16) ++ else: ++ value = val ++ ttt = value & mask ++ okval = self.__OutputStatus_config.get("okval", 0) ++ if ttt == okval: ++ self.__OutputStatus = True ++ else: ++ self.__OutputStatus = False ++ else: ++ self.__OutputStatus = False ++ return self.__OutputStatus ++ ++ @OutputStatus.setter ++ def OutputStatus(self, val): ++ self.__OutputStatus = val ++ ++ @property ++ def FanSpeed(self): ++ return self.__FanSpeed ++ ++ @FanSpeed.setter ++ def FanSpeed(self, val): ++ self.__FanSpeed = val ++ ++ @property ++ def Temperature(self): ++ return self.__Temperature ++ ++ @Temperature.setter ++ def Temperature(self, val): ++ self.__Temperature = val ++ ++ @property ++ def Temperature_config(self): ++ return self.__Temperature_config ++ ++ @Temperature_config.setter ++ def Temperature_config(self, val): ++ self.__Temperature_config = val ++ ++ @property ++ def AirFlowconifg(self): ++ return self.__AirFlowconifg ++ ++ @AirFlowconifg.setter ++ def AirFlowconifg(self, val): ++ self.__AirFlowconifg = val ++ ++ @property ++ def psu_display_name_conifg(self): ++ return self.__psu_display_name_conifg ++ ++ @psu_display_name_conifg.setter ++ def psu_display_name_conifg(self, val): ++ self.__psu_display_name_conifg = val ++ ++ @property ++ def pmbus(self): ++ return self.__pmbus ++ ++ @pmbus.setter ++ def pmbus(self, val): ++ self.__pmbus = val ++ ++ @property ++ def e2loc(self): ++ return self.__e2loc ++ ++ @e2loc.setter ++ def e2loc(self, val): ++ self.__e2loc = val ++ ++ @property ++ def AirFlow(self): ++ return self.__AirFlow ++ ++ @AirFlow.setter ++ def AirFlow(self, val): ++ self.__AirFlow = val ++ ++ @property ++ def psu_display_name(self): ++ return self.__psu_display_name ++ ++ @psu_display_name.setter ++ def psu_display_name(self, val): ++ self.__psu_display_name = val ++ ++ @property ++ def psu_not_present_pwm(self): ++ return self.__psu_not_present_pwm ++ ++ @psu_not_present_pwm.setter ++ def psu_not_present_pwm(self, val): ++ self.__psu_not_present_pwm = val ++ ++ @property ++ def present(self): ++ ret, val = self.get_value(self.__presentconfig) ++ if ret is False or val is None: ++ return False ++ mask = self.__presentconfig.get("mask") ++ if isinstance(val, str): ++ value = int(val, 16) ++ else: ++ value = val ++ ttt = value & mask ++ okval = self.__presentconfig.get("okval", 0) ++ if ttt == okval: ++ return True ++ return False ++ ++ @property ++ def productManufacturer(self): ++ return self.__productManufacturer ++ ++ @productManufacturer.setter ++ def productManufacturer(self, val): ++ self.__productManufacturer = val ++ ++ @property ++ def productName(self): ++ return self.__productName ++ ++ @productName.setter ++ def productName(self, val): ++ self.__productName = val ++ ++ @property ++ def productPartModelName(self): ++ return self.__productPartModelName ++ ++ @productPartModelName.setter ++ def productPartModelName(self, val): ++ self.__productPartModelName = val ++ ++ @property ++ def productVersion(self): ++ return self.__productVersion ++ ++ @productVersion.setter ++ def productVersion(self, val): ++ self.__productVersion = val ++ ++ @property ++ def productSerialNumber(self): ++ return self.__productSerialNumber ++ ++ @productSerialNumber.setter ++ def productSerialNumber(self, val): ++ self.__productSerialNumber = val ++ ++ @property ++ def psu_sn_sysfs(self): ++ if self.__psu_sn_config is None: ++ return None ++ ret, val = self.get_value(self.__psu_sn_config) ++ if ret is False or val is None: ++ return None ++ return val ++ ++ @property ++ def psu_hw_sysfs(self): ++ if self.__psu_hw_config is None: ++ return None ++ ret, val = self.get_value(self.__psu_hw_config) ++ if ret is False or val is None: ++ return None ++ return val ++ ++ @property ++ def psu_pn_sysfs(self): ++ if self.__psu_pn_config is None: ++ return None ++ ret, val = self.get_value(self.__psu_pn_config) ++ if ret is False or val is None: ++ return None ++ return val ++ ++ @property ++ def psu_vendor_sysfs(self): ++ if self.__psu_vendor_config is None: ++ return None ++ ret, val = self.get_value(self.__psu_vendor_config) ++ if ret is False or val is None: ++ return None ++ return val ++ ++ def __str__(self): ++ formatstr = \ ++ "name : %s \n" \ ++ "productManufacturer : %s \n" \ ++ "productName : %s \n" \ ++ "productPartModelName: %s \n" \ ++ "productVersion : %s \n" \ ++ "productSerialNumber : %s \n" \ ++ "AirFlow : %s \n" \ ++ ++ tmpstr = formatstr % (self.name, self.productManufacturer, ++ self.productName, self.productPartModelName, ++ self.productVersion, self.productSerialNumber, self.AirFlow) ++ return tmpstr ++ ++ def get_fan_speed_pwm(self): ++ if self.pmbus is None: ++ return None ++ if self.present is False: ++ return self.psu_not_present_pwm ++ selfconfig = {} ++ selfconfig['bus'] = self.pmbus['bus'] ++ selfconfig['addr'] = self.pmbus['addr'] ++ selfconfig['way'] = 'i2cword' ++ selfconfig['offset'] = 0x3b ++ ret, val = self.get_value(selfconfig) ++ if ret is True: ++ return val ++ return None ++ ++ def set_fan_speed_pwm(self, pwm): ++ ''' ++ pmbus ++ if duty: ++ i2cset -f -y 0x3b 0x0064 wp ++ ''' ++ if self.present is False: ++ return None ++ ++ if self.pmbus is None: ++ return None ++ ++ if 0 <= pwm <= 100: ++ # enable duty first ++ selfconfig = {} ++ ++ selfconfig['bus'] = self.pmbus['bus'] ++ selfconfig['addr'] = self.pmbus['addr'] ++ selfconfig['way'] = 'i2cpec' ++ selfconfig['offset'] = 0x3a ++ self.set_value(selfconfig, 0x80) ++ ++ selfconfig['way'] = 'i2cwordpec' ++ selfconfig['offset'] = 0x3b ++ bytetmp = pwm ++ ret, val = self.set_value(selfconfig, int(bytetmp)) ++ if ret is True: ++ return True ++ return None ++ raise Exception("pwm not in range [0,100]") ++ ++ def get_fru_info_by_sysfs(self): ++ try: ++ psu_sn = self.psu_sn_sysfs ++ psu_hw = self.psu_hw_sysfs ++ psu_pn = self.psu_pn_sysfs ++ psu_vendor = self.psu_vendor_sysfs ++ if psu_sn is None or psu_hw is None or psu_pn is None or psu_vendor is None: ++ return False ++ self.productSerialNumber = psu_sn.strip().replace(chr(0), "") ++ self.productVersion = psu_hw.strip() ++ self.productPartModelName = psu_pn.strip() ++ self.productManufacturer = psu_vendor.strip().replace(chr(0), "") ++ except Exception: ++ self.productSerialNumber = None ++ self.productVersion = None ++ self.productPartModelName = None ++ self.productManufacturer = None ++ return False ++ return True ++ ++ def get_fru_info_by_decode(self): ++ try: ++ eeprom = self.get_eeprom_info(self.e2loc) ++ if eeprom is None: ++ raise Exception("%s:value is none" % self.name) ++ fru = ipmifru() ++ if isinstance(eeprom, bytes): ++ eeprom = self.byteTostr(eeprom) ++ fru.decodeBin(eeprom) ++ if fru.productInfoArea is not None: ++ self.productManufacturer = fru.productInfoArea.productManufacturer.strip() ++ self.productName = fru.productInfoArea.productName.strip() ++ self.productPartModelName = fru.productInfoArea.productPartModelName.strip() ++ self.productVersion = fru.productInfoArea.productVersion.strip() ++ self.productSerialNumber = fru.productInfoArea.productSerialNumber.strip().replace(chr(0), "") ++ except Exception: ++ self.productManufacturer = None ++ self.productName = None ++ self.productPartModelName = None ++ self.productVersion = None ++ self.productSerialNumber = None ++ return False ++ return True ++ ++ def get_custfru_info_by_decode(self): ++ try: ++ eeprom = self.get_eeprom_info(self.e2loc) ++ if eeprom is None: ++ raise Exception("%s:value is none" % self.name) ++ custfru = CustFru() ++ if isinstance(eeprom, bytes): ++ eeprom = self.byteTostr(eeprom) ++ custfru.decode(eeprom) ++ self.productManufacturer = custfru.manufacturer.strip() ++ self.productName = custfru.product_name.strip() ++ self.productPartModelName = custfru.product_name.strip() ++ self.productVersion = custfru.version.strip() ++ self.productSerialNumber = custfru.serial_number.strip().replace(chr(0), "") ++ except Exception: ++ self.productManufacturer = None ++ self.productName = None ++ self.productPartModelName = None ++ self.productVersion = None ++ self.productSerialNumber = None ++ return False ++ return True ++ ++ def get_fru_info(self): ++ try: ++ if self.present is not True: ++ raise Exception("%s: not present" % self.name) ++ ++ if self.get_fru_info_by_sysfs() is True: ++ return True ++ ++ if self.e2_type == "fru": ++ return self.get_fru_info_by_decode() ++ ++ if self.e2_type == "custfru": ++ return self.get_custfru_info_by_decode() ++ ++ raise Exception("%s: unsupport e2_type: %s" % (self.name, self.e2_type)) ++ except Exception: ++ self.productManufacturer = None ++ self.productName = None ++ self.productPartModelName = None ++ self.productVersion = None ++ self.productSerialNumber = None ++ return False ++ ++ def get_AirFlow(self): ++ if self.productPartModelName is None: ++ ret = self.get_fru_info() ++ if ret is False: ++ self.AirFlow = None ++ return False ++ if self.AirFlowconifg is None: ++ self.AirFlow = None ++ return False ++ for i in self.AirFlowconifg: ++ if self.productPartModelName in self.AirFlowconifg[i]: ++ self.AirFlow = i ++ return True ++ self.AirFlow = None ++ return False ++ ++ def get_psu_display_name(self): ++ if self.productPartModelName is None: ++ ret = self.get_fru_info() ++ if ret is False: ++ self.psu_display_name = None ++ return False ++ if self.psu_display_name_conifg is None: ++ self.psu_display_name = self.productPartModelName ++ return False ++ for i in self.psu_display_name_conifg: ++ if self.productPartModelName in self.psu_display_name_conifg[i]: ++ self.psu_display_name = i ++ return True ++ self.psu_display_name = self.productPartModelName ++ return False +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/rotor.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/rotor.py +new file mode 100644 +index 000000000..2b4e4ffd5 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/rotor.py +@@ -0,0 +1,149 @@ ++#!/usr/bin/env python3 ++####################################################### ++# ++# rotor.py ++# Python implementation of the Class rotor ++# ++####################################################### ++from plat_hal.devicebase import devicebase ++from plat_hal.sensor import sensor ++ ++ ++class rotor(devicebase): ++ __rotor_Running = None ++ __rotor_HwAlarm_conf = None ++ __rotor_Speed = None ++ __rotor_run_conf = None ++ __Speedconfig = None ++ __i2c_speed = None ++ __SpeedMin = None ++ __SpeedMax = None ++ __SpeedTolerance = None ++ ++ def __init__(self, conf=None): ++ self.name = conf.get('name', None) ++ self.rotor_HwAlarm_conf = conf.get('HwAlarm', None) ++ self.rotor_run_conf = conf.get('Running', None) ++ self.SpeedMin = conf.get('SpeedMin', None) ++ self.SpeedMax = conf.get('SpeedMax', None) ++ self.Tolerance = conf.get('tolerance', 30) ++ self.rotor_Speed = sensor(conf.get('Speed', None)) ++ self.Speedconfig = conf.get('Set_speed', None) ++ ++ def getRunning(self): ++ ret, val = self.get_value(self.rotor_run_conf) ++ if ret is False or val is None: ++ return False ++ if isinstance(val, str): ++ value = int(val, 16) ++ else: ++ value = val ++ mask = self.rotor_run_conf.get("mask") ++ is_runing_value = self.rotor_run_conf.get("is_runing") ++ flag = value & mask ++ if flag == is_runing_value: ++ return True ++ return False ++ ++ @property ++ def SpeedMin(self): ++ return self.__SpeedMin ++ ++ @SpeedMin.setter ++ def SpeedMin(self, val): ++ self.__SpeedMin = val ++ ++ @property ++ def SpeedMax(self): ++ return self.__SpeedMax ++ ++ @SpeedMax.setter ++ def SpeedMax(self, val): ++ self.__SpeedMax = val ++ ++ @property ++ def Tolerance(self): ++ return self.__SpeedTolerance ++ ++ @Tolerance.setter ++ def Tolerance(self, val): ++ self.__SpeedTolerance = val ++ ++ @property ++ def i2c_speed(self): ++ ret, val = self.get_value(self.Speedconfig) ++ if ret is False: ++ return None ++ if val is not None: ++ self.__i2c_speed = val ++ return self.__i2c_speed ++ ++ def feed_watchdog(self): ++ ret, val = self.get_value(self.Speedconfig) ++ if ret is False: ++ return False, None ++ if val is not None: ++ ret, val = self.set_value(self.Speedconfig, val) ++ return ret, val ++ return False, None ++ ++ @i2c_speed.setter ++ def i2c_speed(self, val): ++ self.__i2c_speed = val ++ ++ @property ++ def Speedconfig(self): ++ return self.__Speedconfig ++ ++ @Speedconfig.setter ++ def Speedconfig(self, val): ++ self.__Speedconfig = val ++ ++ @property ++ def rotor_run_conf(self): ++ return self.__rotor_run_conf ++ ++ @rotor_run_conf.setter ++ def rotor_run_conf(self, val): ++ self.__rotor_run_conf = val ++ ++ @property ++ def rotor_Speed(self): ++ return self.__rotor_Speed ++ ++ @rotor_Speed.setter ++ def rotor_Speed(self, val): ++ self.__rotor_Speed = val ++ ++ @property ++ def rotor_HwAlarm(self): ++ ret, val = self.get_value(self.rotor_HwAlarm_conf) ++ mask = self.rotor_HwAlarm_conf.get("mask") ++ no_alarm_value = self.rotor_HwAlarm_conf.get("no_alarm") ++ if ret is False or val is None: ++ return False ++ if isinstance(val, str): ++ value = int(val, 16) ++ else: ++ value = val ++ flag = value & mask ++ if flag == no_alarm_value: ++ return False ++ return True ++ ++ @property ++ def rotor_HwAlarm_conf(self): ++ return self.__rotor_HwAlarm_conf ++ ++ @rotor_HwAlarm_conf.setter ++ def rotor_HwAlarm_conf(self, val): ++ self.__rotor_HwAlarm_conf = val ++ ++ @property ++ def rotor_Running(self): ++ self.__rotor_Running = self.getRunning() ++ return self.__rotor_Running ++ ++ @rotor_Running.setter ++ def rotor_Running(self, val): ++ self.__rotor_Running = val +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/sensor.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/sensor.py +new file mode 100644 +index 000000000..af2a5384b +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/sensor.py +@@ -0,0 +1,274 @@ ++#!/usr/bin/env python3 ++####################################################### ++# ++# sensor.py ++# Python implementation of the Class sensor ++# ++####################################################### ++import time ++from plat_hal.devicebase import devicebase ++ ++ ++class sensor(devicebase): ++ ++ __Value = None ++ __Min = None ++ __Max = None ++ __Low = None ++ __High = None ++ __ValueConfig = None ++ __Flag = None ++ __Unit = None ++ __format = None ++ __read_times = None ++ ++ __Min_config = None ++ __Max_config = None ++ __Low_config = None ++ __High_config = None ++ ++ @property ++ def Min_config(self): ++ return self.__Min_config ++ ++ @Min_config.setter ++ def Min_config(self, val): ++ self.__Min_config = val ++ ++ @property ++ def Max_config(self): ++ return self.__Max_config ++ ++ @Max_config.setter ++ def Max_config(self, val): ++ self.__Max_config = val ++ ++ @property ++ def Low_config(self): ++ return self.__Low_config ++ ++ @Low_config.setter ++ def Low_config(self, val): ++ self.__Low_config = val ++ ++ @property ++ def High_config(self): ++ return self.__High_config ++ ++ @High_config.setter ++ def High_config(self, val): ++ self.__High_config = val ++ ++ @property ++ def Unit(self): ++ return self.__Unit ++ ++ @Unit.setter ++ def Unit(self, val): ++ self.__Unit = val ++ ++ @property ++ def format(self): ++ return self.__format ++ ++ @format.setter ++ def format(self, val): ++ self.__format = val ++ ++ @property ++ def read_times(self): ++ return self.__read_times ++ ++ @read_times.setter ++ def read_times(self, val): ++ self.__read_times = val ++ ++ @property ++ def ValueConfig(self): ++ return self.__ValueConfig ++ ++ @ValueConfig.setter ++ def ValueConfig(self, val): ++ self.__ValueConfig = val ++ ++ @property ++ def Flag(self): ++ return self.__Flag ++ ++ @Flag.setter ++ def Flag(self, val): ++ self.__Flag = val ++ ++ def get_median(self, value_config, read_times): ++ val_list = [] ++ for i in range(0, read_times): ++ ret, real_value = self.get_value(value_config) ++ if i != (read_times - 1): ++ time.sleep(0.01) ++ if ret is False or real_value is None: ++ continue ++ val_list.append(real_value) ++ val_list.sort() ++ if val_list: ++ return True, val_list[int((len(val_list) - 1) / 2)] ++ return False, None ++ ++ @property ++ def Value(self): ++ try: ++ ret, val = self.get_median(self.ValueConfig, self.read_times) ++ if ret is False or val is None: ++ return None ++ if self.format is None: ++ self.__Value = int(val) ++ else: ++ self.__Value = self.get_format_value(self.format % val) ++ self.__Value = round(float(self.__Value), 3) ++ except Exception: ++ return None ++ return self.__Value ++ ++ @Value.setter ++ def Value(self, val): ++ self.__Value = val ++ ++ @property ++ def Min(self): ++ try: ++ if isinstance(self.Min_config, dict): ++ if self.call_back is None: ++ self.__Min = self.Min_config.get("other") ++ else: ++ ret = self.call_back() ++ if ret not in self.Min_config: ++ self.__Min = self.Min_config.get("other") ++ else: ++ self.__Min = self.Min_config[ret] ++ else: ++ self.__Min = self.Min_config ++ ++ if self.__Min is None: ++ return None ++ ++ if self.format is not None: ++ self.__Min = self.get_format_value(self.format % self.__Min) ++ self.__Min = round(float(self.__Min), 3) ++ except Exception: ++ return None ++ return self.__Min ++ ++ @Min.setter ++ def Min(self, val): ++ self.__Min = val ++ ++ @property ++ def Max(self): ++ try: ++ if isinstance(self.Max_config, dict): ++ if self.call_back is None: ++ self.__Max = self.Max_config.get("other") ++ else: ++ ret = self.call_back() ++ if ret not in self.Max_config: ++ self.__Max = self.Max_config.get("other") ++ else: ++ self.__Max = self.Max_config[ret] ++ else: ++ self.__Max = self.Max_config ++ ++ if self.__Max is None: ++ return None ++ ++ if self.format is not None: ++ self.__Max = self.get_format_value(self.format % self.__Max) ++ self.__Max = round(float(self.__Max), 3) ++ except Exception: ++ return None ++ return self.__Max ++ ++ @Max.setter ++ def Max(self, val): ++ self.__Max = val ++ ++ @property ++ def Low(self): ++ try: ++ if isinstance(self.Low_config, dict): ++ if self.call_back is None: ++ self.__Low = self.Low_config.get("other") ++ else: ++ ret = self.call_back() ++ if ret not in self.Low_config: ++ self.__Low = self.Low_config.get("other") ++ else: ++ self.__Low = self.Low_config[ret] ++ else: ++ self.__Low = self.Low_config ++ ++ if self.__Low is None: ++ return None ++ ++ if self.format is not None: ++ self.__Low = self.get_format_value(self.format % self.__Low) ++ self.__Low = round(float(self.__Low), 3) ++ except Exception: ++ return None ++ return self.__Low ++ ++ @Low.setter ++ def Low(self, val): ++ self.__Low = val ++ ++ @property ++ def High(self): ++ try: ++ if isinstance(self.High_config, dict): ++ if self.call_back is None: ++ self.__High = self.High_config.get("other") ++ else: ++ ret = self.call_back() ++ if ret not in self.High_config: ++ self.__High = self.High_config.get("other") ++ else: ++ self.__High = self.High_config[ret] ++ else: ++ self.__High = self.High_config ++ ++ if self.__High is None: ++ return None ++ ++ if self.format is not None: ++ self.__High = self.get_format_value(self.format % self.__High) ++ self.__High = round(float(self.__High), 3) ++ except Exception: ++ return None ++ return self.__High ++ ++ @High.setter ++ def High(self, val): ++ self.__High = val ++ ++ def __init__(self, conf=None, call_back=None): ++ self.ValueConfig = conf.get("value", None) ++ self.Flag = conf.get("flag", None) ++ self.Min_config = conf.get("Min", None) ++ self.Max_config = conf.get("Max", None) ++ self.Low_config = conf.get("Low", None) ++ self.High_config = conf.get("High", None) ++ self.Unit = conf.get('Unit', None) ++ self.format = conf.get('format', None) ++ self.read_times = conf.get('read_times', 1) ++ self.call_back = call_back ++ ++ def __str__(self): ++ formatstr = \ ++ "ValueConfig: : %s \n" \ ++ "Min : %s \n" \ ++ "Max : %s \n" \ ++ "Unit : %s \n" \ ++ "format: : %s \n" ++ ++ tmpstr = formatstr % (self.ValueConfig, self.Min, ++ self.Max, self.Unit, ++ self.format) ++ return tmpstr +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/temp.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/temp.py +new file mode 100644 +index 000000000..a202c2033 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/temp.py +@@ -0,0 +1,139 @@ ++#!/usr/bin/env python3 ++####################################################### ++# ++# temp.py ++# Python implementation of the Class temp ++# ++####################################################### ++import os ++import syslog ++from plat_hal.sensor import sensor ++ ++ ++PLATFORM_HAL_TEMP_DEBUG_FILE = "/etc/.platform_hal_temp_debug_flag" ++ ++ ++def platform_hal_temp_debug(s): ++ if os.path.exists(PLATFORM_HAL_TEMP_DEBUG_FILE): ++ syslog.openlog("PLATFORM_HAL_TEPM", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++class temp(sensor): ++ def __init__(self, conf=None): ++ super(temp, self).__init__(conf.get('Temperature', None)) ++ self.name = conf.get("name", None) ++ self.temp_id = conf.get("temp_id", None) ++ self.api_name = conf.get("api_name", self.name) ++ self.fix_value = conf.get("fix_value", None) ++ self.temp_invalid = conf.get("invalid", None) ++ self.temp_error = conf.get("error", None) ++ ++ def temp_cali_by_fan_pwm(self, param, origin_value): ++ fan_pwm_conf = param.get("fan_pwm") ++ temp_fix_list = param.get("temp_fix_list") ++ ++ ret, val = self.get_value(fan_pwm_conf) ++ if ret is False or val is None: ++ platform_hal_temp_debug("temp calibration get fan pwm failed, msg: %s, return None" % (val)) ++ return None ++ ++ fan_pwm = int(val) ++ for item in temp_fix_list: ++ if item["min"] <= fan_pwm <= item["max"]: ++ fix_value = origin_value + item["fix"] ++ platform_hal_temp_debug("temp calibration by fan pwm, origin_value: %s, pwm: %s, fix_value: %s" % ++ (origin_value, fan_pwm, fix_value)) ++ return fix_value ++ platform_hal_temp_debug("temp calibration by fan pwm, origin_value: %s, pwm: %s, not match return None" % ++ (origin_value, fan_pwm)) ++ return None ++ ++ def fix_temp_value(self, origin_value): ++ try: ++ fix_type = self.fix_value.get("fix_type") ++ ++ if fix_type == "func": ++ func_name = self.fix_value.get("func_name") ++ func_param = self.fix_value.get("func_param") ++ func = getattr(self, func_name) ++ if func is None: ++ platform_hal_temp_debug("function %s, not defined" % func_name) ++ return None ++ value = func(func_param, origin_value) ++ return value ++ ++ if fix_type == "config": ++ coefficient = self.fix_value.get("coefficient", 1) ++ addend = self.fix_value.get("addend", 0) ++ value = (origin_value + addend) * coefficient ++ platform_hal_temp_debug("temp calibration by config, coefficient: %s, addend: %s, origin_value: %s, fix_value: %s" % ++ (coefficient, addend, origin_value, value)) ++ return value ++ ++ platform_hal_temp_debug("unsupport fix type: %s, return origin value: %s" % (fix_type, origin_value)) ++ return origin_value ++ except Exception as e: ++ platform_hal_temp_debug("fix_temp_value raise exception, msg: %s" % (str(e))) ++ return None ++ ++ def get_max_value(self, conf): ++ try: ++ ret, val = self.get_value(conf) ++ if ret is False or val is None: ++ return None ++ return val ++ except Exception: ++ return None ++ ++ def check_flag(self): ++ try: ++ okbit = self.Flag.get('okbit') ++ okval = self.Flag.get('okval') ++ ret, val = self.get_value(self.Flag) ++ if (ret is False) or (val is None): ++ return False ++ val_t = (int(val) & (1 << okbit)) >> okbit ++ if val_t != okval: ++ return False ++ except Exception: ++ return False ++ return True ++ ++ @property ++ def Value(self): ++ try: ++ if self.Flag is not None: ++ if self.check_flag() is False: ++ return None ++ if isinstance(self.ValueConfig, list): ++ max_val = None ++ for i in self.ValueConfig: ++ tmp = self.get_max_value(i) ++ if tmp is None: ++ continue ++ if max_val is None or max_val < tmp: ++ max_val = tmp ++ if max_val is None: ++ return None ++ if self.format is None: ++ self.__Value = int(max_val) ++ else: ++ self.__Value = self.get_format_value(self.format % max_val) ++ else: ++ ret, val = self.get_value(self.ValueConfig) ++ if ret is False or val is None: ++ return None ++ if self.format is None: ++ self.__Value = int(val) ++ else: ++ self.__Value = self.get_format_value(self.format % val) ++ except Exception: ++ return None ++ if self.fix_value is not None and self.__Value != self.temp_invalid and self.__Value != self.temp_error: ++ self.__Value = self.fix_temp_value(self.__Value) ++ return self.__Value ++ ++ @Value.setter ++ def Value(self, val): ++ self.__Value = val +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/__init__.py +new file mode 100644 +index 000000000..e69de29bb +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/baseutil.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/baseutil.py +new file mode 100644 +index 000000000..340a1f7a7 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/baseutil.py +@@ -0,0 +1,38 @@ ++#!/usr/bin/env python3 ++import os ++ ++ ++def get_machine_info(): ++ if not os.path.isfile('/host/machine.conf'): ++ return None ++ machine_vars = {} ++ with open('/host/machine.conf') as machine_file: ++ for line in machine_file: ++ tokens = line.split('=') ++ if len(tokens) < 2: ++ continue ++ machine_vars[tokens[0]] = tokens[1].strip() ++ return machine_vars ++ ++ ++def get_platform_info(machine_info): ++ if machine_info is not None: ++ if 'onie_platform' in machine_info: ++ return machine_info['onie_platform'] ++ if 'aboot_platform' in machine_info: ++ return machine_info['aboot_platform'] ++ return None ++ ++ ++def get_board_id(machine_info): ++ if machine_info is not None: ++ if 'onie_board_id' in machine_info: ++ return machine_info['onie_board_id'].lower() ++ return "NA" ++ ++ ++def get_onie_machine(machine_info): ++ if machine_info is not None: ++ if 'onie_machine' in machine_info: ++ return machine_info['onie_machine'] ++ return None +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/smbus.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/smbus.py +new file mode 100644 +index 000000000..5f1659b3b +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/smbus.py +@@ -0,0 +1,772 @@ ++#!/usr/bin/env python3 ++# smbus2 - A drop-in replacement for smbus-cffi/smbus-python ++# The MIT License (MIT) ++# Copyright (c) 2017 Karl-Petter Lindegaard ++# ++# Permission is hereby granted, free of charge, to any person obtaining a copy ++# of this software and associated documentation files (the "Software"), to deal ++# in the Software without restriction, including without limitation the rights ++# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++# copies of the Software, and to permit persons to whom the Software is ++# furnished to do so, subject to the following conditions: ++# ++# The above copyright notice and this permission notice shall be included in all ++# copies or substantial portions of the Software. ++# ++# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++# SOFTWARE. ++ ++import os ++import sys ++from fcntl import ioctl ++from ctypes import c_uint32, c_uint8, c_uint16, c_char, POINTER, Structure, Array, Union, create_string_buffer, string_at ++ ++ ++# Commands from uapi/linux/i2c-dev.h ++I2C_SLAVE = 0x0703 # Use this slave address ++I2C_SLAVE_FORCE = 0x0706 # Use this slave address, even if it is already in use by a driver! ++I2C_FUNCS = 0x0705 # Get the adapter functionality mask ++I2C_RDWR = 0x0707 # Combined R/W transfer (one STOP only) ++I2C_SMBUS = 0x0720 # SMBus transfer. Takes pointer to i2c_smbus_ioctl_data ++I2C_PEC = 0x0708 ++ ++# SMBus transfer read or write markers from uapi/linux/i2c.h ++I2C_SMBUS_WRITE = 0 ++I2C_SMBUS_READ = 1 ++ ++# Size identifiers uapi/linux/i2c.h ++I2C_SMBUS_QUICK = 0 ++I2C_SMBUS_BYTE = 1 ++I2C_SMBUS_BYTE_DATA = 2 ++I2C_SMBUS_WORD_DATA = 3 ++I2C_SMBUS_PROC_CALL = 4 ++# This isn't supported by Pure-I2C drivers with SMBUS emulation, like those in RaspberryPi, OrangePi, etc :( ++I2C_SMBUS_BLOCK_DATA = 5 ++I2C_SMBUS_BLOCK_PROC_CALL = 7 # Like I2C_SMBUS_BLOCK_DATA, it isn't supported by Pure-I2C drivers either. ++I2C_SMBUS_I2C_BLOCK_DATA = 8 ++I2C_SMBUS_BLOCK_MAX = 32 ++ ++# To determine what functionality is present (uapi/linux/i2c.h) ++try: ++ from enum import IntFlag ++except ImportError: ++ IntFlag = int ++ ++ ++class I2cFunc(IntFlag): ++ """ ++ These flags identify the operations supported by an I2C/SMBus device. ++ ++ You can test these flags on your `smbus.funcs` ++ ++ On newer python versions, I2cFunc is an IntFlag enum, but it ++ falls back to class with a bunch of int constants on older releases. ++ """ ++ I2C = 0x00000001 ++ ADDR_10BIT = 0x00000002 ++ PROTOCOL_MANGLING = 0x00000004 # I2C_M_IGNORE_NAK etc. ++ SMBUS_PEC = 0x00000008 ++ NOSTART = 0x00000010 # I2C_M_NOSTART ++ SLAVE = 0x00000020 ++ SMBUS_BLOCK_PROC_CALL = 0x00008000 # SMBus 2.0 ++ SMBUS_QUICK = 0x00010000 ++ SMBUS_READ_BYTE = 0x00020000 ++ SMBUS_WRITE_BYTE = 0x00040000 ++ SMBUS_READ_BYTE_DATA = 0x00080000 ++ SMBUS_WRITE_BYTE_DATA = 0x00100000 ++ SMBUS_READ_WORD_DATA = 0x00200000 ++ SMBUS_WRITE_WORD_DATA = 0x00400000 ++ SMBUS_PROC_CALL = 0x00800000 ++ SMBUS_READ_BLOCK_DATA = 0x01000000 ++ SMBUS_WRITE_BLOCK_DATA = 0x02000000 ++ SMBUS_READ_I2C_BLOCK = 0x04000000 # I2C-like block xfer ++ SMBUS_WRITE_I2C_BLOCK = 0x08000000 # w/ 1-byte reg. addr. ++ SMBUS_HOST_NOTIFY = 0x10000000 ++ ++ SMBUS_BYTE = 0x00060000 ++ SMBUS_BYTE_DATA = 0x00180000 ++ SMBUS_WORD_DATA = 0x00600000 ++ SMBUS_BLOCK_DATA = 0x03000000 ++ SMBUS_I2C_BLOCK = 0x0c000000 ++ SMBUS_EMUL = 0x0eff0008 ++ ++ ++# i2c_msg flags from uapi/linux/i2c.h ++I2C_M_RD = 0x0001 ++ ++# Pointer definitions ++LP_c_uint8 = POINTER(c_uint8) ++LP_c_uint16 = POINTER(c_uint16) ++LP_c_uint32 = POINTER(c_uint32) ++ ++ ++############################################################# ++# Type definitions as in i2c.h ++ ++ ++class i2c_smbus_data(Array): ++ """ ++ Adaptation of the i2c_smbus_data union in ``i2c.h``. ++ ++ Data for SMBus messages. ++ """ ++ _length_ = I2C_SMBUS_BLOCK_MAX + 2 ++ _type_ = c_uint8 ++ ++ ++class union_i2c_smbus_data(Union): ++ _fields_ = [ ++ ("byte", c_uint8), ++ ("word", c_uint16), ++ ("block", i2c_smbus_data) ++ ] ++ ++ ++union_pointer_type = POINTER(union_i2c_smbus_data) ++ ++ ++class i2c_smbus_ioctl_data(Structure): ++ """ ++ As defined in ``i2c-dev.h``. ++ """ ++ _fields_ = [ ++ ('read_write', c_uint8), ++ ('command', c_uint8), ++ ('size', c_uint32), ++ ('data', union_pointer_type)] ++ __slots__ = [name for name, type in _fields_] ++ ++ @staticmethod ++ def create(read_write=I2C_SMBUS_READ, command=0, size=I2C_SMBUS_BYTE_DATA): ++ u = union_i2c_smbus_data() ++ return i2c_smbus_ioctl_data( ++ read_write=read_write, command=command, size=size, ++ data=union_pointer_type(u)) ++ ++ ++############################################################# ++# Type definitions for i2c_rdwr combined transactions ++ ++ ++class i2c_msg(Structure): ++ """ ++ As defined in ``i2c.h``. ++ """ ++ _fields_ = [ ++ ('addr', c_uint16), ++ ('flags', c_uint16), ++ ('len', c_uint16), ++ ('buf', POINTER(c_char))] ++ ++ def __iter__(self): ++ """ Iterator / Generator ++ ++ :return: iterates over :py:attr:`buf` ++ :rtype: :py:class:`generator` which returns int values ++ """ ++ idx = 0 ++ while idx < self.len: ++ yield ord(self.buf[idx]) ++ idx += 1 ++ ++ def __len__(self): ++ return self.len ++ ++ def __bytes__(self): ++ return string_at(self.buf, self.len) ++ ++ def __repr__(self): ++ return 'i2c_msg(%d,%d,%r)' % (self.addr, self.flags, self.__bytes__()) ++ ++ def __str__(self): ++ s = self.__bytes__() ++ if sys.version_info.major >= 3: ++ s = ''.join(map(chr, s)) ++ return s ++ ++ @staticmethod ++ def read(address, length): ++ """ ++ Prepares an i2c read transaction. ++ ++ :param address: Slave address. ++ :type: address: int ++ :param length: Number of bytes to read. ++ :type: length: int ++ :return: New :py:class:`i2c_msg` instance for read operation. ++ :rtype: :py:class:`i2c_msg` ++ """ ++ arr = create_string_buffer(length) ++ return i2c_msg( ++ addr=address, flags=I2C_M_RD, len=length, ++ buf=arr) ++ ++ @staticmethod ++ def write(address, buf): ++ """ ++ Prepares an i2c write transaction. ++ ++ :param address: Slave address. ++ :type address: int ++ :param buf: Bytes to write. Either list of values or str. ++ :type buf: list ++ :return: New :py:class:`i2c_msg` instance for write operation. ++ :rtype: :py:class:`i2c_msg` ++ """ ++ if sys.version_info.major >= 3: ++ if isinstance(buf, str): ++ buf = bytes(map(ord, buf)) ++ else: ++ buf = bytes(buf) ++ else: ++ if not isinstance(buf, str): ++ buf = ''.join([chr(x) for x in buf]) ++ arr = create_string_buffer(buf, len(buf)) ++ return i2c_msg( ++ addr=address, flags=0, len=len(arr), ++ buf=arr) ++ ++ ++class i2c_rdwr_ioctl_data(Structure): ++ """ ++ As defined in ``i2c-dev.h``. ++ """ ++ _fields_ = [ ++ ('msgs', POINTER(i2c_msg)), ++ ('nmsgs', c_uint32) ++ ] ++ __slots__ = [name for name, type in _fields_] ++ ++ @staticmethod ++ def create(*i2c_msg_instances): ++ """ ++ Factory method for creating a i2c_rdwr_ioctl_data struct that can ++ be called with ``ioctl(fd, I2C_RDWR, data)``. ++ ++ :param i2c_msg_instances: Up to 42 i2c_msg instances ++ :rtype: i2c_rdwr_ioctl_data ++ """ ++ n_msg = len(i2c_msg_instances) ++ msg_array = (i2c_msg * n_msg)(*i2c_msg_instances) ++ return i2c_rdwr_ioctl_data( ++ msgs=msg_array, ++ nmsgs=n_msg ++ ) ++ ++ ++############################################################# ++ ++ ++class SMBus(object): ++ ++ def __init__(self, bus=None, force=False): ++ """ ++ Initialize and (optionally) open an i2c bus connection. ++ ++ :param bus: i2c bus number (e.g. 0 or 1) ++ or an absolute file path (e.g. `/dev/i2c-42`). ++ If not given, a subsequent call to ``open()`` is required. ++ :type bus: int or str ++ :param force: force using the slave address even when driver is ++ already using it. ++ :type force: boolean ++ """ ++ self.fd = None ++ self.funcs = I2cFunc(0) ++ if bus is not None: ++ self.open(bus) ++ self.address = None ++ self.force = force ++ self._force_last = None ++ ++ def __enter__(self): ++ """Enter handler.""" ++ return self ++ ++ def __exit__(self, exc_type, exc_val, exc_tb): ++ """Exit handler.""" ++ self.close() ++ ++ def open(self, bus): ++ """ ++ Open a given i2c bus. ++ ++ :param bus: i2c bus number (e.g. 0 or 1) ++ or an absolute file path (e.g. '/dev/i2c-42'). ++ :type bus: int or str ++ :raise TypeError: if type(bus) is not in (int, str) ++ """ ++ if isinstance(bus, int): ++ filepath = "/dev/i2c-{}".format(bus) ++ elif isinstance(bus, str): ++ filepath = bus ++ else: ++ raise TypeError("Unexpected type(bus)={}".format(type(bus))) ++ ++ self.fd = os.open(filepath, os.O_RDWR) ++ self.funcs = self._get_funcs() ++ ++ def close(self): ++ """ ++ Close the i2c connection. ++ """ ++ if self.fd: ++ os.close(self.fd) ++ self.fd = None ++ ++ def _set_address(self, address, force=None): ++ """ ++ Set i2c slave address to use for subsequent calls. ++ ++ :param address: ++ :type address: int ++ :param force: ++ :type force: Boolean ++ """ ++ force = force if force is not None else self.force ++ if self.address != address or self._force_last != force: ++ if force is True: ++ ioctl(self.fd, I2C_SLAVE_FORCE, address) ++ else: ++ ioctl(self.fd, I2C_SLAVE, address) ++ self.address = address ++ self._force_last = force ++ ++ def _get_funcs(self): ++ """ ++ Returns a 32-bit value stating supported I2C functions. ++ ++ :rtype: int ++ """ ++ f = c_uint32() ++ ioctl(self.fd, I2C_FUNCS, f) ++ return f.value ++ ++ def write_quick(self, i2c_addr, force=None): ++ """ ++ Perform quick transaction. Throws IOError if unsuccessful. ++ :param i2c_addr: i2c address ++ :type i2c_addr: int ++ :param force: ++ :type force: Boolean ++ """ ++ self._set_address(i2c_addr, force=force) ++ msg = i2c_smbus_ioctl_data.create( ++ read_write=I2C_SMBUS_WRITE, command=0, size=I2C_SMBUS_QUICK) ++ ioctl(self.fd, I2C_SMBUS, msg) ++ ++ def read_byte(self, i2c_addr, force=None): ++ """ ++ Read a single byte from a device. ++ ++ :rtype: int ++ :param i2c_addr: i2c address ++ :type i2c_addr: int ++ :param force: ++ :type force: Boolean ++ :return: Read byte value ++ """ ++ self._set_address(i2c_addr, force=force) ++ msg = i2c_smbus_ioctl_data.create( ++ read_write=I2C_SMBUS_READ, command=0, size=I2C_SMBUS_BYTE ++ ) ++ ioctl(self.fd, I2C_SMBUS, msg) ++ return msg.data.contents.byte ++ ++ def write_byte(self, i2c_addr, value, force=None): ++ """ ++ Write a single byte to a device. ++ ++ :param i2c_addr: i2c address ++ :type i2c_addr: int ++ :param value: value to write ++ :type value: int ++ :param force: ++ :type force: Boolean ++ """ ++ self._set_address(i2c_addr, force=force) ++ msg = i2c_smbus_ioctl_data.create( ++ read_write=I2C_SMBUS_WRITE, command=value, size=I2C_SMBUS_BYTE ++ ) ++ ioctl(self.fd, I2C_SMBUS, msg) ++ ++ def read_byte_data(self, i2c_addr, register, force=None): ++ """ ++ Read a single byte from a designated register. ++ ++ :param i2c_addr: i2c address ++ :type i2c_addr: int ++ :param register: Register to read ++ :type register: int ++ :param force: ++ :type force: Boolean ++ :return: Read byte value ++ :rtype: int ++ """ ++ val_t = -1 ++ returnmsg = "" ++ try: ++ self._set_address(i2c_addr, force=force) ++ msg = i2c_smbus_ioctl_data.create( ++ read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_BYTE_DATA ++ ) ++ val_t = ioctl(self.fd, I2C_SMBUS, msg) ++ except Exception as e: ++ self.close() ++ returnmsg = str(e) ++ if val_t < 0: ++ return False, returnmsg ++ return True, msg.data.contents.byte ++ ++ def write_byte_data(self, i2c_addr, register, value, force=None): ++ """ ++ Write a byte to a given register. ++ ++ :param i2c_addr: i2c address ++ :type i2c_addr: int ++ :param register: Register to write to ++ :type register: int ++ :param value: Byte value to transmit ++ :type value: int ++ :param force: ++ :type force: Boolean ++ :rtype: None ++ """ ++ val_t = -1 ++ returnmsg = "" ++ try: ++ self._set_address(i2c_addr, force=force) ++ msg = i2c_smbus_ioctl_data.create( ++ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BYTE_DATA ++ ) ++ msg.data.contents.byte = value ++ val_t = ioctl(self.fd, I2C_SMBUS, msg) ++ except Exception as e: ++ returnmsg = str(e) ++ self.close() ++ if val_t < 0: ++ return False, returnmsg or "" ++ return True, "" ++ ++ def write_byte_data_pec(self, i2c_addr, register, value, force=None): ++ """ ++ Write a byte to a given register. ++ ++ :param i2c_addr: i2c address ++ :type i2c_addr: int ++ :param register: Register to write to ++ :type register: int ++ :param value: Byte value to transmit ++ :type value: int ++ :param force: ++ :type force: Boolean ++ :rtype: None ++ """ ++ val_t = -1 ++ returnmsg = "" ++ try: ++ val_t = ioctl(self.fd, I2C_PEC, 1) ++ if val_t < 0: ++ raise Exception("set pec mod error") ++ self._set_address(i2c_addr, force=force) ++ msg = i2c_smbus_ioctl_data.create( ++ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BYTE_DATA ++ ) ++ msg.data.contents.byte = value ++ val_t = ioctl(self.fd, I2C_SMBUS, msg) ++ except Exception as e: ++ returnmsg = str(e) ++ self.close() ++ if val_t < 0: ++ return False, returnmsg or "" ++ return True, "" ++ ++ def read_word_data(self, i2c_addr, register, force=None): ++ """ ++ Read a single word (2 bytes) from a given register. ++ ++ :param i2c_addr: i2c address ++ :type i2c_addr: int ++ :param register: Register to read ++ :type register: int ++ :param force: ++ :type force: Boolean ++ :return: 2-byte word ++ :rtype: int ++ """ ++ val_t = -1 ++ returnmsg = "" ++ try: ++ self._set_address(i2c_addr, force=force) ++ msg = i2c_smbus_ioctl_data.create( ++ read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_WORD_DATA ++ ) ++ val_t = ioctl(self.fd, I2C_SMBUS, msg) ++ except Exception as e: ++ returnmsg = str(e) ++ self.close() ++ if val_t < 0: ++ return False, returnmsg or "" ++ return True, msg.data.contents.word ++ ++ def write_word_data_pec(self, i2c_addr, register, value, force=None): ++ """ ++ Write a byte to a given register. ++ ++ :param i2c_addr: i2c address ++ :type i2c_addr: int ++ :param register: Register to write to ++ :type register: int ++ :param value: Word value to transmit ++ :type value: int ++ :param force: ++ :type force: Boolean ++ :rtype: None ++ """ ++ val_t = -1 ++ returnmsg = "" ++ try: ++ val_t = ioctl(self.fd, I2C_PEC, 1) ++ if val_t < 0: ++ raise Exception("set pec mod error") ++ self._set_address(i2c_addr, force=force) ++ msg = i2c_smbus_ioctl_data.create( ++ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_WORD_DATA ++ ) ++ msg.data.contents.word = value ++ val_t = ioctl(self.fd, I2C_SMBUS, msg) ++ except Exception as e: ++ returnmsg = str(e) ++ self.close() ++ if val_t < 0: ++ return False, returnmsg or "" ++ return True, "" ++ ++ def write_word_data(self, i2c_addr, register, value, force=None): ++ """ ++ Write a byte to a given register. ++ ++ :param i2c_addr: i2c address ++ :type i2c_addr: int ++ :param register: Register to write to ++ :type register: int ++ :param value: Word value to transmit ++ :type value: int ++ :param force: ++ :type force: Boolean ++ :rtype: None ++ """ ++ val_t = -1 ++ returnmsg = "" ++ try: ++ self._set_address(i2c_addr, force=force) ++ msg = i2c_smbus_ioctl_data.create( ++ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_WORD_DATA ++ ) ++ msg.data.contents.word = value ++ val_t = ioctl(self.fd, I2C_SMBUS, msg) ++ except Exception as e: ++ returnmsg = str(e) ++ self.close() ++ if val_t < 0: ++ return False, returnmsg or "" ++ return True, "" ++ ++ def process_call(self, i2c_addr, register, value, force=None): ++ """ ++ Executes a SMBus Process Call, sending a 16-bit value and receiving a 16-bit response ++ ++ :param i2c_addr: i2c address ++ :type i2c_addr: int ++ :param register: Register to read/write to ++ :type register: int ++ :param value: Word value to transmit ++ :type value: int ++ :param force: ++ :type force: Boolean ++ :rtype: int ++ """ ++ self._set_address(i2c_addr, force=force) ++ msg = i2c_smbus_ioctl_data.create( ++ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_PROC_CALL ++ ) ++ msg.data.contents.word = value ++ ioctl(self.fd, I2C_SMBUS, msg) ++ return msg.data.contents.word ++ ++ def read_block_data(self, i2c_addr, register, force=None): ++ """ ++ Read a block of up to 32-bytes from a given register. ++ ++ :param i2c_addr: i2c address ++ :type i2c_addr: int ++ :param register: Start register ++ :type register: int ++ :param force: ++ :type force: Boolean ++ :return: List of bytes ++ :rtype: list ++ """ ++ self._set_address(i2c_addr, force=force) ++ msg = i2c_smbus_ioctl_data.create( ++ read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_BLOCK_DATA ++ ) ++ ioctl(self.fd, I2C_SMBUS, msg) ++ length = msg.data.contents.block[0] ++ return msg.data.contents.block[1:length + 1] ++ ++ def write_block_data(self, i2c_addr, register, data, force=None): ++ """ ++ Write a block of byte data to a given register. ++ ++ :param i2c_addr: i2c address ++ :type i2c_addr: int ++ :param register: Start register ++ :type register: int ++ :param data: List of bytes ++ :type data: list ++ :param force: ++ :type force: Boolean ++ :rtype: None ++ """ ++ length = len(data) ++ if length > I2C_SMBUS_BLOCK_MAX: ++ raise ValueError("Data length cannot exceed %d bytes" % I2C_SMBUS_BLOCK_MAX) ++ self._set_address(i2c_addr, force=force) ++ msg = i2c_smbus_ioctl_data.create( ++ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BLOCK_DATA ++ ) ++ msg.data.contents.block[0] = length ++ msg.data.contents.block[1:length + 1] = data ++ ioctl(self.fd, I2C_SMBUS, msg) ++ ++ def block_process_call(self, i2c_addr, register, data, force=None): ++ """ ++ Executes a SMBus Block Process Call, sending a variable-size data ++ block and receiving another variable-size response ++ ++ :param i2c_addr: i2c address ++ :type i2c_addr: int ++ :param register: Register to read/write to ++ :type register: int ++ :param data: List of bytes ++ :type data: list ++ :param force: ++ :type force: Boolean ++ :return: List of bytes ++ :rtype: list ++ """ ++ length = len(data) ++ if length > I2C_SMBUS_BLOCK_MAX: ++ raise ValueError("Data length cannot exceed %d bytes" % I2C_SMBUS_BLOCK_MAX) ++ self._set_address(i2c_addr, force=force) ++ msg = i2c_smbus_ioctl_data.create( ++ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BLOCK_PROC_CALL ++ ) ++ msg.data.contents.block[0] = length ++ msg.data.contents.block[1:length + 1] = data ++ ioctl(self.fd, I2C_SMBUS, msg) ++ length = msg.data.contents.block[0] ++ return msg.data.contents.block[1:length + 1] ++ ++ def read_i2c_block_data(self, i2c_addr, register, length, force=None): ++ """ ++ Read a block of byte data from a given register. ++ ++ :param i2c_addr: i2c address ++ :type i2c_addr: int ++ :param register: Start register ++ :type register: int ++ :param length: Desired block length ++ :type length: int ++ :param force: ++ :type force: Boolean ++ :return: List of bytes ++ :rtype: list ++ """ ++ if length > I2C_SMBUS_BLOCK_MAX: ++ raise ValueError("Desired block length over %d bytes" % I2C_SMBUS_BLOCK_MAX) ++ self._set_address(i2c_addr, force=force) ++ msg = i2c_smbus_ioctl_data.create( ++ read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_I2C_BLOCK_DATA ++ ) ++ msg.data.contents.byte = length ++ ioctl(self.fd, I2C_SMBUS, msg) ++ return msg.data.contents.block[1:length + 1] ++ ++ def write_i2c_block_data(self, i2c_addr, register, data, force=None): ++ """ ++ Write a block of byte data to a given register. ++ ++ :param i2c_addr: i2c address ++ :type i2c_addr: int ++ :param register: Start register ++ :type register: int ++ :param data: List of bytes ++ :type data: list ++ :param force: ++ :type force: Boolean ++ :rtype: None ++ """ ++ length = len(data) ++ if length > I2C_SMBUS_BLOCK_MAX: ++ raise ValueError("Data length cannot exceed %d bytes" % I2C_SMBUS_BLOCK_MAX) ++ self._set_address(i2c_addr, force=force) ++ msg = i2c_smbus_ioctl_data.create( ++ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_I2C_BLOCK_DATA ++ ) ++ msg.data.contents.block[0] = length ++ msg.data.contents.block[1:length + 1] = data ++ ioctl(self.fd, I2C_SMBUS, msg) ++ ++ def i2c_rdwr(self, *i2c_msgs): ++ """ ++ Combine a series of i2c read and write operations in a single ++ transaction (with repeated start bits but no stop bits in between). ++ ++ This method takes i2c_msg instances as input, which must be created ++ first with :py:meth:`i2c_msg.read` or :py:meth:`i2c_msg.write`. ++ ++ :param i2c_msgs: One or more i2c_msg class instances. ++ :type i2c_msgs: i2c_msg ++ :rtype: None ++ """ ++ ioctl_data = i2c_rdwr_ioctl_data.create(*i2c_msgs) ++ ioctl(self.fd, I2C_RDWR, ioctl_data) ++ ++ ++class SMBusWrapper: ++ """ ++ Wrapper class around the SMBus. ++ Deprecated as of version 0.3.0. Please replace with :py:class:`SMBus`. ++ ++ Enables the user to wrap access to the :py:class:`SMBus` class in a ++ "with" statement. If auto_cleanup is True (default), the ++ :py:class:`SMBus` handle will be automatically closed ++ upon exit of the ``with`` block. ++ """ ++ ++ def __init__(self, bus_number=0, auto_cleanup=True, force=False): ++ """ ++ :param auto_cleanup: Close bus when leaving scope. ++ :type auto_cleanup: Boolean ++ :param force: Force using the slave address even when driver is already using it. ++ :type force: Boolean ++ """ ++ self.bus_number = bus_number ++ self.auto_cleanup = auto_cleanup ++ self.force = force ++ self.bus = None ++ ++ def __enter__(self): ++ self.bus = SMBus(bus=self.bus_number, force=self.force) ++ return self.bus ++ ++ def __exit__(self, exc_type, exc_val, exc_tb): ++ if self.auto_cleanup: ++ self.bus.close() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modprobe_conf/kernel_drivers_blacklist.conf b/platform/broadcom/sonic-platform-modules-micas/common/modprobe_conf/kernel_drivers_blacklist.conf +new file mode 100644 +index 000000000..39d56582b +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modprobe_conf/kernel_drivers_blacklist.conf +@@ -0,0 +1,7 @@ ++blacklist wb_fpga_pcie ++blacklist wb_i2c_i801 ++blacklist wb_spi_gpio ++blacklist intel_spi ++blacklist intel_spi_platform ++blacklist wb_i2c_ismt ++blacklist intel_spi_pci +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/COPYING b/platform/broadcom/sonic-platform-modules-micas/common/modules/COPYING +new file mode 100644 +index 000000000..a635a38ef +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/COPYING +@@ -0,0 +1,20 @@ ++The Linux Kernel is provided under: ++ ++ SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note ++ ++Being under the terms of the GNU General Public License version 2 only, ++according with: ++ ++ LICENSES/preferred/GPL-2.0 ++ ++With an explicit syscall exception, as stated at: ++ ++ LICENSES/exceptions/Linux-syscall-note ++ ++In addition, other licenses may also apply. Please see: ++ ++ Documentation/process/license-rules.rst ++ ++for more details. ++ ++All contributions to the Linux Kernel are subject to this COPYING file. +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/GPL-2.0 b/platform/broadcom/sonic-platform-modules-micas/common/modules/GPL-2.0 +new file mode 100644 +index 000000000..ff0812fd8 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/GPL-2.0 +@@ -0,0 +1,359 @@ ++Valid-License-Identifier: GPL-2.0 ++Valid-License-Identifier: GPL-2.0-only ++Valid-License-Identifier: GPL-2.0+ ++Valid-License-Identifier: GPL-2.0-or-later ++SPDX-URL: https://spdx.org/licenses/GPL-2.0.html ++Usage-Guide: ++ To use this license in source code, put one of the following SPDX ++ tag/value pairs into a comment according to the placement ++ guidelines in the licensing rules documentation. ++ For 'GNU General Public License (GPL) version 2 only' use: ++ SPDX-License-Identifier: GPL-2.0 ++ or ++ SPDX-License-Identifier: GPL-2.0-only ++ For 'GNU General Public License (GPL) version 2 or any later version' use: ++ SPDX-License-Identifier: GPL-2.0+ ++ or ++ SPDX-License-Identifier: GPL-2.0-or-later ++License-Text: ++ ++ GNU GENERAL PUBLIC LICENSE ++ Version 2, June 1991 ++ ++ Copyright (C) 1989, 1991 Free Software Foundation, Inc. ++ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ Everyone is permitted to copy and distribute verbatim copies ++ of this license document, but changing it is not allowed. ++ ++ Preamble ++ ++ The licenses for most software are designed to take away your ++freedom to share and change it. By contrast, the GNU General Public ++License is intended to guarantee your freedom to share and change free ++software--to make sure the software is free for all its users. This ++General Public License applies to most of the Free Software ++Foundation's software and to any other program whose authors commit to ++using it. (Some other Free Software Foundation software is covered by ++the GNU Library General Public License instead.) You can apply it to ++your programs, too. ++ ++ When we speak of free software, we are referring to freedom, not ++price. Our General Public Licenses are designed to make sure that you ++have the freedom to distribute copies of free software (and charge for ++this service if you wish), that you receive source code or can get it ++if you want it, that you can change the software or use pieces of it ++in new free programs; and that you know you can do these things. ++ ++ To protect your rights, we need to make restrictions that forbid ++anyone to deny you these rights or to ask you to surrender the rights. ++These restrictions translate to certain responsibilities for you if you ++distribute copies of the software, or if you modify it. ++ ++ For example, if you distribute copies of such a program, whether ++gratis or for a fee, you must give the recipients all the rights that ++you have. You must make sure that they, too, receive or can get the ++source code. And you must show them these terms so they know their ++rights. ++ ++ We protect your rights with two steps: (1) copyright the software, and ++(2) offer you this license which gives you legal permission to copy, ++distribute and/or modify the software. ++ ++ Also, for each author's protection and ours, we want to make certain ++that everyone understands that there is no warranty for this free ++software. If the software is modified by someone else and passed on, we ++want its recipients to know that what they have is not the original, so ++that any problems introduced by others will not reflect on the original ++authors' reputations. ++ ++ Finally, any free program is threatened constantly by software ++patents. We wish to avoid the danger that redistributors of a free ++program will individually obtain patent licenses, in effect making the ++program proprietary. To prevent this, we have made it clear that any ++patent must be licensed for everyone's free use or not licensed at all. ++ ++ The precise terms and conditions for copying, distribution and ++modification follow. ++ ++ GNU GENERAL PUBLIC LICENSE ++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ++ ++ 0. This License applies to any program or other work which contains ++a notice placed by the copyright holder saying it may be distributed ++under the terms of this General Public License. The "Program", below, ++refers to any such program or work, and a "work based on the Program" ++means either the Program or any derivative work under copyright law: ++that is to say, a work containing the Program or a portion of it, ++either verbatim or with modifications and/or translated into another ++language. (Hereinafter, translation is included without limitation in ++the term "modification".) Each licensee is addressed as "you". ++ ++Activities other than copying, distribution and modification are not ++covered by this License; they are outside its scope. The act of ++running the Program is not restricted, and the output from the Program ++is covered only if its contents constitute a work based on the ++Program (independent of having been made by running the Program). ++Whether that is true depends on what the Program does. ++ ++ 1. You may copy and distribute verbatim copies of the Program's ++source code as you receive it, in any medium, provided that you ++conspicuously and appropriately publish on each copy an appropriate ++copyright notice and disclaimer of warranty; keep intact all the ++notices that refer to this License and to the absence of any warranty; ++and give any other recipients of the Program a copy of this License ++along with the Program. ++ ++You may charge a fee for the physical act of transferring a copy, and ++you may at your option offer warranty protection in exchange for a fee. ++ ++ 2. You may modify your copy or copies of the Program or any portion ++of it, thus forming a work based on the Program, and copy and ++distribute such modifications or work under the terms of Section 1 ++above, provided that you also meet all of these conditions: ++ ++ a) You must cause the modified files to carry prominent notices ++ stating that you changed the files and the date of any change. ++ ++ b) You must cause any work that you distribute or publish, that in ++ whole or in part contains or is derived from the Program or any ++ part thereof, to be licensed as a whole at no charge to all third ++ parties under the terms of this License. ++ ++ c) If the modified program normally reads commands interactively ++ when run, you must cause it, when started running for such ++ interactive use in the most ordinary way, to print or display an ++ announcement including an appropriate copyright notice and a ++ notice that there is no warranty (or else, saying that you provide ++ a warranty) and that users may redistribute the program under ++ these conditions, and telling the user how to view a copy of this ++ License. (Exception: if the Program itself is interactive but ++ does not normally print such an announcement, your work based on ++ the Program is not required to print an announcement.) ++ ++These requirements apply to the modified work as a whole. If ++identifiable sections of that work are not derived from the Program, ++and can be reasonably considered independent and separate works in ++themselves, then this License, and its terms, do not apply to those ++sections when you distribute them as separate works. But when you ++distribute the same sections as part of a whole which is a work based ++on the Program, the distribution of the whole must be on the terms of ++this License, whose permissions for other licensees extend to the ++entire whole, and thus to each and every part regardless of who wrote it. ++ ++Thus, it is not the intent of this section to claim rights or contest ++your rights to work written entirely by you; rather, the intent is to ++exercise the right to control the distribution of derivative or ++collective works based on the Program. ++ ++In addition, mere aggregation of another work not based on the Program ++with the Program (or with a work based on the Program) on a volume of ++a storage or distribution medium does not bring the other work under ++the scope of this License. ++ ++ 3. You may copy and distribute the Program (or a work based on it, ++under Section 2) in object code or executable form under the terms of ++Sections 1 and 2 above provided that you also do one of the following: ++ ++ a) Accompany it with the complete corresponding machine-readable ++ source code, which must be distributed under the terms of Sections ++ 1 and 2 above on a medium customarily used for software interchange; or, ++ ++ b) Accompany it with a written offer, valid for at least three ++ years, to give any third party, for a charge no more than your ++ cost of physically performing source distribution, a complete ++ machine-readable copy of the corresponding source code, to be ++ distributed under the terms of Sections 1 and 2 above on a medium ++ customarily used for software interchange; or, ++ ++ c) Accompany it with the information you received as to the offer ++ to distribute corresponding source code. (This alternative is ++ allowed only for noncommercial distribution and only if you ++ received the program in object code or executable form with such ++ an offer, in accord with Subsection b above.) ++ ++The source code for a work means the preferred form of the work for ++making modifications to it. For an executable work, complete source ++code means all the source code for all modules it contains, plus any ++associated interface definition files, plus the scripts used to ++control compilation and installation of the executable. However, as a ++special exception, the source code distributed need not include ++anything that is normally distributed (in either source or binary ++form) with the major components (compiler, kernel, and so on) of the ++operating system on which the executable runs, unless that component ++itself accompanies the executable. ++ ++If distribution of executable or object code is made by offering ++access to copy from a designated place, then offering equivalent ++access to copy the source code from the same place counts as ++distribution of the source code, even though third parties are not ++compelled to copy the source along with the object code. ++ ++ 4. You may not copy, modify, sublicense, or distribute the Program ++except as expressly provided under this License. Any attempt ++otherwise to copy, modify, sublicense or distribute the Program is ++void, and will automatically terminate your rights under this License. ++However, parties who have received copies, or rights, from you under ++this License will not have their licenses terminated so long as such ++parties remain in full compliance. ++ ++ 5. You are not required to accept this License, since you have not ++signed it. However, nothing else grants you permission to modify or ++distribute the Program or its derivative works. These actions are ++prohibited by law if you do not accept this License. Therefore, by ++modifying or distributing the Program (or any work based on the ++Program), you indicate your acceptance of this License to do so, and ++all its terms and conditions for copying, distributing or modifying ++the Program or works based on it. ++ ++ 6. Each time you redistribute the Program (or any work based on the ++Program), the recipient automatically receives a license from the ++original licensor to copy, distribute or modify the Program subject to ++these terms and conditions. You may not impose any further ++restrictions on the recipients' exercise of the rights granted herein. ++You are not responsible for enforcing compliance by third parties to ++this License. ++ ++ 7. If, as a consequence of a court judgment or allegation of patent ++infringement or for any other reason (not limited to patent issues), ++conditions are imposed on you (whether by court order, agreement or ++otherwise) that contradict the conditions of this License, they do not ++excuse you from the conditions of this License. If you cannot ++distribute so as to satisfy simultaneously your obligations under this ++License and any other pertinent obligations, then as a consequence you ++may not distribute the Program at all. For example, if a patent ++license would not permit royalty-free redistribution of the Program by ++all those who receive copies directly or indirectly through you, then ++the only way you could satisfy both it and this License would be to ++refrain entirely from distribution of the Program. ++ ++If any portion of this section is held invalid or unenforceable under ++any particular circumstance, the balance of the section is intended to ++apply and the section as a whole is intended to apply in other ++circumstances. ++ ++It is not the purpose of this section to induce you to infringe any ++patents or other property right claims or to contest validity of any ++such claims; this section has the sole purpose of protecting the ++integrity of the free software distribution system, which is ++implemented by public license practices. Many people have made ++generous contributions to the wide range of software distributed ++through that system in reliance on consistent application of that ++system; it is up to the author/donor to decide if he or she is willing ++to distribute software through any other system and a licensee cannot ++impose that choice. ++ ++This section is intended to make thoroughly clear what is believed to ++be a consequence of the rest of this License. ++ ++ 8. If the distribution and/or use of the Program is restricted in ++certain countries either by patents or by copyrighted interfaces, the ++original copyright holder who places the Program under this License ++may add an explicit geographical distribution limitation excluding ++those countries, so that distribution is permitted only in or among ++countries not thus excluded. In such case, this License incorporates ++the limitation as if written in the body of this License. ++ ++ 9. The Free Software Foundation may publish revised and/or new versions ++of the General Public License from time to time. Such new versions will ++be similar in spirit to the present version, but may differ in detail to ++address new problems or concerns. ++ ++Each version is given a distinguishing version number. If the Program ++specifies a version number of this License which applies to it and "any ++later version", you have the option of following the terms and conditions ++either of that version or of any later version published by the Free ++Software Foundation. If the Program does not specify a version number of ++this License, you may choose any version ever published by the Free Software ++Foundation. ++ ++ 10. If you wish to incorporate parts of the Program into other free ++programs whose distribution conditions are different, write to the author ++to ask for permission. For software which is copyrighted by the Free ++Software Foundation, write to the Free Software Foundation; we sometimes ++make exceptions for this. Our decision will be guided by the two goals ++of preserving the free status of all derivatives of our free software and ++of promoting the sharing and reuse of software generally. ++ ++ NO WARRANTY ++ ++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY ++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN ++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES ++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED ++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS ++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE ++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, ++REPAIR OR CORRECTION. ++ ++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR ++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, ++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING ++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED ++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY ++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER ++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE ++POSSIBILITY OF SUCH DAMAGES. ++ ++ END OF TERMS AND CONDITIONS ++ ++ How to Apply These Terms to Your New Programs ++ ++ If you develop a new program, and you want it to be of the greatest ++possible use to the public, the best way to achieve this is to make it ++free software which everyone can redistribute and change under these terms. ++ ++ To do so, attach the following notices to the program. It is safest ++to attach them to the start of each source file to most effectively ++convey the exclusion of warranty; and each file should have at least ++the "copyright" line and a pointer to where the full notice is found. ++ ++ ++ Copyright (C) ++ ++ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ ++ ++Also add information on how to contact you by electronic and paper mail. ++ ++If the program is interactive, make it output a short notice like this ++when it starts in an interactive mode: ++ ++ Gnomovision version 69, Copyright (C) year name of author ++ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. ++ This is free software, and you are welcome to redistribute it ++ under certain conditions; type `show c' for details. ++ ++The hypothetical commands `show w' and `show c' should show the appropriate ++parts of the General Public License. Of course, the commands you use may ++be called something other than `show w' and `show c'; they could even be ++mouse-clicks or menu items--whatever suits your program. ++ ++You should also get your employer (if you work as a programmer) or your ++school, if any, to sign a "copyright disclaimer" for the program, if ++necessary. Here is a sample; alter the names: ++ ++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program ++ `Gnomovision' (which makes passes at compilers) written by James Hacker. ++ ++ , 1 April 1989 ++ Ty Coon, President of Vice ++ ++This General Public License does not permit incorporating your program into ++proprietary programs. If your program is a subroutine library, you may ++consider it more useful to permit linking proprietary applications with the ++library. If this is what you want to do, use the GNU Library General ++Public License instead of this License. +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/Makefile +new file mode 100644 +index 000000000..293750591 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/Makefile +@@ -0,0 +1,62 @@ ++PWD = $(shell pwd) ++EXTRA_CFLAGS:= -I$(M)/include ++EXTRA_CFLAGS+= -Wall ++KVERSION ?= $(shell uname -r) ++KERNEL_SRC ?= /lib/modules/$(KVERSION) ++ ++module_out_put_dir := $(PWD)/build ++export module_out_put_dir ++ ++KERNEL_MODULES_SRC = $(PWD)/linux-5.10 ++ ++PLAT_SYSFS_DIR = $(PWD)/plat_sysfs ++INTEL_SPI = $(PWD)/intel_spi ++PHY = $(PWD)/phy ++PINCTRL = $(PWD)/pinctrl ++SDHCI = $(PWD)/sdhci ++ ++export PLAT_SYSFS_DIR ++ ++platform_common-objs := platform_common_module.o dfd_tlveeprom.o ++obj-m += platform_common.o ++obj-m += wb_mac_bsc.o ++obj-m += wb_fpga_pcie.o ++obj-m += wb_pcie_dev.o ++obj-m += wb_fpga_i2c_bus_drv.o ++obj-m += wb_fpga_pca954x_drv.o ++obj-m += wb_lpc_drv.o ++obj-m += wb_i2c_dev.o ++obj-m += wb_platform_i2c_dev.o ++obj-m += wb_io_dev.o ++obj-m += wb_eeprom_93xx46.o ++obj-m += wb_spi_93xx46.o ++obj-m += wb_gpio_d1500.o ++obj-m += wb_gpio_device.o ++obj-m += wb_i2c_ocores.o ++obj-m += wb_spi_ocores.o ++obj-m += wb_spi_dev.o ++obj-m += wb_wdt.o ++obj-m += wb_optoe.o ++obj-m += wb_spi_gpio.o ++obj-m += wb_spi_gpio_device.o ++obj-m += wb_spi_nor_device.o ++obj-m += wb_xdpe132g5c.o ++obj-m += wb_uio_irq.o ++obj-m += hw_test.o ++ ++all : ++ $(MAKE) -C $(KERNEL_MODULES_SRC) ++ $(MAKE) -C $(PLAT_SYSFS_DIR) ++ $(MAKE) -C $(INTEL_SPI) ++ $(MAKE) -C $(PHY) ++ $(MAKE) -C $(PINCTRL) ++ $(MAKE) -C $(SDHCI) ++ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules ++ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi ++ cp -p $(PWD)/*.ko $(module_out_put_dir) ++ ++clean : ++ rm -rf $(module_out_put_dir) ++ rm -f ${PWD}/*.o ${PWD}/*.ko ${PWD}/*.mod.c ${PWD}/.*.cmd ${PWD}/.*.o.d ${PWD}/*.mod ++ rm -f ${PWD}/Module.markers ${PWD}/Module.symvers ${PWD}/modules.order ++ rm -rf ${PWD}/.tmp_versions +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.c +new file mode 100644 +index 000000000..0d6f38ecc +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.c +@@ -0,0 +1,516 @@ ++/* ++ * Copyright (C) 2003-2014 FreeIPMI Core Team ++ * ++ * 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 ++ * (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, see . ++ * ++ */ ++/*****************************************************************************\ ++ * Copyright (C) 2007-2014 Lawrence Livermore National Security, LLC. ++ * Copyright (C) 2007 The Regents of the University of California. ++ * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). ++ * Written by Albert Chu ++ * UCRL-CODE-232183 ++ * ++ * This file is part of Ipmi-fru, a tool used for retrieving ++ * motherboard field replaceable unit (FRU) information. For details, ++ * see http://www.llnl.gov/linux/. ++ * ++ * Ipmi-fru 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 (at your ++ * option) any later version. ++ * ++ * Ipmi-fru 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 Ipmi-fru. If not, see . ++\*****************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "platform_common.h" ++#include "dfd_tlveeprom.h" ++ ++/* using in is_valid_tlvinfo_header */ ++static u_int32_t eeprom_size; ++ ++/* ++ * List of TLV codes and names. ++ */ ++static const struct tlv_code_desc tlv_code_list[] = { ++ { TLV_CODE_PRODUCT_NAME , "Product Name"}, ++ { TLV_CODE_PART_NUMBER , "Part Number"}, ++ { TLV_CODE_SERIAL_NUMBER , "Serial Number"}, ++ { TLV_CODE_MAC_BASE , "Base MAC Address"}, ++ { TLV_CODE_MANUF_DATE , "Manufacture Date"}, ++ { TLV_CODE_DEVICE_VERSION , "Device Version"}, ++ { TLV_CODE_LABEL_REVISION , "Label Revision"}, ++ { TLV_CODE_PLATFORM_NAME , "Platform Name"}, ++ { TLV_CODE_ONIE_VERSION , "ONIE Version"}, ++ { TLV_CODE_MAC_SIZE , "MAC Addresses"}, ++ { TLV_CODE_MANUF_NAME , "Manufacturer"}, ++ { TLV_CODE_MANUF_COUNTRY , "Country Code"}, ++ { TLV_CODE_VENDOR_NAME , "Vendor Name"}, ++ { TLV_CODE_DIAG_VERSION , "Diag Version"}, ++ { TLV_CODE_SERVICE_TAG , "Service Tag"}, ++ { TLV_CODE_VENDOR_EXT , "Vendor Extension"}, ++ { TLV_CODE_CRC_32 , "CRC-32"}, ++}; ++ ++#if 0 ++#define OPENBMC_VPD_KEY_INVAIL_VAL 0 ++ ++static const tlv_code_map_t tlv_code_map[] = { ++ { TLV_CODE_PRODUCT_NAME , OPENBMC_VPD_KEY_PRODUCT_NAME}, ++ { TLV_CODE_PART_NUMBER , OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM}, ++ { TLV_CODE_SERIAL_NUMBER , OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM}, ++ { TLV_CODE_MAC_BASE , OPENBMC_VPD_KEY_INVAIL_VAL}, ++ { TLV_CODE_MANUF_DATE , OPENBMC_VPD_KEY_BOARD_MFG_DATE}, ++ { TLV_CODE_DEVICE_VERSION , OPENBMC_VPD_KEY_PRODUCT_VER}, ++ { TLV_CODE_LABEL_REVISION , OPENBMC_VPD_KEY_PRODUCT_CUSTOM7}, ++ { TLV_CODE_PLATFORM_NAME , OPENBMC_VPD_KEY_PRODUCT_CUSTOM1}, ++ { TLV_CODE_ONIE_VERSION , OPENBMC_VPD_KEY_PRODUCT_CUSTOM2}, ++ { TLV_CODE_MAC_SIZE , OPENBMC_VPD_KEY_INVAIL_VAL}, ++ { TLV_CODE_MANUF_NAME , OPENBMC_VPD_KEY_PRODUCT_MFR}, ++ { TLV_CODE_MANUF_COUNTRY , OPENBMC_VPD_KEY_PRODUCT_CUSTOM3}, ++ { TLV_CODE_VENDOR_NAME , OPENBMC_VPD_KEY_PRODUCT_CUSTOM4}, ++ { TLV_CODE_DIAG_VERSION , OPENBMC_VPD_KEY_PRODUCT_CUSTOM8}, ++ { TLV_CODE_SERVICE_TAG , OPENBMC_VPD_KEY_PRODUCT_CUSTOM5}, ++ { TLV_CODE_VENDOR_EXT , OPENBMC_VPD_KEY_PRODUCT_CUSTOM6}, ++ { TLV_CODE_CRC_32 , OPENBMC_VPD_KEY_INVAIL_VAL}, ++}; ++#endif ++ ++#define TLV_CODE_NUM (sizeof(tlv_code_list) / sizeof(tlv_code_list[0])) ++ ++#if 0 ++#define TLV_CODE_MAP_NUM (sizeof(tlv_code_map) / sizeof(tlv_code_map[0])) ++#endif ++ ++const unsigned long crc_table[] = { ++ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, ++ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, ++ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, ++ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, ++ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, ++ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, ++ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, ++ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, ++ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, ++ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, ++ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, ++ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, ++ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, ++ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, ++ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, ++ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, ++ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, ++ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, ++ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, ++ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, ++ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, ++ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, ++ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, ++ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, ++ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, ++ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, ++ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, ++ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, ++ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, ++ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, ++ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, ++ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, ++}; ++ ++static unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned len) ++{ ++ unsigned i; ++ if (len < 1) ++ return 0xffffffff; ++ ++ for (i = 0; i != len; ++i) ++ { ++ crc = crc_table[(crc ^ buf[i]) & 0xff] ^ (crc >> 8); ++ } ++ ++ crc = crc ^ 0xffffffff; ++ ++ return crc; ++} ++ ++/* ++ * is_valid_tlv ++ * ++ * Perform basic sanity checks on a TLV field. The TLV is pointed to ++ * by the parameter provided. ++ * 1. The type code is not reserved (0x00 or 0xFF) ++ */ ++static inline bool is_valid_tlv(tlvinfo_tlv_t *tlv) ++{ ++ return ((tlv->type != 0x00) && (tlv->type != 0xFF)); ++} ++ ++/* ++ * is_valid_tlvinfo_header ++ * ++ * Perform sanity checks on the first 11 bytes of the TlvInfo EEPROM ++ * data pointed to by the parameter: ++ * 1. First 8 bytes contain null-terminated ASCII string "TlvInfo" ++ * 2. Version byte is 1 ++ * 3. Total length bytes contain value which is less than or equal ++ * to the allowed maximum (2048-11) ++ * ++ */ ++static inline bool is_valid_tlvinfo_header(tlvinfo_header_t *hdr) ++{ ++ int max_size = eeprom_size; ++ return((strcmp(hdr->signature, TLV_INFO_ID_STRING) == 0) && ++ (hdr->version == TLV_INFO_VERSION) && ++ (be16_to_cpu(hdr->totallen) <= max_size) ); ++} ++ ++/* ++ * decode_tlv_value ++ * ++ * Decode a single TLV value into a string. ++ ++ * The validity of EEPROM contents and the TLV field have been verified ++ * prior to calling this function. ++ */ ++static void decode_tlv_value(tlvinfo_tlv_t *tlv, tlv_decode_value_t *decode_value) ++{ ++ int i; ++ char *value; ++ u_int32_t length; ++ ++ value = (char *)decode_value->value; ++ ++ switch (tlv->type) { ++ case TLV_CODE_PRODUCT_NAME: ++ case TLV_CODE_PART_NUMBER: ++ case TLV_CODE_SERIAL_NUMBER: ++ case TLV_CODE_MANUF_DATE: ++ case TLV_CODE_LABEL_REVISION: ++ case TLV_CODE_PLATFORM_NAME: ++ case TLV_CODE_ONIE_VERSION: ++ case TLV_CODE_MANUF_NAME: ++ case TLV_CODE_MANUF_COUNTRY: ++ case TLV_CODE_VENDOR_NAME: ++ case TLV_CODE_DIAG_VERSION: ++ case TLV_CODE_SERVICE_TAG: ++ case TLV_CODE_VENDOR_EXT: ++ memcpy(value, tlv->value, tlv->length); ++ value[tlv->length] = 0; ++ length = tlv->length; ++ break; ++ case TLV_CODE_MAC_BASE: ++ length = sprintf(value, "%02X:%02X:%02X:%02X:%02X:%02X", ++ tlv->value[0], tlv->value[1], tlv->value[2], ++ tlv->value[3], tlv->value[4], tlv->value[5]); ++ break; ++ case TLV_CODE_DEVICE_VERSION: ++ length = sprintf(value, "%u", tlv->value[0]); ++ break; ++ case TLV_CODE_MAC_SIZE: ++ length = sprintf(value, "%u", (tlv->value[0] << 8) | tlv->value[1]); ++ break; ++ #if 0 ++ case TLV_CODE_VENDOR_EXT: ++ value[0] = 0; ++ length = 0; ++ for (i = 0; (i < (TLV_DECODE_VALUE_MAX_LEN/5)) && (i < tlv->length); i++) { ++ length += sprintf(value, "%s 0x%02X", value, tlv->value[i]); ++ } ++ break; ++ #endif ++ case TLV_CODE_CRC_32: ++ length = sprintf(value, "0x%02X%02X%02X%02X", tlv->value[0], ++ tlv->value[1], tlv->value[2], tlv->value[3]); ++ break; ++ default: ++ value[0] = 0; ++ length = 0; ++ for (i = 0; (i < (TLV_DECODE_VALUE_MAX_LEN/5)) && (i < tlv->length); i++) { ++ length += sprintf(value, "%s 0x%02X", value, tlv->value[i]); ++ } ++ break; ++ } ++ ++ decode_value->length = length; ++} ++ ++/* ++ * is_checksum_valid ++ * ++ * Validate the checksum in the provided TlvInfo EEPROM data. First, ++ * verify that the TlvInfo header is valid, then make sure the last ++ * TLV is a CRC-32 TLV. Then calculate the CRC over the EEPROM data ++ * and compare it to the value stored in the EEPROM CRC-32 TLV. ++ */ ++static bool is_checksum_valid(u_int8_t *eeprom) ++{ ++ tlvinfo_header_t *eeprom_hdr; ++ tlvinfo_tlv_t *eeprom_crc; ++ unsigned int calc_crc; ++ unsigned int stored_crc; ++ ++ eeprom_hdr = (tlvinfo_header_t *) eeprom; ++ ++ // Is the eeprom header valid? ++ if (!is_valid_tlvinfo_header(eeprom_hdr)) { ++ return false; ++ } ++ ++ // Is the last TLV a CRC? ++ eeprom_crc = (tlvinfo_tlv_t *) &eeprom[sizeof(tlvinfo_header_t) + ++ be16_to_cpu(eeprom_hdr->totallen) - (sizeof(tlvinfo_tlv_t) + 4)]; ++ if ((eeprom_crc->type != TLV_CODE_CRC_32) || (eeprom_crc->length != 4)) { ++ return false; ++ } ++ ++ // Calculate the checksum ++ calc_crc = crc32(0xffffffffL, (const unsigned char *)eeprom, sizeof(tlvinfo_header_t) + ++ be16_to_cpu(eeprom_hdr->totallen) - 4); ++ stored_crc = ((eeprom_crc->value[0] << 24) | (eeprom_crc->value[1] << 16) | ++ (eeprom_crc->value[2] << 8) | eeprom_crc->value[3]); ++ ++ return (calc_crc == stored_crc); ++} ++ ++/* ++ * tlvinfo_find_tlv ++ * ++ * This function finds the TLV with the supplied code in the EERPOM. ++ * An offset from the beginning of the EEPROM is returned in the ++ * eeprom_index parameter if the TLV is found. ++ */ ++static bool tlvinfo_find_tlv(u_int8_t *eeprom, u_int8_t tcode, int *eeprom_index) ++{ ++ tlvinfo_header_t *eeprom_hdr; ++ tlvinfo_tlv_t *eeprom_tlv; ++ int eeprom_end; ++ ++ eeprom_hdr = (tlvinfo_header_t *) eeprom; ++ ++ // Search through the TLVs, looking for the first one which matches the ++ // supplied type code. ++ *eeprom_index = sizeof(tlvinfo_header_t); ++ eeprom_end = sizeof(tlvinfo_header_t) + be16_to_cpu(eeprom_hdr->totallen); ++ while (*eeprom_index < eeprom_end) { ++ eeprom_tlv = (tlvinfo_tlv_t *) &eeprom[*eeprom_index]; ++ if (!is_valid_tlv(eeprom_tlv)) { ++ return false; ++ } ++ ++ if (eeprom_tlv->type == tcode) { ++ return true; ++ } ++ ++ *eeprom_index += sizeof(tlvinfo_tlv_t) + eeprom_tlv->length; ++ } ++ ++ return false; ++} ++ ++/* ++ * tlvinfo_decode_tlv ++ * ++ * This function finds the TLV with the supplied code in the EERPOM ++ * and decodes the value into the buffer provided. ++ */ ++static bool tlvinfo_decode_tlv(u_int8_t *eeprom, u_int8_t tcode, tlv_decode_value_t *decode_value) ++{ ++ int eeprom_index; ++ tlvinfo_tlv_t *eeprom_tlv; ++ ++ // Find the TLV and then decode it ++ if (tlvinfo_find_tlv(eeprom, tcode, &eeprom_index)) { ++ eeprom_tlv = (tlvinfo_tlv_t *) &eeprom[eeprom_index]; ++ decode_tlv_value(eeprom_tlv, decode_value); ++ return true; ++ } ++ ++ return false; ++} ++ ++/* ++ * parse_tlv_eeprom ++ * ++ * parse the EEPROM into memory, if it hasn't already been read. ++ */ ++int parse_tlv_eeprom(u_int8_t *eeprom, u_int32_t size) ++{ ++ unsigned int i; ++ bool ret; ++ tlvinfo_header_t *eeprom_hdr; ++ //tlv_info_vec_t tlv_info; ++ tlv_decode_value_t decode_value; ++ int j; ++ ++ eeprom_hdr = (tlvinfo_header_t *) eeprom; ++ eeprom_size = size; /* eeprom real size */ ++ ++ if (!is_valid_tlvinfo_header(eeprom_hdr)) { ++ DBG_ERROR("Failed to check tlv header.\n"); ++ return -1; ++ } ++ ++ if (!is_checksum_valid(eeprom)) { ++ DBG_ERROR("Failed to check tlv crc.\n"); ++ return -1; ++ } ++ ++ for (i = 0; i < TLV_CODE_NUM; i++) { ++ mem_clear((void *)&decode_value, sizeof(tlv_decode_value_t)); ++ ret = tlvinfo_decode_tlv(eeprom, tlv_code_list[i].m_code, &decode_value); ++ if (!ret) { ++ DBG_ERROR("No found type: %s\n", tlv_code_list[i].m_name); ++ continue; ++ } ++ ++ DBG_DEBUG("i: %d,Found type: %s tlv[%d]:%s\n", i, tlv_code_list[i].m_name, tlv_code_list[i].m_code, ++ decode_value.value); ++ for (j = 0; j < decode_value.length; j++) { ++ if ((j % 16) == 0) { ++ DBG_DEBUG("\n"); ++ } ++ DBG_DEBUG("%02x ", decode_value.value[j]); ++ } ++ DBG_DEBUG("\n\n"); ++ } ++ return 0; ++} ++static int dfd_parse_tlv_eeprom(u_int8_t *eeprom, u_int32_t size, u_int8_t main_type, tlv_decode_value_t *decode_value) ++{ ++ bool ret; ++ tlvinfo_header_t *eeprom_hdr; ++ //tlv_info_vec_t tlv_info; ++ int j; ++ ++ eeprom_hdr = (tlvinfo_header_t *) eeprom; ++ eeprom_size = size; /* eeprom real size */ ++ ++ if (!is_valid_tlvinfo_header(eeprom_hdr)) { ++ DBG_ERROR("Failed to check tlv header.\n"); ++ return -1; ++ } ++ ++ if (!is_checksum_valid(eeprom)) { ++ DBG_ERROR("Failed to check tlv crc.\n"); ++ return -1; ++ } ++ ++ ret = tlvinfo_decode_tlv(eeprom, main_type, decode_value); ++ if (!ret) { ++ DBG_ERROR("No found type: %d\n", main_type); ++ return -1; ++ } ++ ++ DBG_DEBUG("Found type: %d, value: %s\n", main_type,decode_value->value); ++ for (j = 0; j < decode_value->length; j++) { ++ if ((j % 16) == 0) { ++ DBG_DEBUG("\n"); ++ } ++ DBG_DEBUG("%02x ", decode_value->value[j]); ++ } ++ DBG_DEBUG("\n\n"); ++ ++ return 0; ++} ++ ++static int tlvinfo_find_wb_ext_tlv(tlv_decode_value_t *ext_tlv_value, u_int8_t ext_type, ++ u_int8_t *buf, u_int8_t *buf_len) ++{ ++ tlvinfo_tlv_t *eeprom_tlv; ++ int eeprom_end, eeprom_index; ++ ++ // Search through the TLVs, looking for the first one which matches the ++ // supplied type code. ++ DBG_DEBUG("ext_tlv_value->length: %d.\n", ext_tlv_value->length); ++ for (eeprom_index = 0; eeprom_index < ext_tlv_value->length; eeprom_index++) { ++ if ((eeprom_index % 16) == 0) { ++ DBG_DEBUG("\n"); ++ } ++ DBG_DEBUG("%02x ", ext_tlv_value->value[eeprom_index]); ++ } ++ ++ DBG_DEBUG("\n"); ++ ++ eeprom_index = 0; ++ eeprom_end = ext_tlv_value->length; ++ while (eeprom_index < eeprom_end) { ++ eeprom_tlv = (tlvinfo_tlv_t *) &(ext_tlv_value->value[eeprom_index]); ++ if (!is_valid_tlv(eeprom_tlv)) { ++ DBG_ERROR("tlv is not valid, eeprom_tlv->type 0x%x.\n", eeprom_tlv->type); ++ return -1; ++ } ++ ++ DBG_DEBUG("eeprom_tlv->length %d.\n", eeprom_tlv->length); ++ if (eeprom_tlv->type == ext_type) { ++ if (*buf_len >= eeprom_tlv->length) { ++ memcpy(buf, eeprom_tlv->value, eeprom_tlv->length); ++ DBG_DEBUG("eeprom_tlv->length %d.\n", eeprom_tlv->length); ++ *buf_len = eeprom_tlv->length; ++ return 0; ++ } ++ DBG_ERROR("buf_len %d small than info_len %d.\n", *buf_len, eeprom_tlv->length); ++ return -1; ++ } ++ ++ eeprom_index += sizeof(tlvinfo_tlv_t) + eeprom_tlv->length; ++ } ++ ++ DBG_ERROR("ext_type %d: tlv is not found.\n", ext_type); ++ return -1; ++} ++ ++int dfd_tlvinfo_get_e2prom_info(u_int8_t *eeprom, u_int32_t size, dfd_tlv_type_t *tlv_type, u_int8_t* buf, u_int8_t *buf_len) ++{ ++ tlv_decode_value_t decode_value; ++ int ret; ++ ++ if (eeprom == NULL || tlv_type == NULL || buf == NULL) { ++ DBG_ERROR("Input para invalid.\n"); ++ return -1; ++ } ++ ++ mem_clear((void *)&decode_value, sizeof(tlv_decode_value_t)); ++ ret = dfd_parse_tlv_eeprom(eeprom, size, tlv_type->main_type, &decode_value); ++ if (ret) { ++ DBG_ERROR("dfd_parse_tlv_eeprom failed ret %d.\n", ret); ++ return ret; ++ } ++ ++ if (tlv_type->main_type != TLV_CODE_VENDOR_EXT) { ++ if (*buf_len >= decode_value.length) { ++ memcpy(buf, decode_value.value, decode_value.length); ++ *buf_len = decode_value.length; ++ return 0; ++ } ++ DBG_ERROR("buf_len %d small than info_len %d.\n", *buf_len, decode_value.length); ++ return -1; ++ } ++ DBG_DEBUG("info_len %d.\n", decode_value.length); ++ ++ return tlvinfo_find_wb_ext_tlv(&decode_value, tlv_type->ext_type, buf, buf_len); ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.h +new file mode 100644 +index 000000000..6eaac5848 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.h +@@ -0,0 +1,121 @@ ++#ifndef DFD_OPENBMC_TLVEEPROM_H ++#define DFD_OPENBMC_TLVEEPROM_H ++ ++#ifndef u_int8_t ++#define u_int8_t unsigned char ++#endif ++ ++#ifndef u_int16_t ++#define u_int16_t unsigned short ++#endif ++ ++#ifndef u_int32_t ++#define u_int32_t unsigned int ++#endif ++ ++#ifndef be16_to_cpu ++#define be16_to_cpu(x) ntohs(x) ++#endif ++ ++#ifndef cpu_to_be16 ++#define cpu_to_be16(x) htons(x) ++#endif ++ ++/** ++ * The TLV Types. ++ * ++ * Keep these in sync with tlv_code_list in cmd_sys_eeprom.c ++ */ ++#define TLV_CODE_PRODUCT_NAME 0x21 ++#define TLV_CODE_PART_NUMBER 0x22 ++#define TLV_CODE_SERIAL_NUMBER 0x23 ++#define TLV_CODE_MAC_BASE 0x24 ++#define TLV_CODE_MANUF_DATE 0x25 ++#define TLV_CODE_DEVICE_VERSION 0x26 ++#define TLV_CODE_LABEL_REVISION 0x27 ++#define TLV_CODE_PLATFORM_NAME 0x28 ++#define TLV_CODE_ONIE_VERSION 0x29 ++#define TLV_CODE_MAC_SIZE 0x2A ++#define TLV_CODE_MANUF_NAME 0x2B ++#define TLV_CODE_MANUF_COUNTRY 0x2C ++#define TLV_CODE_VENDOR_NAME 0x2D ++#define TLV_CODE_DIAG_VERSION 0x2E ++#define TLV_CODE_SERVICE_TAG 0x2F ++#define TLV_CODE_VENDOR_EXT 0xFD ++#define TLV_CODE_CRC_32 0xFE ++ ++#define TLV_CODE_NAME_LEN 64 ++/* ++ * Struct for displaying the TLV codes and names. ++ */ ++struct tlv_code_desc { ++ u_int8_t m_code; ++ char m_name[TLV_CODE_NAME_LEN]; ++}; ++ ++typedef struct dfd_tlv_type_s { ++ u_int8_t main_type; ++ u_int8_t ext_type; ++} dfd_tlv_type_t; ++ ++// Header Field Constants ++#define TLV_INFO_ID_STRING "TlvInfo" ++#define TLV_INFO_VERSION 0x01 ++/*#define TLV_TOTAL_LEN_MAX (XXXXXXXX - sizeof(tlvinfo_header_t))*/ ++ ++struct __attribute__ ((__packed__)) tlvinfo_header_s { ++ char signature[8]; /* 0x00 - 0x07 EEPROM Tag "TlvInfo" */ ++ u_int8_t version; /* 0x08 Structure version */ ++ u_int16_t totallen; /* 0x09 - 0x0A Length of all data which follows */ ++}; ++typedef struct tlvinfo_header_s tlvinfo_header_t; ++ ++/* ++ * TlvInfo TLV: Layout of a TLV field ++ */ ++struct __attribute__ ((__packed__)) tlvinfo_tlv_s { ++ u_int8_t type; ++ u_int8_t length; ++ u_int8_t value[0]; ++}; ++typedef struct tlvinfo_tlv_s tlvinfo_tlv_t; ++ ++#define TLV_VALUE_MAX_LEN 255 ++/* ++ * The max decode value is currently for the 'raw' type or the 'vendor ++ * extension' type, both of which have the same decode format. The ++ * max decode string size is computed as follows: ++ * ++ * strlen(" 0xFF") * TLV_VALUE_MAX_LEN + 1 ++ * ++ */ ++#define TLV_DECODE_VALUE_MAX_LEN ((5 * TLV_VALUE_MAX_LEN) + 1) ++ ++typedef struct tlv_decode_value_s { ++ u_int8_t value[TLV_DECODE_VALUE_MAX_LEN]; ++ u_int32_t length; ++} tlv_decode_value_t; ++ ++typedef enum dfd_tlvinfo_ext_tlv_type_e { ++ DFD_TLVINFO_EXT_TLV_TYPE_DEV_TYPE = 1, ++} dfd_tlvinfo_ext_tlv_type_t; ++ ++#if 0 ++#define TLV_TIME_LEN 64 ++ ++int ipmi_tlv_validate_fru_area(const uint8_t fruid, const char *fru_file_name, ++ sd_bus *bus_type, const bool bmc_fru); ++ ++extern const char *get_vpd_key_names(int key_id); ++extern std::string getService(sdbusplus::bus::bus& bus, ++ const std::string& intf, ++ const std::string& path); ++extern std::string getFRUValue(const std::string& section, ++ const std::string& key, ++ const std::string& delimiter, ++ IPMIFruInfo& fruData); ++#endif ++ ++int dfd_tlvinfo_get_e2prom_info(u_int8_t *eeprom, u_int32_t size, dfd_tlv_type_t *tlv_type, u_int8_t* buf, u_int8_t *buf_len); ++ ++#endif /* endif DFD_OPENBMC_TLVEEPROM_H */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/fpga_i2c.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/fpga_i2c.h +new file mode 100644 +index 000000000..649a8452d +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/fpga_i2c.h +@@ -0,0 +1,133 @@ ++#ifndef _FPGA_I2C_H ++#define _FPGA_I2C_H ++ ++#include ++#include ++#include ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++ ++#if 0 ++ ++#define FPGA_I2C_EXT_9548_ADDR (0x00) ++#define FPGA_I2C_EXT_9548_CHAN (0x04) ++#define FPGA_I2C_DEV_SLAVE_ADDR (0x08) ++#define FPGA_I2C_DEV_REG_ADDR (0x0C) ++#define FPGA_I2C_DEV_RDWR_LEN (0x10) ++#define FPGA_I2C_CTRL_REG (0x14) ++#define FPGA_I2C_STATUS_REG (0x18) ++#define FPGA_I2C_SCALE_REG (0x1C) ++#define FPGA_I2C_FILTER_REG (0x20) ++#define FPGA_I2C_STRETCH_REG (0x24) ++#define FPGA_I2C_EXT_9548_EXITS_FLAG (0x28) ++#define FPGA_I2C_INTERNAL_9548_CHAN (0x2C) ++#define FPGA_I2C_RDWR_DATA_BUF (0x80) ++#endif ++#define FPGA_I2C_RDWR_MAX_LEN_DEFAULT (128) ++#define I2C_REG_MAX_WIDTH (16) ++ ++#define DEV_NAME_MAX_LEN (64) ++ ++#define FPGA_I2C_MAX_TIMES (10) ++#define FPGA_I2C_XFER_TIME_OUT (100000) ++#define FPGA_I2C_SLEEP_TIME (40) ++ ++typedef struct fpga_i2c_reg_s { ++ uint32_t i2c_scale; ++ uint32_t i2c_filter; ++ uint32_t i2c_stretch; ++ uint32_t i2c_ext_9548_exits_flag; ++ uint32_t i2c_ext_9548_addr; ++ uint32_t i2c_ext_9548_chan; ++ uint32_t i2c_in_9548_chan; ++ uint32_t i2c_slave; ++ uint32_t i2c_reg; ++ uint32_t i2c_reg_len; ++ uint32_t i2c_data_len; ++ uint32_t i2c_ctrl; ++ uint32_t i2c_status; ++ uint32_t i2c_err_vec; ++ uint32_t i2c_data_buf; ++ uint32_t i2c_data_buf_len; ++} fpga_i2c_reg_t; ++ ++typedef struct fpga_i2c_reset_cfg_s { ++ uint32_t i2c_adap_reset_flag; ++ uint32_t reset_addr; ++ uint32_t reset_on; ++ uint32_t reset_off; ++ uint32_t reset_delay_b; ++ uint32_t reset_delay; ++ uint32_t reset_delay_a; ++} fpga_i2c_reset_cfg_t; ++ ++typedef struct fpga_i2c_reg_addr_s { ++ uint8_t reg_addr_len; ++ uint8_t read_reg_addr[I2C_REG_MAX_WIDTH]; ++} fpga_i2c_reg_addr_t; ++ ++typedef struct fpga_i2c_dev_s { ++ fpga_i2c_reg_t reg; ++ fpga_i2c_reset_cfg_t reset_cfg; ++ fpga_i2c_reg_addr_t i2c_addr_desc; ++ const char *dev_name; ++ uint32_t i2c_scale_value; ++ uint32_t i2c_filter_value; ++ uint32_t i2c_stretch_value; ++ uint32_t i2c_timeout; ++ uint32_t i2c_func_mode; ++ wait_queue_head_t queue; ++ struct i2c_adapter adap; ++ int adap_nr; ++ struct device *dev; ++ bool i2c_params_check; ++} fpga_i2c_dev_t; ++ ++typedef struct fpga_i2c_bus_device_s { ++ int i2c_timeout; ++ int i2c_scale; ++ int i2c_filter; ++ int i2c_stretch; ++ int i2c_ext_9548_exits_flag; ++ int i2c_ext_9548_addr; ++ int i2c_ext_9548_chan; ++ int i2c_in_9548_chan; ++ int i2c_slave; ++ int i2c_reg; ++ int i2c_reg_len; ++ int i2c_data_len; ++ int i2c_ctrl; ++ int i2c_status; ++ int i2c_err_vec; ++ int i2c_data_buf; ++ int i2c_data_buf_len; ++ char dev_name[DEV_NAME_MAX_LEN]; ++ int adap_nr; ++ int i2c_scale_value; ++ int i2c_filter_value; ++ int i2c_stretch_value; ++ int i2c_func_mode; ++ int i2c_adap_reset_flag; ++ int i2c_reset_addr; ++ int i2c_reset_on; ++ int i2c_reset_off; ++ int i2c_rst_delay_b; /* delay time before reset(us) */ ++ int i2c_rst_delay; /* reset time(us) */ ++ int i2c_rst_delay_a; /* delay time after reset(us) */ ++ int device_flag; ++ bool i2c_params_check; ++ int i2c_data_buf_len_reg; ++ int i2c_offset_reg; ++} fpga_i2c_bus_device_t; ++ ++typedef struct fpga_pca954x_device_s { ++ struct i2c_client *client; ++ uint32_t i2c_bus; ++ uint32_t i2c_addr; ++ uint32_t fpga_9548_flag; ++ uint32_t fpga_9548_reset_flag; ++ uint32_t pca9548_base_nr; ++} fpga_pca954x_device_t; ++ ++#endif /* _FPGA_I2C_H */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.c +new file mode 100644 +index 000000000..e74f4e800 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.c +@@ -0,0 +1,608 @@ ++/* ++ * hw_test.c ++ * Original Author : support, 2020-10-15 ++ * ++ * History ++ * v1.0 support 2020-10-15 Initial version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "hw_test.h" ++ ++extern struct bus_type mdio_bus_type; ++ ++struct board_mdio_dev { ++ struct list_head list; ++ struct mii_bus *mdio_bus; ++ int mdio_index; ++}; ++ ++struct board_phy_dev { ++ struct list_head list; ++ struct phy_device *phydev; ++ int phy_index; ++}; ++ ++static LIST_HEAD(mdio_dev_list); ++static LIST_HEAD(phydev_list); ++static struct class *class_mdio_bus = NULL; ++ ++#define PRINT_BUF_SIZE (256) ++#define INVALID_PHY_ADDR (0xFF) ++#define MAX_MDIO_DEVICE_NUMS (1000) ++#define MAX_PHY_DEVICE_NUMS (1000) ++ ++#define dram_debug(fmt, ...) \ ++ printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__) ++ ++static ssize_t dram_dev_read (struct file *file, char __user *buf, size_t count, ++ loff_t *offset) ++{ ++ u8 value8; ++ u16 value16; ++ u32 value32; ++ ++ if (file->private_data != NULL) { ++ return -EINVAL; ++ } ++ ++ file->private_data = ioremap(file->f_pos, count); ++ ++ if (!file->private_data) { ++ pr_notice("%s, %d\n", __FUNCTION__, __LINE__); ++ return -ENODEV; ++ } ++ ++ rmb(); ++ switch (count) { ++ case 1: ++ value8 = readb(file->private_data); ++ if (copy_to_user(buf, &value8, sizeof(u8))) { ++ return -EFAULT; ++ } ++ break; ++ case 2: ++ value16 = readw(file->private_data); ++ if (copy_to_user(buf, &value16, sizeof(u16))) { ++ return -EFAULT; ++ } ++ break; ++ case 4: ++ value32 = readl(file->private_data); ++ if (copy_to_user(buf, &value32, sizeof(u32))) { ++ return -EFAULT; ++ } ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ iounmap(file->private_data); ++ file->private_data = NULL; ++ return count; ++ ++} ++ ++static ssize_t dram_dev_write (struct file *file, const char __user *buf, size_t count, ++ loff_t *offset) ++{ ++ u8 value8; ++ u16 value16; ++ u32 value32; ++ ++ if (file->private_data != NULL) { ++ return -EINVAL; ++ } ++ ++ file->private_data = ioremap(file->f_pos, count); ++ ++ if (!file->private_data) { ++ pr_err("%s, %d\n", __FUNCTION__, __LINE__); ++ return -ENODEV; ++ } ++ ++ switch (count) { ++ case 1: ++ if (copy_from_user(&value8, buf, sizeof(u8))) { ++ return -EFAULT; ++ } ++ writeb(value8, file->private_data); ++ break; ++ case 2: ++ if (copy_from_user(&value16, buf, sizeof(u16))) { ++ return -EFAULT; ++ } ++ writew(value16, file->private_data); ++ break; ++ case 4: ++ if (copy_from_user(&value32, buf, sizeof(u32))) { ++ return -EFAULT; ++ } ++ writel(value32, file->private_data); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ wmb(); ++ iounmap(file->private_data); ++ file->private_data = NULL; ++ return count; ++} ++ ++static loff_t dram_dev_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t ret; ++ ++ switch (origin) { ++ case 0: ++ file->f_pos = offset; ++ ret = file->f_pos; ++ break; ++ case 1: ++ file->f_pos += offset; ++ ret = file->f_pos; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++static int temp_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum) ++{ ++ return 0; ++} ++ ++static int temp_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value) ++{ ++ return 0; ++} ++ ++static int init_class_mdio_bus(void) ++{ ++ struct mii_bus *bus; ++ int err = 0; ++ ++ bus = mdiobus_alloc(); ++ ++ bus->name = "temp_mdio_bus"; ++ snprintf(bus->id, MII_BUS_ID_SIZE, "temp_mdio_bus0"); ++ bus->read = temp_mdiobus_read; ++ bus->write = temp_mdiobus_write; ++ ++ err = mdiobus_register(bus); ++ if (err) { ++ printk(KERN_ERR "temp mdio bus register fail\n"); ++ return -1; ++ } ++ ++ class_mdio_bus = bus->dev.class; ++ mdiobus_unregister(bus); ++ ++ return 0; ++} ++ ++static int mdio_match_success(struct device *dev, const void * data) ++{ ++ ++ return 1; ++} ++ ++static int add_all_mdio_devices_to_list(void) ++{ ++ struct device *dev, *dev_start = NULL; ++ struct board_mdio_dev *mdio_dev = NULL; ++ int i = 0; ++ struct class *bus_class = class_mdio_bus; ++ ++ for (i = 0; i < MAX_MDIO_DEVICE_NUMS; i++) { ++ dev = class_find_device(bus_class, dev_start, NULL, mdio_match_success); ++ if (dev != NULL) { ++ mdio_dev = kzalloc(sizeof(struct board_mdio_dev), GFP_KERNEL); ++ if (mdio_dev == NULL) { ++ printk(KERN_ERR "%s: alloc fail\n", __func__); ++ return -EFAULT; ++ } ++ ++ mdio_dev->mdio_index = i; ++ mdio_dev->mdio_bus = to_mii_bus(dev); ++ list_add_tail(&mdio_dev->list, &mdio_dev_list); ++ ++ dev_start = dev; ++ } else { ++ break; ++ } ++ } ++ ++ printk(KERN_INFO "mdio dev numbers = %d\n", i); ++ ++ return 0; ++} ++ ++static void delete_all_mdio_devices_from_list(void) ++{ ++ struct list_head *n, *pos; ++ struct board_mdio_dev *mdio_dev; ++ ++ list_for_each_safe(pos, n, &mdio_dev_list) { ++ list_del(pos); ++ mdio_dev = list_entry(pos, struct board_mdio_dev, list); ++ kfree(mdio_dev); ++ } ++ ++ return; ++} ++ ++void list_all_mdio_devices_info(void) ++{ ++ struct board_mdio_dev *mdio_dev; ++ unsigned char phyaddr[PHY_MAX_ADDR]; ++ int i = 0, j = 0; ++ int phydev_num = 0; ++ char buf[PRINT_BUF_SIZE]; ++ int len = 0; ++ ++ printk(KERN_INFO "all the mdio devs info:\n"); ++ printk(KERN_INFO "index busid name phy_num phyaddr \n"); ++ list_for_each_entry(mdio_dev, &mdio_dev_list, list) { ++ i = 0; ++ j = 0; ++ phydev_num = 0; ++ mem_clear(phyaddr, INVALID_PHY_ADDR, sizeof(phyaddr)); ++ mem_clear(buf, 0, sizeof(buf)); ++ ++ for (i = 0; i < PHY_MAX_ADDR; i++) { ++ if (mdio_dev->mdio_bus->mdio_map[i]) { ++ phydev_num++; ++ phyaddr[j] = (unsigned char)i; ++ j++; ++ } ++ } ++ ++ len = snprintf(buf, sizeof(buf), " %-10d %-20s %-20s %-10d ", mdio_dev->mdio_index, ++ mdio_dev->mdio_bus->id, mdio_dev->mdio_bus->name, phydev_num); ++ ++ for (i = 0; i < PHY_MAX_ADDR; i++) { ++ if (phyaddr[i] == INVALID_PHY_ADDR) { ++ break; ++ } ++ ++ len += snprintf(&buf[len], sizeof(buf) - len, " %#x", phyaddr[i]); ++ } ++ ++ printk(KERN_INFO "%s\n", buf); ++ } ++ ++ return; ++} ++ ++static struct mii_bus *get_mdio_dev_according_to_index(int mdio_index) ++{ ++ struct board_mdio_dev *mdio_dev; ++ list_for_each_entry(mdio_dev, &mdio_dev_list, list) { ++ if (mdio_dev->mdio_index == mdio_index) { ++ return mdio_dev->mdio_bus; ++ } ++ } ++ ++ printk(KERN_ERR "no exist the mdio dev it's mdio_index = %d, please exec cmd [hw_test.bin mdiodev_list] to view mdiodev info\n", ++ mdio_index); ++ ++ return NULL; ++} ++ ++int board_mdio_read(int mdio_index, int phyaddr, u32 regnum) ++{ ++ struct mii_bus *bus; ++ int reg_val; ++ ++ bus = get_mdio_dev_according_to_index(mdio_index); ++ if (bus == NULL) { ++ return -1; ++ } ++ ++ reg_val = mdiobus_read(bus, phyaddr, regnum); ++ ++ return reg_val; ++} ++ ++int board_mdio_write(int mdio_index, int phyaddr, u32 regnum, u16 val) ++{ ++ struct mii_bus *bus; ++ int ret; ++ ++ bus = get_mdio_dev_according_to_index(mdio_index); ++ if (bus == NULL) { ++ return -1; ++ } ++ ++ ret = mdiobus_write(bus, phyaddr, regnum, val); ++ ++ return ret; ++} ++ ++static int phy_match_success(struct device *dev, const void * data) ++{ ++ ++ return 1; ++} ++ ++static int add_all_phydevs_to_list(void) ++{ ++ struct device *dev, *dev_start = NULL; ++ struct board_phy_dev *board_phydev = NULL; ++ int i = 0; ++ ++ for (i = 0; i < MAX_PHY_DEVICE_NUMS; i++) { ++ dev = bus_find_device(&mdio_bus_type, dev_start, NULL, phy_match_success); ++ if (dev != NULL) { ++ board_phydev = kzalloc(sizeof(struct board_phy_dev), GFP_KERNEL); ++ if (board_phydev == NULL) { ++ printk(KERN_ERR "%s: alloc fail\n", __func__); ++ return -EFAULT; ++ } ++ ++ board_phydev->phy_index = i; ++ board_phydev->phydev = to_phy_device(dev); ++ list_add_tail(&board_phydev->list, &phydev_list); ++ ++ dev_start = dev; ++ } else { ++ break; ++ } ++ } ++ ++ printk(KERN_INFO "phydev num = %d\n", i); ++ ++ return 0; ++} ++ ++static void delete_all_phydevs_from_list(void) ++{ ++ struct list_head *n, *pos; ++ struct board_phy_dev *board_phydev; ++ ++ list_for_each_safe(pos, n, &phydev_list) { ++ list_del(pos); ++ board_phydev = list_entry(pos, struct board_phy_dev, list); ++ kfree(board_phydev); ++ } ++ ++ return; ++} ++ ++void list_all_phydevs_info(void) ++{ ++ struct board_phy_dev *board_phydev; ++ ++ printk(KERN_INFO "all the phydevs info:\n"); ++ printk(KERN_INFO "index phyaddr phyId phydev_name\n"); ++ list_for_each_entry(board_phydev, &phydev_list, list) { ++ printk(KERN_INFO " %-10d %#-10x %#-10x %-20s\n", board_phydev->phy_index, board_phydev->phydev->mdio.addr,\ ++ board_phydev->phydev->phy_id, dev_name(&board_phydev->phydev->mdio.dev)); ++ } ++ ++ return; ++} ++ ++static struct phy_device *get_phy_dev_according_to_index(int phy_index) ++{ ++ struct board_phy_dev *board_phydev; ++ list_for_each_entry(board_phydev, &phydev_list, list) { ++ if (board_phydev->phy_index == phy_index) { ++ return board_phydev->phydev; ++ } ++ } ++ ++ printk(KERN_ERR "no exist the phydev it's phy_index = %d, please exec cmd [hw_test.bin phydev_list] to view phydev info\n", phy_index); ++ ++ return NULL; ++} ++ ++int board_phy_read(int phy_index, u32 regnum) ++{ ++ struct phy_device *phydev; ++ int reg_val; ++ ++ phydev = get_phy_dev_according_to_index(phy_index); ++ if (phydev == NULL) { ++ return -1; ++ } ++ ++ reg_val = phy_read(phydev, regnum); ++ ++ return reg_val; ++} ++ ++int board_phy_write(int phy_index, u32 regnum, u16 val) ++{ ++ struct phy_device *phydev; ++ int ret; ++ ++ phydev = get_phy_dev_according_to_index(phy_index); ++ if (phydev == NULL) { ++ return -1; ++ } ++ ++ ret = phy_write(phydev, regnum, val); ++ ++ return ret; ++} ++ ++static long dram_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ void __user *argp = (void __user *)arg; ++ int ret = 0; ++ struct phydev_user_info phy_user_info; ++ struct mdio_dev_user_info mdio_user_info; ++ ++ switch (cmd) { ++ case CMD_PHY_LIST: ++ list_all_phydevs_info(); ++ break; ++ ++ case CMD_PHY_READ: ++ if (copy_from_user(&phy_user_info, argp, sizeof(struct phydev_user_info))) ++ return -EFAULT; ++ ++ ret = board_phy_read(phy_user_info.phy_index, phy_user_info.regnum); ++ if (ret < 0) { ++ return -EFAULT; ++ } ++ ++ phy_user_info.regval = (u32)ret; ++ ++ if (copy_to_user(argp, &phy_user_info, sizeof(struct phydev_user_info))) ++ return -EFAULT; ++ ++ break; ++ ++ case CMD_PHY_WRITE: ++ if (copy_from_user(&phy_user_info, argp, sizeof(struct phydev_user_info))) ++ return -EFAULT; ++ ++ ret = board_phy_write(phy_user_info.phy_index, phy_user_info.regnum, (u16)phy_user_info.regval); ++ if (ret < 0) { ++ return -EFAULT; ++ } ++ ++ break; ++ ++ case CMD_MDIO_LIST: ++ list_all_mdio_devices_info(); ++ break; ++ ++ case CMD_MDIO_READ: ++ if (copy_from_user(&mdio_user_info, argp, sizeof(struct mdio_dev_user_info))) ++ return -EFAULT; ++ ++ ret = board_mdio_read(mdio_user_info.mdio_index, mdio_user_info.phyaddr, mdio_user_info.regnum); ++ if (ret < 0) { ++ return -EFAULT; ++ } ++ ++ mdio_user_info.regval = (u32)ret; ++ ++ if (copy_to_user(argp, &mdio_user_info, sizeof(struct mdio_dev_user_info))) ++ return -EFAULT; ++ ++ break; ++ ++ case CMD_MDIO_WRITE: ++ if (copy_from_user(&mdio_user_info, argp, sizeof(struct mdio_dev_user_info))) ++ return -EFAULT; ++ ++ ret = board_mdio_write(mdio_user_info.mdio_index, mdio_user_info.phyaddr, mdio_user_info.regnum, (u16)mdio_user_info.regval); ++ if (ret < 0) { ++ return -EFAULT; ++ } ++ ++ break; ++ ++ default: ++ printk("unknown ioctl cmd\n"); ++ break; ++ } ++ ++ return 0; ++} ++ ++static int dram_dev_open(struct inode *inode, struct file *file) ++{ ++ file->private_data = NULL; ++ file->f_pos = 0; ++ return 0; ++ ++} ++ ++static int dram_dev_release(struct inode *inode, struct file *file) ++{ ++ if (file->private_data) { ++ iounmap(file->private_data); ++ } ++ return 0; ++} ++ ++static const struct file_operations dram_dev_fops = { ++ .owner = THIS_MODULE, ++ .llseek = dram_dev_llseek, ++ .read = dram_dev_read, ++ .write = dram_dev_write, ++ .unlocked_ioctl = dram_dev_ioctl, ++ .open = dram_dev_open, ++ .release = dram_dev_release, ++}; ++ ++static struct miscdevice dram_dev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "dram_test", ++ .fops = &dram_dev_fops, ++}; ++ ++static int __init dram_init(void) ++{ ++ if (add_all_phydevs_to_list() != 0) { ++ printk(KERN_ERR "add all phydev to list fail\n"); ++ delete_all_phydevs_from_list(); ++ return -ENXIO; ++ } ++ ++ if (init_class_mdio_bus() == 0) { ++ if (add_all_mdio_devices_to_list() == -EFAULT) { ++ printk(KERN_ERR "add all mdiodev to list fail\n"); ++ delete_all_mdio_devices_from_list(); ++ delete_all_phydevs_from_list(); ++ return -ENXIO; ++ } ++ } ++ ++ if (misc_register(&dram_dev) != 0) { ++ pr_notice("Register %s failed.\n", dram_dev.name); ++ delete_all_mdio_devices_from_list(); ++ delete_all_phydevs_from_list(); ++ return -ENXIO; ++ } ++ ++ return 0; ++} ++ ++static void __exit dram_exit(void) ++{ ++ misc_deregister(&dram_dev); ++ ++ delete_all_mdio_devices_from_list(); ++ delete_all_phydevs_from_list(); ++} ++ ++module_init(dram_init); ++module_exit(dram_exit); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.h +new file mode 100644 +index 000000000..695fa336c +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.h +@@ -0,0 +1,31 @@ ++ ++#ifndef _LINUX_DRAM_DRIVER_H ++#define _LINUX_DRAM_DRIVER_H ++ ++#include ++#include ++ ++#define mem_clear(data, val, size) memset((data), val, (size)) ++ ++struct phydev_user_info { ++ int phy_index; ++ u32 regnum; ++ u32 regval; ++}; ++ ++#define CMD_PHY_LIST _IOR('P', 0, struct phydev_user_info) ++#define CMD_PHY_READ _IOR('P', 1, struct phydev_user_info) ++#define CMD_PHY_WRITE _IOR('P', 2, struct phydev_user_info) ++ ++struct mdio_dev_user_info { ++ int mdio_index; ++ int phyaddr; ++ u32 regnum; ++ u32 regval; ++}; ++ ++#define CMD_MDIO_LIST _IOR('M', 0, struct mdio_dev_user_info) ++#define CMD_MDIO_READ _IOR('M', 1, struct mdio_dev_user_info) ++#define CMD_MDIO_WRITE _IOR('M', 2, struct mdio_dev_user_info) ++ ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/Makefile +new file mode 100644 +index 000000000..b84963167 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/Makefile +@@ -0,0 +1,22 @@ ++PWD = $(shell pwd) ++ ++EXTRA_CFLAGS:= -I$(M)/include ++EXTRA_CFLAGS+= -Wall ++#ifdef ENABLE_GCOV ++#ifeq ($(ENABLE_GCOV), y) ++#EXTRA_CFLAGS+= -fprofile-arcs -ftest-coverage -lgcov ++#endif ++#endif # ENABLE_GCOV ++ ++obj-m := intel_spi.o ++obj-m += intel_spi_platform.o ++obj-m += intel_spi_pci.o ++ ++all: ++ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules ++ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi ++ cp -p $(PWD)/*.ko $(module_out_put_dir) ++clean: ++ rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd ++ rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order ++ rm -rf $(PWD)/.tmp_versions +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/include/intel_spi.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/include/intel_spi.h +new file mode 100644 +index 000000000..d0a570b1f +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/include/intel_spi.h +@@ -0,0 +1,23 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Intel PCH/PCU SPI flash driver. ++ * ++ * Copyright (C) 2016, Intel Corporation ++ * Author: Mika Westerberg ++ */ ++ ++#ifndef INTEL_SPI_H ++#define INTEL_SPI_H ++ ++#include ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++struct intel_spi; ++struct resource; ++ ++struct intel_spi *intel_spi_probe(struct device *dev, ++ struct resource *mem, const struct intel_spi_boardinfo *info); ++int intel_spi_remove(struct intel_spi *ispi); ++ ++#endif /* INTEL_SPI_H */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi.c +new file mode 100644 +index 000000000..a111d5221 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi.c +@@ -0,0 +1,966 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Intel PCH/PCU SPI flash driver. ++ * ++ * Copyright (C) 2016, Intel Corporation ++ * Author: Mika Westerberg ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "intel_spi.h" ++ ++/* Offsets are from @ispi->base */ ++#define BFPREG 0x00 ++ ++#define HSFSTS_CTL 0x04 ++#define HSFSTS_CTL_FSMIE BIT(31) ++#define HSFSTS_CTL_FDBC_SHIFT 24 ++#define HSFSTS_CTL_FDBC_MASK (0x3f << HSFSTS_CTL_FDBC_SHIFT) ++ ++#define HSFSTS_CTL_FCYCLE_SHIFT 17 ++#define HSFSTS_CTL_FCYCLE_MASK (0x0f << HSFSTS_CTL_FCYCLE_SHIFT) ++/* HW sequencer opcodes */ ++#define HSFSTS_CTL_FCYCLE_READ (0x00 << HSFSTS_CTL_FCYCLE_SHIFT) ++#define HSFSTS_CTL_FCYCLE_WRITE (0x02 << HSFSTS_CTL_FCYCLE_SHIFT) ++#define HSFSTS_CTL_FCYCLE_ERASE (0x03 << HSFSTS_CTL_FCYCLE_SHIFT) ++#define HSFSTS_CTL_FCYCLE_ERASE_64K (0x04 << HSFSTS_CTL_FCYCLE_SHIFT) ++#define HSFSTS_CTL_FCYCLE_RDID (0x06 << HSFSTS_CTL_FCYCLE_SHIFT) ++#define HSFSTS_CTL_FCYCLE_WRSR (0x07 << HSFSTS_CTL_FCYCLE_SHIFT) ++#define HSFSTS_CTL_FCYCLE_RDSR (0x08 << HSFSTS_CTL_FCYCLE_SHIFT) ++ ++#define HSFSTS_CTL_FGO BIT(16) ++#define HSFSTS_CTL_FLOCKDN BIT(15) ++#define HSFSTS_CTL_FDV BIT(14) ++#define HSFSTS_CTL_SCIP BIT(5) ++#define HSFSTS_CTL_AEL BIT(2) ++#define HSFSTS_CTL_FCERR BIT(1) ++#define HSFSTS_CTL_FDONE BIT(0) ++ ++#define FADDR 0x08 ++#define DLOCK 0x0c ++#define FDATA(n) (0x10 + ((n) * 4)) ++ ++#define FRACC 0x50 ++ ++#define FREG(n) (0x54 + ((n) * 4)) ++#define FREG_BASE_MASK GENMASK(14, 0) ++#define FREG_LIMIT_SHIFT 16 ++#define FREG_LIMIT_MASK GENMASK(30, 16) ++ ++/* Offset is from @ispi->pregs */ ++#define PR(n) ((n) * 4) ++#define PR_WPE BIT(31) ++#define PR_LIMIT_SHIFT 16 ++#define PR_LIMIT_MASK GENMASK(30, 16) ++#define PR_RPE BIT(15) ++#define PR_BASE_MASK GENMASK(14, 0) ++ ++/* Offsets are from @ispi->sregs */ ++#define SSFSTS_CTL 0x00 ++#define SSFSTS_CTL_FSMIE BIT(23) ++#define SSFSTS_CTL_DS BIT(22) ++#define SSFSTS_CTL_DBC_SHIFT 16 ++#define SSFSTS_CTL_SPOP BIT(11) ++#define SSFSTS_CTL_ACS BIT(10) ++#define SSFSTS_CTL_SCGO BIT(9) ++#define SSFSTS_CTL_COP_SHIFT 12 ++#define SSFSTS_CTL_FRS BIT(7) ++#define SSFSTS_CTL_DOFRS BIT(6) ++#define SSFSTS_CTL_AEL BIT(4) ++#define SSFSTS_CTL_FCERR BIT(3) ++#define SSFSTS_CTL_FDONE BIT(2) ++#define SSFSTS_CTL_SCIP BIT(0) ++ ++#define PREOP_OPTYPE 0x04 ++#define OPMENU0 0x08 ++#define OPMENU1 0x0c ++ ++#define OPTYPE_READ_NO_ADDR 0 ++#define OPTYPE_WRITE_NO_ADDR 1 ++#define OPTYPE_READ_WITH_ADDR 2 ++#define OPTYPE_WRITE_WITH_ADDR 3 ++ ++/* CPU specifics */ ++#define BYT_PR 0x74 ++#define BYT_SSFSTS_CTL 0x90 ++#define BYT_BCR 0xfc ++#define BYT_BCR_WPD BIT(0) ++#define BYT_FREG_NUM 5 ++#define BYT_PR_NUM 5 ++ ++#define LPT_PR 0x74 ++#define LPT_SSFSTS_CTL 0x90 ++#define LPT_FREG_NUM 5 ++#define LPT_PR_NUM 5 ++ ++#define BXT_PR 0x84 ++#define BXT_SSFSTS_CTL 0xa0 ++#define BXT_FREG_NUM 12 ++#define BXT_PR_NUM 6 ++ ++#define CNL_PR 0x84 ++#define CNL_FREG_NUM 6 ++#define CNL_PR_NUM 5 ++ ++#define LVSCC 0xc4 ++#define UVSCC 0xc8 ++#define ERASE_OPCODE_SHIFT 8 ++#define ERASE_OPCODE_MASK (0xff << ERASE_OPCODE_SHIFT) ++#define ERASE_64K_OPCODE_SHIFT 16 ++#define ERASE_64K_OPCODE_MASK (0xff << ERASE_64K_OPCODE_SHIFT) ++ ++#define INTEL_SPI_TIMEOUT 5000 /* ms */ ++#define INTEL_SPI_FIFO_SZ 64 ++ ++/** ++ * struct intel_spi - Driver private data ++ * @dev: Device pointer ++ * @info: Pointer to board specific info ++ * @nor: SPI NOR layer structure ++ * @base: Beginning of MMIO space ++ * @pregs: Start of protection registers ++ * @sregs: Start of software sequencer registers ++ * @nregions: Maximum number of regions ++ * @pr_num: Maximum number of protected range registers ++ * @locked: Is SPI setting locked ++ * @swseq_reg: Use SW sequencer in register reads/writes ++ * @swseq_erase: Use SW sequencer in erase operation ++ * @erase_64k: 64k erase supported ++ * @atomic_preopcode: Holds preopcode when atomic sequence is requested ++ * @opcodes: Opcodes which are supported. This are programmed by BIOS ++ * before it locks down the controller. ++ */ ++struct intel_spi { ++ struct device *dev; ++ const struct intel_spi_boardinfo *info; ++ struct spi_nor nor; ++ void __iomem *base; ++ void __iomem *pregs; ++ void __iomem *sregs; ++ size_t nregions; ++ size_t pr_num; ++ bool locked; ++ bool swseq_reg; ++ bool swseq_erase; ++ bool erase_64k; ++ u8 atomic_preopcode; ++ u8 opcodes[8]; ++}; ++ ++static bool writeable; ++module_param(writeable, bool, 0); ++MODULE_PARM_DESC(writeable, "Enable write access to SPI flash chip (default=0)"); ++ ++static void intel_spi_dump_regs(struct intel_spi *ispi) ++{ ++ u32 value; ++ int i; ++ ++ dev_dbg(ispi->dev, "BFPREG=0x%08x\n", readl(ispi->base + BFPREG)); ++ ++ value = readl(ispi->base + HSFSTS_CTL); ++ dev_dbg(ispi->dev, "HSFSTS_CTL=0x%08x\n", value); ++ if (value & HSFSTS_CTL_FLOCKDN) ++ dev_dbg(ispi->dev, "-> Locked\n"); ++ ++ dev_dbg(ispi->dev, "FADDR=0x%08x\n", readl(ispi->base + FADDR)); ++ dev_dbg(ispi->dev, "DLOCK=0x%08x\n", readl(ispi->base + DLOCK)); ++ ++ for (i = 0; i < 16; i++) ++ dev_dbg(ispi->dev, "FDATA(%d)=0x%08x\n", ++ i, readl(ispi->base + FDATA(i))); ++ ++ dev_dbg(ispi->dev, "FRACC=0x%08x\n", readl(ispi->base + FRACC)); ++ ++ for (i = 0; i < ispi->nregions; i++) ++ dev_dbg(ispi->dev, "FREG(%d)=0x%08x\n", i, ++ readl(ispi->base + FREG(i))); ++ for (i = 0; i < ispi->pr_num; i++) ++ dev_dbg(ispi->dev, "PR(%d)=0x%08x\n", i, ++ readl(ispi->pregs + PR(i))); ++ ++ if (ispi->sregs) { ++ value = readl(ispi->sregs + SSFSTS_CTL); ++ dev_dbg(ispi->dev, "SSFSTS_CTL=0x%08x\n", value); ++ dev_dbg(ispi->dev, "PREOP_OPTYPE=0x%08x\n", ++ readl(ispi->sregs + PREOP_OPTYPE)); ++ dev_dbg(ispi->dev, "OPMENU0=0x%08x\n", ++ readl(ispi->sregs + OPMENU0)); ++ dev_dbg(ispi->dev, "OPMENU1=0x%08x\n", ++ readl(ispi->sregs + OPMENU1)); ++ } ++ ++ if (ispi->info->type == INTEL_SPI_BYT) ++ dev_dbg(ispi->dev, "BCR=0x%08x\n", readl(ispi->base + BYT_BCR)); ++ ++ dev_dbg(ispi->dev, "LVSCC=0x%08x\n", readl(ispi->base + LVSCC)); ++ dev_dbg(ispi->dev, "UVSCC=0x%08x\n", readl(ispi->base + UVSCC)); ++ ++ dev_dbg(ispi->dev, "Protected regions:\n"); ++ for (i = 0; i < ispi->pr_num; i++) { ++ u32 base, limit; ++ ++ value = readl(ispi->pregs + PR(i)); ++ if (!(value & (PR_WPE | PR_RPE))) ++ continue; ++ ++ limit = (value & PR_LIMIT_MASK) >> PR_LIMIT_SHIFT; ++ base = value & PR_BASE_MASK; ++ ++ dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x [%c%c]\n", ++ i, base << 12, (limit << 12) | 0xfff, ++ value & PR_WPE ? 'W' : '.', ++ value & PR_RPE ? 'R' : '.'); ++ } ++ ++ dev_dbg(ispi->dev, "Flash regions:\n"); ++ for (i = 0; i < ispi->nregions; i++) { ++ u32 region, base, limit; ++ ++ region = readl(ispi->base + FREG(i)); ++ base = region & FREG_BASE_MASK; ++ limit = (region & FREG_LIMIT_MASK) >> FREG_LIMIT_SHIFT; ++ ++ if (base >= limit || (i > 0 && limit == 0)) ++ dev_dbg(ispi->dev, " %02d disabled\n", i); ++ else ++ dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x\n", ++ i, base << 12, (limit << 12) | 0xfff); ++ } ++ ++ dev_dbg(ispi->dev, "Using %cW sequencer for register access\n", ++ ispi->swseq_reg ? 'S' : 'H'); ++ dev_dbg(ispi->dev, "Using %cW sequencer for erase operation\n", ++ ispi->swseq_erase ? 'S' : 'H'); ++} ++ ++/* Reads max INTEL_SPI_FIFO_SZ bytes from the device fifo */ ++static int intel_spi_read_block(struct intel_spi *ispi, void *buf, size_t size) ++{ ++ size_t bytes; ++ int i = 0; ++ ++ if (size > INTEL_SPI_FIFO_SZ) ++ return -EINVAL; ++ ++ while (size > 0) { ++ bytes = min_t(size_t, size, 4); ++ memcpy_fromio(buf, ispi->base + FDATA(i), bytes); ++ size -= bytes; ++ buf += bytes; ++ i++; ++ } ++ ++ return 0; ++} ++ ++/* Writes max INTEL_SPI_FIFO_SZ bytes to the device fifo */ ++static int intel_spi_write_block(struct intel_spi *ispi, const void *buf, ++ size_t size) ++{ ++ size_t bytes; ++ int i = 0; ++ ++ if (size > INTEL_SPI_FIFO_SZ) ++ return -EINVAL; ++ ++ while (size > 0) { ++ bytes = min_t(size_t, size, 4); ++ memcpy_toio(ispi->base + FDATA(i), buf, bytes); ++ size -= bytes; ++ buf += bytes; ++ i++; ++ } ++ ++ return 0; ++} ++ ++static int intel_spi_wait_hw_busy(struct intel_spi *ispi) ++{ ++ u32 val; ++ ++ return readl_poll_timeout(ispi->base + HSFSTS_CTL, val, ++ !(val & HSFSTS_CTL_SCIP), 0, ++ INTEL_SPI_TIMEOUT * 1000); ++} ++ ++static int intel_spi_wait_sw_busy(struct intel_spi *ispi) ++{ ++ u32 val; ++ ++ return readl_poll_timeout(ispi->sregs + SSFSTS_CTL, val, ++ !(val & SSFSTS_CTL_SCIP), 0, ++ INTEL_SPI_TIMEOUT * 1000); ++} ++ ++static bool intel_spi_set_writeable(struct intel_spi *ispi) ++{ ++ if (!ispi->info->set_writeable) ++ return false; ++ ++ return ispi->info->set_writeable(ispi->base, ispi->info->data); ++} ++ ++static int intel_spi_init(struct intel_spi *ispi) ++{ ++ u32 opmenu0, opmenu1, lvscc, uvscc, val; ++ int i; ++ ++ switch (ispi->info->type) { ++ case INTEL_SPI_BYT: ++ ispi->sregs = ispi->base + BYT_SSFSTS_CTL; ++ ispi->pregs = ispi->base + BYT_PR; ++ ispi->nregions = BYT_FREG_NUM; ++ ispi->pr_num = BYT_PR_NUM; ++ ispi->swseq_reg = true; ++ break; ++ ++ case INTEL_SPI_LPT: ++ ispi->sregs = ispi->base + LPT_SSFSTS_CTL; ++ ispi->pregs = ispi->base + LPT_PR; ++ ispi->nregions = LPT_FREG_NUM; ++ ispi->pr_num = LPT_PR_NUM; ++ ispi->swseq_reg = true; ++ break; ++ ++ case INTEL_SPI_BXT: ++ ispi->sregs = ispi->base + BXT_SSFSTS_CTL; ++ ispi->pregs = ispi->base + BXT_PR; ++ ispi->nregions = BXT_FREG_NUM; ++ ispi->pr_num = BXT_PR_NUM; ++ ispi->erase_64k = true; ++ break; ++ ++ case INTEL_SPI_CNL: ++ ispi->sregs = NULL; ++ ispi->pregs = ispi->base + CNL_PR; ++ ispi->nregions = CNL_FREG_NUM; ++ ispi->pr_num = CNL_PR_NUM; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ /* Try to disable write protection if user asked to do so */ ++ if (writeable && !intel_spi_set_writeable(ispi)) { ++ dev_warn(ispi->dev, "can't disable chip write protection\n"); ++ writeable = false; ++ } ++ ++ /* Disable #SMI generation from HW sequencer */ ++ val = readl(ispi->base + HSFSTS_CTL); ++ val &= ~HSFSTS_CTL_FSMIE; ++ writel(val, ispi->base + HSFSTS_CTL); ++ ++ /* ++ * Determine whether erase operation should use HW or SW sequencer. ++ * ++ * The HW sequencer has a predefined list of opcodes, with only the ++ * erase opcode being programmable in LVSCC and UVSCC registers. ++ * If these registers don't contain a valid erase opcode, erase ++ * cannot be done using HW sequencer. ++ */ ++ lvscc = readl(ispi->base + LVSCC); ++ uvscc = readl(ispi->base + UVSCC); ++ if (!(lvscc & ERASE_OPCODE_MASK) || !(uvscc & ERASE_OPCODE_MASK)) ++ ispi->swseq_erase = true; ++ /* SPI controller on Intel BXT supports 64K erase opcode */ ++ if (ispi->info->type == INTEL_SPI_BXT && !ispi->swseq_erase) ++ if (!(lvscc & ERASE_64K_OPCODE_MASK) || ++ !(uvscc & ERASE_64K_OPCODE_MASK)) ++ ispi->erase_64k = false; ++ ++ if (ispi->sregs == NULL && (ispi->swseq_reg || ispi->swseq_erase)) { ++ dev_err(ispi->dev, "software sequencer not supported, but required\n"); ++ return -EINVAL; ++ } ++ ++ /* ++ * Some controllers can only do basic operations using hardware ++ * sequencer. All other operations are supposed to be carried out ++ * using software sequencer. ++ */ ++ if (ispi->swseq_reg) { ++ /* Disable #SMI generation from SW sequencer */ ++ val = readl(ispi->sregs + SSFSTS_CTL); ++ val &= ~SSFSTS_CTL_FSMIE; ++ writel(val, ispi->sregs + SSFSTS_CTL); ++ } ++ ++ /* Check controller's lock status */ ++ val = readl(ispi->base + HSFSTS_CTL); ++ ispi->locked = !!(val & HSFSTS_CTL_FLOCKDN); ++ ++ if (ispi->locked && ispi->sregs) { ++ /* ++ * BIOS programs allowed opcodes and then locks down the ++ * register. So read back what opcodes it decided to support. ++ * That's the set we are going to support as well. ++ */ ++ opmenu0 = readl(ispi->sregs + OPMENU0); ++ opmenu1 = readl(ispi->sregs + OPMENU1); ++ ++ if (opmenu0 && opmenu1) { ++ for (i = 0; i < ARRAY_SIZE(ispi->opcodes) / 2; i++) { ++ ispi->opcodes[i] = opmenu0 >> i * 8; ++ ispi->opcodes[i + 4] = opmenu1 >> i * 8; ++ } ++ } ++ } ++ ++ intel_spi_dump_regs(ispi); ++ ++ return 0; ++} ++ ++static int intel_spi_opcode_index(struct intel_spi *ispi, u8 opcode, int optype) ++{ ++ int i; ++ int preop; ++ ++ if (ispi->locked) { ++ for (i = 0; i < ARRAY_SIZE(ispi->opcodes); i++) ++ if (ispi->opcodes[i] == opcode) ++ return i; ++ ++ return -EINVAL; ++ } ++ ++ /* The lock is off, so just use index 0 */ ++ writel(opcode, ispi->sregs + OPMENU0); ++ preop = readw(ispi->sregs + PREOP_OPTYPE); ++ writel(optype << 16 | preop, ispi->sregs + PREOP_OPTYPE); ++ ++ return 0; ++} ++ ++static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, size_t len) ++{ ++ u32 val, status; ++ int ret; ++ ++ val = readl(ispi->base + HSFSTS_CTL); ++ val &= ~(HSFSTS_CTL_FCYCLE_MASK | HSFSTS_CTL_FDBC_MASK); ++ ++ switch (opcode) { ++ case SPINOR_OP_RDID: ++ val |= HSFSTS_CTL_FCYCLE_RDID; ++ break; ++ case SPINOR_OP_WRSR: ++ val |= HSFSTS_CTL_FCYCLE_WRSR; ++ break; ++ case SPINOR_OP_RDSR: ++ val |= HSFSTS_CTL_FCYCLE_RDSR; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (len > INTEL_SPI_FIFO_SZ) ++ return -EINVAL; ++ ++ val |= (len - 1) << HSFSTS_CTL_FDBC_SHIFT; ++ val |= HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; ++ val |= HSFSTS_CTL_FGO; ++ writel(val, ispi->base + HSFSTS_CTL); ++ ++ ret = intel_spi_wait_hw_busy(ispi); ++ if (ret) ++ return ret; ++ ++ status = readl(ispi->base + HSFSTS_CTL); ++ if (status & HSFSTS_CTL_FCERR) ++ return -EIO; ++ else if (status & HSFSTS_CTL_AEL) ++ return -EACCES; ++ ++ return 0; ++} ++ ++static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, size_t len, ++ int optype) ++{ ++ u32 val = 0, status; ++ u8 atomic_preopcode; ++ int ret; ++ ++ ret = intel_spi_opcode_index(ispi, opcode, optype); ++ if (ret < 0) ++ return ret; ++ ++ if (len > INTEL_SPI_FIFO_SZ) ++ return -EINVAL; ++ ++ /* ++ * Always clear it after each SW sequencer operation regardless ++ * of whether it is successful or not. ++ */ ++ atomic_preopcode = ispi->atomic_preopcode; ++ ispi->atomic_preopcode = 0; ++ ++ /* Only mark 'Data Cycle' bit when there is data to be transferred */ ++ if (len > 0) ++ val = ((len - 1) << SSFSTS_CTL_DBC_SHIFT) | SSFSTS_CTL_DS; ++ val |= ret << SSFSTS_CTL_COP_SHIFT; ++ val |= SSFSTS_CTL_FCERR | SSFSTS_CTL_FDONE; ++ val |= SSFSTS_CTL_SCGO; ++ if (atomic_preopcode) { ++ u16 preop; ++ ++ switch (optype) { ++ case OPTYPE_WRITE_NO_ADDR: ++ case OPTYPE_WRITE_WITH_ADDR: ++ /* Pick matching preopcode for the atomic sequence */ ++ preop = readw(ispi->sregs + PREOP_OPTYPE); ++ if ((preop & 0xff) == atomic_preopcode) ++ ; /* Do nothing */ ++ else if ((preop >> 8) == atomic_preopcode) ++ val |= SSFSTS_CTL_SPOP; ++ else ++ return -EINVAL; ++ ++ /* Enable atomic sequence */ ++ val |= SSFSTS_CTL_ACS; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ } ++ writel(val, ispi->sregs + SSFSTS_CTL); ++ ++ ret = intel_spi_wait_sw_busy(ispi); ++ if (ret) ++ return ret; ++ ++ status = readl(ispi->sregs + SSFSTS_CTL); ++ if (status & SSFSTS_CTL_FCERR) ++ return -EIO; ++ else if (status & SSFSTS_CTL_AEL) ++ return -EACCES; ++ ++ return 0; ++} ++ ++static int intel_spi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, ++ size_t len) ++{ ++ struct intel_spi *ispi = nor->priv; ++ int ret; ++ ++ /* Address of the first chip */ ++ writel(0, ispi->base + FADDR); ++ ++ if (ispi->swseq_reg) ++ ret = intel_spi_sw_cycle(ispi, opcode, len, ++ OPTYPE_READ_NO_ADDR); ++ else ++ ret = intel_spi_hw_cycle(ispi, opcode, len); ++ ++ if (ret) ++ return ret; ++ ++ return intel_spi_read_block(ispi, buf, len); ++} ++ ++static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf, ++ size_t len) ++{ ++ struct intel_spi *ispi = nor->priv; ++ int ret; ++ ++ /* ++ * This is handled with atomic operation and preop code in Intel ++ * controller so we only verify that it is available. If the ++ * controller is not locked, program the opcode to the PREOP ++ * register for later use. ++ * ++ * When hardware sequencer is used there is no need to program ++ * any opcodes (it handles them automatically as part of a command). ++ */ ++ if (opcode == SPINOR_OP_WREN) { ++ u16 preop; ++ ++ if (!ispi->swseq_reg) ++ return 0; ++ ++ preop = readw(ispi->sregs + PREOP_OPTYPE); ++ if ((preop & 0xff) != opcode && (preop >> 8) != opcode) { ++ if (ispi->locked) ++ return -EINVAL; ++ writel(opcode, ispi->sregs + PREOP_OPTYPE); ++ } ++ ++ /* ++ * This enables atomic sequence on next SW sycle. Will ++ * be cleared after next operation. ++ */ ++ ispi->atomic_preopcode = opcode; ++ return 0; ++ } ++ ++ /* ++ * We hope that HW sequencer will do the right thing automatically and ++ * with the SW sequencer we cannot use preopcode anyway, so just ignore ++ * the Write Disable operation and pretend it was completed ++ * successfully. ++ */ ++ if (opcode == SPINOR_OP_WRDI) ++ return 0; ++ ++ writel(0, ispi->base + FADDR); ++ ++ /* Write the value beforehand */ ++ ret = intel_spi_write_block(ispi, buf, len); ++ if (ret) ++ return ret; ++ ++ if (ispi->swseq_reg) ++ return intel_spi_sw_cycle(ispi, opcode, len, ++ OPTYPE_WRITE_NO_ADDR); ++ return intel_spi_hw_cycle(ispi, opcode, len); ++} ++ ++static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len, ++ u_char *read_buf) ++{ ++ struct intel_spi *ispi = nor->priv; ++ size_t block_size, retlen = 0; ++ u32 val, status; ++ ssize_t ret; ++ ++ /* ++ * Atomic sequence is not expected with HW sequencer reads. Make ++ * sure it is cleared regardless. ++ */ ++ if (WARN_ON_ONCE(ispi->atomic_preopcode)) ++ ispi->atomic_preopcode = 0; ++ ++ switch (nor->read_opcode) { ++ case SPINOR_OP_READ: ++ case SPINOR_OP_READ_FAST: ++ case SPINOR_OP_READ_4B: ++ case SPINOR_OP_READ_FAST_4B: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ while (len > 0) { ++ block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ); ++ ++ /* Read cannot cross 4K boundary */ ++ block_size = min_t(loff_t, from + block_size, ++ round_up(from + 1, SZ_4K)) - from; ++ ++ writel(from, ispi->base + FADDR); ++ ++ val = readl(ispi->base + HSFSTS_CTL); ++ val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); ++ val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; ++ val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT; ++ val |= HSFSTS_CTL_FCYCLE_READ; ++ val |= HSFSTS_CTL_FGO; ++ writel(val, ispi->base + HSFSTS_CTL); ++ ++ ret = intel_spi_wait_hw_busy(ispi); ++ if (ret) ++ return ret; ++ ++ status = readl(ispi->base + HSFSTS_CTL); ++ if (status & HSFSTS_CTL_FCERR) ++ ret = -EIO; ++ else if (status & HSFSTS_CTL_AEL) ++ ret = -EACCES; ++ ++ if (ret < 0) { ++ dev_err(ispi->dev, "read error: %llx: %#x\n", from, ++ status); ++ return ret; ++ } ++ ++ ret = intel_spi_read_block(ispi, read_buf, block_size); ++ if (ret) ++ return ret; ++ ++ len -= block_size; ++ from += block_size; ++ retlen += block_size; ++ read_buf += block_size; ++ } ++ ++ return retlen; ++} ++ ++static ssize_t intel_spi_write(struct spi_nor *nor, loff_t to, size_t len, ++ const u_char *write_buf) ++{ ++ struct intel_spi *ispi = nor->priv; ++ size_t block_size, retlen = 0; ++ u32 val, status; ++ ssize_t ret; ++ ++ /* Not needed with HW sequencer write, make sure it is cleared */ ++ ispi->atomic_preopcode = 0; ++ ++ while (len > 0) { ++ block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ); ++ ++ /* Write cannot cross 4K boundary */ ++ block_size = min_t(loff_t, to + block_size, ++ round_up(to + 1, SZ_4K)) - to; ++ ++ writel(to, ispi->base + FADDR); ++ ++ val = readl(ispi->base + HSFSTS_CTL); ++ val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); ++ val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; ++ val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT; ++ val |= HSFSTS_CTL_FCYCLE_WRITE; ++ ++ ret = intel_spi_write_block(ispi, write_buf, block_size); ++ if (ret) { ++ dev_err(ispi->dev, "failed to write block\n"); ++ return ret; ++ } ++ ++ /* Start the write now */ ++ val |= HSFSTS_CTL_FGO; ++ writel(val, ispi->base + HSFSTS_CTL); ++ ++ ret = intel_spi_wait_hw_busy(ispi); ++ if (ret) { ++ dev_err(ispi->dev, "timeout\n"); ++ return ret; ++ } ++ ++ status = readl(ispi->base + HSFSTS_CTL); ++ if (status & HSFSTS_CTL_FCERR) ++ ret = -EIO; ++ else if (status & HSFSTS_CTL_AEL) ++ ret = -EACCES; ++ ++ if (ret < 0) { ++ dev_err(ispi->dev, "write error: %llx: %#x\n", to, ++ status); ++ return ret; ++ } ++ ++ len -= block_size; ++ to += block_size; ++ retlen += block_size; ++ write_buf += block_size; ++ } ++ ++ return retlen; ++} ++ ++static int intel_spi_erase(struct spi_nor *nor, loff_t offs) ++{ ++ size_t erase_size, len = nor->mtd.erasesize; ++ struct intel_spi *ispi = nor->priv; ++ u32 val, status, cmd; ++ int ret; ++ ++ /* If the hardware can do 64k erase use that when possible */ ++ if (len >= SZ_64K && ispi->erase_64k) { ++ cmd = HSFSTS_CTL_FCYCLE_ERASE_64K; ++ erase_size = SZ_64K; ++ } else { ++ cmd = HSFSTS_CTL_FCYCLE_ERASE; ++ erase_size = SZ_4K; ++ } ++ ++ if (ispi->swseq_erase) { ++ while (len > 0) { ++ writel(offs, ispi->base + FADDR); ++ ++ ret = intel_spi_sw_cycle(ispi, nor->erase_opcode, ++ 0, OPTYPE_WRITE_WITH_ADDR); ++ if (ret) ++ return ret; ++ ++ offs += erase_size; ++ len -= erase_size; ++ } ++ ++ return 0; ++ } ++ ++ /* Not needed with HW sequencer erase, make sure it is cleared */ ++ ispi->atomic_preopcode = 0; ++ ++ while (len > 0) { ++ writel(offs, ispi->base + FADDR); ++ ++ val = readl(ispi->base + HSFSTS_CTL); ++ val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); ++ val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; ++ val |= cmd; ++ val |= HSFSTS_CTL_FGO; ++ writel(val, ispi->base + HSFSTS_CTL); ++ ++ ret = intel_spi_wait_hw_busy(ispi); ++ if (ret) ++ return ret; ++ ++ status = readl(ispi->base + HSFSTS_CTL); ++ if (status & HSFSTS_CTL_FCERR) ++ return -EIO; ++ else if (status & HSFSTS_CTL_AEL) ++ return -EACCES; ++ ++ offs += erase_size; ++ len -= erase_size; ++ } ++ ++ return 0; ++} ++ ++static bool intel_spi_is_protected(const struct intel_spi *ispi, ++ unsigned int base, unsigned int limit) ++{ ++ int i; ++ ++ for (i = 0; i < ispi->pr_num; i++) { ++ u32 pr_base, pr_limit, pr_value; ++ ++ pr_value = readl(ispi->pregs + PR(i)); ++ if (!(pr_value & (PR_WPE | PR_RPE))) ++ continue; ++ ++ pr_limit = (pr_value & PR_LIMIT_MASK) >> PR_LIMIT_SHIFT; ++ pr_base = pr_value & PR_BASE_MASK; ++ ++ if (pr_base >= base && pr_limit <= limit) ++ return true; ++ } ++ ++ return false; ++} ++ ++/* ++ * There will be a single partition holding all enabled flash regions. We ++ * call this "BIOS". ++ */ ++static void intel_spi_fill_partition(struct intel_spi *ispi, ++ struct mtd_partition *part) ++{ ++ u64 end; ++ int i; ++ ++ mem_clear(part, sizeof(*part)); ++ ++ /* Start from the mandatory descriptor region */ ++ part->size = 4096; ++ part->name = "BIOS"; ++ ++ /* ++ * Now try to find where this partition ends based on the flash ++ * region registers. ++ */ ++ for (i = 1; i < ispi->nregions; i++) { ++ u32 region, base, limit; ++ ++ region = readl(ispi->base + FREG(i)); ++ base = region & FREG_BASE_MASK; ++ limit = (region & FREG_LIMIT_MASK) >> FREG_LIMIT_SHIFT; ++ ++ if (base >= limit || limit == 0) ++ continue; ++ ++ /* ++ * If any of the regions have protection bits set, make the ++ * whole partition read-only to be on the safe side. ++ * ++ * Also if the user did not ask the chip to be writeable ++ * mask the bit too. ++ */ ++ if (!writeable || intel_spi_is_protected(ispi, base, limit)) ++ part->mask_flags |= MTD_WRITEABLE; ++ ++ end = (limit << 12) + 4096; ++ if (end > part->size) ++ part->size = end; ++ } ++} ++ ++static const struct spi_nor_controller_ops intel_spi_controller_ops = { ++ .read_reg = intel_spi_read_reg, ++ .write_reg = intel_spi_write_reg, ++ .read = intel_spi_read, ++ .write = intel_spi_write, ++ .erase = intel_spi_erase, ++}; ++ ++struct intel_spi *intel_spi_probe(struct device *dev, ++ struct resource *mem, const struct intel_spi_boardinfo *info) ++{ ++ const struct spi_nor_hwcaps hwcaps = { ++ .mask = SNOR_HWCAPS_READ | ++ SNOR_HWCAPS_READ_FAST | ++ SNOR_HWCAPS_PP, ++ }; ++ struct mtd_partition part; ++ struct intel_spi *ispi; ++ int ret; ++ ++ if (!info || !mem) ++ return ERR_PTR(-EINVAL); ++ ++ ispi = devm_kzalloc(dev, sizeof(*ispi), GFP_KERNEL); ++ if (!ispi) ++ return ERR_PTR(-ENOMEM); ++ ++ ispi->base = devm_ioremap_resource(dev, mem); ++ if (IS_ERR(ispi->base)) ++ return ERR_CAST(ispi->base); ++ ++ ispi->dev = dev; ++ ispi->info = info; ++ ++ ret = intel_spi_init(ispi); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ ispi->nor.dev = ispi->dev; ++ ispi->nor.priv = ispi; ++ ispi->nor.controller_ops = &intel_spi_controller_ops; ++ ++ ret = spi_nor_scan(&ispi->nor, NULL, &hwcaps); ++ if (ret) { ++ dev_info(dev, "failed to locate the chip\n"); ++ return ERR_PTR(ret); ++ } ++ ++ intel_spi_fill_partition(ispi, &part); ++ ++ ret = mtd_device_register(&ispi->nor.mtd, &part, 1); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ return ispi; ++} ++EXPORT_SYMBOL_GPL(intel_spi_probe); ++ ++int intel_spi_remove(struct intel_spi *ispi) ++{ ++ return mtd_device_unregister(&ispi->nor.mtd); ++} ++EXPORT_SYMBOL_GPL(intel_spi_remove); ++ ++MODULE_DESCRIPTION("Intel PCH/PCU SPI flash core driver"); ++MODULE_AUTHOR("support"); ++MODULE_LICENSE("GPL v2"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_pci.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_pci.c +new file mode 100644 +index 000000000..a89050b8a +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_pci.c +@@ -0,0 +1,106 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Intel PCH/PCU SPI flash PCI driver. ++ * ++ * Copyright (C) 2016, Intel Corporation ++ * Author: Mika Westerberg ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "intel_spi.h" ++ ++#define BCR 0xdc ++#define BCR_WPD BIT(0) ++ ++static bool intel_spi_pci_set_writeable(void __iomem *base, void *data) ++{ ++ struct pci_dev *pdev = data; ++ u32 bcr; ++ ++ /* Try to make the chip read/write */ ++ pci_read_config_dword(pdev, BCR, &bcr); ++ if (!(bcr & BCR_WPD)) { ++ bcr |= BCR_WPD; ++ pci_write_config_dword(pdev, BCR, bcr); ++ pci_read_config_dword(pdev, BCR, &bcr); ++ } ++ ++ return bcr & BCR_WPD; ++} ++ ++static const struct intel_spi_boardinfo bxt_info = { ++ .type = INTEL_SPI_BXT, ++ .set_writeable = intel_spi_pci_set_writeable, ++}; ++ ++static const struct intel_spi_boardinfo cnl_info = { ++ .type = INTEL_SPI_CNL, ++ .set_writeable = intel_spi_pci_set_writeable, ++}; ++ ++static int intel_spi_pci_probe(struct pci_dev *pdev, ++ const struct pci_device_id *id) ++{ ++ struct intel_spi_boardinfo *info; ++ struct intel_spi *ispi; ++ int ret; ++ ++ ret = pcim_enable_device(pdev); ++ if (ret) ++ return ret; ++ ++ info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info), ++ GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ ++ info->data = pdev; ++ ispi = intel_spi_probe(&pdev->dev, &pdev->resource[0], info); ++ if (IS_ERR(ispi)) ++ return PTR_ERR(ispi); ++ ++ pci_set_drvdata(pdev, ispi); ++ return 0; ++} ++ ++static void intel_spi_pci_remove(struct pci_dev *pdev) ++{ ++ intel_spi_remove(pci_get_drvdata(pdev)); ++} ++ ++static const struct pci_device_id intel_spi_pci_ids[] = { ++ { PCI_VDEVICE(INTEL, 0x02a4), (unsigned long)&bxt_info }, ++ { PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&bxt_info }, ++ { PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info }, ++ { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info }, ++ { PCI_VDEVICE(INTEL, 0x1bca), (unsigned long)&bxt_info }, ++ { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info }, ++ { PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info }, ++ { PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info }, ++ { PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info }, ++ { PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info }, ++ { PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info }, ++ { PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info }, ++ { PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info }, ++ { PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info }, ++ { PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&bxt_info }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids); ++ ++static struct pci_driver intel_spi_pci_driver = { ++ .name = "intel-spi", ++ .id_table = intel_spi_pci_ids, ++ .probe = intel_spi_pci_probe, ++ .remove = intel_spi_pci_remove, ++}; ++ ++module_pci_driver(intel_spi_pci_driver); ++ ++MODULE_DESCRIPTION("Intel PCH/PCU SPI flash PCI driver"); ++MODULE_AUTHOR("support"); ++MODULE_LICENSE("GPL v2"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_platform.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_platform.c +new file mode 100644 +index 000000000..489716d4d +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_platform.c +@@ -0,0 +1,168 @@ ++/* ++ * Intel PCH/PCU SPI flash platform driver. ++ * ++ * Copyright (C) 2016, Intel Corporation ++ * Author: Mika Westerberg ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "intel_spi.h" ++ ++#define PCI_VENDOR_ID_D1527_LPC (0x8c54) ++ ++#define BIOS_CNTL (0xdc) ++#define BIOS_CNTL_SRC_SHIFT 2 ++#define BIOS_CNTL_WN BIT(0) ++#define BIOS_CNTL_BLE BIT(1) ++#define BIOS_CNTL_SMM_BMP BIT(5) ++ ++#define RCBABASE 0xf0 ++ ++int intel_spi_platform_debug = 0; ++module_param(intel_spi_platform_debug, int, S_IRUGO | S_IWUSR); ++int intel_spi_platform_error = 0; ++module_param(intel_spi_platform_error, int, S_IRUGO | S_IWUSR); ++ ++static bool writeable; ++module_param(writeable, bool, 0); ++MODULE_PARM_DESC(writeable, "Enable write access to BIOS (default=0)"); ++ ++#define INTEL_SPI_PLATFORM_VERBOSE(fmt, args...) do { \ ++ if (intel_spi_platform_debug) { \ ++ printk(KERN_INFO "[INTEL_SPI_PLATFORM][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++ } while (0) ++ ++#define INTEL_SPI_PLATFORM_ERROR(fmt, args...) do { \ ++ if (intel_spi_platform_error) { \ ++ printk(KERN_ERR "[INTEL_SPI_PLATFORM][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++ } while (0) ++ ++static void intel_spi_enable_bios_write(struct pci_dev *pci_dev, struct intel_spi_boardinfo *info, int *writeable_flag) ++{ ++ u8 bios_cntl, value, want, new; ++ ++ if (writeable) { ++ pci_read_config_byte(pci_dev, BIOS_CNTL, &bios_cntl); ++ want = bios_cntl; ++ value = (bios_cntl >> BIOS_CNTL_SRC_SHIFT) & 0x3 ; ++ if (value == 0x3) { ++ INTEL_SPI_PLATFORM_VERBOSE("invalid prefetching/caching settings, "); ++ } else { ++ INTEL_SPI_PLATFORM_VERBOSE("prefetching %sabled, caching %sabled, ", ++ (value & 0x2) ? "en" : "dis", ++ (value & 0x1) ? "dis" : "en"); ++ } ++ ++ /* writeable regardless */ ++ want &= ~BIOS_CNTL_SMM_BMP; ++ /* write enable */ ++ want |= BIOS_CNTL_WN; ++ /* BIOS lock disabled */ ++ want &= ~BIOS_CNTL_BLE; ++ INTEL_SPI_PLATFORM_VERBOSE("bios cntl is:0x%x, want is:0x%x\n", bios_cntl, want); ++ pci_write_config_byte(pci_dev, BIOS_CNTL, want); ++ pci_read_config_byte(pci_dev, BIOS_CNTL, &new); ++ INTEL_SPI_PLATFORM_VERBOSE("\nBIOS_CNTL = 0x%02x: ", new); ++ INTEL_SPI_PLATFORM_VERBOSE("BIOS Lock Enable: %sabled, ", (new & BIOS_CNTL_BLE) ? "en" : "dis"); ++ INTEL_SPI_PLATFORM_VERBOSE("BIOS Write Enable: %sabled\n", (new & BIOS_CNTL_WN) ? "en" : "dis"); ++ ++ if (new & BIOS_CNTL_SMM_BMP) { ++ INTEL_SPI_PLATFORM_VERBOSE("BIOS region SMM protection is enabled!\n"); ++ } ++ ++ if (new != want) { ++ INTEL_SPI_PLATFORM_VERBOSE("Warning: Setting Bios Control at 0x%x from 0x%02x to 0x%02x failed.\n" ++ "New value is 0x%02x.\n", BIOS_CNTL, value, want, new); ++ } else { ++ *writeable_flag = !!(new & BIOS_CNTL_WN); ++ } ++ INTEL_SPI_PLATFORM_VERBOSE("Bios Control is 0x%x\n", new); ++ } else { ++ INTEL_SPI_PLATFORM_VERBOSE("Bios don't write\n"); ++ } ++ ++ return ; ++} ++ ++static int intel_spi_platform_probe(struct platform_device *pdev) ++{ ++ struct intel_spi_boardinfo *info; ++ struct intel_spi *ispi; ++ struct resource *mem; ++ struct pci_dev *pci_dev = NULL; ++ u32 rcba; ++ int writeable_flag = 0; ++ ++ info = dev_get_platdata(&pdev->dev); ++ if (!info) ++ return -EINVAL; ++ ++ pci_dev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_VENDOR_ID_D1527_LPC, pci_dev); ++ if (!pci_dev) { ++ INTEL_SPI_PLATFORM_ERROR("pci_get_device(0x8086, 0x8c54) failed!\n"); ++ return -1; ++ } ++ ++ switch (info->type) { ++ case INTEL_SPI_LPT: ++ pci_read_config_dword(pci_dev, RCBABASE, &rcba); ++ if (rcba & 1) { ++ intel_spi_enable_bios_write(pci_dev, info, &writeable_flag); ++ } ++ break; ++ default: ++ INTEL_SPI_PLATFORM_ERROR("info type[%d] not need set writeable.\n",info->type); ++ break; ++ } ++ INTEL_SPI_PLATFORM_VERBOSE("intel spi boardinfo writeable is %sabled\n", ++ writeable_flag ? "en" : "dis"); ++ ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ispi = intel_spi_probe(&pdev->dev, mem, info); ++ if (IS_ERR(ispi)) ++ return PTR_ERR(ispi); ++ ++ platform_set_drvdata(pdev, ispi); ++ return 0; ++} ++ ++static int intel_spi_platform_remove(struct platform_device *pdev) ++{ ++ struct intel_spi *ispi = platform_get_drvdata(pdev); ++ ++ return intel_spi_remove(ispi); ++} ++ ++static struct of_device_id intel_spi_match[] = { ++ { ++ .compatible = "spi-c224", ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, intel_spi_match); ++ ++static struct platform_driver intel_spi_platform_driver = { ++ .probe = intel_spi_platform_probe, ++ .remove = intel_spi_platform_remove, ++ .driver = { ++ .name = "intel-spi", ++ .of_match_table = intel_spi_match, ++ }, ++}; ++ ++module_platform_driver(intel_spi_platform_driver); ++ ++MODULE_DESCRIPTION("Intel PCH/PCU SPI flash platform driver"); ++MODULE_AUTHOR("support"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:intel-spi"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/Makefile +new file mode 100644 +index 000000000..02d659d6c +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/Makefile +@@ -0,0 +1,37 @@ ++PWD = $(shell pwd) ++ ++EXTRA_CFLAGS:= -I$(M)/include ++EXTRA_CFLAGS+= -Wall ++#ifdef ENABLE_GCOV ++#ifeq ($(ENABLE_GCOV), y) ++#EXTRA_CFLAGS+= -fprofile-arcs -ftest-coverage -lgcov ++#endif ++#endif # ENABLE_GCOV ++ ++obj-m := wb_lm75.o ++obj-m += wb_tmp401.o ++obj-m += wb_i2c_mux_pca9641.o ++obj-m += wb_i2c_mux_pca954x.o ++obj-m += wb_i2c_i801.o ++obj-m += wb_i2c_algo_bit.o ++obj-m += wb_i2c_gpio.o ++obj-m += wb_i2c_gpio_device.o ++obj-m += wb_at24.o ++obj-m += wb_pmbus_core.o ++obj-m += wb_csu550.o ++obj-m += wb_ina3221.o ++obj-m += wb_isl68137.o ++obj-m += wb_tps53622.o ++obj-m += wb_ucd9000.o ++obj-m += wb_xdpe12284.o ++obj-m += wb_xdpe132g5c_pmbus.o ++obj-m += wb_i2c_ismt.o ++ ++all: ++ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules ++ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi ++ cp -p $(PWD)/*.ko $(module_out_put_dir) ++clean: ++ rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/*.mod ++ rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order ++ rm -rf $(PWD)/.tmp_versions +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_at24.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_at24.c +new file mode 100644 +index 000000000..1075e6ef1 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_at24.c +@@ -0,0 +1,861 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * at24.c - handle most I2C EEPROMs ++ * ++ * Copyright (C) 2005-2007 David Brownell ++ * Copyright (C) 2008 Wolfram Sang, Pengutronix ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Address pointer is 16 bit. */ ++#define AT24_FLAG_ADDR16 BIT(7) ++/* sysfs-entry will be read-only. */ ++#define AT24_FLAG_READONLY BIT(6) ++/* sysfs-entry will be world-readable. */ ++#define AT24_FLAG_IRUGO BIT(5) ++/* Take always 8 addresses (24c00). */ ++#define AT24_FLAG_TAKE8ADDR BIT(4) ++/* Factory-programmed serial number. */ ++#define AT24_FLAG_SERIAL BIT(3) ++/* Factory-programmed mac address. */ ++#define AT24_FLAG_MAC BIT(2) ++/* Does not auto-rollover reads to the next slave address. */ ++#define AT24_FLAG_NO_RDROL BIT(1) ++ ++/* ++ * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable. ++ * Differences between different vendor product lines (like Atmel AT24C or ++ * MicroChip 24LC, etc) won't much matter for typical read/write access. ++ * There are also I2C RAM chips, likewise interchangeable. One example ++ * would be the PCF8570, which acts like a 24c02 EEPROM (256 bytes). ++ * ++ * However, misconfiguration can lose data. "Set 16-bit memory address" ++ * to a part with 8-bit addressing will overwrite data. Writing with too ++ * big a page size also loses data. And it's not safe to assume that the ++ * conventional addresses 0x50..0x57 only hold eeproms; a PCF8563 RTC ++ * uses 0x51, for just one example. ++ * ++ * Accordingly, explicit board-specific configuration data should be used ++ * in almost all cases. (One partial exception is an SMBus used to access ++ * "SPD" data for DRAM sticks. Those only use 24c02 EEPROMs.) ++ * ++ * So this driver uses "new style" I2C driver binding, expecting to be ++ * told what devices exist. That may be in arch/X/mach-Y/board-Z.c or ++ * similar kernel-resident tables; or, configuration data coming from ++ * a bootloader. ++ * ++ * Other than binding model, current differences from "eeprom" driver are ++ * that this one handles write access and isn't restricted to 24c02 devices. ++ * It also handles larger devices (32 kbit and up) with two-byte addresses, ++ * which won't work on pure SMBus systems. ++ */ ++ ++struct at24_client { ++ struct i2c_client *client; ++ struct regmap *regmap; ++}; ++ ++struct at24_data { ++ /* ++ * Lock protects against activities from other Linux tasks, ++ * but not from changes by other I2C masters. ++ */ ++ struct mutex lock; ++ ++ unsigned int write_max; ++ unsigned int num_addresses; ++ unsigned int offset_adj; ++ ++ u32 byte_len; ++ u16 page_size; ++ u8 flags; ++ ++ struct nvmem_device *nvmem; ++ struct regulator *vcc_reg; ++ void (*read_post)(unsigned int off, char *buf, size_t count); ++ ++ /* ++ * Some chips tie up multiple I2C addresses; dummy devices reserve ++ * them for us, and we'll use them with SMBus calls. ++ */ ++ struct at24_client client[]; ++}; ++ ++/* ++ * This parameter is to help this driver avoid blocking other drivers out ++ * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C ++ * clock, one 256 byte read takes about 1/43 second which is excessive; ++ * but the 1/170 second it takes at 400 kHz may be quite reasonable; and ++ * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible. ++ * ++ * This value is forced to be a power of two so that writes align on pages. ++ */ ++static unsigned int at24_io_limit = 128; ++module_param_named(io_limit, at24_io_limit, uint, 0); ++MODULE_PARM_DESC(at24_io_limit, "Maximum bytes per I/O (default 128)"); ++ ++/* ++ * Specs often allow 5 msec for a page write, sometimes 20 msec; ++ * it's important to recover from write timeouts. ++ */ ++static unsigned int at24_write_timeout = 25; ++module_param_named(write_timeout, at24_write_timeout, uint, 0); ++MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)"); ++ ++struct at24_chip_data { ++ u32 byte_len; ++ u8 flags; ++ void (*read_post)(unsigned int off, char *buf, size_t count); ++}; ++ ++#define AT24_CHIP_DATA(_name, _len, _flags) \ ++ static const struct at24_chip_data _name = { \ ++ .byte_len = _len, .flags = _flags, \ ++ } ++ ++#define AT24_CHIP_DATA_CB(_name, _len, _flags, _read_post) \ ++ static const struct at24_chip_data _name = { \ ++ .byte_len = _len, .flags = _flags, \ ++ .read_post = _read_post, \ ++ } ++ ++static void at24_read_post_vaio(unsigned int off, char *buf, size_t count) ++{ ++ int i; ++ ++ if (capable(CAP_SYS_ADMIN)) ++ return; ++ ++ /* ++ * Hide VAIO private settings to regular users: ++ * - BIOS passwords: bytes 0x00 to 0x0f ++ * - UUID: bytes 0x10 to 0x1f ++ * - Serial number: 0xc0 to 0xdf ++ */ ++ for (i = 0; i < count; i++) { ++ if ((off + i <= 0x1f) || ++ (off + i >= 0xc0 && off + i <= 0xdf)) ++ buf[i] = 0; ++ } ++} ++ ++/* needs 8 addresses as A0-A2 are ignored */ ++AT24_CHIP_DATA(at24_data_24c00, 128 / 8, AT24_FLAG_TAKE8ADDR); ++/* old variants can't be handled with this generic entry! */ ++AT24_CHIP_DATA(at24_data_24c01, 1024 / 8, 0); ++AT24_CHIP_DATA(at24_data_24cs01, 16, ++ AT24_FLAG_SERIAL | AT24_FLAG_READONLY); ++AT24_CHIP_DATA(at24_data_24c02, 2048 / 8, AT24_FLAG_IRUGO); ++AT24_CHIP_DATA(at24_data_24cs02, 16, ++ AT24_FLAG_SERIAL | AT24_FLAG_READONLY); ++AT24_CHIP_DATA(at24_data_24mac402, 48 / 8, ++ AT24_FLAG_MAC | AT24_FLAG_READONLY); ++AT24_CHIP_DATA(at24_data_24mac602, 64 / 8, ++ AT24_FLAG_MAC | AT24_FLAG_READONLY); ++/* spd is a 24c02 in memory DIMMs */ ++AT24_CHIP_DATA(at24_data_spd, 2048 / 8, ++ AT24_FLAG_READONLY | AT24_FLAG_IRUGO); ++/* 24c02_vaio is a 24c02 on some Sony laptops */ ++AT24_CHIP_DATA_CB(at24_data_24c02_vaio, 2048 / 8, ++ AT24_FLAG_READONLY | AT24_FLAG_IRUGO, ++ at24_read_post_vaio); ++AT24_CHIP_DATA(at24_data_24c04, 4096 / 8, 0); ++AT24_CHIP_DATA(at24_data_24cs04, 16, ++ AT24_FLAG_SERIAL | AT24_FLAG_READONLY); ++/* 24rf08 quirk is handled at i2c-core */ ++AT24_CHIP_DATA(at24_data_24c08, 8192 / 8, 0); ++AT24_CHIP_DATA(at24_data_24cs08, 16, ++ AT24_FLAG_SERIAL | AT24_FLAG_READONLY); ++AT24_CHIP_DATA(at24_data_24c16, 16384 / 8, 0); ++AT24_CHIP_DATA(at24_data_24cs16, 16, ++ AT24_FLAG_SERIAL | AT24_FLAG_READONLY); ++AT24_CHIP_DATA(at24_data_24c32, 32768 / 8, AT24_FLAG_ADDR16); ++AT24_CHIP_DATA(at24_data_24cs32, 16, ++ AT24_FLAG_ADDR16 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY); ++AT24_CHIP_DATA(at24_data_24c64, 65536 / 8, AT24_FLAG_ADDR16 | AT24_FLAG_IRUGO); ++AT24_CHIP_DATA(at24_data_24cs64, 16, ++ AT24_FLAG_ADDR16 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY); ++AT24_CHIP_DATA(at24_data_24c128, 131072 / 8, AT24_FLAG_ADDR16); ++AT24_CHIP_DATA(at24_data_24c256, 262144 / 8, AT24_FLAG_ADDR16); ++AT24_CHIP_DATA(at24_data_24c512, 524288 / 8, AT24_FLAG_ADDR16); ++AT24_CHIP_DATA(at24_data_24c1024, 1048576 / 8, AT24_FLAG_ADDR16); ++AT24_CHIP_DATA(at24_data_24c2048, 2097152 / 8, AT24_FLAG_ADDR16); ++/* identical to 24c08 ? */ ++AT24_CHIP_DATA(at24_data_INT3499, 8192 / 8, 0); ++ ++static const struct i2c_device_id at24_ids[] = { ++ { "wb_24c00", (kernel_ulong_t)&at24_data_24c00 }, ++ { "wb_24c01", (kernel_ulong_t)&at24_data_24c01 }, ++ { "wb_24cs01", (kernel_ulong_t)&at24_data_24cs01 }, ++ { "wb_24c02", (kernel_ulong_t)&at24_data_24c02 }, ++ { "wb_24cs02", (kernel_ulong_t)&at24_data_24cs02 }, ++ { "wb_24mac402", (kernel_ulong_t)&at24_data_24mac402 }, ++ { "wb_24mac602", (kernel_ulong_t)&at24_data_24mac602 }, ++ { "wb_spd", (kernel_ulong_t)&at24_data_spd }, ++ { "wb_24c02-vaio", (kernel_ulong_t)&at24_data_24c02_vaio }, ++ { "wb_24c04", (kernel_ulong_t)&at24_data_24c04 }, ++ { "wb_24cs04", (kernel_ulong_t)&at24_data_24cs04 }, ++ { "wb_24c08", (kernel_ulong_t)&at24_data_24c08 }, ++ { "wb_24cs08", (kernel_ulong_t)&at24_data_24cs08 }, ++ { "wb_24c16", (kernel_ulong_t)&at24_data_24c16 }, ++ { "wb_24cs16", (kernel_ulong_t)&at24_data_24cs16 }, ++ { "wb_24c32", (kernel_ulong_t)&at24_data_24c32 }, ++ { "wb_24cs32", (kernel_ulong_t)&at24_data_24cs32 }, ++ { "wb_24c64", (kernel_ulong_t)&at24_data_24c64 }, ++ { "wb_24cs64", (kernel_ulong_t)&at24_data_24cs64 }, ++ { "wb_24c128", (kernel_ulong_t)&at24_data_24c128 }, ++ { "wb_24c256", (kernel_ulong_t)&at24_data_24c256 }, ++ { "wb_24c512", (kernel_ulong_t)&at24_data_24c512 }, ++ { "wb_24c1024", (kernel_ulong_t)&at24_data_24c1024 }, ++ { "wb_24c2048", (kernel_ulong_t)&at24_data_24c2048 }, ++ { "wb_at24", 0 }, ++ { /* END OF LIST */ } ++}; ++MODULE_DEVICE_TABLE(i2c, at24_ids); ++ ++static const struct of_device_id at24_of_match[] = { ++ { .compatible = "atmel,24c00", .data = &at24_data_24c00 }, ++ { .compatible = "atmel,24c01", .data = &at24_data_24c01 }, ++ { .compatible = "atmel,24cs01", .data = &at24_data_24cs01 }, ++ { .compatible = "atmel,24c02", .data = &at24_data_24c02 }, ++ { .compatible = "atmel,24cs02", .data = &at24_data_24cs02 }, ++ { .compatible = "atmel,24mac402", .data = &at24_data_24mac402 }, ++ { .compatible = "atmel,24mac602", .data = &at24_data_24mac602 }, ++ { .compatible = "atmel,spd", .data = &at24_data_spd }, ++ { .compatible = "atmel,24c04", .data = &at24_data_24c04 }, ++ { .compatible = "atmel,24cs04", .data = &at24_data_24cs04 }, ++ { .compatible = "atmel,24c08", .data = &at24_data_24c08 }, ++ { .compatible = "atmel,24cs08", .data = &at24_data_24cs08 }, ++ { .compatible = "atmel,24c16", .data = &at24_data_24c16 }, ++ { .compatible = "atmel,24cs16", .data = &at24_data_24cs16 }, ++ { .compatible = "atmel,24c32", .data = &at24_data_24c32 }, ++ { .compatible = "atmel,24cs32", .data = &at24_data_24cs32 }, ++ { .compatible = "atmel,24c64", .data = &at24_data_24c64 }, ++ { .compatible = "atmel,24cs64", .data = &at24_data_24cs64 }, ++ { .compatible = "atmel,24c128", .data = &at24_data_24c128 }, ++ { .compatible = "atmel,24c256", .data = &at24_data_24c256 }, ++ { .compatible = "atmel,24c512", .data = &at24_data_24c512 }, ++ { .compatible = "atmel,24c1024", .data = &at24_data_24c1024 }, ++ { .compatible = "atmel,24c2048", .data = &at24_data_24c2048 }, ++ { /* END OF LIST */ }, ++}; ++MODULE_DEVICE_TABLE(of, at24_of_match); ++ ++static const struct acpi_device_id __maybe_unused at24_acpi_ids[] = { ++ { "INT3499", (kernel_ulong_t)&at24_data_INT3499 }, ++ { "TPF0001", (kernel_ulong_t)&at24_data_24c1024 }, ++ { /* END OF LIST */ } ++}; ++MODULE_DEVICE_TABLE(acpi, at24_acpi_ids); ++ ++/* ++ * This routine supports chips which consume multiple I2C addresses. It ++ * computes the addressing information to be used for a given r/w request. ++ * Assumes that sanity checks for offset happened at sysfs-layer. ++ * ++ * Slave address and byte offset derive from the offset. Always ++ * set the byte address; on a multi-master board, another master ++ * may have changed the chip's "current" address pointer. ++ */ ++static struct at24_client *at24_translate_offset(struct at24_data *at24, ++ unsigned int *offset) ++{ ++ unsigned int i; ++ ++ if (at24->flags & AT24_FLAG_ADDR16) { ++ i = *offset >> 16; ++ *offset &= 0xffff; ++ } else { ++ i = *offset >> 8; ++ *offset &= 0xff; ++ } ++ ++ return &at24->client[i]; ++} ++ ++static struct device *at24_base_client_dev(struct at24_data *at24) ++{ ++ return &at24->client[0].client->dev; ++} ++ ++static size_t at24_adjust_read_count(struct at24_data *at24, ++ unsigned int offset, size_t count) ++{ ++ unsigned int bits; ++ size_t remainder; ++ ++ /* ++ * In case of multi-address chips that don't rollover reads to ++ * the next slave address: truncate the count to the slave boundary, ++ * so that the read never straddles slaves. ++ */ ++ if (at24->flags & AT24_FLAG_NO_RDROL) { ++ bits = (at24->flags & AT24_FLAG_ADDR16) ? 16 : 8; ++ remainder = BIT(bits) - offset; ++ if (count > remainder) ++ count = remainder; ++ } ++ ++ if (count > at24_io_limit) ++ count = at24_io_limit; ++ ++ return count; ++} ++ ++static ssize_t at24_regmap_read(struct at24_data *at24, char *buf, ++ unsigned int offset, size_t count) ++{ ++ unsigned long timeout, read_time; ++ struct at24_client *at24_client; ++ struct i2c_client *client; ++ struct regmap *regmap; ++ int ret; ++ ++ at24_client = at24_translate_offset(at24, &offset); ++ regmap = at24_client->regmap; ++ client = at24_client->client; ++ count = at24_adjust_read_count(at24, offset, count); ++ ++ /* adjust offset for mac and serial read ops */ ++ offset += at24->offset_adj; ++ ++ timeout = jiffies + msecs_to_jiffies(at24_write_timeout); ++ do { ++ /* ++ * The timestamp shall be taken before the actual operation ++ * to avoid a premature timeout in case of high CPU load. ++ */ ++ read_time = jiffies; ++ ++ ret = regmap_bulk_read(regmap, offset, buf, count); ++ dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n", ++ count, offset, ret, jiffies); ++ if (!ret) ++ return count; ++ ++ usleep_range(1000, 1500); ++ } while (time_before(read_time, timeout)); ++ ++ return -ETIMEDOUT; ++} ++ ++/* ++ * Note that if the hardware write-protect pin is pulled high, the whole ++ * chip is normally write protected. But there are plenty of product ++ * variants here, including OTP fuses and partial chip protect. ++ * ++ * We only use page mode writes; the alternative is sloooow. These routines ++ * write at most one page. ++ */ ++ ++static size_t at24_adjust_write_count(struct at24_data *at24, ++ unsigned int offset, size_t count) ++{ ++ unsigned int next_page; ++ ++ /* write_max is at most a page */ ++ if (count > at24->write_max) ++ count = at24->write_max; ++ ++ /* Never roll over backwards, to the start of this page */ ++ next_page = roundup(offset + 1, at24->page_size); ++ if (offset + count > next_page) ++ count = next_page - offset; ++ ++ return count; ++} ++ ++static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf, ++ unsigned int offset, size_t count) ++{ ++ unsigned long timeout, write_time; ++ struct at24_client *at24_client; ++ struct i2c_client *client; ++ struct regmap *regmap; ++ int ret; ++ ++ at24_client = at24_translate_offset(at24, &offset); ++ regmap = at24_client->regmap; ++ client = at24_client->client; ++ count = at24_adjust_write_count(at24, offset, count); ++ timeout = jiffies + msecs_to_jiffies(at24_write_timeout); ++ ++ do { ++ /* ++ * The timestamp shall be taken before the actual operation ++ * to avoid a premature timeout in case of high CPU load. ++ */ ++ write_time = jiffies; ++ ++ ret = regmap_bulk_write(regmap, offset, buf, count); ++ dev_dbg(&client->dev, "write %zu@%d --> %d (%ld)\n", ++ count, offset, ret, jiffies); ++ if (!ret) ++ return count; ++ ++ usleep_range(1000, 1500); ++ } while (time_before(write_time, timeout)); ++ ++ return -ETIMEDOUT; ++} ++ ++static int at24_read(void *priv, unsigned int off, void *val, size_t count) ++{ ++ struct at24_data *at24; ++ struct device *dev; ++ char *buf = val; ++ int i, ret; ++ ++ at24 = priv; ++ dev = at24_base_client_dev(at24); ++ ++ if (unlikely(!count)) ++ return count; ++ ++ if (off + count > at24->byte_len) ++ return -EINVAL; ++ ++ ret = pm_runtime_get_sync(dev); ++ if (ret < 0) { ++ pm_runtime_put_noidle(dev); ++ return ret; ++ } ++ ++ /* ++ * Read data from chip, protecting against concurrent updates ++ * from this host, but not from other I2C masters. ++ */ ++ mutex_lock(&at24->lock); ++ ++ for (i = 0; count; i += ret, count -= ret) { ++ ret = at24_regmap_read(at24, buf + i, off + i, count); ++ if (ret < 0) { ++ mutex_unlock(&at24->lock); ++ pm_runtime_put(dev); ++ return ret; ++ } ++ } ++ ++ mutex_unlock(&at24->lock); ++ ++ pm_runtime_put(dev); ++ ++ if (unlikely(at24->read_post)) ++ at24->read_post(off, buf, i); ++ ++ return 0; ++} ++ ++static int at24_write(void *priv, unsigned int off, void *val, size_t count) ++{ ++ struct at24_data *at24; ++ struct device *dev; ++ char *buf = val; ++ int ret; ++ ++ at24 = priv; ++ dev = at24_base_client_dev(at24); ++ ++ if (unlikely(!count)) ++ return -EINVAL; ++ ++ if (off + count > at24->byte_len) ++ return -EINVAL; ++ ++ ret = pm_runtime_get_sync(dev); ++ if (ret < 0) { ++ pm_runtime_put_noidle(dev); ++ return ret; ++ } ++ ++ /* ++ * Write data to chip, protecting against concurrent updates ++ * from this host, but not from other I2C masters. ++ */ ++ mutex_lock(&at24->lock); ++ ++ while (count) { ++ ret = at24_regmap_write(at24, buf, off, count); ++ if (ret < 0) { ++ mutex_unlock(&at24->lock); ++ pm_runtime_put(dev); ++ return ret; ++ } ++ buf += ret; ++ off += ret; ++ count -= ret; ++ } ++ ++ mutex_unlock(&at24->lock); ++ ++ pm_runtime_put(dev); ++ ++ return 0; ++} ++ ++static const struct at24_chip_data *at24_get_chip_data(struct device *dev) ++{ ++ struct device_node *of_node = dev->of_node; ++ const struct at24_chip_data *cdata; ++ const struct i2c_device_id *id; ++ ++ id = i2c_match_id(at24_ids, to_i2c_client(dev)); ++ ++ /* ++ * The I2C core allows OF nodes compatibles to match against the ++ * I2C device ID table as a fallback, so check not only if an OF ++ * node is present but also if it matches an OF device ID entry. ++ */ ++ if (of_node && of_match_device(at24_of_match, dev)) ++ cdata = of_device_get_match_data(dev); ++ else if (id) ++ cdata = (void *)id->driver_data; ++ else ++ cdata = acpi_device_get_match_data(dev); ++ ++ if (!cdata) ++ return ERR_PTR(-ENODEV); ++ ++ return cdata; ++} ++ ++static int at24_make_dummy_client(struct at24_data *at24, unsigned int index, ++ struct regmap_config *regmap_config) ++{ ++ struct i2c_client *base_client, *dummy_client; ++ struct regmap *regmap; ++ struct device *dev; ++ ++ base_client = at24->client[0].client; ++ dev = &base_client->dev; ++ ++ dummy_client = devm_i2c_new_dummy_device(dev, base_client->adapter, ++ base_client->addr + index); ++ if (IS_ERR(dummy_client)) ++ return PTR_ERR(dummy_client); ++ ++ regmap = devm_regmap_init_i2c(dummy_client, regmap_config); ++ if (IS_ERR(regmap)) ++ return PTR_ERR(regmap); ++ ++ at24->client[index].client = dummy_client; ++ at24->client[index].regmap = regmap; ++ ++ return 0; ++} ++ ++static unsigned int at24_get_offset_adj(u8 flags, unsigned int byte_len) ++{ ++ if (flags & AT24_FLAG_MAC) { ++ /* EUI-48 starts from 0x9a, EUI-64 from 0x98 */ ++ return 0xa0 - byte_len; ++ } else if (flags & AT24_FLAG_SERIAL && flags & AT24_FLAG_ADDR16) { ++ /* ++ * For 16 bit address pointers, the word address must contain ++ * a '10' sequence in bits 11 and 10 regardless of the ++ * intended position of the address pointer. ++ */ ++ return 0x0800; ++ } else if (flags & AT24_FLAG_SERIAL) { ++ /* ++ * Otherwise the word address must begin with a '10' sequence, ++ * regardless of the intended address. ++ */ ++ return 0x0080; ++ } else { ++ return 0; ++ } ++} ++ ++static int at24_probe(struct i2c_client *client) ++{ ++ struct regmap_config regmap_config = { }; ++ struct nvmem_config nvmem_config = { }; ++ u32 byte_len, page_size, flags, addrw; ++ const struct at24_chip_data *cdata; ++ struct device *dev = &client->dev; ++ bool i2c_fn_i2c, i2c_fn_block; ++ unsigned int i, num_addresses; ++ struct at24_data *at24; ++ struct regmap *regmap; ++ bool writable; ++ u8 test_byte; ++ int err; ++ ++ i2c_fn_i2c = i2c_check_functionality(client->adapter, I2C_FUNC_I2C); ++ i2c_fn_block = i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK); ++ ++ cdata = at24_get_chip_data(dev); ++ if (IS_ERR(cdata)) ++ return PTR_ERR(cdata); ++ ++ err = device_property_read_u32(dev, "pagesize", &page_size); ++ if (err) ++ /* ++ * This is slow, but we can't know all eeproms, so we better ++ * play safe. Specifying custom eeprom-types via device tree ++ * or properties is recommended anyhow. ++ */ ++ page_size = 1; ++ ++ flags = cdata->flags; ++ if (device_property_present(dev, "read-only")) ++ flags |= AT24_FLAG_READONLY; ++ if (device_property_present(dev, "no-read-rollover")) ++ flags |= AT24_FLAG_NO_RDROL; ++ ++ err = device_property_read_u32(dev, "address-width", &addrw); ++ if (!err) { ++ switch (addrw) { ++ case 8: ++ if (flags & AT24_FLAG_ADDR16) ++ dev_warn(dev, ++ "Override address width to be 8, while default is 16\n"); ++ flags &= ~AT24_FLAG_ADDR16; ++ break; ++ case 16: ++ flags |= AT24_FLAG_ADDR16; ++ break; ++ default: ++ dev_warn(dev, "Bad \"address-width\" property: %u\n", ++ addrw); ++ } ++ } ++ ++ err = device_property_read_u32(dev, "size", &byte_len); ++ if (err) ++ byte_len = cdata->byte_len; ++ ++ if (!i2c_fn_i2c && !i2c_fn_block) ++ page_size = 1; ++ ++ if (!page_size) { ++ dev_err(dev, "page_size must not be 0!\n"); ++ return -EINVAL; ++ } ++ ++ if (!is_power_of_2(page_size)) ++ dev_warn(dev, "page_size looks suspicious (no power of 2)!\n"); ++ ++ err = device_property_read_u32(dev, "num-addresses", &num_addresses); ++ if (err) { ++ if (flags & AT24_FLAG_TAKE8ADDR) ++ num_addresses = 8; ++ else ++ num_addresses = DIV_ROUND_UP(byte_len, ++ (flags & AT24_FLAG_ADDR16) ? 65536 : 256); ++ } ++ ++ if ((flags & AT24_FLAG_SERIAL) && (flags & AT24_FLAG_MAC)) { ++ dev_err(dev, ++ "invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC."); ++ return -EINVAL; ++ } ++ ++ regmap_config.val_bits = 8; ++ regmap_config.reg_bits = (flags & AT24_FLAG_ADDR16) ? 16 : 8; ++ regmap_config.disable_locking = true; ++ ++ regmap = devm_regmap_init_i2c(client, ®map_config); ++ if (IS_ERR(regmap)) ++ return PTR_ERR(regmap); ++ ++ at24 = devm_kzalloc(dev, struct_size(at24, client, num_addresses), ++ GFP_KERNEL); ++ if (!at24) ++ return -ENOMEM; ++ ++ mutex_init(&at24->lock); ++ at24->byte_len = byte_len; ++ at24->page_size = page_size; ++ at24->flags = flags; ++ at24->read_post = cdata->read_post; ++ at24->num_addresses = num_addresses; ++ at24->offset_adj = at24_get_offset_adj(flags, byte_len); ++ at24->client[0].client = client; ++ at24->client[0].regmap = regmap; ++ ++ at24->vcc_reg = devm_regulator_get(dev, "vcc"); ++ if (IS_ERR(at24->vcc_reg)) ++ return PTR_ERR(at24->vcc_reg); ++ ++ writable = !(flags & AT24_FLAG_READONLY); ++ if (writable) { ++ at24->write_max = min_t(unsigned int, ++ page_size, at24_io_limit); ++ if (!i2c_fn_i2c && at24->write_max > I2C_SMBUS_BLOCK_MAX) ++ at24->write_max = I2C_SMBUS_BLOCK_MAX; ++ } ++ ++ /* use dummy devices for multiple-address chips */ ++ for (i = 1; i < num_addresses; i++) { ++ err = at24_make_dummy_client(at24, i, ®map_config); ++ if (err) ++ return err; ++ } ++ ++ /* ++ * If the 'label' property is not present for the AT24 EEPROM, ++ * then nvmem_config.id is initialised to NVMEM_DEVID_AUTO, ++ * and this will append the 'devid' to the name of the NVMEM ++ * device. This is purely legacy and the AT24 driver has always ++ * defaulted to this. However, if the 'label' property is ++ * present then this means that the name is specified by the ++ * firmware and this name should be used verbatim and so it is ++ * not necessary to append the 'devid'. ++ */ ++ if (device_property_present(dev, "label")) { ++ nvmem_config.id = NVMEM_DEVID_NONE; ++ err = device_property_read_string(dev, "label", ++ &nvmem_config.name); ++ if (err) ++ return err; ++ } else { ++ nvmem_config.id = NVMEM_DEVID_AUTO; ++ nvmem_config.name = dev_name(dev); ++ } ++ ++ nvmem_config.type = NVMEM_TYPE_EEPROM; ++ nvmem_config.dev = dev; ++ nvmem_config.read_only = !writable; ++ nvmem_config.root_only = !(flags & AT24_FLAG_IRUGO); ++ nvmem_config.owner = THIS_MODULE; ++ nvmem_config.compat = true; ++ nvmem_config.base_dev = dev; ++ nvmem_config.reg_read = at24_read; ++ nvmem_config.reg_write = at24_write; ++ nvmem_config.priv = at24; ++ nvmem_config.stride = 1; ++ nvmem_config.word_size = 1; ++ nvmem_config.size = byte_len; ++ ++ i2c_set_clientdata(client, at24); ++ ++ err = regulator_enable(at24->vcc_reg); ++ if (err) { ++ dev_err(dev, "Failed to enable vcc regulator\n"); ++ return err; ++ } ++ ++ /* enable runtime pm */ ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ ++ at24->nvmem = devm_nvmem_register(dev, &nvmem_config); ++ if (IS_ERR(at24->nvmem)) { ++ pm_runtime_disable(dev); ++ if (!pm_runtime_status_suspended(dev)) ++ regulator_disable(at24->vcc_reg); ++ return PTR_ERR(at24->nvmem); ++ } ++ ++ /* ++ * Perform a one-byte test read to verify that the ++ * chip is functional. ++ */ ++ err = at24_read(at24, 0, &test_byte, 1); ++ if (err) { ++ pm_runtime_disable(dev); ++ if (!pm_runtime_status_suspended(dev)) ++ regulator_disable(at24->vcc_reg); ++ return -ENODEV; ++ } ++ ++ pm_runtime_idle(dev); ++ ++ if (writable) ++ dev_info(dev, "%u byte %s EEPROM, writable, %u bytes/write\n", ++ byte_len, client->name, at24->write_max); ++ else ++ dev_info(dev, "%u byte %s EEPROM, read-only\n", ++ byte_len, client->name); ++ ++ return 0; ++} ++ ++static int at24_remove(struct i2c_client *client) ++{ ++ struct at24_data *at24 = i2c_get_clientdata(client); ++ ++ pm_runtime_disable(&client->dev); ++ if (!pm_runtime_status_suspended(&client->dev)) ++ regulator_disable(at24->vcc_reg); ++ pm_runtime_set_suspended(&client->dev); ++ ++ return 0; ++} ++ ++static int __maybe_unused at24_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct at24_data *at24 = i2c_get_clientdata(client); ++ ++ return regulator_disable(at24->vcc_reg); ++} ++ ++static int __maybe_unused at24_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct at24_data *at24 = i2c_get_clientdata(client); ++ ++ return regulator_enable(at24->vcc_reg); ++} ++ ++static const struct dev_pm_ops at24_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) ++ SET_RUNTIME_PM_OPS(at24_suspend, at24_resume, NULL) ++}; ++ ++static struct i2c_driver at24_driver = { ++ .driver = { ++ .name = "wb_at24", ++ .pm = &at24_pm_ops, ++ .of_match_table = at24_of_match, ++ .acpi_match_table = ACPI_PTR(at24_acpi_ids), ++ }, ++ .probe_new = at24_probe, ++ .remove = at24_remove, ++ .id_table = at24_ids, ++}; ++ ++static int __init at24_init(void) ++{ ++ if (!at24_io_limit) { ++ pr_err("at24: at24_io_limit must not be 0!\n"); ++ return -EINVAL; ++ } ++ ++ at24_io_limit = rounddown_pow_of_two(at24_io_limit); ++ return i2c_add_driver(&at24_driver); ++} ++module_init(at24_init); ++ ++static void __exit at24_exit(void) ++{ ++ i2c_del_driver(&at24_driver); ++} ++module_exit(at24_exit); ++ ++MODULE_DESCRIPTION("Driver for most I2C EEPROMs"); ++MODULE_AUTHOR("support"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_csu550.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_csu550.c +new file mode 100644 +index 000000000..36d07f071 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_csu550.c +@@ -0,0 +1,236 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Hardware monitoring driver for PMBus devices ++ * ++ * Copyright (c) 2010, 2011 Ericsson AB. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "wb_pmbus.h" ++ ++struct pmbus_device_info { ++ int pages; ++ u32 flags; ++}; ++ ++static const struct i2c_device_id pmbus_id[]; ++ ++/* ++ * Find sensor groups and status registers on each page. ++ */ ++static void pmbus_find_sensor_groups(struct i2c_client *client, ++ struct pmbus_driver_info *info) ++{ ++ int page; ++ ++ /* Sensors detected on page 0 only */ ++ if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_VIN)) ++ info->func[0] |= PMBUS_HAVE_VIN; ++ if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_IIN)) ++ info->func[0] |= PMBUS_HAVE_IIN; ++ if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_PIN)) ++ info->func[0] |= PMBUS_HAVE_PIN; ++ if (info->func[0] ++ && wb_pmbus_check_byte_register(client, 0, PMBUS_STATUS_INPUT)) ++ info->func[0] |= PMBUS_HAVE_STATUS_INPUT; ++ if (wb_pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_12) && ++ wb_pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_1)) { ++ info->func[0] |= PMBUS_HAVE_FAN12; ++ if (wb_pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_12)) ++ info->func[0] |= PMBUS_HAVE_STATUS_FAN12; ++ } ++ if (wb_pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_34) && ++ wb_pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_3)) { ++ info->func[0] |= PMBUS_HAVE_FAN34; ++ if (wb_pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_34)) ++ info->func[0] |= PMBUS_HAVE_STATUS_FAN34; ++ } ++ if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_1)) ++ info->func[0] |= PMBUS_HAVE_TEMP; ++ if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_2)) ++ info->func[0] |= PMBUS_HAVE_TEMP2; ++ if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_3)) ++ info->func[0] |= PMBUS_HAVE_TEMP3; ++ if (info->func[0] & (PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 ++ | PMBUS_HAVE_TEMP3) ++ && wb_pmbus_check_byte_register(client, 0, ++ PMBUS_STATUS_TEMPERATURE)) ++ info->func[0] |= PMBUS_HAVE_STATUS_TEMP; ++ ++ /* Sensors detected on all pages */ ++ for (page = 0; page < info->pages; page++) { ++ if (wb_pmbus_check_word_register(client, page, PMBUS_READ_VOUT)) { ++ info->func[page] |= PMBUS_HAVE_VOUT; ++ if (wb_pmbus_check_byte_register(client, page, ++ PMBUS_STATUS_VOUT)) ++ info->func[page] |= PMBUS_HAVE_STATUS_VOUT; ++ } ++ if (wb_pmbus_check_word_register(client, page, PMBUS_READ_IOUT)) { ++ info->func[page] |= PMBUS_HAVE_IOUT; ++ if (wb_pmbus_check_byte_register(client, 0, ++ PMBUS_STATUS_IOUT)) ++ info->func[page] |= PMBUS_HAVE_STATUS_IOUT; ++ } ++ if (wb_pmbus_check_word_register(client, page, PMBUS_READ_POUT)) ++ info->func[page] |= PMBUS_HAVE_POUT; ++ } ++} ++ ++/* ++ * Identify chip parameters. ++ */ ++static int pmbus_identify(struct i2c_client *client, ++ struct pmbus_driver_info *info) ++{ ++ int ret = 0; ++ ++ if (!info->pages) { ++ /* ++ * Check if the PAGE command is supported. If it is, ++ * keep setting the page number until it fails or until the ++ * maximum number of pages has been reached. Assume that ++ * this is the number of pages supported by the chip. ++ */ ++ if (wb_pmbus_check_byte_register(client, 0, PMBUS_PAGE)) { ++ int page; ++ ++ for (page = 1; page < PMBUS_PAGES; page++) { ++ if (wb_pmbus_set_page(client, page, 0xff) < 0) ++ break; ++ } ++ wb_pmbus_set_page(client, 0, 0xff); ++ info->pages = page; ++ } else { ++ info->pages = 1; ++ } ++ ++ wb_pmbus_clear_faults(client); ++ } ++ ++ if (wb_pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) { ++ int vout_mode, i; ++ ++ vout_mode = wb_pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); ++ if (vout_mode >= 0 && vout_mode != 0xff) { ++ switch (vout_mode >> 5) { ++ case 0: ++ break; ++ case 1: ++ info->format[PSC_VOLTAGE_OUT] = vid; ++ for (i = 0; i < info->pages; i++) ++ info->vrm_version[i] = vr11; ++ break; ++ case 2: ++ info->format[PSC_VOLTAGE_OUT] = direct; ++ break; ++ default: ++ ret = -ENODEV; ++ goto abort; ++ } ++ } ++ } ++ ++ /* ++ * We should check if the COEFFICIENTS register is supported. ++ * If it is, and the chip is configured for direct mode, we can read ++ * the coefficients from the chip, one set per group of sensor ++ * registers. ++ * ++ * To do this, we will need access to a chip which actually supports the ++ * COEFFICIENTS command, since the command is too complex to implement ++ * without testing it. Until then, abort if a chip configured for direct ++ * mode was detected. ++ */ ++ if (info->format[PSC_VOLTAGE_OUT] == direct) { ++ ret = -ENODEV; ++ goto abort; ++ } ++ ++ /* Try to find sensor groups */ ++ pmbus_find_sensor_groups(client, info); ++abort: ++ return ret; ++} ++ ++static int pmbus_probe(struct i2c_client *client) ++{ ++ struct pmbus_driver_info *info; ++ struct pmbus_platform_data *pdata = NULL; ++ struct device *dev = &client->dev; ++ struct pmbus_device_info *device_info; ++ ++ info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ ++ device_info = (struct pmbus_device_info *)i2c_match_id(pmbus_id, client)->driver_data; ++ if (device_info->flags & PMBUS_SKIP_STATUS_CHECK) { ++ pdata = devm_kzalloc(dev, sizeof(struct pmbus_platform_data), ++ GFP_KERNEL); ++ if (!pdata) ++ return -ENOMEM; ++ ++ pdata->flags = PMBUS_SKIP_STATUS_CHECK; ++ } ++ ++ info->pages = device_info->pages; ++ info->identify = pmbus_identify; ++ dev->platform_data = pdata; ++ ++ return wb_pmbus_do_probe(client, info); ++} ++ ++static const struct pmbus_device_info pmbus_info_one = { ++ .pages = 1, ++ .flags = 0 ++}; ++ ++static const struct pmbus_device_info pmbus_info_zero = { ++ .pages = 0, ++ .flags = 0 ++}; ++ ++static const struct pmbus_device_info pmbus_info_one_skip = { ++ .pages = 1, ++ .flags = PMBUS_SKIP_STATUS_CHECK ++}; ++ ++static const struct pmbus_device_info pmbus_info_zero_skip = { ++ .pages = 0, ++ .flags = PMBUS_SKIP_STATUS_CHECK ++}; ++/* ++ * Use driver_data to set the number of pages supported by the chip. ++ */ ++static const struct i2c_device_id pmbus_id[] = { ++ {"wb_csu550", (kernel_ulong_t)&pmbus_info_zero_skip}, ++ {"wb_csu800", (kernel_ulong_t)&pmbus_info_one_skip}, ++ {"wb_fsp1200", (kernel_ulong_t)&pmbus_info_one_skip}, ++ {"wb_dps550", (kernel_ulong_t)&pmbus_info_one_skip}, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(i2c, pmbus_id); ++ ++/* This is the driver that will be inserted */ ++static struct i2c_driver pmbus_driver = { ++ .driver = { ++ .name = "wb_pmbus", ++ }, ++ .probe_new = pmbus_probe, ++ .remove = wb_pmbus_do_remove, ++ .id_table = pmbus_id, ++}; ++ ++module_i2c_driver(pmbus_driver); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("Generic PMBus driver"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_algo_bit.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_algo_bit.c +new file mode 100644 +index 000000000..c98ac7a1c +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_algo_bit.c +@@ -0,0 +1,725 @@ ++/* ------------------------------------------------------------------------- ++ * i2c-algo-bit.c i2c driver algorithms for bit-shift adapters ++ * ------------------------------------------------------------------------- ++ * Copyright (C) 1995-2000 Simon G. Vogl ++ ++ 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. ++ * ------------------------------------------------------------------------- */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int g_i2c_algo_bit_debug = 0; ++static int g_i2c_algo_bit_error = 0; ++ ++module_param(g_i2c_algo_bit_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_i2c_algo_bit_error, int, S_IRUGO | S_IWUSR); ++ ++#define I2C_ALGO_BIT_DEBUG(fmt, args...) do { \ ++ if (g_i2c_algo_bit_debug) { \ ++ printk(KERN_INFO "[I2C_ALGO_BIT][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define I2C_ALGO_BIT_ERROR(fmt, args...) do { \ ++ if (g_i2c_algo_bit_error) { \ ++ printk(KERN_ERR "[I2C_ALGO_BIT][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++/* ----- global defines ----------------------------------------------- */ ++ ++#ifdef DEBUG ++#define bit_dbg(level, dev, format, args...) \ ++ do { \ ++ if (i2c_debug >= level) \ ++ dev_dbg(dev, format, ##args); \ ++ } while (0) ++#else ++#define bit_dbg(level, dev, format, args...) \ ++ do {} while (0) ++#endif /* DEBUG */ ++ ++/* ----- global variables --------------------------------------------- */ ++ ++static int bit_test; /* see if the line-setting functions work */ ++module_param(bit_test, int, S_IRUGO); ++MODULE_PARM_DESC(bit_test, "lines testing - 0 off; 1 report; 2 fail if stuck"); ++ ++#ifdef DEBUG ++static int i2c_debug = 1; ++module_param(i2c_debug, int, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(i2c_debug, ++ "debug level - 0 off; 1 normal; 2 verbose; 3 very verbose"); ++#endif ++ ++/* --- setting states on the bus with the right timing: --------------- */ ++ ++#define setsda(adap, val) adap->setsda(adap->data, val) ++#define setscl(adap, val) adap->setscl(adap->data, val) ++#define getsda(adap) adap->getsda(adap->data) ++#define getscl(adap) adap->getscl(adap->data) ++ ++static inline void sdalo(struct i2c_algo_bit_data *adap) ++{ ++ setsda(adap, 0); ++ udelay((adap->udelay + 1) / 2); ++} ++ ++static inline void sdahi(struct i2c_algo_bit_data *adap) ++{ ++ setsda(adap, 1); ++ udelay((adap->udelay + 1) / 2); ++} ++ ++static inline void scllo(struct i2c_algo_bit_data *adap) ++{ ++ setscl(adap, 0); ++ udelay(adap->udelay / 2); ++} ++ ++/* ++ * Raise scl line, and do checking for delays. This is necessary for slower ++ * devices. ++ */ ++static int sclhi(struct i2c_algo_bit_data *adap) ++{ ++ unsigned long start; ++ ++ setscl(adap, 1); ++ ++ /* Not all adapters have scl sense line... */ ++ if (!adap->getscl) ++ goto done; ++ ++ start = jiffies; ++ while (!getscl(adap)) { ++ /* This hw knows how to read the clock line, so we wait ++ * until it actually gets high. This is safer as some ++ * chips may hold it low ("clock stretching") while they ++ * are processing data internally. ++ */ ++ if (time_after(jiffies, start + adap->timeout)) { ++ /* Test one last time, as we may have been preempted ++ * between last check and timeout test. ++ */ ++ if (getscl(adap)) ++ break; ++ return -ETIMEDOUT; ++ } ++ cpu_relax(); ++ } ++#ifdef DEBUG ++ if (jiffies != start && i2c_debug >= 3) ++ pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go " ++ "high\n", jiffies - start); ++#endif ++ ++done: ++ udelay(adap->udelay); ++ return 0; ++} ++ ++/* --- other auxiliary functions -------------------------------------- */ ++static void i2c_start(struct i2c_algo_bit_data *adap) ++{ ++ /* assert: scl, sda are high */ ++ setsda(adap, 0); ++ udelay(adap->udelay); ++ scllo(adap); ++} ++ ++static void i2c_repstart(struct i2c_algo_bit_data *adap) ++{ ++ /* assert: scl is low */ ++ sdahi(adap); ++ sclhi(adap); ++ setsda(adap, 0); ++ udelay(adap->udelay); ++ scllo(adap); ++} ++ ++static void i2c_stop(struct i2c_algo_bit_data *adap) ++{ ++ /* assert: scl is low */ ++ sdalo(adap); ++ sclhi(adap); ++ setsda(adap, 1); ++ udelay(adap->udelay); ++} ++ ++/* send a byte without start cond., look for arbitration, ++ check ackn. from slave */ ++/* returns: ++ * 1 if the device acknowledged ++ * 0 if the device did not ack ++ * -ETIMEDOUT if an error occurred (while raising the scl line) ++ */ ++static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c) ++{ ++ int i; ++ int sb; ++ int ack; ++ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; ++ ++ /* assert: scl is low */ ++ for (i = 7; i >= 0; i--) { ++ sb = (c >> i) & 1; ++ setsda(adap, sb); ++ udelay((adap->udelay + 1) / 2); ++ if (sclhi(adap) < 0) { /* timed out */ ++ bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " ++ "timeout at bit #%d\n", (int)c, i); ++ return -ETIMEDOUT; ++ } ++ /* FIXME do arbitration here: ++ * if (sb && !getsda(adap)) -> ouch! Get out of here. ++ * ++ * Report a unique code, so higher level code can retry ++ * the whole (combined) message and *NOT* issue STOP. ++ */ ++ scllo(adap); ++ } ++ sdahi(adap); ++ if (sclhi(adap) < 0) { /* timeout */ ++ bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " ++ "timeout at ack\n", (int)c); ++ return -ETIMEDOUT; ++ } ++ ++ /* read ack: SDA should be pulled down by slave, or it may ++ * NAK (usually to report problems with the data we wrote). ++ */ ++ ack = !getsda(adap); /* ack: sda is pulled low -> success */ ++ bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c, ++ ack ? "A" : "NA"); ++ ++ scllo(adap); ++ return ack; ++ /* assert: scl is low (sda undef) */ ++} ++ ++static int i2c_inb(struct i2c_adapter *i2c_adap) ++{ ++ /* read byte via i2c port, without start/stop sequence */ ++ /* acknowledge is sent in i2c_read. */ ++ int i; ++ unsigned char indata = 0; ++ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; ++ ++ /* assert: scl is low */ ++ sdahi(adap); ++ for (i = 0; i < 8; i++) { ++ if (sclhi(adap) < 0) { /* timeout */ ++ bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit " ++ "#%d\n", 7 - i); ++ return -ETIMEDOUT; ++ } ++ indata *= 2; ++ if (getsda(adap)) ++ indata |= 0x01; ++ setscl(adap, 0); ++ udelay(i == 7 ? adap->udelay / 2 : adap->udelay); ++ } ++ /* assert: scl is low */ ++ return indata; ++} ++ ++/* ++ * Sanity check for the adapter hardware - check the reaction of ++ * the bus lines only if it seems to be idle. ++ */ ++static int test_bus(struct i2c_adapter *i2c_adap) ++{ ++ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; ++ const char *name = i2c_adap->name; ++ int scl, sda, ret; ++ ++ if (adap->pre_xfer) { ++ ret = adap->pre_xfer(i2c_adap); ++ if (ret < 0) ++ return -ENODEV; ++ } ++ ++ if (adap->getscl == NULL) ++ pr_info("%s: Testing SDA only, SCL is not readable\n", name); ++ ++ sda = getsda(adap); ++ scl = (adap->getscl == NULL) ? 1 : getscl(adap); ++ if (!scl || !sda) { ++ printk(KERN_WARNING ++ "%s: bus seems to be busy (scl=%d, sda=%d)\n", ++ name, scl, sda); ++ goto bailout; ++ } ++ ++ sdalo(adap); ++ sda = getsda(adap); ++ scl = (adap->getscl == NULL) ? 1 : getscl(adap); ++ if (sda) { ++ printk(KERN_WARNING "%s: SDA stuck high!\n", name); ++ goto bailout; ++ } ++ if (!scl) { ++ printk(KERN_WARNING "%s: SCL unexpected low " ++ "while pulling SDA low!\n", name); ++ goto bailout; ++ } ++ ++ sdahi(adap); ++ sda = getsda(adap); ++ scl = (adap->getscl == NULL) ? 1 : getscl(adap); ++ if (!sda) { ++ printk(KERN_WARNING "%s: SDA stuck low!\n", name); ++ goto bailout; ++ } ++ if (!scl) { ++ printk(KERN_WARNING "%s: SCL unexpected low " ++ "while pulling SDA high!\n", name); ++ goto bailout; ++ } ++ ++ scllo(adap); ++ sda = getsda(adap); ++ scl = (adap->getscl == NULL) ? 0 : getscl(adap); ++ if (scl) { ++ printk(KERN_WARNING "%s: SCL stuck high!\n", name); ++ goto bailout; ++ } ++ if (!sda) { ++ printk(KERN_WARNING "%s: SDA unexpected low " ++ "while pulling SCL low!\n", name); ++ goto bailout; ++ } ++ ++ sclhi(adap); ++ sda = getsda(adap); ++ scl = (adap->getscl == NULL) ? 1 : getscl(adap); ++ if (!scl) { ++ printk(KERN_WARNING "%s: SCL stuck low!\n", name); ++ goto bailout; ++ } ++ if (!sda) { ++ printk(KERN_WARNING "%s: SDA unexpected low " ++ "while pulling SCL high!\n", name); ++ goto bailout; ++ } ++ ++ if (adap->post_xfer) ++ adap->post_xfer(i2c_adap); ++ ++ pr_info("%s: Test OK\n", name); ++ return 0; ++bailout: ++ sdahi(adap); ++ sclhi(adap); ++ ++ if (adap->post_xfer) ++ adap->post_xfer(i2c_adap); ++ ++ return -ENODEV; ++} ++ ++/* ----- Utility functions ++ */ ++ ++/* try_address tries to contact a chip for a number of ++ * times before it gives up. ++ * return values: ++ * 1 chip answered ++ * 0 chip did not answer ++ * -x transmission error ++ */ ++static int try_address(struct i2c_adapter *i2c_adap, ++ unsigned char addr, int retries) ++{ ++ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; ++ int i, ret = 0; ++ ++ for (i = 0; i <= retries; i++) { ++ ret = i2c_outb(i2c_adap, addr); ++ if (ret == 1 || i == retries) ++ break; ++ bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); ++ i2c_stop(adap); ++ udelay(adap->udelay); ++ yield(); ++ bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); ++ i2c_start(adap); ++ } ++ if (i && ret) ++ bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at " ++ "0x%02x: %s\n", i + 1, ++ addr & 1 ? "read from" : "write to", addr >> 1, ++ ret == 1 ? "success" : "failed, timeout?"); ++ return ret; ++} ++ ++static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) ++{ ++ const unsigned char *temp = msg->buf; ++ int count = msg->len; ++ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; ++ int retval; ++ int wrcount = 0; ++ ++ while (count > 0) { ++ retval = i2c_outb(i2c_adap, *temp); ++ ++ /* OK/ACK; or ignored NAK */ ++ if ((retval > 0) || (nak_ok && (retval == 0))) { ++ count--; ++ temp++; ++ wrcount++; ++ ++ /* A slave NAKing the master means the slave didn't like ++ * something about the data it saw. For example, maybe ++ * the SMBus PEC was wrong. ++ */ ++ } else if (retval == 0) { ++ dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n"); ++ return -EIO; ++ ++ /* Timeout; or (someday) lost arbitration ++ * ++ * FIXME Lost ARB implies retrying the transaction from ++ * the first message, after the "winning" master issues ++ * its STOP. As a rule, upper layer code has no reason ++ * to know or care about this ... it is *NOT* an error. ++ */ ++ } else { ++ dev_err(&i2c_adap->dev, "sendbytes: error %d\n", ++ retval); ++ return retval; ++ } ++ } ++ return wrcount; ++} ++ ++static int acknak(struct i2c_adapter *i2c_adap, int is_ack) ++{ ++ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; ++ ++ /* assert: sda is high */ ++ if (is_ack) /* send ack */ ++ setsda(adap, 0); ++ udelay((adap->udelay + 1) / 2); ++ if (sclhi(adap) < 0) { /* timeout */ ++ dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n"); ++ return -ETIMEDOUT; ++ } ++ scllo(adap); ++ return 0; ++} ++ ++static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) ++{ ++ int inval; ++ int rdcount = 0; /* counts bytes read */ ++ unsigned char *temp = msg->buf; ++ int count = msg->len; ++ const unsigned flags = msg->flags; ++ ++ while (count > 0) { ++ inval = i2c_inb(i2c_adap); ++ if (inval >= 0) { ++ *temp = inval; ++ rdcount++; ++ } else { /* read timed out */ ++ break; ++ } ++ ++ temp++; ++ count--; ++ ++ /* Some SMBus transactions require that we receive the ++ transaction length as the first read byte. */ ++ if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) { ++ if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) { ++ if (!(flags & I2C_M_NO_RD_ACK)) ++ acknak(i2c_adap, 0); ++ dev_err(&i2c_adap->dev, "readbytes: invalid " ++ "block length (%d)\n", inval); ++ return -EPROTO; ++ } ++ /* The original count value accounts for the extra ++ bytes, that is, either 1 for a regular transaction, ++ or 2 for a PEC transaction. */ ++ count += inval; ++ msg->len += inval; ++ } ++ ++ bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n", ++ inval, ++ (flags & I2C_M_NO_RD_ACK) ++ ? "(no ack/nak)" ++ : (count ? "A" : "NA")); ++ ++ if (!(flags & I2C_M_NO_RD_ACK)) { ++ inval = acknak(i2c_adap, count); ++ if (inval < 0) ++ return inval; ++ } ++ } ++ return rdcount; ++} ++ ++/* doAddress initiates the transfer by generating the start condition (in ++ * try_address) and transmits the address in the necessary format to handle ++ * reads, writes as well as 10bit-addresses. ++ * returns: ++ * 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set ++ * -x an error occurred (like: -ENXIO if the device did not answer, or ++ * -ETIMEDOUT, for example if the lines are stuck...) ++ */ ++static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) ++{ ++ unsigned short flags = msg->flags; ++ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; ++ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; ++ ++ unsigned char addr; ++ int ret, retries; ++ ++ retries = nak_ok ? 0 : i2c_adap->retries; ++ ++ if (flags & I2C_M_TEN) { ++ /* a ten bit address */ ++ addr = 0xf0 | ((msg->addr >> 7) & 0x06); ++ bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr); ++ /* try extended address code...*/ ++ ret = try_address(i2c_adap, addr, retries); ++ if ((ret != 1) && !nak_ok) { ++ dev_err(&i2c_adap->dev, ++ "died at extended address code\n"); ++ return -ENXIO; ++ } ++ /* the remaining 8 bit address */ ++ ret = i2c_outb(i2c_adap, msg->addr & 0xff); ++ if ((ret != 1) && !nak_ok) { ++ /* the chip did not ack / xmission error occurred */ ++ dev_err(&i2c_adap->dev, "died at 2nd address code\n"); ++ return -ENXIO; ++ } ++ if (flags & I2C_M_RD) { ++ bit_dbg(3, &i2c_adap->dev, "emitting repeated " ++ "start condition\n"); ++ i2c_repstart(adap); ++ /* okay, now switch into reading mode */ ++ addr |= 0x01; ++ ret = try_address(i2c_adap, addr, retries); ++ if ((ret != 1) && !nak_ok) { ++ dev_err(&i2c_adap->dev, ++ "died at repeated address code\n"); ++ return -EIO; ++ } ++ } ++ } else { /* normal 7bit address */ ++ addr = msg->addr << 1; ++ if (flags & I2C_M_RD) ++ addr |= 1; ++ if (flags & I2C_M_REV_DIR_ADDR) ++ addr ^= 1; ++ ret = try_address(i2c_adap, addr, retries); ++ if ((ret != 1) && !nak_ok) ++ return -ENXIO; ++ } ++ ++ return 0; ++} ++ ++static void bit_i2c_unblock(struct i2c_adapter *i2c_adap) ++{ ++ int i; ++ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; ++ ++ for (i = 0; i < 9; i++) { ++ setscl(adap, 0); ++ udelay(5); ++ setscl(adap, 1); ++ udelay(5); ++ } ++ setscl(adap, 0); ++ setsda(adap, 0); ++ udelay(5); ++ setscl(adap, 1); ++ udelay(5); ++ setsda(adap, 1); ++} ++ ++static int check_bit_i2c_unblock(struct i2c_adapter *i2c_adap) ++{ ++ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; ++ int sda, scl; ++ ++ sda = getsda(adap); ++ scl = getscl(adap); ++ if ((sda == 0) && scl) { ++ I2C_ALGO_BIT_ERROR("SCL is high and SDA is low, send 9 clock to device.\n"); ++ bit_i2c_unblock(i2c_adap); ++ } ++ ++ sda = getsda(adap); ++ scl = getscl(adap); ++ if (sda && scl) { ++ I2C_ALGO_BIT_DEBUG("SCL and SDA are both high, i2c level check ok.\n"); ++ return 0; ++ } ++ dev_warn(&i2c_adap->dev, "Check i2c level failed, SCL %s, SDA %s.\n", scl ? "high" : "low", sda ? "high" : "low"); ++ return -EIO; ++} ++ ++static int bit_xfer(struct i2c_adapter *i2c_adap, ++ struct i2c_msg msgs[], int num) ++{ ++ struct i2c_msg *pmsg; ++ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; ++ int i, ret; ++ unsigned short nak_ok; ++ ++ if (adap->pre_xfer) { ++ ret = adap->pre_xfer(i2c_adap); ++ if (ret < 0) ++ return ret; ++ } ++ ++ if (check_bit_i2c_unblock(i2c_adap) < 0) { ++ I2C_ALGO_BIT_ERROR("check i2c is block.\n"); ++ return -EIO; ++ } ++ ++ bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); ++ i2c_start(adap); ++ for (i = 0; i < num; i++) { ++ pmsg = &msgs[i]; ++ nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; ++ if (!(pmsg->flags & I2C_M_NOSTART)) { ++ if (i) { ++ bit_dbg(3, &i2c_adap->dev, "emitting " ++ "repeated start condition\n"); ++ i2c_repstart(adap); ++ } ++ ret = bit_doAddress(i2c_adap, pmsg); ++ if ((ret != 0) && !nak_ok) { ++ bit_dbg(1, &i2c_adap->dev, "NAK from " ++ "device addr 0x%02x msg #%d\n", ++ msgs[i].addr, i); ++ goto bailout; ++ } ++ } ++ if (pmsg->flags & I2C_M_RD) { ++ /* read bytes into buffer*/ ++ ret = readbytes(i2c_adap, pmsg); ++ if (ret >= 1) ++ bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n", ++ ret, ret == 1 ? "" : "s"); ++ if (ret < pmsg->len) { ++ if (ret >= 0) ++ ret = -EIO; ++ goto bailout; ++ } ++ } else { ++ /* write bytes from buffer */ ++ ret = sendbytes(i2c_adap, pmsg); ++ if (ret >= 1) ++ bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n", ++ ret, ret == 1 ? "" : "s"); ++ if (ret < pmsg->len) { ++ if (ret >= 0) ++ ret = -EIO; ++ goto bailout; ++ } ++ } ++ } ++ ret = i; ++ ++bailout: ++ bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); ++ i2c_stop(adap); ++ ++ if (adap->post_xfer) ++ adap->post_xfer(i2c_adap); ++ return ret; ++} ++ ++static u32 bit_func(struct i2c_adapter *adap) ++{ ++ return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL | ++ I2C_FUNC_SMBUS_READ_BLOCK_DATA | ++ I2C_FUNC_SMBUS_BLOCK_PROC_CALL | ++ I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; ++} ++ ++/* -----exported algorithm data: ------------------------------------- */ ++ ++const struct i2c_algorithm wb_i2c_bit_algo = { ++ .master_xfer = bit_xfer, ++ .functionality = bit_func, ++}; ++EXPORT_SYMBOL(wb_i2c_bit_algo); ++ ++static const struct i2c_adapter_quirks i2c_bit_quirk_no_clk_stretch = { ++ .flags = I2C_AQ_NO_CLK_STRETCH, ++}; ++ ++/* ++ * registering functions to load algorithms at runtime ++ */ ++static int __i2c_bit_add_bus(struct i2c_adapter *adap, ++ int (*add_adapter)(struct i2c_adapter *)) ++{ ++ struct i2c_algo_bit_data *bit_adap = adap->algo_data; ++ int ret; ++ ++ if (bit_test) { ++ ret = test_bus(adap); ++ if (bit_test >= 2 && ret < 0) ++ return -ENODEV; ++ } ++ ++ /* register new adapter to i2c module... */ ++ adap->algo = &wb_i2c_bit_algo; ++ adap->retries = 3; ++ if (bit_adap->getscl == NULL) ++ adap->quirks = &i2c_bit_quirk_no_clk_stretch; ++ ++ ret = add_adapter(adap); ++ if (ret < 0) ++ return ret; ++ ++ /* Complain if SCL can't be read */ ++ if (bit_adap->getscl == NULL) { ++ dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n"); ++ dev_warn(&adap->dev, "Bus may be unreliable\n"); ++ } ++ return 0; ++} ++ ++int wb_i2c_bit_add_bus(struct i2c_adapter *adap) ++{ ++ return __i2c_bit_add_bus(adap, i2c_add_adapter); ++} ++EXPORT_SYMBOL(wb_i2c_bit_add_bus); ++ ++int wb_i2c_bit_add_numbered_bus(struct i2c_adapter *adap) ++{ ++ return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter); ++} ++EXPORT_SYMBOL(wb_i2c_bit_add_numbered_bus); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio.c +new file mode 100644 +index 000000000..0362e905f +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio.c +@@ -0,0 +1,431 @@ ++/* ++ * Bitbanging I2C bus driver using the GPIO API ++ * ++ * Copyright (C) 2007 Atmel Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++extern int wb_i2c_bit_add_numbered_bus(struct i2c_adapter *adap); ++ ++struct i2c_gpio_private_data { ++ struct gpio_desc *sda; ++ struct gpio_desc *scl; ++ struct i2c_adapter adap; ++ struct i2c_algo_bit_data bit_data; ++ struct i2c_gpio_platform_data pdata; ++#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR ++ struct dentry *debug_dir; ++#endif ++}; ++ ++/* ++ * Toggle SDA by changing the output value of the pin. This is only ++ * valid for pins configured as open drain (i.e. setting the value ++ * high effectively turns off the output driver.) ++ */ ++static void i2c_gpio_setsda_val(void *data, int state) ++{ ++ struct i2c_gpio_private_data *priv = data; ++ ++ gpiod_set_value_cansleep(priv->sda, state); ++} ++ ++/* ++ * Toggle SCL by changing the output value of the pin. This is used ++ * for pins that are configured as open drain and for output-only ++ * pins. The latter case will break the i2c protocol, but it will ++ * often work in practice. ++ */ ++static void i2c_gpio_setscl_val(void *data, int state) ++{ ++ struct i2c_gpio_private_data *priv = data; ++ ++ gpiod_set_value_cansleep(priv->scl, state); ++} ++ ++static int i2c_gpio_getsda(void *data) ++{ ++ struct i2c_gpio_private_data *priv = data; ++ ++ return gpiod_get_value_cansleep(priv->sda); ++} ++ ++static int i2c_gpio_getscl(void *data) ++{ ++ struct i2c_gpio_private_data *priv = data; ++ ++ return gpiod_get_value_cansleep(priv->scl); ++} ++ ++#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR ++static struct dentry *i2c_gpio_debug_dir; ++ ++#define setsda(bd, val) ((bd)->setsda((bd)->data, val)) ++#define setscl(bd, val) ((bd)->setscl((bd)->data, val)) ++#define getsda(bd) ((bd)->getsda((bd)->data)) ++#define getscl(bd) ((bd)->getscl((bd)->data)) ++ ++#define WIRE_ATTRIBUTE(wire) \ ++static int fops_##wire##_get(void *data, u64 *val) \ ++{ \ ++ struct i2c_gpio_private_data *priv = data; \ ++ \ ++ i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ ++ *val = get##wire(&priv->bit_data); \ ++ i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ ++ return 0; \ ++} \ ++static int fops_##wire##_set(void *data, u64 val) \ ++{ \ ++ struct i2c_gpio_private_data *priv = data; \ ++ \ ++ i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ ++ set##wire(&priv->bit_data, val); \ ++ i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ ++ return 0; \ ++} \ ++DEFINE_DEBUGFS_ATTRIBUTE(fops_##wire, fops_##wire##_get, fops_##wire##_set, "%llu\n") ++ ++WIRE_ATTRIBUTE(scl); ++WIRE_ATTRIBUTE(sda); ++ ++static void i2c_gpio_incomplete_transfer(struct i2c_gpio_private_data *priv, ++ u32 pattern, u8 pattern_size) ++{ ++ struct i2c_algo_bit_data *bit_data = &priv->bit_data; ++ int i; ++ ++ i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); ++ ++ /* START condition */ ++ setsda(bit_data, 0); ++ udelay(bit_data->udelay); ++ ++ /* Send pattern, request ACK, don't send STOP */ ++ for (i = pattern_size - 1; i >= 0; i--) { ++ setscl(bit_data, 0); ++ udelay(bit_data->udelay / 2); ++ setsda(bit_data, (pattern >> i) & 1); ++ udelay((bit_data->udelay + 1) / 2); ++ setscl(bit_data, 1); ++ udelay(bit_data->udelay); ++ } ++ ++ i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); ++} ++ ++static int fops_incomplete_addr_phase_set(void *data, u64 addr) ++{ ++ struct i2c_gpio_private_data *priv = data; ++ u32 pattern; ++ ++ if (addr > 0x7f) ++ return -EINVAL; ++ ++ /* ADDR (7 bit) + RD (1 bit) + Client ACK, keep SDA hi (1 bit) */ ++ pattern = (addr << 2) | 3; ++ ++ i2c_gpio_incomplete_transfer(priv, pattern, 9); ++ ++ return 0; ++} ++DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_addr_phase, NULL, fops_incomplete_addr_phase_set, "%llu\n"); ++ ++static int fops_incomplete_write_byte_set(void *data, u64 addr) ++{ ++ struct i2c_gpio_private_data *priv = data; ++ u32 pattern; ++ ++ if (addr > 0x7f) ++ return -EINVAL; ++ ++ /* ADDR (7 bit) + WR (1 bit) + Client ACK (1 bit) */ ++ pattern = (addr << 2) | 1; ++ /* 0x00 (8 bit) + Client ACK, keep SDA hi (1 bit) */ ++ pattern = (pattern << 9) | 1; ++ ++ i2c_gpio_incomplete_transfer(priv, pattern, 18); ++ ++ return 0; ++} ++DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write_byte_set, "%llu\n"); ++ ++static void i2c_gpio_fault_injector_init(struct platform_device *pdev) ++{ ++ struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); ++ ++ /* ++ * If there will be a debugfs-dir per i2c adapter somewhen, put the ++ * 'fault-injector' dir there. Until then, we have a global dir with ++ * all adapters as subdirs. ++ */ ++ if (!i2c_gpio_debug_dir) { ++ i2c_gpio_debug_dir = debugfs_create_dir("i2c-fault-injector", NULL); ++ if (!i2c_gpio_debug_dir) ++ return; ++ } ++ ++ priv->debug_dir = debugfs_create_dir(pdev->name, i2c_gpio_debug_dir); ++ if (!priv->debug_dir) ++ return; ++ ++ debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl); ++ debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda); ++ debugfs_create_file_unsafe("incomplete_address_phase", 0200, priv->debug_dir, ++ priv, &fops_incomplete_addr_phase); ++ debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->debug_dir, ++ priv, &fops_incomplete_write_byte); ++} ++ ++static void i2c_gpio_fault_injector_exit(struct platform_device *pdev) ++{ ++ struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); ++ ++ debugfs_remove_recursive(priv->debug_dir); ++} ++#else ++static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {} ++static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {} ++#endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/ ++ ++static void of_i2c_gpio_get_props(struct device_node *np, ++ struct i2c_gpio_platform_data *pdata) ++{ ++ u32 reg; ++ ++ of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay); ++ ++ if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", ®)) ++ pdata->timeout = msecs_to_jiffies(reg); ++ ++ pdata->sda_is_open_drain = ++ of_property_read_bool(np, "i2c-gpio,sda-open-drain"); ++ pdata->scl_is_open_drain = ++ of_property_read_bool(np, "i2c-gpio,scl-open-drain"); ++ pdata->scl_is_output_only = ++ of_property_read_bool(np, "i2c-gpio,scl-output-only"); ++} ++ ++static struct gpio_desc *i2c_gpio_get_desc(struct device *dev, ++ const char *con_id, ++ unsigned int index, ++ enum gpiod_flags gflags) ++{ ++ struct gpio_desc *retdesc; ++ int ret; ++ ++ retdesc = devm_gpiod_get(dev, con_id, gflags); ++ if (!IS_ERR(retdesc)) { ++ dev_dbg(dev, "got GPIO from name %s\n", con_id); ++ return retdesc; ++ } ++ ++ retdesc = devm_gpiod_get_index(dev, NULL, index, gflags); ++ if (!IS_ERR(retdesc)) { ++ dev_dbg(dev, "got GPIO from index %u\n", index); ++ return retdesc; ++ } ++ ++ ret = PTR_ERR(retdesc); ++ ++ /* FIXME: hack in the old code, is this really necessary? */ ++ if (ret == -EINVAL) ++ retdesc = ERR_PTR(-EPROBE_DEFER); ++ ++ /* This happens if the GPIO driver is not yet probed, let's defer */ ++ if (ret == -ENOENT) ++ retdesc = ERR_PTR(-EPROBE_DEFER); ++ ++ if (PTR_ERR(retdesc) != -EPROBE_DEFER) ++ dev_err(dev, "error trying to get descriptor: %d\n", ret); ++ ++ return retdesc; ++} ++ ++static int i2c_gpio_probe(struct platform_device *pdev) ++{ ++ struct i2c_gpio_private_data *priv; ++ struct i2c_gpio_platform_data *pdata; ++ struct i2c_algo_bit_data *bit_data; ++ struct i2c_adapter *adap; ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ enum gpiod_flags gflags; ++ int ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ adap = &priv->adap; ++ bit_data = &priv->bit_data; ++ pdata = &priv->pdata; ++ ++ if (np) { ++ of_i2c_gpio_get_props(np, pdata); ++ } else { ++ /* ++ * If all platform data settings are zero it is OK ++ * to not provide any platform data from the board. ++ */ ++ if (dev_get_platdata(dev)) ++ memcpy(pdata, dev_get_platdata(dev), sizeof(*pdata)); ++ } ++ ++ /* ++ * First get the GPIO pins; if it fails, we'll defer the probe. ++ * If the SDA line is marked from platform data or device tree as ++ * "open drain" it means something outside of our control is making ++ * this line being handled as open drain, and we should just handle ++ * it as any other output. Else we enforce open drain as this is ++ * required for an I2C bus. ++ */ ++ if (pdata->sda_is_open_drain) ++ gflags = GPIOD_OUT_HIGH; ++ else ++ gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; ++ priv->sda = i2c_gpio_get_desc(dev, "sda", 0, gflags); ++ if (IS_ERR(priv->sda)) ++ return PTR_ERR(priv->sda); ++ ++ /* ++ * If the SCL line is marked from platform data or device tree as ++ * "open drain" it means something outside of our control is making ++ * this line being handled as open drain, and we should just handle ++ * it as any other output. Else we enforce open drain as this is ++ * required for an I2C bus. ++ */ ++ if (pdata->scl_is_open_drain) ++ gflags = GPIOD_OUT_HIGH; ++ else ++ gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; ++ priv->scl = i2c_gpio_get_desc(dev, "scl", 1, gflags); ++ if (IS_ERR(priv->scl)) ++ return PTR_ERR(priv->scl); ++ ++ if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl)) ++ dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing"); ++ ++ bit_data->setsda = i2c_gpio_setsda_val; ++ bit_data->setscl = i2c_gpio_setscl_val; ++ ++ if (!pdata->scl_is_output_only) ++ bit_data->getscl = i2c_gpio_getscl; ++ bit_data->getsda = i2c_gpio_getsda; ++ ++ if (pdata->udelay) ++ bit_data->udelay = pdata->udelay; ++ else if (pdata->scl_is_output_only) ++ bit_data->udelay = 50; /* 10 kHz */ ++ else ++ bit_data->udelay = 5; /* 100 kHz */ ++ ++ if (pdata->timeout) ++ bit_data->timeout = pdata->timeout; ++ else ++ bit_data->timeout = HZ / 10; /* 100 ms */ ++ ++ bit_data->data = priv; ++ ++ adap->owner = THIS_MODULE; ++ if (np) ++ strlcpy(adap->name, dev_name(dev), sizeof(adap->name)); ++ else ++ snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); ++ ++ adap->algo_data = bit_data; ++ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; ++ adap->dev.parent = dev; ++ adap->dev.of_node = np; ++ ++ adap->nr = pdev->id; ++ ret = wb_i2c_bit_add_numbered_bus(adap); ++ if (ret) ++ return ret; ++ ++ platform_set_drvdata(pdev, priv); ++ ++ /* ++ * FIXME: using global GPIO numbers is not helpful. If/when we ++ * get accessors to get the actual name of the GPIO line, ++ * from the descriptor, then provide that instead. ++ */ ++ dev_info(dev, "using lines %u (SDA) and %u (SCL%s)\n", ++ desc_to_gpio(priv->sda), desc_to_gpio(priv->scl), ++ pdata->scl_is_output_only ++ ? ", no clock stretching" : ""); ++ ++ i2c_gpio_fault_injector_init(pdev); ++ ++ return 0; ++} ++ ++static int i2c_gpio_remove(struct platform_device *pdev) ++{ ++ struct i2c_gpio_private_data *priv; ++ struct i2c_adapter *adap; ++ ++ i2c_gpio_fault_injector_exit(pdev); ++ ++ priv = platform_get_drvdata(pdev); ++ adap = &priv->adap; ++ ++ i2c_del_adapter(adap); ++ ++ return 0; ++} ++ ++#if defined(CONFIG_OF) ++static const struct of_device_id i2c_gpio_dt_ids[] = { ++ { .compatible = "wb-i2c-gpio", }, ++ { /* sentinel */ } ++}; ++ ++MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids); ++#endif ++ ++static struct platform_driver i2c_gpio_driver = { ++ .driver = { ++ .name = "wb-i2c-gpio", ++ .of_match_table = of_match_ptr(i2c_gpio_dt_ids), ++ }, ++ .probe = i2c_gpio_probe, ++ .remove = i2c_gpio_remove, ++}; ++ ++static int __init i2c_gpio_init(void) ++{ ++ int ret; ++ ++ ret = platform_driver_register(&i2c_gpio_driver); ++ if (ret) ++ printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret); ++ ++ return ret; ++} ++subsys_initcall(i2c_gpio_init); ++ ++static void __exit i2c_gpio_exit(void) ++{ ++ platform_driver_unregister(&i2c_gpio_driver); ++} ++module_exit(i2c_gpio_exit); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:i2c-gpio"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio_device.c +new file mode 100644 +index 000000000..1e1d815ee +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio_device.c +@@ -0,0 +1,133 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define I2C_GPIO_DEV_NAME_LEN (16) ++static char i2c_gpio_dev_name[I2C_GPIO_DEV_NAME_LEN] = {0}; ++ ++static int gpio_sda = 17; ++module_param(gpio_sda, int, S_IRUGO | S_IWUSR); ++ ++static int gpio_scl = 1; ++module_param(gpio_scl, int, S_IRUGO | S_IWUSR); ++ ++static int gpio_udelay = 2; ++module_param(gpio_udelay, int, S_IRUGO | S_IWUSR); ++ ++static int bus_num = -1; ++module_param(bus_num, int, S_IRUGO | S_IWUSR); ++ ++static char *gpio_chip_name = NULL; ++module_param(gpio_chip_name, charp, 0644); ++MODULE_PARM_DESC(str_var, "A string variable for GPIO controller"); ++ ++static int g_wb_i2c_gpio_device_debug = 0; ++static int g_wb_i2c_gpio_device_error = 0; ++ ++module_param(g_wb_i2c_gpio_device_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_i2c_gpio_device_error, int, S_IRUGO | S_IWUSR); ++ ++#define WB_I2C_GPIO_DEVICE_VERBOSE(fmt, args...) do { \ ++ if (g_wb_i2c_gpio_device_debug) { \ ++ printk(KERN_INFO "[WB_I2C_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_I2C_GPIO_DEVICE_ERROR(fmt, args...) do { \ ++ if (g_wb_i2c_gpio_device_error) { \ ++ printk(KERN_ERR "[WB_I2C_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++/****************** i2c adapter with gpio ***********************/ ++static struct i2c_gpio_platform_data i2c_pdata = { ++ .udelay = 2, ++ .scl_is_output_only = 0, ++ .sda_is_open_drain = 0, ++ .scl_is_open_drain = 0, ++}; ++ ++static void i2c_gpio_release(struct device *dev) ++{ ++ return; ++} ++ ++static struct platform_device wb_i2c_gpio_device = { ++ .name = "wb-i2c-gpio", ++ .id = -1, ++ .num_resources = 0, ++ .resource = NULL, ++ .dev = { ++ .platform_data = &i2c_pdata, ++ .release = i2c_gpio_release, ++ }, ++}; ++ ++/* ++ * i2c ++ */ ++static struct gpiod_lookup_table wb_i2c_gpio_table = { ++ .dev_id = "wb-i2c-gpio", ++ .table = { ++ GPIO_LOOKUP("wb_gpio_d1500", 17, "sda", ++ GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), ++ GPIO_LOOKUP("wb_gpio_d1500", 1, "scl", ++ GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), ++ { }, ++ }, ++}; ++ ++static int __init wb_i2c_gpio_device_init(void) ++{ ++ int err; ++ ++ WB_I2C_GPIO_DEVICE_VERBOSE("wb_i2c_gpio_device_init enter!\n"); ++ wb_i2c_gpio_table.table[0].chip_hwnum = gpio_sda; ++ wb_i2c_gpio_table.table[1].chip_hwnum = gpio_scl; ++ i2c_pdata.udelay = gpio_udelay; ++ ++ if (gpio_chip_name) { ++ wb_i2c_gpio_table.table[0].key = gpio_chip_name; ++ wb_i2c_gpio_table.table[1].key = gpio_chip_name; ++ } ++ ++ if (bus_num >= 0) { ++ wb_i2c_gpio_device.id = bus_num; ++ snprintf(i2c_gpio_dev_name, I2C_GPIO_DEV_NAME_LEN, "wb-i2c-gpio.%d", bus_num); ++ wb_i2c_gpio_table.dev_id = i2c_gpio_dev_name; ++ } ++ ++ gpiod_add_lookup_table(&wb_i2c_gpio_table); ++ ++ err = platform_device_register(&wb_i2c_gpio_device); ++ if (err < 0) { ++ printk(KERN_ERR "register i2c gpio device fail(%d). \n", err); ++ gpiod_remove_lookup_table(&wb_i2c_gpio_table); ++ return -1; ++ } ++ return 0; ++} ++ ++static void __exit wb_i2c_gpio_device_exit(void) ++{ ++ WB_I2C_GPIO_DEVICE_VERBOSE("wb_i2c_gpio_device_exit enter!\n"); ++ platform_device_unregister(&wb_i2c_gpio_device); ++ gpiod_remove_lookup_table(&wb_i2c_gpio_table); ++} ++ ++module_init(wb_i2c_gpio_device_init); ++module_exit(wb_i2c_gpio_device_exit); ++MODULE_DESCRIPTION("I2C GPIO Devices"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_i801.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_i801.c +new file mode 100644 +index 000000000..a733c1154 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_i801.c +@@ -0,0 +1,2114 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ Copyright (c) 1998 - 2002 Frodo Looijaard , ++ Philip Edelbrock , and Mark D. Studebaker ++ ++ Copyright (C) 2007 - 2014 Jean Delvare ++ Copyright (C) 2010 Intel Corporation, ++ David Woodhouse ++ ++*/ ++ ++/* ++ * Supports the following Intel I/O Controller Hubs (ICH): ++ * ++ * I/O Block I2C ++ * region SMBus Block proc. block ++ * Chip name PCI ID size PEC buffer call read ++ * --------------------------------------------------------------------------- ++ * 82801AA (ICH) 0x2413 16 no no no no ++ * 82801AB (ICH0) 0x2423 16 no no no no ++ * 82801BA (ICH2) 0x2443 16 no no no no ++ * 82801CA (ICH3) 0x2483 32 soft no no no ++ * 82801DB (ICH4) 0x24c3 32 hard yes no no ++ * 82801E (ICH5) 0x24d3 32 hard yes yes yes ++ * 6300ESB 0x25a4 32 hard yes yes yes ++ * 82801F (ICH6) 0x266a 32 hard yes yes yes ++ * 6310ESB/6320ESB 0x269b 32 hard yes yes yes ++ * 82801G (ICH7) 0x27da 32 hard yes yes yes ++ * 82801H (ICH8) 0x283e 32 hard yes yes yes ++ * 82801I (ICH9) 0x2930 32 hard yes yes yes ++ * EP80579 (Tolapai) 0x5032 32 hard yes yes yes ++ * ICH10 0x3a30 32 hard yes yes yes ++ * ICH10 0x3a60 32 hard yes yes yes ++ * 5/3400 Series (PCH) 0x3b30 32 hard yes yes yes ++ * 6 Series (PCH) 0x1c22 32 hard yes yes yes ++ * Patsburg (PCH) 0x1d22 32 hard yes yes yes ++ * Patsburg (PCH) IDF 0x1d70 32 hard yes yes yes ++ * Patsburg (PCH) IDF 0x1d71 32 hard yes yes yes ++ * Patsburg (PCH) IDF 0x1d72 32 hard yes yes yes ++ * DH89xxCC (PCH) 0x2330 32 hard yes yes yes ++ * Panther Point (PCH) 0x1e22 32 hard yes yes yes ++ * Lynx Point (PCH) 0x8c22 32 hard yes yes yes ++ * Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes ++ * Avoton (SOC) 0x1f3c 32 hard yes yes yes ++ * Wellsburg (PCH) 0x8d22 32 hard yes yes yes ++ * Wellsburg (PCH) MS 0x8d7d 32 hard yes yes yes ++ * Wellsburg (PCH) MS 0x8d7e 32 hard yes yes yes ++ * Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes ++ * Coleto Creek (PCH) 0x23b0 32 hard yes yes yes ++ * Wildcat Point (PCH) 0x8ca2 32 hard yes yes yes ++ * Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes ++ * BayTrail (SOC) 0x0f12 32 hard yes yes yes ++ * Braswell (SOC) 0x2292 32 hard yes yes yes ++ * Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes ++ * Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes ++ * DNV (SOC) 0x19df 32 hard yes yes yes ++ * Emmitsburg (PCH) 0x1bc9 32 hard yes yes yes ++ * Broxton (SOC) 0x5ad4 32 hard yes yes yes ++ * Lewisburg (PCH) 0xa1a3 32 hard yes yes yes ++ * Lewisburg Supersku (PCH) 0xa223 32 hard yes yes yes ++ * Kaby Lake PCH-H (PCH) 0xa2a3 32 hard yes yes yes ++ * Gemini Lake (SOC) 0x31d4 32 hard yes yes yes ++ * Cannon Lake-H (PCH) 0xa323 32 hard yes yes yes ++ * Cannon Lake-LP (PCH) 0x9da3 32 hard yes yes yes ++ * Cedar Fork (PCH) 0x18df 32 hard yes yes yes ++ * Ice Lake-LP (PCH) 0x34a3 32 hard yes yes yes ++ * Comet Lake (PCH) 0x02a3 32 hard yes yes yes ++ * Comet Lake-H (PCH) 0x06a3 32 hard yes yes yes ++ * Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes ++ * Tiger Lake-LP (PCH) 0xa0a3 32 hard yes yes yes ++ * Tiger Lake-H (PCH) 0x43a3 32 hard yes yes yes ++ * Jasper Lake (SOC) 0x4da3 32 hard yes yes yes ++ * Comet Lake-V (PCH) 0xa3a3 32 hard yes yes yes ++ * Alder Lake-S (PCH) 0x7aa3 32 hard yes yes yes ++ * ++ * Features supported by this driver: ++ * Software PEC no ++ * Hardware PEC yes ++ * Block buffer yes ++ * Block process call transaction yes ++ * I2C block read transaction yes (doesn't use the block buffer) ++ * Slave mode no ++ * SMBus Host Notify yes ++ * Interrupt processing yes ++ * ++ * See the file Documentation/i2c/busses/i2c-i801.rst for details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI ++#include ++#include ++#endif ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++ ++/* I801 SMBus address offsets */ ++#define SMBHSTSTS(p) (0 + (p)->smba) ++#define SMBHSTCNT(p) (2 + (p)->smba) ++#define SMBHSTCMD(p) (3 + (p)->smba) ++#define SMBHSTADD(p) (4 + (p)->smba) ++#define SMBHSTDAT0(p) (5 + (p)->smba) ++#define SMBHSTDAT1(p) (6 + (p)->smba) ++#define SMBBLKDAT(p) (7 + (p)->smba) ++#define SMBPEC(p) (8 + (p)->smba) /* ICH3 and later */ ++#define SMBAUXSTS(p) (12 + (p)->smba) /* ICH4 and later */ ++#define SMBAUXCTL(p) (13 + (p)->smba) /* ICH4 and later */ ++#define SMBSLVSTS(p) (16 + (p)->smba) /* ICH3 and later */ ++#define SMBSLVCMD(p) (17 + (p)->smba) /* ICH3 and later */ ++#define SMBNTFDADD(p) (20 + (p)->smba) /* ICH3 and later */ ++#define SMBPINCTL(p) (15 + (p)->smba) /* SMBus Pin Control Register */ ++ ++/* PCI Address Constants */ ++#define SMBBAR 4 ++#define SMBPCICTL 0x004 ++#define SMBPCISTS 0x006 ++#define SMBHSTCFG 0x040 ++#define TCOBASE 0x050 ++#define TCOCTL 0x054 ++ ++#define SBREG_BAR 0x10 ++#define SBREG_SMBCTRL 0xc6000c ++#define SBREG_SMBCTRL_DNV 0xcf000c ++ ++/* Host status bits for SMBPCISTS */ ++#define SMBPCISTS_INTS BIT(3) ++ ++/* Control bits for SMBPCICTL */ ++#define SMBPCICTL_INTDIS BIT(10) ++ ++/* Host configuration bits for SMBHSTCFG */ ++#define SMBHSTCFG_HST_EN BIT(0) ++#define SMBHSTCFG_SMB_SMI_EN BIT(1) ++#define SMBHSTCFG_I2C_EN BIT(2) ++#define SMBHSTCFG_SSRESET BIT(3) ++#define SSRESET_SLEEP_TIME 1 /* 1us */ ++#define SSRESET_RETRY_TIME (1000 / SSRESET_SLEEP_TIME) ++ ++/* Pin status for SMBPINCTL */ ++#define SMBPINCTL_CLK_STS 1 /* bit0 SMBCLK_CUR_STS*/ ++#define SMBPINCTL_SDA_STS 2 /* bit1 SMBDATA_CUR_STS*/ ++#define SMBPINCTL_CLK_CTL 4 /* bit2 SMBCLK_CTL */ ++ ++#define SMBHSTCFG_SPD_WD BIT(4) ++ ++/* TCO configuration bits for TCOCTL */ ++#define TCOCTL_EN BIT(8) ++ ++/* Auxiliary status register bits, ICH4+ only */ ++#define SMBAUXSTS_CRCE BIT(0) ++#define SMBAUXSTS_STCO BIT(1) ++ ++/* Auxiliary control register bits, ICH4+ only */ ++#define SMBAUXCTL_CRC BIT(0) ++#define SMBAUXCTL_E32B BIT(1) ++ ++/* Other settings */ ++#define MAX_RETRIES 400 ++ ++/* I801 command constants */ ++#define I801_QUICK 0x00 ++#define I801_BYTE 0x04 ++#define I801_BYTE_DATA 0x08 ++#define I801_WORD_DATA 0x0C ++#define I801_PROC_CALL 0x10 /* unimplemented */ ++#define I801_BLOCK_DATA 0x14 ++#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ ++#define I801_BLOCK_PROC_CALL 0x1C ++ ++/* I801 Host Control register bits */ ++#define SMBHSTCNT_INTREN BIT(0) ++#define SMBHSTCNT_KILL BIT(1) ++#define SMBHSTCNT_LAST_BYTE BIT(5) ++#define SMBHSTCNT_START BIT(6) ++#define SMBHSTCNT_PEC_EN BIT(7) /* ICH3 and later */ ++ ++/* I801 Hosts Status register bits */ ++#define SMBHSTSTS_BYTE_DONE BIT(7) ++#define SMBHSTSTS_INUSE_STS BIT(6) ++#define SMBHSTSTS_SMBALERT_STS BIT(5) ++#define SMBHSTSTS_FAILED BIT(4) ++#define SMBHSTSTS_BUS_ERR BIT(3) ++#define SMBHSTSTS_DEV_ERR BIT(2) ++#define SMBHSTSTS_INTR BIT(1) ++#define SMBHSTSTS_HOST_BUSY BIT(0) ++ ++/* Host Notify Status register bits */ ++#define SMBSLVSTS_HST_NTFY_STS BIT(0) ++ ++/* Host Notify Command register bits */ ++#define SMBSLVCMD_HST_NTFY_INTREN BIT(0) ++ ++#define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \ ++ SMBHSTSTS_DEV_ERR) ++ ++#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR | \ ++ STATUS_ERROR_FLAGS) ++ ++/* Older devices have their ID defined in */ ++#define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS 0x02a3 ++#define PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS 0x06a3 ++#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12 ++#define PCI_DEVICE_ID_INTEL_CDF_SMBUS 0x18df ++#define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df ++#define PCI_DEVICE_ID_INTEL_EBG_SMBUS 0x1bc9 ++#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 ++#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 ++/* Patsburg also has three 'Integrated Device Function' SMBus controllers */ ++#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70 ++#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71 ++#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72 ++#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22 ++#define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS 0x1f3c ++#define PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS 0x2292 ++#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 ++#define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0 ++#define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4 ++#define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS 0x34a3 ++#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 ++#define PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS 0x43a3 ++#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23 ++#define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS 0x4da3 ++#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4 ++#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS 0x7aa3 ++#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 ++#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS 0x8ca2 ++#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22 ++#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0 0x8d7d ++#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1 0x8d7e ++#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2 0x8d7f ++#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22 ++#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2 ++#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23 ++#define PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS 0x9da3 ++#define PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS 0xa0a3 ++#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123 ++#define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS 0xa1a3 ++#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223 ++#define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS 0xa2a3 ++#define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323 ++#define PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS 0xa3a3 ++ ++struct i801_mux_config { ++ char *gpio_chip; ++ unsigned values[3]; ++ int n_values; ++ unsigned classes[3]; ++ unsigned gpios[2]; /* Relative to gpio_chip->base */ ++ int n_gpios; ++}; ++ ++struct i801_priv { ++ struct i2c_adapter adapter; ++ unsigned long smba; ++ unsigned char original_hstcfg; ++ unsigned char original_slvcmd; ++ struct pci_dev *pci_dev; ++ unsigned int features; ++ ++ /* isr processing */ ++ wait_queue_head_t waitq; ++ u8 status; ++ ++ /* Command state used by isr for byte-by-byte block transactions */ ++ u8 cmd; ++ bool is_read; ++ int count; ++ int len; ++ u8 *data; ++ ++#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI ++ const struct i801_mux_config *mux_drvdata; ++ struct platform_device *mux_pdev; ++ struct gpiod_lookup_table *lookup; ++#endif ++ struct platform_device *tco_pdev; ++ ++ /* ++ * If set to true the host controller registers are reserved for ++ * ACPI AML use. Protected by acpi_lock. ++ */ ++ bool acpi_reserved; ++ struct mutex acpi_lock; ++}; ++ ++#define FEATURE_SMBUS_PEC BIT(0) ++#define FEATURE_BLOCK_BUFFER BIT(1) ++#define FEATURE_BLOCK_PROC BIT(2) ++#define FEATURE_I2C_BLOCK_READ BIT(3) ++#define FEATURE_IRQ BIT(4) ++#define FEATURE_HOST_NOTIFY BIT(5) ++/* Not really a feature, but it's convenient to handle it as such */ ++#define FEATURE_IDF BIT(15) ++#define FEATURE_TCO_SPT BIT(16) ++#define FEATURE_TCO_CNL BIT(17) ++ ++static const char *i801_feature_names[] = { ++ "SMBus PEC", ++ "Block buffer", ++ "Block process call", ++ "I2C block read", ++ "Interrupt", ++ "SMBus Host Notify", ++}; ++ ++static unsigned int disable_features; ++module_param(disable_features, uint, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n" ++ "\t\t 0x01 disable SMBus PEC\n" ++ "\t\t 0x02 disable the block buffer\n" ++ "\t\t 0x08 disable the I2C block read functionality\n" ++ "\t\t 0x10 don't use interrupts\n" ++ "\t\t 0x20 disable SMBus Host Notify "); ++ ++static void i801_setscl(struct i801_priv *priv, unsigned int level) ++{ ++ int pin_status; ++ pin_status = inb_p(SMBPINCTL(priv)); ++ if (level == 0) { ++ pin_status &= (~SMBPINCTL_CLK_CTL); ++ } ++ else { ++ pin_status |= SMBPINCTL_CLK_CTL; ++ } ++ outb_p(pin_status, SMBPINCTL(priv)); ++ return; ++} ++ ++static void i801_i2c_unblock(struct i801_priv *priv) ++{ ++ int i; ++ for (i = 0; i < 10; i++) { ++ i801_setscl(priv, 0); ++ udelay(5); ++ i801_setscl(priv, 1); ++ udelay(5); ++ } ++ return; ++} ++ ++static int i801_check_i2c_unblock(struct i801_priv *priv) ++{ ++ int pin_status; ++ ++ pin_status = inb_p(SMBPINCTL(priv)); ++ if ( (!(pin_status & SMBPINCTL_SDA_STS) ) && (pin_status & SMBPINCTL_CLK_STS) ) { ++ dev_dbg(&priv->pci_dev->dev, "SDA is low, send 9 clock to device!\n"); ++ i801_i2c_unblock(priv); ++ } ++ return 0; ++} ++ ++static void i801_do_reset(struct i801_priv *priv) ++{ ++ unsigned char tmp; ++ unsigned int retry_count = 0; ++ ++ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &tmp); ++ tmp |= SMBHSTCFG_SSRESET; ++ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, tmp); ++ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &tmp); ++ ++ while( ((tmp & SMBHSTCFG_SSRESET) != 0) && (retry_count < SSRESET_RETRY_TIME)) { ++ usleep_range(SSRESET_SLEEP_TIME, SSRESET_SLEEP_TIME + 1); ++ retry_count++; ++ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &tmp); ++ } ++ ++ return ; ++} ++ ++static int i801_check_i2c_scl(struct i801_priv *priv) ++{ ++ int pin_status; ++ ++ pin_status = inb_p(SMBPINCTL(priv)); ++ if ( (pin_status & SMBPINCTL_SDA_STS) && (pin_status & SMBPINCTL_CLK_STS) ) { ++ return 0; ++ } ++ ++ dev_dbg(&priv->pci_dev->dev, "SDA or SCL is low, begin to reset SMBus adapter, pin_status: 0x%x\n",pin_status); ++ i801_do_reset(priv); ++ pin_status = inb_p(SMBPINCTL(priv)); ++ if ( (pin_status & SMBPINCTL_SDA_STS) && (pin_status & SMBPINCTL_CLK_STS) ) { ++ return 0; ++ } ++ dev_warn(&priv->pci_dev->dev, "SDA or SCL is low.pin_status:0x%x\n",pin_status); ++ return -1; ++} ++ ++/* Make sure the SMBus host is ready to start transmitting. ++ Return 0 if it is, -EBUSY if it is not. */ ++static int i801_check_pre(struct i801_priv *priv) ++{ ++ int status; ++ ++ i801_check_i2c_unblock(priv); ++ ++ if (i801_check_i2c_scl(priv)) { ++ return -EIO; ++ } ++ ++ status = inb_p(SMBHSTSTS(priv)); ++ if (status & SMBHSTSTS_HOST_BUSY) { ++ dev_dbg(&priv->pci_dev->dev, "SMBus is busy, begin to reset SMBus adapter!\n"); ++ ++ i801_do_reset(priv); ++ ++ status = inb_p(SMBHSTSTS(priv)); ++ if (status & SMBHSTSTS_HOST_BUSY) { ++ dev_err(&priv->pci_dev->dev, "SMBus is busy, can't use it!\n"); ++ return -EBUSY; ++ } ++ } ++ ++ status &= STATUS_FLAGS; ++ if (status) { ++ dev_dbg(&priv->pci_dev->dev, "Clearing status flags (%02x)\n", ++ status); ++ outb_p(status, SMBHSTSTS(priv)); ++ status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS; ++ if (status) { ++ dev_err(&priv->pci_dev->dev, ++ "Failed clearing status flags (%02x)\n", ++ status); ++ return -EBUSY; ++ } ++ } ++ ++ /* ++ * Clear CRC status if needed. ++ * During normal operation, i801_check_post() takes care ++ * of it after every operation. We do it here only in case ++ * the hardware was already in this state when the driver ++ * started. ++ */ ++ if (priv->features & FEATURE_SMBUS_PEC) { ++ status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; ++ if (status) { ++ dev_dbg(&priv->pci_dev->dev, ++ "Clearing aux status flags (%02x)\n", status); ++ outb_p(status, SMBAUXSTS(priv)); ++ status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; ++ if (status) { ++ dev_err(&priv->pci_dev->dev, ++ "Failed clearing aux status flags (%02x)\n", ++ status); ++ return -EBUSY; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * Convert the status register to an error code, and clear it. ++ * Note that status only contains the bits we want to clear, not the ++ * actual register value. ++ */ ++static int i801_check_post(struct i801_priv *priv, int status) ++{ ++ int result = 0; ++ ++ /* ++ * If the SMBus is still busy, we give up ++ * Note: This timeout condition only happens when using polling ++ * transactions. For interrupt operation, NAK/timeout is indicated by ++ * DEV_ERR. ++ */ ++ if (unlikely(status < 0)) { ++ dev_err(&priv->pci_dev->dev, "Transaction timeout\n"); ++ /* try to stop the current command */ ++ dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n"); ++ outb_p(SMBHSTCNT_KILL, SMBHSTCNT(priv)); ++ usleep_range(1000, 2000); ++ outb_p(0, SMBHSTCNT(priv)); ++ ++ /* Check if it worked */ ++ status = inb_p(SMBHSTSTS(priv)); ++ if ((status & SMBHSTSTS_HOST_BUSY) || ++ !(status & SMBHSTSTS_FAILED)) ++ dev_err(&priv->pci_dev->dev, ++ "Failed terminating the transaction\n"); ++ outb_p(STATUS_FLAGS, SMBHSTSTS(priv)); ++ return -ETIMEDOUT; ++ } ++ ++ if (status & SMBHSTSTS_FAILED) { ++ result = -EIO; ++ dev_err(&priv->pci_dev->dev, "Transaction failed\n"); ++ } ++ if (status & SMBHSTSTS_DEV_ERR) { ++ /* ++ * This may be a PEC error, check and clear it. ++ * ++ * AUXSTS is handled differently from HSTSTS. ++ * For HSTSTS, i801_isr() or i801_wait_intr() ++ * has already cleared the error bits in hardware, ++ * and we are passed a copy of the original value ++ * in "status". ++ * For AUXSTS, the hardware register is left ++ * for us to handle here. ++ * This is asymmetric, slightly iffy, but safe, ++ * since all this code is serialized and the CRCE ++ * bit is harmless as long as it's cleared before ++ * the next operation. ++ */ ++ if ((priv->features & FEATURE_SMBUS_PEC) && ++ (inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE)) { ++ outb_p(SMBAUXSTS_CRCE, SMBAUXSTS(priv)); ++ result = -EBADMSG; ++ dev_dbg(&priv->pci_dev->dev, "PEC error\n"); ++ } else { ++ result = -ENXIO; ++ dev_dbg(&priv->pci_dev->dev, "No response\n"); ++ } ++ } ++ if (status & SMBHSTSTS_BUS_ERR) { ++ result = -EAGAIN; ++ dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n"); ++ } ++ ++ /* Clear status flags except BYTE_DONE, to be cleared by caller */ ++ outb_p(status, SMBHSTSTS(priv)); ++ ++ return result; ++} ++ ++/* Wait for BUSY being cleared and either INTR or an error flag being set */ ++static int i801_wait_intr(struct i801_priv *priv) ++{ ++ int timeout = 0; ++ int status; ++ ++ /* We will always wait for a fraction of a second! */ ++ do { ++ usleep_range(250, 500); ++ status = inb_p(SMBHSTSTS(priv)); ++ } while (((status & SMBHSTSTS_HOST_BUSY) || ++ !(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR))) && ++ (timeout++ < MAX_RETRIES)); ++ ++ if (timeout > MAX_RETRIES) { ++ dev_dbg(&priv->pci_dev->dev, "INTR Timeout!\n"); ++ return -ETIMEDOUT; ++ } ++ return status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR); ++} ++ ++/* Wait for either BYTE_DONE or an error flag being set */ ++static int i801_wait_byte_done(struct i801_priv *priv) ++{ ++ int timeout = 0; ++ int status; ++ ++ /* We will always wait for a fraction of a second! */ ++ do { ++ usleep_range(250, 500); ++ status = inb_p(SMBHSTSTS(priv)); ++ } while (!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE)) && ++ (timeout++ < MAX_RETRIES)); ++ ++ if (timeout > MAX_RETRIES) { ++ dev_dbg(&priv->pci_dev->dev, "BYTE_DONE Timeout!\n"); ++ return -ETIMEDOUT; ++ } ++ return status & STATUS_ERROR_FLAGS; ++} ++ ++static int i801_transaction(struct i801_priv *priv, int xact) ++{ ++ int status; ++ int result; ++ const struct i2c_adapter *adap = &priv->adapter; ++ ++ result = i801_check_pre(priv); ++ if (result < 0) ++ return result; ++ ++ if (priv->features & FEATURE_IRQ) { ++ outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START, ++ SMBHSTCNT(priv)); ++ result = wait_event_timeout(priv->waitq, ++ (status = priv->status), ++ adap->timeout); ++ if (!result) { ++ status = -ETIMEDOUT; ++ dev_warn(&priv->pci_dev->dev, ++ "Timeout waiting for interrupt!\n"); ++ } ++ priv->status = 0; ++ return i801_check_post(priv, status); ++ } ++ ++ /* the current contents of SMBHSTCNT can be overwritten, since PEC, ++ * SMBSCMD are passed in xact */ ++ outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv)); ++ ++ status = i801_wait_intr(priv); ++ return i801_check_post(priv, status); ++} ++ ++static int i801_block_transaction_by_block(struct i801_priv *priv, ++ union i2c_smbus_data *data, ++ char read_write, int command, ++ int hwpec) ++{ ++ int i, len; ++ int status; ++ int xact = hwpec ? SMBHSTCNT_PEC_EN : 0; ++ ++ switch (command) { ++ case I2C_SMBUS_BLOCK_PROC_CALL: ++ xact |= I801_BLOCK_PROC_CALL; ++ break; ++ case I2C_SMBUS_BLOCK_DATA: ++ xact |= I801_BLOCK_DATA; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */ ++ ++ /* Use 32-byte buffer to process this transaction */ ++ if (read_write == I2C_SMBUS_WRITE) { ++ len = data->block[0]; ++ outb_p(len, SMBHSTDAT0(priv)); ++ for (i = 0; i < len; i++) ++ outb_p(data->block[i+1], SMBBLKDAT(priv)); ++ } ++ ++ status = i801_transaction(priv, xact); ++ if (status) ++ return status; ++ ++ if (read_write == I2C_SMBUS_READ || ++ command == I2C_SMBUS_BLOCK_PROC_CALL) { ++ len = inb_p(SMBHSTDAT0(priv)); ++ if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) ++ return -EPROTO; ++ ++ data->block[0] = len; ++ for (i = 0; i < len; i++) ++ data->block[i + 1] = inb_p(SMBBLKDAT(priv)); ++ } ++ return 0; ++} ++ ++static void i801_isr_byte_done(struct i801_priv *priv) ++{ ++ if (priv->is_read) { ++ /* For SMBus block reads, length is received with first byte */ ++ if (((priv->cmd & 0x1c) == I801_BLOCK_DATA) && ++ (priv->count == 0)) { ++ priv->len = inb_p(SMBHSTDAT0(priv)); ++ if (priv->len < 1 || priv->len > I2C_SMBUS_BLOCK_MAX) { ++ dev_err(&priv->pci_dev->dev, ++ "Illegal SMBus block read size %d\n", ++ priv->len); ++ /* FIXME: Recover */ ++ priv->len = I2C_SMBUS_BLOCK_MAX; ++ } else { ++ dev_dbg(&priv->pci_dev->dev, ++ "SMBus block read size is %d\n", ++ priv->len); ++ } ++ priv->data[-1] = priv->len; ++ } ++ ++ /* Read next byte */ ++ if (priv->count < priv->len) ++ priv->data[priv->count++] = inb(SMBBLKDAT(priv)); ++ else ++ dev_dbg(&priv->pci_dev->dev, ++ "Discarding extra byte on block read\n"); ++ ++ /* Set LAST_BYTE for last byte of read transaction */ ++ if (priv->count == priv->len - 1) ++ outb_p(priv->cmd | SMBHSTCNT_LAST_BYTE, ++ SMBHSTCNT(priv)); ++ } else if (priv->count < priv->len - 1) { ++ /* Write next byte, except for IRQ after last byte */ ++ outb_p(priv->data[++priv->count], SMBBLKDAT(priv)); ++ } ++ ++ /* Clear BYTE_DONE to continue with next byte */ ++ outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); ++} ++ ++static irqreturn_t i801_host_notify_isr(struct i801_priv *priv) ++{ ++ unsigned short addr; ++ ++ addr = inb_p(SMBNTFDADD(priv)) >> 1; ++ ++ /* ++ * With the tested platforms, reading SMBNTFDDAT (22 + (p)->smba) ++ * always returns 0. Our current implementation doesn't provide ++ * data, so we just ignore it. ++ */ ++ i2c_handle_smbus_host_notify(&priv->adapter, addr); ++ ++ /* clear Host Notify bit and return */ ++ outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); ++ return IRQ_HANDLED; ++} ++ ++/* ++ * There are three kinds of interrupts: ++ * ++ * 1) i801 signals transaction completion with one of these interrupts: ++ * INTR - Success ++ * DEV_ERR - Invalid command, NAK or communication timeout ++ * BUS_ERR - SMI# transaction collision ++ * FAILED - transaction was canceled due to a KILL request ++ * When any of these occur, update ->status and wake up the waitq. ++ * ->status must be cleared before kicking off the next transaction. ++ * ++ * 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt ++ * occurs for each byte of a byte-by-byte to prepare the next byte. ++ * ++ * 3) Host Notify interrupts ++ */ ++static irqreturn_t i801_isr(int irq, void *dev_id) ++{ ++ struct i801_priv *priv = dev_id; ++ u16 pcists; ++ u8 status; ++ ++ /* Confirm this is our interrupt */ ++ pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists); ++ if (!(pcists & SMBPCISTS_INTS)) ++ return IRQ_NONE; ++ ++ if (priv->features & FEATURE_HOST_NOTIFY) { ++ status = inb_p(SMBSLVSTS(priv)); ++ if (status & SMBSLVSTS_HST_NTFY_STS) ++ return i801_host_notify_isr(priv); ++ } ++ ++ status = inb_p(SMBHSTSTS(priv)); ++ if (status & SMBHSTSTS_BYTE_DONE) ++ i801_isr_byte_done(priv); ++ ++ /* ++ * Clear irq sources and report transaction result. ++ * ->status must be cleared before the next transaction is started. ++ */ ++ status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS; ++ if (status) { ++ outb_p(status, SMBHSTSTS(priv)); ++ priv->status = status; ++ wake_up(&priv->waitq); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * For "byte-by-byte" block transactions: ++ * I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1 ++ * I2C read uses cmd=I801_I2C_BLOCK_DATA ++ */ ++static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, ++ union i2c_smbus_data *data, ++ char read_write, int command, ++ int hwpec) ++{ ++ int i, len; ++ int smbcmd; ++ int status; ++ int result; ++ const struct i2c_adapter *adap = &priv->adapter; ++ ++ if (command == I2C_SMBUS_BLOCK_PROC_CALL) ++ return -EOPNOTSUPP; ++ ++ result = i801_check_pre(priv); ++ if (result < 0) ++ return result; ++ ++ len = data->block[0]; ++ ++ if (read_write == I2C_SMBUS_WRITE) { ++ outb_p(len, SMBHSTDAT0(priv)); ++ outb_p(data->block[1], SMBBLKDAT(priv)); ++ } ++ ++ if (command == I2C_SMBUS_I2C_BLOCK_DATA && ++ read_write == I2C_SMBUS_READ) ++ smbcmd = I801_I2C_BLOCK_DATA; ++ else ++ smbcmd = I801_BLOCK_DATA; ++ ++ if (priv->features & FEATURE_IRQ) { ++ priv->is_read = (read_write == I2C_SMBUS_READ); ++ if (len == 1 && priv->is_read) ++ smbcmd |= SMBHSTCNT_LAST_BYTE; ++ priv->cmd = smbcmd | SMBHSTCNT_INTREN; ++ priv->len = len; ++ priv->count = 0; ++ priv->data = &data->block[1]; ++ ++ outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv)); ++ result = wait_event_timeout(priv->waitq, ++ (status = priv->status), ++ adap->timeout); ++ if (!result) { ++ status = -ETIMEDOUT; ++ dev_warn(&priv->pci_dev->dev, ++ "Timeout waiting for interrupt!\n"); ++ } ++ priv->status = 0; ++ return i801_check_post(priv, status); ++ } ++ ++ for (i = 1; i <= len; i++) { ++ if (i == len && read_write == I2C_SMBUS_READ) ++ smbcmd |= SMBHSTCNT_LAST_BYTE; ++ outb_p(smbcmd, SMBHSTCNT(priv)); ++ ++ if (i == 1) ++ outb_p(inb(SMBHSTCNT(priv)) | SMBHSTCNT_START, ++ SMBHSTCNT(priv)); ++ ++ status = i801_wait_byte_done(priv); ++ if (status) ++ goto exit; ++ ++ if (i == 1 && read_write == I2C_SMBUS_READ ++ && command != I2C_SMBUS_I2C_BLOCK_DATA) { ++ len = inb_p(SMBHSTDAT0(priv)); ++ if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) { ++ dev_err(&priv->pci_dev->dev, ++ "Illegal SMBus block read size %d\n", ++ len); ++ /* Recover */ ++ while (inb_p(SMBHSTSTS(priv)) & ++ SMBHSTSTS_HOST_BUSY) ++ outb_p(SMBHSTSTS_BYTE_DONE, ++ SMBHSTSTS(priv)); ++ outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv)); ++ return -EPROTO; ++ } ++ data->block[0] = len; ++ } ++ ++ /* Retrieve/store value in SMBBLKDAT */ ++ if (read_write == I2C_SMBUS_READ) ++ data->block[i] = inb_p(SMBBLKDAT(priv)); ++ if (read_write == I2C_SMBUS_WRITE && i+1 <= len) ++ outb_p(data->block[i+1], SMBBLKDAT(priv)); ++ ++ /* signals SMBBLKDAT ready */ ++ outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); ++ } ++ ++ status = i801_wait_intr(priv); ++exit: ++ return i801_check_post(priv, status); ++} ++ ++static int i801_set_block_buffer_mode(struct i801_priv *priv) ++{ ++ outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv)); ++ if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0) ++ return -EIO; ++ return 0; ++} ++ ++/* Block transaction function */ ++static int i801_block_transaction(struct i801_priv *priv, ++ union i2c_smbus_data *data, char read_write, ++ int command, int hwpec) ++{ ++ int result = 0; ++ unsigned char hostc; ++ ++ if (command == I2C_SMBUS_I2C_BLOCK_DATA) { ++ if (read_write == I2C_SMBUS_WRITE) { ++ /* set I2C_EN bit in configuration register */ ++ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc); ++ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, ++ hostc | SMBHSTCFG_I2C_EN); ++ } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) { ++ dev_err(&priv->pci_dev->dev, ++ "I2C block read is unsupported!\n"); ++ return -EOPNOTSUPP; ++ } ++ } ++ ++ if (read_write == I2C_SMBUS_WRITE ++ || command == I2C_SMBUS_I2C_BLOCK_DATA) { ++ if (data->block[0] < 1) ++ data->block[0] = 1; ++ if (data->block[0] > I2C_SMBUS_BLOCK_MAX) ++ data->block[0] = I2C_SMBUS_BLOCK_MAX; ++ } else { ++ data->block[0] = 32; /* max for SMBus block reads */ ++ } ++ ++ /* Experience has shown that the block buffer can only be used for ++ SMBus (not I2C) block transactions, even though the datasheet ++ doesn't mention this limitation. */ ++ if ((priv->features & FEATURE_BLOCK_BUFFER) ++ && command != I2C_SMBUS_I2C_BLOCK_DATA ++ && i801_set_block_buffer_mode(priv) == 0) ++ result = i801_block_transaction_by_block(priv, data, ++ read_write, ++ command, hwpec); ++ else ++ result = i801_block_transaction_byte_by_byte(priv, data, ++ read_write, ++ command, hwpec); ++ ++ if (command == I2C_SMBUS_I2C_BLOCK_DATA ++ && read_write == I2C_SMBUS_WRITE) { ++ /* restore saved configuration register value */ ++ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc); ++ } ++ return result; ++} ++ ++/* Return negative errno on error. */ ++static s32 i801_access(struct i2c_adapter *adap, u16 addr, ++ unsigned short flags, char read_write, u8 command, ++ int size, union i2c_smbus_data *data) ++{ ++ int hwpec; ++ int block = 0; ++ int ret = 0, xact = 0; ++ struct i801_priv *priv = i2c_get_adapdata(adap); ++ ++ mutex_lock(&priv->acpi_lock); ++ if (priv->acpi_reserved) { ++ mutex_unlock(&priv->acpi_lock); ++ return -EBUSY; ++ } ++ ++ pm_runtime_get_sync(&priv->pci_dev->dev); ++ ++ hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) ++ && size != I2C_SMBUS_QUICK ++ && size != I2C_SMBUS_I2C_BLOCK_DATA; ++ ++ switch (size) { ++ case I2C_SMBUS_QUICK: ++ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), ++ SMBHSTADD(priv)); ++ xact = I801_QUICK; ++ break; ++ case I2C_SMBUS_BYTE: ++ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), ++ SMBHSTADD(priv)); ++ if (read_write == I2C_SMBUS_WRITE) ++ outb_p(command, SMBHSTCMD(priv)); ++ xact = I801_BYTE; ++ break; ++ case I2C_SMBUS_BYTE_DATA: ++ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), ++ SMBHSTADD(priv)); ++ outb_p(command, SMBHSTCMD(priv)); ++ if (read_write == I2C_SMBUS_WRITE) ++ outb_p(data->byte, SMBHSTDAT0(priv)); ++ xact = I801_BYTE_DATA; ++ break; ++ case I2C_SMBUS_WORD_DATA: ++ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), ++ SMBHSTADD(priv)); ++ outb_p(command, SMBHSTCMD(priv)); ++ if (read_write == I2C_SMBUS_WRITE) { ++ outb_p(data->word & 0xff, SMBHSTDAT0(priv)); ++ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv)); ++ } ++ xact = I801_WORD_DATA; ++ break; ++ case I2C_SMBUS_BLOCK_DATA: ++ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), ++ SMBHSTADD(priv)); ++ outb_p(command, SMBHSTCMD(priv)); ++ block = 1; ++ break; ++ case I2C_SMBUS_I2C_BLOCK_DATA: ++ /* ++ * NB: page 240 of ICH5 datasheet shows that the R/#W ++ * bit should be cleared here, even when reading. ++ * However if SPD Write Disable is set (Lynx Point and later), ++ * the read will fail if we don't set the R/#W bit. ++ */ ++ outb_p(((addr & 0x7f) << 1) | ++ ((priv->original_hstcfg & SMBHSTCFG_SPD_WD) ? ++ (read_write & 0x01) : 0), ++ SMBHSTADD(priv)); ++ if (read_write == I2C_SMBUS_READ) { ++ /* NB: page 240 of ICH5 datasheet also shows ++ * that DATA1 is the cmd field when reading */ ++ outb_p(command, SMBHSTDAT1(priv)); ++ } else ++ outb_p(command, SMBHSTCMD(priv)); ++ block = 1; ++ break; ++ case I2C_SMBUS_BLOCK_PROC_CALL: ++ /* ++ * Bit 0 of the slave address register always indicate a write ++ * command. ++ */ ++ outb_p((addr & 0x7f) << 1, SMBHSTADD(priv)); ++ outb_p(command, SMBHSTCMD(priv)); ++ block = 1; ++ break; ++ default: ++ dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n", ++ size); ++ ret = -EOPNOTSUPP; ++ goto out; ++ } ++ ++ if (hwpec) /* enable/disable hardware PEC */ ++ outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv)); ++ else ++ outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC), ++ SMBAUXCTL(priv)); ++ ++ if (block) ++ ret = i801_block_transaction(priv, data, read_write, size, ++ hwpec); ++ else ++ ret = i801_transaction(priv, xact); ++ ++ /* Some BIOSes don't like it when PEC is enabled at reboot or resume ++ time, so we forcibly disable it after every transaction. Turn off ++ E32B for the same reason. */ ++ if (hwpec || block) ++ outb_p(inb_p(SMBAUXCTL(priv)) & ++ ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); ++ ++ if (block) ++ goto out; ++ if (ret) ++ goto out; ++ if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) ++ goto out; ++ ++ switch (xact & 0x7f) { ++ case I801_BYTE: /* Result put in SMBHSTDAT0 */ ++ case I801_BYTE_DATA: ++ data->byte = inb_p(SMBHSTDAT0(priv)); ++ break; ++ case I801_WORD_DATA: ++ data->word = inb_p(SMBHSTDAT0(priv)) + ++ (inb_p(SMBHSTDAT1(priv)) << 8); ++ break; ++ } ++ ++out: ++ pm_runtime_mark_last_busy(&priv->pci_dev->dev); ++ pm_runtime_put_autosuspend(&priv->pci_dev->dev); ++ mutex_unlock(&priv->acpi_lock); ++ return ret; ++} ++ ++static u32 i801_func(struct i2c_adapter *adapter) ++{ ++ struct i801_priv *priv = i2c_get_adapdata(adapter); ++ ++ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | ++ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | ++ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | ++ ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | ++ ((priv->features & FEATURE_BLOCK_PROC) ? ++ I2C_FUNC_SMBUS_BLOCK_PROC_CALL : 0) | ++ ((priv->features & FEATURE_I2C_BLOCK_READ) ? ++ I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) | ++ ((priv->features & FEATURE_HOST_NOTIFY) ? ++ I2C_FUNC_SMBUS_HOST_NOTIFY : 0); ++} ++ ++static void i801_enable_host_notify(struct i2c_adapter *adapter) ++{ ++ struct i801_priv *priv = i2c_get_adapdata(adapter); ++ ++ if (!(priv->features & FEATURE_HOST_NOTIFY)) ++ return; ++ ++ if (!(SMBSLVCMD_HST_NTFY_INTREN & priv->original_slvcmd)) ++ outb_p(SMBSLVCMD_HST_NTFY_INTREN | priv->original_slvcmd, ++ SMBSLVCMD(priv)); ++ ++ /* clear Host Notify bit to allow a new notification */ ++ outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); ++} ++ ++static void i801_disable_host_notify(struct i801_priv *priv) ++{ ++ if (!(priv->features & FEATURE_HOST_NOTIFY)) ++ return; ++ ++ outb_p(priv->original_slvcmd, SMBSLVCMD(priv)); ++} ++ ++static const struct i2c_algorithm smbus_algorithm = { ++ .smbus_xfer = i801_access, ++ .functionality = i801_func, ++}; ++ ++static const struct pci_device_id i801_ids[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_3) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_3) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_3) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_4) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_16) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EP80579_1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EBG_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS) }, ++ { 0, } ++}; ++ ++MODULE_DEVICE_TABLE(pci, i801_ids); ++ ++#if defined CONFIG_X86 && defined CONFIG_DMI ++static unsigned char apanel_addr; ++ ++/* Scan the system ROM for the signature "FJKEYINF" */ ++static __init const void __iomem *bios_signature(const void __iomem *bios) ++{ ++ ssize_t offset; ++ const unsigned char signature[] = "FJKEYINF"; ++ ++ for (offset = 0; offset < 0x10000; offset += 0x10) { ++ if (check_signature(bios + offset, signature, ++ sizeof(signature)-1)) ++ return bios + offset; ++ } ++ return NULL; ++} ++ ++static void __init input_apanel_init(void) ++{ ++ void __iomem *bios; ++ const void __iomem *p; ++ ++ bios = ioremap(0xF0000, 0x10000); /* Can't fail */ ++ p = bios_signature(bios); ++ if (p) { ++ /* just use the first address */ ++ apanel_addr = readb(p + 8 + 3) >> 1; ++ } ++ iounmap(bios); ++} ++ ++struct dmi_onboard_device_info { ++ const char *name; ++ u8 type; ++ unsigned short i2c_addr; ++ const char *i2c_type; ++}; ++ ++static const struct dmi_onboard_device_info dmi_devices[] = { ++ { "Syleus", DMI_DEV_TYPE_OTHER, 0x73, "fscsyl" }, ++ { "Hermes", DMI_DEV_TYPE_OTHER, 0x73, "fscher" }, ++ { "Hades", DMI_DEV_TYPE_OTHER, 0x73, "fschds" }, ++}; ++ ++static void dmi_check_onboard_device(u8 type, const char *name, ++ struct i2c_adapter *adap) ++{ ++ int i; ++ struct i2c_board_info info; ++ ++ for (i = 0; i < ARRAY_SIZE(dmi_devices); i++) { ++ /* & ~0x80, ignore enabled/disabled bit */ ++ if ((type & ~0x80) != dmi_devices[i].type) ++ continue; ++ if (strcasecmp(name, dmi_devices[i].name)) ++ continue; ++ ++ mem_clear(&info, sizeof(struct i2c_board_info)); ++ info.addr = dmi_devices[i].i2c_addr; ++ strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE); ++ i2c_new_client_device(adap, &info); ++ break; ++ } ++} ++ ++/* We use our own function to check for onboard devices instead of ++ dmi_find_device() as some buggy BIOS's have the devices we are interested ++ in marked as disabled */ ++static void dmi_check_onboard_devices(const struct dmi_header *dm, void *adap) ++{ ++ int i, count; ++ ++ if (dm->type != 10) ++ return; ++ ++ count = (dm->length - sizeof(struct dmi_header)) / 2; ++ for (i = 0; i < count; i++) { ++ const u8 *d = (char *)(dm + 1) + (i * 2); ++ const char *name = ((char *) dm) + dm->length; ++ u8 type = d[0]; ++ u8 s = d[1]; ++ ++ if (!s) ++ continue; ++ s--; ++ while (s > 0 && name[0]) { ++ name += strlen(name) + 1; ++ s--; ++ } ++ if (name[0] == 0) /* Bogus string reference */ ++ continue; ++ ++ dmi_check_onboard_device(type, name, adap); ++ } ++} ++ ++/* NOTE: Keep this list in sync with drivers/platform/x86/dell-smo8800.c */ ++static const char *const acpi_smo8800_ids[] = { ++ "SMO8800", ++ "SMO8801", ++ "SMO8810", ++ "SMO8811", ++ "SMO8820", ++ "SMO8821", ++ "SMO8830", ++ "SMO8831", ++}; ++ ++static acpi_status check_acpi_smo88xx_device(acpi_handle obj_handle, ++ u32 nesting_level, ++ void *context, ++ void **return_value) ++{ ++ struct acpi_device_info *info; ++ acpi_status status; ++ char *hid; ++ int i; ++ ++ status = acpi_get_object_info(obj_handle, &info); ++ if (ACPI_FAILURE(status)) ++ return AE_OK; ++ ++ if (!(info->valid & ACPI_VALID_HID)) ++ goto smo88xx_not_found; ++ ++ hid = info->hardware_id.string; ++ if (!hid) ++ goto smo88xx_not_found; ++ ++ i = match_string(acpi_smo8800_ids, ARRAY_SIZE(acpi_smo8800_ids), hid); ++ if (i < 0) ++ goto smo88xx_not_found; ++ ++ kfree(info); ++ ++ *((bool *)return_value) = true; ++ return AE_CTRL_TERMINATE; ++ ++smo88xx_not_found: ++ kfree(info); ++ return AE_OK; ++} ++ ++static bool is_dell_system_with_lis3lv02d(void) ++{ ++ bool found; ++ const char *vendor; ++ ++ vendor = dmi_get_system_info(DMI_SYS_VENDOR); ++ if (!vendor || strcmp(vendor, "Dell Inc.")) ++ return false; ++ ++ /* ++ * Check that ACPI device SMO88xx is present and is functioning. ++ * Function acpi_get_devices() already filters all ACPI devices ++ * which are not present or are not functioning. ++ * ACPI device SMO88xx represents our ST microelectronics lis3lv02d ++ * accelerometer but unfortunately ACPI does not provide any other ++ * information (like I2C address). ++ */ ++ found = false; ++ acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL, ++ (void **)&found); ++ ++ return found; ++} ++ ++/* ++ * Accelerometer's I2C address is not specified in DMI nor ACPI, ++ * so it is needed to define mapping table based on DMI product names. ++ */ ++static const struct { ++ const char *dmi_product_name; ++ unsigned short i2c_addr; ++} dell_lis3lv02d_devices[] = { ++ /* ++ * Dell platform team told us that these Latitude devices have ++ * ST microelectronics accelerometer at I2C address 0x29. ++ */ ++ { "Latitude E5250", 0x29 }, ++ { "Latitude E5450", 0x29 }, ++ { "Latitude E5550", 0x29 }, ++ { "Latitude E6440", 0x29 }, ++ { "Latitude E6440 ATG", 0x29 }, ++ { "Latitude E6540", 0x29 }, ++ /* ++ * Additional individual entries were added after verification. ++ */ ++ { "Latitude 5480", 0x29 }, ++ { "Vostro V131", 0x1d }, ++}; ++ ++static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv) ++{ ++ struct i2c_board_info info; ++ const char *dmi_product_name; ++ int i; ++ ++ dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME); ++ for (i = 0; i < ARRAY_SIZE(dell_lis3lv02d_devices); ++i) { ++ if (strcmp(dmi_product_name, ++ dell_lis3lv02d_devices[i].dmi_product_name) == 0) ++ break; ++ } ++ ++ if (i == ARRAY_SIZE(dell_lis3lv02d_devices)) { ++ dev_warn(&priv->pci_dev->dev, ++ "Accelerometer lis3lv02d is present on SMBus but its" ++ " address is unknown, skipping registration\n"); ++ return; ++ } ++ ++ mem_clear(&info, sizeof(struct i2c_board_info)); ++ info.addr = dell_lis3lv02d_devices[i].i2c_addr; ++ strlcpy(info.type, "lis3lv02d", I2C_NAME_SIZE); ++ i2c_new_client_device(&priv->adapter, &info); ++} ++ ++/* Register optional slaves */ ++static void i801_probe_optional_slaves(struct i801_priv *priv) ++{ ++ /* Only register slaves on main SMBus channel */ ++ if (priv->features & FEATURE_IDF) ++ return; ++ ++ if (apanel_addr) { ++ struct i2c_board_info info; ++ ++ mem_clear(&info, sizeof(struct i2c_board_info)); ++ info.addr = apanel_addr; ++ strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE); ++ i2c_new_client_device(&priv->adapter, &info); ++ } ++ ++ if (dmi_name_in_vendors("FUJITSU")) ++ dmi_walk(dmi_check_onboard_devices, &priv->adapter); ++ ++ if (is_dell_system_with_lis3lv02d()) ++ register_dell_lis3lv02d_i2c_device(priv); ++ ++ /* Instantiate SPD EEPROMs unless the SMBus is multiplexed */ ++#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) ++ if (!priv->mux_drvdata) ++#endif ++ i2c_register_spd(&priv->adapter); ++} ++#else ++static void __init input_apanel_init(void) {} ++static void i801_probe_optional_slaves(struct i801_priv *priv) {} ++#endif /* CONFIG_X86 && CONFIG_DMI */ ++ ++#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI ++static struct i801_mux_config i801_mux_config_asus_z8_d12 = { ++ .gpio_chip = "gpio_ich", ++ .values = { 0x02, 0x03 }, ++ .n_values = 2, ++ .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD }, ++ .gpios = { 52, 53 }, ++ .n_gpios = 2, ++}; ++ ++static struct i801_mux_config i801_mux_config_asus_z8_d18 = { ++ .gpio_chip = "gpio_ich", ++ .values = { 0x02, 0x03, 0x01 }, ++ .n_values = 3, ++ .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD, I2C_CLASS_SPD }, ++ .gpios = { 52, 53 }, ++ .n_gpios = 2, ++}; ++ ++static const struct dmi_system_id mux_dmi_table[] = { ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), ++ DMI_MATCH(DMI_BOARD_NAME, "Z8NA-D6(C)"), ++ }, ++ .driver_data = &i801_mux_config_asus_z8_d12, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), ++ DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)E-D12(X)"), ++ }, ++ .driver_data = &i801_mux_config_asus_z8_d12, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), ++ DMI_MATCH(DMI_BOARD_NAME, "Z8NH-D12"), ++ }, ++ .driver_data = &i801_mux_config_asus_z8_d12, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), ++ DMI_MATCH(DMI_BOARD_NAME, "Z8PH-D12/IFB"), ++ }, ++ .driver_data = &i801_mux_config_asus_z8_d12, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), ++ DMI_MATCH(DMI_BOARD_NAME, "Z8NR-D12"), ++ }, ++ .driver_data = &i801_mux_config_asus_z8_d12, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), ++ DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)H-D12"), ++ }, ++ .driver_data = &i801_mux_config_asus_z8_d12, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), ++ DMI_MATCH(DMI_BOARD_NAME, "Z8PG-D18"), ++ }, ++ .driver_data = &i801_mux_config_asus_z8_d18, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), ++ DMI_MATCH(DMI_BOARD_NAME, "Z8PE-D18"), ++ }, ++ .driver_data = &i801_mux_config_asus_z8_d18, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), ++ DMI_MATCH(DMI_BOARD_NAME, "Z8PS-D12"), ++ }, ++ .driver_data = &i801_mux_config_asus_z8_d12, ++ }, ++ { } ++}; ++ ++/* Setup multiplexing if needed */ ++static int i801_add_mux(struct i801_priv *priv) ++{ ++ struct device *dev = &priv->adapter.dev; ++ const struct i801_mux_config *mux_config; ++ struct i2c_mux_gpio_platform_data gpio_data; ++ struct gpiod_lookup_table *lookup; ++ int err, i; ++ ++ if (!priv->mux_drvdata) ++ return 0; ++ mux_config = priv->mux_drvdata; ++ ++ /* Prepare the platform data */ ++ mem_clear(&gpio_data, sizeof(struct i2c_mux_gpio_platform_data)); ++ gpio_data.parent = priv->adapter.nr; ++ gpio_data.values = mux_config->values; ++ gpio_data.n_values = mux_config->n_values; ++ gpio_data.classes = mux_config->classes; ++ gpio_data.idle = I2C_MUX_GPIO_NO_IDLE; ++ ++ /* Register GPIO descriptor lookup table */ ++ lookup = devm_kzalloc(dev, ++ struct_size(lookup, table, mux_config->n_gpios + 1), ++ GFP_KERNEL); ++ if (!lookup) ++ return -ENOMEM; ++ lookup->dev_id = "i2c-mux-gpio"; ++ for (i = 0; i < mux_config->n_gpios; i++) { ++ lookup->table[i] = (struct gpiod_lookup) ++ GPIO_LOOKUP(mux_config->gpio_chip, ++ mux_config->gpios[i], "mux", 0); ++ } ++ gpiod_add_lookup_table(lookup); ++ priv->lookup = lookup; ++ ++ /* ++ * Register the mux device, we use PLATFORM_DEVID_NONE here ++ * because since we are referring to the GPIO chip by name we are ++ * anyways in deep trouble if there is more than one of these ++ * devices, and there should likely only be one platform controller ++ * hub. ++ */ ++ priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio", ++ PLATFORM_DEVID_NONE, &gpio_data, ++ sizeof(struct i2c_mux_gpio_platform_data)); ++ if (IS_ERR(priv->mux_pdev)) { ++ err = PTR_ERR(priv->mux_pdev); ++ gpiod_remove_lookup_table(lookup); ++ priv->mux_pdev = NULL; ++ dev_err(dev, "Failed to register i2c-mux-gpio device\n"); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void i801_del_mux(struct i801_priv *priv) ++{ ++ if (priv->mux_pdev) ++ platform_device_unregister(priv->mux_pdev); ++ if (priv->lookup) ++ gpiod_remove_lookup_table(priv->lookup); ++} ++ ++static unsigned int i801_get_adapter_class(struct i801_priv *priv) ++{ ++ const struct dmi_system_id *id; ++ const struct i801_mux_config *mux_config; ++ unsigned int class = I2C_CLASS_HWMON | I2C_CLASS_SPD; ++ int i; ++ ++ id = dmi_first_match(mux_dmi_table); ++ if (id) { ++ /* Remove branch classes from trunk */ ++ mux_config = id->driver_data; ++ for (i = 0; i < mux_config->n_values; i++) ++ class &= ~mux_config->classes[i]; ++ ++ /* Remember for later */ ++ priv->mux_drvdata = mux_config; ++ } ++ ++ return class; ++} ++#else ++static inline int i801_add_mux(struct i801_priv *priv) { return 0; } ++static inline void i801_del_mux(struct i801_priv *priv) { } ++ ++static inline unsigned int i801_get_adapter_class(struct i801_priv *priv) ++{ ++ return I2C_CLASS_HWMON | I2C_CLASS_SPD; ++} ++#endif ++ ++static const struct itco_wdt_platform_data spt_tco_platform_data = { ++ .name = "Intel PCH", ++ .version = 4, ++}; ++ ++static DEFINE_SPINLOCK(p2sb_spinlock); ++ ++static struct platform_device * ++i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev, ++ struct resource *tco_res) ++{ ++ struct resource *res; ++ unsigned int devfn; ++ u64 base64_addr; ++ u32 base_addr; ++ u8 hidden; ++ ++ /* ++ * We must access the NO_REBOOT bit over the Primary to Sideband ++ * bridge (P2SB). The BIOS prevents the P2SB device from being ++ * enumerated by the PCI subsystem, so we need to unhide/hide it ++ * to lookup the P2SB BAR. ++ */ ++ spin_lock(&p2sb_spinlock); ++ ++ devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 1); ++ ++ /* Unhide the P2SB device, if it is hidden */ ++ pci_bus_read_config_byte(pci_dev->bus, devfn, 0xe1, &hidden); ++ if (hidden) ++ pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, 0x0); ++ ++ pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR, &base_addr); ++ base64_addr = base_addr & 0xfffffff0; ++ ++ pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR + 0x4, &base_addr); ++ base64_addr |= (u64)base_addr << 32; ++ ++ /* Hide the P2SB device, if it was hidden before */ ++ if (hidden) ++ pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden); ++ spin_unlock(&p2sb_spinlock); ++ ++ res = &tco_res[1]; ++ if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS) ++ res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL_DNV; ++ else ++ res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL; ++ ++ res->end = res->start + 3; ++ res->flags = IORESOURCE_MEM; ++ ++ return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1, ++ tco_res, 2, &spt_tco_platform_data, ++ sizeof(spt_tco_platform_data)); ++} ++ ++static const struct itco_wdt_platform_data cnl_tco_platform_data = { ++ .name = "Intel PCH", ++ .version = 6, ++}; ++ ++static struct platform_device * ++i801_add_tco_cnl(struct i801_priv *priv, struct pci_dev *pci_dev, ++ struct resource *tco_res) ++{ ++ return platform_device_register_resndata(&pci_dev->dev, ++ "iTCO_wdt", -1, tco_res, 1, &cnl_tco_platform_data, ++ sizeof(cnl_tco_platform_data)); ++} ++ ++static void i801_add_tco(struct i801_priv *priv) ++{ ++ struct pci_dev *pci_dev = priv->pci_dev; ++ struct resource tco_res[2], *res; ++ u32 tco_base, tco_ctl; ++ ++ /* If we have ACPI based watchdog use that instead */ ++ if (acpi_has_watchdog()) ++ return; ++ ++ if (!(priv->features & (FEATURE_TCO_SPT | FEATURE_TCO_CNL))) ++ return; ++ ++ pci_read_config_dword(pci_dev, TCOBASE, &tco_base); ++ pci_read_config_dword(pci_dev, TCOCTL, &tco_ctl); ++ if (!(tco_ctl & TCOCTL_EN)) ++ return; ++ ++ mem_clear(tco_res, sizeof(tco_res)); ++ /* ++ * Always populate the main iTCO IO resource here. The second entry ++ * for NO_REBOOT MMIO is filled by the SPT specific function. ++ */ ++ res = &tco_res[0]; ++ res->start = tco_base & ~1; ++ res->end = res->start + 32 - 1; ++ res->flags = IORESOURCE_IO; ++ ++ if (priv->features & FEATURE_TCO_CNL) ++ priv->tco_pdev = i801_add_tco_cnl(priv, pci_dev, tco_res); ++ else ++ priv->tco_pdev = i801_add_tco_spt(priv, pci_dev, tco_res); ++ ++ if (IS_ERR(priv->tco_pdev)) ++ dev_warn(&pci_dev->dev, "failed to create iTCO device\n"); ++} ++ ++#ifdef CONFIG_ACPI ++static bool i801_acpi_is_smbus_ioport(const struct i801_priv *priv, ++ acpi_physical_address address) ++{ ++ return address >= priv->smba && ++ address <= pci_resource_end(priv->pci_dev, SMBBAR); ++} ++ ++static acpi_status ++i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, ++ u64 *value, void *handler_context, void *region_context) ++{ ++ struct i801_priv *priv = handler_context; ++ struct pci_dev *pdev = priv->pci_dev; ++ acpi_status status; ++ ++ /* ++ * Once BIOS AML code touches the OpRegion we warn and inhibit any ++ * further access from the driver itself. This device is now owned ++ * by the system firmware. ++ */ ++ mutex_lock(&priv->acpi_lock); ++ ++ if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) { ++ priv->acpi_reserved = true; ++ ++ dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n"); ++ dev_warn(&pdev->dev, "Driver SMBus register access inhibited\n"); ++ ++ /* ++ * BIOS is accessing the host controller so prevent it from ++ * suspending automatically from now on. ++ */ ++ pm_runtime_get_sync(&pdev->dev); ++ } ++ ++ if ((function & ACPI_IO_MASK) == ACPI_READ) ++ status = acpi_os_read_port(address, (u32 *)value, bits); ++ else ++ status = acpi_os_write_port(address, (u32)*value, bits); ++ ++ mutex_unlock(&priv->acpi_lock); ++ ++ return status; ++} ++ ++static int i801_acpi_probe(struct i801_priv *priv) ++{ ++ struct acpi_device *adev; ++ acpi_status status; ++ ++ adev = ACPI_COMPANION(&priv->pci_dev->dev); ++ if (adev) { ++ status = acpi_install_address_space_handler(adev->handle, ++ ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler, ++ NULL, priv); ++ if (ACPI_SUCCESS(status)) ++ return 0; ++ } ++ ++ return acpi_check_resource_conflict(&priv->pci_dev->resource[SMBBAR]); ++} ++ ++static void i801_acpi_remove(struct i801_priv *priv) ++{ ++ struct acpi_device *adev; ++ ++ adev = ACPI_COMPANION(&priv->pci_dev->dev); ++ if (!adev) ++ return; ++ ++ acpi_remove_address_space_handler(adev->handle, ++ ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler); ++ ++ mutex_lock(&priv->acpi_lock); ++ if (priv->acpi_reserved) ++ pm_runtime_put(&priv->pci_dev->dev); ++ mutex_unlock(&priv->acpi_lock); ++} ++#else ++static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; } ++static inline void i801_acpi_remove(struct i801_priv *priv) { } ++#endif ++ ++static unsigned char i801_setup_hstcfg(struct i801_priv *priv) ++{ ++ unsigned char hstcfg = priv->original_hstcfg; ++ ++ hstcfg &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */ ++ hstcfg |= SMBHSTCFG_HST_EN; ++ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hstcfg); ++ return hstcfg; ++} ++ ++static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) ++{ ++ unsigned char temp; ++ int err, i; ++ struct i801_priv *priv; ++ ++ priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ i2c_set_adapdata(&priv->adapter, priv); ++ priv->adapter.owner = THIS_MODULE; ++ priv->adapter.class = i801_get_adapter_class(priv); ++ priv->adapter.algo = &smbus_algorithm; ++ priv->adapter.dev.parent = &dev->dev; ++ ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev)); ++ priv->adapter.retries = 3; ++ mutex_init(&priv->acpi_lock); ++ ++ priv->pci_dev = dev; ++ switch (dev->device) { ++ case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS: ++ case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS: ++ case PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS: ++ case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS: ++ case PCI_DEVICE_ID_INTEL_DNV_SMBUS: ++ case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS: ++ case PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS: ++ priv->features |= FEATURE_BLOCK_PROC; ++ priv->features |= FEATURE_I2C_BLOCK_READ; ++ priv->features |= FEATURE_IRQ; ++ priv->features |= FEATURE_SMBUS_PEC; ++ priv->features |= FEATURE_BLOCK_BUFFER; ++ priv->features |= FEATURE_TCO_SPT; ++ priv->features |= FEATURE_HOST_NOTIFY; ++ break; ++ ++ case PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS: ++ case PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS: ++ case PCI_DEVICE_ID_INTEL_CDF_SMBUS: ++ case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS: ++ case PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS: ++ case PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS: ++ case PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS: ++ case PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS: ++ case PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS: ++ case PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS: ++ case PCI_DEVICE_ID_INTEL_EBG_SMBUS: ++ case PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS: ++ priv->features |= FEATURE_BLOCK_PROC; ++ priv->features |= FEATURE_I2C_BLOCK_READ; ++ priv->features |= FEATURE_IRQ; ++ priv->features |= FEATURE_SMBUS_PEC; ++ priv->features |= FEATURE_BLOCK_BUFFER; ++ priv->features |= FEATURE_TCO_CNL; ++ priv->features |= FEATURE_HOST_NOTIFY; ++ break; ++ ++ case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0: ++ case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1: ++ case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2: ++ case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0: ++ case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1: ++ case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2: ++ priv->features |= FEATURE_IDF; ++ fallthrough; ++ default: ++ priv->features |= FEATURE_BLOCK_PROC; ++ priv->features |= FEATURE_I2C_BLOCK_READ; ++ priv->features |= FEATURE_IRQ; ++ fallthrough; ++ case PCI_DEVICE_ID_INTEL_82801DB_3: ++ priv->features |= FEATURE_SMBUS_PEC; ++ priv->features |= FEATURE_BLOCK_BUFFER; ++ fallthrough; ++ case PCI_DEVICE_ID_INTEL_82801CA_3: ++ priv->features |= FEATURE_HOST_NOTIFY; ++ fallthrough; ++ case PCI_DEVICE_ID_INTEL_82801BA_2: ++ case PCI_DEVICE_ID_INTEL_82801AB_3: ++ case PCI_DEVICE_ID_INTEL_82801AA_3: ++ break; ++ } ++ ++ /* Disable features on user request */ ++ for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) { ++ if (priv->features & disable_features & (1 << i)) ++ dev_notice(&dev->dev, "%s disabled by user\n", ++ i801_feature_names[i]); ++ } ++ priv->features &= ~disable_features; ++ ++ err = pcim_enable_device(dev); ++ if (err) { ++ dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n", ++ err); ++ return err; ++ } ++ pcim_pin_device(dev); ++ ++ /* Determine the address of the SMBus area */ ++ priv->smba = pci_resource_start(dev, SMBBAR); ++ if (!priv->smba) { ++ dev_err(&dev->dev, ++ "SMBus base address uninitialized, upgrade BIOS\n"); ++ return -ENODEV; ++ } ++ ++ if (i801_acpi_probe(priv)) ++ return -ENODEV; ++ ++ err = pcim_iomap_regions(dev, 1 << SMBBAR, ++ dev_driver_string(&dev->dev)); ++ if (err) { ++ dev_err(&dev->dev, ++ "Failed to request SMBus region 0x%lx-0x%Lx\n", ++ priv->smba, ++ (unsigned long long)pci_resource_end(dev, SMBBAR)); ++ i801_acpi_remove(priv); ++ return err; ++ } ++ ++ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &priv->original_hstcfg); ++ temp = i801_setup_hstcfg(priv); ++ if (!(priv->original_hstcfg & SMBHSTCFG_HST_EN)) ++ dev_info(&dev->dev, "Enabling SMBus device\n"); ++ ++ if (temp & SMBHSTCFG_SMB_SMI_EN) { ++ dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n"); ++ /* Disable SMBus interrupt feature if SMBus using SMI# */ ++ priv->features &= ~FEATURE_IRQ; ++ } ++ if (temp & SMBHSTCFG_SPD_WD) ++ dev_info(&dev->dev, "SPD Write Disable is set\n"); ++ ++ /* Clear special mode bits */ ++ if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER)) ++ outb_p(inb_p(SMBAUXCTL(priv)) & ++ ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); ++ ++ /* Remember original Host Notify setting */ ++ if (priv->features & FEATURE_HOST_NOTIFY) ++ priv->original_slvcmd = inb_p(SMBSLVCMD(priv)); ++ ++ /* Default timeout in interrupt mode: 200 ms */ ++ priv->adapter.timeout = HZ / 5; ++ ++ if (dev->irq == IRQ_NOTCONNECTED) ++ priv->features &= ~FEATURE_IRQ; ++ ++ if (priv->features & FEATURE_IRQ) { ++ u16 pcictl, pcists; ++ ++ /* Complain if an interrupt is already pending */ ++ pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists); ++ if (pcists & SMBPCISTS_INTS) ++ dev_warn(&dev->dev, "An interrupt is pending!\n"); ++ ++ /* Check if interrupts have been disabled */ ++ pci_read_config_word(priv->pci_dev, SMBPCICTL, &pcictl); ++ if (pcictl & SMBPCICTL_INTDIS) { ++ dev_info(&dev->dev, "Interrupts are disabled\n"); ++ priv->features &= ~FEATURE_IRQ; ++ } ++ } ++ ++ if (priv->features & FEATURE_IRQ) { ++ init_waitqueue_head(&priv->waitq); ++ ++ err = devm_request_irq(&dev->dev, dev->irq, i801_isr, ++ IRQF_SHARED, ++ dev_driver_string(&dev->dev), priv); ++ if (err) { ++ dev_err(&dev->dev, "Failed to allocate irq %d: %d\n", ++ dev->irq, err); ++ priv->features &= ~FEATURE_IRQ; ++ } ++ } ++ dev_info(&dev->dev, "SMBus using %s\n", ++ priv->features & FEATURE_IRQ ? "PCI interrupt" : "polling"); ++ ++ i801_add_tco(priv); ++ ++ snprintf(priv->adapter.name, sizeof(priv->adapter.name), ++ "SMBus I801 adapter at %04lx", priv->smba); ++ err = i2c_add_adapter(&priv->adapter); ++ if (err) { ++ i801_acpi_remove(priv); ++ return err; ++ } ++ ++ i801_enable_host_notify(&priv->adapter); ++ ++ i801_probe_optional_slaves(priv); ++ /* We ignore errors - multiplexing is optional */ ++ i801_add_mux(priv); ++ ++ pci_set_drvdata(dev, priv); ++ ++ dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_NO_DIRECT_COMPLETE); ++ pm_runtime_set_autosuspend_delay(&dev->dev, 1000); ++ pm_runtime_use_autosuspend(&dev->dev); ++ pm_runtime_put_autosuspend(&dev->dev); ++ pm_runtime_allow(&dev->dev); ++ dev_info(&dev->dev, "wb-i2c-i801 probe ok.\n"); ++ ++ return 0; ++} ++ ++static void i801_remove(struct pci_dev *dev) ++{ ++ struct i801_priv *priv = pci_get_drvdata(dev); ++ ++ pm_runtime_forbid(&dev->dev); ++ pm_runtime_get_noresume(&dev->dev); ++ ++ i801_disable_host_notify(priv); ++ i801_del_mux(priv); ++ i2c_del_adapter(&priv->adapter); ++ i801_acpi_remove(priv); ++ pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); ++ ++ platform_device_unregister(priv->tco_pdev); ++ ++ /* ++ * do not call pci_disable_device(dev) since it can cause hard hangs on ++ * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010) ++ */ ++} ++ ++static void i801_shutdown(struct pci_dev *dev) ++{ ++ struct i801_priv *priv = pci_get_drvdata(dev); ++ ++ /* Restore config registers to avoid hard hang on some systems */ ++ i801_disable_host_notify(priv); ++ pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int i801_suspend(struct device *dev) ++{ ++ struct i801_priv *priv = dev_get_drvdata(dev); ++ ++ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, priv->original_hstcfg); ++ return 0; ++} ++ ++static int i801_resume(struct device *dev) ++{ ++ struct i801_priv *priv = dev_get_drvdata(dev); ++ ++ i801_setup_hstcfg(priv); ++ i801_enable_host_notify(&priv->adapter); ++ ++ return 0; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume); ++ ++static struct pci_driver i801_driver = { ++ .name = "wb_i801_smbus", ++ .id_table = i801_ids, ++ .probe = i801_probe, ++ .remove = i801_remove, ++ .shutdown = i801_shutdown, ++ .driver = { ++ .pm = &i801_pm_ops, ++ }, ++}; ++ ++static int __init i2c_i801_init(void) ++{ ++ if (dmi_name_in_vendors("FUJITSU")) ++ input_apanel_init(); ++ return pci_register_driver(&i801_driver); ++} ++ ++static void __exit i2c_i801_exit(void) ++{ ++ pci_unregister_driver(&i801_driver); ++} ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("I801 SMBus driver"); ++MODULE_LICENSE("GPL"); ++ ++module_init(i2c_i801_init); ++module_exit(i2c_i801_exit); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_ismt.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_ismt.c +new file mode 100644 +index 000000000..2015c8ca2 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_ismt.c +@@ -0,0 +1,1105 @@ ++/* ++ * This file is provided under a dual BSD/GPLv2 license. When using or ++ * redistributing this file, you may do so under either license. ++ * ++ * Copyright(c) 2012 Intel Corporation. All rights reserved. ++ * ++ * GPL LICENSE SUMMARY ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * 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. ++ * The full GNU General Public License is included in this distribution ++ * in the file called LICENSE.GPL. ++ * ++ * BSD LICENSE ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * * Neither the name of Intel Corporation nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ * Supports the SMBus Message Transport (SMT) in the Intel Atom Processor ++ * S12xx Product Family. ++ * ++ * Features supported by this driver: ++ * Hardware PEC yes ++ * Block buffer yes ++ * Block process call transaction no ++ * Slave mode no ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++ ++/* PCI Address Constants */ ++#define SMBBAR 0 ++ ++#define ISMT_DBCTRL 0x388 /* ISMT PIN Control Register */ ++#define ISMT_DBSTS 0X38C /* ISMT PIN Status Register */ ++ ++#define ISMT_DBSTS_CLK_STS (1<<9) /* bit9 SMBCLK_CUR_STS */ ++#define ISMT_DBSTS_SDA_STS (1<<8) /* bit8 SMBDATA_CUR_STS */ ++#define ISMT_DBCTRL_CLK_CTL (1<<1) /* bit1 SMBCLK_CTL */ ++#define ISMT_DBCTRL_ENABLE (1<<31) /* bit31 EN */ ++ ++/* PCI DIDs for the Intel SMBus Message Transport (SMT) Devices */ ++#define PCI_DEVICE_ID_INTEL_S1200_SMT0 0x0c59 ++#define PCI_DEVICE_ID_INTEL_S1200_SMT1 0x0c5a ++#define PCI_DEVICE_ID_INTEL_CDF_SMT 0x18ac ++#define PCI_DEVICE_ID_INTEL_DNV_SMT 0x19ac ++#define PCI_DEVICE_ID_INTEL_EBG_SMT 0x1bff ++#define PCI_DEVICE_ID_INTEL_AVOTON_SMT 0x1f15 ++ ++#define ISMT_DESC_ENTRIES 2 /* number of descriptor entries */ ++#define ISMT_MAX_RETRIES 3 /* number of SMBus retries to attempt */ ++ ++/* Hardware Descriptor Constants - Control Field */ ++#define ISMT_DESC_CWRL 0x01 /* Command/Write Length */ ++#define ISMT_DESC_BLK 0X04 /* Perform Block Transaction */ ++#define ISMT_DESC_FAIR 0x08 /* Set fairness flag upon successful arbit. */ ++#define ISMT_DESC_PEC 0x10 /* Packet Error Code */ ++#define ISMT_DESC_I2C 0x20 /* I2C Enable */ ++#define ISMT_DESC_INT 0x40 /* Interrupt */ ++#define ISMT_DESC_SOE 0x80 /* Stop On Error */ ++ ++/* Hardware Descriptor Constants - Status Field */ ++#define ISMT_DESC_SCS 0x01 /* Success */ ++#define ISMT_DESC_DLTO 0x04 /* Data Low Time Out */ ++#define ISMT_DESC_NAK 0x08 /* NAK Received */ ++#define ISMT_DESC_CRC 0x10 /* CRC Error */ ++#define ISMT_DESC_CLTO 0x20 /* Clock Low Time Out */ ++#define ISMT_DESC_COL 0x40 /* Collisions */ ++#define ISMT_DESC_LPR 0x80 /* Large Packet Received */ ++ ++/* Macros */ ++#define ISMT_DESC_ADDR_RW(addr, rw) (((addr) << 1) | (rw)) ++ ++/* iSMT General Register address offsets (SMBBAR + ) */ ++#define ISMT_GR_GCTRL 0x000 /* General Control */ ++#define ISMT_GR_SMTICL 0x008 /* SMT Interrupt Cause Location */ ++#define ISMT_GR_ERRINTMSK 0x010 /* Error Interrupt Mask */ ++#define ISMT_GR_ERRAERMSK 0x014 /* Error AER Mask */ ++#define ISMT_GR_ERRSTS 0x018 /* Error Status */ ++#define ISMT_GR_ERRINFO 0x01c /* Error Information */ ++ ++/* iSMT Master Registers */ ++#define ISMT_MSTR_MDBA 0x100 /* Master Descriptor Base Address */ ++#define ISMT_MSTR_MCTRL 0x108 /* Master Control */ ++#define ISMT_MSTR_MSTS 0x10c /* Master Status */ ++#define ISMT_MSTR_MDS 0x110 /* Master Descriptor Size */ ++#define ISMT_MSTR_RPOLICY 0x114 /* Retry Policy */ ++ ++/* iSMT Miscellaneous Registers */ ++#define ISMT_SPGT 0x300 /* SMBus PHY Global Timing */ ++ ++/* General Control Register (GCTRL) bit definitions */ ++#define ISMT_GCTRL_TRST 0x04 /* Target Reset */ ++#define ISMT_GCTRL_KILL 0x08 /* Kill */ ++#define ISMT_GCTRL_SRST 0x40 /* Soft Reset */ ++ ++/* Master Control Register (MCTRL) bit definitions */ ++#define ISMT_MCTRL_SS 0x01 /* Start/Stop */ ++#define ISMT_MCTRL_MEIE 0x10 /* Master Error Interrupt Enable */ ++#define ISMT_MCTRL_FMHP 0x00ff0000 /* Firmware Master Head Ptr (FMHP) */ ++ ++/* Master Status Register (MSTS) bit definitions */ ++#define ISMT_MSTS_HMTP 0xff0000 /* HW Master Tail Pointer (HMTP) */ ++#define ISMT_MSTS_MIS 0x20 /* Master Interrupt Status (MIS) */ ++#define ISMT_MSTS_MEIS 0x10 /* Master Error Int Status (MEIS) */ ++#define ISMT_MSTS_IP 0x01 /* In Progress */ ++ ++/* Master Descriptor Size (MDS) bit definitions */ ++#define ISMT_MDS_MASK 0xff /* Master Descriptor Size mask (MDS) */ ++ ++/* SMBus PHY Global Timing Register (SPGT) bit definitions */ ++#define ISMT_SPGT_SPD_MASK 0xc0000000 /* SMBus Speed mask */ ++#define ISMT_SPGT_SPD_80K 0x00 /* 80 kHz */ ++#define ISMT_SPGT_SPD_100K (0x1 << 30) /* 100 kHz */ ++#define ISMT_SPGT_SPD_400K (0x2 << 30) /* 400 kHz */ ++#define ISMT_SPGT_SPD_1M (0x3 << 30) /* 1 MHz */ ++ ++/* MSI Control Register (MSICTL) bit definitions */ ++#define ISMT_MSICTL_MSIE 0x01 /* MSI Enable */ ++ ++/* iSMT Hardware Descriptor */ ++struct ismt_desc { ++ u8 tgtaddr_rw; /* target address & r/w bit */ ++ u8 wr_len_cmd; /* write length in bytes or a command */ ++ u8 rd_len; /* read length */ ++ u8 control; /* control bits */ ++ u8 status; /* status bits */ ++ u8 retry; /* collision retry and retry count */ ++ u8 rxbytes; /* received bytes */ ++ u8 txbytes; /* transmitted bytes */ ++ u32 dptr_low; /* lower 32 bit of the data pointer */ ++ u32 dptr_high; /* upper 32 bit of the data pointer */ ++} __packed; ++ ++struct ismt_priv { ++ struct i2c_adapter adapter; ++ void __iomem *smba; /* PCI BAR */ ++ struct pci_dev *pci_dev; ++ struct ismt_desc *hw; /* descriptor virt base addr */ ++ dma_addr_t io_rng_dma; /* descriptor HW base addr */ ++ u8 head; /* ring buffer head pointer */ ++ struct completion cmp; /* interrupt completion */ ++ u8 buffer[I2C_SMBUS_BLOCK_MAX + 16]; /* temp R/W data buffer */ ++}; ++ ++static const struct pci_device_id ismt_ids[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMT) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMT) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EBG_SMT) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) }, ++ { 0, } ++}; ++ ++MODULE_DEVICE_TABLE(pci, ismt_ids); ++ ++/* Bus speed control bits for slow debuggers - refer to the docs for usage */ ++static unsigned int bus_speed = 100; ++static unsigned int delay = 1000; ++module_param(bus_speed, uint, S_IRUGO); ++MODULE_PARM_DESC(bus_speed, "Bus Speed in kHz (100 by default)"); ++module_param(delay, uint, S_IRUGO); ++MODULE_PARM_DESC(delay, "Delay in microsecs before access (1000 by default)"); ++ ++static unsigned int dma_reset_timeout = 1000; ++module_param(dma_reset_timeout, uint, S_IRUGO); ++ ++static void ismt_hw_init(struct ismt_priv *priv); ++ ++/** ++ * __ismt_desc_dump() - dump the contents of a specific descriptor ++ * @dev: the iSMT device ++ * @desc: the iSMT hardware descriptor ++ */ ++static void __ismt_desc_dump(struct device *dev, const struct ismt_desc *desc) ++{ ++ ++ dev_dbg(dev, "Descriptor struct: %p\n", desc); ++ dev_dbg(dev, "\ttgtaddr_rw=0x%02X\n", desc->tgtaddr_rw); ++ dev_dbg(dev, "\twr_len_cmd=0x%02X\n", desc->wr_len_cmd); ++ dev_dbg(dev, "\trd_len= 0x%02X\n", desc->rd_len); ++ dev_dbg(dev, "\tcontrol= 0x%02X\n", desc->control); ++ dev_dbg(dev, "\tstatus= 0x%02X\n", desc->status); ++ dev_dbg(dev, "\tretry= 0x%02X\n", desc->retry); ++ dev_dbg(dev, "\trxbytes= 0x%02X\n", desc->rxbytes); ++ dev_dbg(dev, "\ttxbytes= 0x%02X\n", desc->txbytes); ++ dev_dbg(dev, "\tdptr_low= 0x%08X\n", desc->dptr_low); ++ dev_dbg(dev, "\tdptr_high= 0x%08X\n", desc->dptr_high); ++} ++/** ++ * ismt_desc_dump() - dump the contents of a descriptor for debug purposes ++ * @priv: iSMT private data ++ */ ++static void ismt_desc_dump(struct ismt_priv *priv) ++{ ++ struct device *dev = &priv->pci_dev->dev; ++ struct ismt_desc *desc = &priv->hw[priv->head]; ++ ++ dev_dbg(dev, "Dump of the descriptor struct: 0x%X\n", priv->head); ++ __ismt_desc_dump(dev, desc); ++} ++ ++static void ismt_reset_dma(struct ismt_priv *priv) ++{ ++ uint val; ++ u16 ctrl; ++ struct pci_dev *pdev; ++ u32 addr_lo, addr_hi; ++ ++ /* save msiaddr */ ++ pdev = priv->pci_dev; ++ pci_read_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_LO, &addr_lo); ++ pci_read_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_HI, &addr_hi); ++ ++ /* Clear the start bit */ ++ val = readl(priv->smba + ISMT_MSTR_MCTRL); ++ val &= ~ISMT_MCTRL_SS; ++ writel(val, priv->smba + ISMT_MSTR_MCTRL); ++ ++ val = readl(priv->smba + ISMT_GR_GCTRL); ++ writel(val | ISMT_GCTRL_KILL | ISMT_GCTRL_TRST | ISMT_GCTRL_SRST, priv->smba + ISMT_GR_GCTRL); ++ ++ if (dma_reset_timeout > 0) { ++ usleep_range(dma_reset_timeout, dma_reset_timeout + 1); ++ } ++ ++ ismt_hw_init(priv); ++ pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_LO, addr_lo); ++ pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_HI, addr_hi); ++ /* enable msi */ ++ pci_read_config_word(pdev, pdev->msi_cap + PCI_MSI_FLAGS, &ctrl); ++ ctrl |= PCI_MSI_FLAGS_ENABLE; ++ pci_write_config_word(pdev, pdev->msi_cap + PCI_MSI_FLAGS, ctrl); ++} ++ ++/** ++ * ismt_gen_reg_dump() - dump the iSMT General Registers ++ * @priv: iSMT private data ++ */ ++static void ismt_gen_reg_dump(struct ismt_priv *priv) ++{ ++ struct device *dev = &priv->pci_dev->dev; ++ ++ dev_dbg(dev, "Dump of the iSMT General Registers\n"); ++ dev_dbg(dev, " GCTRL.... : (0x%p)=0x%X\n", ++ priv->smba + ISMT_GR_GCTRL, ++ readl(priv->smba + ISMT_GR_GCTRL)); ++ dev_dbg(dev, " SMTICL... : (0x%p)=0x%016llX\n", ++ priv->smba + ISMT_GR_SMTICL, ++ (long long unsigned int)readq(priv->smba + ISMT_GR_SMTICL)); ++ dev_dbg(dev, " ERRINTMSK : (0x%p)=0x%X\n", ++ priv->smba + ISMT_GR_ERRINTMSK, ++ readl(priv->smba + ISMT_GR_ERRINTMSK)); ++ dev_dbg(dev, " ERRAERMSK : (0x%p)=0x%X\n", ++ priv->smba + ISMT_GR_ERRAERMSK, ++ readl(priv->smba + ISMT_GR_ERRAERMSK)); ++ dev_dbg(dev, " ERRSTS... : (0x%p)=0x%X\n", ++ priv->smba + ISMT_GR_ERRSTS, ++ readl(priv->smba + ISMT_GR_ERRSTS)); ++ dev_dbg(dev, " ERRINFO.. : (0x%p)=0x%X\n", ++ priv->smba + ISMT_GR_ERRINFO, ++ readl(priv->smba + ISMT_GR_ERRINFO)); ++} ++ ++/** ++ * ismt_mstr_reg_dump() - dump the iSMT Master Registers ++ * @priv: iSMT private data ++ */ ++static void ismt_mstr_reg_dump(struct ismt_priv *priv) ++{ ++ struct device *dev = &priv->pci_dev->dev; ++ ++ dev_dbg(dev, "Dump of the iSMT Master Registers\n"); ++ dev_dbg(dev, " MDBA..... : (0x%p)=0x%016llX\n", ++ priv->smba + ISMT_MSTR_MDBA, ++ (long long unsigned int)readq(priv->smba + ISMT_MSTR_MDBA)); ++ dev_dbg(dev, " MCTRL.... : (0x%p)=0x%X\n", ++ priv->smba + ISMT_MSTR_MCTRL, ++ readl(priv->smba + ISMT_MSTR_MCTRL)); ++ dev_dbg(dev, " MSTS..... : (0x%p)=0x%X\n", ++ priv->smba + ISMT_MSTR_MSTS, ++ readl(priv->smba + ISMT_MSTR_MSTS)); ++ dev_dbg(dev, " MDS...... : (0x%p)=0x%X\n", ++ priv->smba + ISMT_MSTR_MDS, ++ readl(priv->smba + ISMT_MSTR_MDS)); ++ dev_dbg(dev, " RPOLICY.. : (0x%p)=0x%X\n", ++ priv->smba + ISMT_MSTR_RPOLICY, ++ readl(priv->smba + ISMT_MSTR_RPOLICY)); ++ dev_dbg(dev, " SPGT..... : (0x%p)=0x%X\n", ++ priv->smba + ISMT_SPGT, ++ readl(priv->smba + ISMT_SPGT)); ++} ++ ++/** ++ * ismt_submit_desc() - add a descriptor to the ring ++ * @priv: iSMT private data ++ */ ++static void ismt_submit_desc(struct ismt_priv *priv) ++{ ++ uint fmhp; ++ uint val; ++ ++ ismt_desc_dump(priv); ++ ismt_gen_reg_dump(priv); ++ ismt_mstr_reg_dump(priv); ++ ++ /* Set the FMHP (Firmware Master Head Pointer)*/ ++ fmhp = ((priv->head + 1) % ISMT_DESC_ENTRIES) << 16; ++ val = readl(priv->smba + ISMT_MSTR_MCTRL); ++ writel((val & ~ISMT_MCTRL_FMHP) | fmhp, ++ priv->smba + ISMT_MSTR_MCTRL); ++ ++ /* Set the start bit */ ++ val = readl(priv->smba + ISMT_MSTR_MCTRL); ++ writel(val | ISMT_MCTRL_SS, ++ priv->smba + ISMT_MSTR_MCTRL); ++} ++ ++/** ++ * ismt_process_desc() - handle the completion of the descriptor ++ * @desc: the iSMT hardware descriptor ++ * @data: data buffer from the upper layer ++ * @priv: ismt_priv struct holding our dma buffer ++ * @size: SMBus transaction type ++ * @read_write: flag to indicate if this is a read or write ++ */ ++static int ismt_process_desc(const struct ismt_desc *desc, ++ union i2c_smbus_data *data, ++ struct ismt_priv *priv, int size, ++ char read_write) ++{ ++ u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16); ++ ++ dev_dbg(&priv->pci_dev->dev, "Processing completed descriptor\n"); ++ __ismt_desc_dump(&priv->pci_dev->dev, desc); ++ ismt_gen_reg_dump(priv); ++ ismt_mstr_reg_dump(priv); ++ ++ if (desc->status & ISMT_DESC_SCS) { ++ if (read_write == I2C_SMBUS_WRITE && ++ size != I2C_SMBUS_PROC_CALL) ++ return 0; ++ ++ switch (size) { ++ case I2C_SMBUS_BYTE: ++ case I2C_SMBUS_BYTE_DATA: ++ data->byte = dma_buffer[0]; ++ break; ++ case I2C_SMBUS_WORD_DATA: ++ case I2C_SMBUS_PROC_CALL: ++ data->word = dma_buffer[0] | (dma_buffer[1] << 8); ++ break; ++ case I2C_SMBUS_BLOCK_DATA: ++ if (desc->rxbytes != dma_buffer[0] + 1) ++ return -EMSGSIZE; ++ ++ memcpy(data->block, dma_buffer, desc->rxbytes); ++ break; ++ case I2C_SMBUS_I2C_BLOCK_DATA: ++ memcpy(&data->block[1], dma_buffer, desc->rxbytes); ++ data->block[0] = desc->rxbytes; ++ break; ++ } ++ return 0; ++ } ++ ++ if (likely(desc->status & ISMT_DESC_NAK)) ++ return -ENXIO; ++ ++ if (desc->status & ISMT_DESC_CRC) ++ return -EBADMSG; ++ ++ if (desc->status & ISMT_DESC_COL) ++ return -EAGAIN; ++ ++ if (desc->status & ISMT_DESC_LPR) ++ return -EPROTO; ++ ++ if (desc->status & (ISMT_DESC_DLTO | ISMT_DESC_CLTO)) ++ return -ETIMEDOUT; ++ ++ return -EIO; ++} ++ ++static void ismt_setscl(struct ismt_priv *priv, unsigned int level) ++{ ++ int pin_status; ++ ++ pin_status = readl(priv->smba + ISMT_DBCTRL); ++ if (level == 0) { ++ pin_status &= (~ISMT_DBCTRL_CLK_CTL); ++ } else { ++ pin_status |= ISMT_DBCTRL_CLK_CTL; ++ } ++ writel(pin_status, priv->smba + ISMT_DBCTRL); ++ pin_status = readl(priv->smba + ISMT_DBCTRL); ++ dev_dbg(&priv->pci_dev->dev, "dbctrl status = 0x%04x\r\n", pin_status); ++ return; ++} ++ ++static void ismt_i2c_unblock(struct ismt_priv *priv) ++{ ++ int i; ++ int pin_status, ori_status; ++ ++ pin_status = readl(priv->smba + ISMT_DBCTRL); ++ ori_status = pin_status; ++ if ((pin_status & ISMT_DBCTRL_ENABLE) == 0) { ++ pin_status |= ISMT_DBCTRL_ENABLE; ++ writel(pin_status, priv->smba + ISMT_DBCTRL); ++ pin_status = readl(priv->smba + ISMT_DBCTRL); ++ dev_dbg(&priv->pci_dev->dev, "enable dbctrl pin status = 0x%04x\r\n", pin_status); ++ } ++ ++ for (i = 0; i < 10; i++) { ++ ismt_setscl(priv, 0); ++ udelay(5); ++ ismt_setscl(priv, 1); ++ udelay(5); ++ } ++ ++ pin_status = readl(priv->smba + ISMT_DBCTRL); ++ if (pin_status != ori_status) { ++ writel(ori_status, priv->smba + ISMT_DBCTRL); ++ pin_status = readl(priv->smba + ISMT_DBCTRL); ++ dev_dbg(&priv->pci_dev->dev, "reback dbctrl pin status = 0x%04x\r\n", pin_status); ++ } ++ ++ return; ++} ++ ++static int ismt_check_i2c_unblock(struct ismt_priv *priv) ++{ ++ int pin_status; ++ ++ pin_status = readl(priv->smba + ISMT_DBSTS); ++ ++ if ( (!(pin_status & ISMT_DBSTS_SDA_STS) ) && (pin_status & ISMT_DBSTS_CLK_STS) ) { ++ dev_dbg(&priv->pci_dev->dev, "SDA is low, send 9 clock to device!\n"); ++ ismt_i2c_unblock(priv); ++ } ++ return 0; ++} ++ ++static int ismt_check_i2c_scl(struct ismt_priv *priv) ++{ ++ int pin_status; ++ ++ pin_status = readl(priv->smba + ISMT_DBSTS); ++ ++ if ( (pin_status & ISMT_DBSTS_SDA_STS) && (pin_status & ISMT_DBSTS_CLK_STS) ) { ++ return 0; ++ } ++ ++ dev_warn(&priv->pci_dev->dev, "SDA or SCL is low.pin_status:0x%x\n", pin_status); ++ return -1; ++} ++ ++/* Make sure the SMBus host is ready to start transmitting. ++ Return 0 if it is, -EIO if it is not. */ ++static int ismt_check_pre(struct ismt_priv *priv) ++{ ++ ismt_check_i2c_unblock(priv); ++ ++ /* SDA or SCL is low, return -EIO */ ++ if (ismt_check_i2c_scl(priv)) { ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++/** ++ * ismt_access() - process an SMBus command ++ * @adap: the i2c host adapter ++ * @addr: address of the i2c/SMBus target ++ * @flags: command options ++ * @read_write: read from or write to device ++ * @command: the i2c/SMBus command to issue ++ * @size: SMBus transaction type ++ * @data: read/write data buffer ++ */ ++static int ismt_access(struct i2c_adapter *adap, u16 addr, ++ unsigned short flags, char read_write, u8 command, ++ int size, union i2c_smbus_data *data) ++{ ++ int ret; ++ unsigned long time_left; ++ dma_addr_t dma_addr = 0; /* address of the data buffer */ ++ u8 dma_size = 0; ++ enum dma_data_direction dma_direction = 0; ++ struct ismt_desc *desc; ++ struct ismt_priv *priv = i2c_get_adapdata(adap); ++ struct device *dev = &priv->pci_dev->dev; ++ u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16); ++ ++ if (delay > 0) { ++ usleep_range(delay, delay + 1); ++ } ++ ++ ret = ismt_check_pre(priv); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ desc = &priv->hw[priv->head]; ++ ++ /* Initialize the DMA buffer */ ++ mem_clear(priv->buffer, sizeof(priv->buffer)); ++ ++ /* Initialize the descriptor */ ++ mem_clear(desc, sizeof(struct ismt_desc)); ++ desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write); ++ ++ /* Initialize common control bits */ ++ if (likely(pci_dev_msi_enabled(priv->pci_dev))) ++ desc->control = ISMT_DESC_INT | ISMT_DESC_FAIR; ++ else ++ desc->control = ISMT_DESC_FAIR; ++ ++ if ((flags & I2C_CLIENT_PEC) && (size != I2C_SMBUS_QUICK) ++ && (size != I2C_SMBUS_I2C_BLOCK_DATA)) ++ desc->control |= ISMT_DESC_PEC; ++ ++ switch (size) { ++ case I2C_SMBUS_QUICK: ++ dev_dbg(dev, "I2C_SMBUS_QUICK\n"); ++ break; ++ ++ case I2C_SMBUS_BYTE: ++ if (read_write == I2C_SMBUS_WRITE) { ++ /* ++ * Send Byte ++ * The command field contains the write data ++ */ ++ dev_dbg(dev, "I2C_SMBUS_BYTE: WRITE\n"); ++ desc->control |= ISMT_DESC_CWRL; ++ desc->wr_len_cmd = command; ++ } else { ++ /* Receive Byte */ ++ dev_dbg(dev, "I2C_SMBUS_BYTE: READ\n"); ++ dma_size = 1; ++ dma_direction = DMA_FROM_DEVICE; ++ desc->rd_len = 1; ++ } ++ break; ++ ++ case I2C_SMBUS_BYTE_DATA: ++ if (read_write == I2C_SMBUS_WRITE) { ++ /* ++ * Write Byte ++ * Command plus 1 data byte ++ */ ++ dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: WRITE\n"); ++ desc->wr_len_cmd = 2; ++ dma_size = 2; ++ dma_direction = DMA_TO_DEVICE; ++ dma_buffer[0] = command; ++ dma_buffer[1] = data->byte; ++ } else { ++ /* Read Byte */ ++ dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: READ\n"); ++ desc->control |= ISMT_DESC_CWRL; ++ desc->wr_len_cmd = command; ++ desc->rd_len = 1; ++ dma_size = 1; ++ dma_direction = DMA_FROM_DEVICE; ++ } ++ break; ++ ++ case I2C_SMBUS_WORD_DATA: ++ if (read_write == I2C_SMBUS_WRITE) { ++ /* Write Word */ ++ dev_dbg(dev, "I2C_SMBUS_WORD_DATA: WRITE\n"); ++ desc->wr_len_cmd = 3; ++ dma_size = 3; ++ dma_direction = DMA_TO_DEVICE; ++ dma_buffer[0] = command; ++ dma_buffer[1] = data->word & 0xff; ++ dma_buffer[2] = data->word >> 8; ++ } else { ++ /* Read Word */ ++ dev_dbg(dev, "I2C_SMBUS_WORD_DATA: READ\n"); ++ desc->wr_len_cmd = command; ++ desc->control |= ISMT_DESC_CWRL; ++ desc->rd_len = 2; ++ dma_size = 2; ++ dma_direction = DMA_FROM_DEVICE; ++ } ++ break; ++ ++ case I2C_SMBUS_PROC_CALL: ++ dev_dbg(dev, "I2C_SMBUS_PROC_CALL\n"); ++ desc->wr_len_cmd = 3; ++ desc->rd_len = 2; ++ dma_size = 3; ++ dma_direction = DMA_BIDIRECTIONAL; ++ dma_buffer[0] = command; ++ dma_buffer[1] = data->word & 0xff; ++ dma_buffer[2] = data->word >> 8; ++ break; ++ ++ case I2C_SMBUS_BLOCK_DATA: ++ if (read_write == I2C_SMBUS_WRITE) { ++ /* Block Write */ ++ dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: WRITE\n"); ++ dma_size = data->block[0] + 1; ++ dma_direction = DMA_TO_DEVICE; ++ desc->wr_len_cmd = dma_size; ++ desc->control |= ISMT_DESC_BLK; ++ dma_buffer[0] = command; ++ memcpy(&dma_buffer[1], &data->block[1], dma_size - 1); ++ } else { ++ /* Block Read */ ++ dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: READ\n"); ++ dma_size = I2C_SMBUS_BLOCK_MAX; ++ dma_direction = DMA_FROM_DEVICE; ++ desc->rd_len = dma_size; ++ desc->wr_len_cmd = command; ++ desc->control |= (ISMT_DESC_BLK | ISMT_DESC_CWRL); ++ } ++ break; ++ ++ case I2C_SMBUS_I2C_BLOCK_DATA: ++ /* Make sure the length is valid */ ++ if (data->block[0] < 1) ++ data->block[0] = 1; ++ ++ if (data->block[0] > I2C_SMBUS_BLOCK_MAX) ++ data->block[0] = I2C_SMBUS_BLOCK_MAX; ++ ++ if (read_write == I2C_SMBUS_WRITE) { ++ /* i2c Block Write */ ++ dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: WRITE\n"); ++ dma_size = data->block[0] + 1; ++ dma_direction = DMA_TO_DEVICE; ++ desc->wr_len_cmd = dma_size; ++ desc->control |= ISMT_DESC_I2C; ++ dma_buffer[0] = command; ++ memcpy(&dma_buffer[1], &data->block[1], dma_size - 1); ++ } else { ++ /* i2c Block Read */ ++ dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: READ\n"); ++ dma_size = data->block[0]; ++ dma_direction = DMA_FROM_DEVICE; ++ desc->rd_len = dma_size; ++ desc->wr_len_cmd = command; ++ desc->control |= (ISMT_DESC_I2C | ISMT_DESC_CWRL); ++ /* ++ * Per the "Table 15-15. I2C Commands", ++ * in the External Design Specification (EDS), ++ * (Document Number: 508084, Revision: 2.0), ++ * the _rw bit must be 0 ++ */ ++ desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, 0); ++ } ++ break; ++ ++ default: ++ dev_err(dev, "Unsupported transaction %d\n", ++ size); ++ return -EOPNOTSUPP; ++ } ++ ++ /* map the data buffer */ ++ if (dma_size != 0) { ++ dev_dbg(dev, " dev=%p\n", dev); ++ dev_dbg(dev, " data=%p\n", data); ++ dev_dbg(dev, " dma_buffer=%p\n", dma_buffer); ++ dev_dbg(dev, " dma_size=%d\n", dma_size); ++ dev_dbg(dev, " dma_direction=%d\n", dma_direction); ++ ++ dma_addr = dma_map_single(dev, ++ dma_buffer, ++ dma_size, ++ dma_direction); ++ ++ if (dma_mapping_error(dev, dma_addr)) { ++ dev_err(dev, "Error in mapping dma buffer %p\n", ++ dma_buffer); ++ return -EIO; ++ } ++ ++ dev_dbg(dev, " dma_addr = %pad\n", &dma_addr); ++ ++ desc->dptr_low = lower_32_bits(dma_addr); ++ desc->dptr_high = upper_32_bits(dma_addr); ++ } ++ ++ reinit_completion(&priv->cmp); ++ ++ /* Add the descriptor */ ++ ismt_submit_desc(priv); ++ ++ /* Now we wait for interrupt completion, 1s */ ++ time_left = wait_for_completion_timeout(&priv->cmp, HZ*1); ++ ++ /* unmap the data buffer */ ++ if (dma_size != 0) ++ dma_unmap_single(dev, dma_addr, dma_size, dma_direction); ++ ++ if (unlikely(!time_left)) { ++ dev_warn(dev, "completion wait timed out:addr[%d-0x%x], read_write[%d], command[0x%x], size[%d]\n", ++ adap->nr, addr, read_write, command, size); ++ ismt_reset_dma(priv); ++ ret = -ETIMEDOUT; ++ priv->head = 0; ++ return ret; ++ } ++ ++ /* do any post processing of the descriptor here */ ++ ret = ismt_process_desc(desc, data, priv, size, read_write); ++ /* Update the ring pointer */ ++ priv->head++; ++ priv->head %= ISMT_DESC_ENTRIES; ++ ++ return ret; ++} ++ ++/** ++ * ismt_func() - report which i2c commands are supported by this adapter ++ * @adap: the i2c host adapter ++ */ ++static u32 ismt_func(struct i2c_adapter *adap) ++{ ++ return I2C_FUNC_SMBUS_QUICK | ++ I2C_FUNC_SMBUS_BYTE | ++ I2C_FUNC_SMBUS_BYTE_DATA | ++ I2C_FUNC_SMBUS_WORD_DATA | ++ I2C_FUNC_SMBUS_PROC_CALL | ++ I2C_FUNC_SMBUS_BLOCK_DATA | ++ I2C_FUNC_SMBUS_I2C_BLOCK | ++ I2C_FUNC_SMBUS_PEC; ++} ++ ++static const struct i2c_algorithm smbus_algorithm = { ++ .smbus_xfer = ismt_access, ++ .functionality = ismt_func, ++}; ++ ++/** ++ * ismt_handle_isr() - interrupt handler bottom half ++ * @priv: iSMT private data ++ */ ++static irqreturn_t ismt_handle_isr(struct ismt_priv *priv) ++{ ++ complete(&priv->cmp); ++ ++ return IRQ_HANDLED; ++} ++ ++/** ++ * ismt_do_interrupt() - IRQ interrupt handler ++ * @vec: interrupt vector ++ * @data: iSMT private data ++ */ ++static irqreturn_t ismt_do_interrupt(int vec, void *data) ++{ ++ u32 val; ++ struct ismt_priv *priv = data; ++ ++ /* ++ * check to see it's our interrupt, return IRQ_NONE if not ours ++ * since we are sharing interrupt ++ */ ++ val = readl(priv->smba + ISMT_MSTR_MSTS); ++ ++ if (!(val & (ISMT_MSTS_MIS | ISMT_MSTS_MEIS))) ++ return IRQ_NONE; ++ else ++ writel(val | ISMT_MSTS_MIS | ISMT_MSTS_MEIS, ++ priv->smba + ISMT_MSTR_MSTS); ++ ++ return ismt_handle_isr(priv); ++} ++ ++/** ++ * ismt_do_msi_interrupt() - MSI interrupt handler ++ * @vec: interrupt vector ++ * @data: iSMT private data ++ */ ++static irqreturn_t ismt_do_msi_interrupt(int vec, void *data) ++{ ++ return ismt_handle_isr(data); ++} ++ ++/** ++ * ismt_hw_init() - initialize the iSMT hardware ++ * @priv: iSMT private data ++ */ ++static void ismt_hw_init(struct ismt_priv *priv) ++{ ++ u32 val; ++ struct device *dev = &priv->pci_dev->dev; ++ ++ /* initialize the Master Descriptor Base Address (MDBA) */ ++ writeq(priv->io_rng_dma, priv->smba + ISMT_MSTR_MDBA); ++ ++ /* initialize the Master Control Register (MCTRL) */ ++ writel(ISMT_MCTRL_MEIE, priv->smba + ISMT_MSTR_MCTRL); ++ ++ /* initialize the Master Status Register (MSTS) */ ++ writel(0, priv->smba + ISMT_MSTR_MSTS); ++ ++ /* initialize the Master Descriptor Size (MDS) */ ++ val = readl(priv->smba + ISMT_MSTR_MDS); ++ writel((val & ~ISMT_MDS_MASK) | (ISMT_DESC_ENTRIES - 1), ++ priv->smba + ISMT_MSTR_MDS); ++ ++ /* ++ * Set the SMBus speed (could use this for slow HW debuggers) ++ */ ++ ++ val = readl(priv->smba + ISMT_SPGT); ++ ++ switch (bus_speed) { ++ case 0: ++ break; ++ ++ case 80: ++ dev_dbg(dev, "Setting SMBus clock to 80 kHz\n"); ++ writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_80K), ++ priv->smba + ISMT_SPGT); ++ break; ++ ++ case 100: ++ dev_dbg(dev, "Setting SMBus clock to 100 kHz\n"); ++ writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_100K), ++ priv->smba + ISMT_SPGT); ++ break; ++ ++ case 400: ++ dev_dbg(dev, "Setting SMBus clock to 400 kHz\n"); ++ writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_400K), ++ priv->smba + ISMT_SPGT); ++ break; ++ ++ case 1000: ++ dev_dbg(dev, "Setting SMBus clock to 1000 kHz\n"); ++ writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_1M), ++ priv->smba + ISMT_SPGT); ++ break; ++ ++ default: ++ dev_warn(dev, "Invalid SMBus clock speed, only 0, 80, 100, 400, and 1000 are valid\n"); ++ break; ++ } ++ ++ val = readl(priv->smba + ISMT_SPGT); ++ ++ switch (val & ISMT_SPGT_SPD_MASK) { ++ case ISMT_SPGT_SPD_80K: ++ bus_speed = 80; ++ break; ++ case ISMT_SPGT_SPD_100K: ++ bus_speed = 100; ++ break; ++ case ISMT_SPGT_SPD_400K: ++ bus_speed = 400; ++ break; ++ case ISMT_SPGT_SPD_1M: ++ bus_speed = 1000; ++ break; ++ } ++ dev_info(dev, "SMBus clock is running at %d kHz with delay %d us\n", bus_speed, delay); ++} ++ ++/** ++ * ismt_dev_init() - initialize the iSMT data structures ++ * @priv: iSMT private data ++ */ ++static int ismt_dev_init(struct ismt_priv *priv) ++{ ++ /* allocate memory for the descriptor */ ++ priv->hw = dmam_alloc_coherent(&priv->pci_dev->dev, ++ (ISMT_DESC_ENTRIES ++ * sizeof(struct ismt_desc)), ++ &priv->io_rng_dma, ++ GFP_KERNEL); ++ if (!priv->hw) ++ return -ENOMEM; ++ ++ priv->head = 0; ++ init_completion(&priv->cmp); ++ ++ return 0; ++} ++ ++/** ++ * ismt_int_init() - initialize interrupts ++ * @priv: iSMT private data ++ */ ++static int ismt_int_init(struct ismt_priv *priv) ++{ ++ int err; ++ ++ /* Try using MSI interrupts */ ++ err = pci_enable_msi(priv->pci_dev); ++ if (err) ++ goto intx; ++ ++ err = devm_request_irq(&priv->pci_dev->dev, ++ priv->pci_dev->irq, ++ ismt_do_msi_interrupt, ++ 0, ++ "ismt-msi", ++ priv); ++ if (err) { ++ pci_disable_msi(priv->pci_dev); ++ goto intx; ++ } ++ ++ return 0; ++ ++ /* Try using legacy interrupts */ ++intx: ++ dev_warn(&priv->pci_dev->dev, ++ "Unable to use MSI interrupts, falling back to legacy\n"); ++ ++ err = devm_request_irq(&priv->pci_dev->dev, ++ priv->pci_dev->irq, ++ ismt_do_interrupt, ++ IRQF_SHARED, ++ "ismt-intx", ++ priv); ++ if (err) { ++ dev_err(&priv->pci_dev->dev, "no usable interrupts\n"); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static struct pci_driver ismt_driver; ++ ++/** ++ * ismt_probe() - probe for iSMT devices ++ * @pdev: PCI-Express device ++ * @id: PCI-Express device ID ++ */ ++static int ++ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id) ++{ ++ int err; ++ struct ismt_priv *priv; ++ unsigned long start, len; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ pci_set_drvdata(pdev, priv); ++ ++ i2c_set_adapdata(&priv->adapter, priv); ++ priv->adapter.owner = THIS_MODULE; ++ priv->adapter.class = I2C_CLASS_HWMON; ++ priv->adapter.algo = &smbus_algorithm; ++ priv->adapter.dev.parent = &pdev->dev; ++ ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev)); ++ priv->adapter.retries = ISMT_MAX_RETRIES; ++ ++ priv->pci_dev = pdev; ++ ++ err = pcim_enable_device(pdev); ++ if (err) { ++ dev_err(&pdev->dev, "Failed to enable SMBus PCI device (%d)\n", ++ err); ++ return err; ++ } ++ ++ /* enable bus mastering */ ++ pci_set_master(pdev); ++ ++ /* Determine the address of the SMBus area */ ++ start = pci_resource_start(pdev, SMBBAR); ++ len = pci_resource_len(pdev, SMBBAR); ++ if (!start || !len) { ++ dev_err(&pdev->dev, ++ "SMBus base address uninitialized, upgrade BIOS\n"); ++ return -ENODEV; ++ } ++ ++ snprintf(priv->adapter.name, sizeof(priv->adapter.name), ++ "SMBus iSMT adapter at %lx", start); ++ ++ dev_dbg(&priv->pci_dev->dev, " start=0x%lX\n", start); ++ dev_dbg(&priv->pci_dev->dev, " len=0x%lX\n", len); ++ ++ err = acpi_check_resource_conflict(&pdev->resource[SMBBAR]); ++ if (err) { ++ dev_err(&pdev->dev, "ACPI resource conflict!\n"); ++ return err; ++ } ++ ++ err = pci_request_region(pdev, SMBBAR, ismt_driver.name); ++ if (err) { ++ dev_err(&pdev->dev, ++ "Failed to request SMBus region 0x%lx-0x%lx\n", ++ start, start + len); ++ return err; ++ } ++ ++ priv->smba = pcim_iomap(pdev, SMBBAR, len); ++ if (!priv->smba) { ++ dev_err(&pdev->dev, "Unable to ioremap SMBus BAR\n"); ++ return -ENODEV; ++ } ++ ++ if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) || ++ (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)) { ++ if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) || ++ (pci_set_consistent_dma_mask(pdev, ++ DMA_BIT_MASK(32)) != 0)) { ++ dev_err(&pdev->dev, "pci_set_dma_mask fail %p\n", ++ pdev); ++ return -ENODEV; ++ } ++ } ++ ++ err = ismt_dev_init(priv); ++ if (err) ++ return err; ++ ++ ismt_hw_init(priv); ++ ++ err = ismt_int_init(priv); ++ if (err) ++ return err; ++ ++ err = i2c_add_adapter(&priv->adapter); ++ if (err) ++ return -ENODEV; ++ dev_info(&pdev->dev, "wb-i2c-ismt probe ok.\n"); ++ return 0; ++} ++ ++/** ++ * ismt_remove() - release driver resources ++ * @pdev: PCI-Express device ++ */ ++static void ismt_remove(struct pci_dev *pdev) ++{ ++ struct ismt_priv *priv = pci_get_drvdata(pdev); ++ ++ i2c_del_adapter(&priv->adapter); ++} ++ ++static struct pci_driver ismt_driver = { ++ .name = "wb_ismt_smbus", ++ .id_table = ismt_ids, ++ .probe = ismt_probe, ++ .remove = ismt_remove, ++}; ++ ++module_pci_driver(ismt_driver); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Bill E. Brown "); ++MODULE_DESCRIPTION("Intel SMBus Message Transport (iSMT) driver"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.c +new file mode 100644 +index 000000000..f318234ae +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.c +@@ -0,0 +1,1332 @@ ++/* ++ * I2C multiplexer ++ * ++ * Copyright (c) 2008-2009 Rodolfo Giometti ++ * Copyright (c) 2008-2009 Eurotech S.p.A. ++ * ++ * This module supports the PCA954x series of I2C multiplexer/switch chips ++ * made by Philips Semiconductors. ++ * This includes the: ++ * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547 ++ * and PCA9548. ++ * ++ * These chips are all controlled via the I2C bus itself, and all have a ++ * single 8-bit register. The upstream "parent" bus fans out to two, ++ * four, or eight downstream busses or channels; which of these ++ * are selected is determined by the chip type and register contents. A ++ * mux can select only one sub-bus at a time; a switch can select any ++ * combination simultaneously. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wb_i2c_mux_pca954x.h" ++ ++#define PCA954X_MAX_NCHANS 8 ++#define PCA954X_IRQ_OFFSET 4 ++ ++#define I2C_RETRY_TIMES 5 ++#define I2C_RETRY_WAIT_TIMES 10 /*delay 10ms*/ ++ ++typedef struct pca9548_cfg_info_s { ++ uint32_t pca9548_base_nr; ++ uint32_t pca9548_reset_type; ++ uint32_t rst_delay_b; /* delay time before reset(us) */ ++ uint32_t rst_delay; /* reset time(us) */ ++ uint32_t rst_delay_a; /* delay time after reset(us) */ ++ union { ++ i2c_attr_t i2c_attr; ++ gpio_attr_t gpio_attr; ++ io_attr_t io_attr; ++ file_attr_t file_attr; ++ } attr; ++ bool select_chan_check; ++ bool close_chan_force_reset; ++} pca9548_cfg_info_t; ++ ++int g_pca954x_debug = 0; ++int g_pca954x_error = 0; ++ ++module_param(g_pca954x_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_pca954x_error, int, S_IRUGO | S_IWUSR); ++ ++#define PCA954X_DEBUG(fmt, args...) do { \ ++ if (g_pca954x_debug) { \ ++ printk(KERN_INFO "[PCA95x][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define PCA954X_ERROR(fmt, args...) do { \ ++ if (g_pca954x_error) { \ ++ printk(KERN_ERR "[PCA95x][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++extern int pca9641_setmuxflag(int nr, int flag); ++enum pca_type { ++ pca_9540, ++ pca_9542, ++ pca_9543, ++ pca_9544, ++ pca_9545, ++ pca_9546, ++ pca_9547, ++ pca_9548, ++}; ++ ++struct chip_desc { ++ u8 nchans; ++ u8 enable; /* used for muxes only */ ++ u8 has_irq; ++ enum muxtype { ++ pca954x_ismux = 0, ++ pca954x_isswi ++ } muxtype; ++}; ++ ++struct pca954x { ++ const struct chip_desc *chip; ++ u8 last_chan; /* last register value */ ++ u8 deselect; ++ struct i2c_client *client; ++ struct irq_domain *irq; ++ unsigned int irq_mask; ++ raw_spinlock_t lock; ++ pca9548_cfg_info_t pca9548_cfg_info; /* pca9548 reset cfg */ ++}; ++ ++/* Provide specs for the PCA954x types we know about */ ++static const struct chip_desc chips[] = { ++ [pca_9540] = { ++ .nchans = 2, ++ .enable = 0x4, ++ .muxtype = pca954x_ismux, ++ }, ++ [pca_9542] = { ++ .nchans = 2, ++ .enable = 0x4, ++ .has_irq = 1, ++ .muxtype = pca954x_ismux, ++ }, ++ [pca_9543] = { ++ .nchans = 2, ++ .has_irq = 1, ++ .muxtype = pca954x_isswi, ++ }, ++ [pca_9544] = { ++ .nchans = 4, ++ .enable = 0x4, ++ .has_irq = 1, ++ .muxtype = pca954x_ismux, ++ }, ++ [pca_9545] = { ++ .nchans = 4, ++ .has_irq = 1, ++ .muxtype = pca954x_isswi, ++ }, ++ [pca_9546] = { ++ .nchans = 4, ++ .muxtype = pca954x_isswi, ++ }, ++ [pca_9547] = { ++ .nchans = 8, ++ .enable = 0x8, ++ .muxtype = pca954x_ismux, ++ }, ++ [pca_9548] = { ++ .nchans = 8, ++ .muxtype = pca954x_isswi, ++ }, ++}; ++ ++static const struct i2c_device_id pca954x_id[] = { ++ { "wb_pca9540", pca_9540 }, ++ { "wb_pca9542", pca_9542 }, ++ { "wb_pca9543", pca_9543 }, ++ { "wb_pca9544", pca_9544 }, ++ { "wb_pca9545", pca_9545 }, ++ { "wb_pca9546", pca_9546 }, ++ { "wb_pca9547", pca_9547 }, ++ { "wb_pca9548", pca_9548 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, pca954x_id); ++ ++#ifdef CONFIG_OF ++static const struct of_device_id pca954x_of_match[] = { ++ { .compatible = "nxp,wb_pca9540", .data = &chips[pca_9540] }, ++ { .compatible = "nxp,wb_pca9542", .data = &chips[pca_9542] }, ++ { .compatible = "nxp,wb_pca9543", .data = &chips[pca_9543] }, ++ { .compatible = "nxp,wb_pca9544", .data = &chips[pca_9544] }, ++ { .compatible = "nxp,wb_pca9545", .data = &chips[pca_9545] }, ++ { .compatible = "nxp,wb_pca9546", .data = &chips[pca_9546] }, ++ { .compatible = "nxp,wb_pca9547", .data = &chips[pca_9547] }, ++ { .compatible = "nxp,wb_pca9548", .data = &chips[pca_9548] }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, pca954x_of_match); ++#endif ++ ++/* 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 pca954x_reg_write(struct i2c_adapter *adap, ++ struct i2c_client *client, u8 val) ++{ ++ int ret = -ENODEV; ++ ++ if (adap->algo->master_xfer) { ++ struct i2c_msg msg; ++ char buf[1]; ++ ++ msg.addr = client->addr; ++ msg.flags = 0; ++ msg.len = 1; ++ buf[0] = val; ++ msg.buf = buf; ++ ret = __i2c_transfer(adap, &msg, 1); ++ ++ if (ret >= 0 && ret != 1) ++ ret = -EREMOTEIO; ++ } else { ++ union i2c_smbus_data data; ++ ret = adap->algo->smbus_xfer(adap, client->addr, ++ client->flags, ++ I2C_SMBUS_WRITE, ++ val, I2C_SMBUS_BYTE, &data); ++ } ++ return ret; ++} ++ ++static int pca954x_reg_read(struct i2c_adapter *adap, ++ struct i2c_client *client, u8 *val) ++{ ++ int ret = -ENODEV; ++ u8 tmp_val; ++ ++ if (adap->algo->master_xfer) { ++ struct i2c_msg msg; ++ ++ msg.addr = client->addr; ++ msg.flags = I2C_M_RD; ++ msg.len = 1; ++ msg.buf = &tmp_val; ++ ret = __i2c_transfer(adap, &msg, 1); ++ ++ if (ret >= 0 && ret != 1) { ++ ret = -EREMOTEIO; ++ } else { ++ *val = tmp_val; ++ } ++ } else { ++ union i2c_smbus_data data; ++ ret = adap->algo->smbus_xfer(adap, client->addr, ++ client->flags, ++ I2C_SMBUS_READ, ++ 0, I2C_SMBUS_BYTE, &data); ++ ++ if (!ret) { ++ tmp_val = data.byte; ++ *val = tmp_val; ++ } ++ } ++ ++ return ret; ++} ++ ++static int pca954x_setmuxflag(struct i2c_client *client, int flag) ++{ ++ int ret; ++ struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); ++ ++ ret = pca9641_setmuxflag(adap->nr, flag); ++ return ret; ++} ++ ++static int pca9548_gpio_init(gpio_attr_t *gpio_attr) ++{ ++ int err; ++ ++ if (gpio_attr->gpio_init) { ++ PCA954X_DEBUG("gpio%d already init, do nothing.\n", gpio_attr->gpio); ++ return 0; ++ } ++ ++ PCA954X_DEBUG("gpio%d init.\n", gpio_attr->gpio); ++ err = gpio_request(gpio_attr->gpio, "pca9548_reset"); ++ if (err) { ++ goto error; ++ } ++ err = gpio_direction_output(gpio_attr->gpio, gpio_attr->reset_off); ++ if (err) { ++ gpio_free(gpio_attr->gpio); ++ goto error; ++ } ++ gpio_attr->gpio_init = 1; ++ return 0; ++error: ++ PCA954X_ERROR("pca9548_gpio_init failed, ret:%d.\n", err); ++ return err; ++} ++ ++static void pca9548_gpio_free(gpio_attr_t *gpio_attr) ++{ ++ if (gpio_attr->gpio_init == 1) { ++ PCA954X_DEBUG("gpio%d release.\n", gpio_attr->gpio); ++ gpio_free(gpio_attr->gpio); ++ gpio_attr->gpio_init = 0; ++ } ++} ++ ++static int pca954x_reset_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) ++{ ++ int ret; ++ struct file *filp; ++ loff_t tmp_pos; ++ ++ filp = filp_open(path, O_RDONLY, 0); ++ if (IS_ERR(filp)) { ++ PCA954X_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); ++ filp = NULL; ++ goto exit; ++ } ++ ++ tmp_pos = (loff_t)pos; ++ ret = kernel_read(filp, val, size, &tmp_pos); ++ if (ret < 0) { ++ PCA954X_ERROR("kernel_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); ++ goto exit; ++ } ++ ++ filp_close(filp, NULL); ++ ++ return ret; ++ ++exit: ++ if (filp != NULL) { ++ filp_close(filp, NULL); ++ } ++ ++ return -1; ++} ++ ++static int pca954x_reset_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) ++{ ++ int ret; ++ struct file *filp; ++ loff_t tmp_pos; ++ ++ filp = filp_open(path, O_RDWR, 777); ++ if (IS_ERR(filp)) { ++ PCA954X_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); ++ filp = NULL; ++ goto exit; ++ } ++ ++ tmp_pos = (loff_t)pos; ++ ret = kernel_write(filp, val, size, &tmp_pos); ++ if (ret < 0) { ++ PCA954X_ERROR("kernel_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); ++ goto exit; ++ } ++ ++ vfs_fsync(filp, 1); ++ filp_close(filp, NULL); ++ ++ return ret; ++ ++exit: ++ if (filp != NULL) { ++ filp_close(filp, NULL); ++ } ++ ++ return -1; ++} ++ ++static int pca954x_reset_i2c_read(uint32_t bus, uint32_t addr, uint32_t offset_addr, ++ unsigned char *buf, uint32_t size) ++{ ++ struct file *fp; ++ struct i2c_client client; ++ char i2c_path[32]; ++ int i ,j ; ++ int rv; ++ ++ rv = 0; ++ mem_clear(i2c_path, sizeof(i2c_path)); ++ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); ++ fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); ++ if (IS_ERR(fp)) { ++ PCA954X_ERROR("i2c open fail.\n"); ++ return -1; ++ } ++ memcpy(&client, fp->private_data, sizeof(struct i2c_client)); ++ client.addr = addr; ++ for (j = 0 ;j < size ;j++) { ++ for (i = 0; i < I2C_RETRY_TIMES; i++) { ++ rv = i2c_smbus_read_byte_data(&client, (offset_addr + j)); ++ if (rv < 0) { ++ PCA954X_ERROR("i2c read failed, try again.\n"); ++ msleep(I2C_RETRY_WAIT_TIMES); ++ if (i >= (I2C_RETRY_TIMES - 1)) { ++ goto out; ++ } ++ continue; ++ } ++ *(buf + j) = (unsigned char)rv; ++ break; ++ } ++ } ++out: ++ filp_close(fp, NULL); ++ return rv; ++} ++ ++static int pca954x_reset_i2c_write(uint32_t bus, uint32_t dev_addr, uint32_t offset_addr, ++ uint8_t write_buf) ++{ ++ struct file *fp; ++ struct i2c_client client; ++ char i2c_path[32]; ++ int i; ++ int rv; ++ ++ rv = 0; ++ mem_clear(i2c_path, sizeof(i2c_path)); ++ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); ++ fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); ++ if (IS_ERR(fp)) { ++ PCA954X_ERROR("i2c open fail.\n"); ++ return -1; ++ } ++ memcpy(&client, fp->private_data, sizeof(struct i2c_client)); ++ client.addr = dev_addr; ++ for (i = 0; i < I2C_RETRY_TIMES; i++) { ++ rv = i2c_smbus_write_byte_data(&client, offset_addr, write_buf); ++ if (rv < 0) { ++ PCA954X_ERROR("i2c write failed, try again.\n"); ++ msleep(I2C_RETRY_WAIT_TIMES); ++ if (i >= (I2C_RETRY_TIMES - 1)) { ++ goto out; ++ } ++ continue; ++ } ++ break; ++ } ++out: ++ filp_close(fp, NULL); ++ return rv; ++} ++ ++static int pca954x_do_file_reset(struct i2c_mux_core *muxc) ++{ ++ int ret, timeout, err; ++ struct pca954x *data; ++ pca9548_cfg_info_t *reset_cfg; ++ file_attr_t *file_attr; ++ u8 val; ++ int udelay_cnt; ++ ++ data = i2c_mux_priv(muxc); ++ reset_cfg = &data->pca9548_cfg_info; ++ file_attr = &reset_cfg->attr.file_attr; ++ ret = -1; ++ ++ PCA954X_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", ++ reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); ++ PCA954X_DEBUG("dev_name:%s, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", ++ file_attr->dev_name, file_attr->offset, file_attr->mask, ++ file_attr->reset_on, file_attr->reset_off); ++ ++ if (reset_cfg->rst_delay_b) { ++ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); ++ } ++ ++ err = pca954x_reset_file_read(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); ++ if (err < 0) { ++ goto out; ++ } ++ val &= ~(file_attr->mask); ++ val |= file_attr->reset_on; ++ err = pca954x_reset_file_write(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); ++ if (err < 0) { ++ goto out; ++ } ++ ++ if (reset_cfg->rst_delay) { ++ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); ++ } ++ ++ val &= ~(file_attr->mask); ++ val |= file_attr->reset_off; ++ err = pca954x_reset_file_write(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); ++ if (err < 0) { ++ goto out; ++ } ++ ++ udelay_cnt = 0; ++ timeout = reset_cfg->rst_delay_a; ++ while (timeout > 0) { ++ usleep_range(1, 2); ++ err = pca954x_reset_file_read(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); ++ if (err < 0) { ++ goto out; ++ } ++ val &= (file_attr->mask); ++ if (val == file_attr->reset_off) { ++ ret = 0; ++ PCA954X_DEBUG("pca954x_do_file_reset success.\n"); ++ break; ++ } ++ udelay_cnt++; ++ if ((udelay_cnt % 1000) == 0) { ++ /* 1MS schedule*/ ++ schedule(); ++ } ++ timeout--; ++ } ++ if (ret < 0) { ++ PCA954X_ERROR("pca954x_do_file_reset timeout.\n"); ++ } ++out: ++ if (err < 0) { ++ PCA954X_ERROR("pca954x_do_file_reset file rd/wr failed, ret:%d.\n", err); ++ } ++ ++ return ret; ++} ++ ++static int pca954x_do_io_reset(struct i2c_mux_core *muxc) ++{ ++ int ret, timeout; ++ struct pca954x *data; ++ pca9548_cfg_info_t *reset_cfg; ++ io_attr_t *io_attr; ++ u8 val; ++ int udelay_cnt; ++ ++ data = i2c_mux_priv(muxc); ++ reset_cfg = &data->pca9548_cfg_info; ++ io_attr = &reset_cfg->attr.io_attr; ++ ++ PCA954X_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", ++ reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); ++ PCA954X_DEBUG("io_addr:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", ++ io_attr->io_addr, io_attr->mask, io_attr->reset_on, io_attr->reset_off); ++ ++ if (reset_cfg->rst_delay_b) { ++ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); ++ } ++ ++ val = inb(io_attr->io_addr); ++ val &= ~(io_attr->mask); ++ val |= io_attr->reset_on; ++ outb(val, io_attr->io_addr); ++ ++ if (reset_cfg->rst_delay) { ++ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); ++ } ++ ++ val &= ~(io_attr->mask); ++ val |= io_attr->reset_off; ++ outb(val, io_attr->io_addr); ++ ++ ret = -1; ++ udelay_cnt = 0; ++ timeout = reset_cfg->rst_delay_a; ++ while (timeout > 0) { ++ usleep_range(1, 2); ++ val = inb(io_attr->io_addr); ++ val &= (io_attr->mask); ++ if (val == io_attr->reset_off) { ++ ret = 0; ++ PCA954X_DEBUG("pca954x_do_io_reset success.\n"); ++ break; ++ } ++ udelay_cnt++; ++ if ((udelay_cnt % 1000) == 0) { ++ /* 1MS schedule*/ ++ schedule(); ++ } ++ timeout--; ++ } ++ ++ if (ret < 0) { ++ PCA954X_ERROR("pca954x_do_io_reset timeout.\n"); ++ } ++ ++ return ret; ++} ++ ++static int pca954x_do_gpio_reset(struct i2c_mux_core *muxc) ++{ ++ int ret, timeout; ++ struct pca954x *data; ++ pca9548_cfg_info_t *reset_cfg; ++ gpio_attr_t *gpio_attr; ++ u8 val; ++ int udelay_cnt; ++ ++ data = i2c_mux_priv(muxc); ++ reset_cfg = &data->pca9548_cfg_info; ++ gpio_attr = &reset_cfg->attr.gpio_attr; ++ ++ ret = pca9548_gpio_init(gpio_attr); ++ if (ret) { ++ return -1; ++ } ++ ++ if (reset_cfg->rst_delay_b) { ++ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); ++ } ++ ++ /* reset on */ ++ __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_on); ++ ++ if (reset_cfg->rst_delay) { ++ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); ++ } ++ ++ /* reset off */ ++ __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_off); ++ ret = -1; ++ udelay_cnt = 0; ++ timeout = reset_cfg->rst_delay_a; ++ while (timeout > 0) { ++ usleep_range(1, 2); ++ val = __gpio_get_value(gpio_attr->gpio); ++ if (val == gpio_attr->reset_off) { ++ ret = 0; ++ PCA954X_DEBUG("pca954x_do_gpio_reset success.\n"); ++ break; ++ } ++ udelay_cnt++; ++ if ((udelay_cnt % 1000) == 0) { ++ /* 1MS schedule*/ ++ schedule(); ++ } ++ timeout--; ++ } ++ ++ if (ret < 0) { ++ PCA954X_ERROR("pca954x_do_gpio_reset timeout.\n"); ++ } ++ ++ pca9548_gpio_free(gpio_attr); ++ return ret; ++} ++ ++static int pca954x_do_i2c_reset(struct i2c_mux_core *muxc) ++{ ++ int ret, timeout, err; ++ struct pca954x *data; ++ pca9548_cfg_info_t *reset_cfg; ++ i2c_attr_t *i2c_attr; ++ u8 val; ++ int udelay_cnt; ++ ++ data = i2c_mux_priv(muxc); ++ reset_cfg = &data->pca9548_cfg_info; ++ i2c_attr = &reset_cfg->attr.i2c_attr; ++ ret = -1; ++ ++ PCA954X_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", ++ reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); ++ PCA954X_DEBUG("bus:0x%x, addr:0x%x, reg:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", ++ i2c_attr->i2c_bus, i2c_attr->i2c_addr, i2c_attr->reg_offset, ++ i2c_attr->mask, i2c_attr->reset_on, i2c_attr->reset_off); ++ ++ if (reset_cfg->rst_delay_b) { ++ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); ++ } ++ ++ err = pca954x_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, ++ i2c_attr->reg_offset, &val, sizeof(val)); ++ if (err < 0) { ++ goto out; ++ } ++ val &= ~(i2c_attr->mask); ++ val |= i2c_attr->reset_on; ++ err = pca954x_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, ++ i2c_attr->reg_offset, val); ++ if (err < 0) { ++ goto out; ++ } ++ ++ if (reset_cfg->rst_delay) { ++ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); ++ } ++ ++ val &= ~(i2c_attr->mask); ++ val |= i2c_attr->reset_off; ++ err = pca954x_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, ++ i2c_attr->reg_offset, val); ++ if (err < 0) { ++ goto out; ++ } ++ ++ udelay_cnt = 0; ++ timeout = reset_cfg->rst_delay_a; ++ while (timeout > 0) { ++ usleep_range(1, 2); ++ err = pca954x_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, ++ i2c_attr->reg_offset, &val, sizeof(val)); ++ if (err < 0) { ++ goto out; ++ } ++ val &= (i2c_attr->mask); ++ if (val == i2c_attr->reset_off) { ++ ret = 0; ++ PCA954X_DEBUG("pca954x_do_i2c_reset success.\n"); ++ break; ++ } ++ udelay_cnt++; ++ if ((udelay_cnt % 1000) == 0) { ++ /* 1MS schedule*/ ++ schedule(); ++ } ++ timeout--; ++ } ++ if (ret < 0) { ++ PCA954X_ERROR("pca954x_do_i2c_reset timeout.\n"); ++ } ++out: ++ if (err < 0) { ++ PCA954X_ERROR("pca954x_do_i2c_reset i2c op failed, ret:%d.\n", err); ++ } ++ return ret; ++} ++ ++static int pca954x_do_reset(struct i2c_mux_core *muxc) ++{ ++ int ret; ++ struct pca954x *data; ++ ++ data = i2c_mux_priv(muxc); ++ if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_NONE) { ++ ret = -1; ++ PCA954X_DEBUG("Don't need to reset.\n"); ++ } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_I2C) { ++ ret = pca954x_do_i2c_reset(muxc); ++ } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_GPIO) { ++ ret = pca954x_do_gpio_reset(muxc); ++ } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_IO) { ++ ret = pca954x_do_io_reset(muxc); ++ } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_FILE) { ++ ret = pca954x_do_file_reset(muxc); ++ } else { ++ ret = -1; ++ PCA954X_ERROR("Unsupport reset type:0x%x.\n", ++ data->pca9548_cfg_info.pca9548_reset_type); ++ } ++ ++ if (ret < 0) { ++ PCA954X_ERROR("pca9548_reset_ctrl failed, reset type:%u, ret:%d.\n", ++ data->pca9548_cfg_info.pca9548_reset_type, ret); ++ } ++ return ret; ++} ++ ++static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) ++{ ++ struct pca954x *data = i2c_mux_priv(muxc); ++ struct i2c_client *client = data->client; ++ const struct chip_desc *chip = data->chip; ++ u8 regval; ++ int ret = 0; ++ u8 read_val = 0; ++ int rv; ++ ++ /* we make switches look like muxes, not sure how to be smarter */ ++ if (chip->muxtype == pca954x_ismux) ++ regval = chan | chip->enable; ++ else ++ regval = 1 << chan; ++ ++ /* Only select the channel if its different from the last channel */ ++ if (data->last_chan != regval) { ++ pca954x_setmuxflag(client, 0); ++ ret = pca954x_reg_write(muxc->parent, client, regval); ++ data->last_chan = ret < 0 ? 0 : regval; ++ } ++ ++ if (data->pca9548_cfg_info.select_chan_check) { /* check chan */ ++ ret = pca954x_reg_read(muxc->parent, client, &read_val); ++ /* read failed or chan not open, reset pca9548 */ ++ if ((ret < 0) || (read_val != data->last_chan)) { ++ dev_warn(&client->dev, "pca954x open channle %u failed, do reset.\n", chan); ++ PCA954X_DEBUG("ret = %d, read_val = %d, last_chan = %d.\n", ret, read_val, data->last_chan); ++ rv = pca954x_do_reset(muxc); ++ if (rv >= 0) { ++ PCA954X_DEBUG("pca954x_do_reset success, rv = %d.\n", rv); ++ } else { ++ PCA954X_DEBUG("pca954x_do_reset failed, rv = %d.\n", rv); ++ } ++ if (ret >= 0) { ++ ret = -EIO; /* chan not match, return IO error */ ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan) ++{ ++ struct pca954x *data = i2c_mux_priv(muxc); ++ struct i2c_client *client = data->client; ++ int ret, rv; ++ ++ /* Deselect active channel */ ++ data->last_chan = 0; ++ if (data->pca9548_cfg_info.close_chan_force_reset) { ++ ret = pca954x_do_reset(muxc); ++ } else { ++ ret = pca954x_reg_write(muxc->parent, client, data->last_chan); ++ if (ret < 0 ) { ++ dev_warn(&client->dev, "pca954x close channel %u failed, do reset.\n", chan); ++ rv = pca954x_do_reset(muxc); ++ if (rv == 0) { ++ ret = 0; ++ } ++ } ++ } ++ ++ rv = pca954x_setmuxflag(client, 1); ++ if (rv == 0) { ++ PCA954X_DEBUG("match 9641, close 9548 channel to deselect 9641.\n"); ++ (void)pca954x_reg_write(muxc->parent, client, data->last_chan); ++ } else { ++ PCA954X_DEBUG("dismatch 9641, do nothing.\n"); ++ } ++ ++ return ret; ++ ++} ++ ++static irqreturn_t pca954x_irq_handler(int irq, void *dev_id) ++{ ++ struct pca954x *data = dev_id; ++ unsigned int child_irq; ++ int ret, i, handled = 0; ++ ++ ret = i2c_smbus_read_byte(data->client); ++ if (ret < 0) ++ return IRQ_NONE; ++ ++ for (i = 0; i < data->chip->nchans; i++) { ++ if (ret & BIT(PCA954X_IRQ_OFFSET + i)) { ++ child_irq = irq_linear_revmap(data->irq, i); ++ handle_nested_irq(child_irq); ++ handled++; ++ } ++ } ++ return handled ? IRQ_HANDLED : IRQ_NONE; ++} ++ ++static void pca954x_irq_mask(struct irq_data *idata) ++{ ++ struct pca954x *data = irq_data_get_irq_chip_data(idata); ++ unsigned int pos = idata->hwirq; ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&data->lock, flags); ++ ++ data->irq_mask &= ~BIT(pos); ++ if (!data->irq_mask) ++ disable_irq(data->client->irq); ++ ++ raw_spin_unlock_irqrestore(&data->lock, flags); ++} ++ ++static void pca954x_irq_unmask(struct irq_data *idata) ++{ ++ struct pca954x *data = irq_data_get_irq_chip_data(idata); ++ unsigned int pos = idata->hwirq; ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&data->lock, flags); ++ ++ if (!data->irq_mask) ++ enable_irq(data->client->irq); ++ data->irq_mask |= BIT(pos); ++ ++ raw_spin_unlock_irqrestore(&data->lock, flags); ++} ++ ++static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) ++{ ++ if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_LOW) ++ return -EINVAL; ++ return 0; ++} ++ ++static struct irq_chip pca954x_irq_chip = { ++ .name = "i2c-mux-pca954x", ++ .irq_mask = pca954x_irq_mask, ++ .irq_unmask = pca954x_irq_unmask, ++ .irq_set_type = pca954x_irq_set_type, ++}; ++ ++static int of_pca954x_irq_setup(struct i2c_mux_core *muxc) ++{ ++ struct pca954x *data = i2c_mux_priv(muxc); ++ struct i2c_client *client = data->client; ++ int c, err, irq; ++ ++ if (!data->chip->has_irq || client->irq <= 0) ++ return 0; ++ ++ raw_spin_lock_init(&data->lock); ++ ++ data->irq = irq_domain_add_linear(client->dev.of_node, ++ data->chip->nchans, ++ &irq_domain_simple_ops, data); ++ if (!data->irq) ++ return -ENODEV; ++ ++ for (c = 0; c < data->chip->nchans; c++) { ++ irq = irq_create_mapping(data->irq, c); ++ irq_set_chip_data(irq, data); ++ irq_set_chip_and_handler(irq, &pca954x_irq_chip, ++ handle_simple_irq); ++ } ++ ++ err = devm_request_threaded_irq(&client->dev, data->client->irq, NULL, ++ pca954x_irq_handler, ++ IRQF_ONESHOT | IRQF_SHARED, ++ "pca954x", data); ++ if (err) ++ goto err_req_irq; ++ ++ disable_irq(data->client->irq); ++ ++ return 0; ++err_req_irq: ++ for (c = 0; c < data->chip->nchans; c++) { ++ irq = irq_find_mapping(data->irq, c); ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(data->irq); ++ ++ return err; ++} ++ ++static int pca954x_irq_setup(struct i2c_mux_core *muxc) ++{ ++ return 0; ++} ++ ++static int of_pca954x_reset_data_init(struct pca954x *data) ++{ ++ int err; ++ struct device *dev = &data->client->dev; ++ pca9548_cfg_info_t *reset_cfg; ++ ++ reset_cfg = &data->pca9548_cfg_info; ++ if (dev == NULL || dev->of_node == NULL) { ++ PCA954X_DEBUG("dev or dev->of_node is NUll, no reset.\n"); ++ reset_cfg->pca9548_reset_type = PCA9548_RESET_NONE; ++ return 0; ++ } ++ ++ reset_cfg->select_chan_check = of_property_read_bool(dev->of_node, "select_chan_check"); ++ reset_cfg->close_chan_force_reset = of_property_read_bool(dev->of_node, "close_chan_force_reset"); ++ PCA954X_DEBUG("select_chan_check:%d, close_chan_force_reset:%d.\n", reset_cfg->select_chan_check, ++ reset_cfg->close_chan_force_reset); ++ ++ if (of_property_read_u32(dev->of_node, "pca9548_reset_type", &reset_cfg->pca9548_reset_type)) { ++ ++ PCA954X_DEBUG("pca9548_reset_type not found, no reset.\n"); ++ reset_cfg->pca9548_reset_type = PCA9548_RESET_NONE; ++ return 0; ++ } ++ err = of_property_read_u32(dev->of_node, "rst_delay_b", &reset_cfg->rst_delay_b); ++ err |= of_property_read_u32(dev->of_node, "rst_delay", &reset_cfg->rst_delay); ++ err |= of_property_read_u32(dev->of_node, "rst_delay_a", &reset_cfg->rst_delay_a); ++ ++ if (err) { ++ goto dts_config_err; ++ } ++ PCA954X_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", ++ reset_cfg->pca9548_reset_type, reset_cfg->rst_delay_b, ++ reset_cfg->rst_delay, reset_cfg->rst_delay_a); ++ ++ if (reset_cfg->pca9548_reset_type == PCA9548_RESET_I2C) { ++ ++ PCA954X_DEBUG("reset by i2c.\n"); ++ err = of_property_read_u32(dev->of_node, "i2c_bus", &reset_cfg->attr.i2c_attr.i2c_bus); ++ err |=of_property_read_u32(dev->of_node, "i2c_addr", &reset_cfg->attr.i2c_attr.i2c_addr); ++ err |=of_property_read_u32(dev->of_node, "reg_offset", &reset_cfg->attr.i2c_attr.reg_offset); ++ err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.i2c_attr.mask); ++ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.i2c_attr.reset_on); ++ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.i2c_attr.reset_off); ++ if (err) { ++ goto dts_config_err; ++ } ++ PCA954X_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", ++ reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, ++ reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, ++ reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); ++ } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_GPIO) { ++ ++ PCA954X_DEBUG("reset by gpio.\n"); ++ err = of_property_read_u32(dev->of_node, "gpio", &reset_cfg->attr.gpio_attr.gpio); ++ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.gpio_attr.reset_on); ++ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.gpio_attr.reset_off); ++ if (err) { ++ goto dts_config_err; ++ } ++ PCA954X_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", ++ reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, ++ reset_cfg->attr.gpio_attr.reset_off); ++ reset_cfg->attr.gpio_attr.gpio_init = 0; ++ } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_IO) { ++ ++ PCA954X_DEBUG("reset by io.\n"); ++ err = of_property_read_u32(dev->of_node, "io_addr", &reset_cfg->attr.io_attr.io_addr); ++ err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.io_attr.mask); ++ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.io_attr.reset_on); ++ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.io_attr.reset_off); ++ if (err) { ++ goto dts_config_err; ++ } ++ PCA954X_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", ++ reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, ++ reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); ++ } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_FILE) { ++ ++ PCA954X_DEBUG("reset by file.\n"); ++ err = of_property_read_string(dev->of_node, "dev_name", &reset_cfg->attr.file_attr.dev_name); ++ err |=of_property_read_u32(dev->of_node, "offset", &reset_cfg->attr.file_attr.offset); ++ err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.file_attr.mask); ++ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.file_attr.reset_on); ++ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.file_attr.reset_off); ++ if (err) { ++ goto dts_config_err; ++ } ++ PCA954X_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", ++ reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, ++ reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off); ++ } else { ++ PCA954X_ERROR("Unsupport reset type:%d.\n", reset_cfg->pca9548_reset_type); ++ goto dts_config_err; ++ } ++ return 0; ++dts_config_err: ++ PCA954X_ERROR("dts config error, ret:%d.\n", err); ++ return -EINVAL; ++} ++ ++static int pca954x_reset_data_init(struct pca954x *data) ++{ ++ pca9548_cfg_info_t *reset_cfg; ++ i2c_mux_pca954x_device_t *i2c_mux_pca954x_device; ++ ++ if (data->client->dev.platform_data == NULL) { ++ PCA954X_DEBUG("pca954x has no reset platform data config.\n"); ++ return 0; ++ } ++ reset_cfg = &data->pca9548_cfg_info; ++ i2c_mux_pca954x_device = data->client->dev.platform_data; ++ reset_cfg->select_chan_check = i2c_mux_pca954x_device->select_chan_check; ++ reset_cfg->close_chan_force_reset = i2c_mux_pca954x_device->close_chan_force_reset; ++ PCA954X_DEBUG("select_chan_check:%d, close_chan_force_reset:%d.\n", reset_cfg->select_chan_check, ++ reset_cfg->close_chan_force_reset); ++ ++ reset_cfg->pca9548_reset_type = i2c_mux_pca954x_device->pca9548_reset_type; ++ if (reset_cfg->pca9548_reset_type == PCA9548_RESET_NONE) { ++ PCA954X_DEBUG("pca9548_reset_type not found, no reset.\n"); ++ return 0; ++ } ++ ++ reset_cfg->rst_delay_b = i2c_mux_pca954x_device->rst_delay_b; ++ reset_cfg->rst_delay = i2c_mux_pca954x_device->rst_delay; ++ reset_cfg->rst_delay_a = i2c_mux_pca954x_device->rst_delay_a; ++ PCA954X_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", ++ reset_cfg->pca9548_reset_type, reset_cfg->rst_delay_b, ++ reset_cfg->rst_delay, reset_cfg->rst_delay_a); ++ ++ if (reset_cfg->pca9548_reset_type == PCA9548_RESET_I2C) { ++ ++ PCA954X_DEBUG("reset by i2c.\n"); ++ reset_cfg->attr.i2c_attr.i2c_bus = i2c_mux_pca954x_device->attr.i2c_attr.i2c_bus; ++ reset_cfg->attr.i2c_attr.i2c_addr = i2c_mux_pca954x_device->attr.i2c_attr.i2c_addr; ++ reset_cfg->attr.i2c_attr.reg_offset = i2c_mux_pca954x_device->attr.i2c_attr.reg_offset; ++ reset_cfg->attr.i2c_attr.mask = i2c_mux_pca954x_device->attr.i2c_attr.mask; ++ reset_cfg->attr.i2c_attr.reset_on = i2c_mux_pca954x_device->attr.i2c_attr.reset_on; ++ reset_cfg->attr.i2c_attr.reset_off = i2c_mux_pca954x_device->attr.i2c_attr.reset_off; ++ PCA954X_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", ++ reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, ++ reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, ++ reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); ++ } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_GPIO) { ++ ++ PCA954X_DEBUG("reset by gpio.\n"); ++ reset_cfg->attr.gpio_attr.gpio = i2c_mux_pca954x_device->attr.gpio_attr.gpio; ++ reset_cfg->attr.gpio_attr.reset_on = i2c_mux_pca954x_device->attr.gpio_attr.reset_on; ++ reset_cfg->attr.gpio_attr.reset_off = i2c_mux_pca954x_device->attr.gpio_attr.reset_off; ++ PCA954X_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", ++ reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, ++ reset_cfg->attr.gpio_attr.reset_off); ++ reset_cfg->attr.gpio_attr.gpio_init = 0; ++ } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_IO) { ++ ++ PCA954X_DEBUG("reset by io.\n"); ++ reset_cfg->attr.io_attr.io_addr = i2c_mux_pca954x_device->attr.io_attr.io_addr; ++ reset_cfg->attr.io_attr.mask = i2c_mux_pca954x_device->attr.io_attr.mask; ++ reset_cfg->attr.io_attr.reset_on = i2c_mux_pca954x_device->attr.io_attr.reset_on; ++ reset_cfg->attr.io_attr.reset_off = i2c_mux_pca954x_device->attr.io_attr.reset_off; ++ PCA954X_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", ++ reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, ++ reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); ++ } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_FILE) { ++ ++ reset_cfg->attr.file_attr.dev_name = i2c_mux_pca954x_device->attr.file_attr.dev_name; ++ reset_cfg->attr.file_attr.offset = i2c_mux_pca954x_device->attr.file_attr.offset; ++ reset_cfg->attr.file_attr.mask = i2c_mux_pca954x_device->attr.file_attr.mask; ++ reset_cfg->attr.file_attr.reset_on = i2c_mux_pca954x_device->attr.file_attr.reset_on; ++ reset_cfg->attr.file_attr.reset_off = i2c_mux_pca954x_device->attr.file_attr.reset_off; ++ PCA954X_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", ++ reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, ++ reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off); ++ } else { ++ PCA954X_ERROR("Unsupport reset type:%d.\n", reset_cfg->pca9548_reset_type); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/* ++ * I2C init/probing/exit functions ++ */ ++static int pca954x_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); ++ struct device_node *of_node = client->dev.of_node; ++ bool idle_disconnect_dt; ++ struct gpio_desc *gpio; ++ int num, force, class; ++ struct i2c_mux_core *muxc; ++ struct pca954x *data; ++ const struct of_device_id *match; ++ unsigned int probe_disable; ++ int ret, dynamic_nr; ++ i2c_mux_pca954x_device_t *i2c_mux_pca954x_device; ++ ++ PCA954X_DEBUG("pca954x_probe, parent bus: %d, 9548 addr:0x%x.\n", adap->nr, client->addr); ++ ++ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) ++ return -ENODEV; ++ ++ muxc = i2c_mux_alloc(adap, &client->dev, ++ PCA954X_MAX_NCHANS, sizeof(*data), 0, ++ pca954x_select_chan, pca954x_deselect_mux); ++ if (!muxc) ++ return -ENOMEM; ++ data = i2c_mux_priv(muxc); ++ ++ i2c_set_clientdata(client, muxc); ++ data->client = client; ++ ++ /* Get the mux out of reset if a reset GPIO is specified. */ ++ gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); ++ if (IS_ERR(gpio)) ++ return PTR_ERR(gpio); ++ ++ /* check device connection status */ ++ ++ if (client->dev.of_node == NULL) { ++ if (client->dev.platform_data == NULL) { ++ probe_disable = 1; ++ PCA954X_DEBUG("has no platform data config, set probe_disable = 1.\n"); ++ } else { ++ i2c_mux_pca954x_device = client->dev.platform_data; ++ probe_disable = i2c_mux_pca954x_device->probe_disable; ++ } ++ } else { ++ probe_disable = of_property_read_bool(of_node, "probe_disable"); ++ } ++ ++ /* Write the mux register at addr to verify ++ * that the mux is in fact present. This also ++ * initializes the mux to disconnected state. ++ */ ++ if (!probe_disable && (i2c_smbus_write_byte(client, 0) < 0)) { ++ dev_warn(&client->dev, "probe failed\n"); ++ return -ENODEV; ++ } ++ ++ match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); ++ if (match) ++ data->chip = of_device_get_match_data(&client->dev); ++ else ++ data->chip = &chips[id->driver_data]; ++ ++ data->last_chan = 0; /* force the first selection */ ++ ++ if (client->dev.of_node == NULL) { ++ idle_disconnect_dt = false; ++ } else { ++ idle_disconnect_dt = of_node && ++ of_property_read_bool(of_node, "i2c-mux-idle-disconnect"); ++ } ++ ++ if (client->dev.of_node) { ++ ret= of_pca954x_reset_data_init(data); ++ } else { ++ ret= pca954x_reset_data_init(data); ++ } ++ if (ret < 0) { ++ dev_err(&client->dev, "pca954x reset config err, ret:%d.\n", ret); ++ return ret; ++ } ++ ++ if (client->dev.of_node) { ++ ret = of_pca954x_irq_setup(muxc); ++ } else { ++ ret = pca954x_irq_setup(muxc); ++ } ++ if (ret) { ++ goto fail_del_adapters; ++ } ++ ++ if (client->dev.of_node == NULL) { ++ if (client->dev.platform_data == NULL) { ++ dynamic_nr = 1; ++ PCA954X_DEBUG("platform data is NULL, use dynamic adap number.\n"); ++ } else { ++ i2c_mux_pca954x_device = client->dev.platform_data; ++ data->pca9548_cfg_info.pca9548_base_nr = i2c_mux_pca954x_device->pca9548_base_nr; ++ if (data->pca9548_cfg_info.pca9548_base_nr == 0) { ++ dynamic_nr = 1; ++ PCA954X_DEBUG("pca9548_base_nr = 0, use dynamic adap number.\n"); ++ } else { ++ dynamic_nr = 0; ++ PCA954X_DEBUG("pca9548_base_nr:%u.\n", data->pca9548_cfg_info.pca9548_base_nr); ++ } ++ } ++ } else { ++ if (of_property_read_u32(of_node, "pca9548_base_nr", &data->pca9548_cfg_info.pca9548_base_nr)) { ++ ++ dynamic_nr = 1; ++ PCA954X_DEBUG("pca9548_base_nr not found, use dynamic adap number"); ++ } else { ++ dynamic_nr = 0; ++ PCA954X_DEBUG("pca9548_base_nr:%u.\n", data->pca9548_cfg_info.pca9548_base_nr); ++ } ++ } ++ ++ /* Now create an adapter for each channel */ ++ for (num = 0; num < data->chip->nchans; num++) { ++ bool idle_disconnect_pd = false; ++ if (dynamic_nr == 1) { ++ force = 0; /* dynamic adap number */ ++ } else { ++ force = data->pca9548_cfg_info.pca9548_base_nr + num; ++ } ++ ++ class = 0; /* no class by default */ ++ data->deselect |= (idle_disconnect_pd || ++ idle_disconnect_dt) << num; ++ ++ ret = i2c_mux_add_adapter(muxc, force, num, class); ++ if (ret) ++ goto fail_del_adapters; ++ } ++ ++ dev_info(&client->dev, ++ "registered %d multiplexed busses for I2C %s %s\n", ++ num, data->chip->muxtype == pca954x_ismux ++ ? "mux" : "switch", client->name); ++ ++ return 0; ++ ++fail_del_adapters: ++ i2c_mux_del_adapters(muxc); ++ return ret; ++} ++ ++static int pca954x_remove(struct i2c_client *client) ++{ ++ struct i2c_mux_core *muxc = i2c_get_clientdata(client); ++ struct pca954x *data = i2c_mux_priv(muxc); ++ int c, irq; ++ ++ if (data->irq) { ++ for (c = 0; c < data->chip->nchans; c++) { ++ irq = irq_find_mapping(data->irq, c); ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(data->irq); ++ } ++ ++ i2c_mux_del_adapters(muxc); ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int pca954x_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct i2c_mux_core *muxc = i2c_get_clientdata(client); ++ struct pca954x *data = i2c_mux_priv(muxc); ++ ++ data->last_chan = 0; ++ return i2c_smbus_write_byte(client, 0); ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(pca954x_pm, NULL, pca954x_resume); ++ ++static struct i2c_driver pca954x_driver = { ++ .driver = { ++ .name = "wb_pca954x", ++ .pm = &pca954x_pm, ++ .of_match_table = of_match_ptr(pca954x_of_match), ++ }, ++ .probe = pca954x_probe, ++ .remove = pca954x_remove, ++ .id_table = pca954x_id, ++}; ++ ++module_i2c_driver(pca954x_driver); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("PCA954x I2C mux/switch driver"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.h +new file mode 100644 +index 000000000..9cbe16278 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.h +@@ -0,0 +1,67 @@ ++#ifndef __WB_I2C_MUX_PCA954X_H__ ++#define __WB_I2C_MUX_PCA954X_H__ ++ ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++ ++typedef enum pca9548_reset_type_s { ++ PCA9548_RESET_NONE = 0, ++ PCA9548_RESET_I2C = 1, ++ PCA9548_RESET_GPIO = 2, ++ PCA9548_RESET_IO = 3, ++ PCA9548_RESET_FILE = 4, ++} pca9548_reset_type_t; ++ ++typedef struct i2c_attr_s { ++ uint32_t i2c_bus; ++ uint32_t i2c_addr; ++ uint32_t reg_offset; ++ uint32_t mask; ++ uint32_t reset_on; ++ uint32_t reset_off; ++} i2c_attr_t; ++ ++typedef struct io_attr_s { ++ uint32_t io_addr; ++ uint32_t mask; ++ uint32_t reset_on; ++ uint32_t reset_off; ++} io_attr_t; ++ ++typedef struct file_attr_s { ++ const char *dev_name; ++ uint32_t offset; ++ uint32_t mask; ++ uint32_t reset_on; ++ uint32_t reset_off; ++} file_attr_t; ++ ++typedef struct gpio_attr_s { ++ int gpio_init; ++ uint32_t gpio; ++ uint32_t reset_on; ++ uint32_t reset_off; ++} gpio_attr_t; ++ ++typedef struct i2c_mux_pca954x_device_s { ++ struct i2c_client *client; ++ uint32_t i2c_bus; ++ uint32_t i2c_addr; ++ uint32_t pca9548_base_nr; ++ uint32_t pca9548_reset_type; ++ uint32_t rst_delay_b; /* delay time before reset(us) */ ++ uint32_t rst_delay; /* reset time(us) */ ++ uint32_t rst_delay_a; /* delay time after reset(us) */ ++ bool probe_disable; ++ bool select_chan_check; ++ bool close_chan_force_reset; ++ union { ++ i2c_attr_t i2c_attr; ++ gpio_attr_t gpio_attr; ++ io_attr_t io_attr; ++ file_attr_t file_attr; ++ } attr; ++} i2c_mux_pca954x_device_t; ++ ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.c +new file mode 100644 +index 000000000..c5b6a835a +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.c +@@ -0,0 +1,1396 @@ ++/* ++ * I2C multiplexer driver for PCA9541 bus master selector ++ * ++ * Copyright (c) 2010 Ericsson AB. ++ * ++ * Author: Guenter Roeck ++ * ++ * Derived from: ++ * pca954x.c ++ * ++ * Copyright (c) 2008-2009 Rodolfo Giometti ++ * Copyright (c) 2008-2009 Eurotech S.p.A. ++ * ++ * 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 ++#include ++#include ++ ++#include "wb_i2c_mux_pca9641.h" ++ ++/* ++ * The PCA9541 is a bus master selector. It supports two I2C masters connected ++ * to a single slave bus. ++ * ++ * Before each bus transaction, a master has to acquire bus ownership. After the ++ * transaction is complete, bus ownership has to be released. This fits well ++ * into the I2C multiplexer framework, which provides select and release ++ * functions for this purpose. For this reason, this driver is modeled as ++ * single-channel I2C bus multiplexer. ++ * ++ * This driver assumes that the two bus masters are controlled by two different ++ * hosts. If a single host controls both masters, platform code has to ensure ++ * that only one of the masters is instantiated at any given time. ++ */ ++ ++#define PCA9541_CONTROL 0x01 ++#define PCA9541_ISTAT 0x02 ++ ++#define PCA9541_CTL_MYBUS (1 << 0) ++#define PCA9541_CTL_NMYBUS (1 << 1) ++#define PCA9541_CTL_BUSON (1 << 2) ++#define PCA9541_CTL_NBUSON (1 << 3) ++#define PCA9541_CTL_BUSINIT (1 << 4) ++#define PCA9541_CTL_TESTON (1 << 6) ++#define PCA9541_CTL_NTESTON (1 << 7) ++#define PCA9541_ISTAT_INTIN (1 << 0) ++#define PCA9541_ISTAT_BUSINIT (1 << 1) ++#define PCA9541_ISTAT_BUSOK (1 << 2) ++#define PCA9541_ISTAT_BUSLOST (1 << 3) ++#define PCA9541_ISTAT_MYTEST (1 << 6) ++#define PCA9541_ISTAT_NMYTEST (1 << 7) ++#define PCA9641_ID 0x00 ++#define PCA9641_ID_MAGIC 0x38 ++#define PCA9641_CONTROL 0x01 ++#define PCA9641_STATUS 0x02 ++#define PCA9641_TIME 0x03 ++#define PCA9641_CTL_LOCK_REQ BIT(0) ++#define PCA9641_CTL_LOCK_GRANT BIT(1) ++#define PCA9641_CTL_BUS_CONNECT BIT(2) ++#define PCA9641_CTL_BUS_INIT BIT(3) ++#define PCA9641_CTL_SMBUS_SWRST BIT(4) ++#define PCA9641_CTL_IDLE_TIMER_DIS BIT(5) ++#define PCA9641_CTL_SMBUS_DIS BIT(6) ++#define PCA9641_CTL_PRIORITY BIT(7) ++#define PCA9641_STS_OTHER_LOCK BIT(0) ++#define PCA9641_STS_BUS_INIT_FAIL BIT(1) ++#define PCA9641_STS_BUS_HUNG BIT(2) ++#define PCA9641_STS_MBOX_EMPTY BIT(3) ++#define PCA9641_STS_MBOX_FULL BIT(4) ++#define PCA9641_STS_TEST_INT BIT(5) ++#define PCA9641_STS_SCL_IO BIT(6) ++#define PCA9641_STS_SDA_IO BIT(7) ++#define PCA9641_RES_TIME 0x03 ++#define BUSON (PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON) ++#define MYBUS (PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS) ++#define mybus(x) (!((x) & MYBUS) || ((x) & MYBUS) == MYBUS) ++#define busoff(x) (!((x) & BUSON) || ((x) & BUSON) == BUSON) ++#define BUSOFF(x, y) (!((x) & PCA9641_CTL_LOCK_GRANT) && \ ++ !((y) & PCA9641_STS_OTHER_LOCK)) ++#define other_lock(x) ((x) & PCA9641_STS_OTHER_LOCK) ++#define lock_grant(x) ((x) & PCA9641_CTL_LOCK_GRANT) ++ ++#define PCA9641_RETRY_TIME (8) ++#define PCA9641_RESET_DELAY (150) ++ ++typedef struct i2c_muxs_struct_flag ++{ ++ int nr; ++ char name[48]; ++ struct mutex update_lock; ++ int flag; ++}i2c_mux_flag; ++ ++i2c_mux_flag pca_flag = { ++ .nr = -1, ++ .flag = -1, ++}; ++ ++int pca9641_setmuxflag(int nr, int flag) ++{ ++ if (pca_flag.nr == nr) { ++ pca_flag.flag = flag; ++ return 0; ++ } ++ return -1; ++} ++EXPORT_SYMBOL(pca9641_setmuxflag); ++ ++static int g_debug_info = 0; ++static int g_debug_err = 0; ++ ++module_param(g_debug_info, int, S_IRUGO | S_IWUSR); ++module_param(g_debug_err, int, S_IRUGO | S_IWUSR); ++ ++#define PCA_DEBUG(fmt, args...) do { \ ++ if (g_debug_info) { \ ++ printk(KERN_INFO "[pca9641][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define PCA_DEBUG_ERR(fmt, args...) do { \ ++ if (g_debug_err) { \ ++ printk(KERN_ERR "[pca9641][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++/* arbitration timeouts, in jiffies */ ++#define ARB_TIMEOUT (HZ / 8) /* 125 ms until forcing bus ownership */ ++#define ARB2_TIMEOUT (HZ / 4) /* 250 ms until acquisition failure */ ++ ++/* arbitration retry delays, in us */ ++#define SELECT_DELAY_SHORT 50 ++#define SELECT_DELAY_LONG 1000 ++#define I2C_RETRY_TIMES (5) ++#define I2C_RETRY_WAIT_TIMES (10) /*delay 10ms*/ ++ ++typedef struct pca9641_cfg_info_s { ++ uint32_t pca9641_reset_type; ++ uint32_t rst_delay_b; /* delay time before reset(us) */ ++ uint32_t rst_delay; /* reset time(us) */ ++ uint32_t rst_delay_a; /* delay time after reset(us) */ ++ union { ++ i2c_attr_t i2c_attr; ++ gpio_attr_t gpio_attr; ++ io_attr_t io_attr; ++ file_attr_t file_attr; ++ } attr; ++} pca9641_cfg_info_t; ++ ++struct pca9541 { ++ struct i2c_client *client; ++ unsigned long select_timeout; ++ unsigned long arb_timeout; ++ uint32_t pca9641_nr; ++ pca9641_cfg_info_t pca9641_cfg_info; /* pca9641 reset cfg */ ++}; ++ ++static const struct i2c_device_id pca9541_id[] = { ++ {"wb_pca9541", 0}, ++ {"wb_pca9641", 1}, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(i2c, pca9541_id); ++ ++#ifdef CONFIG_OF ++static const struct of_device_id pca9541_of_match[] = { ++ { .compatible = "nxp,wb_pca9541" }, ++ { .compatible = "nxp,wb_pca9641" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, pca9541_of_match); ++#endif ++ ++static int pca9641_gpio_init(gpio_attr_t *gpio_attr) ++{ ++ int err; ++ ++ if (gpio_attr->gpio_init) { ++ PCA_DEBUG("gpio%d already init, do nothing.\n", gpio_attr->gpio); ++ return 0; ++ } ++ ++ PCA_DEBUG("gpio%d init.\n", gpio_attr->gpio); ++ err = gpio_request(gpio_attr->gpio, "pca9641_reset"); ++ if (err) { ++ goto error; ++ } ++ err = gpio_direction_output(gpio_attr->gpio, gpio_attr->reset_off); ++ if (err) { ++ gpio_free(gpio_attr->gpio); ++ goto error; ++ } ++ gpio_attr->gpio_init = 1; ++ return 0; ++error: ++ PCA_DEBUG_ERR("pca9641_gpio_init failed, ret:%d.\n", err); ++ return err; ++} ++ ++static void pca9641_gpio_free(gpio_attr_t *gpio_attr) ++{ ++ if (gpio_attr->gpio_init == 1) { ++ PCA_DEBUG("gpio%d release.\n", gpio_attr->gpio); ++ gpio_free(gpio_attr->gpio); ++ gpio_attr->gpio_init = 0; ++ } ++ return; ++} ++ ++static int pca9641_reset_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) ++{ ++ int ret; ++ struct file *filp; ++ loff_t tmp_pos; ++ ++ filp = filp_open(path, O_RDONLY, 0); ++ if (IS_ERR(filp)) { ++ PCA_DEBUG_ERR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); ++ filp = NULL; ++ goto exit; ++ } ++ ++ tmp_pos = (loff_t)pos; ++ ret = kernel_read(filp, val, size, &tmp_pos); ++ if (ret < 0) { ++ PCA_DEBUG_ERR("kernel_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); ++ goto exit; ++ } ++ ++ filp_close(filp, NULL); ++ ++ return ret; ++ ++exit: ++ if (filp != NULL) { ++ filp_close(filp, NULL); ++ } ++ ++ return -1; ++} ++ ++static int pca9641_reset_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) ++{ ++ ++ int ret; ++ struct file *filp; ++ loff_t tmp_pos; ++ ++ filp = filp_open(path, O_RDWR, 777); ++ if (IS_ERR(filp)) { ++ PCA_DEBUG_ERR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); ++ filp = NULL; ++ goto exit; ++ } ++ ++ tmp_pos = (loff_t)pos; ++ ret = kernel_write(filp, val, size, &tmp_pos); ++ if (ret < 0) { ++ PCA_DEBUG_ERR("kernel_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); ++ goto exit; ++ } ++ ++ vfs_fsync(filp, 1); ++ filp_close(filp, NULL); ++ ++ return ret; ++ ++exit: ++ if (filp != NULL) { ++ filp_close(filp, NULL); ++ } ++ ++ return -1; ++} ++ ++static int pca9641_reset_i2c_read(uint32_t bus, uint32_t addr, uint32_t offset_addr, ++ unsigned char *buf, uint32_t size) ++{ ++ struct file *fp; ++ struct i2c_client client; ++ char i2c_path[32]; ++ int i, j; ++ int rv; ++ ++ rv = 0; ++ mem_clear(i2c_path, sizeof(i2c_path)); ++ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); ++ fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); ++ if (IS_ERR(fp)) { ++ PCA_DEBUG_ERR("i2c open fail.\n"); ++ return -1; ++ } ++ memcpy(&client, fp->private_data, sizeof(struct i2c_client)); ++ client.addr = addr; ++ for (j = 0; j < size; j++) { ++ for (i = 0; i < I2C_RETRY_TIMES; i++) { ++ rv = i2c_smbus_read_byte_data(&client, (offset_addr + j)); ++ if (rv < 0) { ++ PCA_DEBUG_ERR("i2c read failed, try again.\n"); ++ msleep(I2C_RETRY_WAIT_TIMES); ++ if (i >= (I2C_RETRY_TIMES - 1)) { ++ goto out; ++ } ++ continue; ++ } ++ *(buf + j) = (unsigned char)rv; ++ break; ++ } ++ } ++out: ++ filp_close(fp, NULL); ++ return rv; ++} ++ ++static int pca9641_reset_i2c_write(uint32_t bus, uint32_t dev_addr, uint32_t offset_addr, ++ uint8_t write_buf) ++{ ++ struct file *fp; ++ struct i2c_client client; ++ char i2c_path[32]; ++ int i; ++ int rv; ++ ++ rv = 0; ++ mem_clear(i2c_path, sizeof(i2c_path)); ++ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); ++ fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); ++ if (IS_ERR(fp)) { ++ PCA_DEBUG_ERR("i2c open fail.\n"); ++ return -1; ++ } ++ memcpy(&client, fp->private_data, sizeof(struct i2c_client)); ++ client.addr = dev_addr; ++ for (i = 0; i < I2C_RETRY_TIMES; i++) { ++ rv = i2c_smbus_write_byte_data(&client, offset_addr, write_buf); ++ if (rv < 0) { ++ PCA_DEBUG_ERR("i2c write failed, try again.\n"); ++ msleep(I2C_RETRY_WAIT_TIMES); ++ if (i >= (I2C_RETRY_TIMES - 1)) { ++ goto out; ++ } ++ continue; ++ } ++ break; ++ } ++out: ++ filp_close(fp, NULL); ++ return rv; ++} ++ ++static int pca9641_do_file_reset(struct i2c_mux_core *muxc) ++{ ++ int ret, timeout, err; ++ struct pca9541 *data; ++ pca9641_cfg_info_t *reset_cfg; ++ file_attr_t *file_attr; ++ u8 val; ++ int udelay_cnt; ++ ++ data = i2c_mux_priv(muxc); ++ reset_cfg = &data->pca9641_cfg_info; ++ file_attr = &reset_cfg->attr.file_attr; ++ ret = -1; ++ ++ PCA_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", ++ reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); ++ PCA_DEBUG("dev_name:%s, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", ++ file_attr->dev_name, file_attr->offset, file_attr->mask, ++ file_attr->reset_on, file_attr->reset_off); ++ ++ if (reset_cfg->rst_delay_b) { ++ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); ++ } ++ ++ err = pca9641_reset_file_read(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); ++ if (err < 0) { ++ goto out; ++ } ++ ++ val &= ~(file_attr->mask); ++ val |= file_attr->reset_on; ++ err = pca9641_reset_file_write(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); ++ if (err < 0) { ++ goto out; ++ } ++ ++ if (reset_cfg->rst_delay) { ++ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); ++ } ++ ++ val &= ~(file_attr->mask); ++ val |= file_attr->reset_off; ++ err = pca9641_reset_file_write(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); ++ if (err < 0) { ++ goto out; ++ } ++ ++ udelay_cnt = 0; ++ timeout = reset_cfg->rst_delay_a; ++ while (timeout > 0) { ++ usleep_range(1, 2); ++ err = pca9641_reset_file_read(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); ++ if (err < 0) { ++ goto out; ++ } ++ val &= (file_attr->mask); ++ if (val == file_attr->reset_off) { ++ ret = 0; ++ PCA_DEBUG("pca9641_do_file_reset success.\n"); ++ break; ++ } ++ udelay_cnt++; ++ if ((udelay_cnt % 1000) == 0) { ++ /* 1MS schedule*/ ++ schedule(); ++ } ++ timeout--; ++ } ++ if (ret < 0) { ++ PCA_DEBUG_ERR("pca9641_do_file_reset timeout.\n"); ++ } ++out: ++ if (err < 0) { ++ PCA_DEBUG_ERR("pca9641_do_file_reset file rd/wr failed, ret:%d.\n", err); ++ } ++ ++ return ret; ++} ++ ++static int pca9641_do_io_reset(struct i2c_mux_core *muxc) ++{ ++ int ret, timeout; ++ struct pca9541 *data; ++ pca9641_cfg_info_t *reset_cfg; ++ io_attr_t *io_attr; ++ u8 val; ++ int udelay_cnt; ++ ++ data = i2c_mux_priv(muxc); ++ reset_cfg = &data->pca9641_cfg_info; ++ io_attr = &reset_cfg->attr.io_attr; ++ ++ PCA_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", ++ reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); ++ PCA_DEBUG("io_addr:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", ++ io_attr->io_addr, io_attr->mask, io_attr->reset_on, io_attr->reset_off); ++ ++ if (reset_cfg->rst_delay_b) { ++ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); ++ } ++ ++ val = inb(io_attr->io_addr); ++ val &= ~(io_attr->mask); ++ val |= io_attr->reset_on; ++ outb(val, io_attr->io_addr); ++ ++ if (reset_cfg->rst_delay) { ++ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); ++ } ++ ++ val &= ~(io_attr->mask); ++ val |= io_attr->reset_off; ++ outb(val, io_attr->io_addr); ++ ++ ret = -1; ++ udelay_cnt = 0; ++ timeout = reset_cfg->rst_delay_a; ++ while (timeout > 0) { ++ usleep_range(1, 2); ++ val = inb(io_attr->io_addr); ++ val &= (io_attr->mask); ++ if (val == io_attr->reset_off) { ++ ret = 0; ++ PCA_DEBUG("pca9641_do_io_reset success.\n"); ++ break; ++ } ++ udelay_cnt++; ++ if ((udelay_cnt % 1000) == 0) { ++ /* 1MS schedule*/ ++ schedule(); ++ } ++ timeout--; ++ } ++ ++ if (ret < 0) { ++ PCA_DEBUG_ERR("pca9641_do_io_reset timeout.\n"); ++ } ++ ++ return ret; ++} ++ ++static int pca9641_do_gpio_reset(struct i2c_mux_core *muxc) ++{ ++ int ret, timeout; ++ struct pca9541 *data; ++ pca9641_cfg_info_t *reset_cfg; ++ gpio_attr_t *gpio_attr; ++ u8 val; ++ int udelay_cnt; ++ ++ data = i2c_mux_priv(muxc); ++ reset_cfg = &data->pca9641_cfg_info; ++ gpio_attr = &reset_cfg->attr.gpio_attr; ++ ++ ret = pca9641_gpio_init(gpio_attr); ++ if (ret) { ++ return -1; ++ } ++ ++ if (reset_cfg->rst_delay_b) { ++ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); ++ } ++ ++ __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_on); ++ ++ if (reset_cfg->rst_delay) { ++ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); ++ } ++ ++ __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_off); ++ ret = -1; ++ udelay_cnt = 0; ++ timeout = reset_cfg->rst_delay_a; ++ while (timeout > 0) { ++ usleep_range(1, 2); ++ val = __gpio_get_value(gpio_attr->gpio); ++ if (val == gpio_attr->reset_off) { ++ ret = 0; ++ PCA_DEBUG("pca9641_do_gpio_reset success.\n"); ++ break; ++ } ++ udelay_cnt++; ++ if ((udelay_cnt % 1000) == 0) { ++ /* 1MS schedule*/ ++ schedule(); ++ } ++ timeout--; ++ } ++ ++ if (ret < 0) { ++ PCA_DEBUG_ERR("pca9641_do_gpio_reset timeout.\n"); ++ } ++ ++ pca9641_gpio_free(gpio_attr); ++ return ret; ++} ++ ++static int pca9641_do_i2c_reset(struct i2c_mux_core *muxc) ++{ ++ int ret, timeout, err; ++ struct pca9541 *data; ++ pca9641_cfg_info_t *reset_cfg; ++ i2c_attr_t *i2c_attr; ++ u8 val; ++ int udelay_cnt; ++ ++ data = i2c_mux_priv(muxc); ++ reset_cfg = &data->pca9641_cfg_info; ++ i2c_attr = &reset_cfg->attr.i2c_attr; ++ ret = -1; ++ ++ PCA_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", ++ reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); ++ PCA_DEBUG("bus:0x%x, addr:0x%x, reg:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", ++ i2c_attr->i2c_bus, i2c_attr->i2c_addr, i2c_attr->reg_offset, ++ i2c_attr->mask, i2c_attr->reset_on, i2c_attr->reset_off); ++ ++ if (reset_cfg->rst_delay_b) { ++ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); ++ } ++ ++ err = pca9641_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, ++ i2c_attr->reg_offset, &val, sizeof(val)); ++ if (err < 0) { ++ goto out; ++ } ++ ++ val &= ~(i2c_attr->mask); ++ val |= i2c_attr->reset_on; ++ err = pca9641_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, ++ i2c_attr->reg_offset, val); ++ if (err < 0) { ++ goto out; ++ } ++ ++ if (reset_cfg->rst_delay) { ++ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); ++ } ++ ++ val &= ~(i2c_attr->mask); ++ val |= i2c_attr->reset_off; ++ err = pca9641_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, ++ i2c_attr->reg_offset, val); ++ if (err < 0) { ++ goto out; ++ } ++ ++ udelay_cnt = 0; ++ timeout = reset_cfg->rst_delay_a; ++ while (timeout > 0) { ++ usleep_range(1, 2); ++ err = pca9641_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, ++ i2c_attr->reg_offset, &val, sizeof(val)); ++ if (err < 0) { ++ goto out; ++ } ++ val &= (i2c_attr->mask); ++ if (val == i2c_attr->reset_off) { ++ ret = 0; ++ PCA_DEBUG("pca9641_do_i2c_reset success.\n"); ++ break; ++ } ++ udelay_cnt++; ++ if ((udelay_cnt % 1000) == 0) { ++ /* 1MS schedule*/ ++ schedule(); ++ } ++ timeout--; ++ } ++ if (ret < 0) { ++ PCA_DEBUG_ERR("pca9641_do_i2c_reset timeout.\n"); ++ } ++out: ++ if (err < 0) { ++ PCA_DEBUG_ERR("pca9641_do_i2c_reset i2c op failed, ret:%d.\n", err); ++ } ++ return ret; ++} ++ ++static int pca9641_do_reset(struct i2c_mux_core *muxc) ++{ ++ int ret; ++ struct pca9541 *data; ++ ++ data = i2c_mux_priv(muxc); ++ if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_NONE) { ++ ret = -1; ++ PCA_DEBUG("Don't need to reset.\n"); ++ } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_I2C) { ++ ret = pca9641_do_i2c_reset(muxc); ++ } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_GPIO) { ++ ret = pca9641_do_gpio_reset(muxc); ++ } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_IO) { ++ ret = pca9641_do_io_reset(muxc); ++ } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_FILE) { ++ ret = pca9641_do_file_reset(muxc); ++ } else { ++ ret = -1; ++ PCA_DEBUG_ERR("Unsupport reset type:0x%x.\n", ++ data->pca9641_cfg_info.pca9641_reset_type); ++ } ++ ++ if (ret < 0) { ++ PCA_DEBUG_ERR("pca9641_reset_ctrl failed, reset type:%u, ret:%d.\n", ++ data->pca9641_cfg_info.pca9641_reset_type, ret); ++ } else { ++ usleep_range(PCA9641_RESET_DELAY, PCA9641_RESET_DELAY + 1); ++ } ++ return ret; ++} ++ ++/* ++ * Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer() ++ * as they will try to lock the adapter a second time. ++ */ ++static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val) ++{ ++ struct i2c_adapter *adap = client->adapter; ++ int ret; ++ ++ if (adap->algo->master_xfer) { ++ struct i2c_msg msg; ++ char buf[2]; ++ ++ msg.addr = client->addr; ++ msg.flags = 0; ++ msg.len = 2; ++ buf[0] = command; ++ buf[1] = val; ++ msg.buf = buf; ++ ret = __i2c_transfer(adap, &msg, 1); ++ } else { ++ union i2c_smbus_data data; ++ ++ data.byte = val; ++ ret = adap->algo->smbus_xfer(adap, client->addr, ++ client->flags, ++ I2C_SMBUS_WRITE, ++ command, ++ I2C_SMBUS_BYTE_DATA, &data); ++ } ++ ++ return ret; ++} ++ ++/* ++ * Read from chip register. Don't use i2c_transfer()/i2c_smbus_xfer() ++ * as they will try to lock adapter a second time. ++ */ ++static int pca9541_reg_read(struct i2c_client *client, u8 command) ++{ ++ struct i2c_adapter *adap = client->adapter; ++ int ret; ++ u8 val; ++ ++ if (adap->algo->master_xfer) { ++ struct i2c_msg msg[2] = { ++ { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 1, ++ .buf = &command ++ }, ++ { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = &val ++ } ++ }; ++ ret = __i2c_transfer(adap, msg, 2); ++ if (ret == 2) ++ ret = val; ++ else if (ret >= 0) ++ ret = -EIO; ++ } else { ++ union i2c_smbus_data data; ++ ++ ret = adap->algo->smbus_xfer(adap, client->addr, ++ client->flags, ++ I2C_SMBUS_READ, ++ command, ++ I2C_SMBUS_BYTE_DATA, &data); ++ if (!ret) ++ ret = data.byte; ++ } ++ return ret; ++} ++ ++/* ++ * Arbitration management functions ++ */ ++ ++/* Release bus. Also reset NTESTON and BUSINIT if it was set. */ ++static void pca9541_release_bus(struct i2c_client *client) ++{ ++ int reg; ++ ++ reg = pca9541_reg_read(client, PCA9541_CONTROL); ++ if (reg >= 0 && !busoff(reg) && mybus(reg)) ++ pca9541_reg_write(client, PCA9541_CONTROL, ++ (reg & PCA9541_CTL_NBUSON) >> 1); ++} ++ ++/* ++ * Arbitration is defined as a two-step process. A bus master can only activate ++ * the slave bus if it owns it; otherwise it has to request ownership first. ++ * This multi-step process ensures that access contention is resolved ++ * gracefully. ++ * ++ * Bus Ownership Other master Action ++ * state requested access ++ * ---------------------------------------------------- ++ * off - yes wait for arbitration timeout or ++ * for other master to drop request ++ * off no no take ownership ++ * off yes no turn on bus ++ * on yes - done ++ * on no - wait for arbitration timeout or ++ * for other master to release bus ++ * ++ * The main contention point occurs if the slave bus is off and both masters ++ * request ownership at the same time. In this case, one master will turn on ++ * the slave bus, believing that it owns it. The other master will request ++ * bus ownership. Result is that the bus is turned on, and master which did ++ * _not_ own the slave bus before ends up owning it. ++ */ ++ ++/* Control commands per PCA9541 datasheet */ ++static const u8 pca9541_control[16] = { ++ 4, 0, 1, 5, 4, 4, 5, 5, 0, 0, 1, 1, 0, 4, 5, 1 ++}; ++ ++/* ++ * Channel arbitration ++ * ++ * Return values: ++ * <0: error ++ * 0 : bus not acquired ++ * 1 : bus acquired ++ */ ++static int pca9541_arbitrate(struct i2c_client *client) ++{ ++ struct i2c_mux_core *muxc = i2c_get_clientdata(client); ++ struct pca9541 *data = i2c_mux_priv(muxc); ++ int reg; ++ ++ reg = pca9541_reg_read(client, PCA9541_CONTROL); ++ if (reg < 0) ++ return reg; ++ ++ if (busoff(reg)) { ++ int istat; ++ /* ++ * Bus is off. Request ownership or turn it on unless ++ * other master requested ownership. ++ */ ++ istat = pca9541_reg_read(client, PCA9541_ISTAT); ++ if (!(istat & PCA9541_ISTAT_NMYTEST) ++ || time_is_before_eq_jiffies(data->arb_timeout)) { ++ /* ++ * Other master did not request ownership, ++ * or arbitration timeout expired. Take the bus. ++ */ ++ pca9541_reg_write(client, ++ PCA9541_CONTROL, ++ pca9541_control[reg & 0x0f] ++ | PCA9541_CTL_NTESTON); ++ data->select_timeout = SELECT_DELAY_SHORT; ++ } else { ++ /* ++ * Other master requested ownership. ++ * Set extra long timeout to give it time to acquire it. ++ */ ++ data->select_timeout = SELECT_DELAY_LONG * 2; ++ } ++ } else if (mybus(reg)) { ++ /* ++ * Bus is on, and we own it. We are done with acquisition. ++ * Reset NTESTON and BUSINIT, then return success. ++ */ ++ if (reg & (PCA9541_CTL_NTESTON | PCA9541_CTL_BUSINIT)) ++ pca9541_reg_write(client, ++ PCA9541_CONTROL, ++ reg & ~(PCA9541_CTL_NTESTON ++ | PCA9541_CTL_BUSINIT)); ++ return 1; ++ } else { ++ /* ++ * Other master owns the bus. ++ * If arbitration timeout has expired, force ownership. ++ * Otherwise request it. ++ */ ++ data->select_timeout = SELECT_DELAY_LONG; ++ if (time_is_before_eq_jiffies(data->arb_timeout)) { ++ /* Time is up, take the bus and reset it. */ ++ pca9541_reg_write(client, ++ PCA9541_CONTROL, ++ pca9541_control[reg & 0x0f] ++ | PCA9541_CTL_BUSINIT ++ | PCA9541_CTL_NTESTON); ++ } else { ++ /* Request bus ownership if needed */ ++ if (!(reg & PCA9541_CTL_NTESTON)) ++ pca9541_reg_write(client, ++ PCA9541_CONTROL, ++ reg | PCA9541_CTL_NTESTON); ++ } ++ } ++ return 0; ++} ++ ++static int pca9541_select_chan(struct i2c_mux_core *muxc, u32 chan) ++{ ++ struct pca9541 *data = i2c_mux_priv(muxc); ++ struct i2c_client *client = data->client; ++ int ret; ++ unsigned long timeout = jiffies + ARB2_TIMEOUT; ++ /* give up after this time */ ++ ++ data->arb_timeout = jiffies + ARB_TIMEOUT; ++ /* force bus ownership after this time */ ++ ++ do { ++ ret = pca9541_arbitrate(client); ++ if (ret) ++ return ret < 0 ? ret : 0; ++ ++ if (data->select_timeout == SELECT_DELAY_SHORT) ++ udelay(data->select_timeout); ++ else ++ msleep(data->select_timeout / 1000); ++ } while (time_is_after_eq_jiffies(timeout)); ++ ++ dev_warn(&client->dev, "pca9541 select channel timeout.\n"); ++ return -ETIMEDOUT; ++} ++ ++static int pca9541_release_chan(struct i2c_mux_core *muxc, u32 chan) ++{ ++ struct pca9541 *data = i2c_mux_priv(muxc); ++ struct i2c_client *client = data->client; ++ pca9541_release_bus(client); ++ return 0; ++} ++ ++/* ++* Arbitration management functions ++*/ ++static void pca9641_release_bus(struct i2c_client *client) ++{ ++ pca9541_reg_write(client, PCA9641_CONTROL, 0x80); //master 0x80 ++} ++ ++/* ++* Channel arbitration ++* ++* Return values: ++* <0: error ++* 0 : bus not acquired ++* 1 : bus acquired ++*/ ++static int pca9641_arbitrate(struct i2c_client *client) ++{ ++ struct i2c_mux_core *muxc = i2c_get_clientdata(client); ++ struct pca9541 *data = i2c_mux_priv(muxc); ++ int reg_ctl, reg_sts; ++ ++ reg_ctl = pca9541_reg_read(client, PCA9641_CONTROL); ++ if (reg_ctl < 0) { ++ PCA_DEBUG_ERR("pca9641 read control register failed, ret:%d.\n", reg_ctl); ++ return reg_ctl; ++ } ++ ++ reg_sts = pca9541_reg_read(client, PCA9641_STATUS); ++ if (reg_sts < 0) { ++ PCA_DEBUG_ERR("pca9641 read status register failed, ret:%d.\n", reg_sts); ++ return reg_sts; ++ } ++ ++ if (BUSOFF(reg_ctl, reg_sts)) { ++ /* ++ * Bus is off. Request ownership or turn it on unless ++ * other master requested ownership. ++ */ ++ reg_ctl |= PCA9641_CTL_LOCK_REQ; ++ pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); ++ reg_ctl = pca9541_reg_read(client, PCA9641_CONTROL); ++ if (reg_ctl < 0) { ++ PCA_DEBUG_ERR("Bus is off, but read control register failed, ret:%d.\n", reg_ctl); ++ return reg_ctl; ++ } ++ ++ if (lock_grant(reg_ctl)) { ++ /* ++ * Other master did not request ownership, ++ * or arbitration timeout expired. Take the bus. ++ */ ++ PCA_DEBUG("Bus is off, get pca9641 arbitration success.\n"); ++ reg_ctl |= PCA9641_CTL_BUS_CONNECT | PCA9641_CTL_LOCK_REQ; ++ pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); ++ return 1; ++ } else { ++ /* ++ * Other master requested ownership. ++ * Set extra long timeout to give it time to acquire it. ++ */ ++ PCA_DEBUG("Bus is off, but get pca9641 arbitration failed.\n"); ++ data->select_timeout = SELECT_DELAY_LONG * 2; ++ } ++ } else if (lock_grant(reg_ctl)) { ++ /* ++ * Bus is on, and we own it. We are done with acquisition. ++ */ ++ PCA_DEBUG("Bus is on, get pca9641 arbitration success.\n"); ++ reg_ctl |= PCA9641_CTL_BUS_CONNECT | PCA9641_CTL_LOCK_REQ; ++ pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); ++ return 1; ++ } else if (other_lock(reg_sts)) { ++ /* ++ * Other master owns the bus. ++ * If arbitration timeout has expired, force ownership. ++ * Otherwise request it. ++ */ ++ PCA_DEBUG("Other master owns the bus, try to request it.\n"); ++ data->select_timeout = SELECT_DELAY_LONG; ++ reg_ctl |= PCA9641_CTL_LOCK_REQ; ++ pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); ++ } ++ return 0; ++} ++ ++int pca9641_select_chan_single(struct i2c_mux_core *muxc, u32 chan) ++{ ++ struct pca9541 *data = i2c_mux_priv(muxc); ++ struct i2c_client *client = data->client; ++ int ret; ++ int result; ++ unsigned long msleep_time; ++ unsigned long timeout = jiffies + ARB2_TIMEOUT; ++ /* give up after this time */ ++ data->arb_timeout = jiffies + ARB_TIMEOUT; ++ /* force bus ownership after this time */ ++ for (result = 0 ; result < PCA9641_RETRY_TIME ; result ++) { ++ do { ++ ret = pca9641_arbitrate(client); ++ if (ret) { ++ return ret < 0 ? -EIO : 0; ++ } ++ msleep_time = data->select_timeout / 1000; ++ if (msleep_time < 1) { ++ msleep(1); ++ } else { ++ msleep(msleep_time); ++ } ++ } while (time_is_after_eq_jiffies(timeout)); ++ timeout = jiffies + ARB2_TIMEOUT; ++ } ++ dev_warn(&client->dev, "pca9641 select channel timeout.\n"); ++ return -ETIMEDOUT; ++} ++ ++static int pca9641_select_chan(struct i2c_mux_core *muxc, u32 chan) ++{ ++ int ret, rv; ++ ++ ret = pca9641_select_chan_single(muxc, chan); ++ if (ret < 0) { ++ PCA_DEBUG_ERR("pca9641 select channel failed, ret:%d, try to reset pca9641.\n", ret); ++ rv = pca9641_do_reset(muxc); ++ ++ if (rv < 0) { ++ PCA_DEBUG_ERR("pca9641 reset failed, rv:%d.\n", rv); ++ return ret; ++ } ++ ++ ret = pca9641_select_chan_single(muxc, chan); ++ if (ret < 0) { ++ PCA_DEBUG_ERR("after pca9641 reset, select channel still failed, ret:%d.\n", ret); ++ } ++ } ++ return ret; ++} ++ ++static int pca9641_release_chan(struct i2c_mux_core *muxc, u32 chan) ++{ ++ struct pca9541 *data = i2c_mux_priv(muxc); ++ struct i2c_client *client = data->client; ++ if (pca_flag.flag) { ++ pca9641_release_bus(client); ++ } ++ return 0; ++} ++ ++static int pca9641_detect_id(struct i2c_client *client) ++{ ++#if 0 ++ int reg; ++ ++ reg = pca9541_reg_read(client, PCA9641_ID); ++ if (reg == PCA9641_ID_MAGIC) ++ return 1; ++ else ++ return 0; ++#endif ++ /* only support pca9641 */ ++ return 1; ++} ++ ++static int pca9641_recordflag(struct i2c_adapter *adap) { ++ if (pca_flag.flag != -1) { ++ pr_err(" %s %d has init already!!!", __func__, __LINE__); ++ return -1 ; ++ } ++ pca_flag.nr = adap->nr; ++ PCA_DEBUG(" adap->nr:%d\n", adap->nr); ++ snprintf(pca_flag.name, sizeof(pca_flag.name),adap->name); ++ return 0; ++} ++ ++static int of_pca9641_reset_data_init(struct pca9541 *data) ++{ ++ int err; ++ struct device *dev = &data->client->dev; ++ pca9641_cfg_info_t *reset_cfg; ++ ++ reset_cfg = &data->pca9641_cfg_info; ++ if (dev == NULL || dev->of_node == NULL) { ++ PCA_DEBUG("dev or dev->of_node is NUll, no reset.\n"); ++ reset_cfg->pca9641_reset_type = PCA9641_RESET_NONE; ++ return 0; ++ } ++ ++ if (of_property_read_u32(dev->of_node, "pca9641_reset_type", &reset_cfg->pca9641_reset_type)) { ++ ++ PCA_DEBUG("pca9641_reset_type not found, no reset.\n"); ++ reset_cfg->pca9641_reset_type = PCA9641_RESET_NONE; ++ return 0; ++ } ++ err = of_property_read_u32(dev->of_node, "rst_delay_b", &reset_cfg->rst_delay_b); ++ err |= of_property_read_u32(dev->of_node, "rst_delay", &reset_cfg->rst_delay); ++ err |= of_property_read_u32(dev->of_node, "rst_delay_a", &reset_cfg->rst_delay_a); ++ ++ if (err) { ++ goto dts_config_err; ++ } ++ PCA_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", ++ reset_cfg->pca9641_reset_type, reset_cfg->rst_delay_b, ++ reset_cfg->rst_delay, reset_cfg->rst_delay_a); ++ ++ if (reset_cfg->pca9641_reset_type == PCA9641_RESET_I2C) { ++ ++ PCA_DEBUG("reset by i2c.\n"); ++ err = of_property_read_u32(dev->of_node, "i2c_bus", &reset_cfg->attr.i2c_attr.i2c_bus); ++ err |=of_property_read_u32(dev->of_node, "i2c_addr", &reset_cfg->attr.i2c_attr.i2c_addr); ++ err |=of_property_read_u32(dev->of_node, "reg_offset", &reset_cfg->attr.i2c_attr.reg_offset); ++ err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.i2c_attr.mask); ++ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.i2c_attr.reset_on); ++ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.i2c_attr.reset_off); ++ if (err) { ++ goto dts_config_err; ++ } ++ PCA_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", ++ reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, ++ reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, ++ reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); ++ } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_GPIO) { ++ ++ PCA_DEBUG("reset by gpio.\n"); ++ err = of_property_read_u32(dev->of_node, "gpio", &reset_cfg->attr.gpio_attr.gpio); ++ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.gpio_attr.reset_on); ++ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.gpio_attr.reset_off); ++ if (err) { ++ goto dts_config_err; ++ } ++ PCA_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", ++ reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, ++ reset_cfg->attr.gpio_attr.reset_off); ++ reset_cfg->attr.gpio_attr.gpio_init = 0; ++ } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_IO) { ++ ++ PCA_DEBUG("reset by io.\n"); ++ err = of_property_read_u32(dev->of_node, "io_addr", &reset_cfg->attr.io_attr.io_addr); ++ err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.io_attr.mask); ++ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.io_attr.reset_on); ++ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.io_attr.reset_off); ++ if (err) { ++ goto dts_config_err; ++ } ++ PCA_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", ++ reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, ++ reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); ++ } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_FILE) { ++ ++ PCA_DEBUG("reset by file.\n"); ++ err = of_property_read_string(dev->of_node, "dev_name", &reset_cfg->attr.file_attr.dev_name); ++ err |=of_property_read_u32(dev->of_node, "offset", &reset_cfg->attr.file_attr.offset); ++ err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.file_attr.mask); ++ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.file_attr.reset_on); ++ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.file_attr.reset_off); ++ if (err) { ++ goto dts_config_err; ++ } ++ PCA_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", ++ reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, ++ reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off); ++ } else { ++ PCA_DEBUG_ERR("Unsupport reset type:%d.\n", reset_cfg->pca9641_reset_type); ++ goto dts_config_err; ++ } ++ return 0; ++dts_config_err: ++ PCA_DEBUG_ERR("dts config error, ret:%d.\n", err); ++ return -EINVAL; ++} ++ ++static int pca9641_reset_data_init(struct pca9541 *data) ++{ ++ pca9641_cfg_info_t *reset_cfg; ++ i2c_mux_pca9641_device_t *i2c_mux_pca9641_device; ++ ++ if (data->client->dev.platform_data == NULL) { ++ PCA_DEBUG("pca9641 has no reset platform data config.\n"); ++ return 0; ++ } ++ reset_cfg = &data->pca9641_cfg_info; ++ i2c_mux_pca9641_device = data->client->dev.platform_data; ++ reset_cfg->pca9641_reset_type = i2c_mux_pca9641_device->pca9641_reset_type; ++ if (reset_cfg->pca9641_reset_type == PCA9641_RESET_NONE) { ++ PCA_DEBUG("pca9641 has no reset function.\n"); ++ return 0; ++ } ++ ++ reset_cfg->rst_delay_b = i2c_mux_pca9641_device->rst_delay_b; ++ reset_cfg->rst_delay = i2c_mux_pca9641_device->rst_delay; ++ reset_cfg->rst_delay_a = i2c_mux_pca9641_device->rst_delay_a; ++ PCA_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", ++ reset_cfg->pca9641_reset_type, reset_cfg->rst_delay_b, ++ reset_cfg->rst_delay, reset_cfg->rst_delay_a); ++ ++ if (reset_cfg->pca9641_reset_type == PCA9641_RESET_I2C) { ++ ++ PCA_DEBUG("reset by i2c.\n"); ++ reset_cfg->attr.i2c_attr.i2c_bus = i2c_mux_pca9641_device->attr.i2c_attr.i2c_bus; ++ reset_cfg->attr.i2c_attr.i2c_addr = i2c_mux_pca9641_device->attr.i2c_attr.i2c_addr; ++ reset_cfg->attr.i2c_attr.reg_offset = i2c_mux_pca9641_device->attr.i2c_attr.reg_offset; ++ reset_cfg->attr.i2c_attr.mask = i2c_mux_pca9641_device->attr.i2c_attr.mask; ++ reset_cfg->attr.i2c_attr.reset_on = i2c_mux_pca9641_device->attr.i2c_attr.reset_on; ++ reset_cfg->attr.i2c_attr.reset_off = i2c_mux_pca9641_device->attr.i2c_attr.reset_off; ++ PCA_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", ++ reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, ++ reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, ++ reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); ++ } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_GPIO) { ++ ++ PCA_DEBUG("reset by gpio.\n"); ++ reset_cfg->attr.gpio_attr.gpio = i2c_mux_pca9641_device->attr.gpio_attr.gpio; ++ reset_cfg->attr.gpio_attr.reset_on = i2c_mux_pca9641_device->attr.gpio_attr.reset_on; ++ reset_cfg->attr.gpio_attr.reset_off = i2c_mux_pca9641_device->attr.gpio_attr.reset_off; ++ PCA_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", ++ reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, ++ reset_cfg->attr.gpio_attr.reset_off); ++ reset_cfg->attr.gpio_attr.gpio_init = 0; ++ } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_IO) { ++ ++ PCA_DEBUG("reset by io.\n"); ++ reset_cfg->attr.io_attr.io_addr = i2c_mux_pca9641_device->attr.io_attr.io_addr; ++ reset_cfg->attr.io_attr.mask = i2c_mux_pca9641_device->attr.io_attr.mask; ++ reset_cfg->attr.io_attr.reset_on = i2c_mux_pca9641_device->attr.io_attr.reset_on; ++ reset_cfg->attr.io_attr.reset_off = i2c_mux_pca9641_device->attr.io_attr.reset_off; ++ PCA_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", ++ reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, ++ reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); ++ } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_FILE) { ++ ++ PCA_DEBUG("reset by file.\n"); ++ reset_cfg->attr.file_attr.dev_name = i2c_mux_pca9641_device->attr.file_attr.dev_name; ++ reset_cfg->attr.file_attr.offset = i2c_mux_pca9641_device->attr.file_attr.offset; ++ reset_cfg->attr.file_attr.mask = i2c_mux_pca9641_device->attr.file_attr.mask; ++ reset_cfg->attr.file_attr.reset_on = i2c_mux_pca9641_device->attr.file_attr.reset_on; ++ reset_cfg->attr.file_attr.reset_off = i2c_mux_pca9641_device->attr.file_attr.reset_off; ++ PCA_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", ++ reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, ++ reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off); ++ } else { ++ PCA_DEBUG_ERR("Unsupport reset type:%d.\n", reset_cfg->pca9641_reset_type); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/* ++ * I2C init/probing/exit functions ++ */ ++static int pca9541_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ struct i2c_adapter *adap = client->adapter; ++ struct i2c_mux_core *muxc; ++ struct pca9541 *data; ++ int force; ++ int ret = -ENODEV; ++ int detect_id; ++ i2c_mux_pca9641_device_t *i2c_mux_pca9641_device; ++ ++ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA)) ++ return -ENODEV; ++ ++ detect_id = pca9641_detect_id(client); ++ ++ /* ++ * I2C accesses are unprotected here. ++ * We have to lock the adapter before releasing the bus. ++ */ ++ if (detect_id == 0) { ++ i2c_lock_bus(adap, I2C_LOCK_ROOT_ADAPTER); ++ pca9541_release_bus(client); ++ i2c_unlock_bus(adap, I2C_LOCK_ROOT_ADAPTER); ++ } else { ++ i2c_lock_bus(adap, I2C_LOCK_ROOT_ADAPTER); ++ pca9641_release_bus(client); ++ i2c_unlock_bus(adap, I2C_LOCK_ROOT_ADAPTER); ++ } ++ ++ if (detect_id == 0) { /* pca9541 */ ++ muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), ++ I2C_MUX_ARBITRATOR, ++ pca9541_select_chan, pca9541_release_chan); ++ if (!muxc) ++ return -ENOMEM; ++ ++ data = i2c_mux_priv(muxc); ++ data->client = client; ++ ++ i2c_set_clientdata(client, muxc); ++ /* Create mux adapter */ ++ if (of_property_read_u32(client->dev.of_node, "pca9641_nr", &data->pca9641_nr)) { ++ ++ force = 0; ++ PCA_DEBUG("pca9641_nr not found, use dynamic adap number.\n"); ++ } else { ++ force = data->pca9641_nr; ++ PCA_DEBUG("pca9641_nr: %d.\n", force); ++ } ++ ++ ret = i2c_mux_add_adapter(muxc, force, 0, 0); ++ if (ret) ++ return ret; ++ } else { ++ muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), I2C_MUX_ARBITRATOR, ++ pca9641_select_chan, pca9641_release_chan); ++ if (!muxc) { ++ dev_err(&client->dev, "i2c_mux_alloc failed, out of memory.\n"); ++ return -ENOMEM; ++ } ++ ++ data = i2c_mux_priv(muxc); ++ data->client = client; ++ ++ i2c_set_clientdata(client, muxc); ++ ++ if (client->dev.of_node) { ++ ret= of_pca9641_reset_data_init(data); ++ } else { ++ ret= pca9641_reset_data_init(data); ++ } ++ if (ret < 0) { ++ dev_err(&client->dev, "pca9641 reset config err, ret:%d.\n", ret); ++ return ret; ++ } ++ ++ if (client->dev.of_node == NULL) { ++ if (client->dev.platform_data == NULL) { ++ force = 0; ++ PCA_DEBUG("platform data is NULL, use dynamic adap number.\n"); ++ } else { ++ i2c_mux_pca9641_device = client->dev.platform_data; ++ data->pca9641_nr = i2c_mux_pca9641_device->pca9641_nr; ++ if (data->pca9641_nr == 0) { ++ force = 0; ++ PCA_DEBUG("pca9641_nr = 0, use dynamic adap number.\n"); ++ } else { ++ force = data->pca9641_nr; ++ PCA_DEBUG("pca9641_nr: %d.\n", force); ++ } ++ } ++ } else { ++ /* Create mux adapter */ ++ if (of_property_read_u32(client->dev.of_node, "pca9641_nr", &data->pca9641_nr)) { ++ ++ force = 0; ++ PCA_DEBUG("pca9641_nr not found, use dynamic adap number.\n"); ++ } else { ++ force = data->pca9641_nr; ++ PCA_DEBUG("pca9641_nr: %d.\n", force); ++ } ++ } ++ ++ ret = i2c_mux_add_adapter(muxc, force, 0, 0); ++ if (ret) { ++ dev_err(&client->dev, "Failed to register master selector.\n"); ++ return ret; ++ } ++ } ++ pca9641_recordflag(muxc->adapter[0]); ++ ++ dev_info(&client->dev, "registered master selector for I2C %s\n", client->name); ++ ++ return 0; ++} ++ ++static int pca9541_remove(struct i2c_client *client) ++{ ++ struct i2c_mux_core *muxc = i2c_get_clientdata(client); ++ ++ i2c_mux_del_adapters(muxc); ++ return 0; ++} ++ ++static struct i2c_driver pca9641_driver = { ++ .driver = { ++ .name = "wb_pca9641", ++ .of_match_table = of_match_ptr(pca9541_of_match), ++ }, ++ .probe = pca9541_probe, ++ .remove = pca9541_remove, ++ .id_table = pca9541_id, ++}; ++ ++module_i2c_driver(pca9641_driver); ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("PCA9541 I2C master selector driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.h +new file mode 100644 +index 000000000..b87f75855 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.h +@@ -0,0 +1,64 @@ ++#ifndef __WB_I2C_MUX_PCA9641_H__ ++#define __WB_I2C_MUX_PCA9641_H__ ++ ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++ ++typedef enum pca9641_reset_type_s { ++ PCA9641_RESET_NONE = 0, ++ PCA9641_RESET_I2C = 1, ++ PCA9641_RESET_GPIO = 2, ++ PCA9641_RESET_IO = 3, ++ PCA9641_RESET_FILE = 4, ++} pca9641_reset_type_t; ++ ++typedef struct i2c_attr_s { ++ uint32_t i2c_bus; ++ uint32_t i2c_addr; ++ uint32_t reg_offset; ++ uint32_t mask; ++ uint32_t reset_on; ++ uint32_t reset_off; ++} i2c_attr_t; ++ ++typedef struct io_attr_s { ++ uint32_t io_addr; ++ uint32_t mask; ++ uint32_t reset_on; ++ uint32_t reset_off; ++} io_attr_t; ++ ++typedef struct file_attr_s { ++ const char *dev_name; ++ uint32_t offset; ++ uint32_t mask; ++ uint32_t reset_on; ++ uint32_t reset_off; ++} file_attr_t; ++ ++typedef struct gpio_attr_s { ++ int gpio_init; ++ uint32_t gpio; ++ uint32_t reset_on; ++ uint32_t reset_off; ++} gpio_attr_t; ++ ++typedef struct i2c_mux_pca9641_device_s { ++ struct i2c_client *client; ++ uint32_t i2c_bus; ++ uint32_t i2c_addr; ++ uint32_t pca9641_nr; ++ uint32_t pca9641_reset_type; ++ uint32_t rst_delay_b; /* delay time before reset(us) */ ++ uint32_t rst_delay; /* reset time(us) */ ++ uint32_t rst_delay_a; /* delay time after reset(us) */ ++ union { ++ i2c_attr_t i2c_attr; ++ gpio_attr_t gpio_attr; ++ io_attr_t io_attr; ++ file_attr_t file_attr; ++ } attr; ++} i2c_mux_pca9641_device_t; ++ ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ina3221.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ina3221.c +new file mode 100644 +index 000000000..fba2c4e3a +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ina3221.c +@@ -0,0 +1,1031 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * INA3221 Triple Current/Voltage Monitor ++ * ++ * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ ++ * Andrew F. Davis ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define INA3221_DRIVER_NAME "wb_ina3221" ++ ++#define INA3221_CONFIG 0x00 ++#define INA3221_SHUNT1 0x01 ++#define INA3221_BUS1 0x02 ++#define INA3221_SHUNT2 0x03 ++#define INA3221_BUS2 0x04 ++#define INA3221_SHUNT3 0x05 ++#define INA3221_BUS3 0x06 ++#define INA3221_CRIT1 0x07 ++#define INA3221_WARN1 0x08 ++#define INA3221_CRIT2 0x09 ++#define INA3221_WARN2 0x0a ++#define INA3221_CRIT3 0x0b ++#define INA3221_WARN3 0x0c ++#define INA3221_SHUNT_SUM 0x0d ++#define INA3221_CRIT_SUM 0x0e ++#define INA3221_MASK_ENABLE 0x0f ++ ++#define INA3221_CONFIG_MODE_MASK GENMASK(2, 0) ++#define INA3221_CONFIG_MODE_POWERDOWN 0 ++#define INA3221_CONFIG_MODE_SHUNT BIT(0) ++#define INA3221_CONFIG_MODE_BUS BIT(1) ++#define INA3221_CONFIG_MODE_CONTINUOUS BIT(2) ++#define INA3221_CONFIG_VSH_CT_SHIFT 3 ++#define INA3221_CONFIG_VSH_CT_MASK GENMASK(5, 3) ++#define INA3221_CONFIG_VSH_CT(x) (((x) & GENMASK(5, 3)) >> 3) ++#define INA3221_CONFIG_VBUS_CT_SHIFT 6 ++#define INA3221_CONFIG_VBUS_CT_MASK GENMASK(8, 6) ++#define INA3221_CONFIG_VBUS_CT(x) (((x) & GENMASK(8, 6)) >> 6) ++#define INA3221_CONFIG_AVG_SHIFT 9 ++#define INA3221_CONFIG_AVG_MASK GENMASK(11, 9) ++#define INA3221_CONFIG_AVG(x) (((x) & GENMASK(11, 9)) >> 9) ++#define INA3221_CONFIG_CHs_EN_MASK GENMASK(14, 12) ++#define INA3221_CONFIG_CHx_EN(x) BIT(14 - (x)) ++ ++#define INA3221_MASK_ENABLE_SCC_MASK GENMASK(14, 12) ++ ++#define INA3221_CONFIG_DEFAULT 0x7127 ++#define INA3221_RSHUNT_DEFAULT 10000 ++ ++enum ina3221_fields { ++ /* Configuration */ ++ F_RST, ++ ++ /* Status Flags */ ++ F_CVRF, ++ ++ /* Warning Flags */ ++ F_WF3, F_WF2, F_WF1, ++ ++ /* Alert Flags: SF is the summation-alert flag */ ++ F_SF, F_CF3, F_CF2, F_CF1, ++ ++ /* sentinel */ ++ F_MAX_FIELDS ++}; ++ ++static const struct reg_field ina3221_reg_fields[] = { ++ [F_RST] = REG_FIELD(INA3221_CONFIG, 15, 15), ++ ++ [F_CVRF] = REG_FIELD(INA3221_MASK_ENABLE, 0, 0), ++ [F_WF3] = REG_FIELD(INA3221_MASK_ENABLE, 3, 3), ++ [F_WF2] = REG_FIELD(INA3221_MASK_ENABLE, 4, 4), ++ [F_WF1] = REG_FIELD(INA3221_MASK_ENABLE, 5, 5), ++ [F_SF] = REG_FIELD(INA3221_MASK_ENABLE, 6, 6), ++ [F_CF3] = REG_FIELD(INA3221_MASK_ENABLE, 7, 7), ++ [F_CF2] = REG_FIELD(INA3221_MASK_ENABLE, 8, 8), ++ [F_CF1] = REG_FIELD(INA3221_MASK_ENABLE, 9, 9), ++}; ++ ++enum ina3221_channels { ++ INA3221_CHANNEL1, ++ INA3221_CHANNEL2, ++ INA3221_CHANNEL3, ++ INA3221_NUM_CHANNELS ++}; ++ ++/** ++ * struct ina3221_input - channel input source specific information ++ * @label: label of channel input source ++ * @shunt_resistor: shunt resistor value of channel input source ++ * @disconnected: connection status of channel input source ++ */ ++struct ina3221_input { ++ const char *label; ++ int shunt_resistor; ++ bool disconnected; ++}; ++ ++/** ++ * struct ina3221_data - device specific information ++ * @pm_dev: Device pointer for pm runtime ++ * @regmap: Register map of the device ++ * @fields: Register fields of the device ++ * @inputs: Array of channel input source specific structures ++ * @lock: mutex lock to serialize sysfs attribute accesses ++ * @reg_config: Register value of INA3221_CONFIG ++ * @summation_shunt_resistor: equivalent shunt resistor value for summation ++ * @single_shot: running in single-shot operating mode ++ */ ++struct ina3221_data { ++ struct device *pm_dev; ++ struct regmap *regmap; ++ struct regmap_field *fields[F_MAX_FIELDS]; ++ struct ina3221_input inputs[INA3221_NUM_CHANNELS]; ++ struct mutex lock; ++ u32 reg_config; ++ int summation_shunt_resistor; ++ ++ bool single_shot; ++}; ++ ++static inline bool ina3221_is_enabled(struct ina3221_data *ina, int channel) ++{ ++ /* Summation channel checks shunt resistor values */ ++ if (channel > INA3221_CHANNEL3) ++ return ina->summation_shunt_resistor != 0; ++ ++ return pm_runtime_active(ina->pm_dev) && ++ (ina->reg_config & INA3221_CONFIG_CHx_EN(channel)); ++} ++ ++/** ++ * Helper function to return the resistor value for current summation. ++ * ++ * There is a condition to calculate current summation -- all the shunt ++ * resistor values should be the same, so as to simply fit the formula: ++ * current summation = shunt voltage summation / shunt resistor ++ * ++ * Returns the equivalent shunt resistor value on success or 0 on failure ++ */ ++static inline int ina3221_summation_shunt_resistor(struct ina3221_data *ina) ++{ ++ struct ina3221_input *input = ina->inputs; ++ int i, shunt_resistor = 0; ++ ++ for (i = 0; i < INA3221_NUM_CHANNELS; i++) { ++ if (input[i].disconnected || !input[i].shunt_resistor) ++ continue; ++ if (!shunt_resistor) { ++ /* Found the reference shunt resistor value */ ++ shunt_resistor = input[i].shunt_resistor; ++ } else { ++ /* No summation if resistor values are different */ ++ if (shunt_resistor != input[i].shunt_resistor) ++ return 0; ++ } ++ } ++ ++ return shunt_resistor; ++} ++ ++/* Lookup table for Bus and Shunt conversion times in usec */ ++static const u16 ina3221_conv_time[] = { ++ 140, 204, 332, 588, 1100, 2116, 4156, 8244, ++}; ++ ++/* Lookup table for number of samples using in averaging mode */ ++static const int ina3221_avg_samples[] = { ++ 1, 4, 16, 64, 128, 256, 512, 1024, ++}; ++ ++/* Converting update_interval in msec to conversion time in usec */ ++static inline u32 ina3221_interval_ms_to_conv_time(u16 config, int interval) ++{ ++ u32 channels = hweight16(config & INA3221_CONFIG_CHs_EN_MASK); ++ u32 samples_idx = INA3221_CONFIG_AVG(config); ++ u32 samples = ina3221_avg_samples[samples_idx]; ++ ++ /* Bisect the result to Bus and Shunt conversion times */ ++ return DIV_ROUND_CLOSEST(interval * 1000 / 2, channels * samples); ++} ++ ++/* Converting CONFIG register value to update_interval in usec */ ++static inline u32 ina3221_reg_to_interval_us(u16 config) ++{ ++ u32 channels = hweight16(config & INA3221_CONFIG_CHs_EN_MASK); ++ u32 vbus_ct_idx = INA3221_CONFIG_VBUS_CT(config); ++ u32 vsh_ct_idx = INA3221_CONFIG_VSH_CT(config); ++ u32 samples_idx = INA3221_CONFIG_AVG(config); ++ u32 samples = ina3221_avg_samples[samples_idx]; ++ u32 vbus_ct = ina3221_conv_time[vbus_ct_idx]; ++ u32 vsh_ct = ina3221_conv_time[vsh_ct_idx]; ++ ++ /* Calculate total conversion time */ ++ return channels * (vbus_ct + vsh_ct) * samples; ++} ++ ++static inline int ina3221_wait_for_data(struct ina3221_data *ina) ++{ ++ u32 wait, cvrf; ++ ++ wait = ina3221_reg_to_interval_us(ina->reg_config); ++ ++ /* Polling the CVRF bit to make sure read data is ready */ ++ return regmap_field_read_poll_timeout(ina->fields[F_CVRF], ++ cvrf, cvrf, wait, wait * 2); ++} ++ ++static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, ++ int *val) ++{ ++ unsigned int regval; ++ int ret; ++ ++ ret = regmap_read(ina->regmap, reg, ®val); ++ if (ret) ++ return ret; ++ ++ /* ++ * Shunt Voltage Sum register has 14-bit value with 1-bit shift ++ * Other Shunt Voltage registers have 12 bits with 3-bit shift ++ */ ++ if (reg == INA3221_SHUNT_SUM) ++ *val = sign_extend32(regval >> 1, 14); ++ else ++ *val = sign_extend32(regval >> 3, 12); ++ ++ return 0; ++} ++ ++static const u8 ina3221_in_reg[] = { ++ INA3221_BUS1, ++ INA3221_BUS2, ++ INA3221_BUS3, ++ INA3221_SHUNT1, ++ INA3221_SHUNT2, ++ INA3221_SHUNT3, ++ INA3221_SHUNT_SUM, ++}; ++ ++static int ina3221_read_chip(struct device *dev, u32 attr, long *val) ++{ ++ struct ina3221_data *ina = dev_get_drvdata(dev); ++ int regval; ++ ++ switch (attr) { ++ case hwmon_chip_samples: ++ regval = INA3221_CONFIG_AVG(ina->reg_config); ++ *val = ina3221_avg_samples[regval]; ++ return 0; ++ case hwmon_chip_update_interval: ++ /* Return in msec */ ++ *val = ina3221_reg_to_interval_us(ina->reg_config); ++ *val = DIV_ROUND_CLOSEST(*val, 1000); ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int ina3221_read_in(struct device *dev, u32 attr, int channel, long *val) ++{ ++ const bool is_shunt = channel > INA3221_CHANNEL3; ++ struct ina3221_data *ina = dev_get_drvdata(dev); ++ u8 reg = ina3221_in_reg[channel]; ++ int regval, ret; ++ ++ /* ++ * Translate shunt channel index to sensor channel index except ++ * the 7th channel (6 since being 0-aligned) is for summation. ++ */ ++ if (channel != 6) ++ channel %= INA3221_NUM_CHANNELS; ++ ++ switch (attr) { ++ case hwmon_in_input: ++ if (!ina3221_is_enabled(ina, channel)) ++ return -ENODATA; ++ ++ /* Write CONFIG register to trigger a single-shot measurement */ ++ if (ina->single_shot) ++ regmap_write(ina->regmap, INA3221_CONFIG, ++ ina->reg_config); ++ ++ ret = ina3221_wait_for_data(ina); ++ if (ret) ++ return ret; ++ ++ ret = ina3221_read_value(ina, reg, ®val); ++ if (ret) ++ return ret; ++ ++ /* ++ * Scale of shunt voltage (uV): LSB is 40uV ++ * Scale of bus voltage (mV): LSB is 8mV ++ */ ++ *val = regval * (is_shunt ? 40 : 8); ++ return 0; ++ case hwmon_in_enable: ++ *val = ina3221_is_enabled(ina, channel); ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static const u8 ina3221_curr_reg[][INA3221_NUM_CHANNELS + 1] = { ++ [hwmon_curr_input] = { INA3221_SHUNT1, INA3221_SHUNT2, ++ INA3221_SHUNT3, INA3221_SHUNT_SUM }, ++ [hwmon_curr_max] = { INA3221_WARN1, INA3221_WARN2, INA3221_WARN3, 0 }, ++ [hwmon_curr_crit] = { INA3221_CRIT1, INA3221_CRIT2, ++ INA3221_CRIT3, INA3221_CRIT_SUM }, ++ [hwmon_curr_max_alarm] = { F_WF1, F_WF2, F_WF3, 0 }, ++ [hwmon_curr_crit_alarm] = { F_CF1, F_CF2, F_CF3, F_SF }, ++}; ++ ++static int ina3221_read_curr(struct device *dev, u32 attr, ++ int channel, long *val) ++{ ++ struct ina3221_data *ina = dev_get_drvdata(dev); ++ struct ina3221_input *input = ina->inputs; ++ u8 reg = ina3221_curr_reg[attr][channel]; ++ int resistance_uo, voltage_nv; ++ int regval, ret; ++ ++ if (channel > INA3221_CHANNEL3) ++ resistance_uo = ina->summation_shunt_resistor; ++ else ++ resistance_uo = input[channel].shunt_resistor; ++ ++ switch (attr) { ++ case hwmon_curr_input: ++ if (!ina3221_is_enabled(ina, channel)) ++ return -ENODATA; ++ ++ /* Write CONFIG register to trigger a single-shot measurement */ ++ if (ina->single_shot) ++ regmap_write(ina->regmap, INA3221_CONFIG, ++ ina->reg_config); ++ ++ ret = ina3221_wait_for_data(ina); ++ if (ret) ++ return ret; ++ ++ fallthrough; ++ case hwmon_curr_crit: ++ case hwmon_curr_max: ++ if (!resistance_uo) ++ return -ENODATA; ++ ++ ret = ina3221_read_value(ina, reg, ®val); ++ if (ret) ++ return ret; ++ ++ /* Scale of shunt voltage: LSB is 40uV (40000nV) */ ++ voltage_nv = regval * 40000; ++ /* Return current in mA */ ++ *val = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo); ++ return 0; ++ case hwmon_curr_crit_alarm: ++ case hwmon_curr_max_alarm: ++ /* No actual register read if channel is disabled */ ++ if (!ina3221_is_enabled(ina, channel)) { ++ /* Return 0 for alert flags */ ++ *val = 0; ++ return 0; ++ } ++ ret = regmap_field_read(ina->fields[reg], ®val); ++ if (ret) ++ return ret; ++ *val = regval; ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int ina3221_write_chip(struct device *dev, u32 attr, long val) ++{ ++ struct ina3221_data *ina = dev_get_drvdata(dev); ++ int ret, idx; ++ u32 tmp; ++ ++ switch (attr) { ++ case hwmon_chip_samples: ++ idx = find_closest(val, ina3221_avg_samples, ++ ARRAY_SIZE(ina3221_avg_samples)); ++ ++ tmp = (ina->reg_config & ~INA3221_CONFIG_AVG_MASK) | ++ (idx << INA3221_CONFIG_AVG_SHIFT); ++ ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp); ++ if (ret) ++ return ret; ++ ++ /* Update reg_config accordingly */ ++ ina->reg_config = tmp; ++ return 0; ++ case hwmon_chip_update_interval: ++ tmp = ina3221_interval_ms_to_conv_time(ina->reg_config, val); ++ idx = find_closest(tmp, ina3221_conv_time, ++ ARRAY_SIZE(ina3221_conv_time)); ++ ++ /* Update Bus and Shunt voltage conversion times */ ++ tmp = INA3221_CONFIG_VBUS_CT_MASK | INA3221_CONFIG_VSH_CT_MASK; ++ tmp = (ina->reg_config & ~tmp) | ++ (idx << INA3221_CONFIG_VBUS_CT_SHIFT) | ++ (idx << INA3221_CONFIG_VSH_CT_SHIFT); ++ ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp); ++ if (ret) ++ return ret; ++ ++ /* Update reg_config accordingly */ ++ ina->reg_config = tmp; ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int ina3221_write_curr(struct device *dev, u32 attr, ++ int channel, long val) ++{ ++ struct ina3221_data *ina = dev_get_drvdata(dev); ++ struct ina3221_input *input = ina->inputs; ++ u8 reg = ina3221_curr_reg[attr][channel]; ++ int resistance_uo, current_ma, voltage_uv; ++ int regval; ++ ++ if (channel > INA3221_CHANNEL3) ++ resistance_uo = ina->summation_shunt_resistor; ++ else ++ resistance_uo = input[channel].shunt_resistor; ++ ++ if (!resistance_uo) ++ return -EOPNOTSUPP; ++ ++ /* clamp current */ ++ current_ma = clamp_val(val, ++ INT_MIN / resistance_uo, ++ INT_MAX / resistance_uo); ++ ++ voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000); ++ ++ /* clamp voltage */ ++ voltage_uv = clamp_val(voltage_uv, -163800, 163800); ++ ++ /* ++ * Formula to convert voltage_uv to register value: ++ * regval = (voltage_uv / scale) << shift ++ * Note: ++ * The scale is 40uV for all shunt voltage registers ++ * Shunt Voltage Sum register left-shifts 1 bit ++ * All other Shunt Voltage registers shift 3 bits ++ * Results: ++ * SHUNT_SUM: (1 / 40uV) << 1 = 1 / 20uV ++ * SHUNT[1-3]: (1 / 40uV) << 3 = 1 / 5uV ++ */ ++ if (reg == INA3221_SHUNT_SUM) ++ regval = DIV_ROUND_CLOSEST(voltage_uv, 20) & 0xfffe; ++ else ++ regval = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8; ++ ++ return regmap_write(ina->regmap, reg, regval); ++} ++ ++static int ina3221_write_enable(struct device *dev, int channel, bool enable) ++{ ++ struct ina3221_data *ina = dev_get_drvdata(dev); ++ u16 config, mask = INA3221_CONFIG_CHx_EN(channel); ++ u16 config_old = ina->reg_config & mask; ++ u32 tmp; ++ int ret; ++ ++ config = enable ? mask : 0; ++ ++ /* Bypass if enable status is not being changed */ ++ if (config_old == config) ++ return 0; ++ ++ /* For enabling routine, increase refcount and resume() at first */ ++ if (enable) { ++ ret = pm_runtime_resume_and_get(ina->pm_dev); ++ if (ret < 0) { ++ dev_err(dev, "Failed to get PM runtime\n"); ++ return ret; ++ } ++ } ++ ++ /* Enable or disable the channel */ ++ tmp = (ina->reg_config & ~mask) | (config & mask); ++ ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp); ++ if (ret) ++ goto fail; ++ ++ /* Cache the latest config register value */ ++ ina->reg_config = tmp; ++ ++ /* For disabling routine, decrease refcount or suspend() at last */ ++ if (!enable) ++ pm_runtime_put_sync(ina->pm_dev); ++ ++ return 0; ++ ++fail: ++ if (enable) { ++ dev_err(dev, "Failed to enable channel %d: error %d\n", ++ channel, ret); ++ pm_runtime_put_sync(ina->pm_dev); ++ } ++ ++ return ret; ++} ++ ++static int ina3221_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ struct ina3221_data *ina = dev_get_drvdata(dev); ++ int ret; ++ ++ mutex_lock(&ina->lock); ++ ++ switch (type) { ++ case hwmon_chip: ++ ret = ina3221_read_chip(dev, attr, val); ++ break; ++ case hwmon_in: ++ /* 0-align channel ID */ ++ ret = ina3221_read_in(dev, attr, channel - 1, val); ++ break; ++ case hwmon_curr: ++ ret = ina3221_read_curr(dev, attr, channel, val); ++ break; ++ default: ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ mutex_unlock(&ina->lock); ++ ++ return ret; ++} ++ ++static int ina3221_write(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long val) ++{ ++ struct ina3221_data *ina = dev_get_drvdata(dev); ++ int ret; ++ ++ mutex_lock(&ina->lock); ++ ++ switch (type) { ++ case hwmon_chip: ++ ret = ina3221_write_chip(dev, attr, val); ++ break; ++ case hwmon_in: ++ /* 0-align channel ID */ ++ ret = ina3221_write_enable(dev, channel - 1, val); ++ break; ++ case hwmon_curr: ++ ret = ina3221_write_curr(dev, attr, channel, val); ++ break; ++ default: ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ mutex_unlock(&ina->lock); ++ ++ return ret; ++} ++ ++static int ina3221_read_string(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, const char **str) ++{ ++ struct ina3221_data *ina = dev_get_drvdata(dev); ++ int index = channel - 1; ++ ++ if (channel == 7) ++ *str = "sum of shunt voltages"; ++ else ++ *str = ina->inputs[index].label; ++ ++ return 0; ++} ++ ++static umode_t ina3221_is_visible(const void *drvdata, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ const struct ina3221_data *ina = drvdata; ++ const struct ina3221_input *input = NULL; ++ ++ switch (type) { ++ case hwmon_chip: ++ switch (attr) { ++ case hwmon_chip_samples: ++ case hwmon_chip_update_interval: ++ return 0644; ++ default: ++ return 0; ++ } ++ case hwmon_in: ++ /* Ignore in0_ */ ++ if (channel == 0) ++ return 0; ++ ++ switch (attr) { ++ case hwmon_in_label: ++ if (channel - 1 <= INA3221_CHANNEL3) ++ input = &ina->inputs[channel - 1]; ++ else if (channel == 7) ++ return 0444; ++ /* Hide label node if label is not provided */ ++ return (input && input->label) ? 0444 : 0; ++ case hwmon_in_input: ++ return 0444; ++ case hwmon_in_enable: ++ return 0644; ++ default: ++ return 0; ++ } ++ case hwmon_curr: ++ switch (attr) { ++ case hwmon_curr_input: ++ case hwmon_curr_crit_alarm: ++ case hwmon_curr_max_alarm: ++ return 0444; ++ case hwmon_curr_crit: ++ case hwmon_curr_max: ++ return 0644; ++ default: ++ return 0; ++ } ++ default: ++ return 0; ++ } ++} ++ ++#define INA3221_HWMON_CURR_CONFIG (HWMON_C_INPUT | \ ++ HWMON_C_CRIT | HWMON_C_CRIT_ALARM | \ ++ HWMON_C_MAX | HWMON_C_MAX_ALARM) ++ ++static const struct hwmon_channel_info *ina3221_info[] = { ++ HWMON_CHANNEL_INFO(chip, ++ HWMON_C_SAMPLES, ++ HWMON_C_UPDATE_INTERVAL), ++ HWMON_CHANNEL_INFO(in, ++ /* 0: dummy, skipped in is_visible */ ++ HWMON_I_INPUT, ++ /* 1-3: input voltage Channels */ ++ HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, ++ /* 4-6: shunt voltage Channels */ ++ HWMON_I_INPUT, ++ HWMON_I_INPUT, ++ HWMON_I_INPUT, ++ /* 7: summation of shunt voltage channels */ ++ HWMON_I_INPUT | HWMON_I_LABEL), ++ HWMON_CHANNEL_INFO(curr, ++ /* 1-3: current channels*/ ++ INA3221_HWMON_CURR_CONFIG, ++ INA3221_HWMON_CURR_CONFIG, ++ INA3221_HWMON_CURR_CONFIG, ++ /* 4: summation of current channels */ ++ HWMON_C_INPUT | HWMON_C_CRIT | HWMON_C_CRIT_ALARM), ++ NULL ++}; ++ ++static const struct hwmon_ops ina3221_hwmon_ops = { ++ .is_visible = ina3221_is_visible, ++ .read_string = ina3221_read_string, ++ .read = ina3221_read, ++ .write = ina3221_write, ++}; ++ ++static const struct hwmon_chip_info ina3221_chip_info = { ++ .ops = &ina3221_hwmon_ops, ++ .info = ina3221_info, ++}; ++ ++/* Extra attribute groups */ ++static ssize_t ina3221_shunt_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); ++ struct ina3221_data *ina = dev_get_drvdata(dev); ++ unsigned int channel = sd_attr->index; ++ struct ina3221_input *input = &ina->inputs[channel]; ++ ++ return snprintf(buf, PAGE_SIZE, "%d\n", input->shunt_resistor); ++} ++ ++static ssize_t ina3221_shunt_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); ++ struct ina3221_data *ina = dev_get_drvdata(dev); ++ unsigned int channel = sd_attr->index; ++ struct ina3221_input *input = &ina->inputs[channel]; ++ int val; ++ int ret; ++ ++ ret = kstrtoint(buf, 0, &val); ++ if (ret) ++ return ret; ++ ++ val = clamp_val(val, 1, INT_MAX); ++ ++ input->shunt_resistor = val; ++ ++ /* Update summation_shunt_resistor for summation channel */ ++ ina->summation_shunt_resistor = ina3221_summation_shunt_resistor(ina); ++ ++ return count; ++} ++ ++/* shunt resistance */ ++static SENSOR_DEVICE_ATTR_RW(shunt1_resistor, ina3221_shunt, INA3221_CHANNEL1); ++static SENSOR_DEVICE_ATTR_RW(shunt2_resistor, ina3221_shunt, INA3221_CHANNEL2); ++static SENSOR_DEVICE_ATTR_RW(shunt3_resistor, ina3221_shunt, INA3221_CHANNEL3); ++ ++static struct attribute *ina3221_attrs[] = { ++ &sensor_dev_attr_shunt1_resistor.dev_attr.attr, ++ &sensor_dev_attr_shunt2_resistor.dev_attr.attr, ++ &sensor_dev_attr_shunt3_resistor.dev_attr.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(ina3221); ++ ++static const struct regmap_range ina3221_yes_ranges[] = { ++ regmap_reg_range(INA3221_CONFIG, INA3221_BUS3), ++ regmap_reg_range(INA3221_SHUNT_SUM, INA3221_SHUNT_SUM), ++ regmap_reg_range(INA3221_MASK_ENABLE, INA3221_MASK_ENABLE), ++}; ++ ++static const struct regmap_access_table ina3221_volatile_table = { ++ .yes_ranges = ina3221_yes_ranges, ++ .n_yes_ranges = ARRAY_SIZE(ina3221_yes_ranges), ++}; ++ ++static const struct regmap_config ina3221_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 16, ++ ++ .cache_type = REGCACHE_RBTREE, ++ .volatile_table = &ina3221_volatile_table, ++}; ++ ++static int ina3221_probe_child_from_dt(struct device *dev, ++ struct device_node *child, ++ struct ina3221_data *ina) ++{ ++ struct ina3221_input *input; ++ u32 val; ++ int ret; ++ ++ ret = of_property_read_u32(child, "reg", &val); ++ if (ret) { ++ dev_err(dev, "missing reg property of %pOFn\n", child); ++ return ret; ++ } else if (val > INA3221_CHANNEL3) { ++ dev_err(dev, "invalid reg %d of %pOFn\n", val, child); ++ return ret; ++ } ++ ++ input = &ina->inputs[val]; ++ ++ /* Log the disconnected channel input */ ++ if (!of_device_is_available(child)) { ++ input->disconnected = true; ++ return 0; ++ } ++ ++ /* Save the connected input label if available */ ++ of_property_read_string(child, "label", &input->label); ++ ++ /* Overwrite default shunt resistor value optionally */ ++ if (!of_property_read_u32(child, "shunt-resistor-micro-ohms", &val)) { ++ if (val < 1 || val > INT_MAX) { ++ dev_err(dev, "invalid shunt resistor value %u of %pOFn\n", ++ val, child); ++ return -EINVAL; ++ } ++ input->shunt_resistor = val; ++ } ++ ++ return 0; ++} ++ ++static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina) ++{ ++ const struct device_node *np = dev->of_node; ++ struct device_node *child; ++ int ret; ++ ++ /* Compatible with non-DT platforms */ ++ if (!np) ++ return 0; ++ ++ ina->single_shot = of_property_read_bool(np, "ti,single-shot"); ++ ++ for_each_child_of_node(np, child) { ++ ret = ina3221_probe_child_from_dt(dev, child, ina); ++ if (ret) { ++ of_node_put(child); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int ina3221_probe(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct ina3221_data *ina; ++ struct device *hwmon_dev; ++ int i, ret; ++ ++ ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL); ++ if (!ina) ++ return -ENOMEM; ++ ++ ina->regmap = devm_regmap_init_i2c(client, &ina3221_regmap_config); ++ if (IS_ERR(ina->regmap)) { ++ dev_err(dev, "Unable to allocate register map\n"); ++ return PTR_ERR(ina->regmap); ++ } ++ ++ for (i = 0; i < F_MAX_FIELDS; i++) { ++ ina->fields[i] = devm_regmap_field_alloc(dev, ++ ina->regmap, ++ ina3221_reg_fields[i]); ++ if (IS_ERR(ina->fields[i])) { ++ dev_err(dev, "Unable to allocate regmap fields\n"); ++ return PTR_ERR(ina->fields[i]); ++ } ++ } ++ ++ for (i = 0; i < INA3221_NUM_CHANNELS; i++) ++ ina->inputs[i].shunt_resistor = INA3221_RSHUNT_DEFAULT; ++ ++ ret = ina3221_probe_from_dt(dev, ina); ++ if (ret) { ++ dev_err(dev, "Unable to probe from device tree\n"); ++ return ret; ++ } ++ ++ /* The driver will be reset, so use reset value */ ++ ina->reg_config = INA3221_CONFIG_DEFAULT; ++ ++ /* Clear continuous bit to use single-shot mode */ ++ if (ina->single_shot) ++ ina->reg_config &= ~INA3221_CONFIG_MODE_CONTINUOUS; ++ ++ /* Disable channels if their inputs are disconnected */ ++ for (i = 0; i < INA3221_NUM_CHANNELS; i++) { ++ if (ina->inputs[i].disconnected) ++ ina->reg_config &= ~INA3221_CONFIG_CHx_EN(i); ++ } ++ ++ /* Initialize summation_shunt_resistor for summation channel control */ ++ ina->summation_shunt_resistor = ina3221_summation_shunt_resistor(ina); ++ ++ ina->pm_dev = dev; ++ mutex_init(&ina->lock); ++ dev_set_drvdata(dev, ina); ++ ++ /* Enable PM runtime -- status is suspended by default */ ++ pm_runtime_enable(ina->pm_dev); ++ ++ /* Initialize (resume) the device */ ++ for (i = 0; i < INA3221_NUM_CHANNELS; i++) { ++ if (ina->inputs[i].disconnected) ++ continue; ++ /* Match the refcount with number of enabled channels */ ++ ret = pm_runtime_get_sync(ina->pm_dev); ++ if (ret < 0) ++ goto fail; ++ } ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ina, ++ &ina3221_chip_info, ++ ina3221_groups); ++ if (IS_ERR(hwmon_dev)) { ++ dev_err(dev, "Unable to register hwmon device\n"); ++ ret = PTR_ERR(hwmon_dev); ++ goto fail; ++ } ++ ++ return 0; ++ ++fail: ++ pm_runtime_disable(ina->pm_dev); ++ pm_runtime_set_suspended(ina->pm_dev); ++ /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */ ++ for (i = 0; i < INA3221_NUM_CHANNELS; i++) ++ pm_runtime_put_noidle(ina->pm_dev); ++ mutex_destroy(&ina->lock); ++ ++ return ret; ++} ++ ++static int ina3221_remove(struct i2c_client *client) ++{ ++ struct ina3221_data *ina = dev_get_drvdata(&client->dev); ++ int i; ++ ++ pm_runtime_disable(ina->pm_dev); ++ pm_runtime_set_suspended(ina->pm_dev); ++ ++ /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */ ++ for (i = 0; i < INA3221_NUM_CHANNELS; i++) ++ pm_runtime_put_noidle(ina->pm_dev); ++ ++ mutex_destroy(&ina->lock); ++ ++ return 0; ++} ++ ++static int __maybe_unused ina3221_suspend(struct device *dev) ++{ ++ struct ina3221_data *ina = dev_get_drvdata(dev); ++ int ret; ++ ++ /* Save config register value and enable cache-only */ ++ ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); ++ if (ret) ++ return ret; ++ ++ /* Set to power-down mode for power saving */ ++ ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, ++ INA3221_CONFIG_MODE_MASK, ++ INA3221_CONFIG_MODE_POWERDOWN); ++ if (ret) ++ return ret; ++ ++ regcache_cache_only(ina->regmap, true); ++ regcache_mark_dirty(ina->regmap); ++ ++ return 0; ++} ++ ++static int __maybe_unused ina3221_resume(struct device *dev) ++{ ++ struct ina3221_data *ina = dev_get_drvdata(dev); ++ int ret; ++ ++ regcache_cache_only(ina->regmap, false); ++ ++ /* Software reset the chip */ ++ ret = regmap_field_write(ina->fields[F_RST], true); ++ if (ret) { ++ dev_err(dev, "Unable to reset device\n"); ++ return ret; ++ } ++ ++ /* Restore cached register values to hardware */ ++ ret = regcache_sync(ina->regmap); ++ if (ret) ++ return ret; ++ ++ /* Restore config register value to hardware */ ++ ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config); ++ if (ret) ++ return ret; ++ ++ /* Initialize summation channel control */ ++ if (ina->summation_shunt_resistor) { ++ /* ++ * Take all three channels into summation by default ++ * Shunt measurements of disconnected channels should ++ * be 0, so it does not matter for summation. ++ */ ++ ret = regmap_update_bits(ina->regmap, INA3221_MASK_ENABLE, ++ INA3221_MASK_ENABLE_SCC_MASK, ++ INA3221_MASK_ENABLE_SCC_MASK); ++ if (ret) { ++ dev_err(dev, "Unable to control summation channel\n"); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops ina3221_pm = { ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) ++ SET_RUNTIME_PM_OPS(ina3221_suspend, ina3221_resume, NULL) ++}; ++ ++static const struct of_device_id ina3221_of_match_table[] = { ++ { .compatible = "ti,wb_ina3221", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, ina3221_of_match_table); ++ ++static const struct i2c_device_id ina3221_ids[] = { ++ { "wb_ina3221", 0 }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(i2c, ina3221_ids); ++ ++static struct i2c_driver ina3221_i2c_driver = { ++ .probe_new = ina3221_probe, ++ .remove = ina3221_remove, ++ .driver = { ++ .name = INA3221_DRIVER_NAME, ++ .of_match_table = ina3221_of_match_table, ++ .pm = &ina3221_pm, ++ }, ++ .id_table = ina3221_ids, ++}; ++module_i2c_driver(ina3221_i2c_driver); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("Texas Instruments INA3221 HWMon Driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_isl68137.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_isl68137.c +new file mode 100644 +index 000000000..5b3b54d92 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_isl68137.c +@@ -0,0 +1,572 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Hardware monitoring driver for Renesas Digital Multiphase Voltage Regulators ++ * ++ * Copyright (c) 2017 Google Inc ++ * Copyright (c) 2020 Renesas Electronics America ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wb_pmbus.h" ++ ++#define ISL68137_VOUT_AVS (0x30) ++#define RAA_DMPVR2_READ_VMON (0xc8) ++#define WRITE_PROTECT_CLOSE (0x00) ++#define WRITE_PROTECT_OPEN (0x40) ++ ++static int g_wb_isl68137_debug = 0; ++static int g_wb_isl68137_error = 0; ++ ++module_param(g_wb_isl68137_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_isl68137_error, int, S_IRUGO | S_IWUSR); ++ ++#define WB_ISL68137_VERBOSE(fmt, args...) do { \ ++ if (g_wb_isl68137_debug) { \ ++ printk(KERN_INFO "[WB_ISL68137][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_ISL68137_ERROR(fmt, args...) do { \ ++ if (g_wb_isl68137_error) { \ ++ printk(KERN_ERR "[WB_ISL68137][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++enum chips { ++ isl68137, ++ isl68220, ++ isl68221, ++ isl68222, ++ isl68223, ++ isl68224, ++ isl68225, ++ isl68226, ++ isl68227, ++ isl68229, ++ isl68233, ++ isl68239, ++ isl69222, ++ isl69223, ++ isl69224, ++ isl69225, ++ isl69227, ++ isl69228, ++ isl69234, ++ isl69236, ++ isl69239, ++ isl69242, ++ isl69243, ++ isl69247, ++ isl69248, ++ isl69254, ++ isl69255, ++ isl69256, ++ isl69259, ++ isl69260, ++ isl69268, ++ isl69269, ++ isl69298, ++ raa228000, ++ raa228004, ++ raa228006, ++ raa228228, ++ raa229001, ++ raa229004, ++}; ++ ++enum variants { ++ raa_dmpvr1_2rail, ++ raa_dmpvr2_1rail, ++ raa_dmpvr2_2rail, ++ raa_dmpvr2_2rail_nontc, ++ raa_dmpvr2_3rail, ++ raa_dmpvr2_hv, ++}; ++ ++static const struct i2c_device_id raa_dmpvr_id[]; ++ ++static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client, ++ int page, ++ char *buf) ++{ ++ int val = wb_pmbus_read_byte_data(client, page, PMBUS_OPERATION); ++ ++ return sprintf(buf, "%d\n", ++ (val & ISL68137_VOUT_AVS) == ISL68137_VOUT_AVS ? 1 : 0); ++} ++ ++static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client, ++ int page, ++ const char *buf, size_t count) ++{ ++ int rc, op_val; ++ bool result; ++ ++ rc = kstrtobool(buf, &result); ++ if (rc) ++ return rc; ++ ++ op_val = result ? ISL68137_VOUT_AVS : 0; ++ ++ /* ++ * Writes to VOUT setpoint over AVSBus will persist after the VRM is ++ * switched to PMBus control. Switching back to AVSBus control ++ * restores this persisted setpoint rather than re-initializing to ++ * PMBus VOUT_COMMAND. Writing VOUT_COMMAND first over PMBus before ++ * enabling AVS control is the workaround. ++ */ ++ if (op_val == ISL68137_VOUT_AVS) { ++ rc = wb_pmbus_read_word_data(client, page, 0xff, ++ PMBUS_VOUT_COMMAND); ++ if (rc < 0) ++ return rc; ++ ++ rc = wb_pmbus_write_word_data(client, page, PMBUS_VOUT_COMMAND, ++ rc); ++ if (rc < 0) ++ return rc; ++ } ++ ++ rc = wb_pmbus_update_byte_data(client, page, PMBUS_OPERATION, ++ ISL68137_VOUT_AVS, op_val); ++ ++ return (rc < 0) ? rc : count; ++} ++ ++static ssize_t isl68137_avs_enable_show(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ ++ return isl68137_avs_enable_show_page(client, attr->index, buf); ++} ++ ++static ssize_t isl68137_avs_enable_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ ++ return isl68137_avs_enable_store_page(client, attr->index, buf, count); ++} ++ ++static ssize_t isl68137_avs_vout_show(struct device *dev, struct device_attribute *devattr, ++ char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ int vout_cmd, vout; ++ ++ mutex_lock(&data->update_lock); ++ vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); ++ if (vout_cmd < 0) { ++ WB_ISL68137_ERROR("%d-%04x: read page%d vout command reg: 0x%x failed, ret: %d\n", ++ client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd); ++ mutex_unlock(&data->update_lock); ++ return vout_cmd; ++ } ++ vout = vout_cmd * 1000; ++ WB_ISL68137_VERBOSE("%d-%04x: page%d, vout: %d, vout_cmd: 0x%x\n", client->adapter->nr, ++ client->addr, attr->index, vout, vout_cmd); ++ mutex_unlock(&data->update_lock); ++ return snprintf(buf, PAGE_SIZE, "%d\n", vout); ++} ++ ++static ssize_t isl68137_avs_vout_store(struct device *dev, struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ int vout, vout_max, vout_min; ++ int ret, vout_cmd, vout_cmd_set; ++ ++ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { ++ WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, ++ attr->index); ++ return -EINVAL; ++ } ++ ++ ret = kstrtoint(buf, 0, &vout); ++ if (ret) { ++ WB_ISL68137_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); ++ return -EINVAL; ++ } ++ ++ vout_max = data->vout_max[attr->index]; ++ vout_min = data->vout_min[attr->index]; ++ if ((vout > vout_max) || (vout < vout_min)) { ++ WB_ISL68137_ERROR("%d-%04x: vout value: %d, out of range [%d, %d] \n", client->adapter->nr, ++ client->addr, vout, vout_min, vout_max); ++ return -EINVAL; ++ } ++ ++ /* calc VOUT_COMMAND set value */ ++ vout_cmd_set = vout / 1000; ++ if (vout_cmd_set > 0xffff) { ++ WB_ISL68137_ERROR("%d-%04x: invalid value, vout %d, vout_cmd_set: 0x%x\n", ++ client->adapter->nr, client->addr, vout, vout_cmd_set); ++ return -EINVAL; ++ } ++ ++ mutex_lock(&data->update_lock); ++ ++ /* close write protect */ ++ ret = wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, WRITE_PROTECT_CLOSE); ++ if (ret < 0) { ++ WB_ISL68137_ERROR("%d-%04x: close page%d write protect failed, ret: %d\n", client->adapter->nr, ++ client->addr, attr->index, ret); ++ mutex_unlock(&data->update_lock); ++ return ret; ++ } ++ ++ /* set VOUT_COMMAND */ ++ ret = wb_pmbus_write_word_data(client, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set); ++ if (ret < 0) { ++ WB_ISL68137_ERROR("%d-%04x: set page%d vout cmd reg: 0x%x, value: 0x%x failed, ret: %d\n", ++ client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set, ret); ++ goto error; ++ } ++ ++ /* read back VOUT_COMMAND */ ++ vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); ++ if (vout_cmd < 0) { ++ ret = vout_cmd; ++ WB_ISL68137_ERROR("%d-%04x: read page%d vout command reg: 0x%x failed, ret: %d\n", ++ client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, ret); ++ goto error; ++ } ++ ++ /* compare vout_cmd and vout_cmd_set */ ++ if (vout_cmd != vout_cmd_set) { ++ ret = -EIO; ++ WB_ISL68137_ERROR("%d-%04x: vout cmd value check error, vout cmd read: 0x%x, vout cmd set: 0x%x\n", ++ client->adapter->nr, client->addr, vout_cmd, vout_cmd_set); ++ goto error; ++ } ++ ++ /* open write protect */ ++ wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, WRITE_PROTECT_OPEN); ++ mutex_unlock(&data->update_lock); ++ WB_ISL68137_VERBOSE("%d-%04x: set page%d vout cmd success, vout %d, vout_cmd_set: 0x%x\n", ++ client->adapter->nr, client->addr, attr->index, vout, vout_cmd_set); ++ return count; ++error: ++ wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, WRITE_PROTECT_OPEN); ++ mutex_unlock(&data->update_lock); ++ return ret; ++} ++ ++static ssize_t isl68137_avs_vout_max_store(struct device *dev, ++ struct device_attribute *devattr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ int ret, vout_threshold; ++ ++ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { ++ WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, ++ attr->index); ++ return -EINVAL; ++ } ++ ++ ret = kstrtoint(buf, 0, &vout_threshold); ++ if (ret) { ++ WB_ISL68137_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); ++ return -EINVAL; ++ } ++ ++ WB_ISL68137_VERBOSE("%d-%04x: vout%d max threshold: %d", client->adapter->nr, client->addr, ++ attr->index, vout_threshold); ++ ++ data->vout_max[attr->index] = vout_threshold; ++ return count; ++} ++ ++static ssize_t isl68137_avs_vout_max_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ ++ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { ++ WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, ++ attr->index); ++ return -EINVAL; ++ } ++ ++ return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_max[attr->index]); ++} ++ ++static ssize_t isl68137_avs_vout_min_store(struct device *dev, ++ struct device_attribute *devattr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ int ret, vout_threshold; ++ ++ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { ++ WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, ++ attr->index); ++ return -EINVAL; ++ } ++ ++ ret = kstrtoint(buf, 0, &vout_threshold); ++ if (ret) { ++ WB_ISL68137_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); ++ return -EINVAL; ++ } ++ ++ WB_ISL68137_VERBOSE("%d-%04x: vout%d min threshold: %d", client->adapter->nr, client->addr, ++ attr->index, vout_threshold); ++ ++ data->vout_min[attr->index] = vout_threshold; ++ return count; ++} ++ ++static ssize_t isl68137_avs_vout_min_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ ++ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { ++ WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, ++ attr->index); ++ return -EINVAL; ++ } ++ ++ return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_min[attr->index]); ++} ++ ++static SENSOR_DEVICE_ATTR_RW(avs0_enable, isl68137_avs_enable, 0); ++static SENSOR_DEVICE_ATTR_RW(avs1_enable, isl68137_avs_enable, 1); ++ ++static SENSOR_DEVICE_ATTR_RW(avs0_vout, isl68137_avs_vout, 0); ++static SENSOR_DEVICE_ATTR_RW(avs1_vout, isl68137_avs_vout, 1); ++static SENSOR_DEVICE_ATTR_RW(avs0_vout_max, isl68137_avs_vout_max, 0); ++static SENSOR_DEVICE_ATTR_RW(avs0_vout_min, isl68137_avs_vout_min, 0); ++static SENSOR_DEVICE_ATTR_RW(avs1_vout_max, isl68137_avs_vout_max, 1); ++static SENSOR_DEVICE_ATTR_RW(avs1_vout_min, isl68137_avs_vout_min, 1); ++ ++static struct attribute *enable_attrs[] = { ++ &sensor_dev_attr_avs0_enable.dev_attr.attr, ++ &sensor_dev_attr_avs1_enable.dev_attr.attr, ++ NULL, ++}; ++ ++static struct attribute *avs_ctrl_attrs[] = { ++ &sensor_dev_attr_avs0_vout.dev_attr.attr, ++ &sensor_dev_attr_avs1_vout.dev_attr.attr, ++ &sensor_dev_attr_avs0_vout_max.dev_attr.attr, ++ &sensor_dev_attr_avs0_vout_min.dev_attr.attr, ++ &sensor_dev_attr_avs1_vout_max.dev_attr.attr, ++ &sensor_dev_attr_avs1_vout_min.dev_attr.attr, ++ NULL, ++}; ++ ++static const struct attribute_group enable_group = { ++ .attrs = enable_attrs, ++}; ++ ++static const struct attribute_group avs_ctrl_group = { ++ .attrs = avs_ctrl_attrs, ++}; ++ ++static const struct attribute_group *isl68137_attribute_groups[] = { ++ &enable_group, ++ &avs_ctrl_group, ++ NULL, ++}; ++ ++static int raa_dmpvr2_read_word_data(struct i2c_client *client, int page, ++ int phase, int reg) ++{ ++ int ret; ++ ++ switch (reg) { ++ case PMBUS_VIRT_READ_VMON: ++ ret = wb_pmbus_read_word_data(client, page, phase, ++ RAA_DMPVR2_READ_VMON); ++ break; ++ default: ++ ret = -ENODATA; ++ break; ++ } ++ ++ return ret; ++} ++ ++static struct pmbus_driver_info raa_dmpvr_info = { ++ .pages = 3, ++ .format[PSC_VOLTAGE_IN] = direct, ++ .format[PSC_VOLTAGE_OUT] = direct, ++ .format[PSC_CURRENT_IN] = direct, ++ .format[PSC_CURRENT_OUT] = direct, ++ .format[PSC_POWER] = direct, ++ .format[PSC_TEMPERATURE] = direct, ++ .m[PSC_VOLTAGE_IN] = 1, ++ .b[PSC_VOLTAGE_IN] = 0, ++ .R[PSC_VOLTAGE_IN] = 2, ++ .m[PSC_VOLTAGE_OUT] = 1, ++ .b[PSC_VOLTAGE_OUT] = 0, ++ .R[PSC_VOLTAGE_OUT] = 3, ++ .m[PSC_CURRENT_IN] = 1, ++ .b[PSC_CURRENT_IN] = 0, ++ .R[PSC_CURRENT_IN] = 2, ++ .m[PSC_CURRENT_OUT] = 1, ++ .b[PSC_CURRENT_OUT] = 0, ++ .R[PSC_CURRENT_OUT] = 1, ++ .m[PSC_POWER] = 1, ++ .b[PSC_POWER] = 0, ++ .R[PSC_POWER] = 0, ++ .m[PSC_TEMPERATURE] = 1, ++ .b[PSC_TEMPERATURE] = 0, ++ .R[PSC_TEMPERATURE] = 0, ++ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN ++ | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 ++ | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP ++ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT ++ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT ++ | PMBUS_HAVE_VMON, ++ .func[1] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT ++ | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP ++ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT ++ | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, ++ .func[2] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT ++ | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP ++ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT ++ | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, ++}; ++ ++static int isl68137_probe(struct i2c_client *client) ++{ ++ struct pmbus_driver_info *info; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ memcpy(info, &raa_dmpvr_info, sizeof(*info)); ++ ++ switch (i2c_match_id(raa_dmpvr_id, client)->driver_data) { ++ case raa_dmpvr1_2rail: ++ info->pages = 2; ++ info->R[PSC_VOLTAGE_IN] = 3; ++ info->func[0] &= ~PMBUS_HAVE_VMON; ++ info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT ++ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT ++ | PMBUS_HAVE_POUT; ++ info->groups = isl68137_attribute_groups; ++ break; ++ case raa_dmpvr2_1rail: ++ info->pages = 1; ++ info->read_word_data = raa_dmpvr2_read_word_data; ++ break; ++ case raa_dmpvr2_2rail_nontc: ++ info->func[0] &= ~PMBUS_HAVE_TEMP3; ++ info->func[1] &= ~PMBUS_HAVE_TEMP3; ++ fallthrough; ++ case raa_dmpvr2_2rail: ++ info->pages = 2; ++ info->read_word_data = raa_dmpvr2_read_word_data; ++ break; ++ case raa_dmpvr2_3rail: ++ info->read_word_data = raa_dmpvr2_read_word_data; ++ break; ++ case raa_dmpvr2_hv: ++ info->pages = 1; ++ info->R[PSC_VOLTAGE_IN] = 1; ++ info->m[PSC_VOLTAGE_OUT] = 2; ++ info->R[PSC_VOLTAGE_OUT] = 2; ++ info->m[PSC_CURRENT_IN] = 2; ++ info->m[PSC_POWER] = 2; ++ info->R[PSC_POWER] = -1; ++ info->read_word_data = raa_dmpvr2_read_word_data; ++ break; ++ default: ++ return -ENODEV; ++ } ++ ++ return wb_pmbus_do_probe(client, info); ++} ++ ++static const struct i2c_device_id raa_dmpvr_id[] = { ++ {"wb_isl68127", raa_dmpvr1_2rail}, ++ {"wb_isl68137", raa_dmpvr1_2rail}, ++ {"wb_isl68220", raa_dmpvr2_2rail}, ++ {"wb_isl68221", raa_dmpvr2_3rail}, ++ {"wb_isl68222", raa_dmpvr2_2rail}, ++ {"wb_isl68223", raa_dmpvr2_2rail}, ++ {"wb_isl68224", raa_dmpvr2_3rail}, ++ {"wb_isl68225", raa_dmpvr2_2rail}, ++ {"wb_isl68226", raa_dmpvr2_3rail}, ++ {"wb_isl68227", raa_dmpvr2_1rail}, ++ {"wb_isl68229", raa_dmpvr2_3rail}, ++ {"wb_isl68233", raa_dmpvr2_2rail}, ++ {"wb_isl68239", raa_dmpvr2_3rail}, ++ ++ {"wb_isl69222", raa_dmpvr2_2rail}, ++ {"wb_isl69223", raa_dmpvr2_3rail}, ++ {"wb_isl69224", raa_dmpvr2_2rail}, ++ {"wb_isl69225", raa_dmpvr2_2rail}, ++ {"wb_isl69227", raa_dmpvr2_3rail}, ++ {"wb_isl69228", raa_dmpvr2_3rail}, ++ {"wb_isl69234", raa_dmpvr2_2rail}, ++ {"wb_isl69236", raa_dmpvr2_2rail}, ++ {"wb_isl69239", raa_dmpvr2_3rail}, ++ {"wb_isl69242", raa_dmpvr2_2rail}, ++ {"wb_isl69243", raa_dmpvr2_1rail}, ++ {"wb_isl69247", raa_dmpvr2_2rail}, ++ {"wb_isl69248", raa_dmpvr2_2rail}, ++ {"wb_isl69254", raa_dmpvr2_2rail}, ++ {"wb_isl69255", raa_dmpvr2_2rail}, ++ {"wb_isl69256", raa_dmpvr2_2rail}, ++ {"wb_isl69259", raa_dmpvr2_2rail}, ++ {"wb_isl69260", raa_dmpvr2_2rail}, ++ {"wb_isl69268", raa_dmpvr2_2rail}, ++ {"wb_isl69269", raa_dmpvr2_3rail}, ++ {"wb_isl69298", raa_dmpvr2_2rail}, ++ ++ {"wb_raa228000", raa_dmpvr2_hv}, ++ {"wb_raa228004", raa_dmpvr2_hv}, ++ {"wb_raa228006", raa_dmpvr2_hv}, ++ {"wb_raa228228", raa_dmpvr2_2rail_nontc}, ++ {"wb_raa229001", raa_dmpvr2_2rail}, ++ {"wb_raa229004", raa_dmpvr2_2rail}, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(i2c, raa_dmpvr_id); ++ ++/* This is the driver that will be inserted */ ++static struct i2c_driver isl68137_driver = { ++ .driver = { ++ .name = "wb_isl68137", ++ }, ++ .probe_new = isl68137_probe, ++ .remove = wb_pmbus_do_remove, ++ .id_table = raa_dmpvr_id, ++}; ++ ++module_i2c_driver(isl68137_driver); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("PMBus driver for Renesas digital multiphase voltage regulators"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.c +new file mode 100644 +index 000000000..0386cfb0b +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.c +@@ -0,0 +1,992 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * lm75.c - Part of lm_sensors, Linux kernel modules for hardware ++ * monitoring ++ * Copyright (c) 1998, 1999 Frodo Looijaard ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "wb_lm75.h" ++ ++/* ++ * This driver handles the LM75 and compatible digital temperature sensors. ++ */ ++ ++enum lm75_type { /* keep sorted in alphabetical order */ ++ adt75, ++ ds1775, ++ ds75, ++ ds7505, ++ g751, ++ lm75, ++ lm75a, ++ lm75b, ++ max6625, ++ max6626, ++ max31725, ++ mcp980x, ++ pct2075, ++ stds75, ++ stlm75, ++ tcn75, ++ tmp100, ++ tmp101, ++ tmp105, ++ tmp112, ++ tmp175, ++ tmp275, ++ tmp75, ++ tmp75b, ++ tmp75c, ++}; ++ ++/** ++ * struct lm75_params - lm75 configuration parameters. ++ * @set_mask: Bits to set in configuration register when configuring ++ * the chip. ++ * @clr_mask: Bits to clear in configuration register when configuring ++ * the chip. ++ * @default_resolution: Default number of bits to represent the temperature ++ * value. ++ * @resolution_limits: Limit register resolution. Optional. Should be set if ++ * the resolution of limit registers does not match the ++ * resolution of the temperature register. ++ * @resolutions: List of resolutions associated with sample times. ++ * Optional. Should be set if num_sample_times is larger ++ * than 1, and if the resolution changes with sample times. ++ * If set, number of entries must match num_sample_times. ++ * @default_sample_time:Sample time to be set by default. ++ * @num_sample_times: Number of possible sample times to be set. Optional. ++ * Should be set if the number of sample times is larger ++ * than one. ++ * @sample_times: All the possible sample times to be set. Mandatory if ++ * num_sample_times is larger than 1. If set, number of ++ * entries must match num_sample_times. ++ */ ++ ++struct lm75_params { ++ u8 set_mask; ++ u8 clr_mask; ++ u8 default_resolution; ++ u8 resolution_limits; ++ const u8 *resolutions; ++ unsigned int default_sample_time; ++ u8 num_sample_times; ++ const unsigned int *sample_times; ++}; ++#if 0 ++/* Addresses scanned */ ++static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, ++ 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; ++#endif ++/* The LM75 registers */ ++#define LM75_REG_TEMP 0x00 ++#define LM75_REG_CONF 0x01 ++#define LM75_REG_HYST 0x02 ++#define LM75_REG_MAX 0x03 ++#define PCT2075_REG_IDLE 0x04 ++#define LM75_TEMP_INVALID_RETRY_TIMES (3) ++ ++/* Each client has this additional data */ ++struct lm75_data { ++ struct i2c_client *client; ++ struct regmap *regmap; ++ struct regulator *vs; ++ u8 orig_conf; ++ u8 current_conf; ++ u8 resolution; /* In bits, 9 to 16 */ ++ unsigned int sample_time; /* In ms */ ++ enum lm75_type kind; ++ const struct lm75_params *params; ++}; ++ ++/*-----------------------------------------------------------------------*/ ++ ++static const u8 lm75_sample_set_masks[] = { 0 << 5, 1 << 5, 2 << 5, 3 << 5 }; ++ ++#define LM75_SAMPLE_CLEAR_MASK (3 << 5) ++ ++/* The structure below stores the configuration values of the supported devices. ++ * In case of being supported multiple configurations, the default one must ++ * always be the first element of the array ++ */ ++static const struct lm75_params device_params[] = { ++ [adt75] = { ++ .clr_mask = 1 << 5, /* not one-shot mode */ ++ .default_resolution = 12, ++ .default_sample_time = MSEC_PER_SEC / 10, ++ }, ++ [ds1775] = { ++ .clr_mask = 3 << 5, ++ .set_mask = 2 << 5, /* 11-bit mode */ ++ .default_resolution = 11, ++ .default_sample_time = 500, ++ .num_sample_times = 4, ++ .sample_times = (unsigned int []){ 125, 250, 500, 1000 }, ++ .resolutions = (u8 []) {9, 10, 11, 12 }, ++ }, ++ [ds75] = { ++ .clr_mask = 3 << 5, ++ .set_mask = 2 << 5, /* 11-bit mode */ ++ .default_resolution = 11, ++ .default_sample_time = 600, ++ .num_sample_times = 4, ++ .sample_times = (unsigned int []){ 150, 300, 600, 1200 }, ++ .resolutions = (u8 []) {9, 10, 11, 12 }, ++ }, ++ [stds75] = { ++ .clr_mask = 3 << 5, ++ .set_mask = 2 << 5, /* 11-bit mode */ ++ .default_resolution = 11, ++ .default_sample_time = 600, ++ .num_sample_times = 4, ++ .sample_times = (unsigned int []){ 150, 300, 600, 1200 }, ++ .resolutions = (u8 []) {9, 10, 11, 12 }, ++ }, ++ [stlm75] = { ++ .default_resolution = 9, ++ .default_sample_time = MSEC_PER_SEC / 6, ++ }, ++ [ds7505] = { ++ .set_mask = 3 << 5, /* 12-bit mode*/ ++ .default_resolution = 12, ++ .default_sample_time = 200, ++ .num_sample_times = 4, ++ .sample_times = (unsigned int []){ 25, 50, 100, 200 }, ++ .resolutions = (u8 []) {9, 10, 11, 12 }, ++ }, ++ [g751] = { ++ .default_resolution = 9, ++ .default_sample_time = MSEC_PER_SEC / 10, ++ }, ++ [lm75] = { ++ .default_resolution = 9, ++ .default_sample_time = MSEC_PER_SEC / 10, ++ }, ++ [lm75a] = { ++ .default_resolution = 9, ++ .default_sample_time = MSEC_PER_SEC / 10, ++ }, ++ [lm75b] = { ++ .default_resolution = 11, ++ .default_sample_time = MSEC_PER_SEC / 10, ++ }, ++ [max6625] = { ++ .default_resolution = 9, ++ .default_sample_time = MSEC_PER_SEC / 7, ++ }, ++ [max6626] = { ++ .default_resolution = 12, ++ .default_sample_time = MSEC_PER_SEC / 7, ++ .resolution_limits = 9, ++ }, ++ [max31725] = { ++ .default_resolution = 16, ++ .default_sample_time = MSEC_PER_SEC / 20, ++ }, ++ [tcn75] = { ++ .default_resolution = 9, ++ .default_sample_time = MSEC_PER_SEC / 18, ++ }, ++ [pct2075] = { ++ .default_resolution = 11, ++ .default_sample_time = MSEC_PER_SEC / 10, ++ .num_sample_times = 31, ++ .sample_times = (unsigned int []){ 100, 200, 300, 400, 500, 600, ++ 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, ++ 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, ++ 2800, 2900, 3000, 3100 }, ++ }, ++ [mcp980x] = { ++ .set_mask = 3 << 5, /* 12-bit mode */ ++ .clr_mask = 1 << 7, /* not one-shot mode */ ++ .default_resolution = 12, ++ .resolution_limits = 9, ++ .default_sample_time = 240, ++ .num_sample_times = 4, ++ .sample_times = (unsigned int []){ 30, 60, 120, 240 }, ++ .resolutions = (u8 []) {9, 10, 11, 12 }, ++ }, ++ [tmp100] = { ++ .set_mask = 3 << 5, /* 12-bit mode */ ++ .clr_mask = 1 << 7, /* not one-shot mode */ ++ .default_resolution = 12, ++ .default_sample_time = 320, ++ .num_sample_times = 4, ++ .sample_times = (unsigned int []){ 40, 80, 160, 320 }, ++ .resolutions = (u8 []) {9, 10, 11, 12 }, ++ }, ++ [tmp101] = { ++ .set_mask = 3 << 5, /* 12-bit mode */ ++ .clr_mask = 1 << 7, /* not one-shot mode */ ++ .default_resolution = 12, ++ .default_sample_time = 320, ++ .num_sample_times = 4, ++ .sample_times = (unsigned int []){ 40, 80, 160, 320 }, ++ .resolutions = (u8 []) {9, 10, 11, 12 }, ++ }, ++ [tmp105] = { ++ .set_mask = 3 << 5, /* 12-bit mode */ ++ .clr_mask = 1 << 7, /* not one-shot mode*/ ++ .default_resolution = 12, ++ .default_sample_time = 220, ++ .num_sample_times = 4, ++ .sample_times = (unsigned int []){ 28, 55, 110, 220 }, ++ .resolutions = (u8 []) {9, 10, 11, 12 }, ++ }, ++ [tmp112] = { ++ .set_mask = 3 << 5, /* 8 samples / second */ ++ .clr_mask = 1 << 7, /* no one-shot mode*/ ++ .default_resolution = 12, ++ .default_sample_time = 125, ++ .num_sample_times = 4, ++ .sample_times = (unsigned int []){ 125, 250, 1000, 4000 }, ++ }, ++ [tmp175] = { ++ .set_mask = 3 << 5, /* 12-bit mode */ ++ .clr_mask = 1 << 7, /* not one-shot mode*/ ++ .default_resolution = 12, ++ .default_sample_time = 220, ++ .num_sample_times = 4, ++ .sample_times = (unsigned int []){ 28, 55, 110, 220 }, ++ .resolutions = (u8 []) {9, 10, 11, 12 }, ++ }, ++ [tmp275] = { ++ .set_mask = 3 << 5, /* 12-bit mode */ ++ .clr_mask = 1 << 7, /* not one-shot mode*/ ++ .default_resolution = 12, ++ .default_sample_time = 220, ++ .num_sample_times = 4, ++ .sample_times = (unsigned int []){ 28, 55, 110, 220 }, ++ .resolutions = (u8 []) {9, 10, 11, 12 }, ++ }, ++ [tmp75] = { ++ .set_mask = 3 << 5, /* 12-bit mode */ ++ .clr_mask = 1 << 7, /* not one-shot mode*/ ++ .default_resolution = 12, ++ .default_sample_time = 220, ++ .num_sample_times = 4, ++ .sample_times = (unsigned int []){ 28, 55, 110, 220 }, ++ .resolutions = (u8 []) {9, 10, 11, 12 }, ++ }, ++ [tmp75b] = { /* not one-shot mode, Conversion rate 37Hz */ ++ .clr_mask = 1 << 7 | 3 << 5, ++ .default_resolution = 12, ++ .default_sample_time = MSEC_PER_SEC / 37, ++ .sample_times = (unsigned int []){ MSEC_PER_SEC / 37, ++ MSEC_PER_SEC / 18, ++ MSEC_PER_SEC / 9, MSEC_PER_SEC / 4 }, ++ .num_sample_times = 4, ++ }, ++ [tmp75c] = { ++ .clr_mask = 1 << 5, /*not one-shot mode*/ ++ .default_resolution = 12, ++ .default_sample_time = MSEC_PER_SEC / 12, ++ } ++}; ++ ++/* input temp threshold check */ ++typedef struct lm75_temp_threshold_s { ++ int chip_type; ++ int temp_max; ++ int temp_min; ++} lm75_temp_threshold_t; ++ ++static lm75_temp_threshold_t g_lm75_temp_threshold_info[] = { ++ { ++ .chip_type = lm75, ++ .temp_max = 125000, ++ .temp_min = -55000, ++ }, ++ { ++ .chip_type = tmp275, ++ .temp_max = 125000, ++ .temp_min = -40000, ++ }, ++}; ++ ++/*-----------------------------------------------------------------------*/ ++static int lm75_input_temp_check(struct lm75_data *data, int input_val) ++{ ++ int i, size; ++ ++ size = ARRAY_SIZE(g_lm75_temp_threshold_info); ++ ++ for (i = 0; i < size; i++) { ++ if (g_lm75_temp_threshold_info[i].chip_type == data->kind) { ++ if ((input_val > g_lm75_temp_threshold_info[i].temp_max) ++ || (input_val < g_lm75_temp_threshold_info[i].temp_min)) { ++ dev_dbg(&data->client->dev, "input temp: %d not in range[%d, %d]\n", ++ input_val, g_lm75_temp_threshold_info[i].temp_min, ++ g_lm75_temp_threshold_info[i].temp_max); ++ return -EINVAL; ++ } ++ dev_dbg(&data->client->dev, "input temp: %d in range[%d, %d]", input_val, ++ g_lm75_temp_threshold_info[i].temp_min, g_lm75_temp_threshold_info[i].temp_max); ++ return 0; ++ } ++ } ++ return 0; ++} ++ ++static inline long lm75_reg_to_mc(s16 temp, u8 resolution) ++{ ++ return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8); ++} ++ ++static int lm75_write_config(struct lm75_data *data, u8 set_mask, ++ u8 clr_mask) ++{ ++ u8 value; ++ ++ clr_mask |= LM75_SHUTDOWN; ++ value = data->current_conf & ~clr_mask; ++ value |= set_mask; ++ ++ if (data->current_conf != value) { ++ s32 err; ++ ++ err = i2c_smbus_write_byte_data(data->client, LM75_REG_CONF, ++ value); ++ if (err) ++ return err; ++ data->current_conf = value; ++ } ++ return 0; ++} ++ ++static int lm75_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, ++ long *val) ++{ ++ struct lm75_data *data = dev_get_drvdata(dev); ++ unsigned int regval; ++ int err, reg, i, ret; ++ ++ switch (type) { ++ case hwmon_chip: ++ switch (attr) { ++ case hwmon_chip_update_interval: ++ *val = data->sample_time; ++ break; ++ default: ++ return -EINVAL; ++ } ++ break; ++ case hwmon_temp: ++ switch (attr) { ++ case hwmon_temp_input: ++ reg = LM75_REG_TEMP; ++ break; ++ case hwmon_temp_max: ++ reg = LM75_REG_MAX; ++ break; ++ case hwmon_temp_max_hyst: ++ reg = LM75_REG_HYST; ++ break; ++ default: ++ return -EINVAL; ++ } ++ for (i = 0; i < LM75_TEMP_INVALID_RETRY_TIMES; i++) { ++ err = regmap_read(data->regmap, reg, ®val); ++ if (err < 0) { ++ return err; ++ } ++ *val = lm75_reg_to_mc(regval, data->resolution); ++ if (reg != LM75_REG_TEMP) { ++ return 0; ++ } ++ /* do input_temp_check */ ++ ret = lm75_input_temp_check(data, *val); ++ if (ret == 0) { /* input temp check ok */ ++ return 0; ++ } ++ if ((i + 1) < LM75_TEMP_INVALID_RETRY_TIMES) { ++ msleep(data->sample_time); ++ } ++ } ++ dev_info(&data->client->dev, "temp_input value: %ld invalid\n", *val); ++ return -EINVAL; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int lm75_write_temp(struct device *dev, u32 attr, long temp) ++{ ++ struct lm75_data *data = dev_get_drvdata(dev); ++ u8 resolution; ++ int reg; ++ ++ switch (attr) { ++ case hwmon_temp_max: ++ reg = LM75_REG_MAX; ++ break; ++ case hwmon_temp_max_hyst: ++ reg = LM75_REG_HYST; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* ++ * Resolution of limit registers is assumed to be the same as the ++ * temperature input register resolution unless given explicitly. ++ */ ++ if (data->params->resolution_limits) ++ resolution = data->params->resolution_limits; ++ else ++ resolution = data->resolution; ++ ++ temp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); ++ temp = DIV_ROUND_CLOSEST(temp << (resolution - 8), ++ 1000) << (16 - resolution); ++ ++ return regmap_write(data->regmap, reg, (u16)temp); ++} ++ ++static int lm75_update_interval(struct device *dev, long val) ++{ ++ struct lm75_data *data = dev_get_drvdata(dev); ++ unsigned int reg; ++ u8 index; ++ s32 err; ++ ++ index = find_closest(val, data->params->sample_times, ++ (int)data->params->num_sample_times); ++ ++ switch (data->kind) { ++ default: ++ err = lm75_write_config(data, lm75_sample_set_masks[index], ++ LM75_SAMPLE_CLEAR_MASK); ++ if (err) ++ return err; ++ ++ data->sample_time = data->params->sample_times[index]; ++ if (data->params->resolutions) ++ data->resolution = data->params->resolutions[index]; ++ break; ++ case tmp112: ++ err = regmap_read(data->regmap, LM75_REG_CONF, ®); ++ if (err < 0) ++ return err; ++ reg &= ~0x00c0; ++ reg |= (3 - index) << 6; ++ err = regmap_write(data->regmap, LM75_REG_CONF, reg); ++ if (err < 0) ++ return err; ++ data->sample_time = data->params->sample_times[index]; ++ break; ++ case pct2075: ++ err = i2c_smbus_write_byte_data(data->client, PCT2075_REG_IDLE, ++ index + 1); ++ if (err) ++ return err; ++ data->sample_time = data->params->sample_times[index]; ++ break; ++ } ++ return 0; ++} ++ ++static int lm75_write_chip(struct device *dev, u32 attr, long val) ++{ ++ switch (attr) { ++ case hwmon_chip_update_interval: ++ return lm75_update_interval(dev, val); ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int lm75_write(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long val) ++{ ++ switch (type) { ++ case hwmon_chip: ++ return lm75_write_chip(dev, attr, val); ++ case hwmon_temp: ++ return lm75_write_temp(dev, attr, val); ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ const struct lm75_data *config_data = data; ++ ++ switch (type) { ++ case hwmon_chip: ++ switch (attr) { ++ case hwmon_chip_update_interval: ++ if (config_data->params->num_sample_times > 1) ++ return 0644; ++ return 0444; ++ } ++ break; ++ case hwmon_temp: ++ switch (attr) { ++ case hwmon_temp_input: ++ return 0444; ++ case hwmon_temp_max: ++ case hwmon_temp_max_hyst: ++ return 0644; ++ } ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static const struct hwmon_channel_info *lm75_info[] = { ++ HWMON_CHANNEL_INFO(chip, ++ HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL), ++ HWMON_CHANNEL_INFO(temp, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST), ++ NULL ++}; ++ ++static const struct hwmon_ops lm75_hwmon_ops = { ++ .is_visible = lm75_is_visible, ++ .read = lm75_read, ++ .write = lm75_write, ++}; ++ ++static const struct hwmon_chip_info lm75_chip_info = { ++ .ops = &lm75_hwmon_ops, ++ .info = lm75_info, ++}; ++ ++static bool lm75_is_writeable_reg(struct device *dev, unsigned int reg) ++{ ++ return reg != LM75_REG_TEMP; ++} ++ ++static bool lm75_is_volatile_reg(struct device *dev, unsigned int reg) ++{ ++ return reg == LM75_REG_TEMP || reg == LM75_REG_CONF; ++} ++ ++static const struct regmap_config lm75_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 16, ++ .max_register = PCT2075_REG_IDLE, ++ .writeable_reg = lm75_is_writeable_reg, ++ .volatile_reg = lm75_is_volatile_reg, ++ .val_format_endian = REGMAP_ENDIAN_BIG, ++ .cache_type = REGCACHE_RBTREE, ++ .use_single_read = true, ++ .use_single_write = true, ++}; ++ ++static void lm75_disable_regulator(void *data) ++{ ++ struct lm75_data *lm75 = data; ++ ++ regulator_disable(lm75->vs); ++} ++ ++static void lm75_remove(void *data) ++{ ++ struct lm75_data *lm75 = data; ++ struct i2c_client *client = lm75->client; ++ ++ i2c_smbus_write_byte_data(client, LM75_REG_CONF, lm75->orig_conf); ++} ++ ++static const struct i2c_device_id lm75_ids[]; ++ ++static int lm75_probe(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct device *hwmon_dev; ++ struct lm75_data *data; ++ int status, err; ++ enum lm75_type kind; ++ ++ if (client->dev.of_node) ++ kind = (enum lm75_type)of_device_get_match_data(&client->dev); ++ else ++ kind = i2c_match_id(lm75_ids, client)->driver_data; ++ ++ if (!i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) ++ return -EIO; ++ ++ data = devm_kzalloc(dev, sizeof(struct lm75_data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->client = client; ++ data->kind = kind; ++ ++ data->vs = devm_regulator_get(dev, "vs"); ++ if (IS_ERR(data->vs)) ++ return PTR_ERR(data->vs); ++ ++ data->regmap = devm_regmap_init_i2c(client, &lm75_regmap_config); ++ if (IS_ERR(data->regmap)) ++ return PTR_ERR(data->regmap); ++ ++ /* Set to LM75 resolution (9 bits, 1/2 degree C) and range. ++ * Then tweak to be more precise when appropriate. ++ */ ++ ++ data->params = &device_params[data->kind]; ++ ++ /* Save default sample time and resolution*/ ++ data->sample_time = data->params->default_sample_time; ++ data->resolution = data->params->default_resolution; ++ ++ /* Enable the power */ ++ err = regulator_enable(data->vs); ++ if (err) { ++ dev_err(dev, "failed to enable regulator: %d\n", err); ++ return err; ++ } ++ ++ err = devm_add_action_or_reset(dev, lm75_disable_regulator, data); ++ if (err) ++ return err; ++ ++ /* Cache original configuration */ ++ status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); ++ if (status < 0) { ++ dev_dbg(dev, "Can't read config? %d\n", status); ++ return status; ++ } ++ data->orig_conf = status; ++ data->current_conf = status; ++ ++ err = lm75_write_config(data, data->params->set_mask, ++ data->params->clr_mask); ++ if (err) ++ return err; ++ ++ err = devm_add_action_or_reset(dev, lm75_remove, data); ++ if (err) ++ return err; ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ++ data, &lm75_chip_info, ++ NULL); ++ if (IS_ERR(hwmon_dev)) ++ return PTR_ERR(hwmon_dev); ++ ++ dev_info(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), client->name); ++ ++ return 0; ++} ++ ++static const struct i2c_device_id lm75_ids[] = { ++ { "wb_adt75", adt75, }, ++ { "wb_ds1775", ds1775, }, ++ { "wb_ds75", ds75, }, ++ { "wb_ds7505", ds7505, }, ++ { "wb_g751", g751, }, ++ { "wb_lm75", lm75, }, ++ { "wb_lm75a", lm75a, }, ++ { "wb_lm75b", lm75b, }, ++ { "wb_max6625", max6625, }, ++ { "wb_max6626", max6626, }, ++ { "wb_max31725", max31725, }, ++ { "wb_max31726", max31725, }, ++ { "wb_mcp980x", mcp980x, }, ++ { "wb_pct2075", pct2075, }, ++ { "wb_stds75", stds75, }, ++ { "wb_stlm75", stlm75, }, ++ { "wb_tcn75", tcn75, }, ++ { "wb_tmp100", tmp100, }, ++ { "wb_tmp101", tmp101, }, ++ { "wb_tmp105", tmp105, }, ++ { "wb_tmp112", tmp112, }, ++ { "wb_tmp175", tmp175, }, ++ { "wb_tmp275", tmp275, }, ++ { "wb_tmp75", tmp75, }, ++ { "wb_tmp75b", tmp75b, }, ++ { "wb_tmp75c", tmp75c, }, ++ { /* LIST END */ } ++}; ++MODULE_DEVICE_TABLE(i2c, lm75_ids); ++ ++static const struct of_device_id __maybe_unused lm75_of_match[] = { ++ { ++ .compatible = "adi,adt75", ++ .data = (void *)adt75 ++ }, ++ { ++ .compatible = "dallas,ds1775", ++ .data = (void *)ds1775 ++ }, ++ { ++ .compatible = "dallas,ds75", ++ .data = (void *)ds75 ++ }, ++ { ++ .compatible = "dallas,ds7505", ++ .data = (void *)ds7505 ++ }, ++ { ++ .compatible = "gmt,g751", ++ .data = (void *)g751 ++ }, ++ { ++ .compatible = "national,lm75", ++ .data = (void *)lm75 ++ }, ++ { ++ .compatible = "national,lm75a", ++ .data = (void *)lm75a ++ }, ++ { ++ .compatible = "national,lm75b", ++ .data = (void *)lm75b ++ }, ++ { ++ .compatible = "maxim,max6625", ++ .data = (void *)max6625 ++ }, ++ { ++ .compatible = "maxim,max6626", ++ .data = (void *)max6626 ++ }, ++ { ++ .compatible = "maxim,max31725", ++ .data = (void *)max31725 ++ }, ++ { ++ .compatible = "maxim,max31726", ++ .data = (void *)max31725 ++ }, ++ { ++ .compatible = "maxim,mcp980x", ++ .data = (void *)mcp980x ++ }, ++ { ++ .compatible = "nxp,pct2075", ++ .data = (void *)pct2075 ++ }, ++ { ++ .compatible = "st,stds75", ++ .data = (void *)stds75 ++ }, ++ { ++ .compatible = "st,stlm75", ++ .data = (void *)stlm75 ++ }, ++ { ++ .compatible = "microchip,tcn75", ++ .data = (void *)tcn75 ++ }, ++ { ++ .compatible = "ti,tmp100", ++ .data = (void *)tmp100 ++ }, ++ { ++ .compatible = "ti,tmp101", ++ .data = (void *)tmp101 ++ }, ++ { ++ .compatible = "ti,tmp105", ++ .data = (void *)tmp105 ++ }, ++ { ++ .compatible = "ti,tmp112", ++ .data = (void *)tmp112 ++ }, ++ { ++ .compatible = "ti,tmp175", ++ .data = (void *)tmp175 ++ }, ++ { ++ .compatible = "ti,tmp275", ++ .data = (void *)tmp275 ++ }, ++ { ++ .compatible = "ti,tmp75", ++ .data = (void *)tmp75 ++ }, ++ { ++ .compatible = "ti,tmp75b", ++ .data = (void *)tmp75b ++ }, ++ { ++ .compatible = "ti,tmp75c", ++ .data = (void *)tmp75c ++ }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, lm75_of_match); ++ ++#define LM75A_ID 0xA1 ++#if 0 ++/* Return 0 if detection is successful, -ENODEV otherwise */ ++static int lm75_detect(struct i2c_client *new_client, ++ struct i2c_board_info *info) ++{ ++ struct i2c_adapter *adapter = new_client->adapter; ++ int i; ++ int conf, hyst, os; ++ bool is_lm75a = 0; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | ++ I2C_FUNC_SMBUS_WORD_DATA)) ++ return -ENODEV; ++ ++ /* ++ * Now, we do the remaining detection. There is no identification- ++ * dedicated register so we have to rely on several tricks: ++ * unused bits, registers cycling over 8-address boundaries, ++ * addresses 0x04-0x07 returning the last read value. ++ * The cycling+unused addresses combination is not tested, ++ * since it would significantly slow the detection down and would ++ * hardly add any value. ++ * ++ * The National Semiconductor LM75A is different than earlier ++ * LM75s. It has an ID byte of 0xaX (where X is the chip ++ * revision, with 1 being the only revision in existence) in ++ * register 7, and unused registers return 0xff rather than the ++ * last read value. ++ * ++ * Note that this function only detects the original National ++ * Semiconductor LM75 and the LM75A. Clones from other vendors ++ * aren't detected, on purpose, because they are typically never ++ * found on PC hardware. They are found on embedded designs where ++ * they can be instantiated explicitly so detection is not needed. ++ * The absence of identification registers on all these clones ++ * would make their exhaustive detection very difficult and weak, ++ * and odds are that the driver would bind to unsupported devices. ++ */ ++ ++ /* Unused bits */ ++ conf = i2c_smbus_read_byte_data(new_client, 1); ++ if (conf & 0xe0) ++ return -ENODEV; ++ ++ /* First check for LM75A */ ++ if (i2c_smbus_read_byte_data(new_client, 7) == LM75A_ID) { ++ /* ++ * LM75A returns 0xff on unused registers so ++ * just to be sure we check for that too. ++ */ ++ if (i2c_smbus_read_byte_data(new_client, 4) != 0xff ++ || i2c_smbus_read_byte_data(new_client, 5) != 0xff ++ || i2c_smbus_read_byte_data(new_client, 6) != 0xff) ++ return -ENODEV; ++ is_lm75a = 1; ++ hyst = i2c_smbus_read_byte_data(new_client, 2); ++ os = i2c_smbus_read_byte_data(new_client, 3); ++ } else { /* Traditional style LM75 detection */ ++ /* Unused addresses */ ++ hyst = i2c_smbus_read_byte_data(new_client, 2); ++ if (i2c_smbus_read_byte_data(new_client, 4) != hyst ++ || i2c_smbus_read_byte_data(new_client, 5) != hyst ++ || i2c_smbus_read_byte_data(new_client, 6) != hyst ++ || i2c_smbus_read_byte_data(new_client, 7) != hyst) ++ return -ENODEV; ++ os = i2c_smbus_read_byte_data(new_client, 3); ++ if (i2c_smbus_read_byte_data(new_client, 4) != os ++ || i2c_smbus_read_byte_data(new_client, 5) != os ++ || i2c_smbus_read_byte_data(new_client, 6) != os ++ || i2c_smbus_read_byte_data(new_client, 7) != os) ++ return -ENODEV; ++ } ++ /* ++ * It is very unlikely that this is a LM75 if both ++ * hysteresis and temperature limit registers are 0. ++ */ ++ if (hyst == 0 && os == 0) ++ return -ENODEV; ++ ++ /* Addresses cycling */ ++ for (i = 8; i <= 248; i += 40) { ++ if (i2c_smbus_read_byte_data(new_client, i + 1) != conf ++ || i2c_smbus_read_byte_data(new_client, i + 2) != hyst ++ || i2c_smbus_read_byte_data(new_client, i + 3) != os) ++ return -ENODEV; ++ if (is_lm75a && i2c_smbus_read_byte_data(new_client, i + 7) ++ != LM75A_ID) ++ return -ENODEV; ++ } ++ ++ strlcpy(info->type, is_lm75a ? "lm75a" : "lm75", I2C_NAME_SIZE); ++ ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_PM ++static int lm75_suspend(struct device *dev) ++{ ++ int status; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); ++ if (status < 0) { ++ dev_dbg(&client->dev, "Can't read config? %d\n", status); ++ return status; ++ } ++ status = status | LM75_SHUTDOWN; ++ i2c_smbus_write_byte_data(client, LM75_REG_CONF, status); ++ return 0; ++} ++ ++static int lm75_resume(struct device *dev) ++{ ++ int status; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); ++ if (status < 0) { ++ dev_dbg(&client->dev, "Can't read config? %d\n", status); ++ return status; ++ } ++ status = status & ~LM75_SHUTDOWN; ++ i2c_smbus_write_byte_data(client, LM75_REG_CONF, status); ++ return 0; ++} ++ ++static const struct dev_pm_ops lm75_dev_pm_ops = { ++ .suspend = lm75_suspend, ++ .resume = lm75_resume, ++}; ++#define LM75_DEV_PM_OPS (&lm75_dev_pm_ops) ++#else ++#define LM75_DEV_PM_OPS NULL ++#endif /* CONFIG_PM */ ++ ++static struct i2c_driver lm75_driver = { ++ .class = I2C_CLASS_HWMON, ++ .driver = { ++ .name = "wb_lm75", ++ .of_match_table = of_match_ptr(lm75_of_match), ++ .pm = LM75_DEV_PM_OPS, ++ }, ++ .probe_new = lm75_probe, ++ .id_table = lm75_ids, ++ /* .detect = lm75_detect, */ ++ /* .address_list = normal_i2c, */ ++}; ++ ++module_i2c_driver(lm75_driver); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("LM75 driver"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.h +new file mode 100644 +index 000000000..a39817116 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.h +@@ -0,0 +1,40 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * lm75.h - Part of lm_sensors, Linux kernel modules for hardware monitoring ++ * Copyright (c) 2003 Mark M. Hoffman ++ */ ++ ++/* ++ * This file contains common code for encoding/decoding LM75 type ++ * temperature readings, which are emulated by many of the chips ++ * we support. As the user is unlikely to load more than one driver ++ * which contains this code, we don't worry about the wasted space. ++ */ ++ ++#include ++ ++/* straight from the datasheet */ ++#define LM75_TEMP_MIN (-55000) ++#define LM75_TEMP_MAX 125000 ++#define LM75_SHUTDOWN 0x01 ++ ++/* ++ * TEMP: 0.001C/bit (-55C to +125C) ++ * REG: (0.5C/bit, two's complement) << 7 ++ */ ++static inline u16 LM75_TEMP_TO_REG(long temp) ++{ ++ int ntemp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); ++ ++ ntemp += (ntemp < 0 ? -250 : 250); ++ return (u16)((ntemp / 500) << 7); ++} ++ ++static inline int LM75_TEMP_FROM_REG(u16 reg) ++{ ++ /* ++ * use integer division instead of equivalent right shift to ++ * guarantee arithmetic shift and preserve the sign ++ */ ++ return ((s16)reg / 128) * 500; ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus.h +new file mode 100644 +index 000000000..9fb2c9017 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus.h +@@ -0,0 +1,535 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * wb_pmbus.h - Common defines and structures for PMBus devices ++ * ++ * Copyright (c) 2010, 2011 Ericsson AB. ++ * Copyright (c) 2012 Guenter Roeck ++ */ ++ ++#ifndef WB_PMBUS_H ++#define WB_PMBUS_H ++ ++#include ++#include ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++ ++/* ++ * Registers ++ */ ++enum pmbus_regs { ++ PMBUS_PAGE = 0x00, ++ PMBUS_OPERATION = 0x01, ++ PMBUS_ON_OFF_CONFIG = 0x02, ++ PMBUS_CLEAR_FAULTS = 0x03, ++ PMBUS_PHASE = 0x04, ++ ++ PMBUS_WRITE_PROTECT = 0x10, ++ ++ PMBUS_CAPABILITY = 0x19, ++ PMBUS_QUERY = 0x1A, ++ ++ PMBUS_VOUT_MODE = 0x20, ++ PMBUS_VOUT_COMMAND = 0x21, ++ PMBUS_VOUT_TRIM = 0x22, ++ PMBUS_VOUT_CAL_OFFSET = 0x23, ++ PMBUS_VOUT_MAX = 0x24, ++ PMBUS_VOUT_MARGIN_HIGH = 0x25, ++ PMBUS_VOUT_MARGIN_LOW = 0x26, ++ PMBUS_VOUT_TRANSITION_RATE = 0x27, ++ PMBUS_VOUT_DROOP = 0x28, ++ PMBUS_VOUT_SCALE_LOOP = 0x29, ++ PMBUS_VOUT_SCALE_MONITOR = 0x2A, ++ ++ PMBUS_COEFFICIENTS = 0x30, ++ PMBUS_POUT_MAX = 0x31, ++ ++ PMBUS_FAN_CONFIG_12 = 0x3A, ++ PMBUS_FAN_COMMAND_1 = 0x3B, ++ PMBUS_FAN_COMMAND_2 = 0x3C, ++ PMBUS_FAN_CONFIG_34 = 0x3D, ++ PMBUS_FAN_COMMAND_3 = 0x3E, ++ PMBUS_FAN_COMMAND_4 = 0x3F, ++ ++ PMBUS_VOUT_OV_FAULT_LIMIT = 0x40, ++ PMBUS_VOUT_OV_FAULT_RESPONSE = 0x41, ++ PMBUS_VOUT_OV_WARN_LIMIT = 0x42, ++ PMBUS_VOUT_UV_WARN_LIMIT = 0x43, ++ PMBUS_VOUT_UV_FAULT_LIMIT = 0x44, ++ PMBUS_VOUT_UV_FAULT_RESPONSE = 0x45, ++ PMBUS_IOUT_OC_FAULT_LIMIT = 0x46, ++ PMBUS_IOUT_OC_FAULT_RESPONSE = 0x47, ++ PMBUS_IOUT_OC_LV_FAULT_LIMIT = 0x48, ++ PMBUS_IOUT_OC_LV_FAULT_RESPONSE = 0x49, ++ PMBUS_IOUT_OC_WARN_LIMIT = 0x4A, ++ PMBUS_IOUT_UC_FAULT_LIMIT = 0x4B, ++ PMBUS_IOUT_UC_FAULT_RESPONSE = 0x4C, ++ ++ PMBUS_OT_FAULT_LIMIT = 0x4F, ++ PMBUS_OT_FAULT_RESPONSE = 0x50, ++ PMBUS_OT_WARN_LIMIT = 0x51, ++ PMBUS_UT_WARN_LIMIT = 0x52, ++ PMBUS_UT_FAULT_LIMIT = 0x53, ++ PMBUS_UT_FAULT_RESPONSE = 0x54, ++ PMBUS_VIN_OV_FAULT_LIMIT = 0x55, ++ PMBUS_VIN_OV_FAULT_RESPONSE = 0x56, ++ PMBUS_VIN_OV_WARN_LIMIT = 0x57, ++ PMBUS_VIN_UV_WARN_LIMIT = 0x58, ++ PMBUS_VIN_UV_FAULT_LIMIT = 0x59, ++ ++ PMBUS_IIN_OC_FAULT_LIMIT = 0x5B, ++ PMBUS_IIN_OC_WARN_LIMIT = 0x5D, ++ ++ PMBUS_POUT_OP_FAULT_LIMIT = 0x68, ++ PMBUS_POUT_OP_WARN_LIMIT = 0x6A, ++ PMBUS_PIN_OP_WARN_LIMIT = 0x6B, ++ ++ PMBUS_STATUS_BYTE = 0x78, ++ PMBUS_STATUS_WORD = 0x79, ++ PMBUS_STATUS_VOUT = 0x7A, ++ PMBUS_STATUS_IOUT = 0x7B, ++ PMBUS_STATUS_INPUT = 0x7C, ++ PMBUS_STATUS_TEMPERATURE = 0x7D, ++ PMBUS_STATUS_CML = 0x7E, ++ PMBUS_STATUS_OTHER = 0x7F, ++ PMBUS_STATUS_MFR_SPECIFIC = 0x80, ++ PMBUS_STATUS_FAN_12 = 0x81, ++ PMBUS_STATUS_FAN_34 = 0x82, ++ ++ PMBUS_READ_VIN = 0x88, ++ PMBUS_READ_IIN = 0x89, ++ PMBUS_READ_VCAP = 0x8A, ++ PMBUS_READ_VOUT = 0x8B, ++ PMBUS_READ_IOUT = 0x8C, ++ PMBUS_READ_TEMPERATURE_1 = 0x8D, ++ PMBUS_READ_TEMPERATURE_2 = 0x8E, ++ PMBUS_READ_TEMPERATURE_3 = 0x8F, ++ PMBUS_READ_FAN_SPEED_1 = 0x90, ++ PMBUS_READ_FAN_SPEED_2 = 0x91, ++ PMBUS_READ_FAN_SPEED_3 = 0x92, ++ PMBUS_READ_FAN_SPEED_4 = 0x93, ++ PMBUS_READ_DUTY_CYCLE = 0x94, ++ PMBUS_READ_FREQUENCY = 0x95, ++ PMBUS_READ_POUT = 0x96, ++ PMBUS_READ_PIN = 0x97, ++ ++ PMBUS_REVISION = 0x98, ++ PMBUS_MFR_ID = 0x99, ++ PMBUS_MFR_MODEL = 0x9A, ++ PMBUS_MFR_REVISION = 0x9B, ++ PMBUS_MFR_LOCATION = 0x9C, ++ PMBUS_MFR_DATE = 0x9D, ++ PMBUS_MFR_SERIAL = 0x9E, ++ ++ PMBUS_MFR_VIN_MIN = 0xA0, ++ PMBUS_MFR_VIN_MAX = 0xA1, ++ PMBUS_MFR_IIN_MAX = 0xA2, ++ PMBUS_MFR_PIN_MAX = 0xA3, ++ PMBUS_MFR_VOUT_MIN = 0xA4, ++ PMBUS_MFR_VOUT_MAX = 0xA5, ++ PMBUS_MFR_IOUT_MAX = 0xA6, ++ PMBUS_MFR_POUT_MAX = 0xA7, ++ ++ PMBUS_IC_DEVICE_ID = 0xAD, ++ PMBUS_IC_DEVICE_REV = 0xAE, ++ ++ PMBUS_MFR_MAX_TEMP_1 = 0xC0, ++ PMBUS_MFR_MAX_TEMP_2 = 0xC1, ++ PMBUS_MFR_MAX_TEMP_3 = 0xC2, ++ ++/* ++ * Virtual registers. ++ * Useful to support attributes which are not supported by standard PMBus ++ * registers but exist as manufacturer specific registers on individual chips. ++ * Must be mapped to real registers in device specific code. ++ * ++ * Semantics: ++ * Virtual registers are all word size. ++ * READ registers are read-only; writes are either ignored or return an error. ++ * RESET registers are read/write. Reading reset registers returns zero ++ * (used for detection), writing any value causes the associated history to be ++ * reset. ++ * Virtual registers have to be handled in device specific driver code. Chip ++ * driver code returns non-negative register values if a virtual register is ++ * supported, or a negative error code if not. The chip driver may return ++ * -ENODATA or any other error code in this case, though an error code other ++ * than -ENODATA is handled more efficiently and thus preferred. Either case, ++ * the calling PMBus core code will abort if the chip driver returns an error ++ * code when reading or writing virtual registers. ++ */ ++ PMBUS_VIRT_BASE = 0x100, ++ PMBUS_VIRT_READ_TEMP_AVG, ++ PMBUS_VIRT_READ_TEMP_MIN, ++ PMBUS_VIRT_READ_TEMP_MAX, ++ PMBUS_VIRT_RESET_TEMP_HISTORY, ++ PMBUS_VIRT_READ_VIN_AVG, ++ PMBUS_VIRT_READ_VIN_MIN, ++ PMBUS_VIRT_READ_VIN_MAX, ++ PMBUS_VIRT_RESET_VIN_HISTORY, ++ PMBUS_VIRT_READ_IIN_AVG, ++ PMBUS_VIRT_READ_IIN_MIN, ++ PMBUS_VIRT_READ_IIN_MAX, ++ PMBUS_VIRT_RESET_IIN_HISTORY, ++ PMBUS_VIRT_READ_PIN_AVG, ++ PMBUS_VIRT_READ_PIN_MIN, ++ PMBUS_VIRT_READ_PIN_MAX, ++ PMBUS_VIRT_RESET_PIN_HISTORY, ++ PMBUS_VIRT_READ_POUT_AVG, ++ PMBUS_VIRT_READ_POUT_MIN, ++ PMBUS_VIRT_READ_POUT_MAX, ++ PMBUS_VIRT_RESET_POUT_HISTORY, ++ PMBUS_VIRT_READ_VOUT_AVG, ++ PMBUS_VIRT_READ_VOUT_MIN, ++ PMBUS_VIRT_READ_VOUT_MAX, ++ PMBUS_VIRT_RESET_VOUT_HISTORY, ++ PMBUS_VIRT_READ_IOUT_AVG, ++ PMBUS_VIRT_READ_IOUT_MIN, ++ PMBUS_VIRT_READ_IOUT_MAX, ++ PMBUS_VIRT_RESET_IOUT_HISTORY, ++ PMBUS_VIRT_READ_TEMP2_AVG, ++ PMBUS_VIRT_READ_TEMP2_MIN, ++ PMBUS_VIRT_READ_TEMP2_MAX, ++ PMBUS_VIRT_RESET_TEMP2_HISTORY, ++ ++ PMBUS_VIRT_READ_VMON, ++ PMBUS_VIRT_VMON_UV_WARN_LIMIT, ++ PMBUS_VIRT_VMON_OV_WARN_LIMIT, ++ PMBUS_VIRT_VMON_UV_FAULT_LIMIT, ++ PMBUS_VIRT_VMON_OV_FAULT_LIMIT, ++ PMBUS_VIRT_STATUS_VMON, ++ ++ /* ++ * RPM and PWM Fan control ++ * ++ * Drivers wanting to expose PWM control must define the behaviour of ++ * PMBUS_VIRT_PWM_[1-4] and PMBUS_VIRT_PWM_ENABLE_[1-4] in the ++ * {read,write}_word_data callback. ++ * ++ * pmbus core provides a default implementation for ++ * PMBUS_VIRT_FAN_TARGET_[1-4]. ++ * ++ * TARGET, PWM and PWM_ENABLE members must be defined sequentially; ++ * pmbus core uses the difference between the provided register and ++ * it's _1 counterpart to calculate the FAN/PWM ID. ++ */ ++ PMBUS_VIRT_FAN_TARGET_1, ++ PMBUS_VIRT_FAN_TARGET_2, ++ PMBUS_VIRT_FAN_TARGET_3, ++ PMBUS_VIRT_FAN_TARGET_4, ++ PMBUS_VIRT_PWM_1, ++ PMBUS_VIRT_PWM_2, ++ PMBUS_VIRT_PWM_3, ++ PMBUS_VIRT_PWM_4, ++ PMBUS_VIRT_PWM_ENABLE_1, ++ PMBUS_VIRT_PWM_ENABLE_2, ++ PMBUS_VIRT_PWM_ENABLE_3, ++ PMBUS_VIRT_PWM_ENABLE_4, ++ ++ /* Samples for average ++ * ++ * Drivers wanting to expose functionality for changing the number of ++ * samples used for average values should implement support in ++ * {read,write}_word_data callback for either PMBUS_VIRT_SAMPLES if it ++ * applies to all types of measurements, or any number of specific ++ * PMBUS_VIRT_*_SAMPLES registers to allow for individual control. ++ */ ++ PMBUS_VIRT_SAMPLES, ++ PMBUS_VIRT_IN_SAMPLES, ++ PMBUS_VIRT_CURR_SAMPLES, ++ PMBUS_VIRT_POWER_SAMPLES, ++ PMBUS_VIRT_TEMP_SAMPLES, ++}; ++ ++/* ++ * OPERATION ++ */ ++#define PB_OPERATION_CONTROL_ON BIT(7) ++ ++/* ++ * WRITE_PROTECT ++ */ ++#define PB_WP_ALL BIT(7) /* all but WRITE_PROTECT */ ++#define PB_WP_OP BIT(6) /* all but WP, OPERATION, PAGE */ ++#define PB_WP_VOUT BIT(5) /* all but WP, OPERATION, PAGE, VOUT, ON_OFF */ ++ ++#define PB_WP_ANY (PB_WP_ALL | PB_WP_OP | PB_WP_VOUT) ++ ++/* ++ * CAPABILITY ++ */ ++#define PB_CAPABILITY_SMBALERT BIT(4) ++#define PB_CAPABILITY_ERROR_CHECK BIT(7) ++ ++/* ++ * VOUT_MODE ++ */ ++#define PB_VOUT_MODE_MODE_MASK 0xe0 ++#define PB_VOUT_MODE_PARAM_MASK 0x1f ++ ++#define PB_VOUT_MODE_LINEAR 0x00 ++#define PB_VOUT_MODE_VID 0x20 ++#define PB_VOUT_MODE_DIRECT 0x40 ++ ++/* ++ * Fan configuration ++ */ ++#define PB_FAN_2_PULSE_MASK (BIT(0) | BIT(1)) ++#define PB_FAN_2_RPM BIT(2) ++#define PB_FAN_2_INSTALLED BIT(3) ++#define PB_FAN_1_PULSE_MASK (BIT(4) | BIT(5)) ++#define PB_FAN_1_RPM BIT(6) ++#define PB_FAN_1_INSTALLED BIT(7) ++ ++enum pmbus_fan_mode { percent = 0, rpm }; ++ ++/* ++ * STATUS_BYTE, STATUS_WORD (lower) ++ */ ++#define PB_STATUS_NONE_ABOVE BIT(0) ++#define PB_STATUS_CML BIT(1) ++#define PB_STATUS_TEMPERATURE BIT(2) ++#define PB_STATUS_VIN_UV BIT(3) ++#define PB_STATUS_IOUT_OC BIT(4) ++#define PB_STATUS_VOUT_OV BIT(5) ++#define PB_STATUS_OFF BIT(6) ++#define PB_STATUS_BUSY BIT(7) ++ ++/* ++ * STATUS_WORD (upper) ++ */ ++#define PB_STATUS_UNKNOWN BIT(8) ++#define PB_STATUS_OTHER BIT(9) ++#define PB_STATUS_FANS BIT(10) ++#define PB_STATUS_POWER_GOOD_N BIT(11) ++#define PB_STATUS_WORD_MFR BIT(12) ++#define PB_STATUS_INPUT BIT(13) ++#define PB_STATUS_IOUT_POUT BIT(14) ++#define PB_STATUS_VOUT BIT(15) ++ ++/* ++ * STATUS_IOUT ++ */ ++#define PB_POUT_OP_WARNING BIT(0) ++#define PB_POUT_OP_FAULT BIT(1) ++#define PB_POWER_LIMITING BIT(2) ++#define PB_CURRENT_SHARE_FAULT BIT(3) ++#define PB_IOUT_UC_FAULT BIT(4) ++#define PB_IOUT_OC_WARNING BIT(5) ++#define PB_IOUT_OC_LV_FAULT BIT(6) ++#define PB_IOUT_OC_FAULT BIT(7) ++ ++/* ++ * STATUS_VOUT, STATUS_INPUT ++ */ ++#define PB_VOLTAGE_UV_FAULT BIT(4) ++#define PB_VOLTAGE_UV_WARNING BIT(5) ++#define PB_VOLTAGE_OV_WARNING BIT(6) ++#define PB_VOLTAGE_OV_FAULT BIT(7) ++ ++/* ++ * STATUS_INPUT ++ */ ++#define PB_PIN_OP_WARNING BIT(0) ++#define PB_IIN_OC_WARNING BIT(1) ++#define PB_IIN_OC_FAULT BIT(2) ++ ++/* ++ * STATUS_TEMPERATURE ++ */ ++#define PB_TEMP_UT_FAULT BIT(4) ++#define PB_TEMP_UT_WARNING BIT(5) ++#define PB_TEMP_OT_WARNING BIT(6) ++#define PB_TEMP_OT_FAULT BIT(7) ++ ++/* ++ * STATUS_FAN ++ */ ++#define PB_FAN_AIRFLOW_WARNING BIT(0) ++#define PB_FAN_AIRFLOW_FAULT BIT(1) ++#define PB_FAN_FAN2_SPEED_OVERRIDE BIT(2) ++#define PB_FAN_FAN1_SPEED_OVERRIDE BIT(3) ++#define PB_FAN_FAN2_WARNING BIT(4) ++#define PB_FAN_FAN1_WARNING BIT(5) ++#define PB_FAN_FAN2_FAULT BIT(6) ++#define PB_FAN_FAN1_FAULT BIT(7) ++ ++/* ++ * CML_FAULT_STATUS ++ */ ++#define PB_CML_FAULT_OTHER_MEM_LOGIC BIT(0) ++#define PB_CML_FAULT_OTHER_COMM BIT(1) ++#define PB_CML_FAULT_PROCESSOR BIT(3) ++#define PB_CML_FAULT_MEMORY BIT(4) ++#define PB_CML_FAULT_PACKET_ERROR BIT(5) ++#define PB_CML_FAULT_INVALID_DATA BIT(6) ++#define PB_CML_FAULT_INVALID_COMMAND BIT(7) ++ ++enum pmbus_sensor_classes { ++ PSC_VOLTAGE_IN = 0, ++ PSC_VOLTAGE_OUT, ++ PSC_CURRENT_IN, ++ PSC_CURRENT_OUT, ++ PSC_POWER, ++ PSC_TEMPERATURE, ++ PSC_FAN, ++ PSC_PWM, ++ PSC_NUM_CLASSES /* Number of power sensor classes */ ++}; ++ ++#define PMBUS_PAGES 32 /* Per PMBus specification */ ++#define PMBUS_PHASES 8 /* Maximum number of phases per page */ ++ ++/* Functionality bit mask */ ++#define PMBUS_HAVE_VIN BIT(0) ++#define PMBUS_HAVE_VCAP BIT(1) ++#define PMBUS_HAVE_VOUT BIT(2) ++#define PMBUS_HAVE_IIN BIT(3) ++#define PMBUS_HAVE_IOUT BIT(4) ++#define PMBUS_HAVE_PIN BIT(5) ++#define PMBUS_HAVE_POUT BIT(6) ++#define PMBUS_HAVE_FAN12 BIT(7) ++#define PMBUS_HAVE_FAN34 BIT(8) ++#define PMBUS_HAVE_TEMP BIT(9) ++#define PMBUS_HAVE_TEMP2 BIT(10) ++#define PMBUS_HAVE_TEMP3 BIT(11) ++#define PMBUS_HAVE_STATUS_VOUT BIT(12) ++#define PMBUS_HAVE_STATUS_IOUT BIT(13) ++#define PMBUS_HAVE_STATUS_INPUT BIT(14) ++#define PMBUS_HAVE_STATUS_TEMP BIT(15) ++#define PMBUS_HAVE_STATUS_FAN12 BIT(16) ++#define PMBUS_HAVE_STATUS_FAN34 BIT(17) ++#define PMBUS_HAVE_VMON BIT(18) ++#define PMBUS_HAVE_STATUS_VMON BIT(19) ++#define PMBUS_HAVE_PWM12 BIT(20) ++#define PMBUS_HAVE_PWM34 BIT(21) ++#define PMBUS_HAVE_SAMPLES BIT(22) ++ ++#define PMBUS_PHASE_VIRTUAL BIT(30) /* Phases on this page are virtual */ ++#define PMBUS_PAGE_VIRTUAL BIT(31) /* Page is virtual */ ++ ++enum pmbus_data_format { linear = 0, direct, vid }; ++enum vrm_version { vr11 = 0, vr12, vr13, imvp9, amd625mv }; ++ ++struct pmbus_driver_info { ++ int pages; /* Total number of pages */ ++ u8 phases[PMBUS_PAGES]; /* Number of phases per page */ ++ enum pmbus_data_format format[PSC_NUM_CLASSES]; ++ enum vrm_version vrm_version[PMBUS_PAGES]; /* vrm version per page */ ++ /* ++ * Support one set of coefficients for each sensor type ++ * Used for chips providing data in direct mode. ++ */ ++ int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */ ++ int b[PSC_NUM_CLASSES]; /* offset */ ++ int R[PSC_NUM_CLASSES]; /* exponent */ ++ ++ u32 func[PMBUS_PAGES]; /* Functionality, per page */ ++ u32 pfunc[PMBUS_PHASES];/* Functionality, per phase */ ++ /* ++ * The following functions map manufacturing specific register values ++ * to PMBus standard register values. Specify only if mapping is ++ * necessary. ++ * Functions return the register value (read) or zero (write) if ++ * successful. A return value of -ENODATA indicates that there is no ++ * manufacturer specific register, but that a standard PMBus register ++ * may exist. Any other negative return value indicates that the ++ * register does not exist, and that no attempt should be made to read ++ * the standard register. ++ */ ++ int (*read_byte_data)(struct i2c_client *client, int page, int reg); ++ int (*read_word_data)(struct i2c_client *client, int page, int phase, ++ int reg); ++ int (*write_word_data)(struct i2c_client *client, int page, int reg, ++ u16 word); ++ int (*write_byte)(struct i2c_client *client, int page, u8 value); ++ /* ++ * The identify function determines supported PMBus functionality. ++ * This function is only necessary if a chip driver supports multiple ++ * chips, and the chip functionality is not pre-determined. ++ */ ++ int (*identify)(struct i2c_client *client, ++ struct pmbus_driver_info *info); ++ ++ /* Regulator functionality, if supported by this chip driver. */ ++ int num_regulators; ++ const struct regulator_desc *reg_desc; ++ ++ /* custom attributes */ ++ const struct attribute_group **groups; ++}; ++ ++/* Regulator ops */ ++ ++extern const struct regulator_ops wb_pmbus_regulator_ops; ++ ++/* Macro for filling in array of struct regulator_desc */ ++#define PMBUS_REGULATOR(_name, _id) \ ++ [_id] = { \ ++ .name = (_name # _id), \ ++ .id = (_id), \ ++ .of_match = of_match_ptr(_name # _id), \ ++ .regulators_node = of_match_ptr("regulators"), \ ++ .ops = &wb_pmbus_regulator_ops, \ ++ .type = REGULATOR_VOLTAGE, \ ++ .owner = THIS_MODULE, \ ++ } ++ ++struct pmbus_data { ++ struct device *dev; ++ struct device *hwmon_dev; ++ ++ u32 flags; /* from platform data */ ++ ++ int exponent[PMBUS_PAGES]; /* linear mode: exponent for output voltages */ ++ ++ const struct pmbus_driver_info *info; ++ ++ int max_attributes; ++ int num_attributes; ++ struct attribute_group group; ++ const struct attribute_group **groups; ++ struct dentry *debugfs; /* debugfs device directory */ ++ ++ struct pmbus_sensor *sensors; ++ ++ struct mutex update_lock; ++ ++ bool has_status_word; /* device uses STATUS_WORD register */ ++ int (*read_status)(struct i2c_client *client, int page); ++ ++ s16 currpage; /* current page, -1 for unknown/unset */ ++ s16 currphase; /* current phase, 0xff for all, -1 for unknown/unset */ ++ int vout_max[PMBUS_PAGES]; /* pmbus maximum output voltage */ ++ int vout_min[PMBUS_PAGES]; /* pmbus minimum output voltage */ ++}; ++ ++/* Function declarations */ ++void wb_pmbus_clear_cache(struct i2c_client *client); ++int wb_pmbus_set_page(struct i2c_client *client, int page, int phase); ++int wb_pmbus_read_word_data(struct i2c_client *client, int page, int phase, ++ u8 reg); ++int wb_pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, ++ u16 word); ++int wb_pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg); ++int wb_pmbus_write_byte(struct i2c_client *client, int page, u8 value); ++int wb_pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, ++ u8 value); ++int wb_pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, ++ u8 mask, u8 value); ++void wb_pmbus_clear_faults(struct i2c_client *client); ++bool wb_pmbus_check_byte_register(struct i2c_client *client, int page, int reg); ++bool wb_pmbus_check_word_register(struct i2c_client *client, int page, int reg); ++int wb_pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info); ++int wb_pmbus_do_remove(struct i2c_client *client); ++const struct pmbus_driver_info *wb_pmbus_get_driver_info(struct i2c_client ++ *client); ++int wb_pmbus_get_fan_rate_device(struct i2c_client *client, int page, int id, ++ enum pmbus_fan_mode mode); ++int wb_pmbus_get_fan_rate_cached(struct i2c_client *client, int page, int id, ++ enum pmbus_fan_mode mode); ++int wb_pmbus_update_fan(struct i2c_client *client, int page, int id, ++ u8 config, u8 mask, u16 command); ++struct dentry *wb_pmbus_get_debugfs_dir(struct i2c_client *client); ++ ++#endif /* WB_PMBUS_H */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus_core.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus_core.c +new file mode 100644 +index 000000000..343aea446 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus_core.c +@@ -0,0 +1,2780 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Hardware monitoring driver for PMBus devices ++ * ++ * Copyright (c) 2010, 2011 Ericsson AB. ++ * Copyright (c) 2012 Guenter Roeck ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "wb_pmbus.h" ++ ++/* ++ * Number of additional attribute pointers to allocate ++ * with each call to krealloc ++ */ ++#define PMBUS_ATTR_ALLOC_SIZE (32) ++#define PMBUS_NAME_SIZE (24) ++#define PMBUS_RETRY_SLEEP_TIME (10000) /* 10ms */ ++#define PMBUS_RETRY_TIME (3) ++ ++struct pmbus_sensor { ++ struct pmbus_sensor *next; ++ char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */ ++ struct device_attribute attribute; ++ u8 page; /* page number */ ++ u8 phase; /* phase number, 0xff for all phases */ ++ u16 reg; /* register */ ++ enum pmbus_sensor_classes class; /* sensor class */ ++ bool update; /* runtime sensor update needed */ ++ bool convert; /* Whether or not to apply linear/vid/direct */ ++ int data; /* Sensor data. ++ Negative if there was a read error */ ++}; ++#define to_pmbus_sensor(_attr) \ ++ container_of(_attr, struct pmbus_sensor, attribute) ++ ++struct pmbus_boolean { ++ char name[PMBUS_NAME_SIZE]; /* sysfs boolean name */ ++ struct sensor_device_attribute attribute; ++ struct pmbus_sensor *s1; ++ struct pmbus_sensor *s2; ++}; ++#define to_pmbus_boolean(_attr) \ ++ container_of(_attr, struct pmbus_boolean, attribute) ++ ++struct pmbus_label { ++ char name[PMBUS_NAME_SIZE]; /* sysfs label name */ ++ struct device_attribute attribute; ++ char label[PMBUS_NAME_SIZE]; /* label */ ++}; ++#define to_pmbus_label(_attr) \ ++ container_of(_attr, struct pmbus_label, attribute) ++ ++/* Macros for converting between sensor index and register/page/status mask */ ++ ++#define PB_STATUS_MASK 0xffff ++#define PB_REG_SHIFT 16 ++#define PB_REG_MASK 0x3ff ++#define PB_PAGE_SHIFT 26 ++#define PB_PAGE_MASK 0x3f ++ ++#define pb_reg_to_index(page, reg, mask) (((page) << PB_PAGE_SHIFT) | \ ++ ((reg) << PB_REG_SHIFT) | (mask)) ++ ++#define pb_index_to_page(index) (((index) >> PB_PAGE_SHIFT) & PB_PAGE_MASK) ++#define pb_index_to_reg(index) (((index) >> PB_REG_SHIFT) & PB_REG_MASK) ++#define pb_index_to_mask(index) ((index) & PB_STATUS_MASK) ++ ++struct pmbus_debugfs_entry { ++ struct i2c_client *client; ++ u8 page; ++ u8 reg; ++}; ++ ++static const int pmbus_fan_rpm_mask[] = { ++ PB_FAN_1_RPM, ++ PB_FAN_2_RPM, ++ PB_FAN_1_RPM, ++ PB_FAN_2_RPM, ++}; ++ ++static const int pmbus_fan_config_registers[] = { ++ PMBUS_FAN_CONFIG_12, ++ PMBUS_FAN_CONFIG_12, ++ PMBUS_FAN_CONFIG_34, ++ PMBUS_FAN_CONFIG_34 ++}; ++ ++static const int pmbus_fan_command_registers[] = { ++ PMBUS_FAN_COMMAND_1, ++ PMBUS_FAN_COMMAND_2, ++ PMBUS_FAN_COMMAND_3, ++ PMBUS_FAN_COMMAND_4, ++}; ++ ++void wb_pmbus_clear_cache(struct i2c_client *client) ++{ ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ struct pmbus_sensor *sensor; ++ ++ for (sensor = data->sensors; sensor; sensor = sensor->next) ++ sensor->data = -ENODATA; ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_clear_cache); ++ ++static int wb_pmbus_set_page_tmp(struct i2c_client *client, int page, int phase) ++{ ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ int rv; ++ ++ if (page < 0) ++ return 0; ++ ++ if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL) && ++ data->info->pages > 1 && page != data->currpage) { ++ rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); ++ if (rv < 0) ++ return rv; ++ ++ rv = i2c_smbus_read_byte_data(client, PMBUS_PAGE); ++ if (rv < 0) ++ return rv; ++ ++ if (rv != page) ++ return -EIO; ++ } ++ data->currpage = page; ++ ++ if (data->info->phases[page] && data->currphase != phase && ++ !(data->info->func[page] & PMBUS_PHASE_VIRTUAL)) { ++ rv = i2c_smbus_write_byte_data(client, PMBUS_PHASE, ++ phase); ++ if (rv) ++ return rv; ++ } ++ data->currphase = phase; ++ ++ return 0; ++} ++ ++int wb_pmbus_set_page(struct i2c_client *client, int page, int phase) ++{ ++ int rv, i; ++ struct device *dev = &client->dev; ++ ++ for (i = 0; i < PMBUS_RETRY_TIME; i++) { ++ rv = wb_pmbus_set_page_tmp(client, page, phase); ++ if(rv >= 0){ ++ return rv; ++ } ++ if ((i + 1) < PMBUS_RETRY_TIME) { ++ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); ++ } ++ } ++ dev_dbg(dev, "wb_pmbus_set_page failed, page=%d, phase=%d, rv=%d\n", ++ page, phase, rv); ++ return rv; ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_set_page); ++ ++static int wb_pmbus_write_byte_tmp(struct i2c_client *client, int page, u8 value) ++{ ++ int rv; ++ ++ rv = wb_pmbus_set_page(client, page, 0xff); ++ if (rv < 0) ++ return rv; ++ ++ return i2c_smbus_write_byte(client, value); ++} ++ ++int wb_pmbus_write_byte(struct i2c_client *client, int page, u8 value) ++{ ++ int rv, i; ++ struct device *dev = &client->dev; ++ ++ for (i = 0; i < PMBUS_RETRY_TIME; i++) { ++ rv = wb_pmbus_write_byte_tmp(client, page, value); ++ if(rv >= 0){ ++ return rv; ++ } ++ if ((i + 1) < PMBUS_RETRY_TIME) { ++ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); ++ } ++ } ++ dev_dbg(dev, "wb_pmbus_write_byte failed, page=%d, value=0x%x, rv: %d\n", ++ page, value, rv); ++ return rv; ++} ++ ++EXPORT_SYMBOL_GPL(wb_pmbus_write_byte); ++ ++/* ++ * _pmbus_write_byte() is similar to pmbus_write_byte(), but checks if ++ * a device specific mapping function exists and calls it if necessary. ++ */ ++static int _pmbus_write_byte(struct i2c_client *client, int page, u8 value) ++{ ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ const struct pmbus_driver_info *info = data->info; ++ int status; ++ ++ if (info->write_byte) { ++ status = info->write_byte(client, page, value); ++ if (status != -ENODATA) ++ return status; ++ } ++ return wb_pmbus_write_byte(client, page, value); ++} ++ ++static int wb_pmbus_write_word_data_tmp(struct i2c_client *client, int page, u8 reg, ++ u16 word) ++{ ++ int rv; ++ ++ rv = wb_pmbus_set_page(client, page, 0xff); ++ if (rv < 0) ++ return rv; ++ ++ return i2c_smbus_write_word_data(client, reg, word); ++} ++ ++int wb_pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, ++ u16 word) ++{ ++ int rv, i; ++ struct device *dev = &client->dev; ++ ++ for (i = 0; i < PMBUS_RETRY_TIME; i++) { ++ rv = wb_pmbus_write_word_data_tmp(client, page, reg, word); ++ if(rv >= 0){ ++ return rv; ++ } ++ if ((i + 1) < PMBUS_RETRY_TIME) { ++ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); ++ } ++ } ++ dev_dbg(dev, "wb_pmbus_write_word_data failed, page: %d, reg: 0x%x, value: 0x%x, rv: %d\n", ++ page, reg, word, rv); ++ return rv; ++ ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_write_word_data); ++ ++static int pmbus_write_virt_reg(struct i2c_client *client, int page, int reg, ++ u16 word) ++{ ++ int bit; ++ int id; ++ int rv; ++ ++ switch (reg) { ++ case PMBUS_VIRT_FAN_TARGET_1 ... PMBUS_VIRT_FAN_TARGET_4: ++ id = reg - PMBUS_VIRT_FAN_TARGET_1; ++ bit = pmbus_fan_rpm_mask[id]; ++ rv = wb_pmbus_update_fan(client, page, id, bit, bit, word); ++ break; ++ default: ++ rv = -ENXIO; ++ break; ++ } ++ ++ return rv; ++} ++ ++/* ++ * _pmbus_write_word_data() is similar to pmbus_write_word_data(), but checks if ++ * a device specific mapping function exists and calls it if necessary. ++ */ ++static int _pmbus_write_word_data(struct i2c_client *client, int page, int reg, ++ u16 word) ++{ ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ const struct pmbus_driver_info *info = data->info; ++ int status; ++ ++ if (info->write_word_data) { ++ status = info->write_word_data(client, page, reg, word); ++ if (status != -ENODATA) ++ return status; ++ } ++ ++ if (reg >= PMBUS_VIRT_BASE) ++ return pmbus_write_virt_reg(client, page, reg, word); ++ ++ return wb_pmbus_write_word_data(client, page, reg, word); ++} ++ ++int wb_pmbus_update_fan(struct i2c_client *client, int page, int id, ++ u8 config, u8 mask, u16 command) ++{ ++ int from; ++ int rv; ++ u8 to; ++ ++ from = wb_pmbus_read_byte_data(client, page, ++ pmbus_fan_config_registers[id]); ++ if (from < 0) ++ return from; ++ ++ to = (from & ~mask) | (config & mask); ++ if (to != from) { ++ rv = wb_pmbus_write_byte_data(client, page, ++ pmbus_fan_config_registers[id], to); ++ if (rv < 0) ++ return rv; ++ } ++ ++ return _pmbus_write_word_data(client, page, ++ pmbus_fan_command_registers[id], command); ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_update_fan); ++ ++static int wb_pmbus_read_word_data_tmp(struct i2c_client *client, int page, int phase, u8 reg) ++{ ++ int rv; ++ ++ rv = wb_pmbus_set_page(client, page, phase); ++ if (rv < 0) ++ return rv; ++ ++ return i2c_smbus_read_word_data(client, reg); ++} ++ ++int wb_pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg) ++{ ++ int rv, i; ++ struct device *dev = &client->dev; ++ ++ for (i = 0; i < PMBUS_RETRY_TIME; i++) { ++ rv = wb_pmbus_read_word_data_tmp(client, page, phase, reg); ++ if(rv >= 0){ ++ return rv; ++ } ++ if ((i + 1) < PMBUS_RETRY_TIME) { ++ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); ++ } ++ } ++ dev_dbg(dev, "wb_pmbus_read_word_data failed, page: %d, phase: %d, reg: 0x%x, rv: %d\n", ++ page, phase, reg, rv); ++ return rv; ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_read_word_data); ++ ++static int pmbus_read_virt_reg(struct i2c_client *client, int page, int reg) ++{ ++ int rv; ++ int id; ++ ++ switch (reg) { ++ case PMBUS_VIRT_FAN_TARGET_1 ... PMBUS_VIRT_FAN_TARGET_4: ++ id = reg - PMBUS_VIRT_FAN_TARGET_1; ++ rv = wb_pmbus_get_fan_rate_device(client, page, id, rpm); ++ break; ++ default: ++ rv = -ENXIO; ++ break; ++ } ++ ++ return rv; ++} ++ ++/* ++ * _pmbus_read_word_data() is similar to wb_pmbus_read_word_data(), but checks if ++ * a device specific mapping function exists and calls it if necessary. ++ */ ++static int _pmbus_read_word_data(struct i2c_client *client, int page, ++ int phase, int reg) ++{ ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ const struct pmbus_driver_info *info = data->info; ++ int status; ++ ++ if (info->read_word_data) { ++ status = info->read_word_data(client, page, phase, reg); ++ if (status != -ENODATA) ++ return status; ++ } ++ ++ if (reg >= PMBUS_VIRT_BASE) ++ return pmbus_read_virt_reg(client, page, reg); ++ ++ return wb_pmbus_read_word_data(client, page, phase, reg); ++} ++ ++/* Same as above, but without phase parameter, for use in check functions */ ++static int __pmbus_read_word_data(struct i2c_client *client, int page, int reg) ++{ ++ return _pmbus_read_word_data(client, page, 0xff, reg); ++} ++ ++static int wb_pmbus_read_byte_data_tmp(struct i2c_client *client, int page, u8 reg) ++{ ++ int rv; ++ ++ rv = wb_pmbus_set_page(client, page, 0xff); ++ if (rv < 0) ++ return rv; ++ ++ return i2c_smbus_read_byte_data(client, reg); ++} ++ ++int wb_pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg) ++{ ++ int rv, i; ++ struct device *dev = &client->dev; ++ ++ for (i = 0; i < PMBUS_RETRY_TIME; i++) { ++ rv = wb_pmbus_read_byte_data_tmp(client, page, reg); ++ if(rv >= 0){ ++ return rv; ++ } ++ if ((i + 1) < PMBUS_RETRY_TIME) { ++ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); ++ } ++ } ++ dev_dbg(dev, "wb_pmbus_read_byte_data failed, page: %d, reg: 0x%x, rv: %d\n", ++ page, reg, rv); ++ return rv; ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_read_byte_data); ++ ++static int wb_pmbus_write_byte_data_tmp(struct i2c_client *client, int page, u8 reg, u8 value) ++{ ++ int rv; ++ ++ rv = wb_pmbus_set_page(client, page, 0xff); ++ if (rv < 0) ++ return rv; ++ ++ return i2c_smbus_write_byte_data(client, reg, value); ++} ++ ++int wb_pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value) ++{ ++ int rv, i; ++ struct device *dev = &client->dev; ++ ++ for (i = 0; i < PMBUS_RETRY_TIME; i++) { ++ rv = wb_pmbus_write_byte_data_tmp(client, page, reg, value); ++ if(rv >= 0){ ++ return rv; ++ } ++ if ((i + 1) < PMBUS_RETRY_TIME) { ++ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); ++ } ++ } ++ dev_dbg(dev, "wb_pmbus_write_byte_data failed, page: %d, reg: 0x%x, value: 0x%x, rv: %d\n", ++ page, reg, value, rv); ++ return rv; ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_write_byte_data); ++ ++int wb_pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, ++ u8 mask, u8 value) ++{ ++ unsigned int tmp; ++ int rv; ++ ++ rv = wb_pmbus_read_byte_data(client, page, reg); ++ if (rv < 0) ++ return rv; ++ ++ tmp = (rv & ~mask) | (value & mask); ++ ++ if (tmp != rv) ++ rv = wb_pmbus_write_byte_data(client, page, reg, tmp); ++ ++ return rv; ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_update_byte_data); ++ ++/* ++ * _pmbus_read_byte_data() is similar to wb_pmbus_read_byte_data(), but checks if ++ * a device specific mapping function exists and calls it if necessary. ++ */ ++static int _pmbus_read_byte_data(struct i2c_client *client, int page, int reg) ++{ ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ const struct pmbus_driver_info *info = data->info; ++ int status; ++ ++ if (info->read_byte_data) { ++ status = info->read_byte_data(client, page, reg); ++ if (status != -ENODATA) ++ return status; ++ } ++ return wb_pmbus_read_byte_data(client, page, reg); ++} ++ ++static struct pmbus_sensor *pmbus_find_sensor(struct pmbus_data *data, int page, ++ int reg) ++{ ++ struct pmbus_sensor *sensor; ++ ++ for (sensor = data->sensors; sensor; sensor = sensor->next) { ++ if (sensor->page == page && sensor->reg == reg) ++ return sensor; ++ } ++ ++ return ERR_PTR(-EINVAL); ++} ++ ++static int pmbus_get_fan_rate(struct i2c_client *client, int page, int id, ++ enum pmbus_fan_mode mode, ++ bool from_cache) ++{ ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ bool want_rpm, have_rpm; ++ struct pmbus_sensor *s; ++ int config; ++ int reg; ++ ++ want_rpm = (mode == rpm); ++ ++ if (from_cache) { ++ reg = want_rpm ? PMBUS_VIRT_FAN_TARGET_1 : PMBUS_VIRT_PWM_1; ++ s = pmbus_find_sensor(data, page, reg + id); ++ if (IS_ERR(s)) ++ return PTR_ERR(s); ++ ++ return s->data; ++ } ++ ++ config = wb_pmbus_read_byte_data(client, page, ++ pmbus_fan_config_registers[id]); ++ if (config < 0) ++ return config; ++ ++ have_rpm = !!(config & pmbus_fan_rpm_mask[id]); ++ if (want_rpm == have_rpm) ++ return wb_pmbus_read_word_data(client, page, 0xff, ++ pmbus_fan_command_registers[id]); ++ ++ /* Can't sensibly map between RPM and PWM, just return zero */ ++ return 0; ++} ++ ++int wb_pmbus_get_fan_rate_device(struct i2c_client *client, int page, int id, ++ enum pmbus_fan_mode mode) ++{ ++ return pmbus_get_fan_rate(client, page, id, mode, false); ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_get_fan_rate_device); ++ ++int wb_pmbus_get_fan_rate_cached(struct i2c_client *client, int page, int id, ++ enum pmbus_fan_mode mode) ++{ ++ return pmbus_get_fan_rate(client, page, id, mode, true); ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_get_fan_rate_cached); ++ ++static void pmbus_clear_fault_page(struct i2c_client *client, int page) ++{ ++ _pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); ++} ++ ++void wb_pmbus_clear_faults(struct i2c_client *client) ++{ ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ int i; ++ ++ for (i = 0; i < data->info->pages; i++) ++ pmbus_clear_fault_page(client, i); ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_clear_faults); ++ ++static int pmbus_check_status_cml(struct i2c_client *client) ++{ ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ int status, status2; ++ ++ status = data->read_status(client, -1); ++ if (status < 0 || (status & PB_STATUS_CML)) { ++ status2 = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML); ++ if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND)) ++ return -EIO; ++ } ++ return 0; ++} ++ ++static bool pmbus_check_register(struct i2c_client *client, ++ int (*func)(struct i2c_client *client, ++ int page, int reg), ++ int page, int reg) ++{ ++ int rv; ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ ++ rv = func(client, page, reg); ++ if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK)) ++ rv = pmbus_check_status_cml(client); ++ pmbus_clear_fault_page(client, -1); ++ return rv >= 0; ++} ++ ++static bool pmbus_check_status_register(struct i2c_client *client, int page) ++{ ++ int status; ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ ++ status = data->read_status(client, page); ++ if (status >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK) && ++ (status & PB_STATUS_CML)) { ++ status = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML); ++ if (status < 0 || (status & PB_CML_FAULT_INVALID_COMMAND)) ++ status = -EIO; ++ } ++ ++ pmbus_clear_fault_page(client, -1); ++ return status >= 0; ++} ++ ++bool wb_pmbus_check_byte_register(struct i2c_client *client, int page, int reg) ++{ ++ return pmbus_check_register(client, _pmbus_read_byte_data, page, reg); ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_check_byte_register); ++ ++bool wb_pmbus_check_word_register(struct i2c_client *client, int page, int reg) ++{ ++ return pmbus_check_register(client, __pmbus_read_word_data, page, reg); ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_check_word_register); ++ ++const struct pmbus_driver_info *wb_pmbus_get_driver_info(struct i2c_client *client) ++{ ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ ++ return data->info; ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_get_driver_info); ++ ++static int pmbus_read_status_byte(struct i2c_client *client, int page) ++{ ++ return _pmbus_read_byte_data(client, page, PMBUS_STATUS_BYTE); ++} ++ ++static int pmbus_read_status_word(struct i2c_client *client, int page) ++{ ++ return _pmbus_read_word_data(client, page, 0xff, PMBUS_STATUS_WORD); ++} ++ ++static int pmbus_get_status(struct i2c_client *client, int page, int reg) ++{ ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ int status; ++ ++ switch (reg) { ++ case PMBUS_STATUS_WORD: ++ status = data->read_status(client, page); ++ if ((status < 0) || (data->has_status_word && (status == 0xffff)) ++ || (!data->has_status_word && (status == 0xff))) { ++ if (data->has_status_word) { ++ data->read_status = pmbus_read_status_byte; ++ } else { ++ data->read_status = pmbus_read_status_word; ++ } ++ data->has_status_word = !data->has_status_word; ++ status = data->read_status(client, page); ++ } ++ break; ++ default: ++ status = _pmbus_read_byte_data(client, page, reg); ++ break; ++ } ++ if (status < 0) ++ wb_pmbus_clear_faults(client); ++ return status; ++} ++ ++static void pmbus_update_sensor_data(struct i2c_client *client, struct pmbus_sensor *sensor) ++{ ++ if (sensor->data < 0 || sensor->update) ++ sensor->data = _pmbus_read_word_data(client, sensor->page, ++ sensor->phase, sensor->reg); ++} ++ ++/* ++ * Convert linear sensor values to milli- or micro-units ++ * depending on sensor type. ++ */ ++static s64 pmbus_reg2data_linear(struct pmbus_data *data, ++ struct pmbus_sensor *sensor) ++{ ++ s16 exponent; ++ s32 mantissa; ++ s64 val; ++ ++ if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */ ++ exponent = data->exponent[sensor->page]; ++ mantissa = (u16) sensor->data; ++ } else { /* LINEAR11 */ ++ exponent = ((s16)sensor->data) >> 11; ++ mantissa = ((s16)((sensor->data & 0x7ff) << 5)) >> 5; ++ } ++ ++ val = mantissa; ++ ++ /* scale result to milli-units for all sensors except fans */ ++ if (sensor->class != PSC_FAN) ++ val = val * 1000LL; ++ ++ /* scale result to micro-units for power sensors */ ++ if (sensor->class == PSC_POWER) ++ val = val * 1000LL; ++ ++ if (exponent >= 0) ++ val <<= exponent; ++ else ++ val >>= -exponent; ++ ++ return val; ++} ++ ++/* ++ * Convert direct sensor values to milli- or micro-units ++ * depending on sensor type. ++ */ ++static s64 pmbus_reg2data_direct(struct pmbus_data *data, ++ struct pmbus_sensor *sensor) ++{ ++ s64 b, val = (s16)sensor->data; ++ s32 m, R; ++ ++ m = data->info->m[sensor->class]; ++ b = data->info->b[sensor->class]; ++ R = data->info->R[sensor->class]; ++ ++ if (m == 0) ++ return 0; ++ ++ /* X = 1/m * (Y * 10^-R - b) */ ++ R = -R; ++ /* scale result to milli-units for everything but fans */ ++ if (!(sensor->class == PSC_FAN || sensor->class == PSC_PWM)) { ++ R += 3; ++ b *= 1000; ++ } ++ ++ /* scale result to micro-units for power sensors */ ++ if (sensor->class == PSC_POWER) { ++ R += 3; ++ b *= 1000; ++ } ++ ++ while (R > 0) { ++ val *= 10; ++ R--; ++ } ++ while (R < 0) { ++ val = div_s64(val + 5LL, 10L); /* round closest */ ++ R++; ++ } ++ ++ val = div_s64(val - b, m); ++ return val; ++} ++ ++/* ++ * Convert VID sensor values to milli- or micro-units ++ * depending on sensor type. ++ */ ++static s64 pmbus_reg2data_vid(struct pmbus_data *data, ++ struct pmbus_sensor *sensor) ++{ ++ long val = sensor->data; ++ long rv = 0; ++ ++ switch (data->info->vrm_version[sensor->page]) { ++ case vr11: ++ if (val >= 0x02 && val <= 0xb2) ++ rv = DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); ++ break; ++ case vr12: ++ if (val >= 0x01) ++ rv = 250 + (val - 1) * 5; ++ break; ++ case vr13: ++ if (val >= 0x01) ++ rv = 500 + (val - 1) * 10; ++ break; ++ case imvp9: ++ if (val >= 0x01) ++ rv = 200 + (val - 1) * 10; ++ break; ++ case amd625mv: ++ if (val >= 0x0 && val <= 0xd8) ++ rv = DIV_ROUND_CLOSEST(155000 - val * 625, 100); ++ break; ++ } ++ return rv; ++} ++ ++static s64 pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) ++{ ++ s64 val; ++ ++ if (!sensor->convert) ++ return sensor->data; ++ ++ switch (data->info->format[sensor->class]) { ++ case direct: ++ val = pmbus_reg2data_direct(data, sensor); ++ break; ++ case vid: ++ val = pmbus_reg2data_vid(data, sensor); ++ break; ++ case linear: ++ default: ++ val = pmbus_reg2data_linear(data, sensor); ++ break; ++ } ++ return val; ++} ++ ++#define MAX_MANTISSA (1023 * 1000) ++#define MIN_MANTISSA (511 * 1000) ++ ++static u16 pmbus_data2reg_linear(struct pmbus_data *data, ++ struct pmbus_sensor *sensor, s64 val) ++{ ++ s16 exponent = 0, mantissa; ++ bool negative = false; ++ ++ /* simple case */ ++ if (val == 0) ++ return 0; ++ ++ if (sensor->class == PSC_VOLTAGE_OUT) { ++ /* LINEAR16 does not support negative voltages */ ++ if (val < 0) ++ return 0; ++ ++ /* ++ * For a static exponents, we don't have a choice ++ * but to adjust the value to it. ++ */ ++ if (data->exponent[sensor->page] < 0) ++ val <<= -data->exponent[sensor->page]; ++ else ++ val >>= data->exponent[sensor->page]; ++ val = DIV_ROUND_CLOSEST_ULL(val, 1000); ++ return clamp_val(val, 0, 0xffff); ++ } ++ ++ if (val < 0) { ++ negative = true; ++ val = -val; ++ } ++ ++ /* Power is in uW. Convert to mW before converting. */ ++ if (sensor->class == PSC_POWER) ++ val = DIV_ROUND_CLOSEST_ULL(val, 1000); ++ ++ /* ++ * For simplicity, convert fan data to milli-units ++ * before calculating the exponent. ++ */ ++ if (sensor->class == PSC_FAN) ++ val = val * 1000LL; ++ ++ /* Reduce large mantissa until it fits into 10 bit */ ++ while (val >= MAX_MANTISSA && exponent < 15) { ++ exponent++; ++ val >>= 1; ++ } ++ /* Increase small mantissa to improve precision */ ++ while (val < MIN_MANTISSA && exponent > -15) { ++ exponent--; ++ val <<= 1; ++ } ++ ++ /* Convert mantissa from milli-units to units */ ++ mantissa = clamp_val(DIV_ROUND_CLOSEST_ULL(val, 1000), 0, 0x3ff); ++ ++ /* restore sign */ ++ if (negative) ++ mantissa = -mantissa; ++ ++ /* Convert to 5 bit exponent, 11 bit mantissa */ ++ return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800); ++} ++ ++static u16 pmbus_data2reg_direct(struct pmbus_data *data, ++ struct pmbus_sensor *sensor, s64 val) ++{ ++ s64 b; ++ s32 m, R; ++ ++ m = data->info->m[sensor->class]; ++ b = data->info->b[sensor->class]; ++ R = data->info->R[sensor->class]; ++ ++ /* Power is in uW. Adjust R and b. */ ++ if (sensor->class == PSC_POWER) { ++ R -= 3; ++ b *= 1000; ++ } ++ ++ /* Calculate Y = (m * X + b) * 10^R */ ++ if (!(sensor->class == PSC_FAN || sensor->class == PSC_PWM)) { ++ R -= 3; /* Adjust R and b for data in milli-units */ ++ b *= 1000; ++ } ++ val = val * m + b; ++ ++ while (R > 0) { ++ val *= 10; ++ R--; ++ } ++ while (R < 0) { ++ val = div_s64(val + 5LL, 10L); /* round closest */ ++ R++; ++ } ++ ++ return (u16)clamp_val(val, S16_MIN, S16_MAX); ++} ++ ++static u16 pmbus_data2reg_vid(struct pmbus_data *data, ++ struct pmbus_sensor *sensor, s64 val) ++{ ++ val = clamp_val(val, 500, 1600); ++ ++ return 2 + DIV_ROUND_CLOSEST_ULL((1600LL - val) * 100LL, 625); ++} ++ ++static u16 pmbus_data2reg(struct pmbus_data *data, ++ struct pmbus_sensor *sensor, s64 val) ++{ ++ u16 regval; ++ ++ if (!sensor->convert) ++ return val; ++ ++ switch (data->info->format[sensor->class]) { ++ case direct: ++ regval = pmbus_data2reg_direct(data, sensor, val); ++ break; ++ case vid: ++ regval = pmbus_data2reg_vid(data, sensor, val); ++ break; ++ case linear: ++ default: ++ regval = pmbus_data2reg_linear(data, sensor, val); ++ break; ++ } ++ return regval; ++} ++ ++/* ++ * Return boolean calculated from converted data. ++ * defines a status register index and mask. ++ * The mask is in the lower 8 bits, the register index is in bits 8..23. ++ * ++ * The associated pmbus_boolean structure contains optional pointers to two ++ * sensor attributes. If specified, those attributes are compared against each ++ * other to determine if a limit has been exceeded. ++ * ++ * If the sensor attribute pointers are NULL, the function returns true if ++ * (status[reg] & mask) is true. ++ * ++ * If sensor attribute pointers are provided, a comparison against a specified ++ * limit has to be performed to determine the boolean result. ++ * In this case, the function returns true if v1 >= v2 (where v1 and v2 are ++ * sensor values referenced by sensor attribute pointers s1 and s2). ++ * ++ * To determine if an object exceeds upper limits, specify = . ++ * To determine if an object exceeds lower limits, specify = . ++ * ++ * If a negative value is stored in any of the referenced registers, this value ++ * reflects an error code which will be returned. ++ */ ++static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b, ++ int index) ++{ ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ struct pmbus_sensor *s1 = b->s1; ++ struct pmbus_sensor *s2 = b->s2; ++ u16 mask = pb_index_to_mask(index); ++ u8 page = pb_index_to_page(index); ++ u16 reg = pb_index_to_reg(index); ++ int ret, status; ++ u16 regval; ++ ++ mutex_lock(&data->update_lock); ++ status = pmbus_get_status(client, page, reg); ++ if (status < 0) { ++ ret = status; ++ goto unlock; ++ } ++ ++ if (s1) ++ pmbus_update_sensor_data(client, s1); ++ if (s2) ++ pmbus_update_sensor_data(client, s2); ++ ++ regval = status & mask; ++ if (s1 && s2) { ++ s64 v1, v2; ++ ++ if (s1->data < 0) { ++ ret = s1->data; ++ goto unlock; ++ } ++ if (s2->data < 0) { ++ ret = s2->data; ++ goto unlock; ++ } ++ ++ v1 = pmbus_reg2data(data, s1); ++ v2 = pmbus_reg2data(data, s2); ++ ret = !!(regval && v1 >= v2); ++ } else { ++ ret = !!regval; ++ } ++unlock: ++ mutex_unlock(&data->update_lock); ++ return ret; ++} ++ ++static ssize_t pmbus_show_boolean(struct device *dev, ++ struct device_attribute *da, char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); ++ struct pmbus_boolean *boolean = to_pmbus_boolean(attr); ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ int val; ++ ++ val = pmbus_get_boolean(client, boolean, attr->index); ++ if (val < 0) ++ return val; ++ return snprintf(buf, PAGE_SIZE, "%d\n", val); ++} ++ ++static ssize_t pmbus_show_sensor(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ ssize_t ret; ++ ++ mutex_lock(&data->update_lock); ++ pmbus_update_sensor_data(client, sensor); ++ if (sensor->data < 0) ++ ret = sensor->data; ++ else ++ ret = snprintf(buf, PAGE_SIZE, "%lld\n", pmbus_reg2data(data, sensor)); ++ mutex_unlock(&data->update_lock); ++ return ret; ++} ++ ++static ssize_t pmbus_set_sensor(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); ++ ssize_t rv = count; ++ s64 val; ++ int ret; ++ u16 regval; ++ ++ if (kstrtos64(buf, 10, &val) < 0) ++ return -EINVAL; ++ ++ mutex_lock(&data->update_lock); ++ regval = pmbus_data2reg(data, sensor, val); ++ ret = _pmbus_write_word_data(client, sensor->page, sensor->reg, regval); ++ if (ret < 0) ++ rv = ret; ++ else ++ sensor->data = regval; ++ mutex_unlock(&data->update_lock); ++ return rv; ++} ++ ++static ssize_t pmbus_show_label(struct device *dev, ++ struct device_attribute *da, char *buf) ++{ ++ struct pmbus_label *label = to_pmbus_label(da); ++ ++ return snprintf(buf, PAGE_SIZE, "%s\n", label->label); ++} ++ ++static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr) ++{ ++ if (data->num_attributes >= data->max_attributes - 1) { ++ int new_max_attrs = data->max_attributes + PMBUS_ATTR_ALLOC_SIZE; ++ void *new_attrs = devm_krealloc(data->dev, data->group.attrs, ++ new_max_attrs * sizeof(void *), ++ GFP_KERNEL); ++ if (!new_attrs) ++ return -ENOMEM; ++ data->group.attrs = new_attrs; ++ data->max_attributes = new_max_attrs; ++ } ++ ++ data->group.attrs[data->num_attributes++] = attr; ++ data->group.attrs[data->num_attributes] = NULL; ++ return 0; ++} ++ ++static void pmbus_dev_attr_init(struct device_attribute *dev_attr, ++ const char *name, ++ umode_t mode, ++ ssize_t (*show)(struct device *dev, ++ struct device_attribute *attr, ++ char *buf), ++ ssize_t (*store)(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count)) ++{ ++ sysfs_attr_init(&dev_attr->attr); ++ dev_attr->attr.name = name; ++ dev_attr->attr.mode = mode; ++ dev_attr->show = show; ++ dev_attr->store = store; ++} ++ ++static void pmbus_attr_init(struct sensor_device_attribute *a, ++ const char *name, ++ umode_t mode, ++ ssize_t (*show)(struct device *dev, ++ struct device_attribute *attr, ++ char *buf), ++ ssize_t (*store)(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count), ++ int idx) ++{ ++ pmbus_dev_attr_init(&a->dev_attr, name, mode, show, store); ++ a->index = idx; ++} ++ ++static int pmbus_add_boolean(struct pmbus_data *data, ++ const char *name, const char *type, int seq, ++ struct pmbus_sensor *s1, ++ struct pmbus_sensor *s2, ++ u8 page, u16 reg, u16 mask) ++{ ++ struct pmbus_boolean *boolean; ++ struct sensor_device_attribute *a; ++ ++ if (WARN((s1 && !s2) || (!s1 && s2), "Bad s1/s2 parameters\n")) ++ return -EINVAL; ++ ++ boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL); ++ if (!boolean) ++ return -ENOMEM; ++ ++ a = &boolean->attribute; ++ ++ snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s", ++ name, seq, type); ++ boolean->s1 = s1; ++ boolean->s2 = s2; ++ pmbus_attr_init(a, boolean->name, 0444, pmbus_show_boolean, NULL, ++ pb_reg_to_index(page, reg, mask)); ++ ++ return pmbus_add_attribute(data, &a->dev_attr.attr); ++} ++ ++static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, ++ const char *name, const char *type, ++ int seq, int page, int phase, ++ int reg, ++ enum pmbus_sensor_classes class, ++ bool update, bool readonly, ++ bool convert) ++{ ++ struct pmbus_sensor *sensor; ++ struct device_attribute *a; ++ ++ sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL); ++ if (!sensor) ++ return NULL; ++ a = &sensor->attribute; ++ ++ if (type) ++ snprintf(sensor->name, sizeof(sensor->name), "%s%d_%s", ++ name, seq, type); ++ else ++ snprintf(sensor->name, sizeof(sensor->name), "%s%d", ++ name, seq); ++ ++ if (data->flags & PMBUS_WRITE_PROTECTED) ++ readonly = true; ++ ++ sensor->page = page; ++ sensor->phase = phase; ++ sensor->reg = reg; ++ sensor->class = class; ++ sensor->update = update; ++ sensor->convert = convert; ++ sensor->data = -ENODATA; ++ pmbus_dev_attr_init(a, sensor->name, ++ readonly ? 0444 : 0644, ++ pmbus_show_sensor, pmbus_set_sensor); ++ ++ if (pmbus_add_attribute(data, &a->attr)) ++ return NULL; ++ ++ sensor->next = data->sensors; ++ data->sensors = sensor; ++ ++ return sensor; ++} ++ ++static int pmbus_add_label(struct pmbus_data *data, ++ const char *name, int seq, ++ const char *lstring, int index, int phase) ++{ ++ struct pmbus_label *label; ++ struct device_attribute *a; ++ ++ label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL); ++ if (!label) ++ return -ENOMEM; ++ ++ a = &label->attribute; ++ ++ snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq); ++ if (!index) { ++ if (phase == 0xff) ++ strncpy(label->label, lstring, ++ sizeof(label->label) - 1); ++ else ++ snprintf(label->label, sizeof(label->label), "%s.%d", ++ lstring, phase); ++ } else { ++ if (phase == 0xff) ++ snprintf(label->label, sizeof(label->label), "%s%d", ++ lstring, index); ++ else ++ snprintf(label->label, sizeof(label->label), "%s%d.%d", ++ lstring, index, phase); ++ } ++ ++ pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL); ++ return pmbus_add_attribute(data, &a->attr); ++} ++ ++/* ++ * Search for attributes. Allocate sensors, booleans, and labels as needed. ++ */ ++ ++/* ++ * The pmbus_limit_attr structure describes a single limit attribute ++ * and its associated alarm attribute. ++ */ ++struct pmbus_limit_attr { ++ u16 reg; /* Limit register */ ++ u16 sbit; /* Alarm attribute status bit */ ++ bool update; /* True if register needs updates */ ++ bool low; /* True if low limit; for limits with compare ++ functions only */ ++ const char *attr; /* Attribute name */ ++ const char *alarm; /* Alarm attribute name */ ++}; ++ ++/* ++ * The pmbus_sensor_attr structure describes one sensor attribute. This ++ * description includes a reference to the associated limit attributes. ++ */ ++struct pmbus_sensor_attr { ++ u16 reg; /* sensor register */ ++ u16 gbit; /* generic status bit */ ++ u8 nlimit; /* # of limit registers */ ++ enum pmbus_sensor_classes class;/* sensor class */ ++ const char *label; /* sensor label */ ++ bool paged; /* true if paged sensor */ ++ bool update; /* true if update needed */ ++ bool compare; /* true if compare function needed */ ++ u32 func; /* sensor mask */ ++ u32 sfunc; /* sensor status mask */ ++ int sreg; /* status register */ ++ const struct pmbus_limit_attr *limit;/* limit registers */ ++}; ++ ++/* ++ * Add a set of limit attributes and, if supported, the associated ++ * alarm attributes. ++ * returns 0 if no alarm register found, 1 if an alarm register was found, ++ * < 0 on errors. ++ */ ++static int pmbus_add_limit_attrs(struct i2c_client *client, ++ struct pmbus_data *data, ++ const struct pmbus_driver_info *info, ++ const char *name, int index, int page, ++ struct pmbus_sensor *base, ++ const struct pmbus_sensor_attr *attr) ++{ ++ const struct pmbus_limit_attr *l = attr->limit; ++ int nlimit = attr->nlimit; ++ int have_alarm = 0; ++ int i, ret; ++ struct pmbus_sensor *curr; ++ ++ for (i = 0; i < nlimit; i++) { ++ if (wb_pmbus_check_word_register(client, page, l->reg)) { ++ curr = pmbus_add_sensor(data, name, l->attr, index, ++ page, 0xff, l->reg, attr->class, ++ attr->update || l->update, ++ false, true); ++ if (!curr) ++ return -ENOMEM; ++ if (l->sbit && (info->func[page] & attr->sfunc)) { ++ ret = pmbus_add_boolean(data, name, ++ l->alarm, index, ++ attr->compare ? l->low ? curr : base ++ : NULL, ++ attr->compare ? l->low ? base : curr ++ : NULL, ++ page, attr->sreg, l->sbit); ++ if (ret) ++ return ret; ++ have_alarm = 1; ++ } ++ } ++ l++; ++ } ++ return have_alarm; ++} ++ ++static int pmbus_add_sensor_attrs_one(struct i2c_client *client, ++ struct pmbus_data *data, ++ const struct pmbus_driver_info *info, ++ const char *name, ++ int index, int page, int phase, ++ const struct pmbus_sensor_attr *attr, ++ bool paged) ++{ ++ struct pmbus_sensor *base; ++ bool upper = !!(attr->gbit & 0xff00); /* need to check STATUS_WORD */ ++ int ret; ++ ++ if (attr->label) { ++ ret = pmbus_add_label(data, name, index, attr->label, ++ paged ? page + 1 : 0, phase); ++ if (ret) ++ return ret; ++ } ++ base = pmbus_add_sensor(data, name, "input", index, page, phase, ++ attr->reg, attr->class, true, true, true); ++ if (!base) ++ return -ENOMEM; ++ /* No limit and alarm attributes for phase specific sensors */ ++ if (attr->sfunc && phase == 0xff) { ++ ret = pmbus_add_limit_attrs(client, data, info, name, ++ index, page, base, attr); ++ if (ret < 0) ++ return ret; ++ /* ++ * Add generic alarm attribute only if there are no individual ++ * alarm attributes, if there is a global alarm bit, and if ++ * the generic status register (word or byte, depending on ++ * which global bit is set) for this page is accessible. ++ */ ++ if (!ret && attr->gbit && ++ (!upper || (upper && data->has_status_word)) && ++ pmbus_check_status_register(client, page)) { ++ ret = pmbus_add_boolean(data, name, "alarm", index, ++ NULL, NULL, ++ page, PMBUS_STATUS_WORD, ++ attr->gbit); ++ if (ret) ++ return ret; ++ } ++ } ++ return 0; ++} ++ ++static bool pmbus_sensor_is_paged(const struct pmbus_driver_info *info, ++ const struct pmbus_sensor_attr *attr) ++{ ++ int p; ++ ++ if (attr->paged) ++ return true; ++ ++ /* ++ * Some attributes may be present on more than one page despite ++ * not being marked with the paged attribute. If that is the case, ++ * then treat the sensor as being paged and add the page suffix to the ++ * attribute name. ++ * We don't just add the paged attribute to all such attributes, in ++ * order to maintain the un-suffixed labels in the case where the ++ * attribute is only on page 0. ++ */ ++ for (p = 1; p < info->pages; p++) { ++ if (info->func[p] & attr->func) ++ return true; ++ } ++ return false; ++} ++ ++static int pmbus_add_sensor_attrs(struct i2c_client *client, ++ struct pmbus_data *data, ++ const char *name, ++ const struct pmbus_sensor_attr *attrs, ++ int nattrs) ++{ ++ const struct pmbus_driver_info *info = data->info; ++ int index, i; ++ int ret; ++ ++ index = 1; ++ for (i = 0; i < nattrs; i++) { ++ int page, pages; ++ bool paged = pmbus_sensor_is_paged(info, attrs); ++ ++ pages = paged ? info->pages : 1; ++ for (page = 0; page < pages; page++) { ++ if (!(info->func[page] & attrs->func)) ++ continue; ++ ret = pmbus_add_sensor_attrs_one(client, data, info, ++ name, index, page, ++ 0xff, attrs, paged); ++ if (ret) ++ return ret; ++ index++; ++ if (info->phases[page]) { ++ int phase; ++ ++ for (phase = 0; phase < info->phases[page]; ++ phase++) { ++ if (!(info->pfunc[phase] & attrs->func)) ++ continue; ++ ret = pmbus_add_sensor_attrs_one(client, ++ data, info, name, index, page, ++ phase, attrs, paged); ++ if (ret) ++ return ret; ++ index++; ++ } ++ } ++ } ++ attrs++; ++ } ++ return 0; ++} ++ ++static const struct pmbus_limit_attr vin_limit_attrs[] = { ++ { ++ .reg = PMBUS_VIN_UV_WARN_LIMIT, ++ .attr = "min", ++ .alarm = "min_alarm", ++ .sbit = PB_VOLTAGE_UV_WARNING, ++ }, { ++ .reg = PMBUS_VIN_UV_FAULT_LIMIT, ++ .attr = "lcrit", ++ .alarm = "lcrit_alarm", ++ .sbit = PB_VOLTAGE_UV_FAULT, ++ }, { ++ .reg = PMBUS_VIN_OV_WARN_LIMIT, ++ .attr = "max", ++ .alarm = "max_alarm", ++ .sbit = PB_VOLTAGE_OV_WARNING, ++ }, { ++ .reg = PMBUS_VIN_OV_FAULT_LIMIT, ++ .attr = "crit", ++ .alarm = "crit_alarm", ++ .sbit = PB_VOLTAGE_OV_FAULT, ++ }, { ++ .reg = PMBUS_VIRT_READ_VIN_AVG, ++ .update = true, ++ .attr = "average", ++ }, { ++ .reg = PMBUS_VIRT_READ_VIN_MIN, ++ .update = true, ++ .attr = "lowest", ++ }, { ++ .reg = PMBUS_VIRT_READ_VIN_MAX, ++ .update = true, ++ .attr = "highest", ++ }, { ++ .reg = PMBUS_VIRT_RESET_VIN_HISTORY, ++ .attr = "reset_history", ++ }, { ++ .reg = PMBUS_MFR_VIN_MIN, ++ .attr = "rated_min", ++ }, { ++ .reg = PMBUS_MFR_VIN_MAX, ++ .attr = "rated_max", ++ }, ++}; ++ ++static const struct pmbus_limit_attr vmon_limit_attrs[] = { ++ { ++ .reg = PMBUS_VIRT_VMON_UV_WARN_LIMIT, ++ .attr = "min", ++ .alarm = "min_alarm", ++ .sbit = PB_VOLTAGE_UV_WARNING, ++ }, { ++ .reg = PMBUS_VIRT_VMON_UV_FAULT_LIMIT, ++ .attr = "lcrit", ++ .alarm = "lcrit_alarm", ++ .sbit = PB_VOLTAGE_UV_FAULT, ++ }, { ++ .reg = PMBUS_VIRT_VMON_OV_WARN_LIMIT, ++ .attr = "max", ++ .alarm = "max_alarm", ++ .sbit = PB_VOLTAGE_OV_WARNING, ++ }, { ++ .reg = PMBUS_VIRT_VMON_OV_FAULT_LIMIT, ++ .attr = "crit", ++ .alarm = "crit_alarm", ++ .sbit = PB_VOLTAGE_OV_FAULT, ++ } ++}; ++ ++static const struct pmbus_limit_attr vout_limit_attrs[] = { ++ { ++ .reg = PMBUS_VOUT_UV_WARN_LIMIT, ++ .attr = "min", ++ .alarm = "min_alarm", ++ .sbit = PB_VOLTAGE_UV_WARNING, ++ }, { ++ .reg = PMBUS_VOUT_UV_FAULT_LIMIT, ++ .attr = "lcrit", ++ .alarm = "lcrit_alarm", ++ .sbit = PB_VOLTAGE_UV_FAULT, ++ }, { ++ .reg = PMBUS_VOUT_OV_WARN_LIMIT, ++ .attr = "max", ++ .alarm = "max_alarm", ++ .sbit = PB_VOLTAGE_OV_WARNING, ++ }, { ++ .reg = PMBUS_VOUT_OV_FAULT_LIMIT, ++ .attr = "crit", ++ .alarm = "crit_alarm", ++ .sbit = PB_VOLTAGE_OV_FAULT, ++ }, { ++ .reg = PMBUS_VIRT_READ_VOUT_AVG, ++ .update = true, ++ .attr = "average", ++ }, { ++ .reg = PMBUS_VIRT_READ_VOUT_MIN, ++ .update = true, ++ .attr = "lowest", ++ }, { ++ .reg = PMBUS_VIRT_READ_VOUT_MAX, ++ .update = true, ++ .attr = "highest", ++ }, { ++ .reg = PMBUS_VIRT_RESET_VOUT_HISTORY, ++ .attr = "reset_history", ++ }, { ++ .reg = PMBUS_MFR_VOUT_MIN, ++ .attr = "rated_min", ++ }, { ++ .reg = PMBUS_MFR_VOUT_MAX, ++ .attr = "rated_max", ++ }, ++}; ++ ++static const struct pmbus_sensor_attr voltage_attributes[] = { ++ { ++ .reg = PMBUS_READ_VIN, ++ .class = PSC_VOLTAGE_IN, ++ .label = "vin", ++ .func = PMBUS_HAVE_VIN, ++ .sfunc = PMBUS_HAVE_STATUS_INPUT, ++ .sreg = PMBUS_STATUS_INPUT, ++ .gbit = PB_STATUS_VIN_UV, ++ .limit = vin_limit_attrs, ++ .nlimit = 0, ++ }, { ++ .reg = PMBUS_VIRT_READ_VMON, ++ .class = PSC_VOLTAGE_IN, ++ .label = "vmon", ++ .func = PMBUS_HAVE_VMON, ++ .sfunc = PMBUS_HAVE_STATUS_VMON, ++ .sreg = PMBUS_VIRT_STATUS_VMON, ++ .limit = vmon_limit_attrs, ++ .nlimit = 0, ++ }, { ++ .reg = PMBUS_READ_VCAP, ++ .class = PSC_VOLTAGE_IN, ++ .label = "vcap", ++ .func = PMBUS_HAVE_VCAP, ++ }, { ++ .reg = PMBUS_READ_VOUT, ++ .class = PSC_VOLTAGE_OUT, ++ .label = "vout", ++ .paged = true, ++ .func = PMBUS_HAVE_VOUT, ++ .sfunc = PMBUS_HAVE_STATUS_VOUT, ++ .sreg = PMBUS_STATUS_VOUT, ++ .gbit = PB_STATUS_VOUT_OV, ++ .limit = vout_limit_attrs, ++ .nlimit = 0, ++ } ++}; ++ ++/* Current attributes */ ++ ++static const struct pmbus_limit_attr iin_limit_attrs[] = { ++ { ++ .reg = PMBUS_IIN_OC_WARN_LIMIT, ++ .attr = "max", ++ .alarm = "max_alarm", ++ .sbit = PB_IIN_OC_WARNING, ++ }, { ++ .reg = PMBUS_IIN_OC_FAULT_LIMIT, ++ .attr = "crit", ++ .alarm = "crit_alarm", ++ .sbit = PB_IIN_OC_FAULT, ++ }, { ++ .reg = PMBUS_VIRT_READ_IIN_AVG, ++ .update = true, ++ .attr = "average", ++ }, { ++ .reg = PMBUS_VIRT_READ_IIN_MIN, ++ .update = true, ++ .attr = "lowest", ++ }, { ++ .reg = PMBUS_VIRT_READ_IIN_MAX, ++ .update = true, ++ .attr = "highest", ++ }, { ++ .reg = PMBUS_VIRT_RESET_IIN_HISTORY, ++ .attr = "reset_history", ++ }, { ++ .reg = PMBUS_MFR_IIN_MAX, ++ .attr = "rated_max", ++ }, ++}; ++ ++static const struct pmbus_limit_attr iout_limit_attrs[] = { ++ { ++ .reg = PMBUS_IOUT_OC_WARN_LIMIT, ++ .attr = "max", ++ .alarm = "max_alarm", ++ .sbit = PB_IOUT_OC_WARNING, ++ }, { ++ .reg = PMBUS_IOUT_UC_FAULT_LIMIT, ++ .attr = "lcrit", ++ .alarm = "lcrit_alarm", ++ .sbit = PB_IOUT_UC_FAULT, ++ }, { ++ .reg = PMBUS_IOUT_OC_FAULT_LIMIT, ++ .attr = "crit", ++ .alarm = "crit_alarm", ++ .sbit = PB_IOUT_OC_FAULT, ++ }, { ++ .reg = PMBUS_VIRT_READ_IOUT_AVG, ++ .update = true, ++ .attr = "average", ++ }, { ++ .reg = PMBUS_VIRT_READ_IOUT_MIN, ++ .update = true, ++ .attr = "lowest", ++ }, { ++ .reg = PMBUS_VIRT_READ_IOUT_MAX, ++ .update = true, ++ .attr = "highest", ++ }, { ++ .reg = PMBUS_VIRT_RESET_IOUT_HISTORY, ++ .attr = "reset_history", ++ }, { ++ .reg = PMBUS_MFR_IOUT_MAX, ++ .attr = "rated_max", ++ }, ++}; ++ ++static const struct pmbus_sensor_attr current_attributes[] = { ++ { ++ .reg = PMBUS_READ_IIN, ++ .class = PSC_CURRENT_IN, ++ .label = "iin", ++ .func = PMBUS_HAVE_IIN, ++ .sfunc = PMBUS_HAVE_STATUS_INPUT, ++ .sreg = PMBUS_STATUS_INPUT, ++ .gbit = PB_STATUS_INPUT, ++ .limit = iin_limit_attrs, ++ .nlimit = 0, ++ }, { ++ .reg = PMBUS_READ_IOUT, ++ .class = PSC_CURRENT_OUT, ++ .label = "iout", ++ .paged = true, ++ .func = PMBUS_HAVE_IOUT, ++ .sfunc = PMBUS_HAVE_STATUS_IOUT, ++ .sreg = PMBUS_STATUS_IOUT, ++ .gbit = PB_STATUS_IOUT_OC, ++ .limit = iout_limit_attrs, ++ .nlimit = 0, ++ } ++}; ++ ++/* Power attributes */ ++ ++static const struct pmbus_limit_attr pin_limit_attrs[] = { ++ { ++ .reg = PMBUS_PIN_OP_WARN_LIMIT, ++ .attr = "max", ++ .alarm = "alarm", ++ .sbit = PB_PIN_OP_WARNING, ++ }, { ++ .reg = PMBUS_VIRT_READ_PIN_AVG, ++ .update = true, ++ .attr = "average", ++ }, { ++ .reg = PMBUS_VIRT_READ_PIN_MIN, ++ .update = true, ++ .attr = "input_lowest", ++ }, { ++ .reg = PMBUS_VIRT_READ_PIN_MAX, ++ .update = true, ++ .attr = "input_highest", ++ }, { ++ .reg = PMBUS_VIRT_RESET_PIN_HISTORY, ++ .attr = "reset_history", ++ }, { ++ .reg = PMBUS_MFR_PIN_MAX, ++ .attr = "rated_max", ++ }, ++}; ++ ++static const struct pmbus_limit_attr pout_limit_attrs[] = { ++ { ++ .reg = PMBUS_POUT_MAX, ++ .attr = "cap", ++ .alarm = "cap_alarm", ++ .sbit = PB_POWER_LIMITING, ++ }, { ++ .reg = PMBUS_POUT_OP_WARN_LIMIT, ++ .attr = "max", ++ .alarm = "max_alarm", ++ .sbit = PB_POUT_OP_WARNING, ++ }, { ++ .reg = PMBUS_POUT_OP_FAULT_LIMIT, ++ .attr = "crit", ++ .alarm = "crit_alarm", ++ .sbit = PB_POUT_OP_FAULT, ++ }, { ++ .reg = PMBUS_VIRT_READ_POUT_AVG, ++ .update = true, ++ .attr = "average", ++ }, { ++ .reg = PMBUS_VIRT_READ_POUT_MIN, ++ .update = true, ++ .attr = "input_lowest", ++ }, { ++ .reg = PMBUS_VIRT_READ_POUT_MAX, ++ .update = true, ++ .attr = "input_highest", ++ }, { ++ .reg = PMBUS_VIRT_RESET_POUT_HISTORY, ++ .attr = "reset_history", ++ }, { ++ .reg = PMBUS_MFR_POUT_MAX, ++ .attr = "rated_max", ++ }, ++}; ++ ++static const struct pmbus_sensor_attr power_attributes[] = { ++ { ++ .reg = PMBUS_READ_PIN, ++ .class = PSC_POWER, ++ .label = "pin", ++ .func = PMBUS_HAVE_PIN, ++ .sfunc = PMBUS_HAVE_STATUS_INPUT, ++ .sreg = PMBUS_STATUS_INPUT, ++ .gbit = PB_STATUS_INPUT, ++ .limit = pin_limit_attrs, ++ .nlimit = 0, ++ }, { ++ .reg = PMBUS_READ_POUT, ++ .class = PSC_POWER, ++ .label = "pout", ++ .paged = true, ++ .func = PMBUS_HAVE_POUT, ++ .sfunc = PMBUS_HAVE_STATUS_IOUT, ++ .sreg = PMBUS_STATUS_IOUT, ++ .limit = pout_limit_attrs, ++ .nlimit = 0, ++ } ++}; ++ ++/* Temperature atributes */ ++ ++static const struct pmbus_limit_attr temp_limit_attrs[] = { ++ { ++ .reg = PMBUS_UT_WARN_LIMIT, ++ .low = true, ++ .attr = "min", ++ .alarm = "min_alarm", ++ .sbit = PB_TEMP_UT_WARNING, ++ }, { ++ .reg = PMBUS_UT_FAULT_LIMIT, ++ .low = true, ++ .attr = "lcrit", ++ .alarm = "lcrit_alarm", ++ .sbit = PB_TEMP_UT_FAULT, ++ }, { ++ .reg = PMBUS_OT_WARN_LIMIT, ++ .attr = "max", ++ .alarm = "max_alarm", ++ .sbit = PB_TEMP_OT_WARNING, ++ }, { ++ .reg = PMBUS_OT_FAULT_LIMIT, ++ .attr = "crit", ++ .alarm = "crit_alarm", ++ .sbit = PB_TEMP_OT_FAULT, ++ }, { ++ .reg = PMBUS_VIRT_READ_TEMP_MIN, ++ .attr = "lowest", ++ }, { ++ .reg = PMBUS_VIRT_READ_TEMP_AVG, ++ .attr = "average", ++ }, { ++ .reg = PMBUS_VIRT_READ_TEMP_MAX, ++ .attr = "highest", ++ }, { ++ .reg = PMBUS_VIRT_RESET_TEMP_HISTORY, ++ .attr = "reset_history", ++ }, { ++ .reg = PMBUS_MFR_MAX_TEMP_1, ++ .attr = "rated_max", ++ }, ++}; ++ ++static const struct pmbus_limit_attr temp_limit_attrs2[] = { ++ { ++ .reg = PMBUS_UT_WARN_LIMIT, ++ .low = true, ++ .attr = "min", ++ .alarm = "min_alarm", ++ .sbit = PB_TEMP_UT_WARNING, ++ }, { ++ .reg = PMBUS_UT_FAULT_LIMIT, ++ .low = true, ++ .attr = "lcrit", ++ .alarm = "lcrit_alarm", ++ .sbit = PB_TEMP_UT_FAULT, ++ }, { ++ .reg = PMBUS_OT_WARN_LIMIT, ++ .attr = "max", ++ .alarm = "max_alarm", ++ .sbit = PB_TEMP_OT_WARNING, ++ }, { ++ .reg = PMBUS_OT_FAULT_LIMIT, ++ .attr = "crit", ++ .alarm = "crit_alarm", ++ .sbit = PB_TEMP_OT_FAULT, ++ }, { ++ .reg = PMBUS_VIRT_READ_TEMP2_MIN, ++ .attr = "lowest", ++ }, { ++ .reg = PMBUS_VIRT_READ_TEMP2_AVG, ++ .attr = "average", ++ }, { ++ .reg = PMBUS_VIRT_READ_TEMP2_MAX, ++ .attr = "highest", ++ }, { ++ .reg = PMBUS_VIRT_RESET_TEMP2_HISTORY, ++ .attr = "reset_history", ++ }, { ++ .reg = PMBUS_MFR_MAX_TEMP_2, ++ .attr = "rated_max", ++ }, ++}; ++ ++static const struct pmbus_limit_attr temp_limit_attrs3[] = { ++ { ++ .reg = PMBUS_UT_WARN_LIMIT, ++ .low = true, ++ .attr = "min", ++ .alarm = "min_alarm", ++ .sbit = PB_TEMP_UT_WARNING, ++ }, { ++ .reg = PMBUS_UT_FAULT_LIMIT, ++ .low = true, ++ .attr = "lcrit", ++ .alarm = "lcrit_alarm", ++ .sbit = PB_TEMP_UT_FAULT, ++ }, { ++ .reg = PMBUS_OT_WARN_LIMIT, ++ .attr = "max", ++ .alarm = "max_alarm", ++ .sbit = PB_TEMP_OT_WARNING, ++ }, { ++ .reg = PMBUS_OT_FAULT_LIMIT, ++ .attr = "crit", ++ .alarm = "crit_alarm", ++ .sbit = PB_TEMP_OT_FAULT, ++ }, { ++ .reg = PMBUS_MFR_MAX_TEMP_3, ++ .attr = "rated_max", ++ }, ++}; ++ ++static const struct pmbus_sensor_attr temp_attributes[] = { ++ { ++ .reg = PMBUS_READ_TEMPERATURE_1, ++ .class = PSC_TEMPERATURE, ++ .paged = true, ++ .update = true, ++ .compare = true, ++ .func = PMBUS_HAVE_TEMP, ++ .sfunc = PMBUS_HAVE_STATUS_TEMP, ++ .sreg = PMBUS_STATUS_TEMPERATURE, ++ .gbit = PB_STATUS_TEMPERATURE, ++ .limit = temp_limit_attrs, ++ .nlimit = 0, ++ }, { ++ .reg = PMBUS_READ_TEMPERATURE_2, ++ .class = PSC_TEMPERATURE, ++ .paged = true, ++ .update = true, ++ .compare = true, ++ .func = PMBUS_HAVE_TEMP2, ++ .sfunc = PMBUS_HAVE_STATUS_TEMP, ++ .sreg = PMBUS_STATUS_TEMPERATURE, ++ .gbit = PB_STATUS_TEMPERATURE, ++ .limit = temp_limit_attrs2, ++ .nlimit = 0, ++ }, { ++ .reg = PMBUS_READ_TEMPERATURE_3, ++ .class = PSC_TEMPERATURE, ++ .paged = true, ++ .update = true, ++ .compare = true, ++ .func = PMBUS_HAVE_TEMP3, ++ .sfunc = PMBUS_HAVE_STATUS_TEMP, ++ .sreg = PMBUS_STATUS_TEMPERATURE, ++ .gbit = PB_STATUS_TEMPERATURE, ++ .limit = temp_limit_attrs3, ++ .nlimit = 0, ++ } ++}; ++ ++static const int pmbus_fan_registers[] = { ++ PMBUS_READ_FAN_SPEED_1, ++ PMBUS_READ_FAN_SPEED_2, ++ PMBUS_READ_FAN_SPEED_3, ++ PMBUS_READ_FAN_SPEED_4 ++}; ++ ++static const int pmbus_fan_status_registers[] = { ++ PMBUS_STATUS_FAN_12, ++ PMBUS_STATUS_FAN_12, ++ PMBUS_STATUS_FAN_34, ++ PMBUS_STATUS_FAN_34 ++}; ++ ++static const u32 pmbus_fan_flags[] = { ++ PMBUS_HAVE_FAN12, ++ PMBUS_HAVE_FAN12, ++ PMBUS_HAVE_FAN34, ++ PMBUS_HAVE_FAN34 ++}; ++ ++static const u32 pmbus_fan_status_flags[] = { ++ PMBUS_HAVE_STATUS_FAN12, ++ PMBUS_HAVE_STATUS_FAN12, ++ PMBUS_HAVE_STATUS_FAN34, ++ PMBUS_HAVE_STATUS_FAN34 ++}; ++ ++/* Fans */ ++ ++/* Precondition: FAN_CONFIG_x_y and FAN_COMMAND_x must exist for the fan ID */ ++static int pmbus_add_fan_ctrl(struct i2c_client *client, ++ struct pmbus_data *data, int index, int page, int id, ++ u8 config) ++{ ++ struct pmbus_sensor *sensor; ++ ++ sensor = pmbus_add_sensor(data, "fan", "target", index, page, ++ 0xff, PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN, ++ false, false, true); ++ ++ if (!sensor) ++ return -ENOMEM; ++ ++ if (!((data->info->func[page] & PMBUS_HAVE_PWM12) || ++ (data->info->func[page] & PMBUS_HAVE_PWM34))) ++ return 0; ++ ++ sensor = pmbus_add_sensor(data, "pwm", NULL, index, page, ++ 0xff, PMBUS_VIRT_PWM_1 + id, PSC_PWM, ++ false, false, true); ++ ++ if (!sensor) ++ return -ENOMEM; ++ ++ sensor = pmbus_add_sensor(data, "pwm", "enable", index, page, ++ 0xff, PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM, ++ true, false, false); ++ ++ if (!sensor) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static int pmbus_add_fan_attributes(struct i2c_client *client, ++ struct pmbus_data *data) ++{ ++ const struct pmbus_driver_info *info = data->info; ++ int index = 1; ++ int page; ++ int ret; ++ ++ for (page = 0; page < info->pages; page++) { ++ int f; ++ ++ for (f = 0; f < ARRAY_SIZE(pmbus_fan_registers); f++) { ++ int regval; ++ ++ if (!(info->func[page] & pmbus_fan_flags[f])) ++ break; ++ ++ if (!wb_pmbus_check_word_register(client, page, ++ pmbus_fan_registers[f])) ++ break; ++ ++ /* ++ * Skip fan if not installed. ++ * Each fan configuration register covers multiple fans, ++ * so we have to do some magic. ++ */ ++ regval = _pmbus_read_byte_data(client, page, ++ pmbus_fan_config_registers[f]); ++ if (regval < 0 || ++ (!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4))))) ++ continue; ++ ++ if (pmbus_add_sensor(data, "fan", "input", index, ++ page, 0xff, pmbus_fan_registers[f], ++ PSC_FAN, true, true, true) == NULL) ++ return -ENOMEM; ++ ++ /* Fan control */ ++ if (wb_pmbus_check_word_register(client, page, ++ pmbus_fan_command_registers[f])) { ++ ret = pmbus_add_fan_ctrl(client, data, index, ++ page, f, regval); ++ if (ret < 0) ++ return ret; ++ } ++ ++ /* ++ * Each fan status register covers multiple fans, ++ * so we have to do some magic. ++ */ ++ if ((info->func[page] & pmbus_fan_status_flags[f]) && ++ wb_pmbus_check_byte_register(client, ++ page, pmbus_fan_status_registers[f])) { ++ int reg; ++ ++ if (f > 1) /* fan 3, 4 */ ++ reg = PMBUS_STATUS_FAN_34; ++ else ++ reg = PMBUS_STATUS_FAN_12; ++ ret = pmbus_add_boolean(data, "fan", ++ "alarm", index, NULL, NULL, page, reg, ++ PB_FAN_FAN1_WARNING >> (f & 1)); ++ if (ret) ++ return ret; ++ ret = pmbus_add_boolean(data, "fan", ++ "fault", index, NULL, NULL, page, reg, ++ PB_FAN_FAN1_FAULT >> (f & 1)); ++ if (ret) ++ return ret; ++ } ++ index++; ++ } ++ } ++ return 0; ++} ++ ++struct pmbus_samples_attr { ++ int reg; ++ char *name; ++}; ++ ++struct pmbus_samples_reg { ++ int page; ++ struct pmbus_samples_attr *attr; ++ struct device_attribute dev_attr; ++}; ++ ++static struct pmbus_samples_attr pmbus_samples_registers[] = { ++ { ++ .reg = PMBUS_VIRT_SAMPLES, ++ .name = "samples", ++ }, { ++ .reg = PMBUS_VIRT_IN_SAMPLES, ++ .name = "in_samples", ++ }, { ++ .reg = PMBUS_VIRT_CURR_SAMPLES, ++ .name = "curr_samples", ++ }, { ++ .reg = PMBUS_VIRT_POWER_SAMPLES, ++ .name = "power_samples", ++ }, { ++ .reg = PMBUS_VIRT_TEMP_SAMPLES, ++ .name = "temp_samples", ++ } ++}; ++ ++#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, dev_attr) ++ ++static ssize_t pmbus_show_samples(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ int val; ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct pmbus_samples_reg *reg = to_samples_reg(devattr); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ ++ mutex_lock(&data->update_lock); ++ val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg); ++ mutex_unlock(&data->update_lock); ++ if (val < 0) ++ return val; ++ ++ return snprintf(buf, PAGE_SIZE, "%d\n", val); ++} ++ ++static ssize_t pmbus_set_samples(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ int ret; ++ long val; ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct pmbus_samples_reg *reg = to_samples_reg(devattr); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ ++ if (kstrtol(buf, 0, &val) < 0) ++ return -EINVAL; ++ ++ mutex_lock(&data->update_lock); ++ ret = _pmbus_write_word_data(client, reg->page, reg->attr->reg, val); ++ mutex_unlock(&data->update_lock); ++ ++ return ret ? : count; ++} ++ ++static int pmbus_add_samples_attr(struct pmbus_data *data, int page, ++ struct pmbus_samples_attr *attr) ++{ ++ struct pmbus_samples_reg *reg; ++ ++ reg = devm_kzalloc(data->dev, sizeof(*reg), GFP_KERNEL); ++ if (!reg) ++ return -ENOMEM; ++ ++ reg->attr = attr; ++ reg->page = page; ++ ++ pmbus_dev_attr_init(®->dev_attr, attr->name, 0644, ++ pmbus_show_samples, pmbus_set_samples); ++ ++ return pmbus_add_attribute(data, ®->dev_attr.attr); ++} ++ ++static int pmbus_add_samples_attributes(struct i2c_client *client, ++ struct pmbus_data *data) ++{ ++ const struct pmbus_driver_info *info = data->info; ++ int s; ++ ++ if (!(info->func[0] & PMBUS_HAVE_SAMPLES)) ++ return 0; ++ ++ for (s = 0; s < ARRAY_SIZE(pmbus_samples_registers); s++) { ++ struct pmbus_samples_attr *attr; ++ int ret; ++ ++ attr = &pmbus_samples_registers[s]; ++ if (!wb_pmbus_check_word_register(client, 0, attr->reg)) ++ continue; ++ ++ ret = pmbus_add_samples_attr(data, 0, attr); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int pmbus_find_attributes(struct i2c_client *client, ++ struct pmbus_data *data) ++{ ++ int ret; ++ ++ /* Voltage sensors */ ++ ret = pmbus_add_sensor_attrs(client, data, "in", voltage_attributes, ++ ARRAY_SIZE(voltage_attributes)); ++ if (ret) ++ return ret; ++ ++ /* Current sensors */ ++ ret = pmbus_add_sensor_attrs(client, data, "curr", current_attributes, ++ ARRAY_SIZE(current_attributes)); ++ if (ret) ++ return ret; ++ ++ /* Power sensors */ ++ ret = pmbus_add_sensor_attrs(client, data, "power", power_attributes, ++ ARRAY_SIZE(power_attributes)); ++ if (ret) ++ return ret; ++ ++ /* Temperature sensors */ ++ ret = pmbus_add_sensor_attrs(client, data, "temp", temp_attributes, ++ ARRAY_SIZE(temp_attributes)); ++ if (ret) ++ return ret; ++ ++ /* Fans */ ++ ret = pmbus_add_fan_attributes(client, data); ++ if (ret) ++ return ret; ++ ++ ret = pmbus_add_samples_attributes(client, data); ++ return ret; ++} ++ ++/* ++ * Identify chip parameters. ++ * This function is called for all chips. ++ */ ++static int pmbus_identify_common(struct i2c_client *client, ++ struct pmbus_data *data, int page) ++{ ++ int vout_mode = -1; ++ ++ if (wb_pmbus_check_byte_register(client, page, PMBUS_VOUT_MODE)) ++ vout_mode = _pmbus_read_byte_data(client, page, ++ PMBUS_VOUT_MODE); ++ if (vout_mode >= 0 && vout_mode != 0xff) { ++ /* ++ * Not all chips support the VOUT_MODE command, ++ * so a failure to read it is not an error. ++ */ ++ switch (vout_mode >> 5) { ++ case 0: /* linear mode */ ++ if (data->info->format[PSC_VOLTAGE_OUT] != linear) ++ return -ENODEV; ++ ++ data->exponent[page] = ((s8)(vout_mode << 3)) >> 3; ++ break; ++ case 1: /* VID mode */ ++ if (data->info->format[PSC_VOLTAGE_OUT] != vid) ++ return -ENODEV; ++ break; ++ case 2: /* direct mode */ ++ if (data->info->format[PSC_VOLTAGE_OUT] != direct) ++ return -ENODEV; ++ break; ++ default: ++ return -ENODEV; ++ } ++ } ++ ++ pmbus_clear_fault_page(client, page); ++ return 0; ++} ++ ++static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, ++ struct pmbus_driver_info *info) ++{ ++ struct device *dev = &client->dev; ++ int page, ret, i; ++ ++ /* ++ * Some PMBus chips don't support PMBUS_STATUS_WORD, so try ++ * to use PMBUS_STATUS_BYTE instead if that is the case. ++ * Bail out if both registers are not supported. ++ */ ++ for(i = 0; i < PMBUS_RETRY_TIME; i++) { ++ data->read_status = pmbus_read_status_word; ++ ret = i2c_smbus_read_word_data(client, PMBUS_STATUS_WORD); ++ if (ret < 0 || ret == 0xffff) { ++ data->read_status = pmbus_read_status_byte; ++ ret = i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE); ++ if (ret < 0 || ret == 0xff) { ++ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); ++ continue; ++ } ++ } else { ++ data->has_status_word = true; ++ } ++ break; ++ } ++ ++ if(i == PMBUS_RETRY_TIME) { ++ dev_err(dev, "PMBus status register not found\n"); ++ return -ENODEV; ++ } ++ ++ /* Enable PEC if the controller supports it */ ++ for(i = 0; i < PMBUS_RETRY_TIME; i++) { ++ ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); ++ if (ret >= 0) { ++ break; ++ } ++ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); ++ } ++ ++ if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) ++ client->flags |= I2C_CLIENT_PEC; ++ ++ /* ++ * Check if the chip is write protected. If it is, we can not clear ++ * faults, and we should not try it. Also, in that case, writes into ++ * limit registers need to be disabled. ++ */ ++ for(i = 0; i < PMBUS_RETRY_TIME; i++) { ++ ret = i2c_smbus_read_byte_data(client, PMBUS_WRITE_PROTECT); ++ if (ret >= 0) { ++ break; ++ } ++ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); ++ } ++ ++ if (ret > 0 && (ret & PB_WP_ANY)) ++ data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK; ++ ++ if (data->info->pages) ++ wb_pmbus_clear_faults(client); ++ else ++ pmbus_clear_fault_page(client, -1); ++ ++ if (info->identify) { ++ ret = (*info->identify)(client, info); ++ if (ret < 0) { ++ dev_err(dev, "Chip identification failed\n"); ++ return ret; ++ } ++ } ++ ++ if (info->pages <= 0 || info->pages > PMBUS_PAGES) { ++ dev_err(dev, "Bad number of PMBus pages: %d\n", info->pages); ++ return -ENODEV; ++ } ++ ++ for (page = 0; page < info->pages; page++) { ++ ret = pmbus_identify_common(client, data, page); ++ if (ret < 0) { ++ dev_err(dev, "Failed to identify chip capabilities\n"); ++ return ret; ++ } ++ } ++ return 0; ++} ++ ++#if IS_ENABLED(CONFIG_REGULATOR) ++static int pmbus_regulator_is_enabled(struct regulator_dev *rdev) ++{ ++ struct device *dev = rdev_get_dev(rdev); ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ u8 page = rdev_get_id(rdev); ++ int ret; ++ ++ ret = wb_pmbus_read_byte_data(client, page, PMBUS_OPERATION); ++ if (ret < 0) ++ return ret; ++ ++ return !!(ret & PB_OPERATION_CONTROL_ON); ++} ++ ++static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable) ++{ ++ struct device *dev = rdev_get_dev(rdev); ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ u8 page = rdev_get_id(rdev); ++ ++ return wb_pmbus_update_byte_data(client, page, PMBUS_OPERATION, ++ PB_OPERATION_CONTROL_ON, ++ enable ? PB_OPERATION_CONTROL_ON : 0); ++} ++ ++static int pmbus_regulator_enable(struct regulator_dev *rdev) ++{ ++ return _pmbus_regulator_on_off(rdev, 1); ++} ++ ++static int pmbus_regulator_disable(struct regulator_dev *rdev) ++{ ++ return _pmbus_regulator_on_off(rdev, 0); ++} ++ ++const struct regulator_ops wb_pmbus_regulator_ops = { ++ .enable = pmbus_regulator_enable, ++ .disable = pmbus_regulator_disable, ++ .is_enabled = pmbus_regulator_is_enabled, ++}; ++EXPORT_SYMBOL_GPL(wb_pmbus_regulator_ops); ++ ++static int pmbus_regulator_register(struct pmbus_data *data) ++{ ++ struct device *dev = data->dev; ++ const struct pmbus_driver_info *info = data->info; ++ const struct pmbus_platform_data *pdata = dev_get_platdata(dev); ++ struct regulator_dev *rdev; ++ int i; ++ ++ for (i = 0; i < info->num_regulators; i++) { ++ struct regulator_config config = { }; ++ ++ config.dev = dev; ++ config.driver_data = data; ++ ++ if (pdata && pdata->reg_init_data) ++ config.init_data = &pdata->reg_init_data[i]; ++ ++ rdev = devm_regulator_register(dev, &info->reg_desc[i], ++ &config); ++ if (IS_ERR(rdev)) { ++ dev_err(dev, "Failed to register %s regulator\n", ++ info->reg_desc[i].name); ++ return PTR_ERR(rdev); ++ } ++ } ++ ++ return 0; ++} ++#else ++static int pmbus_regulator_register(struct pmbus_data *data) ++{ ++ return 0; ++} ++#endif ++ ++static struct dentry *pmbus_debugfs_dir; /* pmbus debugfs directory */ ++ ++#if IS_ENABLED(CONFIG_DEBUG_FS) ++static int pmbus_debugfs_get(void *data, u64 *val) ++{ ++ int rc; ++ struct pmbus_debugfs_entry *entry = data; ++ ++ rc = _pmbus_read_byte_data(entry->client, entry->page, entry->reg); ++ if (rc < 0) ++ return rc; ++ ++ *val = rc; ++ ++ return 0; ++} ++DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops, pmbus_debugfs_get, NULL, ++ "0x%02llx\n"); ++ ++static int pmbus_debugfs_get_status(void *data, u64 *val) ++{ ++ int rc; ++ struct pmbus_debugfs_entry *entry = data; ++ struct pmbus_data *pdata = i2c_get_clientdata(entry->client); ++ ++ rc = pdata->read_status(entry->client, entry->page); ++ if (rc < 0) ++ return rc; ++ ++ *val = rc; ++ ++ return 0; ++} ++DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_status, pmbus_debugfs_get_status, ++ NULL, "0x%04llx\n"); ++ ++static int pmbus_debugfs_get_pec(void *data, u64 *val) ++{ ++ struct i2c_client *client = data; ++ ++ *val = !!(client->flags & I2C_CLIENT_PEC); ++ ++ return 0; ++} ++ ++static int pmbus_debugfs_set_pec(void *data, u64 val) ++{ ++ int rc; ++ struct i2c_client *client = data; ++ ++ if (!val) { ++ client->flags &= ~I2C_CLIENT_PEC; ++ return 0; ++ } ++ ++ if (val != 1) ++ return -EINVAL; ++ ++ rc = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); ++ if (rc < 0) ++ return rc; ++ ++ if (!(rc & PB_CAPABILITY_ERROR_CHECK)) ++ return -EOPNOTSUPP; ++ ++ client->flags |= I2C_CLIENT_PEC; ++ ++ return 0; ++} ++DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_pec, pmbus_debugfs_get_pec, ++ pmbus_debugfs_set_pec, "%llu\n"); ++ ++static int pmbus_init_debugfs(struct i2c_client *client, ++ struct pmbus_data *data) ++{ ++ int i, idx = 0; ++ char name[PMBUS_NAME_SIZE]; ++ struct pmbus_debugfs_entry *entries; ++ ++ if (!pmbus_debugfs_dir) ++ return -ENODEV; ++ ++ /* ++ * Create the debugfs directory for this device. Use the hwmon device ++ * name to avoid conflicts (hwmon numbers are globally unique). ++ */ ++ data->debugfs = debugfs_create_dir(dev_name(data->hwmon_dev), ++ pmbus_debugfs_dir); ++ if (IS_ERR_OR_NULL(data->debugfs)) { ++ data->debugfs = NULL; ++ return -ENODEV; ++ } ++ ++ /* Allocate the max possible entries we need. */ ++ entries = devm_kcalloc(data->dev, ++ data->info->pages * 10, sizeof(*entries), ++ GFP_KERNEL); ++ if (!entries) ++ return -ENOMEM; ++ ++ debugfs_create_file("pec", 0664, data->debugfs, client, ++ &pmbus_debugfs_ops_pec); ++ ++ for (i = 0; i < data->info->pages; ++i) { ++ /* Check accessibility of status register if it's not page 0 */ ++ if (!i || pmbus_check_status_register(client, i)) { ++ /* No need to set reg as we have special read op. */ ++ entries[idx].client = client; ++ entries[idx].page = i; ++ scnprintf(name, PMBUS_NAME_SIZE, "status%d", i); ++ debugfs_create_file(name, 0444, data->debugfs, ++ &entries[idx++], ++ &pmbus_debugfs_ops_status); ++ } ++ ++ if (data->info->func[i] & PMBUS_HAVE_STATUS_VOUT) { ++ entries[idx].client = client; ++ entries[idx].page = i; ++ entries[idx].reg = PMBUS_STATUS_VOUT; ++ scnprintf(name, PMBUS_NAME_SIZE, "status%d_vout", i); ++ debugfs_create_file(name, 0444, data->debugfs, ++ &entries[idx++], ++ &pmbus_debugfs_ops); ++ } ++ ++ if (data->info->func[i] & PMBUS_HAVE_STATUS_IOUT) { ++ entries[idx].client = client; ++ entries[idx].page = i; ++ entries[idx].reg = PMBUS_STATUS_IOUT; ++ scnprintf(name, PMBUS_NAME_SIZE, "status%d_iout", i); ++ debugfs_create_file(name, 0444, data->debugfs, ++ &entries[idx++], ++ &pmbus_debugfs_ops); ++ } ++ ++ if (data->info->func[i] & PMBUS_HAVE_STATUS_INPUT) { ++ entries[idx].client = client; ++ entries[idx].page = i; ++ entries[idx].reg = PMBUS_STATUS_INPUT; ++ scnprintf(name, PMBUS_NAME_SIZE, "status%d_input", i); ++ debugfs_create_file(name, 0444, data->debugfs, ++ &entries[idx++], ++ &pmbus_debugfs_ops); ++ } ++ ++ if (data->info->func[i] & PMBUS_HAVE_STATUS_TEMP) { ++ entries[idx].client = client; ++ entries[idx].page = i; ++ entries[idx].reg = PMBUS_STATUS_TEMPERATURE; ++ scnprintf(name, PMBUS_NAME_SIZE, "status%d_temp", i); ++ debugfs_create_file(name, 0444, data->debugfs, ++ &entries[idx++], ++ &pmbus_debugfs_ops); ++ } ++ ++ if (wb_pmbus_check_byte_register(client, i, PMBUS_STATUS_CML)) { ++ entries[idx].client = client; ++ entries[idx].page = i; ++ entries[idx].reg = PMBUS_STATUS_CML; ++ scnprintf(name, PMBUS_NAME_SIZE, "status%d_cml", i); ++ debugfs_create_file(name, 0444, data->debugfs, ++ &entries[idx++], ++ &pmbus_debugfs_ops); ++ } ++ ++ if (wb_pmbus_check_byte_register(client, i, PMBUS_STATUS_OTHER)) { ++ entries[idx].client = client; ++ entries[idx].page = i; ++ entries[idx].reg = PMBUS_STATUS_OTHER; ++ scnprintf(name, PMBUS_NAME_SIZE, "status%d_other", i); ++ debugfs_create_file(name, 0444, data->debugfs, ++ &entries[idx++], ++ &pmbus_debugfs_ops); ++ } ++ ++ if (wb_pmbus_check_byte_register(client, i, ++ PMBUS_STATUS_MFR_SPECIFIC)) { ++ entries[idx].client = client; ++ entries[idx].page = i; ++ entries[idx].reg = PMBUS_STATUS_MFR_SPECIFIC; ++ scnprintf(name, PMBUS_NAME_SIZE, "status%d_mfr", i); ++ debugfs_create_file(name, 0444, data->debugfs, ++ &entries[idx++], ++ &pmbus_debugfs_ops); ++ } ++ ++ if (data->info->func[i] & PMBUS_HAVE_STATUS_FAN12) { ++ entries[idx].client = client; ++ entries[idx].page = i; ++ entries[idx].reg = PMBUS_STATUS_FAN_12; ++ scnprintf(name, PMBUS_NAME_SIZE, "status%d_fan12", i); ++ debugfs_create_file(name, 0444, data->debugfs, ++ &entries[idx++], ++ &pmbus_debugfs_ops); ++ } ++ ++ if (data->info->func[i] & PMBUS_HAVE_STATUS_FAN34) { ++ entries[idx].client = client; ++ entries[idx].page = i; ++ entries[idx].reg = PMBUS_STATUS_FAN_34; ++ scnprintf(name, PMBUS_NAME_SIZE, "status%d_fan34", i); ++ debugfs_create_file(name, 0444, data->debugfs, ++ &entries[idx++], ++ &pmbus_debugfs_ops); ++ } ++ } ++ ++ return 0; ++} ++#else ++static int pmbus_init_debugfs(struct i2c_client *client, ++ struct pmbus_data *data) ++{ ++ return 0; ++} ++#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */ ++ ++int wb_pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info) ++{ ++ struct device *dev = &client->dev; ++ const struct pmbus_platform_data *pdata = dev_get_platdata(dev); ++ struct pmbus_data *data; ++ size_t groups_num = 0; ++ int ret; ++ ++ if (!info) ++ return -ENODEV; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE ++ | I2C_FUNC_SMBUS_BYTE_DATA ++ | I2C_FUNC_SMBUS_WORD_DATA)) ++ return -ENODEV; ++ ++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ if (info->groups) ++ while (info->groups[groups_num]) ++ groups_num++; ++ ++ data->groups = devm_kcalloc(dev, groups_num + 2, sizeof(void *), ++ GFP_KERNEL); ++ if (!data->groups) ++ return -ENOMEM; ++ ++ i2c_set_clientdata(client, data); ++ mutex_init(&data->update_lock); ++ data->dev = dev; ++ ++ if (pdata) ++ data->flags = pdata->flags; ++ data->info = info; ++ data->currpage = -1; ++ data->currphase = -1; ++ ++ ret = pmbus_init_common(client, data, info); ++ if (ret < 0) ++ return ret; ++ ++ ret = pmbus_find_attributes(client, data); ++ if (ret) ++ return ret; ++ ++ /* ++ * If there are no attributes, something is wrong. ++ * Bail out instead of trying to register nothing. ++ */ ++ if (!data->num_attributes) { ++ dev_err(dev, "No attributes found\n"); ++ return -ENODEV; ++ } ++ ++ data->groups[0] = &data->group; ++ memcpy(data->groups + 1, info->groups, sizeof(void *) * groups_num); ++ data->hwmon_dev = devm_hwmon_device_register_with_groups(dev, ++ client->name, data, data->groups); ++ if (IS_ERR(data->hwmon_dev)) { ++ dev_err(dev, "Failed to register hwmon device\n"); ++ return PTR_ERR(data->hwmon_dev); ++ } ++ ++ ret = pmbus_regulator_register(data); ++ if (ret) ++ return ret; ++ ++ ret = pmbus_init_debugfs(client, data); ++ if (ret) ++ dev_warn(dev, "Failed to register debugfs\n"); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_do_probe); ++ ++int wb_pmbus_do_remove(struct i2c_client *client) ++{ ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ ++ debugfs_remove_recursive(data->debugfs); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_do_remove); ++ ++struct dentry *wb_pmbus_get_debugfs_dir(struct i2c_client *client) ++{ ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ ++ return data->debugfs; ++} ++EXPORT_SYMBOL_GPL(wb_pmbus_get_debugfs_dir); ++ ++static int __init pmbus_core_init(void) ++{ ++ pmbus_debugfs_dir = debugfs_create_dir("pmbus", NULL); ++ if (IS_ERR(pmbus_debugfs_dir)) ++ pmbus_debugfs_dir = NULL; ++ ++ return 0; ++} ++ ++static void __exit pmbus_core_exit(void) ++{ ++ debugfs_remove_recursive(pmbus_debugfs_dir); ++} ++ ++module_init(pmbus_core_init); ++module_exit(pmbus_core_exit); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("PMBus core driver"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tmp401.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tmp401.c +new file mode 100644 +index 000000000..b8d3a024f +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tmp401.c +@@ -0,0 +1,1010 @@ ++/* tmp401.c ++ * ++ * Copyright (C) 2007,2008 Hans de Goede ++ * Preliminary tmp411 support by: ++ * Gabriel Konat, Sander Leget, Wouter Willems ++ * Copyright (C) 2009 Andre Prendel ++ * ++ * Cleanup and support for TMP431 and TMP432 by Guenter Roeck ++ * Copyright (c) 2013 Guenter Roeck ++ * ++ * 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. ++ */ ++ ++/* ++ * Driver for the Texas Instruments TMP401 SMBUS temperature sensor IC. ++ * ++ * Note this IC is in some aspect similar to the LM90, but it has quite a ++ * few differences too, for example the local temp has a higher resolution ++ * and thus has 16 bits registers for its value and limit instead of 8 bits. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Addresses to scan */ ++/* static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c, 0x4d, ++ 0x4e, 0x4f, I2C_CLIENT_END }; */ ++ ++enum chips { tmp401, tmp411, tmp431, tmp432, tmp435, tmp461 }; ++ ++/* ++ * The TMP401 registers, note some registers have different addresses for ++ * reading and writing ++ */ ++#define TMP401_STATUS (0x02) ++#define TMP401_CONFIG_READ (0x03) ++#define TMP401_CONFIG_WRITE (0x09) ++#define TMP401_CONVERSION_RATE_READ (0x04) ++#define TMP401_CONVERSION_RATE_WRITE (0x0A) ++#define TMP401_TEMP_CRIT_HYST (0x21) ++#define TMP401_MANUFACTURER_ID_REG (0xFE) ++#define TMP401_DEVICE_ID_REG (0xFF) ++#define TMP401_DEVICE_CAR_REG (0x22) /* Consecutive Alert Register */ ++ ++static const u8 TMP401_TEMP_MSB_READ[7][2] = { ++ { 0x00, 0x01 }, /* temp */ ++ { 0x06, 0x08 }, /* low limit */ ++ { 0x05, 0x07 }, /* high limit */ ++ { 0x20, 0x19 }, /* therm (crit) limit */ ++ { 0x30, 0x34 }, /* lowest */ ++ { 0x32, 0x36 }, /* highest */ ++ { 0, 0x11 }, /* offset */ ++}; ++ ++static const u8 TMP401_TEMP_MSB_WRITE[7][2] = { ++ { 0, 0 }, /* temp (unused) */ ++ { 0x0C, 0x0E }, /* low limit */ ++ { 0x0B, 0x0D }, /* high limit */ ++ { 0x20, 0x19 }, /* therm (crit) limit */ ++ { 0x30, 0x34 }, /* lowest */ ++ { 0x32, 0x36 }, /* highest */ ++ { 0, 0x11 }, /* offset */ ++}; ++ ++static const u8 TMP401_TEMP_LSB[7][2] = { ++ { 0x15, 0x10 }, /* temp */ ++ { 0x17, 0x14 }, /* low limit */ ++ { 0x16, 0x13 }, /* high limit */ ++ { 0, 0 }, /* therm (crit) limit (unused) */ ++ { 0x31, 0x35 }, /* lowest */ ++ { 0x33, 0x37 }, /* highest */ ++ { 0, 0x12 }, /* offset */ ++}; ++ ++static const u8 TMP432_TEMP_MSB_READ[4][3] = { ++ { 0x00, 0x01, 0x23 }, /* temp */ ++ { 0x06, 0x08, 0x16 }, /* low limit */ ++ { 0x05, 0x07, 0x15 }, /* high limit */ ++ { 0x20, 0x19, 0x1A }, /* therm (crit) limit */ ++}; ++ ++static const u8 TMP432_TEMP_MSB_WRITE[4][3] = { ++ { 0, 0, 0 }, /* temp - unused */ ++ { 0x0C, 0x0E, 0x16 }, /* low limit */ ++ { 0x0B, 0x0D, 0x15 }, /* high limit */ ++ { 0x20, 0x19, 0x1A }, /* therm (crit) limit */ ++}; ++ ++static const u8 TMP432_TEMP_LSB[3][3] = { ++ { 0x29, 0x10, 0x24 }, /* temp */ ++ { 0x3E, 0x14, 0x18 }, /* low limit */ ++ { 0x3D, 0x13, 0x17 }, /* high limit */ ++}; ++ ++/* [0] = fault, [1] = low, [2] = high, [3] = therm/crit */ ++static const u8 TMP432_STATUS_REG[] = { ++ 0x1b, 0x36, 0x35, 0x37 }; ++ ++/* Flags */ ++#define TMP401_CONFIG_RANGE BIT(2) ++#define TMP401_CONFIG_SHUTDOWN BIT(6) ++#define TMP401_STATUS_LOCAL_CRIT BIT(0) ++#define TMP401_STATUS_REMOTE_CRIT BIT(1) ++#define TMP401_STATUS_REMOTE_OPEN BIT(2) ++#define TMP401_STATUS_REMOTE_LOW BIT(3) ++#define TMP401_STATUS_REMOTE_HIGH BIT(4) ++#define TMP401_STATUS_LOCAL_LOW BIT(5) ++#define TMP401_STATUS_LOCAL_HIGH BIT(6) ++ ++/* On TMP432, each status has its own register */ ++#define TMP432_STATUS_LOCAL BIT(0) ++#define TMP432_STATUS_REMOTE1 BIT(1) ++#define TMP432_STATUS_REMOTE2 BIT(2) ++ ++/* Manufacturer / Device ID's */ ++#define TMP401_MANUFACTURER_ID (0x55) ++#define TMP401_DEVICE_ID (0x11) ++#define TMP411A_DEVICE_ID (0x12) ++#define TMP411B_DEVICE_ID (0x13) ++#define TMP411C_DEVICE_ID (0x10) ++#define TMP431_DEVICE_ID (0x31) ++#define TMP432_DEVICE_ID (0x32) ++#define TMP435_DEVICE_ID (0x35) ++ ++/* Timeout function bit */ ++#define TIMEOUT_STATE_BIT (7) /* 1:enable 0:disable */ ++#define TIMEOUT_STATE_EN (1) /* 1:enable */ ++#define TIMEOUT_STATE_IEN (0) /* 0:disable */ ++#define TIMEOUT_STATE_NA "NA" ++#define TMP401_TEMP_INVALID_RETRY_TIMES (3) ++ ++/* input temp threshold check */ ++typedef struct tmp401_temp_threshold_s { ++ int chip_type; ++ int temp_max; ++ int temp_min; ++} tmp401_temp_threshold_t; ++ ++static tmp401_temp_threshold_t g_tmp401_input_threshold_info[] = { ++ { ++ .chip_type = tmp411, ++ .temp_max = 127000, ++ .temp_min = -55000, ++ }, ++}; ++ ++/* ++ * Driver data (common to all clients) ++ */ ++ ++static const struct i2c_device_id tmp401_id[] = { ++ { "wb_tmp401", tmp401 }, ++ { "wb_tmp411", tmp411 }, ++ { "wb_tmp431", tmp431 }, ++ { "wb_tmp432", tmp432 }, ++ { "wb_tmp435", tmp435 }, ++ { "wb_tmp461", tmp461 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, tmp401_id); ++ ++/* ++ * Client data (each client gets its own) ++ */ ++ ++struct tmp401_data { ++ struct i2c_client *client; ++ const struct attribute_group *groups[3]; ++ struct mutex update_lock; ++ char valid; /* zero until following fields are valid */ ++ unsigned long last_updated; /* in jiffies */ ++ enum chips kind; ++ ++ unsigned int update_interval; /* in milliseconds */ ++ ++ /* register values */ ++ u8 status[4]; ++ u8 config; ++ u16 temp[7][3]; ++ u8 temp_crit_hyst; ++}; ++ ++/* ++ * Sysfs attr show / store functions ++ */ ++ ++static int tmp401_register_to_temp(u16 reg, u8 config) ++{ ++ int temp = reg; ++ ++ if (config & TMP401_CONFIG_RANGE) ++ temp -= 64 * 256; ++ ++ return DIV_ROUND_CLOSEST(temp * 125, 32); ++} ++ ++static u16 tmp401_temp_to_register(long temp, u8 config, int zbits) ++{ ++ if (config & TMP401_CONFIG_RANGE) { ++ temp = clamp_val(temp, -64000, 191000); ++ temp += 64000; ++ } else ++ temp = clamp_val(temp, 0, 127000); ++ ++ return DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits; ++} ++ ++static int tmp401_update_device_reg16(struct i2c_client *client, ++ struct tmp401_data *data) ++{ ++ int i, j, val; ++ int num_regs = data->kind == tmp411 ? 6 : 4; ++ int num_sensors = data->kind == tmp432 ? 3 : 2; ++ ++ for (i = 0; i < num_sensors; i++) { /* local / r1 / r2 */ ++ for (j = 0; j < num_regs; j++) { /* temp / low / ... */ ++ u8 regaddr; ++ /* ++ * High byte must be read first immediately followed ++ * by the low byte ++ */ ++ regaddr = data->kind == tmp432 ? ++ TMP432_TEMP_MSB_READ[j][i] : ++ TMP401_TEMP_MSB_READ[j][i]; ++ val = i2c_smbus_read_byte_data(client, regaddr); ++ if (val < 0) ++ return val; ++ data->temp[j][i] = val << 8; ++ if (j == 3) /* crit is msb only */ ++ continue; ++ regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[j][i] ++ : TMP401_TEMP_LSB[j][i]; ++ val = i2c_smbus_read_byte_data(client, regaddr); ++ if (val < 0) ++ return val; ++ data->temp[j][i] |= val; ++ } ++ } ++ return 0; ++} ++ ++static struct tmp401_data *tmp401_update_device(struct device *dev) ++{ ++ struct tmp401_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ struct tmp401_data *ret = data; ++ int i, val; ++ unsigned long next_update; ++ ++ mutex_lock(&data->update_lock); ++ ++ next_update = data->last_updated + ++ msecs_to_jiffies(data->update_interval); ++ if (time_after(jiffies, next_update) || !data->valid) { ++ if (data->kind != tmp432) { ++ /* ++ * The driver uses the TMP432 status format internally. ++ * Convert status to TMP432 format for other chips. ++ */ ++ val = i2c_smbus_read_byte_data(client, TMP401_STATUS); ++ if (val < 0) { ++ ret = ERR_PTR(val); ++ goto abort; ++ } ++ data->status[0] = ++ (val & TMP401_STATUS_REMOTE_OPEN) >> 1; ++ data->status[1] = ++ ((val & TMP401_STATUS_REMOTE_LOW) >> 2) | ++ ((val & TMP401_STATUS_LOCAL_LOW) >> 5); ++ data->status[2] = ++ ((val & TMP401_STATUS_REMOTE_HIGH) >> 3) | ++ ((val & TMP401_STATUS_LOCAL_HIGH) >> 6); ++ data->status[3] = val & (TMP401_STATUS_LOCAL_CRIT ++ | TMP401_STATUS_REMOTE_CRIT); ++ } else { ++ for (i = 0; i < ARRAY_SIZE(data->status); i++) { ++ val = i2c_smbus_read_byte_data(client, ++ TMP432_STATUS_REG[i]); ++ if (val < 0) { ++ ret = ERR_PTR(val); ++ goto abort; ++ } ++ data->status[i] = val; ++ } ++ } ++ ++ val = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); ++ if (val < 0) { ++ ret = ERR_PTR(val); ++ goto abort; ++ } ++ data->config = val; ++ val = tmp401_update_device_reg16(client, data); ++ if (val < 0) { ++ ret = ERR_PTR(val); ++ goto abort; ++ } ++ val = i2c_smbus_read_byte_data(client, TMP401_TEMP_CRIT_HYST); ++ if (val < 0) { ++ ret = ERR_PTR(val); ++ goto abort; ++ } ++ data->temp_crit_hyst = val; ++ ++ data->last_updated = jiffies; ++ data->valid = 1; ++ } ++ ++abort: ++ mutex_unlock(&data->update_lock); ++ return ret; ++} ++ ++static int tmp401_input_temp_check(struct tmp401_data *data, int input_val) ++{ ++ int i, size; ++ ++ size = ARRAY_SIZE(g_tmp401_input_threshold_info); ++ ++ for (i = 0; i < size; i++) { ++ if (g_tmp401_input_threshold_info[i].chip_type == data->kind) { ++ if ((input_val > g_tmp401_input_threshold_info[i].temp_max) ++ || (input_val < g_tmp401_input_threshold_info[i].temp_min)) { ++ dev_dbg(&data->client->dev, "input temp: %d not in range[%d, %d]\n", ++ input_val, g_tmp401_input_threshold_info[i].temp_min, ++ g_tmp401_input_threshold_info[i].temp_max); ++ return -EINVAL; ++ } ++ dev_dbg(&data->client->dev, "input temp: %d in range[%d, %d]", input_val, ++ g_tmp401_input_threshold_info[i].temp_min, g_tmp401_input_threshold_info[i].temp_max); ++ return 0; ++ } ++ } ++ return 0; ++} ++ ++static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, char *buf) ++{ ++ int nr, index, i, value, ret; ++ struct tmp401_data *data; ++ struct i2c_client *client; ++ ++ data = dev_get_drvdata(dev); ++ client = data->client; ++ ++ nr = to_sensor_dev_attr_2(devattr)->nr; ++ index = to_sensor_dev_attr_2(devattr)->index; ++ ++ for (i = 0; i < TMP401_TEMP_INVALID_RETRY_TIMES; i++) { ++ data = tmp401_update_device(dev); ++ if (IS_ERR(data)) { ++ return PTR_ERR(data); ++ } ++ value = tmp401_register_to_temp(data->temp[nr][index], data->config); ++ if (nr != 0) { /* not input temp, return value */ ++ return sprintf(buf, "%d\n", value); ++ } ++ /* nr == 0 is temp input, do input_temp_check */ ++ ret = tmp401_input_temp_check(data, value); ++ if (ret == 0) { /* input temp check ok */ ++ return sprintf(buf, "%d\n", value); ++ } ++ if ((i + 1) < TMP401_TEMP_INVALID_RETRY_TIMES) { ++ msleep(data->update_interval); ++ } ++ } ++ dev_info(&client->dev, "temp%d_input value: %d invalid\n", index + 1, value); ++ return -EINVAL; ++} ++ ++static ssize_t show_temp_crit_hyst(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ int temp, index = to_sensor_dev_attr(devattr)->index; ++ struct tmp401_data *data = tmp401_update_device(dev); ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ mutex_lock(&data->update_lock); ++ temp = tmp401_register_to_temp(data->temp[3][index], data->config); ++ temp -= data->temp_crit_hyst * 1000; ++ mutex_unlock(&data->update_lock); ++ ++ return sprintf(buf, "%d\n", temp); ++} ++ ++static ssize_t show_status(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ int nr = to_sensor_dev_attr_2(devattr)->nr; ++ int mask = to_sensor_dev_attr_2(devattr)->index; ++ struct tmp401_data *data = tmp401_update_device(dev); ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ return sprintf(buf, "%d\n", !!(data->status[nr] & mask)); ++} ++ ++static ssize_t store_temp(struct device *dev, struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ int nr = to_sensor_dev_attr_2(devattr)->nr; ++ int index = to_sensor_dev_attr_2(devattr)->index; ++ struct tmp401_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ long val; ++ u16 reg; ++ u8 regaddr; ++ ++ if (kstrtol(buf, 10, &val)) ++ return -EINVAL; ++ ++ reg = tmp401_temp_to_register(val, data->config, nr == 3 ? 8 : 4); ++ ++ mutex_lock(&data->update_lock); ++ ++ regaddr = data->kind == tmp432 ? TMP432_TEMP_MSB_WRITE[nr][index] ++ : TMP401_TEMP_MSB_WRITE[nr][index]; ++ i2c_smbus_write_byte_data(client, regaddr, reg >> 8); ++ if (nr != 3) { ++ regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[nr][index] ++ : TMP401_TEMP_LSB[nr][index]; ++ i2c_smbus_write_byte_data(client, regaddr, reg & 0xFF); ++ } ++ data->temp[nr][index] = reg; ++ ++ mutex_unlock(&data->update_lock); ++ ++ return count; ++} ++ ++static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute ++ *devattr, const char *buf, size_t count) ++{ ++ int temp, index = to_sensor_dev_attr(devattr)->index; ++ struct tmp401_data *data = tmp401_update_device(dev); ++ long val; ++ u8 reg; ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ if (kstrtol(buf, 10, &val)) ++ return -EINVAL; ++ ++ if (data->config & TMP401_CONFIG_RANGE) ++ val = clamp_val(val, -64000, 191000); ++ else ++ val = clamp_val(val, 0, 127000); ++ ++ mutex_lock(&data->update_lock); ++ temp = tmp401_register_to_temp(data->temp[3][index], data->config); ++ val = clamp_val(val, temp - 255000, temp); ++ reg = ((temp - val) + 500) / 1000; ++ ++ i2c_smbus_write_byte_data(data->client, TMP401_TEMP_CRIT_HYST, ++ reg); ++ ++ data->temp_crit_hyst = reg; ++ ++ mutex_unlock(&data->update_lock); ++ ++ return count; ++} ++ ++/* ++ * Resets the historical measurements of minimum and maximum temperatures. ++ * This is done by writing any value to any of the minimum/maximum registers ++ * (0x30-0x37). ++ */ ++static ssize_t reset_temp_history(struct device *dev, ++ struct device_attribute *devattr, const char *buf, size_t count) ++{ ++ struct tmp401_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ long val; ++ ++ if (kstrtol(buf, 10, &val)) ++ return -EINVAL; ++ ++ if (val != 1) { ++ dev_err(dev, ++ "temp_reset_history value %ld not supported. Use 1 to reset the history!\n", ++ val); ++ return -EINVAL; ++ } ++ mutex_lock(&data->update_lock); ++ i2c_smbus_write_byte_data(client, TMP401_TEMP_MSB_WRITE[5][0], val); ++ data->valid = 0; ++ mutex_unlock(&data->update_lock); ++ ++ return count; ++} ++ ++static ssize_t show_update_interval(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct tmp401_data *data = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%u\n", data->update_interval); ++} ++ ++static ssize_t set_update_interval(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct tmp401_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ unsigned long val; ++ int err, rate; ++ ++ err = kstrtoul(buf, 10, &val); ++ if (err) ++ return err; ++ ++ /* ++ * For valid rates, interval can be calculated as ++ * interval = (1 << (7 - rate)) * 125; ++ * Rounded rate is therefore ++ * rate = 7 - __fls(interval * 4 / (125 * 3)); ++ * Use clamp_val() to avoid overflows, and to ensure valid input ++ * for __fls. ++ */ ++ val = clamp_val(val, 125, 16000); ++ rate = 7 - __fls(val * 4 / (125 * 3)); ++ mutex_lock(&data->update_lock); ++ i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, rate); ++ data->update_interval = (1 << (7 - rate)) * 125; ++ mutex_unlock(&data->update_lock); ++ ++ return count; ++} ++ ++/* ++ * Enable/disable the state of the timeout function ++ * @dev: device info ++ * @state: 1:enable 0:disable ++ */ ++static int timeout_cfg(struct device *dev, int state) ++{ ++ int rv, chip_type; ++ u8 reg_value; ++ struct tmp401_data *data; ++ struct i2c_client *client; ++ ++ data = dev_get_drvdata(dev); ++ client = data->client; ++ ++ /* get chip type */ ++ chip_type = data->kind; ++ dev_dbg(&client->dev, "set timeout. chip:%d, state:%d\n", chip_type, state); ++ ++ /* chip type check */ ++ if(chip_type != tmp401 && chip_type != tmp411) { ++ dev_info(&client->dev, ++ "Chip type: %d, not support timeout config.!\n", chip_type); ++ return -EPERM; ++ } ++ ++ /* parameter check */ ++ if(state != TIMEOUT_STATE_EN && state != TIMEOUT_STATE_IEN) { ++ dev_err(&client->dev, ++ "Parameter check error. state: %d not supported.!\n", state); ++ return -EINVAL; ++ } ++ ++ mutex_lock(&data->update_lock); ++ /* read the Consecutive alert register */ ++ reg_value = i2c_smbus_read_byte_data(client, TMP401_DEVICE_CAR_REG); ++ if (reg_value < 0) { ++ dev_err(&client->dev, "Failed to read. reg:0x%0x, value:%d\n", TMP401_DEVICE_CAR_REG, reg_value); ++ mutex_unlock(&data->update_lock); ++ return -EIO; ++ } ++ dev_dbg(&client->dev, "get register value. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); ++ ++ /* same value case, do not write */ ++ if((u8)state == (reg_value >> TIMEOUT_STATE_BIT)) { ++ mutex_unlock(&data->update_lock); ++ dev_info(&client->dev, "timeout config has been set and the current state is %d.\n", state); ++ return 0; ++ } ++ ++ /* calculate the register value */ ++ reg_value = (reg_value & ~(1 << TIMEOUT_STATE_BIT)) | (state << TIMEOUT_STATE_BIT); ++ ++ /* set the Consecutive alert register */ ++ dev_dbg(&client->dev, "set register value. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); ++ rv = i2c_smbus_write_byte_data(client, TMP401_DEVICE_CAR_REG, reg_value); ++ if (rv < 0) { ++ dev_err(&client->dev, ++ "set the register Error. reg:0x%0x, value:%d\n", TMP401_DEVICE_CAR_REG, reg_value); ++ mutex_unlock(&data->update_lock); ++ return -EIO; ++ } ++ mutex_unlock(&data->update_lock); ++ ++ dev_info(&client->dev, "set bus timeout success. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); ++ ++ return 0; ++} ++ ++static ssize_t set_timeout_en(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int val, err; ++ struct i2c_client *client; ++ struct tmp401_data *data; ++ ++ data = dev_get_drvdata(dev); ++ client = data->client; ++ ++ err = kstrtoint(buf, 0, &val); ++ if (err) { ++ dev_err(&client->dev, ++ "kstrtoint error: %d.\n", err); ++ return err; ++ } ++ ++ err = timeout_cfg(dev, val); ++ if(err < 0) { ++ dev_err(&client->dev, ++ "set bus timeout error: %d. value:%d!\n", err, val); ++ return err; ++ } ++ ++ return count; ++} ++ ++static ssize_t show_timeout_en(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ int chip_type; ++ u8 reg_value; ++ struct tmp401_data *data; ++ struct i2c_client *client; ++ ++ data = dev_get_drvdata(dev); ++ client = data->client; ++ ++ /* get chip type */ ++ chip_type = data->kind; ++ dev_dbg(&client->dev, "get timeout. chip:%d\n", chip_type); ++ ++ /* chip type check */ ++ if(chip_type != tmp401 && chip_type != tmp411) { ++ dev_info(&client->dev, ++ "Chip type: %d, not support timeout config.!\n", chip_type); ++ /* not support, return NA */ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", TIMEOUT_STATE_NA); ++ } ++ ++ /* read the Consecutive alert register */ ++ reg_value = i2c_smbus_read_byte_data(client, TMP401_DEVICE_CAR_REG); ++ if (reg_value < 0) { ++ dev_err(&client->dev, "Failed to read. reg:0x%0x, value:%d\n", TMP401_DEVICE_CAR_REG, reg_value); ++ return -EIO; ++ } ++ dev_dbg(&client->dev, "get register value. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); ++ ++ /* decode the register value */ ++ reg_value = reg_value >> TIMEOUT_STATE_BIT; ++ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", reg_value); ++} ++ ++static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0); ++static SENSOR_DEVICE_ATTR_2(temp1_min, S_IWUSR | S_IRUGO, show_temp, ++ store_temp, 1, 0); ++static SENSOR_DEVICE_ATTR_2(temp1_max, S_IWUSR | S_IRUGO, show_temp, ++ store_temp, 2, 0); ++static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IWUSR | S_IRUGO, show_temp, ++ store_temp, 3, 0); ++static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, ++ show_temp_crit_hyst, store_temp_crit_hyst, 0); ++static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO, show_status, NULL, ++ 1, TMP432_STATUS_LOCAL); ++static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_status, NULL, ++ 2, TMP432_STATUS_LOCAL); ++static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_status, NULL, ++ 3, TMP432_STATUS_LOCAL); ++static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1); ++static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp, ++ store_temp, 1, 1); ++static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp, ++ store_temp, 2, 1); ++static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IWUSR | S_IRUGO, show_temp, ++ store_temp, 3, 1); ++static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, ++ NULL, 1); ++static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_status, NULL, ++ 0, TMP432_STATUS_REMOTE1); ++static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_status, NULL, ++ 1, TMP432_STATUS_REMOTE1); ++static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_status, NULL, ++ 2, TMP432_STATUS_REMOTE1); ++static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_status, NULL, ++ 3, TMP432_STATUS_REMOTE1); ++ ++static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval, ++ set_update_interval); ++static DEVICE_ATTR(timeout_en, S_IRUGO | S_IWUSR, show_timeout_en, set_timeout_en); ++ ++static struct attribute *tmp401_attributes[] = { ++ &sensor_dev_attr_temp1_input.dev_attr.attr, ++ &sensor_dev_attr_temp1_min.dev_attr.attr, ++ &sensor_dev_attr_temp1_max.dev_attr.attr, ++ &sensor_dev_attr_temp1_crit.dev_attr.attr, ++ &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, ++ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, ++ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, ++ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, ++ ++ &sensor_dev_attr_temp2_input.dev_attr.attr, ++ &sensor_dev_attr_temp2_min.dev_attr.attr, ++ &sensor_dev_attr_temp2_max.dev_attr.attr, ++ &sensor_dev_attr_temp2_crit.dev_attr.attr, ++ &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, ++ &sensor_dev_attr_temp2_fault.dev_attr.attr, ++ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, ++ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, ++ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, ++ ++ &dev_attr_update_interval.attr, ++ &dev_attr_timeout_en.attr, ++ ++ NULL ++}; ++ ++static const struct attribute_group tmp401_group = { ++ .attrs = tmp401_attributes, ++}; ++ ++/* ++ * Additional features of the TMP411 chip. ++ * The TMP411 stores the minimum and maximum ++ * temperature measured since power-on, chip-reset, or ++ * minimum and maximum register reset for both the local ++ * and remote channels. ++ */ ++static SENSOR_DEVICE_ATTR_2(temp1_lowest, S_IRUGO, show_temp, NULL, 4, 0); ++static SENSOR_DEVICE_ATTR_2(temp1_highest, S_IRUGO, show_temp, NULL, 5, 0); ++static SENSOR_DEVICE_ATTR_2(temp2_lowest, S_IRUGO, show_temp, NULL, 4, 1); ++static SENSOR_DEVICE_ATTR_2(temp2_highest, S_IRUGO, show_temp, NULL, 5, 1); ++static SENSOR_DEVICE_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history, ++ 0); ++ ++static struct attribute *tmp411_attributes[] = { ++ &sensor_dev_attr_temp1_highest.dev_attr.attr, ++ &sensor_dev_attr_temp1_lowest.dev_attr.attr, ++ &sensor_dev_attr_temp2_highest.dev_attr.attr, ++ &sensor_dev_attr_temp2_lowest.dev_attr.attr, ++ &sensor_dev_attr_temp_reset_history.dev_attr.attr, ++ NULL ++}; ++ ++static const struct attribute_group tmp411_group = { ++ .attrs = tmp411_attributes, ++}; ++ ++static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2); ++static SENSOR_DEVICE_ATTR_2(temp3_min, S_IWUSR | S_IRUGO, show_temp, ++ store_temp, 1, 2); ++static SENSOR_DEVICE_ATTR_2(temp3_max, S_IWUSR | S_IRUGO, show_temp, ++ store_temp, 2, 2); ++static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IWUSR | S_IRUGO, show_temp, ++ store_temp, 3, 2); ++static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, ++ NULL, 2); ++static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_status, NULL, ++ 0, TMP432_STATUS_REMOTE2); ++static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_status, NULL, ++ 1, TMP432_STATUS_REMOTE2); ++static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_status, NULL, ++ 2, TMP432_STATUS_REMOTE2); ++static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_status, NULL, ++ 3, TMP432_STATUS_REMOTE2); ++ ++static struct attribute *tmp432_attributes[] = { ++ &sensor_dev_attr_temp3_input.dev_attr.attr, ++ &sensor_dev_attr_temp3_min.dev_attr.attr, ++ &sensor_dev_attr_temp3_max.dev_attr.attr, ++ &sensor_dev_attr_temp3_crit.dev_attr.attr, ++ &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, ++ &sensor_dev_attr_temp3_fault.dev_attr.attr, ++ &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, ++ &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, ++ &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, ++ ++ NULL ++}; ++ ++static const struct attribute_group tmp432_group = { ++ .attrs = tmp432_attributes, ++}; ++ ++/* ++ * Additional features of the TMP461 chip. ++ * The TMP461 temperature offset for the remote channel. ++ */ ++static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IWUSR | S_IRUGO, show_temp, ++ store_temp, 6, 1); ++ ++static struct attribute *tmp461_attributes[] = { ++ &sensor_dev_attr_temp2_offset.dev_attr.attr, ++ NULL ++}; ++ ++static const struct attribute_group tmp461_group = { ++ .attrs = tmp461_attributes, ++}; ++ ++/* ++ * Begin non sysfs callback code (aka Real code) ++ */ ++ ++static int tmp401_init_client(struct tmp401_data *data, ++ struct i2c_client *client) ++{ ++ int config, config_orig, status = 0; ++ ++ /* Set the conversion rate to 2 Hz */ ++ i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5); ++ data->update_interval = 500; ++ ++ /* Start conversions (disable shutdown if necessary) */ ++ config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); ++ if (config < 0) ++ return config; ++ ++ config_orig = config; ++ config &= ~TMP401_CONFIG_SHUTDOWN; ++ ++ if (config != config_orig) ++ status = i2c_smbus_write_byte_data(client, ++ TMP401_CONFIG_WRITE, ++ config); ++ ++ return status; ++} ++ ++#if 0 ++static int tmp401_detect(struct i2c_client *client, ++ struct i2c_board_info *info) ++{ ++ enum chips kind; ++ struct i2c_adapter *adapter = client->adapter; ++ u8 reg; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) ++ return -ENODEV; ++ ++ /* Detect and identify the chip */ ++ reg = i2c_smbus_read_byte_data(client, TMP401_MANUFACTURER_ID_REG); ++ if (reg != TMP401_MANUFACTURER_ID) ++ return -ENODEV; ++ ++ reg = i2c_smbus_read_byte_data(client, TMP401_DEVICE_ID_REG); ++ ++ switch (reg) { ++ case TMP401_DEVICE_ID: ++ if (client->addr != 0x4c) ++ return -ENODEV; ++ kind = tmp401; ++ break; ++ case TMP411A_DEVICE_ID: ++ if (client->addr != 0x4c) ++ return -ENODEV; ++ kind = tmp411; ++ break; ++ case TMP411B_DEVICE_ID: ++ if (client->addr != 0x4d) ++ return -ENODEV; ++ kind = tmp411; ++ break; ++ case TMP411C_DEVICE_ID: ++ if (client->addr != 0x4e) ++ return -ENODEV; ++ kind = tmp411; ++ break; ++ case TMP431_DEVICE_ID: ++ if (client->addr != 0x4c && client->addr != 0x4d) ++ return -ENODEV; ++ kind = tmp431; ++ break; ++ case TMP432_DEVICE_ID: ++ if (client->addr != 0x4c && client->addr != 0x4d) ++ return -ENODEV; ++ kind = tmp432; ++ break; ++ case TMP435_DEVICE_ID: ++ kind = tmp435; ++ break; ++ default: ++ return -ENODEV; ++ } ++ ++ reg = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); ++ if (reg & 0x1b) ++ return -ENODEV; ++ ++ reg = i2c_smbus_read_byte_data(client, TMP401_CONVERSION_RATE_READ); ++ /* Datasheet says: 0x1-0x6 */ ++ if (reg > 15) ++ return -ENODEV; ++ ++ strlcpy(info->type, tmp401_id[kind].name, I2C_NAME_SIZE); ++ ++ return 0; ++} ++#endif ++ ++static int tmp401_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ static const char * const names[] = { ++ "TMP401", "TMP411", "TMP431", "TMP432", "TMP435", "TMP461" ++ }; ++ struct device *dev = &client->dev; ++ struct device *hwmon_dev; ++ struct tmp401_data *data; ++ int groups = 0, status; ++ ++ data = devm_kzalloc(dev, sizeof(struct tmp401_data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->client = client; ++ mutex_init(&data->update_lock); ++ data->kind = id->driver_data; ++ ++ /* Initialize the TMP401 chip */ ++ status = tmp401_init_client(data, client); ++ if (status < 0) ++ return status; ++ ++ /* Register sysfs hooks */ ++ data->groups[groups++] = &tmp401_group; ++ ++ /* Register additional tmp411 sysfs hooks */ ++ if (data->kind == tmp411) ++ data->groups[groups++] = &tmp411_group; ++ ++ /* Register additional tmp432 sysfs hooks */ ++ if (data->kind == tmp432) ++ data->groups[groups++] = &tmp432_group; ++ ++ if (data->kind == tmp461) ++ data->groups[groups++] = &tmp461_group; ++ ++ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, ++ data, data->groups); ++ if (IS_ERR(hwmon_dev)) ++ return PTR_ERR(hwmon_dev); ++ ++ /* disable the timeout function */ ++ status = timeout_cfg(hwmon_dev, TIMEOUT_STATE_IEN); ++ if((status < 0) && (status != -EPERM)) { ++ dev_err(dev, ++ "set bus timeout error when probing: %d.!\n", status); ++ /* here, no need call devm_hwmon_device_unregister, device managed. */ ++ return status; ++ } ++ ++ dev_info(dev, "Detected TI %s chip\n", names[data->kind]); ++ ++ return 0; ++} ++ ++static struct i2c_driver tmp401_driver = { ++ .class = I2C_CLASS_HWMON, ++ .driver = { ++ .name = "wb_tmp401", ++ }, ++ .probe = tmp401_probe, ++ .id_table = tmp401_id, ++ /* .detect = tmp401_detect, */ ++ /* .address_list = normal_i2c, */ ++}; ++ ++module_i2c_driver(tmp401_driver); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("Texas Instruments TMP401 temperature sensor driver"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tps53622.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tps53622.c +new file mode 100644 +index 000000000..b68196d9f +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tps53622.c +@@ -0,0 +1,265 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Hardware monitoring driver for Texas Instruments TPS53679 ++ * ++ * Copyright (c) 2017 Mellanox Technologies. All rights reserved. ++ * Copyright (c) 2017 Vadim Pasternak ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "wb_pmbus.h" ++ ++enum chips { ++ tps53647, tps53667, tps53679, tps53681, tps53688, tps53622 ++}; ++ ++#define TPS53647_PAGE_NUM 1 ++ ++#define TPS53679_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */ ++#define TPS53679_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */ ++#define TPS53679_PROT_VR13_10MV 0x04 /* VR13.0 mode, 10-mV DAC */ ++#define TPS53679_PROT_IMVP8_5MV 0x05 /* IMVP8 mode, 5-mV DAC */ ++#define TPS53679_PROT_VR13_5MV 0x07 /* VR13.0 mode, 5-mV DAC */ ++#define TPS53679_PAGE_NUM 2 ++ ++#define TPS53681_DEVICE_ID 0x81 ++ ++#define TPS53681_PMBUS_REVISION 0x33 ++ ++#define TPS53681_MFR_SPECIFIC_20 0xe4 /* Number of phases, per page */ ++ ++static const struct i2c_device_id tps53679_id[]; ++ ++static int tps53679_identify_mode(struct i2c_client *client, ++ struct pmbus_driver_info *info) ++{ ++ u8 vout_params; ++ int i, ret; ++ ++ for (i = 0; i < info->pages; i++) { ++ /* Read the register with VOUT scaling value.*/ ++ ret = wb_pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); ++ if (ret < 0) ++ return ret; ++ ++ vout_params = ret & GENMASK(4, 0); ++ ++ switch (vout_params) { ++ case TPS53679_PROT_VR13_10MV: ++ case TPS53679_PROT_VR12_5_10MV: ++ info->vrm_version[i] = vr13; ++ break; ++ case TPS53679_PROT_VR13_5MV: ++ case TPS53679_PROT_VR12_5MV: ++ case TPS53679_PROT_IMVP8_5MV: ++ info->vrm_version[i] = vr12; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static int tps53679_identify_phases(struct i2c_client *client, ++ struct pmbus_driver_info *info) ++{ ++ int ret; ++ ++ /* On TPS53681, only channel A provides per-phase output current */ ++ ret = wb_pmbus_read_byte_data(client, 0, TPS53681_MFR_SPECIFIC_20); ++ if (ret < 0) ++ return ret; ++ info->phases[0] = (ret & 0x07) + 1; ++ ++ return 0; ++} ++ ++static int tps53679_identify_chip(struct i2c_client *client, ++ u8 revision, u16 id) ++{ ++ u8 buf[I2C_SMBUS_BLOCK_MAX]; ++ int ret; ++ ++ ret = wb_pmbus_read_byte_data(client, 0, PMBUS_REVISION); ++ if (ret < 0) ++ return ret; ++ if (ret != revision) { ++ dev_err(&client->dev, "Unexpected PMBus revision 0x%x\n", ret); ++ return -ENODEV; ++ } ++ ++ ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf); ++ if (ret < 0) ++ return ret; ++ if (ret != 1 || buf[0] != id) { ++ dev_err(&client->dev, "Unexpected device ID 0x%x\n", buf[0]); ++ return -ENODEV; ++ } ++ return 0; ++} ++ ++/* ++ * Common identification function for chips with multi-phase support. ++ * Since those chips have special configuration registers, we want to have ++ * some level of reassurance that we are really talking with the chip ++ * being probed. Check PMBus revision and chip ID. ++ */ ++static int tps53679_identify_multiphase(struct i2c_client *client, ++ struct pmbus_driver_info *info, ++ int pmbus_rev, int device_id) ++{ ++ int ret; ++ ++ ret = tps53679_identify_chip(client, pmbus_rev, device_id); ++ if (ret < 0) ++ return ret; ++ ++ ret = tps53679_identify_mode(client, info); ++ if (ret < 0) ++ return ret; ++ ++ return tps53679_identify_phases(client, info); ++} ++ ++static int tps53679_identify(struct i2c_client *client, ++ struct pmbus_driver_info *info) ++{ ++ return tps53679_identify_mode(client, info); ++} ++ ++static int tps53681_identify(struct i2c_client *client, ++ struct pmbus_driver_info *info) ++{ ++ return tps53679_identify_multiphase(client, info, ++ TPS53681_PMBUS_REVISION, ++ TPS53681_DEVICE_ID); ++} ++ ++static int tps53681_read_word_data(struct i2c_client *client, int page, ++ int phase, int reg) ++{ ++ /* ++ * For reading the total output current (READ_IOUT) for all phases, ++ * the chip datasheet is a bit vague. It says "PHASE must be set to ++ * FFh to access all phases simultaneously. PHASE may also be set to ++ * 80h readack (!) the total phase current". ++ * Experiments show that the command does _not_ report the total ++ * current for all phases if the phase is set to 0xff. Instead, it ++ * appears to report the current of one of the phases. Override phase ++ * parameter with 0x80 when reading the total output current on page 0. ++ */ ++ if (reg == PMBUS_READ_IOUT && page == 0 && phase == 0xff) ++ return wb_pmbus_read_word_data(client, page, 0x80, reg); ++ return -ENODATA; ++} ++ ++static struct pmbus_driver_info tps53679_info = { ++ .format[PSC_VOLTAGE_IN] = linear, ++ .format[PSC_VOLTAGE_OUT] = vid, ++ .format[PSC_TEMPERATURE] = linear, ++ .format[PSC_CURRENT_OUT] = linear, ++ .format[PSC_POWER] = linear, ++ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | ++ PMBUS_HAVE_STATUS_INPUT | ++ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ++ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | ++ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | ++ PMBUS_HAVE_POUT, ++ .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ++ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | ++ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | ++ PMBUS_HAVE_POUT, ++ .pfunc[0] = PMBUS_HAVE_IOUT, ++ .pfunc[1] = PMBUS_HAVE_IOUT, ++ .pfunc[2] = PMBUS_HAVE_IOUT, ++ .pfunc[3] = PMBUS_HAVE_IOUT, ++ .pfunc[4] = PMBUS_HAVE_IOUT, ++ .pfunc[5] = PMBUS_HAVE_IOUT, ++}; ++ ++static int tps53679_probe(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct pmbus_driver_info *info; ++ enum chips chip_id; ++ ++ if (dev->of_node) ++ chip_id = (enum chips)of_device_get_match_data(dev); ++ else ++ chip_id = i2c_match_id(tps53679_id, client)->driver_data; ++ ++ info = devm_kmemdup(dev, &tps53679_info, sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ ++ switch (chip_id) { ++ case tps53647: ++ case tps53667: ++ info->pages = TPS53647_PAGE_NUM; ++ info->identify = tps53679_identify; ++ break; ++ case tps53679: ++ case tps53688: ++ case tps53622: ++ info->pages = TPS53679_PAGE_NUM; ++ info->identify = tps53679_identify; ++ break; ++ case tps53681: ++ info->pages = TPS53679_PAGE_NUM; ++ info->phases[0] = 6; ++ info->identify = tps53681_identify; ++ info->read_word_data = tps53681_read_word_data; ++ break; ++ default: ++ return -ENODEV; ++ } ++ ++ return wb_pmbus_do_probe(client, info); ++} ++ ++static const struct i2c_device_id tps53679_id[] = { ++ {"wb_tps53647", tps53647}, ++ {"wb_tps53667", tps53667}, ++ {"wb_tps53679", tps53679}, ++ {"wb_tps53681", tps53681}, ++ {"wb_tps53688", tps53688}, ++ {"wb_tps53622", tps53622}, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(i2c, tps53679_id); ++ ++static const struct of_device_id __maybe_unused tps53679_of_match[] = { ++ {.compatible = "ti,wb_tps53647", .data = (void *)tps53647}, ++ {.compatible = "ti,wb_tps53667", .data = (void *)tps53667}, ++ {.compatible = "ti,wb_tps53679", .data = (void *)tps53679}, ++ {.compatible = "ti,wb_tps53681", .data = (void *)tps53681}, ++ {.compatible = "ti,wb_tps53688", .data = (void *)tps53688}, ++ {.compatible = "ti,wb_tps53622", .data = (void *)tps53622}, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, tps53679_of_match); ++ ++static struct i2c_driver tps53679_driver = { ++ .driver = { ++ .name = "wb_tps53622", ++ .of_match_table = of_match_ptr(tps53679_of_match), ++ }, ++ .probe_new = tps53679_probe, ++ .remove = wb_pmbus_do_remove, ++ .id_table = tps53679_id, ++}; ++ ++module_i2c_driver(tps53679_driver); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("PMBus driver for Texas Instruments TPS53679"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ucd9000.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ucd9000.c +new file mode 100644 +index 000000000..5c3d125af +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ucd9000.c +@@ -0,0 +1,676 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Hardware monitoring driver for UCD90xxx Sequencer and System Health ++ * Controller series ++ * ++ * Copyright (C) 2011 Ericsson AB. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "wb_pmbus.h" ++ ++enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd90320, ucd9090, ++ ucd90910 }; ++ ++#define UCD9000_MONITOR_CONFIG 0xd5 ++#define UCD9000_NUM_PAGES 0xd6 ++#define UCD9000_FAN_CONFIG_INDEX 0xe7 ++#define UCD9000_FAN_CONFIG 0xe8 ++#define UCD9000_MFR_STATUS 0xf3 ++#define UCD9000_GPIO_SELECT 0xfa ++#define UCD9000_GPIO_CONFIG 0xfb ++#define UCD9000_DEVICE_ID 0xfd ++ ++/* GPIO CONFIG bits */ ++#define UCD9000_GPIO_CONFIG_ENABLE BIT(0) ++#define UCD9000_GPIO_CONFIG_OUT_ENABLE BIT(1) ++#define UCD9000_GPIO_CONFIG_OUT_VALUE BIT(2) ++#define UCD9000_GPIO_CONFIG_STATUS BIT(3) ++#define UCD9000_GPIO_INPUT 0 ++#define UCD9000_GPIO_OUTPUT 1 ++ ++#define UCD9000_MON_TYPE(x) (((x) >> 5) & 0x07) ++#define UCD9000_MON_PAGE(x) ((x) & 0x1f) ++ ++#define UCD9000_MON_VOLTAGE 1 ++#define UCD9000_MON_TEMPERATURE 2 ++#define UCD9000_MON_CURRENT 3 ++#define UCD9000_MON_VOLTAGE_HW 4 ++ ++#define UCD9000_NUM_FAN 4 ++ ++#define UCD9000_GPIO_NAME_LEN 16 ++#define UCD9090_NUM_GPIOS 23 ++#define UCD901XX_NUM_GPIOS 26 ++#define UCD90320_NUM_GPIOS 84 ++#define UCD90910_NUM_GPIOS 26 ++ ++#define UCD9000_DEBUGFS_NAME_LEN 24 ++#define UCD9000_GPI_COUNT 8 ++#define UCD90320_GPI_COUNT 32 ++ ++#define UCD9000_RETRY_SLEEP_TIME (10000) /* 10ms */ ++#define UCD9000_RETRY_TIME (3) ++#define WB_DEV_NAME_MAX_LEN (64) ++ ++static int g_wb_ucd9000_debug = 0; ++static int g_wb_ucd9000_error = 0; ++ ++module_param(g_wb_ucd9000_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_ucd9000_error, int, S_IRUGO | S_IWUSR); ++ ++#define WB_UDC9000_VERBOSE(fmt, args...) do { \ ++ if (g_wb_ucd9000_debug) { \ ++ printk(KERN_INFO "[WB_UCD9000][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_UDC9000_ERROR(fmt, args...) do { \ ++ if (g_wb_ucd9000_error) { \ ++ printk(KERN_ERR "[WB_UCD9000][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++struct ucd9000_data { ++ u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX]; ++ struct pmbus_driver_info info; ++#ifdef CONFIG_GPIOLIB ++ struct gpio_chip gpio; ++#endif ++ struct dentry *debugfs; ++}; ++#define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info) ++ ++struct ucd9000_debugfs_entry { ++ struct i2c_client *client; ++ u8 index; ++}; ++ ++static int wb_i2c_smbus_read_block_data(const struct i2c_client *client, u8 command, u8 *values) ++{ ++ int rv, i; ++ ++ for(i = 0; i < UCD9000_RETRY_TIME; i++) { ++ rv = i2c_smbus_read_block_data(client, command, values); ++ if(rv >= 0){ ++ return rv; ++ } ++ usleep_range(UCD9000_RETRY_SLEEP_TIME, UCD9000_RETRY_SLEEP_TIME + 1); ++ } ++ WB_UDC9000_ERROR("read_block_data failed. nr:%d, addr:0x%x, reg:0x%x, rv:%d.", ++ client->adapter->nr, client->addr, command, rv); ++ return rv; ++} ++ ++static int ucd9000_get_fan_config(struct i2c_client *client, int fan) ++{ ++ int fan_config = 0; ++ struct ucd9000_data *data ++ = to_ucd9000_data(wb_pmbus_get_driver_info(client)); ++ ++ if (data->fan_data[fan][3] & 1) ++ fan_config |= PB_FAN_2_INSTALLED; /* Use lower bit position */ ++ ++ /* Pulses/revolution */ ++ fan_config |= (data->fan_data[fan][3] & 0x06) >> 1; ++ ++ return fan_config; ++} ++ ++static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg) ++{ ++ int ret = 0; ++ int fan_config; ++ ++ switch (reg) { ++ case PMBUS_FAN_CONFIG_12: ++ if (page > 0) ++ return -ENXIO; ++ ++ ret = ucd9000_get_fan_config(client, 0); ++ if (ret < 0) ++ return ret; ++ fan_config = ret << 4; ++ ret = ucd9000_get_fan_config(client, 1); ++ if (ret < 0) ++ return ret; ++ fan_config |= ret; ++ ret = fan_config; ++ break; ++ case PMBUS_FAN_CONFIG_34: ++ if (page > 0) ++ return -ENXIO; ++ ++ ret = ucd9000_get_fan_config(client, 2); ++ if (ret < 0) ++ return ret; ++ fan_config = ret << 4; ++ ret = ucd9000_get_fan_config(client, 3); ++ if (ret < 0) ++ return ret; ++ fan_config |= ret; ++ ret = fan_config; ++ break; ++ default: ++ ret = -ENODATA; ++ break; ++ } ++ return ret; ++} ++ ++static const struct i2c_device_id ucd9000_id[] = { ++ {"wb_ucd9000", ucd9000}, ++ {"wb_ucd90120", ucd90120}, ++ {"wb_ucd90124", ucd90124}, ++ {"wb_ucd90160", ucd90160}, ++ {"wb_ucd90320", ucd90320}, ++ {"wb_ucd9090", ucd9090}, ++ {"wb_ucd90910", ucd90910}, ++ {} ++}; ++MODULE_DEVICE_TABLE(i2c, ucd9000_id); ++ ++static const struct of_device_id __maybe_unused ucd9000_of_match[] = { ++ { ++ .compatible = "ti,wb_ucd9000", ++ .data = (void *)ucd9000 ++ }, ++ { ++ .compatible = "ti,wb_ucd90120", ++ .data = (void *)ucd90120 ++ }, ++ { ++ .compatible = "ti,wb_ucd90124", ++ .data = (void *)ucd90124 ++ }, ++ { ++ .compatible = "ti,wb_ucd90160", ++ .data = (void *)ucd90160 ++ }, ++ { ++ .compatible = "ti,wb_ucd90320", ++ .data = (void *)ucd90320 ++ }, ++ { ++ .compatible = "ti,wb_ucd9090", ++ .data = (void *)ucd9090 ++ }, ++ { ++ .compatible = "ti,wb_ucd90910", ++ .data = (void *)ucd90910 ++ }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, ucd9000_of_match); ++ ++#ifdef CONFIG_GPIOLIB ++static int ucd9000_gpio_read_config(struct i2c_client *client, ++ unsigned int offset) ++{ ++ int ret; ++ ++ /* No page set required */ ++ ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_SELECT, offset); ++ if (ret < 0) ++ return ret; ++ ++ return i2c_smbus_read_byte_data(client, UCD9000_GPIO_CONFIG); ++} ++ ++static int ucd9000_gpio_get(struct gpio_chip *gc, unsigned int offset) ++{ ++ struct i2c_client *client = gpiochip_get_data(gc); ++ int ret; ++ ++ ret = ucd9000_gpio_read_config(client, offset); ++ if (ret < 0) ++ return ret; ++ ++ return !!(ret & UCD9000_GPIO_CONFIG_STATUS); ++} ++ ++static void ucd9000_gpio_set(struct gpio_chip *gc, unsigned int offset, ++ int value) ++{ ++ struct i2c_client *client = gpiochip_get_data(gc); ++ int ret; ++ ++ ret = ucd9000_gpio_read_config(client, offset); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "failed to read GPIO %d config: %d\n", ++ offset, ret); ++ return; ++ } ++ ++ if (value) { ++ if (ret & UCD9000_GPIO_CONFIG_STATUS) ++ return; ++ ++ ret |= UCD9000_GPIO_CONFIG_STATUS; ++ } else { ++ if (!(ret & UCD9000_GPIO_CONFIG_STATUS)) ++ return; ++ ++ ret &= ~UCD9000_GPIO_CONFIG_STATUS; ++ } ++ ++ ret |= UCD9000_GPIO_CONFIG_ENABLE; ++ ++ /* Page set not required */ ++ ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, ret); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "Failed to write GPIO %d config: %d\n", ++ offset, ret); ++ return; ++ } ++ ++ ret &= ~UCD9000_GPIO_CONFIG_ENABLE; ++ ++ ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, ret); ++ if (ret < 0) ++ dev_dbg(&client->dev, "Failed to write GPIO %d config: %d\n", ++ offset, ret); ++} ++ ++static int ucd9000_gpio_get_direction(struct gpio_chip *gc, ++ unsigned int offset) ++{ ++ struct i2c_client *client = gpiochip_get_data(gc); ++ int ret; ++ ++ ret = ucd9000_gpio_read_config(client, offset); ++ if (ret < 0) ++ return ret; ++ ++ return !(ret & UCD9000_GPIO_CONFIG_OUT_ENABLE); ++} ++ ++static int ucd9000_gpio_set_direction(struct gpio_chip *gc, ++ unsigned int offset, bool direction_out, ++ int requested_out) ++{ ++ struct i2c_client *client = gpiochip_get_data(gc); ++ int ret, config, out_val; ++ ++ ret = ucd9000_gpio_read_config(client, offset); ++ if (ret < 0) ++ return ret; ++ ++ if (direction_out) { ++ out_val = requested_out ? UCD9000_GPIO_CONFIG_OUT_VALUE : 0; ++ ++ if (ret & UCD9000_GPIO_CONFIG_OUT_ENABLE) { ++ if ((ret & UCD9000_GPIO_CONFIG_OUT_VALUE) == out_val) ++ return 0; ++ } else { ++ ret |= UCD9000_GPIO_CONFIG_OUT_ENABLE; ++ } ++ ++ if (out_val) ++ ret |= UCD9000_GPIO_CONFIG_OUT_VALUE; ++ else ++ ret &= ~UCD9000_GPIO_CONFIG_OUT_VALUE; ++ ++ } else { ++ if (!(ret & UCD9000_GPIO_CONFIG_OUT_ENABLE)) ++ return 0; ++ ++ ret &= ~UCD9000_GPIO_CONFIG_OUT_ENABLE; ++ } ++ ++ ret |= UCD9000_GPIO_CONFIG_ENABLE; ++ config = ret; ++ ++ /* Page set not required */ ++ ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, config); ++ if (ret < 0) ++ return ret; ++ ++ config &= ~UCD9000_GPIO_CONFIG_ENABLE; ++ ++ return i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, config); ++} ++ ++static int ucd9000_gpio_direction_input(struct gpio_chip *gc, ++ unsigned int offset) ++{ ++ return ucd9000_gpio_set_direction(gc, offset, UCD9000_GPIO_INPUT, 0); ++} ++ ++static int ucd9000_gpio_direction_output(struct gpio_chip *gc, ++ unsigned int offset, int val) ++{ ++ return ucd9000_gpio_set_direction(gc, offset, UCD9000_GPIO_OUTPUT, ++ val); ++} ++ ++static void ucd9000_probe_gpio(struct i2c_client *client, ++ const struct i2c_device_id *mid, ++ struct ucd9000_data *data) ++{ ++ int rc; ++ ++ switch (mid->driver_data) { ++ case ucd9090: ++ data->gpio.ngpio = UCD9090_NUM_GPIOS; ++ break; ++ case ucd90120: ++ case ucd90124: ++ case ucd90160: ++ data->gpio.ngpio = UCD901XX_NUM_GPIOS; ++ break; ++ case ucd90320: ++ data->gpio.ngpio = UCD90320_NUM_GPIOS; ++ break; ++ case ucd90910: ++ data->gpio.ngpio = UCD90910_NUM_GPIOS; ++ break; ++ default: ++ return; /* GPIO support is optional. */ ++ } ++ ++ /* ++ * Pinmux support has not been added to the new gpio_chip. ++ * This support should be added when possible given the mux ++ * behavior of these IO devices. ++ */ ++ data->gpio.label = client->name; ++ data->gpio.get_direction = ucd9000_gpio_get_direction; ++ data->gpio.direction_input = ucd9000_gpio_direction_input; ++ data->gpio.direction_output = ucd9000_gpio_direction_output; ++ data->gpio.get = ucd9000_gpio_get; ++ data->gpio.set = ucd9000_gpio_set; ++ data->gpio.can_sleep = true; ++ data->gpio.base = -1; ++ data->gpio.parent = &client->dev; ++ ++ rc = devm_gpiochip_add_data(&client->dev, &data->gpio, client); ++ if (rc) ++ dev_warn(&client->dev, "Could not add gpiochip: %d\n", rc); ++} ++#else ++static void ucd9000_probe_gpio(struct i2c_client *client, ++ const struct i2c_device_id *mid, ++ struct ucd9000_data *data) ++{ ++} ++#endif /* CONFIG_GPIOLIB */ ++ ++#ifdef CONFIG_DEBUG_FS ++static int ucd9000_get_mfr_status(struct i2c_client *client, u8 *buffer) ++{ ++ int ret = wb_pmbus_set_page(client, 0, 0xff); ++ ++ if (ret < 0) ++ return ret; ++ ++ return wb_i2c_smbus_read_block_data(client, UCD9000_MFR_STATUS, buffer); ++} ++ ++static int ucd9000_debugfs_show_mfr_status_bit(void *data, u64 *val) ++{ ++ struct ucd9000_debugfs_entry *entry = data; ++ struct i2c_client *client = entry->client; ++ u8 buffer[I2C_SMBUS_BLOCK_MAX]; ++ int ret, i; ++ ++ ret = ucd9000_get_mfr_status(client, buffer); ++ if (ret < 0) ++ return ret; ++ ++ /* ++ * GPI fault bits are in sets of 8, two bytes from end of response. ++ */ ++ i = ret - 3 - entry->index / 8; ++ if (i >= 0) ++ *val = !!(buffer[i] & BIT(entry->index % 8)); ++ ++ return 0; ++} ++DEFINE_DEBUGFS_ATTRIBUTE(ucd9000_debugfs_mfr_status_bit, ++ ucd9000_debugfs_show_mfr_status_bit, NULL, "%1lld\n"); ++ ++static ssize_t ucd9000_debugfs_read_mfr_status(struct file *file, ++ char __user *buf, size_t count, ++ loff_t *ppos) ++{ ++ struct i2c_client *client = file->private_data; ++ u8 buffer[I2C_SMBUS_BLOCK_MAX]; ++ char str[(I2C_SMBUS_BLOCK_MAX * 2) + 2]; ++ char *res; ++ int rc; ++ ++ rc = ucd9000_get_mfr_status(client, buffer); ++ if (rc < 0) ++ return rc; ++ ++ res = bin2hex(str, buffer, min(rc, I2C_SMBUS_BLOCK_MAX)); ++ *res++ = '\n'; ++ *res = 0; ++ ++ return simple_read_from_buffer(buf, count, ppos, str, res - str); ++} ++ ++static const struct file_operations ucd9000_debugfs_show_mfr_status_fops = { ++ .llseek = noop_llseek, ++ .read = ucd9000_debugfs_read_mfr_status, ++ .open = simple_open, ++}; ++ ++static int ucd9000_init_debugfs(struct i2c_client *client, ++ const struct i2c_device_id *mid, ++ struct ucd9000_data *data) ++{ ++ struct dentry *debugfs; ++ struct ucd9000_debugfs_entry *entries; ++ int i, gpi_count; ++ char name[UCD9000_DEBUGFS_NAME_LEN]; ++ ++ debugfs = wb_pmbus_get_debugfs_dir(client); ++ if (!debugfs) ++ return -ENOENT; ++ ++ data->debugfs = debugfs_create_dir(client->name, debugfs); ++ if (!data->debugfs) ++ return -ENOENT; ++ ++ /* ++ * Of the chips this driver supports, only the UCD9090, UCD90160, ++ * UCD90320, and UCD90910 report GPI faults in their MFR_STATUS ++ * register, so only create the GPI fault debugfs attributes for those ++ * chips. ++ */ ++ if (mid->driver_data == ucd9090 || mid->driver_data == ucd90160 || ++ mid->driver_data == ucd90320 || mid->driver_data == ucd90910) { ++ gpi_count = mid->driver_data == ucd90320 ? UCD90320_GPI_COUNT ++ : UCD9000_GPI_COUNT; ++ entries = devm_kcalloc(&client->dev, ++ gpi_count, sizeof(*entries), ++ GFP_KERNEL); ++ if (!entries) ++ return -ENOMEM; ++ ++ for (i = 0; i < gpi_count; i++) { ++ entries[i].client = client; ++ entries[i].index = i; ++ scnprintf(name, UCD9000_DEBUGFS_NAME_LEN, ++ "gpi%d_alarm", i + 1); ++ debugfs_create_file(name, 0444, data->debugfs, ++ &entries[i], ++ &ucd9000_debugfs_mfr_status_bit); ++ } ++ } ++ ++ scnprintf(name, UCD9000_DEBUGFS_NAME_LEN, "mfr_status"); ++ debugfs_create_file(name, 0444, data->debugfs, client, ++ &ucd9000_debugfs_show_mfr_status_fops); ++ ++ return 0; ++} ++#else ++static int ucd9000_init_debugfs(struct i2c_client *client, ++ const struct i2c_device_id *mid, ++ struct ucd9000_data *data) ++{ ++ return 0; ++} ++#endif /* CONFIG_DEBUG_FS */ ++ ++static int ucd9000_probe(struct i2c_client *client) ++{ ++ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; ++ char wb_device_name[WB_DEV_NAME_MAX_LEN]; ++ struct ucd9000_data *data; ++ struct pmbus_driver_info *info; ++ const struct i2c_device_id *mid; ++ enum chips chip; ++ int i, ret; ++ ++ if (!i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_BYTE_DATA | ++ I2C_FUNC_SMBUS_BLOCK_DATA)) ++ return -ENODEV; ++ ++ ret = wb_i2c_smbus_read_block_data(client, UCD9000_DEVICE_ID, ++ block_buffer); ++ if (ret < 0) { ++ dev_err(&client->dev, "Failed to read device ID\n"); ++ return ret; ++ } ++ block_buffer[ret] = '\0'; ++ dev_info(&client->dev, "Device ID %s\n", block_buffer); ++ ++ mem_clear(wb_device_name, sizeof(wb_device_name)); ++ snprintf(wb_device_name, sizeof(wb_device_name), "wb_%s", block_buffer); ++ ++ for (mid = ucd9000_id; mid->name[0]; mid++) { ++ if (!strncasecmp(mid->name, wb_device_name, strlen(mid->name))) ++ break; ++ } ++ if (!mid->name[0]) { ++ dev_err(&client->dev, "Unsupported device\n"); ++ return -ENODEV; ++ } ++ ++ if (client->dev.of_node) ++ chip = (enum chips)of_device_get_match_data(&client->dev); ++ else ++ chip = mid->driver_data; ++ ++ if (chip != ucd9000 && strcmp(client->name, mid->name) != 0) ++ dev_notice(&client->dev, ++ "Device mismatch: Configured %s, detected %s\n", ++ client->name, mid->name); ++ ++ data = devm_kzalloc(&client->dev, sizeof(struct ucd9000_data), ++ GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ info = &data->info; ++ ++ ret = i2c_smbus_read_byte_data(client, UCD9000_NUM_PAGES); ++ if (ret < 0) { ++ dev_err(&client->dev, ++ "Failed to read number of active pages\n"); ++ return ret; ++ } ++ info->pages = ret; ++ if (!info->pages) { ++ dev_err(&client->dev, "No pages configured\n"); ++ return -ENODEV; ++ } ++ ++ /* The internal temperature sensor is always active */ ++ /* ucd90160 have no temperature */ ++ /* info->func[0] = PMBUS_HAVE_TEMP; */ ++ ++ /* Everything else is configurable */ ++ ret = wb_i2c_smbus_read_block_data(client, UCD9000_MONITOR_CONFIG, ++ block_buffer); ++ if (ret <= 0) { ++ dev_err(&client->dev, "Failed to read configuration data\n"); ++ return -ENODEV; ++ } ++ for (i = 0; i < ret; i++) { ++ int page = UCD9000_MON_PAGE(block_buffer[i]); ++ ++ if (page >= info->pages) ++ continue; ++ ++ switch (UCD9000_MON_TYPE(block_buffer[i])) { ++ case UCD9000_MON_VOLTAGE: ++ case UCD9000_MON_VOLTAGE_HW: ++ info->func[page] |= PMBUS_HAVE_VOUT ++ | PMBUS_HAVE_STATUS_VOUT; ++ break; ++ case UCD9000_MON_TEMPERATURE: ++ info->func[page] |= PMBUS_HAVE_TEMP2 ++ | PMBUS_HAVE_STATUS_TEMP; ++ break; ++ case UCD9000_MON_CURRENT: ++ info->func[page] |= PMBUS_HAVE_IOUT ++ | PMBUS_HAVE_STATUS_IOUT; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ /* Fan configuration */ ++ if (mid->driver_data == ucd90124) { ++ for (i = 0; i < UCD9000_NUM_FAN; i++) { ++ i2c_smbus_write_byte_data(client, ++ UCD9000_FAN_CONFIG_INDEX, i); ++ ret = wb_i2c_smbus_read_block_data(client, ++ UCD9000_FAN_CONFIG, ++ data->fan_data[i]); ++ if (ret < 0) ++ return ret; ++ } ++ i2c_smbus_write_byte_data(client, UCD9000_FAN_CONFIG_INDEX, 0); ++ ++ info->read_byte_data = ucd9000_read_byte_data; ++ info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 ++ | PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34; ++ } ++ ++ ucd9000_probe_gpio(client, mid, data); ++ ++ ret = wb_pmbus_do_probe(client, info); ++ if (ret) ++ return ret; ++ ++ ret = ucd9000_init_debugfs(client, mid, data); ++ if (ret) ++ dev_warn(&client->dev, "Failed to register debugfs: %d\n", ++ ret); ++ ++ return 0; ++} ++ ++/* This is the driver that will be inserted */ ++static struct i2c_driver ucd9000_driver = { ++ .driver = { ++ .name = "wb_ucd9000", ++ .of_match_table = of_match_ptr(ucd9000_of_match), ++ }, ++ .probe_new = ucd9000_probe, ++ .remove = wb_pmbus_do_remove, ++ .id_table = ucd9000_id, ++}; ++ ++module_i2c_driver(ucd9000_driver); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe12284.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe12284.c +new file mode 100644 +index 000000000..404c349f5 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe12284.c +@@ -0,0 +1,495 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Hardware monitoring driver for Infineon Multi-phase Digital VR Controllers ++ * ++ * Copyright (c) 2020 Mellanox Technologies. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "wb_pmbus.h" ++ ++#define XDPE122_PROT_VR12_5MV (0x01) /* VR12.0 mode, 5-mV DAC */ ++#define XDPE122_PROT_VR12_5_10MV (0x02) /* VR12.5 mode, 10-mV DAC */ ++#define XDPE122_PROT_IMVP9_10MV (0x03) /* IMVP9 mode, 10-mV DAC */ ++#define XDPE122_AMD_625MV (0x10) /* AMD mode 6.25mV */ ++#define XDPE122_PAGE_NUM (2) ++#define XDPE122_WRITE_PROTECT_CLOSE (0x00) ++#define XDPE122_WRITE_PROTECT_OPEN (0x40) ++ ++static int g_wb_xdpe122_debug = 0; ++static int g_wb_xdpe122_error = 0; ++ ++module_param(g_wb_xdpe122_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_xdpe122_error, int, S_IRUGO | S_IWUSR); ++ ++#define WB_XDPE122_VERBOSE(fmt, args...) do { \ ++ if (g_wb_xdpe122_debug) { \ ++ printk(KERN_INFO "[WB_XDPE122][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_XDPE122_ERROR(fmt, args...) do { \ ++ if (g_wb_xdpe122_error) { \ ++ printk(KERN_ERR "[WB_XDPE122][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static int xdpe122_data2reg_vid(struct pmbus_data *data, int page, long val) ++{ ++ int vrm_version; ++ ++ vrm_version = data->info->vrm_version[page]; ++ WB_XDPE122_VERBOSE("page%d, vrm_version: %d, data_val: %ld\n", ++ page, vrm_version, val); ++ /* Convert data to VID register. */ ++ switch (vrm_version) { ++ case vr13: ++ if (val >= 500) { ++ return 1 + DIV_ROUND_CLOSEST(val - 500, 10); ++ } ++ return 0; ++ case vr12: ++ if (val >= 250) { ++ return 1 + DIV_ROUND_CLOSEST(val - 250, 5); ++ } ++ return 0; ++ case imvp9: ++ if (val >= 200) { ++ return 1 + DIV_ROUND_CLOSEST(val - 200, 10); ++ } ++ return 0; ++ case amd625mv: ++ if (val >= 200 && val <= 1550) { ++ return DIV_ROUND_CLOSEST((1550 - val) * 100, 625); ++ } ++ return 0; ++ default: ++ WB_XDPE122_ERROR("Unsupport vrm_version, page%d, vrm_version: %d\n", ++ page, vrm_version); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Convert VID sensor values to milli- or micro-units ++ * depending on sensor type. ++ */ ++static s64 xdpe122_reg2data_vid(struct pmbus_data *data, int page, long val) ++{ ++ ++ long rv; ++ int vrm_version; ++ ++ rv = 0; ++ vrm_version = data->info->vrm_version[page]; ++ switch (vrm_version) { ++ case vr11: ++ if (val >= 0x02 && val <= 0xb2) ++ rv = DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); ++ break; ++ case vr12: ++ if (val >= 0x01) ++ rv = 250 + (val - 1) * 5; ++ break; ++ case vr13: ++ if (val >= 0x01) ++ rv = 500 + (val - 1) * 10; ++ break; ++ case imvp9: ++ if (val >= 0x01) ++ rv = 200 + (val - 1) * 10; ++ break; ++ case amd625mv: ++ if (val >= 0x0 && val <= 0xd8) ++ rv = DIV_ROUND_CLOSEST(155000 - val * 625, 100); ++ break; ++ } ++ WB_XDPE122_VERBOSE("page%d, vrm_version: %d, reg_val: 0x%lx, data_val: %ld\n", ++ page, vrm_version, val, rv); ++ return rv; ++} ++ ++static ssize_t xdpe122_avs_vout_show(struct device *dev, struct device_attribute *devattr, ++ char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ int vout_cmd, vout; ++ ++ mutex_lock(&data->update_lock); ++ vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); ++ if (vout_cmd < 0) { ++ WB_XDPE122_ERROR("%d-%04x: read page%d, vout command reg: 0x%x failed, ret: %d\n", ++ client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd); ++ mutex_unlock(&data->update_lock); ++ return vout_cmd; ++ } ++ ++ vout = xdpe122_reg2data_vid(data, attr->index, vout_cmd); ++ vout = vout * 1000; ++ WB_XDPE122_VERBOSE("%d-%04x: page%d, vout command reg_val: 0x%x, vout: %d uV\n", ++ client->adapter->nr, client->addr, attr->index, vout_cmd, vout); ++ ++ mutex_unlock(&data->update_lock); ++ return snprintf(buf, PAGE_SIZE, "%d\n", vout); ++} ++ ++static ssize_t xdpe122_avs_vout_store(struct device *dev, struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ int vout, vout_max, vout_min, vout_mv; ++ int ret, vout_cmd, vout_cmd_set; ++ ++ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { ++ WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, ++ attr->index); ++ return -EINVAL; ++ } ++ ++ ret = kstrtoint(buf, 0, &vout); ++ if (ret) { ++ WB_XDPE122_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); ++ return -EINVAL; ++ } ++ ++ vout_max = data->vout_max[attr->index]; ++ vout_min = data->vout_min[attr->index]; ++ if ((vout > vout_max) || (vout < vout_min)) { ++ WB_XDPE122_ERROR("%d-%04x: vout value: %d, out of range [%d, %d] \n", client->adapter->nr, ++ client->addr, vout, vout_min, vout_max); ++ return -EINVAL; ++ } ++ ++ /* calc VOUT_COMMAND set value Unit must be mV*/ ++ vout_mv = vout / 1000; ++ vout_cmd_set = xdpe122_data2reg_vid(data, attr->index, vout_mv); ++ if ((vout_cmd_set < 0) || (vout_cmd_set > 0xffff)) { ++ WB_XDPE122_ERROR("%d-%04x: invalid value, vout %d uV, vout_cmd_set: %d\n", ++ client->adapter->nr, client->addr, vout, vout_cmd_set); ++ return -EINVAL; ++ } ++ ++ mutex_lock(&data->update_lock); ++ ++ /* close write protect */ ++ ret = wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, XDPE122_WRITE_PROTECT_CLOSE); ++ if (ret < 0) { ++ WB_XDPE122_ERROR("%d-%04x: close page%d write protect failed, ret: %d\n", client->adapter->nr, ++ client->addr, attr->index, ret); ++ mutex_unlock(&data->update_lock); ++ return ret; ++ } ++ ++ /* set VOUT_COMMAND */ ++ ret = wb_pmbus_write_word_data(client, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set); ++ if (ret < 0) { ++ WB_XDPE122_ERROR("%d-%04x: set page%d vout cmd reg: 0x%x, value: 0x%x failed, ret: %d\n", ++ client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set, ret); ++ goto error; ++ } ++ ++ /* read back VOUT_COMMAND */ ++ vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); ++ if (vout_cmd < 0) { ++ ret = vout_cmd; ++ WB_XDPE122_ERROR("%d-%04x: read page%d vout command reg: 0x%x failed, ret: %d\n", ++ client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, ret); ++ goto error; ++ } ++ ++ /* compare vout_cmd and vout_cmd_set */ ++ if (vout_cmd != vout_cmd_set) { ++ ret = -EIO; ++ WB_XDPE122_ERROR("%d-%04x: vout cmd value check error, vout cmd read: 0x%x, vout cmd set: 0x%x\n", ++ client->adapter->nr, client->addr, vout_cmd, vout_cmd_set); ++ goto error; ++ } ++ ++ /* open write protect */ ++ wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, XDPE122_WRITE_PROTECT_OPEN); ++ mutex_unlock(&data->update_lock); ++ WB_XDPE122_VERBOSE("%d-%04x: set page%d vout cmd success, vout %d uV, vout_cmd_set: 0x%x\n", ++ client->adapter->nr, client->addr, attr->index, vout, vout_cmd_set); ++ return count; ++error: ++ wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, XDPE122_WRITE_PROTECT_OPEN); ++ mutex_unlock(&data->update_lock); ++ return ret; ++} ++ ++static ssize_t xdpe122_avs_vout_max_store(struct device *dev, ++ struct device_attribute *devattr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ int ret, vout_threshold; ++ ++ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { ++ WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, ++ attr->index); ++ return -EINVAL; ++ } ++ ++ ret = kstrtoint(buf, 0, &vout_threshold); ++ if (ret) { ++ WB_XDPE122_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); ++ return -EINVAL; ++ } ++ ++ WB_XDPE122_VERBOSE("%d-%04x: vout%d max threshold: %d", client->adapter->nr, client->addr, ++ attr->index, vout_threshold); ++ ++ data->vout_max[attr->index] = vout_threshold; ++ return count; ++} ++ ++static ssize_t xdpe122_avs_vout_max_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ ++ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { ++ WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, ++ attr->index); ++ return -EINVAL; ++ } ++ ++ return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_max[attr->index]); ++} ++ ++static ssize_t xdpe122_avs_vout_min_store(struct device *dev, ++ struct device_attribute *devattr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ int ret, vout_threshold; ++ ++ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { ++ WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, ++ attr->index); ++ return -EINVAL; ++ } ++ ++ ret = kstrtoint(buf, 0, &vout_threshold); ++ if (ret) { ++ WB_XDPE122_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); ++ return -EINVAL; ++ } ++ ++ WB_XDPE122_VERBOSE("%d-%04x: vout%d min threshold: %d", client->adapter->nr, client->addr, ++ attr->index, vout_threshold); ++ ++ data->vout_min[attr->index] = vout_threshold; ++ return count; ++} ++ ++static ssize_t xdpe122_avs_vout_min_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev->parent); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct pmbus_data *data = i2c_get_clientdata(client); ++ ++ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { ++ WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, ++ attr->index); ++ return -EINVAL; ++ } ++ ++ return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_min[attr->index]); ++} ++ ++static SENSOR_DEVICE_ATTR_RW(avs0_vout, xdpe122_avs_vout, 0); ++static SENSOR_DEVICE_ATTR_RW(avs1_vout, xdpe122_avs_vout, 1); ++static SENSOR_DEVICE_ATTR_RW(avs0_vout_max, xdpe122_avs_vout_max, 0); ++static SENSOR_DEVICE_ATTR_RW(avs0_vout_min, xdpe122_avs_vout_min, 0); ++static SENSOR_DEVICE_ATTR_RW(avs1_vout_max, xdpe122_avs_vout_max, 1); ++static SENSOR_DEVICE_ATTR_RW(avs1_vout_min, xdpe122_avs_vout_min, 1); ++ ++static struct attribute *avs_ctrl_attrs[] = { ++ &sensor_dev_attr_avs0_vout.dev_attr.attr, ++ &sensor_dev_attr_avs1_vout.dev_attr.attr, ++ &sensor_dev_attr_avs0_vout_max.dev_attr.attr, ++ &sensor_dev_attr_avs0_vout_min.dev_attr.attr, ++ &sensor_dev_attr_avs1_vout_max.dev_attr.attr, ++ &sensor_dev_attr_avs1_vout_min.dev_attr.attr, ++ NULL, ++}; ++ ++static const struct attribute_group avs_ctrl_group = { ++ .attrs = avs_ctrl_attrs, ++}; ++ ++static const struct attribute_group *xdpe122_attribute_groups[] = { ++ &avs_ctrl_group, ++ NULL, ++}; ++ ++static int xdpe122_read_word_data(struct i2c_client *client, int page, ++ int phase, int reg) ++{ ++ const struct pmbus_driver_info *info = wb_pmbus_get_driver_info(client); ++ long val; ++ s16 exponent; ++ s32 mantissa; ++ int ret; ++ ++ switch (reg) { ++ case PMBUS_VOUT_OV_FAULT_LIMIT: ++ case PMBUS_VOUT_UV_FAULT_LIMIT: ++ ret = wb_pmbus_read_word_data(client, page, phase, reg); ++ if (ret < 0) ++ return ret; ++ ++ /* Convert register value to LINEAR11 data. */ ++ exponent = ((s16)ret) >> 11; ++ mantissa = ((s16)((ret & GENMASK(10, 0)) << 5)) >> 5; ++ val = mantissa * 1000L; ++ if (exponent >= 0) ++ val <<= exponent; ++ else ++ val >>= -exponent; ++ ++ /* Convert data to VID register. */ ++ switch (info->vrm_version[page]) { ++ case vr13: ++ if (val >= 500) ++ return 1 + DIV_ROUND_CLOSEST(val - 500, 10); ++ return 0; ++ case vr12: ++ if (val >= 250) ++ return 1 + DIV_ROUND_CLOSEST(val - 250, 5); ++ return 0; ++ case imvp9: ++ if (val >= 200) ++ return 1 + DIV_ROUND_CLOSEST(val - 200, 10); ++ return 0; ++ case amd625mv: ++ if (val >= 200 && val <= 1550) ++ return DIV_ROUND_CLOSEST((1550 - val) * 100, ++ 625); ++ return 0; ++ default: ++ return -EINVAL; ++ } ++ default: ++ return -ENODATA; ++ } ++ ++ return 0; ++} ++ ++static int xdpe122_identify(struct i2c_client *client, ++ struct pmbus_driver_info *info) ++{ ++ u8 vout_params; ++ int i, ret; ++ ++ for (i = 0; i < XDPE122_PAGE_NUM; i++) { ++ /* Read the register with VOUT scaling value.*/ ++ ret = wb_pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); ++ if (ret < 0) ++ return ret; ++ ++ vout_params = ret & GENMASK(4, 0); ++ ++ switch (vout_params) { ++ case XDPE122_PROT_VR12_5_10MV: ++ info->vrm_version[i] = vr13; ++ break; ++ case XDPE122_PROT_VR12_5MV: ++ info->vrm_version[i] = vr12; ++ break; ++ case XDPE122_PROT_IMVP9_10MV: ++ info->vrm_version[i] = imvp9; ++ break; ++ case XDPE122_AMD_625MV: ++ info->vrm_version[i] = amd625mv; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static struct pmbus_driver_info xdpe122_info = { ++ .pages = XDPE122_PAGE_NUM, ++ .format[PSC_VOLTAGE_IN] = linear, ++ .format[PSC_VOLTAGE_OUT] = vid, ++ .format[PSC_TEMPERATURE] = linear, ++ .format[PSC_CURRENT_IN] = linear, ++ .format[PSC_CURRENT_OUT] = linear, ++ .format[PSC_POWER] = linear, ++ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ++ PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | ++ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | ++ PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT, ++ .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ++ PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | ++ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | ++ PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT, ++ .groups = xdpe122_attribute_groups, ++ .identify = xdpe122_identify, ++ .read_word_data = xdpe122_read_word_data, ++}; ++ ++static int xdpe122_probe(struct i2c_client *client) ++{ ++ struct pmbus_driver_info *info; ++ ++ info = devm_kmemdup(&client->dev, &xdpe122_info, sizeof(*info), ++ GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ ++ return wb_pmbus_do_probe(client, info); ++} ++ ++static const struct i2c_device_id xdpe122_id[] = { ++ {"wb_xdpe12254", 0}, ++ {"wb_xdpe12284", 0}, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(i2c, xdpe122_id); ++ ++static const struct of_device_id __maybe_unused xdpe122_of_match[] = { ++ {.compatible = "infineon,wb_xdpe12254"}, ++ {.compatible = "infineon,wb_xdpe12284"}, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, xdpe122_of_match); ++ ++static struct i2c_driver xdpe122_driver = { ++ .driver = { ++ .name = "wb_xdpe12284", ++ .of_match_table = of_match_ptr(xdpe122_of_match), ++ }, ++ .probe_new = xdpe122_probe, ++ .remove = wb_pmbus_do_remove, ++ .id_table = xdpe122_id, ++}; ++ ++module_i2c_driver(xdpe122_driver); ++ ++MODULE_AUTHOR("Vadim Pasternak "); ++MODULE_DESCRIPTION("PMBus driver for Infineon XDPE122 family"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe132g5c_pmbus.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe132g5c_pmbus.c +new file mode 100644 +index 000000000..c0c3d2bc7 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe132g5c_pmbus.c +@@ -0,0 +1,277 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "wb_pmbus.h" ++ ++typedef enum { ++ DBG_START, ++ DBG_VERBOSE, ++ DBG_KEY, ++ DBG_WARN, ++ DBG_ERROR, ++ DBG_END, ++} dbg_level_t; ++ ++static int debuglevel = 0; ++module_param(debuglevel, int, S_IRUGO); ++ ++#define DBG_DEBUG(fmt, arg...) do { \ ++ if ( debuglevel > DBG_START && debuglevel < DBG_ERROR) { \ ++ printk(KERN_INFO "[DEBUG]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ ++ } else if ( debuglevel >= DBG_ERROR ) { \ ++ printk(KERN_ERR "[DEBUG]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ ++ } else { } \ ++} while (0) ++ ++#define DBG_ERROR(fmt, arg...) do { \ ++ if ( debuglevel > DBG_START) { \ ++ printk(KERN_ERR "[ERROR]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ ++ } \ ++} while (0) ++ ++#define BUF_SIZE (256) ++#define XDPE132G5C_PAGE_NUM (2) ++#define XDPE132G5C_PROT_VR12_5MV (0x01) /* VR12.0 mode, 5-mV DAC */ ++#define XDPE132G5C_PROT_VR12_5_10MV (0x02) /* VR12.5 mode, 10-mV DAC */ ++#define XDPE132G5C_PROT_IMVP9_10MV (0x03) /* IMVP9 mode, 10-mV DAC */ ++#define XDPE132G5C_PROT_VR13_10MV (0x04) /* VR13.0 mode, 10-mV DAC */ ++#define XDPE132G5C_PROT_IMVP8_5MV (0x05) /* IMVP8 mode, 5-mV DAC */ ++#define XDPE132G5C_PROT_VR13_5MV (0x07) /* VR13.0 mode, 5-mV DAC */ ++#define RETRY_TIME (15) ++ ++static ssize_t set_xdpe132g5c_avs(struct device *dev, struct device_attribute *da, const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long val; ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); ++ struct i2c_client *client = to_i2c_client(dev); ++ struct pmbus_data *data; ++ ++ data = i2c_get_clientdata(client); ++ ret = kstrtoul(buf, 0, &val); ++ if (ret){ ++ return ret; ++ } ++ mutex_lock(&data->update_lock); ++ /* set value */ ++ ret = wb_pmbus_write_word_data(client, attr->index, PMBUS_VOUT_COMMAND, (u16)val); ++ if (ret < 0) { ++ DBG_ERROR("set pmbus_vout_command fail\n"); ++ goto finish_set; ++ } ++finish_set: ++ wb_pmbus_clear_faults(client); ++ mutex_unlock(&data->update_lock); ++ return (ret < 0) ? ret : count; ++ ++} ++ ++static ssize_t show_xdpe132g5c_avs(struct device *dev, struct device_attribute *da, char *buf) ++{ ++ int val; ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); ++ struct i2c_client *client = to_i2c_client(dev); ++ struct pmbus_data *data; ++ ++ data = i2c_get_clientdata(client); ++ mutex_lock(&data->update_lock); ++ val = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); ++ if (val < 0) { ++ DBG_ERROR("fail val = %d\n", val); ++ goto finish_show; ++ } ++finish_show: ++ wb_pmbus_clear_faults(client); ++ mutex_unlock(&data->update_lock); ++ return snprintf(buf, BUF_SIZE, "0x%04x\n", val); ++} ++ ++static SENSOR_DEVICE_ATTR(avs0_vout_command, S_IRUGO | S_IWUSR, show_xdpe132g5c_avs, set_xdpe132g5c_avs, 0); ++static SENSOR_DEVICE_ATTR(avs1_vout_command, S_IRUGO | S_IWUSR, show_xdpe132g5c_avs, set_xdpe132g5c_avs, 1); ++ ++static struct attribute *xdpe132g5c_sysfs_attrs[] = { ++ &sensor_dev_attr_avs0_vout_command.dev_attr.attr, ++ &sensor_dev_attr_avs1_vout_command.dev_attr.attr, ++ NULL, ++}; ++ ++static const struct attribute_group xdpe132g5c_sysfs_attrs_group = { ++ .attrs = xdpe132g5c_sysfs_attrs, ++}; ++ ++static int xdpe132g5c_read_word_data(struct i2c_client *client, int page, int phase, int reg) ++{ ++ int rv; ++ int retry; ++ int value; ++ ++ rv = wb_pmbus_set_page(client, page, 0xff); ++ if (rv < 0) { ++ return rv; ++ } ++ ++ retry = 3; ++ while (retry--) { ++ value = i2c_smbus_read_word_data(client, reg); ++ if ((value == 0xffff) || (value < 0)) { ++ continue; ++ } ++ } ++ return value; ++} ++ ++static int xdpe132g5c_identify(struct i2c_client *client, struct pmbus_driver_info *info) ++{ ++ u8 vout_params; ++ int ret, i, retry; ++ ++ /* Read the register with VOUT scaling value.*/ ++ for (i = 0; i < XDPE132G5C_PAGE_NUM; i++) { ++ for (retry = 0; retry < RETRY_TIME; retry++) { ++ ret = wb_pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); ++ if (ret < 0 || ret == 0xff) { ++ msleep(5); ++ continue; ++ } else { ++ break; ++ } ++ } ++ if (ret < 0) { ++ return ret; ++ } ++ ++ switch (ret >> 5) { ++ case 0: /* linear mode */ ++ if (info->format[PSC_VOLTAGE_OUT] != linear) { ++ return -ENODEV; ++ } ++ break; ++ case 1: /* VID mode */ ++ if (info->format[PSC_VOLTAGE_OUT] != vid) { ++ return -ENODEV; ++ } ++ vout_params = ret & GENMASK(4, 0); ++ switch (vout_params) { ++ case XDPE132G5C_PROT_VR13_10MV: ++ case XDPE132G5C_PROT_VR12_5_10MV: ++ info->vrm_version[i] = vr13; ++ break; ++ case XDPE132G5C_PROT_VR13_5MV: ++ case XDPE132G5C_PROT_VR12_5MV: ++ case XDPE132G5C_PROT_IMVP8_5MV: ++ info->vrm_version[i] = vr12; ++ break; ++ case XDPE132G5C_PROT_IMVP9_10MV: ++ info->vrm_version[i] = imvp9; ++ break; ++ default: ++ return -EINVAL; ++ } ++ break; ++ case 2: /* direct mode */ ++ if (info->format[PSC_VOLTAGE_OUT] != direct) { ++ return -ENODEV; ++ } ++ break; ++ default: ++ return -ENODEV; ++ } ++ } ++ ++ return 0; ++} ++ ++static struct pmbus_driver_info xdpe132g5c_info = { ++ .pages = XDPE132G5C_PAGE_NUM, ++ .format[PSC_VOLTAGE_IN] = linear, ++ .format[PSC_VOLTAGE_OUT] = linear, ++ .format[PSC_TEMPERATURE] = linear, ++ .format[PSC_CURRENT_IN] = linear, ++ .format[PSC_CURRENT_OUT] = linear, ++ .format[PSC_POWER] = linear, ++ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN ++ | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP ++ | PMBUS_HAVE_STATUS_TEMP ++ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT ++ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, ++ .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN ++ | PMBUS_HAVE_STATUS_INPUT ++ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT ++ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, ++ .identify = xdpe132g5c_identify, ++ .read_word_data = xdpe132g5c_read_word_data, ++}; ++ ++static int xdpe132g5c_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ int status; ++ struct pmbus_driver_info *info; ++ ++ info = devm_kmemdup(&client->dev, &xdpe132g5c_info, sizeof(*info), GFP_KERNEL); ++ if (!info) { ++ return -ENOMEM; ++ } ++ ++ status = wb_pmbus_do_probe(client, &xdpe132g5c_info); ++ if (status != 0) { ++ DBG_ERROR("pmbus probe error %d\n", status); ++ return status; ++ } ++ ++ status = sysfs_create_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); ++ if (status != 0) { ++ DBG_ERROR("sysfs_create_group error %d\n", status); ++ return status; ++ } ++ ++ return status; ++} ++ ++static int xdpe132g5c_remove(struct i2c_client *client) ++{ ++ int ret; ++ ++ sysfs_remove_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); ++ ret = wb_pmbus_do_remove(client); ++ if (ret != 0){ ++ DBG_ERROR("fail remove xdpe132g5c %d\n", ret); ++ } ++ return ret; ++} ++ ++static const struct i2c_device_id xdpe132g5c_id[] = { ++ {"wb_xdpe132g5c_pmbus", 0}, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(i2c, xdpe132g5c_id); ++ ++static const struct of_device_id __maybe_unused xdpe132g5c_of_match[] = { ++ {.compatible = "infineon,wb_xdpe132g5c_pmbus"}, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, xdpe132g5c_of_match); ++ ++static struct i2c_driver xdpe132g5c_driver = { ++ .driver = { ++ .name = "wb_xdpe132g5c_pmbus", ++ .of_match_table = of_match_ptr(xdpe132g5c_of_match), ++ }, ++ .probe = xdpe132g5c_probe, ++ .remove = xdpe132g5c_remove, ++ .id_table = xdpe132g5c_id, ++}; ++ ++module_i2c_driver(xdpe132g5c_driver); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("PMBus driver for Infineon XDPE132 family"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/Makefile +new file mode 100644 +index 000000000..4d5f8d535 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/Makefile +@@ -0,0 +1,23 @@ ++PWD = $(shell pwd) ++ ++EXTRA_CFLAGS:= -I$(M)/include ++EXTRA_CFLAGS+= -Wall ++ ++ifndef CONFIG_MDIO_BITBANG ++obj-m += mdio_bitbang.o ++endif ++ ++ifndef CONFIG_MDIO_GPIO ++obj-m += mdio_gpio.o ++endif ++ ++obj-m += wb_mdio_gpio_device.o ++ ++all: ++ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules ++ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi ++ cp -p $(PWD)/*.ko $(module_out_put_dir) ++clean: ++ rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/*.mod ++ rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order ++ rm -rf $(PWD)/.tmp_versions +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_bitbang.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_bitbang.c +new file mode 100644 +index 000000000..5136275c8 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_bitbang.c +@@ -0,0 +1,232 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Bitbanged MDIO support. ++ * ++ * Author: Scott Wood ++ * Copyright (c) 2007 Freescale Semiconductor ++ * ++ * Based on CPM2 MDIO code which is: ++ * ++ * Copyright (c) 2003 Intracom S.A. ++ * by Pantelis Antoniou ++ * ++ * 2005 (c) MontaVista Software, Inc. ++ * Vitaly Bordug ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#define MDIO_READ 2 ++#define MDIO_WRITE 1 ++ ++#define MDIO_C45 (1<<15) ++#define MDIO_C45_ADDR (MDIO_C45 | 0) ++#define MDIO_C45_READ (MDIO_C45 | 3) ++#define MDIO_C45_WRITE (MDIO_C45 | 1) ++ ++#define MDIO_SETUP_TIME 10 ++#define MDIO_HOLD_TIME 10 ++ ++/* Minimum MDC period is 400 ns, plus some margin for error. MDIO_DELAY ++ * is done twice per period. ++ */ ++#define MDIO_DELAY 250 ++ ++/* The PHY may take up to 300 ns to produce data, plus some margin ++ * for error. ++ */ ++#define MDIO_READ_DELAY 350 ++ ++/* MDIO must already be configured as output. */ ++static void mdiobb_send_bit(struct mdiobb_ctrl *ctrl, int val) ++{ ++ const struct mdiobb_ops *ops = ctrl->ops; ++ ++ ops->set_mdio_data(ctrl, val); ++ ndelay(MDIO_DELAY); ++ ops->set_mdc(ctrl, 1); ++ ndelay(MDIO_DELAY); ++ ops->set_mdc(ctrl, 0); ++} ++ ++/* MDIO must already be configured as input. */ ++static int mdiobb_get_bit(struct mdiobb_ctrl *ctrl) ++{ ++ const struct mdiobb_ops *ops = ctrl->ops; ++ ++ ndelay(MDIO_DELAY); ++ ops->set_mdc(ctrl, 1); ++ ndelay(MDIO_READ_DELAY); ++ ops->set_mdc(ctrl, 0); ++ ++ return ops->get_mdio_data(ctrl); ++} ++ ++/* MDIO must already be configured as output. */ ++static void mdiobb_send_num(struct mdiobb_ctrl *ctrl, u16 val, int bits) ++{ ++ int i; ++ ++ for (i = bits - 1; i >= 0; i--) ++ mdiobb_send_bit(ctrl, (val >> i) & 1); ++} ++ ++/* MDIO must already be configured as input. */ ++static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits) ++{ ++ int i; ++ u16 ret = 0; ++ ++ for (i = bits - 1; i >= 0; i--) { ++ ret <<= 1; ++ ret |= mdiobb_get_bit(ctrl); ++ } ++ ++ return ret; ++} ++ ++/* Utility to send the preamble, address, and ++ * register (common to read and write). ++ */ ++static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int op, u8 phy, u8 reg) ++{ ++ const struct mdiobb_ops *ops = ctrl->ops; ++ int i; ++ ++ ops->set_mdio_dir(ctrl, 1); ++ ++ /* ++ * Send a 32 bit preamble ('1's) with an extra '1' bit for good ++ * measure. The IEEE spec says this is a PHY optional ++ * requirement. The AMD 79C874 requires one after power up and ++ * one after a MII communications error. This means that we are ++ * doing more preambles than we need, but it is safer and will be ++ * much more robust. ++ */ ++ ++ for (i = 0; i < 32; i++) ++ mdiobb_send_bit(ctrl, 1); ++ ++ /* send the start bit (01) and the read opcode (10) or write (01). ++ Clause 45 operation uses 00 for the start and 11, 10 for ++ read/write */ ++ mdiobb_send_bit(ctrl, 0); ++ if (op & MDIO_C45) ++ mdiobb_send_bit(ctrl, 0); ++ else ++ mdiobb_send_bit(ctrl, 1); ++ mdiobb_send_bit(ctrl, (op >> 1) & 1); ++ mdiobb_send_bit(ctrl, (op >> 0) & 1); ++ ++ mdiobb_send_num(ctrl, phy, 5); ++ mdiobb_send_num(ctrl, reg, 5); ++} ++ ++/* In clause 45 mode all commands are prefixed by MDIO_ADDR to specify the ++ lower 16 bits of the 21 bit address. This transfer is done identically to a ++ MDIO_WRITE except for a different code. To enable clause 45 mode or ++ MII_ADDR_C45 into the address. Theoretically clause 45 and normal devices ++ can exist on the same bus. Normal devices should ignore the MDIO_ADDR ++ phase. */ ++static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr) ++{ ++ unsigned int dev_addr = (addr >> 16) & 0x1F; ++ unsigned int reg = addr & 0xFFFF; ++ mdiobb_cmd(ctrl, MDIO_C45_ADDR, phy, dev_addr); ++ ++ /* send the turnaround (10) */ ++ mdiobb_send_bit(ctrl, 1); ++ mdiobb_send_bit(ctrl, 0); ++ ++ mdiobb_send_num(ctrl, reg, 16); ++ ++ ctrl->ops->set_mdio_dir(ctrl, 0); ++ mdiobb_get_bit(ctrl); ++ ++ return dev_addr; ++} ++ ++static int mdiobb_read(struct mii_bus *bus, int phy, int reg) ++{ ++ struct mdiobb_ctrl *ctrl = bus->priv; ++ int ret, i; ++ ++ if (reg & MII_ADDR_C45) { ++ reg = mdiobb_cmd_addr(ctrl, phy, reg); ++ mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg); ++ } else ++ mdiobb_cmd(ctrl, MDIO_READ, phy, reg); ++ ++ ctrl->ops->set_mdio_dir(ctrl, 0); ++ ++ /* check the turnaround bit: the PHY should be driving it to zero, if this ++ * PHY is listed in phy_ignore_ta_mask as having broken TA, skip that ++ */ ++ if (mdiobb_get_bit(ctrl) != 0 && ++ !(bus->phy_ignore_ta_mask & (1 << phy))) { ++ /* PHY didn't drive TA low -- flush any bits it ++ * may be trying to send. ++ */ ++ for (i = 0; i < 32; i++) ++ mdiobb_get_bit(ctrl); ++ ++ return 0xffff; ++ } ++ ++ ret = mdiobb_get_num(ctrl, 16); ++ mdiobb_get_bit(ctrl); ++ return ret; ++} ++ ++static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val) ++{ ++ struct mdiobb_ctrl *ctrl = bus->priv; ++ ++ if (reg & MII_ADDR_C45) { ++ reg = mdiobb_cmd_addr(ctrl, phy, reg); ++ mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg); ++ } else ++ mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg); ++ ++ /* send the turnaround (10) */ ++ mdiobb_send_bit(ctrl, 1); ++ mdiobb_send_bit(ctrl, 0); ++ ++ mdiobb_send_num(ctrl, val, 16); ++ ++ ctrl->ops->set_mdio_dir(ctrl, 0); ++ mdiobb_get_bit(ctrl); ++ return 0; ++} ++ ++struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) ++{ ++ struct mii_bus *bus; ++ ++ bus = mdiobus_alloc(); ++ if (!bus) ++ return NULL; ++ ++ __module_get(ctrl->ops->owner); ++ ++ bus->read = mdiobb_read; ++ bus->write = mdiobb_write; ++ bus->priv = ctrl; ++ ++ return bus; ++} ++EXPORT_SYMBOL(alloc_mdio_bitbang); ++ ++void free_mdio_bitbang(struct mii_bus *bus) ++{ ++ struct mdiobb_ctrl *ctrl = bus->priv; ++ ++ module_put(ctrl->ops->owner); ++ mdiobus_free(bus); ++} ++EXPORT_SYMBOL(free_mdio_bitbang); ++ ++MODULE_LICENSE("GPL v2"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_gpio.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_gpio.c +new file mode 100644 +index 000000000..1b00235d7 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_gpio.c +@@ -0,0 +1,217 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * GPIO based MDIO bitbang driver. ++ * Supports OpenFirmware. ++ * ++ * Copyright (c) 2008 CSE Semaphore Belgium. ++ * by Laurent Pinchart ++ * ++ * Copyright (C) 2008, Paulius Zaleckas ++ * ++ * Based on earlier work by ++ * ++ * Copyright (c) 2003 Intracom S.A. ++ * by Pantelis Antoniou ++ * ++ * 2005 (c) MontaVista Software, Inc. ++ * Vitaly Bordug ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct mdio_gpio_info { ++ struct mdiobb_ctrl ctrl; ++ struct gpio_desc *mdc, *mdio, *mdo; ++}; ++ ++static int mdio_gpio_get_data(struct device *dev, ++ struct mdio_gpio_info *bitbang) ++{ ++ bitbang->mdc = devm_gpiod_get_index(dev, NULL, MDIO_GPIO_MDC, ++ GPIOD_OUT_LOW); ++ if (IS_ERR(bitbang->mdc)) ++ return PTR_ERR(bitbang->mdc); ++ ++ bitbang->mdio = devm_gpiod_get_index(dev, NULL, MDIO_GPIO_MDIO, ++ GPIOD_IN); ++ if (IS_ERR(bitbang->mdio)) ++ return PTR_ERR(bitbang->mdio); ++ ++ bitbang->mdo = devm_gpiod_get_index_optional(dev, NULL, MDIO_GPIO_MDO, ++ GPIOD_OUT_LOW); ++ return PTR_ERR_OR_ZERO(bitbang->mdo); ++} ++ ++static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) ++{ ++ struct mdio_gpio_info *bitbang = ++ container_of(ctrl, struct mdio_gpio_info, ctrl); ++ ++ if (bitbang->mdo) { ++ /* Separate output pin. Always set its value to high ++ * when changing direction. If direction is input, ++ * assume the pin serves as pull-up. If direction is ++ * output, the default value is high. ++ */ ++ gpiod_set_value_cansleep(bitbang->mdo, 1); ++ return; ++ } ++ ++ if (dir) ++ gpiod_direction_output(bitbang->mdio, 1); ++ else ++ gpiod_direction_input(bitbang->mdio); ++} ++ ++static int mdio_get(struct mdiobb_ctrl *ctrl) ++{ ++ struct mdio_gpio_info *bitbang = ++ container_of(ctrl, struct mdio_gpio_info, ctrl); ++ ++ return gpiod_get_value_cansleep(bitbang->mdio); ++} ++ ++static void mdio_set(struct mdiobb_ctrl *ctrl, int what) ++{ ++ struct mdio_gpio_info *bitbang = ++ container_of(ctrl, struct mdio_gpio_info, ctrl); ++ ++ if (bitbang->mdo) ++ gpiod_set_value_cansleep(bitbang->mdo, what); ++ else ++ gpiod_set_value_cansleep(bitbang->mdio, what); ++} ++ ++static void mdc_set(struct mdiobb_ctrl *ctrl, int what) ++{ ++ struct mdio_gpio_info *bitbang = ++ container_of(ctrl, struct mdio_gpio_info, ctrl); ++ ++ gpiod_set_value_cansleep(bitbang->mdc, what); ++} ++ ++static const struct mdiobb_ops mdio_gpio_ops = { ++ .owner = THIS_MODULE, ++ .set_mdc = mdc_set, ++ .set_mdio_dir = mdio_dir, ++ .set_mdio_data = mdio_set, ++ .get_mdio_data = mdio_get, ++}; ++ ++static struct mii_bus *mdio_gpio_bus_init(struct device *dev, ++ struct mdio_gpio_info *bitbang, ++ int bus_id) ++{ ++ struct mdio_gpio_platform_data *pdata = dev_get_platdata(dev); ++ struct mii_bus *new_bus; ++ ++ bitbang->ctrl.ops = &mdio_gpio_ops; ++ ++ new_bus = alloc_mdio_bitbang(&bitbang->ctrl); ++ if (!new_bus) ++ return NULL; ++ ++ new_bus->name = "GPIO Bitbanged MDIO"; ++ new_bus->parent = dev; ++ ++ if (bus_id != -1) ++ snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id); ++ else ++ strncpy(new_bus->id, "gpio", MII_BUS_ID_SIZE); ++ ++ if (pdata) { ++ new_bus->phy_mask = pdata->phy_mask; ++ new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask; ++ } ++ ++ dev_set_drvdata(dev, new_bus); ++ ++ return new_bus; ++} ++ ++static void mdio_gpio_bus_deinit(struct device *dev) ++{ ++ struct mii_bus *bus = dev_get_drvdata(dev); ++ ++ free_mdio_bitbang(bus); ++} ++ ++static void mdio_gpio_bus_destroy(struct device *dev) ++{ ++ struct mii_bus *bus = dev_get_drvdata(dev); ++ ++ mdiobus_unregister(bus); ++ mdio_gpio_bus_deinit(dev); ++} ++ ++static int mdio_gpio_probe(struct platform_device *pdev) ++{ ++ struct mdio_gpio_info *bitbang; ++ struct mii_bus *new_bus; ++ int ret, bus_id; ++ ++ bitbang = devm_kzalloc(&pdev->dev, sizeof(*bitbang), GFP_KERNEL); ++ if (!bitbang) ++ return -ENOMEM; ++ ++ ret = mdio_gpio_get_data(&pdev->dev, bitbang); ++ if (ret) ++ return ret; ++ ++ if (pdev->dev.of_node) { ++ bus_id = of_alias_get_id(pdev->dev.of_node, "mdio-gpio"); ++ if (bus_id < 0) { ++ dev_warn(&pdev->dev, "failed to get alias id\n"); ++ bus_id = 0; ++ } ++ } else { ++ bus_id = pdev->id; ++ } ++ ++ new_bus = mdio_gpio_bus_init(&pdev->dev, bitbang, bus_id); ++ if (!new_bus) ++ return -ENODEV; ++ ++ ret = of_mdiobus_register(new_bus, pdev->dev.of_node); ++ if (ret) ++ mdio_gpio_bus_deinit(&pdev->dev); ++ ++ return ret; ++} ++ ++static int mdio_gpio_remove(struct platform_device *pdev) ++{ ++ mdio_gpio_bus_destroy(&pdev->dev); ++ ++ return 0; ++} ++ ++static const struct of_device_id mdio_gpio_of_match[] = { ++ { .compatible = "virtual,mdio-gpio", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, mdio_gpio_of_match); ++ ++static struct platform_driver mdio_gpio_driver = { ++ .probe = mdio_gpio_probe, ++ .remove = mdio_gpio_remove, ++ .driver = { ++ .name = "mdio-gpio", ++ .of_match_table = mdio_gpio_of_match, ++ }, ++}; ++ ++module_platform_driver(mdio_gpio_driver); ++ ++MODULE_ALIAS("platform:mdio-gpio"); ++MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas"); ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/wb_mdio_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/wb_mdio_gpio_device.c +new file mode 100644 +index 000000000..e3198b378 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/wb_mdio_gpio_device.c +@@ -0,0 +1,110 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int gpio_mdc = 44; ++module_param(gpio_mdc, int, S_IRUGO | S_IWUSR); ++ ++static int gpio_mdio = 45; ++module_param(gpio_mdio, int, S_IRUGO | S_IWUSR); ++ ++static char *gpio_chip_name = NULL; ++module_param(gpio_chip_name, charp, 0644); ++MODULE_PARM_DESC(str_var, "A string variable for GPIO controller"); ++ ++static int g_wb_mdio_gpio_device_debug = 0; ++static int g_wb_mdio_gpio_device_error = 0; ++ ++module_param(g_wb_mdio_gpio_device_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_mdio_gpio_device_error, int, S_IRUGO | S_IWUSR); ++ ++#define WB_MIDO_GPIO_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ ++ if (g_wb_mdio_gpio_device_debug) { \ ++ printk(KERN_INFO "[WB_MDIO_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_MIDO_GPIO_DEVICE_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_wb_mdio_gpio_device_error) { \ ++ printk(KERN_ERR "[WB_MDIO_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++struct mdio_gpio_platform_data mdio_gpio_device_data = { ++ .phy_mask = 0, ++ .phy_ignore_ta_mask = 0, ++}; ++ ++static void wb_mdio_gpio_device_release(struct device *dev) ++{ ++ return; ++} ++ ++static struct platform_device mdio_gpio_device = { ++ .name = "mdio-gpio", ++ .num_resources = 0, ++ .id = -1, ++ .dev = { ++ .platform_data = &mdio_gpio_device_data, ++ .release = wb_mdio_gpio_device_release, ++ }, ++}; ++ ++static struct gpiod_lookup_table wb_mdio_gpio_table = { ++ .dev_id = "mdio-gpio", ++ .table = { ++ GPIO_LOOKUP_IDX("wb_gpio_d1500", 44, NULL, MDIO_GPIO_MDC, ++ GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP_IDX("wb_gpio_d1500", 45, NULL, MDIO_GPIO_MDIO, ++ GPIO_ACTIVE_HIGH), ++ { }, ++ }, ++}; ++ ++static int __init wb_mdio_gpio_device_init(void) ++{ ++ int err; ++ ++ WB_MIDO_GPIO_DEVICE_DEBUG_VERBOSE("wb_mdio_gpio_device_init enter!\n"); ++ wb_mdio_gpio_table.table[0].chip_hwnum = gpio_mdc; ++ wb_mdio_gpio_table.table[1].chip_hwnum = gpio_mdio; ++ ++ if (gpio_chip_name) { ++ wb_mdio_gpio_table.table[0].key = gpio_chip_name; ++ wb_mdio_gpio_table.table[1].key = gpio_chip_name; ++ } ++ ++ gpiod_add_lookup_table(&wb_mdio_gpio_table); ++ ++ err = platform_device_register(&mdio_gpio_device); ++ if (err < 0) { ++ printk(KERN_ERR "register mdio gpio device fail(%d). \n", err); ++ gpiod_remove_lookup_table(&wb_mdio_gpio_table); ++ return -1; ++ } ++ return 0; ++ ++} ++ ++static void __exit wb_mdio_gpio_device_exit(void) ++{ ++ WB_MIDO_GPIO_DEVICE_DEBUG_VERBOSE("wb_mdio_gpio_device_exit enter!\n"); ++ platform_device_unregister(&mdio_gpio_device); ++ gpiod_remove_lookup_table(&wb_mdio_gpio_table); ++} ++ ++module_init(wb_mdio_gpio_device_init); ++module_exit(wb_mdio_gpio_device_exit); ++MODULE_DESCRIPTION("WB MDIO GPIO Devices"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/Makefile +new file mode 100644 +index 000000000..295934ca4 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/Makefile +@@ -0,0 +1,17 @@ ++PWD = $(shell pwd) ++ ++EXTRA_CFLAGS:= -I$(M)/include ++EXTRA_CFLAGS+= -Wall ++ ++obj-m := wb_pinctrl_intel.o ++obj-m += wb_gpio_c3000.o ++obj-m += wb_gpio_c3000_device.o ++ ++all: ++ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules ++ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi ++ cp -p $(PWD)/*.ko $(module_out_put_dir) ++clean: ++ rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/*.mod ++ rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order ++ rm -rf $(PWD)/.tmp_versions +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/core.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/core.h +new file mode 100644 +index 000000000..840103c40 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/core.h +@@ -0,0 +1,249 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Core private header for the pin control subsystem ++ * ++ * Copyright (C) 2011 ST-Ericsson SA ++ * Written on behalf of Linaro for ST-Ericsson ++ * ++ * Author: Linus Walleij ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++struct pinctrl_gpio_range; ++ ++/** ++ * struct pinctrl_dev - pin control class device ++ * @node: node to include this pin controller in the global pin controller list ++ * @desc: the pin controller descriptor supplied when initializing this pin ++ * controller ++ * @pin_desc_tree: each pin descriptor for this pin controller is stored in ++ * this radix tree ++ * @pin_group_tree: optionally each pin group can be stored in this radix tree ++ * @num_groups: optionally number of groups can be kept here ++ * @pin_function_tree: optionally each function can be stored in this radix tree ++ * @num_functions: optionally number of functions can be kept here ++ * @gpio_ranges: a list of GPIO ranges that is handled by this pin controller, ++ * ranges are added to this list at runtime ++ * @dev: the device entry for this pin controller ++ * @owner: module providing the pin controller, used for refcounting ++ * @driver_data: driver data for drivers registering to the pin controller ++ * subsystem ++ * @p: result of pinctrl_get() for this device ++ * @hog_default: default state for pins hogged by this device ++ * @hog_sleep: sleep state for pins hogged by this device ++ * @mutex: mutex taken on each pin controller specific action ++ * @device_root: debugfs root for this device ++ */ ++struct pinctrl_dev { ++ struct list_head node; ++ struct pinctrl_desc *desc; ++ struct radix_tree_root pin_desc_tree; ++#ifdef CONFIG_GENERIC_PINCTRL_GROUPS ++ struct radix_tree_root pin_group_tree; ++ unsigned int num_groups; ++#endif ++#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS ++ struct radix_tree_root pin_function_tree; ++ unsigned int num_functions; ++#endif ++ struct list_head gpio_ranges; ++ struct device *dev; ++ struct module *owner; ++ void *driver_data; ++ struct pinctrl *p; ++ struct pinctrl_state *hog_default; ++ struct pinctrl_state *hog_sleep; ++ struct mutex mutex; ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *device_root; ++#endif ++}; ++ ++/** ++ * struct pinctrl - per-device pin control state holder ++ * @node: global list node ++ * @dev: the device using this pin control handle ++ * @states: a list of states for this device ++ * @state: the current state ++ * @dt_maps: the mapping table chunks dynamically parsed from device tree for ++ * this device, if any ++ * @users: reference count ++ */ ++struct pinctrl { ++ struct list_head node; ++ struct device *dev; ++ struct list_head states; ++ struct pinctrl_state *state; ++ struct list_head dt_maps; ++ struct kref users; ++}; ++ ++/** ++ * struct pinctrl_state - a pinctrl state for a device ++ * @node: list node for struct pinctrl's @states field ++ * @name: the name of this state ++ * @settings: a list of settings for this state ++ */ ++struct pinctrl_state { ++ struct list_head node; ++ const char *name; ++ struct list_head settings; ++}; ++ ++/** ++ * struct pinctrl_setting_mux - setting data for MAP_TYPE_MUX_GROUP ++ * @group: the group selector to program ++ * @func: the function selector to program ++ */ ++struct pinctrl_setting_mux { ++ unsigned group; ++ unsigned func; ++}; ++ ++/** ++ * struct pinctrl_setting_configs - setting data for MAP_TYPE_CONFIGS_* ++ * @group_or_pin: the group selector or pin ID to program ++ * @configs: a pointer to an array of config parameters/values to program into ++ * hardware. Each individual pin controller defines the format and meaning ++ * of config parameters. ++ * @num_configs: the number of entries in array @configs ++ */ ++struct pinctrl_setting_configs { ++ unsigned group_or_pin; ++ unsigned long *configs; ++ unsigned num_configs; ++}; ++ ++/** ++ * struct pinctrl_setting - an individual mux or config setting ++ * @node: list node for struct pinctrl_settings's @settings field ++ * @type: the type of setting ++ * @pctldev: pin control device handling to be programmed. Not used for ++ * PIN_MAP_TYPE_DUMMY_STATE. ++ * @dev_name: the name of the device using this state ++ * @data: Data specific to the setting type ++ */ ++struct pinctrl_setting { ++ struct list_head node; ++ enum pinctrl_map_type type; ++ struct pinctrl_dev *pctldev; ++ const char *dev_name; ++ union { ++ struct pinctrl_setting_mux mux; ++ struct pinctrl_setting_configs configs; ++ } data; ++}; ++ ++/** ++ * struct pin_desc - pin descriptor for each physical pin in the arch ++ * @pctldev: corresponding pin control device ++ * @name: a name for the pin, e.g. the name of the pin/pad/finger on a ++ * datasheet or such ++ * @dynamic_name: if the name of this pin was dynamically allocated ++ * @drv_data: driver-defined per-pin data. pinctrl core does not touch this ++ * @mux_usecount: If zero, the pin is not claimed, and @owner should be NULL. ++ * If non-zero, this pin is claimed by @owner. This field is an integer ++ * rather than a boolean, since pinctrl_get() might process multiple ++ * mapping table entries that refer to, and hence claim, the same group ++ * or pin, and each of these will increment the @usecount. ++ * @mux_owner: The name of device that called pinctrl_get(). ++ * @mux_setting: The most recent selected mux setting for this pin, if any. ++ * @gpio_owner: If pinctrl_gpio_request() was called for this pin, this is ++ * the name of the GPIO that "owns" this pin. ++ */ ++struct pin_desc { ++ struct pinctrl_dev *pctldev; ++ const char *name; ++ bool dynamic_name; ++ void *drv_data; ++ /* These fields only added when supporting pinmux drivers */ ++#ifdef CONFIG_PINMUX ++ unsigned mux_usecount; ++ const char *mux_owner; ++ const struct pinctrl_setting_mux *mux_setting; ++ const char *gpio_owner; ++#endif ++}; ++ ++/** ++ * struct pinctrl_maps - a list item containing part of the mapping table ++ * @node: mapping table list node ++ * @maps: array of mapping table entries ++ * @num_maps: the number of entries in @maps ++ */ ++struct pinctrl_maps { ++ struct list_head node; ++ const struct pinctrl_map *maps; ++ unsigned num_maps; ++}; ++ ++#ifdef CONFIG_GENERIC_PINCTRL_GROUPS ++ ++/** ++ * struct group_desc - generic pin group descriptor ++ * @name: name of the pin group ++ * @pins: array of pins that belong to the group ++ * @num_pins: number of pins in the group ++ * @data: pin controller driver specific data ++ */ ++struct group_desc { ++ const char *name; ++ int *pins; ++ int num_pins; ++ void *data; ++}; ++ ++int pinctrl_generic_get_group_count(struct pinctrl_dev *pctldev); ++ ++const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev, ++ unsigned int group_selector); ++ ++int pinctrl_generic_get_group_pins(struct pinctrl_dev *pctldev, ++ unsigned int group_selector, ++ const unsigned int **pins, ++ unsigned int *npins); ++ ++struct group_desc *pinctrl_generic_get_group(struct pinctrl_dev *pctldev, ++ unsigned int group_selector); ++ ++int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name, ++ int *gpins, int ngpins, void *data); ++ ++int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev, ++ unsigned int group_selector); ++ ++#endif /* CONFIG_GENERIC_PINCTRL_GROUPS */ ++ ++struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name); ++struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np); ++int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name); ++const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin); ++int pinctrl_get_group_selector(struct pinctrl_dev *pctldev, ++ const char *pin_group); ++ ++static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev, ++ unsigned int pin) ++{ ++ return radix_tree_lookup(&pctldev->pin_desc_tree, pin); ++} ++ ++extern struct pinctrl_gpio_range * ++pinctrl_find_gpio_range_from_pin_nolock(struct pinctrl_dev *pctldev, ++ unsigned int pin); ++ ++extern int pinctrl_force_sleep(struct pinctrl_dev *pctldev); ++extern int pinctrl_force_default(struct pinctrl_dev *pctldev); ++ ++extern struct mutex pinctrl_maps_mutex; ++extern struct list_head pinctrl_maps; ++ ++#define for_each_maps(_maps_node_, _i_, _map_) \ ++ list_for_each_entry(_maps_node_, &pinctrl_maps, node) \ ++ for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \ ++ _i_ < _maps_node_->num_maps; \ ++ _i_++, _map_ = &_maps_node_->maps[_i_]) +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000.c +new file mode 100644 +index 000000000..753c8a061 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000.c +@@ -0,0 +1,452 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Intel Denverton SoC pinctrl/GPIO driver ++ * ++ * Copyright (C) 2017, Intel Corporation ++ * Author: Mika Westerberg ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wb_pinctrl_intel.h" ++ ++static int g_c3000_gpio_debug = 0; ++static int g_c3000_gpio_error = 0; ++module_param(g_c3000_gpio_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_c3000_gpio_error, int, S_IRUGO | S_IWUSR); ++ ++#define C3000_GPIO_VERBOSE(fmt, args...) do { \ ++ if (g_c3000_gpio_debug) { \ ++ printk(KERN_INFO "[GPIO_PCIE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define C3000_GPIO_ERROR(fmt, args...) do { \ ++ if (g_c3000_gpio_error) { \ ++ printk(KERN_ERR "[GPIO_PCIE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define DNV_PAD_OWN 0x020 ++#define DNV_PADCFGLOCK 0x090 ++#define DNV_HOSTSW_OWN 0x0C0 ++#define DNV_GPI_IS 0x100 ++#define DNV_GPI_IE 0x120 ++ ++#define DNV_GPP(n, s, e) \ ++ { \ ++ .reg_num = (n), \ ++ .base = (s), \ ++ .size = ((e) - (s) + 1), \ ++ } ++ ++#define DNV_COMMUNITY(b, s, e, g, d) \ ++ { \ ++ .barno = (b), \ ++ .padown_offset = DNV_PAD_OWN, \ ++ .padcfglock_offset = DNV_PADCFGLOCK, \ ++ .hostown_offset = DNV_HOSTSW_OWN, \ ++ .is_offset = DNV_GPI_IS, \ ++ .ie_offset = DNV_GPI_IE, \ ++ .pin_base = (s), \ ++ .npins = ((e) - (s) + 1), \ ++ .gpps = (g), \ ++ .ngpps = ARRAY_SIZE(g), \ ++ .dw_base = (d), \ ++ } ++ ++/* Denverton */ ++static const struct pinctrl_pin_desc dnv_pins[] = { ++ /* North ALL */ ++ PINCTRL_PIN(0, "GBE0_SDP0"), ++ PINCTRL_PIN(1, "GBE1_SDP0"), ++ PINCTRL_PIN(2, "GBE0_SDP1"), ++ PINCTRL_PIN(3, "GBE1_SDP1"), ++ PINCTRL_PIN(4, "GBE0_SDP2"), ++ PINCTRL_PIN(5, "GBE1_SDP2"), ++ PINCTRL_PIN(6, "GBE0_SDP3"), ++ PINCTRL_PIN(7, "GBE1_SDP3"), ++ PINCTRL_PIN(8, "GBE2_LED0"), ++ PINCTRL_PIN(9, "GBE2_LED1"), ++ PINCTRL_PIN(10, "GBE0_I2C_CLK"), ++ PINCTRL_PIN(11, "GBE0_I2C_DATA"), ++ PINCTRL_PIN(12, "GBE1_I2C_CLK"), ++ PINCTRL_PIN(13, "GBE1_I2C_DATA"), ++ PINCTRL_PIN(14, "NCSI_RXD0"), ++ PINCTRL_PIN(15, "NCSI_CLK_IN"), ++ PINCTRL_PIN(16, "NCSI_RXD1"), ++ PINCTRL_PIN(17, "NCSI_CRS_DV"), ++ PINCTRL_PIN(18, "NCSI_ARB_IN"), ++ PINCTRL_PIN(19, "NCSI_TX_EN"), ++ PINCTRL_PIN(20, "NCSI_TXD0"), ++ PINCTRL_PIN(21, "NCSI_TXD1"), ++ PINCTRL_PIN(22, "NCSI_ARB_OUT"), ++ PINCTRL_PIN(23, "GBE0_LED0"), ++ PINCTRL_PIN(24, "GBE0_LED1"), ++ PINCTRL_PIN(25, "GBE1_LED0"), ++ PINCTRL_PIN(26, "GBE1_LED1"), ++ PINCTRL_PIN(27, "GPIO0"), ++ PINCTRL_PIN(28, "PCIE_CLKREQ0_N"), ++ PINCTRL_PIN(29, "PCIE_CLKREQ1_N"), ++ PINCTRL_PIN(30, "PCIE_CLKREQ2_N"), ++ PINCTRL_PIN(31, "PCIE_CLKREQ3_N"), ++ PINCTRL_PIN(32, "PCIE_CLKREQ4_N"), ++ PINCTRL_PIN(33, "GPIO1"), ++ PINCTRL_PIN(34, "GPIO2"), ++ PINCTRL_PIN(35, "SVID_ALERT_N"), ++ PINCTRL_PIN(36, "SVID_DATA"), ++ PINCTRL_PIN(37, "SVID_CLK"), ++ PINCTRL_PIN(38, "THERMTRIP_N"), ++ PINCTRL_PIN(39, "PROCHOT_N"), ++ PINCTRL_PIN(40, "MEMHOT_N"), ++ /* South DFX */ ++ PINCTRL_PIN(41, "DFX_PORT_CLK0"), ++ PINCTRL_PIN(42, "DFX_PORT_CLK1"), ++ PINCTRL_PIN(43, "DFX_PORT0"), ++ PINCTRL_PIN(44, "DFX_PORT1"), ++ PINCTRL_PIN(45, "DFX_PORT2"), ++ PINCTRL_PIN(46, "DFX_PORT3"), ++ PINCTRL_PIN(47, "DFX_PORT4"), ++ PINCTRL_PIN(48, "DFX_PORT5"), ++ PINCTRL_PIN(49, "DFX_PORT6"), ++ PINCTRL_PIN(50, "DFX_PORT7"), ++ PINCTRL_PIN(51, "DFX_PORT8"), ++ PINCTRL_PIN(52, "DFX_PORT9"), ++ PINCTRL_PIN(53, "DFX_PORT10"), ++ PINCTRL_PIN(54, "DFX_PORT11"), ++ PINCTRL_PIN(55, "DFX_PORT12"), ++ PINCTRL_PIN(56, "DFX_PORT13"), ++ PINCTRL_PIN(57, "DFX_PORT14"), ++ PINCTRL_PIN(58, "DFX_PORT15"), ++ /* South GPP0 */ ++ PINCTRL_PIN(59, "GPIO12"), ++ PINCTRL_PIN(60, "SMB5_GBE_ALRT_N"), ++ PINCTRL_PIN(61, "PCIE_CLKREQ5_N"), ++ PINCTRL_PIN(62, "PCIE_CLKREQ6_N"), ++ PINCTRL_PIN(63, "PCIE_CLKREQ7_N"), ++ PINCTRL_PIN(64, "UART0_RXD"), ++ PINCTRL_PIN(65, "UART0_TXD"), ++ PINCTRL_PIN(66, "SMB5_GBE_CLK"), ++ PINCTRL_PIN(67, "SMB5_GBE_DATA"), ++ PINCTRL_PIN(68, "ERROR2_N"), ++ PINCTRL_PIN(69, "ERROR1_N"), ++ PINCTRL_PIN(70, "ERROR0_N"), ++ PINCTRL_PIN(71, "IERR_N"), ++ PINCTRL_PIN(72, "MCERR_N"), ++ PINCTRL_PIN(73, "SMB0_LEG_CLK"), ++ PINCTRL_PIN(74, "SMB0_LEG_DATA"), ++ PINCTRL_PIN(75, "SMB0_LEG_ALRT_N"), ++ PINCTRL_PIN(76, "SMB1_HOST_DATA"), ++ PINCTRL_PIN(77, "SMB1_HOST_CLK"), ++ PINCTRL_PIN(78, "SMB2_PECI_DATA"), ++ PINCTRL_PIN(79, "SMB2_PECI_CLK"), ++ PINCTRL_PIN(80, "SMB4_CSME0_DATA"), ++ PINCTRL_PIN(81, "SMB4_CSME0_CLK"), ++ PINCTRL_PIN(82, "SMB4_CSME0_ALRT_N"), ++ PINCTRL_PIN(83, "USB_OC0_N"), ++ PINCTRL_PIN(84, "FLEX_CLK_SE0"), ++ PINCTRL_PIN(85, "FLEX_CLK_SE1"), ++ PINCTRL_PIN(86, "GPIO4"), ++ PINCTRL_PIN(87, "GPIO5"), ++ PINCTRL_PIN(88, "GPIO6"), ++ PINCTRL_PIN(89, "GPIO7"), ++ PINCTRL_PIN(90, "SATA0_LED_N"), ++ PINCTRL_PIN(91, "SATA1_LED_N"), ++ PINCTRL_PIN(92, "SATA_PDETECT0"), ++ PINCTRL_PIN(93, "SATA_PDETECT1"), ++ PINCTRL_PIN(94, "SATA0_SDOUT"), ++ PINCTRL_PIN(95, "SATA1_SDOUT"), ++ PINCTRL_PIN(96, "UART1_RXD"), ++ PINCTRL_PIN(97, "UART1_TXD"), ++ PINCTRL_PIN(98, "GPIO8"), ++ PINCTRL_PIN(99, "GPIO9"), ++ PINCTRL_PIN(100, "TCK"), ++ PINCTRL_PIN(101, "TRST_N"), ++ PINCTRL_PIN(102, "TMS"), ++ PINCTRL_PIN(103, "TDI"), ++ PINCTRL_PIN(104, "TDO"), ++ PINCTRL_PIN(105, "CX_PRDY_N"), ++ PINCTRL_PIN(106, "CX_PREQ_N"), ++ PINCTRL_PIN(107, "CTBTRIGINOUT"), ++ PINCTRL_PIN(108, "CTBTRIGOUT"), ++ PINCTRL_PIN(109, "DFX_SPARE2"), ++ PINCTRL_PIN(110, "DFX_SPARE3"), ++ PINCTRL_PIN(111, "DFX_SPARE4"), ++ /* South GPP1 */ ++ PINCTRL_PIN(112, "SUSPWRDNACK"), ++ PINCTRL_PIN(113, "PMU_SUSCLK"), ++ PINCTRL_PIN(114, "ADR_TRIGGER"), ++ PINCTRL_PIN(115, "PMU_SLP_S45_N"), ++ PINCTRL_PIN(116, "PMU_SLP_S3_N"), ++ PINCTRL_PIN(117, "PMU_WAKE_N"), ++ PINCTRL_PIN(118, "PMU_PWRBTN_N"), ++ PINCTRL_PIN(119, "PMU_RESETBUTTON_N"), ++ PINCTRL_PIN(120, "PMU_PLTRST_N"), ++ PINCTRL_PIN(121, "SUS_STAT_N"), ++ PINCTRL_PIN(122, "SLP_S0IX_N"), ++ PINCTRL_PIN(123, "SPI_CS0_N"), ++ PINCTRL_PIN(124, "SPI_CS1_N"), ++ PINCTRL_PIN(125, "SPI_MOSI_IO0"), ++ PINCTRL_PIN(126, "SPI_MISO_IO1"), ++ PINCTRL_PIN(127, "SPI_IO2"), ++ PINCTRL_PIN(128, "SPI_IO3"), ++ PINCTRL_PIN(129, "SPI_CLK"), ++ PINCTRL_PIN(130, "SPI_CLK_LOOPBK"), ++ PINCTRL_PIN(131, "ESPI_IO0"), ++ PINCTRL_PIN(132, "ESPI_IO1"), ++ PINCTRL_PIN(133, "ESPI_IO2"), ++ PINCTRL_PIN(134, "ESPI_IO3"), ++ PINCTRL_PIN(135, "ESPI_CS0_N"), ++ PINCTRL_PIN(136, "ESPI_CLK"), ++ PINCTRL_PIN(137, "ESPI_RST_N"), ++ PINCTRL_PIN(138, "ESPI_ALRT0_N"), ++ PINCTRL_PIN(139, "GPIO10"), ++ PINCTRL_PIN(140, "GPIO11"), ++ PINCTRL_PIN(141, "ESPI_CLK_LOOPBK"), ++ PINCTRL_PIN(142, "EMMC_CMD"), ++ PINCTRL_PIN(143, "EMMC_STROBE"), ++ PINCTRL_PIN(144, "EMMC_CLK"), ++ PINCTRL_PIN(145, "EMMC_D0"), ++ PINCTRL_PIN(146, "EMMC_D1"), ++ PINCTRL_PIN(147, "EMMC_D2"), ++ PINCTRL_PIN(148, "EMMC_D3"), ++ PINCTRL_PIN(149, "EMMC_D4"), ++ PINCTRL_PIN(150, "EMMC_D5"), ++ PINCTRL_PIN(151, "EMMC_D6"), ++ PINCTRL_PIN(152, "EMMC_D7"), ++ PINCTRL_PIN(153, "GPIO3"), ++}; ++ ++static const unsigned int dnv_uart0_pins[] = { 60, 61, 64, 65 }; ++static const unsigned int dnv_uart0_modes[] = { 2, 3, 1, 1 }; ++static const unsigned int dnv_uart1_pins[] = { 94, 95, 96, 97 }; ++static const unsigned int dnv_uart2_pins[] = { 60, 61, 62, 63 }; ++static const unsigned int dnv_uart2_modes[] = { 1, 2, 2, 2 }; ++static const unsigned int dnv_emmc_pins[] = { ++ 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, ++}; ++ ++static const struct intel_pingroup dnv_groups[] = { ++ PIN_GROUP("uart0_grp", dnv_uart0_pins, dnv_uart0_modes), ++ PIN_GROUP("uart1_grp", dnv_uart1_pins, 1), ++ PIN_GROUP("uart2_grp", dnv_uart2_pins, dnv_uart2_modes), ++ PIN_GROUP("emmc_grp", dnv_emmc_pins, 1), ++}; ++ ++static const char * const dnv_uart0_groups[] = { "uart0_grp" }; ++static const char * const dnv_uart1_groups[] = { "uart1_grp" }; ++static const char * const dnv_uart2_groups[] = { "uart2_grp" }; ++static const char * const dnv_emmc_groups[] = { "emmc_grp" }; ++ ++static const struct intel_function dnv_functions[] = { ++ FUNCTION("uart0", dnv_uart0_groups), ++ FUNCTION("uart1", dnv_uart1_groups), ++ FUNCTION("uart2", dnv_uart2_groups), ++ FUNCTION("emmc", dnv_emmc_groups), ++}; ++ ++static const struct intel_padgroup dnv_north_gpps[] = { ++ DNV_GPP(0, 0, 31), /* North ALL_0 */ ++ DNV_GPP(1, 32, 40), /* North ALL_1 */ ++}; ++ ++static const struct intel_padgroup dnv_south_gpps[] = { ++ DNV_GPP(0, 41, 58), /* South DFX */ ++ DNV_GPP(1, 59, 90), /* South GPP0_0 */ ++ DNV_GPP(2, 91, 111), /* South GPP0_1 */ ++ DNV_GPP(3, 112, 143), /* South GPP1_0 */ ++ DNV_GPP(4, 144, 153), /* South GPP1_1 */ ++}; ++ ++static const struct intel_community dnv_communities[] = { ++ DNV_COMMUNITY(0, 0, 40, dnv_north_gpps, 0xc20000), ++ DNV_COMMUNITY(1, 41, 153, dnv_south_gpps, 0xc50000), ++}; ++ ++static const struct intel_pinctrl_soc_data dnv_soc_data = { ++ .pins = dnv_pins, ++ .npins = ARRAY_SIZE(dnv_pins), ++ .groups = dnv_groups, ++ .ngroups = ARRAY_SIZE(dnv_groups), ++ .functions = dnv_functions, ++ .nfunctions = ARRAY_SIZE(dnv_functions), ++ .communities = dnv_communities, ++ .ncommunities = ARRAY_SIZE(dnv_communities), ++}; ++ ++static INTEL_PINCTRL_PM_OPS(dnv_pinctrl_pm_ops); ++ ++static int pci_dev_init(wb_gpio_data_t *wb_gpio_data, struct pci_dev *pci_dev) ++{ ++ int err, i; ++ void __iomem *base; ++ ++ C3000_GPIO_VERBOSE("Enter vendor 0x%x, device 0x%x.\n", ++ pci_dev->vendor, pci_dev->device); ++ ++ C3000_GPIO_VERBOSE("start pci_enable_device!\n"); ++ err = pci_enable_device(pci_dev); ++ if (err) { ++ dev_err(&pci_dev->dev, "Failed to enable pci device, ret:%d.\n", err); ++ return err; ++ } ++ ++ err = pci_request_region(pci_dev, 0, "P2SB"); ++ if (err) { ++ dev_err(&pci_dev->dev, "Requesting C3000 P2SB BAR0 region failed, ret: %d\n", err); ++ goto err_disable; ++ } ++ ++ C3000_GPIO_VERBOSE("start pci_set_master!\n"); ++ pci_set_master(pci_dev); ++ ++ base = pci_iomap(pci_dev, wb_gpio_data->pci_bar, 0); ++ if (!base) { ++ dev_err(&pci_dev->dev, "pci_iomap bar: %d failed\n", wb_gpio_data->pci_bar); ++ err = -ENOMEM; ++ goto err_release; ++ } ++ wb_gpio_data->pci_mem_base = base; ++ ++ for (i = 0; i < dnv_soc_data.ncommunities; i++) { ++ wb_gpio_data->res[i] = base + dnv_soc_data.communities[i].dw_base; ++ } ++ return 0; ++err_release: ++ pci_release_region(pci_dev, wb_gpio_data->pci_bar); ++err_disable: ++ pci_disable_device(pci_dev); ++ return err; ++} ++ ++static void pci_dev_release(wb_gpio_data_t *wb_gpio_data) ++{ ++ struct pci_dev *pci_dev; ++ ++ pci_dev = wb_gpio_data->pci_dev; ++ if (wb_gpio_data->pci_mem_base) { ++ pci_iounmap(pci_dev, wb_gpio_data->pci_mem_base); ++ } ++ pci_release_region(pci_dev, wb_gpio_data->pci_bar); ++ pci_disable_device(pci_dev); ++ return; ++} ++ ++static int wb_gpio_driver_probe(struct platform_device *plat_dev) ++{ ++ int ret, devfn; ++ wb_gpio_data_t *wb_gpio_data; ++ wb_gpio_data_t *c3000_gpio_device; ++ struct pci_dev *pci_dev; ++ ++ if (dnv_soc_data.ncommunities > GPIO_RES_MAX) { ++ dev_err(&plat_dev->dev, "GPIO ncommunities %lu is more than GPIO resource number: %d\n", ++ dnv_soc_data.ncommunities, GPIO_RES_MAX); ++ return -EINVAL; ++ } ++ ++ wb_gpio_data = devm_kzalloc(&plat_dev->dev, sizeof(wb_gpio_data_t), GFP_KERNEL); ++ if (!wb_gpio_data) { ++ dev_err(&plat_dev->dev, "devm_kzalloc failed.\n"); ++ ret = -ENOMEM; ++ return ret; ++ } ++ ++ if (plat_dev->dev.of_node) { ++ ret = 0; ++ ret += of_property_read_u32(plat_dev->dev.of_node, "pci_domain", &wb_gpio_data->pci_domain); ++ ret += of_property_read_u32(plat_dev->dev.of_node, "pci_bus", &wb_gpio_data->pci_bus); ++ ret += of_property_read_u32(plat_dev->dev.of_node, "pci_slot", &wb_gpio_data->pci_slot); ++ ret += of_property_read_u32(plat_dev->dev.of_node, "pci_fn", &wb_gpio_data->pci_fn); ++ ret += of_property_read_u32(plat_dev->dev.of_node, "pci_bar", &wb_gpio_data->pci_bar); ++ ret += of_property_read_u32(plat_dev->dev.of_node, "irq", &wb_gpio_data->irq); ++ if (ret != 0) { ++ dev_err(&plat_dev->dev, "Failed to get dts config, ret:%d.\n", ret); ++ return -ENXIO; ++ } ++ } else { ++ if (plat_dev->dev.platform_data == NULL) { ++ dev_err(&plat_dev->dev, "Failed to get platform data config.\n"); ++ return -ENXIO; ++ } ++ c3000_gpio_device = plat_dev->dev.platform_data; ++ wb_gpio_data->pci_domain = c3000_gpio_device->pci_domain; ++ wb_gpio_data->pci_bus = c3000_gpio_device->pci_bus; ++ wb_gpio_data->pci_slot = c3000_gpio_device->pci_slot; ++ wb_gpio_data->pci_fn = c3000_gpio_device->pci_fn; ++ wb_gpio_data->pci_bar = c3000_gpio_device->pci_bar; ++ wb_gpio_data->irq = c3000_gpio_device->irq; ++ } ++ ++ C3000_GPIO_VERBOSE("domain:0x%04x, bus:0x%02x, slot:0x%02x, fn:%u, bar:%u, irq: %d\n", ++ wb_gpio_data->pci_domain, wb_gpio_data->pci_bus, wb_gpio_data->pci_slot, wb_gpio_data->pci_fn, ++ wb_gpio_data->pci_bar, wb_gpio_data->irq); ++ ++ devfn = PCI_DEVFN(wb_gpio_data->pci_slot, wb_gpio_data->pci_fn); ++ pci_dev = pci_get_domain_bus_and_slot(wb_gpio_data->pci_domain, wb_gpio_data->pci_bus, devfn); ++ if (pci_dev == NULL) { ++ dev_err(&plat_dev->dev, "Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", ++ wb_gpio_data->pci_domain, wb_gpio_data->pci_bus, devfn); ++ return -ENXIO; ++ } ++ wb_gpio_data->pci_dev = pci_dev; ++ ret = pci_dev_init(wb_gpio_data, pci_dev); ++ if (ret != 0) { ++ dev_err(&plat_dev->dev, "Failed to get pci bar address.\n"); ++ return ret; ++ } ++ C3000_GPIO_VERBOSE("pci_dev_init success, pci_mem_bae: 0x%pK, res0: 0x%pK, res1: 0x%pK\n", ++ wb_gpio_data->pci_mem_base, wb_gpio_data->res[0], wb_gpio_data->res[1]); ++ ++ platform_set_drvdata(plat_dev, wb_gpio_data); ++ ++ ret = wb_pinctrl_probe(plat_dev, &dnv_soc_data); ++ if (ret) { ++ dev_err(&plat_dev->dev, "C3000 gpio pinctrl probe failed, ret:%d\n", ret); ++ pci_dev_release(wb_gpio_data); ++ return ret; ++ } ++ dev_info(&plat_dev->dev, "C3000 gpio pinctrl probe success.\n"); ++ return 0; ++} ++ ++static int wb_gpio_driver_remove(struct platform_device *plat_dev) ++{ ++ wb_gpio_data_t *wb_gpio_data; ++ ++ C3000_GPIO_VERBOSE("c3000_gpio_pcie_remove.\n"); ++ ++ wb_gpio_data = platform_get_drvdata(plat_dev); ++ pci_dev_release(wb_gpio_data); ++ return 0; ++} ++ ++static const struct of_device_id gpio_c3000_match[] = { ++ { ++ .compatible = "wb_gpio_c3000", ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, gpio_c3000_match); ++ ++static struct platform_driver wb_gpio_c3000_driver = { ++ .driver = { ++ .name = "wb_gpio_c3000", ++ .of_match_table = gpio_c3000_match, ++ }, ++ .probe = wb_gpio_driver_probe, ++ .remove = wb_gpio_driver_remove, ++}; ++ ++module_platform_driver(wb_gpio_c3000_driver); ++ ++MODULE_DESCRIPTION("C3000 GPIO Controller driver"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000_device.c +new file mode 100644 +index 000000000..33ab19a5a +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000_device.c +@@ -0,0 +1,69 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#include "wb_pinctrl_intel.h" ++ ++static int g_wb_c300_gpio_device_debug = 0; ++static int g_wb_c300_gpio_device_error = 0; ++ ++module_param(g_wb_c300_gpio_device_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_c300_gpio_device_error, int, S_IRUGO | S_IWUSR); ++ ++#define WB_C3000_GPIO_DEVICE_DEBUG(fmt, args...) do { \ ++ if (g_wb_c300_gpio_device_debug) { \ ++ printk(KERN_INFO "[WB_C3000_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_C3000_GPIO_DEVICE_ERROR(fmt, args...) do { \ ++ if (g_wb_c300_gpio_device_error) { \ ++ printk(KERN_ERR "[WB_C3000_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static wb_gpio_data_t c3000_gpio_device_data = { ++ .irq = 15, ++ .pci_domain = 0x0000, ++ .pci_bus = 0x00, ++ .pci_slot = 0x1f, ++ .pci_fn = 1, ++ .pci_bar = 0, ++}; ++ ++static void wb_c3000_gpio_device_release(struct device *dev) ++{ ++ return; ++} ++ ++static struct platform_device c3000_gpio_device = { ++ .name = "wb_gpio_c3000", ++ .id = -1, ++ .dev = { ++ .platform_data = &c3000_gpio_device_data, ++ .release = wb_c3000_gpio_device_release, ++ }, ++}; ++ ++static int __init wb_c3000_gpio_device_init(void) ++{ ++ WB_C3000_GPIO_DEVICE_DEBUG("wb_c3000_gpio_device_init enter!\n"); ++ return platform_device_register(&c3000_gpio_device); ++ ++} ++ ++static void __exit wb_c3000_gpio_device_exit(void) ++{ ++ ++ WB_C3000_GPIO_DEVICE_DEBUG("wb_c3000_gpio_device_exit enter!\n"); ++ platform_device_unregister(&c3000_gpio_device); ++ return; ++} ++ ++module_init(wb_c3000_gpio_device_init); ++module_exit(wb_c3000_gpio_device_exit); ++MODULE_DESCRIPTION("C3000 GPIO Controller device"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.c +new file mode 100644 +index 000000000..7a52f17ac +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.c +@@ -0,0 +1,1829 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Intel pinctrl/GPIO core driver. ++ * ++ * Copyright (C) 2015, Intel Corporation ++ * Authors: Mathias Nyman ++ * Mika Westerberg ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "core.h" ++#include "wb_pinctrl_intel.h" ++ ++/* Offset from regs */ ++#define REVID 0x000 ++#define REVID_SHIFT 16 ++#define REVID_MASK GENMASK(31, 16) ++ ++#define PADBAR 0x00c ++ ++#define PADOWN_BITS 4 ++#define PADOWN_SHIFT(p) ((p) % 8 * PADOWN_BITS) ++#define PADOWN_MASK(p) (GENMASK(3, 0) << PADOWN_SHIFT(p)) ++#define PADOWN_GPP(p) ((p) / 8) ++ ++/* Offset from pad_regs */ ++#define PADCFG0 0x000 ++#define PADCFG0_RXEVCFG_SHIFT 25 ++#define PADCFG0_RXEVCFG_MASK GENMASK(26, 25) ++#define PADCFG0_RXEVCFG_LEVEL 0 ++#define PADCFG0_RXEVCFG_EDGE 1 ++#define PADCFG0_RXEVCFG_DISABLED 2 ++#define PADCFG0_RXEVCFG_EDGE_BOTH 3 ++#define PADCFG0_PREGFRXSEL BIT(24) ++#define PADCFG0_RXINV BIT(23) ++#define PADCFG0_GPIROUTIOXAPIC BIT(20) ++#define PADCFG0_GPIROUTSCI BIT(19) ++#define PADCFG0_GPIROUTSMI BIT(18) ++#define PADCFG0_GPIROUTNMI BIT(17) ++#define PADCFG0_PMODE_SHIFT 10 ++#define PADCFG0_PMODE_MASK GENMASK(13, 10) ++#define PADCFG0_PMODE_GPIO 0 ++#define PADCFG0_GPIORXDIS BIT(9) ++#define PADCFG0_GPIOTXDIS BIT(8) ++#define PADCFG0_GPIORXSTATE BIT(1) ++#define PADCFG0_GPIOTXSTATE BIT(0) ++ ++#define PADCFG1 0x004 ++#define PADCFG1_TERM_UP BIT(13) ++#define PADCFG1_TERM_SHIFT 10 ++#define PADCFG1_TERM_MASK GENMASK(12, 10) ++#define PADCFG1_TERM_20K BIT(2) ++#define PADCFG1_TERM_5K BIT(1) ++#define PADCFG1_TERM_1K BIT(0) ++#define PADCFG1_TERM_833 (BIT(1) | BIT(0)) ++ ++#define PADCFG2 0x008 ++#define PADCFG2_DEBEN BIT(0) ++#define PADCFG2_DEBOUNCE_SHIFT 1 ++#define PADCFG2_DEBOUNCE_MASK GENMASK(4, 1) ++ ++#define DEBOUNCE_PERIOD_NSEC 31250 ++ ++struct intel_pad_context { ++ u32 padcfg0; ++ u32 padcfg1; ++ u32 padcfg2; ++}; ++ ++struct intel_community_context { ++ u32 *intmask; ++ u32 *hostown; ++}; ++ ++#define pin_to_padno(c, p) ((p) - (c)->pin_base) ++#define padgroup_offset(g, p) ((p) - (g)->base) ++ ++static struct intel_community *intel_get_community(struct intel_pinctrl *pctrl, ++ unsigned int pin) ++{ ++ struct intel_community *community; ++ int i; ++ ++ for (i = 0; i < pctrl->ncommunities; i++) { ++ community = &pctrl->communities[i]; ++ if (pin >= community->pin_base && ++ pin < community->pin_base + community->npins) ++ return community; ++ } ++ ++ dev_warn(pctrl->dev, "failed to find community for pin %u\n", pin); ++ return NULL; ++} ++ ++static const struct intel_padgroup * ++intel_community_get_padgroup(const struct intel_community *community, ++ unsigned int pin) ++{ ++ int i; ++ ++ for (i = 0; i < community->ngpps; i++) { ++ const struct intel_padgroup *padgrp = &community->gpps[i]; ++ ++ if (pin >= padgrp->base && pin < padgrp->base + padgrp->size) ++ return padgrp; ++ } ++ ++ return NULL; ++} ++ ++static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl, ++ unsigned int pin, unsigned int reg) ++{ ++ const struct intel_community *community; ++ unsigned int padno; ++ size_t nregs; ++ ++ community = intel_get_community(pctrl, pin); ++ if (!community) ++ return NULL; ++ ++ padno = pin_to_padno(community, pin); ++ nregs = (community->features & PINCTRL_FEATURE_DEBOUNCE) ? 4 : 2; ++ ++ if (reg >= nregs * 4) ++ return NULL; ++ ++ return community->pad_regs + reg + padno * nregs * 4; ++} ++ ++static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned int pin) ++{ ++ const struct intel_community *community; ++ const struct intel_padgroup *padgrp; ++ unsigned int gpp, offset, gpp_offset; ++ void __iomem *padown; ++ ++ community = intel_get_community(pctrl, pin); ++ if (!community) ++ return false; ++ if (!community->padown_offset) ++ return true; ++ ++ padgrp = intel_community_get_padgroup(community, pin); ++ if (!padgrp) ++ return false; ++ ++ gpp_offset = padgroup_offset(padgrp, pin); ++ gpp = PADOWN_GPP(gpp_offset); ++ offset = community->padown_offset + padgrp->padown_num * 4 + gpp * 4; ++ padown = community->regs + offset; ++ ++ return !(readl(padown) & PADOWN_MASK(gpp_offset)); ++} ++ ++static bool intel_pad_set_acpi_mode(struct intel_pinctrl *pctrl, ++ unsigned pin, bool acpi_mode) ++{ ++ const struct intel_community *community; ++ const struct intel_padgroup *padgrp; ++ unsigned int offset, gpp_offset; ++ void __iomem *hostown; ++ uint32_t value; ++ ++ community = intel_get_community(pctrl, pin); ++ if (!community) ++ return true; ++ if (!community->hostown_offset) ++ return false; ++ ++ padgrp = intel_community_get_padgroup(community, pin); ++ if (!padgrp) ++ return true; ++ ++ gpp_offset = padgroup_offset(padgrp, pin); ++ offset = community->hostown_offset + padgrp->reg_num * 4; ++ hostown = community->regs + offset; ++ ++ value = readl(hostown); ++ if (acpi_mode) { ++ /* ACPI mode */ ++ value &= ~BIT(gpp_offset); ++ } else { ++ /* GPIO mode */ ++ value |= BIT(gpp_offset); ++ } ++ ++ writel(value, hostown); ++ ++ return !(readl(hostown) & BIT(gpp_offset)); ++} ++ ++static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned int pin) ++{ ++ const struct intel_community *community; ++ const struct intel_padgroup *padgrp; ++ unsigned int offset, gpp_offset; ++ void __iomem *hostown; ++ ++ community = intel_get_community(pctrl, pin); ++ if (!community) ++ return true; ++ if (!community->hostown_offset) ++ return false; ++ ++ padgrp = intel_community_get_padgroup(community, pin); ++ if (!padgrp) ++ return true; ++ ++ gpp_offset = padgroup_offset(padgrp, pin); ++ offset = community->hostown_offset + padgrp->reg_num * 4; ++ hostown = community->regs + offset; ++ ++ return !(readl(hostown) & BIT(gpp_offset)); ++} ++ ++/** ++ * enum - Locking variants of the pad configuration ++ * ++ * @PAD_UNLOCKED: pad is fully controlled by the configuration registers ++ * @PAD_LOCKED: pad configuration registers, except TX state, are locked ++ * @PAD_LOCKED_TX: pad configuration TX state is locked ++ * @PAD_LOCKED_FULL: pad configuration registers are locked completely ++ * ++ * Locking is considered as read-only mode for corresponding registers and ++ * their respective fields. That said, TX state bit is locked separately from ++ * the main locking scheme. ++ */ ++enum { ++ PAD_UNLOCKED = 0, ++ PAD_LOCKED = 1, ++ PAD_LOCKED_TX = 2, ++ PAD_LOCKED_FULL = PAD_LOCKED | PAD_LOCKED_TX, ++}; ++ ++static int intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin) ++{ ++ struct intel_community *community; ++ const struct intel_padgroup *padgrp; ++ unsigned int offset, gpp_offset; ++ u32 value; ++ int ret = PAD_UNLOCKED; ++ ++ community = intel_get_community(pctrl, pin); ++ if (!community) ++ return PAD_LOCKED_FULL; ++ if (!community->padcfglock_offset) ++ return PAD_UNLOCKED; ++ ++ padgrp = intel_community_get_padgroup(community, pin); ++ if (!padgrp) ++ return PAD_LOCKED_FULL; ++ ++ gpp_offset = padgroup_offset(padgrp, pin); ++ ++ /* ++ * If PADCFGLOCK and PADCFGLOCKTX bits are both clear for this pad, ++ * the pad is considered unlocked. Any other case means that it is ++ * either fully or partially locked. ++ */ ++ offset = community->padcfglock_offset + 0 + padgrp->reg_num * 8; ++ value = readl(community->regs + offset); ++ if (value & BIT(gpp_offset)) ++ ret |= PAD_LOCKED; ++ ++ offset = community->padcfglock_offset + 4 + padgrp->reg_num * 8; ++ value = readl(community->regs + offset); ++ if (value & BIT(gpp_offset)) ++ ret |= PAD_LOCKED_TX; ++ ++ return ret; ++} ++ ++static bool intel_pad_is_unlocked(struct intel_pinctrl *pctrl, unsigned int pin) ++{ ++ return (intel_pad_locked(pctrl, pin) & PAD_LOCKED) == PAD_UNLOCKED; ++} ++ ++static bool intel_pad_usable(struct intel_pinctrl *pctrl, unsigned int pin) ++{ ++ return intel_pad_owned_by_host(pctrl, pin) && intel_pad_is_unlocked(pctrl, pin); ++} ++ ++static int intel_get_groups_count(struct pinctrl_dev *pctldev) ++{ ++ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); ++ ++ return pctrl->soc->ngroups; ++} ++ ++static const char *intel_get_group_name(struct pinctrl_dev *pctldev, ++ unsigned int group) ++{ ++ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); ++ ++ return pctrl->soc->groups[group].name; ++} ++ ++static int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group, ++ const unsigned int **pins, unsigned int *npins) ++{ ++ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); ++ ++ *pins = pctrl->soc->groups[group].pins; ++ *npins = pctrl->soc->groups[group].npins; ++ return 0; ++} ++ ++static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, ++ unsigned int pin) ++{ ++ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); ++ void __iomem *padcfg; ++ u32 cfg0, cfg1, mode; ++ int locked; ++ bool acpi; ++ ++ if (!intel_pad_owned_by_host(pctrl, pin)) { ++ seq_puts(s, "not available"); ++ return; ++ } ++ ++ cfg0 = readl(intel_get_padcfg(pctrl, pin, PADCFG0)); ++ cfg1 = readl(intel_get_padcfg(pctrl, pin, PADCFG1)); ++ ++ mode = (cfg0 & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT; ++ if (mode == PADCFG0_PMODE_GPIO) ++ seq_puts(s, "GPIO "); ++ else ++ seq_printf(s, "mode %d ", mode); ++ ++ seq_printf(s, "0x%08x 0x%08x", cfg0, cfg1); ++ ++ /* Dump the additional PADCFG registers if available */ ++ padcfg = intel_get_padcfg(pctrl, pin, PADCFG2); ++ if (padcfg) ++ seq_printf(s, " 0x%08x", readl(padcfg)); ++ ++ locked = intel_pad_locked(pctrl, pin); ++ acpi = intel_pad_acpi_mode(pctrl, pin); ++ ++ if (locked || acpi) { ++ seq_puts(s, " ["); ++ if (locked) ++ seq_puts(s, "LOCKED"); ++ if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_TX) ++ seq_puts(s, " tx"); ++ else if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_FULL) ++ seq_puts(s, " full"); ++ ++ if (locked && acpi) ++ seq_puts(s, ", "); ++ ++ if (acpi) ++ seq_puts(s, "ACPI"); ++ seq_puts(s, "]"); ++ } ++} ++ ++static const struct pinctrl_ops intel_pinctrl_ops = { ++ .get_groups_count = intel_get_groups_count, ++ .get_group_name = intel_get_group_name, ++ .get_group_pins = intel_get_group_pins, ++ .pin_dbg_show = intel_pin_dbg_show, ++}; ++ ++static int intel_get_functions_count(struct pinctrl_dev *pctldev) ++{ ++ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); ++ ++ return pctrl->soc->nfunctions; ++} ++ ++static const char *intel_get_function_name(struct pinctrl_dev *pctldev, ++ unsigned int function) ++{ ++ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); ++ ++ return pctrl->soc->functions[function].name; ++} ++ ++static int intel_get_function_groups(struct pinctrl_dev *pctldev, ++ unsigned int function, ++ const char * const **groups, ++ unsigned int * const ngroups) ++{ ++ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); ++ ++ *groups = pctrl->soc->functions[function].groups; ++ *ngroups = pctrl->soc->functions[function].ngroups; ++ return 0; ++} ++ ++static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, ++ unsigned int function, unsigned int group) ++{ ++ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); ++ const struct intel_pingroup *grp = &pctrl->soc->groups[group]; ++ unsigned long flags; ++ int i; ++ ++ raw_spin_lock_irqsave(&pctrl->lock, flags); ++ ++ /* ++ * All pins in the groups needs to be accessible and writable ++ * before we can enable the mux for this group. ++ */ ++ for (i = 0; i < grp->npins; i++) { ++ if (!intel_pad_usable(pctrl, grp->pins[i])) { ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ return -EBUSY; ++ } ++ } ++ ++ /* Now enable the mux setting for each pin in the group */ ++ for (i = 0; i < grp->npins; i++) { ++ void __iomem *padcfg0; ++ u32 value; ++ ++ padcfg0 = intel_get_padcfg(pctrl, grp->pins[i], PADCFG0); ++ value = readl(padcfg0); ++ ++ value &= ~PADCFG0_PMODE_MASK; ++ ++ if (grp->modes) ++ value |= grp->modes[i] << PADCFG0_PMODE_SHIFT; ++ else ++ value |= grp->mode << PADCFG0_PMODE_SHIFT; ++ ++ writel(value, padcfg0); ++ } ++ ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ ++ return 0; ++} ++ ++static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input) ++{ ++ u32 value; ++ ++ value = readl(padcfg0); ++ if (input) { ++ value &= ~PADCFG0_GPIORXDIS; ++ value |= PADCFG0_GPIOTXDIS; ++ } else { ++ value &= ~PADCFG0_GPIOTXDIS; ++ value |= PADCFG0_GPIORXDIS; ++ } ++ writel(value, padcfg0); ++} ++ ++static int intel_gpio_get_gpio_mode(void __iomem *padcfg0) ++{ ++ return (readl(padcfg0) & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT; ++} ++ ++static void intel_gpio_set_gpio_mode(void __iomem *padcfg0) ++{ ++ u32 value; ++ ++ value = readl(padcfg0); ++ ++ /* Put the pad into GPIO mode */ ++ value &= ~PADCFG0_PMODE_MASK; ++ value |= PADCFG0_PMODE_GPIO; ++ ++ /* Disable input and output buffers */ ++ value |= PADCFG0_GPIORXDIS; ++ value |= PADCFG0_GPIOTXDIS; ++ ++ /* Disable SCI/SMI/NMI generation */ ++ value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI); ++ value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI); ++ ++ writel(value, padcfg0); ++} ++ ++static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned int pin) ++{ ++ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); ++ void __iomem *padcfg0; ++ unsigned long flags; ++ ++ padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); ++ ++ raw_spin_lock_irqsave(&pctrl->lock, flags); ++ ++ if (!intel_pad_owned_by_host(pctrl, pin)) { ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ return -EBUSY; ++ } ++ ++ if (!intel_pad_is_unlocked(pctrl, pin)) { ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ return 0; ++ } ++ ++ /* ++ * If pin is already configured in GPIO mode, we assume that ++ * firmware provides correct settings. In such case we avoid ++ * potential glitches on the pin. Otherwise, for the pin in ++ * alternative mode, consumer has to supply respective flags. ++ */ ++ if (intel_gpio_get_gpio_mode(padcfg0) == PADCFG0_PMODE_GPIO) { ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ return 0; ++ } ++ ++ intel_gpio_set_gpio_mode(padcfg0); ++ ++ /* Disable TX buffer and enable RX (this will be input) */ ++ __intel_gpio_set_direction(padcfg0, true); ++ ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ ++ return 0; ++} ++ ++static int intel_gpio_set_direction(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned int pin, bool input) ++{ ++ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); ++ void __iomem *padcfg0; ++ unsigned long flags; ++ ++ padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); ++ ++ raw_spin_lock_irqsave(&pctrl->lock, flags); ++ __intel_gpio_set_direction(padcfg0, input); ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ ++ return 0; ++} ++ ++static const struct pinmux_ops intel_pinmux_ops = { ++ .get_functions_count = intel_get_functions_count, ++ .get_function_name = intel_get_function_name, ++ .get_function_groups = intel_get_function_groups, ++ .set_mux = intel_pinmux_set_mux, ++ .gpio_request_enable = intel_gpio_request_enable, ++ .gpio_set_direction = intel_gpio_set_direction, ++}; ++ ++static int intel_config_get_pull(struct intel_pinctrl *pctrl, unsigned int pin, ++ enum pin_config_param param, u32 *arg) ++{ ++ const struct intel_community *community; ++ void __iomem *padcfg1; ++ unsigned long flags; ++ u32 value, term; ++ ++ community = intel_get_community(pctrl, pin); ++ padcfg1 = intel_get_padcfg(pctrl, pin, PADCFG1); ++ ++ raw_spin_lock_irqsave(&pctrl->lock, flags); ++ value = readl(padcfg1); ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ ++ term = (value & PADCFG1_TERM_MASK) >> PADCFG1_TERM_SHIFT; ++ ++ switch (param) { ++ case PIN_CONFIG_BIAS_DISABLE: ++ if (term) ++ return -EINVAL; ++ break; ++ ++ case PIN_CONFIG_BIAS_PULL_UP: ++ if (!term || !(value & PADCFG1_TERM_UP)) ++ return -EINVAL; ++ ++ switch (term) { ++ case PADCFG1_TERM_833: ++ *arg = 833; ++ break; ++ case PADCFG1_TERM_1K: ++ *arg = 1000; ++ break; ++ case PADCFG1_TERM_5K: ++ *arg = 5000; ++ break; ++ case PADCFG1_TERM_20K: ++ *arg = 20000; ++ break; ++ } ++ ++ break; ++ ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ if (!term || value & PADCFG1_TERM_UP) ++ return -EINVAL; ++ ++ switch (term) { ++ case PADCFG1_TERM_833: ++ if (!(community->features & PINCTRL_FEATURE_1K_PD)) ++ return -EINVAL; ++ *arg = 833; ++ break; ++ case PADCFG1_TERM_1K: ++ if (!(community->features & PINCTRL_FEATURE_1K_PD)) ++ return -EINVAL; ++ *arg = 1000; ++ break; ++ case PADCFG1_TERM_5K: ++ *arg = 5000; ++ break; ++ case PADCFG1_TERM_20K: ++ *arg = 20000; ++ break; ++ } ++ ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int intel_config_get_debounce(struct intel_pinctrl *pctrl, unsigned int pin, ++ enum pin_config_param param, u32 *arg) ++{ ++ void __iomem *padcfg2; ++ unsigned long flags; ++ unsigned long v; ++ u32 value2; ++ ++ padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2); ++ if (!padcfg2) ++ return -ENOTSUPP; ++ ++ raw_spin_lock_irqsave(&pctrl->lock, flags); ++ value2 = readl(padcfg2); ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ if (!(value2 & PADCFG2_DEBEN)) ++ return -EINVAL; ++ ++ v = (value2 & PADCFG2_DEBOUNCE_MASK) >> PADCFG2_DEBOUNCE_SHIFT; ++ *arg = BIT(v) * DEBOUNCE_PERIOD_NSEC / NSEC_PER_USEC; ++ ++ return 0; ++} ++ ++static int intel_config_get(struct pinctrl_dev *pctldev, unsigned int pin, ++ unsigned long *config) ++{ ++ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); ++ enum pin_config_param param = pinconf_to_config_param(*config); ++ u32 arg = 0; ++ int ret; ++ ++ if (!intel_pad_owned_by_host(pctrl, pin)) ++ return -ENOTSUPP; ++ ++ switch (param) { ++ case PIN_CONFIG_BIAS_DISABLE: ++ case PIN_CONFIG_BIAS_PULL_UP: ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ ret = intel_config_get_pull(pctrl, pin, param, &arg); ++ if (ret) ++ return ret; ++ break; ++ ++ case PIN_CONFIG_INPUT_DEBOUNCE: ++ ret = intel_config_get_debounce(pctrl, pin, param, &arg); ++ if (ret) ++ return ret; ++ break; ++ ++ default: ++ return -ENOTSUPP; ++ } ++ ++ *config = pinconf_to_config_packed(param, arg); ++ return 0; ++} ++ ++static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin, ++ unsigned long config) ++{ ++ unsigned int param = pinconf_to_config_param(config); ++ unsigned int arg = pinconf_to_config_argument(config); ++ const struct intel_community *community; ++ void __iomem *padcfg1; ++ unsigned long flags; ++ int ret = 0; ++ u32 value; ++ ++ community = intel_get_community(pctrl, pin); ++ padcfg1 = intel_get_padcfg(pctrl, pin, PADCFG1); ++ ++ raw_spin_lock_irqsave(&pctrl->lock, flags); ++ ++ value = readl(padcfg1); ++ ++ switch (param) { ++ case PIN_CONFIG_BIAS_DISABLE: ++ value &= ~(PADCFG1_TERM_MASK | PADCFG1_TERM_UP); ++ break; ++ ++ case PIN_CONFIG_BIAS_PULL_UP: ++ value &= ~PADCFG1_TERM_MASK; ++ ++ value |= PADCFG1_TERM_UP; ++ ++ /* Set default strength value in case none is given */ ++ if (arg == 1) ++ arg = 5000; ++ ++ switch (arg) { ++ case 20000: ++ value |= PADCFG1_TERM_20K << PADCFG1_TERM_SHIFT; ++ break; ++ case 5000: ++ value |= PADCFG1_TERM_5K << PADCFG1_TERM_SHIFT; ++ break; ++ case 1000: ++ value |= PADCFG1_TERM_1K << PADCFG1_TERM_SHIFT; ++ break; ++ case 833: ++ value |= PADCFG1_TERM_833 << PADCFG1_TERM_SHIFT; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ ++ break; ++ ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ value &= ~(PADCFG1_TERM_UP | PADCFG1_TERM_MASK); ++ ++ /* Set default strength value in case none is given */ ++ if (arg == 1) ++ arg = 5000; ++ ++ switch (arg) { ++ case 20000: ++ value |= PADCFG1_TERM_20K << PADCFG1_TERM_SHIFT; ++ break; ++ case 5000: ++ value |= PADCFG1_TERM_5K << PADCFG1_TERM_SHIFT; ++ break; ++ case 1000: ++ if (!(community->features & PINCTRL_FEATURE_1K_PD)) { ++ ret = -EINVAL; ++ break; ++ } ++ value |= PADCFG1_TERM_1K << PADCFG1_TERM_SHIFT; ++ break; ++ case 833: ++ if (!(community->features & PINCTRL_FEATURE_1K_PD)) { ++ ret = -EINVAL; ++ break; ++ } ++ value |= PADCFG1_TERM_833 << PADCFG1_TERM_SHIFT; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ ++ break; ++ } ++ ++ if (!ret) ++ writel(value, padcfg1); ++ ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ ++ return ret; ++} ++ ++static int intel_config_set_debounce(struct intel_pinctrl *pctrl, ++ unsigned int pin, unsigned int debounce) ++{ ++ void __iomem *padcfg0, *padcfg2; ++ unsigned long flags; ++ u32 value0, value2; ++ ++ padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2); ++ if (!padcfg2) ++ return -ENOTSUPP; ++ ++ padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); ++ ++ raw_spin_lock_irqsave(&pctrl->lock, flags); ++ ++ value0 = readl(padcfg0); ++ value2 = readl(padcfg2); ++ ++ /* Disable glitch filter and debouncer */ ++ value0 &= ~PADCFG0_PREGFRXSEL; ++ value2 &= ~(PADCFG2_DEBEN | PADCFG2_DEBOUNCE_MASK); ++ ++ if (debounce) { ++ unsigned long v; ++ ++ v = order_base_2(debounce * NSEC_PER_USEC / DEBOUNCE_PERIOD_NSEC); ++ if (v < 3 || v > 15) { ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ return -EINVAL; ++ } ++ ++ /* Enable glitch filter and debouncer */ ++ value0 |= PADCFG0_PREGFRXSEL; ++ value2 |= v << PADCFG2_DEBOUNCE_SHIFT; ++ value2 |= PADCFG2_DEBEN; ++ } ++ ++ writel(value0, padcfg0); ++ writel(value2, padcfg2); ++ ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ ++ return 0; ++} ++ ++static int intel_config_set(struct pinctrl_dev *pctldev, unsigned int pin, ++ unsigned long *configs, unsigned int nconfigs) ++{ ++ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); ++ int i, ret; ++ ++ if (!intel_pad_usable(pctrl, pin)) ++ return -ENOTSUPP; ++ ++ for (i = 0; i < nconfigs; i++) { ++ switch (pinconf_to_config_param(configs[i])) { ++ case PIN_CONFIG_BIAS_DISABLE: ++ case PIN_CONFIG_BIAS_PULL_UP: ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ ret = intel_config_set_pull(pctrl, pin, configs[i]); ++ if (ret) ++ return ret; ++ break; ++ ++ case PIN_CONFIG_INPUT_DEBOUNCE: ++ ret = intel_config_set_debounce(pctrl, pin, ++ pinconf_to_config_argument(configs[i])); ++ if (ret) ++ return ret; ++ break; ++ ++ default: ++ return -ENOTSUPP; ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct pinconf_ops intel_pinconf_ops = { ++ .is_generic = true, ++ .pin_config_get = intel_config_get, ++ .pin_config_set = intel_config_set, ++}; ++ ++static const struct pinctrl_desc intel_pinctrl_desc = { ++ .pctlops = &intel_pinctrl_ops, ++ .pmxops = &intel_pinmux_ops, ++ .confops = &intel_pinconf_ops, ++ .owner = THIS_MODULE, ++}; ++ ++/** ++ * intel_gpio_to_pin() - Translate from GPIO offset to pin number ++ * @pctrl: Pinctrl structure ++ * @offset: GPIO offset from gpiolib ++ * @community: Community is filled here if not %NULL ++ * @padgrp: Pad group is filled here if not %NULL ++ * ++ * When coming through gpiolib irqchip, the GPIO offset is not ++ * automatically translated to pinctrl pin number. This function can be ++ * used to find out the corresponding pinctrl pin. ++ */ ++static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned int offset, ++ const struct intel_community **community, ++ const struct intel_padgroup **padgrp) ++{ ++ int i; ++ ++ for (i = 0; i < pctrl->ncommunities; i++) { ++ const struct intel_community *comm = &pctrl->communities[i]; ++ int j; ++ ++ for (j = 0; j < comm->ngpps; j++) { ++ const struct intel_padgroup *pgrp = &comm->gpps[j]; ++ ++ if (pgrp->gpio_base == INTEL_GPIO_BASE_NOMAP) ++ continue; ++ ++ if (offset >= pgrp->gpio_base && ++ offset < pgrp->gpio_base + pgrp->size) { ++ int pin; ++ ++ pin = pgrp->base + offset - pgrp->gpio_base; ++ if (community) ++ *community = comm; ++ if (padgrp) ++ *padgrp = pgrp; ++ ++ return pin; ++ } ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++/** ++ * intel_pin_to_gpio() - Translate from pin number to GPIO offset ++ * @pctrl: Pinctrl structure ++ * @pin: pin number ++ * ++ * Translate the pin number of pinctrl to GPIO offset ++ */ ++static __maybe_unused int intel_pin_to_gpio(struct intel_pinctrl *pctrl, int pin) ++{ ++ const struct intel_community *community; ++ const struct intel_padgroup *padgrp; ++ ++ community = intel_get_community(pctrl, pin); ++ if (!community) ++ return -EINVAL; ++ ++ padgrp = intel_community_get_padgroup(community, pin); ++ if (!padgrp) ++ return -EINVAL; ++ ++ return pin - padgrp->base + padgrp->gpio_base; ++} ++ ++static int intel_gpio_get(struct gpio_chip *chip, unsigned int offset) ++{ ++ struct intel_pinctrl *pctrl = gpiochip_get_data(chip); ++ void __iomem *reg; ++ u32 padcfg0; ++ int pin; ++ ++ pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL); ++ if (pin < 0) ++ return -EINVAL; ++ ++ reg = intel_get_padcfg(pctrl, pin, PADCFG0); ++ if (!reg) ++ return -EINVAL; ++ ++ padcfg0 = readl(reg); ++ if (!(padcfg0 & PADCFG0_GPIOTXDIS)) ++ return !!(padcfg0 & PADCFG0_GPIOTXSTATE); ++ ++ return !!(padcfg0 & PADCFG0_GPIORXSTATE); ++} ++ ++static void intel_gpio_set(struct gpio_chip *chip, unsigned int offset, ++ int value) ++{ ++ struct intel_pinctrl *pctrl = gpiochip_get_data(chip); ++ unsigned long flags; ++ void __iomem *reg; ++ u32 padcfg0; ++ int pin; ++ ++ pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL); ++ if (pin < 0) ++ return; ++ ++ reg = intel_get_padcfg(pctrl, pin, PADCFG0); ++ if (!reg) ++ return; ++ ++ raw_spin_lock_irqsave(&pctrl->lock, flags); ++ padcfg0 = readl(reg); ++ if (value) ++ padcfg0 |= PADCFG0_GPIOTXSTATE; ++ else ++ padcfg0 &= ~PADCFG0_GPIOTXSTATE; ++ writel(padcfg0, reg); ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++} ++ ++static int intel_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) ++{ ++ struct intel_pinctrl *pctrl = gpiochip_get_data(chip); ++ unsigned long flags; ++ void __iomem *reg; ++ u32 padcfg0; ++ int pin; ++ ++ pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL); ++ if (pin < 0) ++ return -EINVAL; ++ ++ reg = intel_get_padcfg(pctrl, pin, PADCFG0); ++ if (!reg) ++ return -EINVAL; ++ ++ raw_spin_lock_irqsave(&pctrl->lock, flags); ++ padcfg0 = readl(reg); ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ if (padcfg0 & PADCFG0_PMODE_MASK) ++ return -EINVAL; ++ ++ if (padcfg0 & PADCFG0_GPIOTXDIS) ++ return GPIO_LINE_DIRECTION_IN; ++ ++ return GPIO_LINE_DIRECTION_OUT; ++} ++ ++static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) ++{ ++ return pinctrl_gpio_direction_input(chip->base + offset); ++} ++ ++static int intel_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, ++ int value) ++{ ++ intel_gpio_set(chip, offset, value); ++ return pinctrl_gpio_direction_output(chip->base + offset); ++} ++ ++static const struct gpio_chip intel_gpio_chip = { ++ .owner = THIS_MODULE, ++ .request = gpiochip_generic_request, ++ .free = gpiochip_generic_free, ++ .get_direction = intel_gpio_get_direction, ++ .direction_input = intel_gpio_direction_input, ++ .direction_output = intel_gpio_direction_output, ++ .get = intel_gpio_get, ++ .set = intel_gpio_set, ++ .set_config = gpiochip_generic_config, ++}; ++ ++static void intel_gpio_irq_ack(struct irq_data *d) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); ++ struct intel_pinctrl *pctrl = gpiochip_get_data(gc); ++ const struct intel_community *community; ++ const struct intel_padgroup *padgrp; ++ int pin; ++ ++ pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); ++ if (pin >= 0) { ++ unsigned int gpp, gpp_offset, is_offset; ++ ++ gpp = padgrp->reg_num; ++ gpp_offset = padgroup_offset(padgrp, pin); ++ is_offset = community->is_offset + gpp * 4; ++ ++ raw_spin_lock(&pctrl->lock); ++ writel(BIT(gpp_offset), community->regs + is_offset); ++ raw_spin_unlock(&pctrl->lock); ++ } ++} ++ ++static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); ++ struct intel_pinctrl *pctrl = gpiochip_get_data(gc); ++ const struct intel_community *community; ++ const struct intel_padgroup *padgrp; ++ int pin; ++ ++ pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); ++ if (pin >= 0) { ++ unsigned int gpp, gpp_offset; ++ unsigned long flags; ++ void __iomem *reg, *is; ++ u32 value; ++ ++ gpp = padgrp->reg_num; ++ gpp_offset = padgroup_offset(padgrp, pin); ++ ++ reg = community->regs + community->ie_offset + gpp * 4; ++ is = community->regs + community->is_offset + gpp * 4; ++ ++ raw_spin_lock_irqsave(&pctrl->lock, flags); ++ ++ /* Clear interrupt status first to avoid unexpected interrupt */ ++ writel(BIT(gpp_offset), is); ++ ++ value = readl(reg); ++ if (mask) ++ value &= ~BIT(gpp_offset); ++ else ++ value |= BIT(gpp_offset); ++ writel(value, reg); ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ } ++} ++ ++static void intel_gpio_irq_mask(struct irq_data *d) ++{ ++ intel_gpio_irq_mask_unmask(d, true); ++} ++ ++static void intel_gpio_irq_unmask(struct irq_data *d) ++{ ++ intel_gpio_irq_mask_unmask(d, false); ++} ++ ++static int intel_gpio_irq_type(struct irq_data *d, unsigned int type) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); ++ struct intel_pinctrl *pctrl = gpiochip_get_data(gc); ++ unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); ++ unsigned long flags; ++ void __iomem *reg; ++ u32 value; ++ ++ reg = intel_get_padcfg(pctrl, pin, PADCFG0); ++ if (!reg) ++ return -EINVAL; ++ ++ /* set not ACPI mode */ ++ intel_pad_set_acpi_mode(pctrl, pin, false); ++ ++ /* ++ * If the pin is in ACPI mode it is still usable as a GPIO but it ++ * cannot be used as IRQ because GPI_IS status bit will not be ++ * updated by the host controller hardware. ++ */ ++ if (intel_pad_acpi_mode(pctrl, pin)) { ++ dev_warn(pctrl->dev, "pin %u cannot be used as IRQ\n", pin); ++ return -EPERM; ++ } ++ ++ raw_spin_lock_irqsave(&pctrl->lock, flags); ++ ++ intel_gpio_set_gpio_mode(reg); ++ ++ /* Disable TX buffer and enable RX (this will be input) */ ++ __intel_gpio_set_direction(reg, true); ++ ++ value = readl(reg); ++ ++ value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV); ++ ++ if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { ++ value |= PADCFG0_RXEVCFG_EDGE_BOTH << PADCFG0_RXEVCFG_SHIFT; ++ } else if (type & IRQ_TYPE_EDGE_FALLING) { ++ value |= PADCFG0_RXEVCFG_EDGE << PADCFG0_RXEVCFG_SHIFT; ++ value |= PADCFG0_RXINV; ++ } else if (type & IRQ_TYPE_EDGE_RISING) { ++ value |= PADCFG0_RXEVCFG_EDGE << PADCFG0_RXEVCFG_SHIFT; ++ } else if (type & IRQ_TYPE_LEVEL_MASK) { ++ if (type & IRQ_TYPE_LEVEL_LOW) ++ value |= PADCFG0_RXINV; ++ } else { ++ value |= PADCFG0_RXEVCFG_DISABLED << PADCFG0_RXEVCFG_SHIFT; ++ } ++ ++ writel(value, reg); ++ ++ if (type & IRQ_TYPE_EDGE_BOTH) ++ irq_set_handler_locked(d, handle_edge_irq); ++ else if (type & IRQ_TYPE_LEVEL_MASK) ++ irq_set_handler_locked(d, handle_level_irq); ++ ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ ++ return 0; ++} ++ ++static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); ++ struct intel_pinctrl *pctrl = gpiochip_get_data(gc); ++ unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); ++ ++ if (on) ++ enable_irq_wake(pctrl->irq); ++ else ++ disable_irq_wake(pctrl->irq); ++ ++ dev_dbg(pctrl->dev, "%sable wake for pin %u\n", on ? "en" : "dis", pin); ++ return 0; ++} ++ ++static int intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl, ++ const struct intel_community *community) ++{ ++ struct gpio_chip *gc = &pctrl->chip; ++ unsigned int gpp; ++ int ret = 0; ++ ++ for (gpp = 0; gpp < community->ngpps; gpp++) { ++ const struct intel_padgroup *padgrp = &community->gpps[gpp]; ++ unsigned long pending, enabled, gpp_offset; ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&pctrl->lock, flags); ++ ++ pending = readl(community->regs + community->is_offset + ++ padgrp->reg_num * 4); ++ enabled = readl(community->regs + community->ie_offset + ++ padgrp->reg_num * 4); ++ ++ raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ ++ /* Only interrupts that are enabled */ ++ pending &= enabled; ++ ++ for_each_set_bit(gpp_offset, &pending, padgrp->size) { ++ unsigned int irq; ++ ++ irq = irq_find_mapping(gc->irq.domain, ++ padgrp->gpio_base + gpp_offset); ++ generic_handle_irq(irq); ++ } ++ ++ ret += pending ? 1 : 0; ++ } ++ ++ return ret; ++} ++ ++static irqreturn_t intel_gpio_irq(int irq, void *data) ++{ ++ const struct intel_community *community; ++ struct intel_pinctrl *pctrl = data; ++ unsigned int i; ++ int ret = 0; ++ ++ /* Need to check all communities for pending interrupts */ ++ for (i = 0; i < pctrl->ncommunities; i++) { ++ community = &pctrl->communities[i]; ++ ret += intel_gpio_community_irq_handler(pctrl, community); ++ } ++ ++ return IRQ_RETVAL(ret); ++} ++ ++static int intel_gpio_add_community_ranges(struct intel_pinctrl *pctrl, ++ const struct intel_community *community) ++{ ++ int ret = 0, i; ++ ++ for (i = 0; i < community->ngpps; i++) { ++ const struct intel_padgroup *gpp = &community->gpps[i]; ++ ++ if (gpp->gpio_base == INTEL_GPIO_BASE_NOMAP) ++ continue; ++ ++ ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), ++ gpp->gpio_base, gpp->base, ++ gpp->size); ++ if (ret) ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static int intel_gpio_add_pin_ranges(struct gpio_chip *gc) ++{ ++ struct intel_pinctrl *pctrl = gpiochip_get_data(gc); ++ int ret, i; ++ ++ for (i = 0; i < pctrl->ncommunities; i++) { ++ struct intel_community *community = &pctrl->communities[i]; ++ ++ ret = intel_gpio_add_community_ranges(pctrl, community); ++ if (ret) { ++ dev_err(pctrl->dev, "failed to add GPIO pin range\n"); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static unsigned int intel_gpio_ngpio(const struct intel_pinctrl *pctrl) ++{ ++ const struct intel_community *community; ++ unsigned int ngpio = 0; ++ int i, j; ++ ++ for (i = 0; i < pctrl->ncommunities; i++) { ++ community = &pctrl->communities[i]; ++ for (j = 0; j < community->ngpps; j++) { ++ const struct intel_padgroup *gpp = &community->gpps[j]; ++ ++ if (gpp->gpio_base == INTEL_GPIO_BASE_NOMAP) ++ continue; ++ ++ if (gpp->gpio_base + gpp->size > ngpio) ++ ngpio = gpp->gpio_base + gpp->size; ++ } ++ } ++ ++ return ngpio; ++} ++ ++static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq) ++{ ++ int ret; ++ struct gpio_irq_chip *girq; ++ ++ pctrl->chip = intel_gpio_chip; ++ ++ /* Setup GPIO chip */ ++ pctrl->chip.ngpio = intel_gpio_ngpio(pctrl); ++ pctrl->chip.label = dev_name(pctrl->dev); ++ pctrl->chip.parent = pctrl->dev; ++ pctrl->chip.base = 0; ++ pctrl->chip.add_pin_ranges = intel_gpio_add_pin_ranges; ++ pctrl->irq = irq; ++ ++ /* Setup IRQ chip */ ++ pctrl->irqchip.name = dev_name(pctrl->dev); ++ pctrl->irqchip.irq_ack = intel_gpio_irq_ack; ++ pctrl->irqchip.irq_mask = intel_gpio_irq_mask; ++ pctrl->irqchip.irq_unmask = intel_gpio_irq_unmask; ++ pctrl->irqchip.irq_set_type = intel_gpio_irq_type; ++ pctrl->irqchip.irq_set_wake = intel_gpio_irq_wake; ++ pctrl->irqchip.flags = IRQCHIP_MASK_ON_SUSPEND; ++ ++ /* ++ * On some platforms several GPIO controllers share the same interrupt ++ * line. ++ */ ++ ret = devm_request_irq(pctrl->dev, irq, intel_gpio_irq, ++ IRQF_SHARED | IRQF_NO_THREAD, ++ dev_name(pctrl->dev), pctrl); ++ if (ret) { ++ dev_err(pctrl->dev, "failed to request interrupt\n"); ++ return ret; ++ } ++ ++ girq = &pctrl->chip.irq; ++ girq->chip = &pctrl->irqchip; ++ /* This will let us handle the IRQ in the driver */ ++ girq->parent_handler = NULL; ++ girq->num_parents = 0; ++ girq->default_type = IRQ_TYPE_NONE; ++ girq->handler = handle_bad_irq; ++ ++ ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl); ++ if (ret) { ++ dev_err(pctrl->dev, "failed to register gpiochip\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int intel_pinctrl_add_padgroups(struct intel_pinctrl *pctrl, ++ struct intel_community *community) ++{ ++ struct intel_padgroup *gpps; ++ unsigned int npins = community->npins; ++ unsigned int padown_num = 0; ++ size_t ngpps, i; ++ ++ if (community->gpps) ++ ngpps = community->ngpps; ++ else ++ ngpps = DIV_ROUND_UP(community->npins, community->gpp_size); ++ ++ gpps = devm_kcalloc(pctrl->dev, ngpps, sizeof(*gpps), GFP_KERNEL); ++ if (!gpps) ++ return -ENOMEM; ++ ++ for (i = 0; i < ngpps; i++) { ++ if (community->gpps) { ++ gpps[i] = community->gpps[i]; ++ } else { ++ unsigned int gpp_size = community->gpp_size; ++ ++ gpps[i].reg_num = i; ++ gpps[i].base = community->pin_base + i * gpp_size; ++ gpps[i].size = min(gpp_size, npins); ++ npins -= gpps[i].size; ++ } ++ ++ if (gpps[i].size > 32) ++ return -EINVAL; ++ ++ /* Special treatment for GPIO base */ ++ switch (gpps[i].gpio_base) { ++ case INTEL_GPIO_BASE_MATCH: ++ gpps[i].gpio_base = gpps[i].base; ++ break; ++ case INTEL_GPIO_BASE_ZERO: ++ gpps[i].gpio_base = 0; ++ break; ++ case INTEL_GPIO_BASE_NOMAP: ++ default: ++ break; ++ } ++ ++ gpps[i].padown_num = padown_num; ++ ++ /* ++ * In older hardware the number of padown registers per ++ * group is fixed regardless of the group size. ++ */ ++ if (community->gpp_num_padown_regs) ++ padown_num += community->gpp_num_padown_regs; ++ else ++ padown_num += DIV_ROUND_UP(gpps[i].size * 4, 32); ++ } ++ ++ community->ngpps = ngpps; ++ community->gpps = gpps; ++ ++ return 0; ++} ++ ++static int intel_pinctrl_pm_init(struct intel_pinctrl *pctrl) ++{ ++#ifdef CONFIG_PM_SLEEP ++ const struct intel_pinctrl_soc_data *soc = pctrl->soc; ++ struct intel_community_context *communities; ++ struct intel_pad_context *pads; ++ int i; ++ ++ pads = devm_kcalloc(pctrl->dev, soc->npins, sizeof(*pads), GFP_KERNEL); ++ if (!pads) ++ return -ENOMEM; ++ ++ communities = devm_kcalloc(pctrl->dev, pctrl->ncommunities, ++ sizeof(*communities), GFP_KERNEL); ++ if (!communities) ++ return -ENOMEM; ++ ++ for (i = 0; i < pctrl->ncommunities; i++) { ++ struct intel_community *community = &pctrl->communities[i]; ++ u32 *intmask, *hostown; ++ ++ intmask = devm_kcalloc(pctrl->dev, community->ngpps, ++ sizeof(*intmask), GFP_KERNEL); ++ if (!intmask) ++ return -ENOMEM; ++ ++ communities[i].intmask = intmask; ++ ++ hostown = devm_kcalloc(pctrl->dev, community->ngpps, ++ sizeof(*hostown), GFP_KERNEL); ++ if (!hostown) ++ return -ENOMEM; ++ ++ communities[i].hostown = hostown; ++ } ++ ++ pctrl->context.pads = pads; ++ pctrl->context.communities = communities; ++#endif ++ ++ return 0; ++} ++ ++int wb_pinctrl_probe(struct platform_device *pdev, ++ const struct intel_pinctrl_soc_data *soc_data) ++{ ++ struct intel_pinctrl *pctrl; ++ struct intel_community *community; ++ wb_gpio_data_t *wb_gpio_data; ++ void __iomem *regs; ++ int i, ret; ++ u32 padbar, rev; ++ ++ if (!soc_data) { ++ dev_err(&pdev->dev, "soc_data is null\n"); ++ return -EINVAL; ++ } ++ ++ wb_gpio_data = platform_get_drvdata(pdev); ++ pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); ++ if (!pctrl) { ++ dev_err(&pdev->dev, "pctrl kzalloc failed\n"); ++ return -ENOMEM; ++ } ++ ++ /* check resource */ ++ if (soc_data->ncommunities > GPIO_RES_MAX) { ++ dev_err(&pdev->dev, "GPIO ncommunities %lu is more than GPIO resource number: %d\n", ++ soc_data->ncommunities, GPIO_RES_MAX); ++ return -EINVAL; ++ } ++ ++ pctrl->dev = &pdev->dev; ++ pctrl->soc = soc_data; ++ pctrl->irq = wb_gpio_data->irq; ++ raw_spin_lock_init(&pctrl->lock); ++ ++ /* ++ * Make a copy of the communities which we can use to hold pointers ++ * to the registers. ++ */ ++ pctrl->ncommunities = pctrl->soc->ncommunities; ++ pctrl->communities = devm_kcalloc(&pdev->dev, pctrl->ncommunities, ++ sizeof(*pctrl->communities), GFP_KERNEL); ++ if (!pctrl->communities) { ++ dev_err(&pdev->dev, "devm_kcalloc communities failed. ret:%d\n", ret); ++ return -ENOMEM; ++ } ++ ++ for (i = 0; i < pctrl->ncommunities; i++) { ++ community = &pctrl->communities[i]; ++ *community = pctrl->soc->communities[i]; ++ ++ regs = wb_gpio_data->res[i]; ++ ++ /* ++ * Determine community features based on the revision if ++ * not specified already. ++ */ ++ if (!community->features) { ++ rev = (readl(regs + REVID) & REVID_MASK) >> REVID_SHIFT; ++ if (rev >= 0x94) { ++ community->features |= PINCTRL_FEATURE_DEBOUNCE; ++ community->features |= PINCTRL_FEATURE_1K_PD; ++ } ++ } ++ ++ /* Read offset of the pad configuration registers */ ++ padbar = readl(regs + PADBAR); ++ ++ community->regs = regs; ++ community->pad_regs = regs + padbar; ++ ++ ret = intel_pinctrl_add_padgroups(pctrl, community); ++ if (ret) { ++ dev_err(&pdev->dev, "intel_pinctrl_add_padgroups failed. ret:%d\n", ret); ++ return ret; ++ } ++ } ++ ++ ret = intel_pinctrl_pm_init(pctrl); ++ if (ret) { ++ dev_err(&pdev->dev, "intel_pinctrl_pm_init failed. ret:%d\n", ret); ++ return ret; ++ } ++ ++ pctrl->pctldesc = intel_pinctrl_desc; ++ pctrl->pctldesc.name = dev_name(&pdev->dev); ++ pctrl->pctldesc.pins = pctrl->soc->pins; ++ pctrl->pctldesc.npins = pctrl->soc->npins; ++ ++ pctrl->pctldev = devm_pinctrl_register(&pdev->dev, &pctrl->pctldesc, ++ pctrl); ++ if (IS_ERR(pctrl->pctldev)) { ++ dev_err(&pdev->dev, "failed to register pinctrl driver\n"); ++ return PTR_ERR(pctrl->pctldev); ++ } ++ ++ ret = intel_gpio_probe(pctrl, pctrl->irq); ++ if (ret) { ++ dev_err(&pdev->dev, "intel_gpio_probe failed. ret:%d\n", ret); ++ return ret; ++ } ++ return 0; ++} ++EXPORT_SYMBOL_GPL(wb_pinctrl_probe); ++ ++#if 0 ++int intel_pinctrl_probe_by_hid(struct platform_device *pdev) ++{ ++ const struct intel_pinctrl_soc_data *data; ++ ++ data = device_get_match_data(&pdev->dev); ++ if (!data) ++ return -ENODATA; ++ ++ return intel_pinctrl_probe(pdev, data); ++} ++EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_hid); ++ ++int intel_pinctrl_probe_by_uid(struct platform_device *pdev) ++{ ++ const struct intel_pinctrl_soc_data *data; ++ ++ data = intel_pinctrl_get_soc_data(pdev); ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ return intel_pinctrl_probe(pdev, data); ++} ++EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_uid); ++ ++const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_device *pdev) ++{ ++ const struct intel_pinctrl_soc_data *data = NULL; ++ const struct intel_pinctrl_soc_data **table; ++ struct acpi_device *adev; ++ unsigned int i; ++ ++ adev = ACPI_COMPANION(&pdev->dev); ++ if (adev) { ++ const void *match = device_get_match_data(&pdev->dev); ++ ++ table = (const struct intel_pinctrl_soc_data **)match; ++ for (i = 0; table[i]; i++) { ++ if (!strcmp(adev->pnp.unique_id, table[i]->uid)) { ++ data = table[i]; ++ break; ++ } ++ } ++ } else { ++ const struct platform_device_id *id; ++ ++ id = platform_get_device_id(pdev); ++ if (!id) ++ return ERR_PTR(-ENODEV); ++ ++ table = (const struct intel_pinctrl_soc_data **)id->driver_data; ++ data = table[pdev->id]; ++ } ++ ++ return data ?: ERR_PTR(-ENODATA); ++} ++EXPORT_SYMBOL_GPL(intel_pinctrl_get_soc_data); ++#endif ++ ++#ifdef CONFIG_PM_SLEEP ++static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int pin) ++{ ++ const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin); ++ ++ if (!pd || !intel_pad_usable(pctrl, pin)) ++ return false; ++ ++ /* ++ * Only restore the pin if it is actually in use by the kernel (or ++ * by userspace). It is possible that some pins are used by the ++ * BIOS during resume and those are not always locked down so leave ++ * them alone. ++ */ ++ if (pd->mux_owner || pd->gpio_owner || ++ gpiochip_line_is_irq(&pctrl->chip, intel_pin_to_gpio(pctrl, pin))) ++ return true; ++ ++ return false; ++} ++ ++int wb_intel_pinctrl_suspend_noirq(struct device *dev) ++{ ++ struct intel_pinctrl *pctrl = dev_get_drvdata(dev); ++ struct intel_community_context *communities; ++ struct intel_pad_context *pads; ++ int i; ++ ++ pads = pctrl->context.pads; ++ for (i = 0; i < pctrl->soc->npins; i++) { ++ const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i]; ++ void __iomem *padcfg; ++ u32 val; ++ ++ if (!intel_pinctrl_should_save(pctrl, desc->number)) ++ continue; ++ ++ val = readl(intel_get_padcfg(pctrl, desc->number, PADCFG0)); ++ pads[i].padcfg0 = val & ~PADCFG0_GPIORXSTATE; ++ val = readl(intel_get_padcfg(pctrl, desc->number, PADCFG1)); ++ pads[i].padcfg1 = val; ++ ++ padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG2); ++ if (padcfg) ++ pads[i].padcfg2 = readl(padcfg); ++ } ++ ++ communities = pctrl->context.communities; ++ for (i = 0; i < pctrl->ncommunities; i++) { ++ struct intel_community *community = &pctrl->communities[i]; ++ void __iomem *base; ++ unsigned int gpp; ++ ++ base = community->regs + community->ie_offset; ++ for (gpp = 0; gpp < community->ngpps; gpp++) ++ communities[i].intmask[gpp] = readl(base + gpp * 4); ++ ++ base = community->regs + community->hostown_offset; ++ for (gpp = 0; gpp < community->ngpps; gpp++) ++ communities[i].hostown[gpp] = readl(base + gpp * 4); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(wb_intel_pinctrl_suspend_noirq); ++ ++static void intel_gpio_irq_init(struct intel_pinctrl *pctrl) ++{ ++ size_t i; ++ ++ for (i = 0; i < pctrl->ncommunities; i++) { ++ const struct intel_community *community; ++ void __iomem *base; ++ unsigned int gpp; ++ ++ community = &pctrl->communities[i]; ++ base = community->regs; ++ ++ for (gpp = 0; gpp < community->ngpps; gpp++) { ++ /* Mask and clear all interrupts */ ++ writel(0, base + community->ie_offset + gpp * 4); ++ writel(0xffff, base + community->is_offset + gpp * 4); ++ } ++ } ++} ++ ++static bool intel_gpio_update_reg(void __iomem *reg, u32 mask, u32 value) ++{ ++ u32 curr, updated; ++ ++ curr = readl(reg); ++ ++ updated = (curr & ~mask) | (value & mask); ++ if (curr == updated) ++ return false; ++ ++ writel(updated, reg); ++ return true; ++} ++ ++static void intel_restore_hostown(struct intel_pinctrl *pctrl, unsigned int c, ++ void __iomem *base, unsigned int gpp, u32 saved) ++{ ++ const struct intel_community *community = &pctrl->communities[c]; ++ const struct intel_padgroup *padgrp = &community->gpps[gpp]; ++ struct device *dev = pctrl->dev; ++ const char *dummy; ++ u32 requested = 0; ++ unsigned int i; ++ ++ if (padgrp->gpio_base == INTEL_GPIO_BASE_NOMAP) ++ return; ++ ++ for_each_requested_gpio_in_range(&pctrl->chip, i, padgrp->gpio_base, padgrp->size, dummy) ++ requested |= BIT(i); ++ ++ if (!intel_gpio_update_reg(base + gpp * 4, requested, saved)) ++ return; ++ ++ dev_dbg(dev, "restored hostown %u/%u %#08x\n", c, gpp, readl(base + gpp * 4)); ++} ++ ++static void intel_restore_intmask(struct intel_pinctrl *pctrl, unsigned int c, ++ void __iomem *base, unsigned int gpp, u32 saved) ++{ ++ struct device *dev = pctrl->dev; ++ ++ if (!intel_gpio_update_reg(base + gpp * 4, ~0U, saved)) ++ return; ++ ++ dev_dbg(dev, "restored mask %u/%u %#08x\n", c, gpp, readl(base + gpp * 4)); ++} ++ ++static void intel_restore_padcfg(struct intel_pinctrl *pctrl, unsigned int pin, ++ unsigned int reg, u32 saved) ++{ ++ u32 mask = (reg == PADCFG0) ? PADCFG0_GPIORXSTATE : 0; ++ unsigned int n = reg / sizeof(u32); ++ struct device *dev = pctrl->dev; ++ void __iomem *padcfg; ++ ++ padcfg = intel_get_padcfg(pctrl, pin, reg); ++ if (!padcfg) ++ return; ++ ++ if (!intel_gpio_update_reg(padcfg, ~mask, saved)) ++ return; ++ ++ dev_dbg(dev, "restored pin %u padcfg%u %#08x\n", pin, n, readl(padcfg)); ++} ++ ++int wb_intel_pinctrl_resume_noirq(struct device *dev) ++{ ++ struct intel_pinctrl *pctrl = dev_get_drvdata(dev); ++ const struct intel_community_context *communities; ++ const struct intel_pad_context *pads; ++ int i; ++ ++ /* Mask all interrupts */ ++ intel_gpio_irq_init(pctrl); ++ ++ pads = pctrl->context.pads; ++ for (i = 0; i < pctrl->soc->npins; i++) { ++ const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i]; ++ ++ if (!intel_pinctrl_should_save(pctrl, desc->number)) ++ continue; ++ ++ intel_restore_padcfg(pctrl, desc->number, PADCFG0, pads[i].padcfg0); ++ intel_restore_padcfg(pctrl, desc->number, PADCFG1, pads[i].padcfg1); ++ intel_restore_padcfg(pctrl, desc->number, PADCFG2, pads[i].padcfg2); ++ } ++ ++ communities = pctrl->context.communities; ++ for (i = 0; i < pctrl->ncommunities; i++) { ++ struct intel_community *community = &pctrl->communities[i]; ++ void __iomem *base; ++ unsigned int gpp; ++ ++ base = community->regs + community->ie_offset; ++ for (gpp = 0; gpp < community->ngpps; gpp++) ++ intel_restore_intmask(pctrl, i, base, gpp, communities[i].intmask[gpp]); ++ ++ base = community->regs + community->hostown_offset; ++ for (gpp = 0; gpp < community->ngpps; gpp++) ++ intel_restore_hostown(pctrl, i, base, gpp, communities[i].hostown[gpp]); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(wb_intel_pinctrl_resume_noirq); ++#endif ++ ++MODULE_AUTHOR("Mathias Nyman "); ++MODULE_AUTHOR("Mika Westerberg "); ++MODULE_DESCRIPTION("Intel pinctrl/GPIO core driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.h +new file mode 100644 +index 000000000..5ed0cc065 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.h +@@ -0,0 +1,275 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Core pinctrl/GPIO driver for Intel GPIO controllers ++ * ++ * Copyright (C) 2015, Intel Corporation ++ * Authors: Mathias Nyman ++ * Mika Westerberg ++ */ ++ ++#ifndef PINCTRL_INTEL_H ++#define PINCTRL_INTEL_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct platform_device; ++struct device; ++ ++#define GPIO_RES_MAX (2) ++ ++typedef struct wb_gpio_data_s { ++ int irq; ++ void __iomem *res[GPIO_RES_MAX]; ++ unsigned int pci_domain; ++ unsigned int pci_bus; ++ unsigned int pci_slot; ++ unsigned int pci_fn; ++ unsigned int pci_bar; ++ struct pci_dev *pci_dev; ++ void __iomem *pci_mem_base; ++} wb_gpio_data_t; ++ ++/** ++ * struct intel_pingroup - Description about group of pins ++ * @name: Name of the groups ++ * @pins: All pins in this group ++ * @npins: Number of pins in this groups ++ * @mode: Native mode in which the group is muxed out @pins. Used if @modes ++ * is %NULL. ++ * @modes: If not %NULL this will hold mode for each pin in @pins ++ */ ++struct intel_pingroup { ++ const char *name; ++ const unsigned int *pins; ++ size_t npins; ++ unsigned short mode; ++ const unsigned int *modes; ++}; ++ ++/** ++ * struct intel_function - Description about a function ++ * @name: Name of the function ++ * @groups: An array of groups for this function ++ * @ngroups: Number of groups in @groups ++ */ ++struct intel_function { ++ const char *name; ++ const char * const *groups; ++ size_t ngroups; ++}; ++ ++/** ++ * struct intel_padgroup - Hardware pad group information ++ * @reg_num: GPI_IS register number ++ * @base: Starting pin of this group ++ * @size: Size of this group (maximum is 32). ++ * @gpio_base: Starting GPIO base of this group ++ * @padown_num: PAD_OWN register number (assigned by the core driver) ++ * ++ * If pad groups of a community are not the same size, use this structure ++ * to specify them. ++ */ ++struct intel_padgroup { ++ unsigned int reg_num; ++ unsigned int base; ++ unsigned int size; ++ int gpio_base; ++ unsigned int padown_num; ++}; ++ ++/** ++ * enum - Special treatment for GPIO base in pad group ++ * ++ * @INTEL_GPIO_BASE_ZERO: force GPIO base to be 0 ++ * @INTEL_GPIO_BASE_NOMAP: no GPIO mapping should be created ++ * @INTEL_GPIO_BASE_MATCH: matches with starting pin number ++ */ ++enum { ++ INTEL_GPIO_BASE_ZERO = -2, ++ INTEL_GPIO_BASE_NOMAP = -1, ++ INTEL_GPIO_BASE_MATCH = 0, ++}; ++ ++/** ++ * struct intel_community - Intel pin community description ++ * @barno: MMIO BAR number where registers for this community reside ++ * @padown_offset: Register offset of PAD_OWN register from @regs. If %0 ++ * then there is no support for owner. ++ * @padcfglock_offset: Register offset of PADCFGLOCK from @regs. If %0 then ++ * locking is not supported. ++ * @hostown_offset: Register offset of HOSTSW_OWN from @regs. If %0 then it ++ * is assumed that the host owns the pin (rather than ++ * ACPI). ++ * @is_offset: Register offset of GPI_IS from @regs. ++ * @ie_offset: Register offset of GPI_IE from @regs. ++ * @features: Additional features supported by the hardware ++ * @pin_base: Starting pin of pins in this community ++ * @npins: Number of pins in this community ++ * @gpp_size: Maximum number of pads in each group, such as PADCFGLOCK, ++ * HOSTSW_OWN, GPI_IS, GPI_IE. Used when @gpps is %NULL. ++ * @gpp_num_padown_regs: Number of pad registers each pad group consumes at ++ * minimum. Use %0 if the number of registers can be ++ * determined by the size of the group. ++ * @gpps: Pad groups if the controller has variable size pad groups ++ * @ngpps: Number of pad groups in this community ++ * @pad_map: Optional non-linear mapping of the pads ++ * @nirqs: Optional total number of IRQs this community can generate ++ * @acpi_space_id: Optional address space ID for ACPI OpRegion handler ++ * @regs: Community specific common registers (reserved for core driver) ++ * @pad_regs: Community specific pad registers (reserved for core driver) ++ * ++ * In some of Intel GPIO host controllers this driver supports each pad group ++ * is of equal size (except the last one). In that case the driver can just ++ * fill in @gpp_size field and let the core driver to handle the rest. If ++ * the controller has pad groups of variable size the client driver can ++ * pass custom @gpps and @ngpps instead. ++ */ ++struct intel_community { ++ unsigned int barno; ++ unsigned int padown_offset; ++ unsigned int padcfglock_offset; ++ unsigned int hostown_offset; ++ unsigned int is_offset; ++ unsigned int ie_offset; ++ unsigned int features; ++ unsigned int pin_base; ++ size_t npins; ++ unsigned int gpp_size; ++ unsigned int gpp_num_padown_regs; ++ const struct intel_padgroup *gpps; ++ size_t ngpps; ++ const unsigned int *pad_map; ++ unsigned short nirqs; ++ unsigned short acpi_space_id; ++ ++ /* Reserved for the core driver */ ++ void __iomem *regs; ++ void __iomem *pad_regs; ++ u32 dw_base; ++}; ++ ++/* Additional features supported by the hardware */ ++#define PINCTRL_FEATURE_DEBOUNCE BIT(0) ++#define PINCTRL_FEATURE_1K_PD BIT(1) ++ ++/** ++ * PIN_GROUP - Declare a pin group ++ * @n: Name of the group ++ * @p: An array of pins this group consists ++ * @m: Mode which the pins are put when this group is active. Can be either ++ * a single integer or an array of integers in which case mode is per ++ * pin. ++ */ ++#define PIN_GROUP(n, p, m) \ ++ { \ ++ .name = (n), \ ++ .pins = (p), \ ++ .npins = ARRAY_SIZE((p)), \ ++ .mode = __builtin_choose_expr( \ ++ __builtin_constant_p((m)), (m), 0), \ ++ .modes = __builtin_choose_expr( \ ++ __builtin_constant_p((m)), NULL, (m)), \ ++ } ++ ++#define FUNCTION(n, g) \ ++ { \ ++ .name = (n), \ ++ .groups = (g), \ ++ .ngroups = ARRAY_SIZE((g)), \ ++ } ++ ++/** ++ * struct intel_pinctrl_soc_data - Intel pin controller per-SoC configuration ++ * @uid: ACPI _UID for the probe driver use if needed ++ * @pins: Array if pins this pinctrl controls ++ * @npins: Number of pins in the array ++ * @groups: Array of pin groups ++ * @ngroups: Number of groups in the array ++ * @functions: Array of functions ++ * @nfunctions: Number of functions in the array ++ * @communities: Array of communities this pinctrl handles ++ * @ncommunities: Number of communities in the array ++ * ++ * The @communities is used as a template by the core driver. It will make ++ * copy of all communities and fill in rest of the information. ++ */ ++struct intel_pinctrl_soc_data { ++ const char *uid; ++ const struct pinctrl_pin_desc *pins; ++ size_t npins; ++ const struct intel_pingroup *groups; ++ size_t ngroups; ++ const struct intel_function *functions; ++ size_t nfunctions; ++ const struct intel_community *communities; ++ size_t ncommunities; ++}; ++ ++struct intel_pad_context; ++struct intel_community_context; ++ ++/** ++ * struct intel_pinctrl_context - context to be saved during suspend-resume ++ * @pads: Opaque context per pad (driver dependent) ++ * @communities: Opaque context per community (driver dependent) ++ */ ++struct intel_pinctrl_context { ++ struct intel_pad_context *pads; ++ struct intel_community_context *communities; ++}; ++ ++/** ++ * struct intel_pinctrl - Intel pinctrl private structure ++ * @dev: Pointer to the device structure ++ * @lock: Lock to serialize register access ++ * @pctldesc: Pin controller description ++ * @pctldev: Pointer to the pin controller device ++ * @chip: GPIO chip in this pin controller ++ * @irqchip: IRQ chip in this pin controller ++ * @soc: SoC/PCH specific pin configuration data ++ * @communities: All communities in this pin controller ++ * @ncommunities: Number of communities in this pin controller ++ * @context: Configuration saved over system sleep ++ * @irq: pinctrl/GPIO chip irq number ++ */ ++struct intel_pinctrl { ++ struct device *dev; ++ raw_spinlock_t lock; ++ struct pinctrl_desc pctldesc; ++ struct pinctrl_dev *pctldev; ++ struct gpio_chip chip; ++ struct irq_chip irqchip; ++ const struct intel_pinctrl_soc_data *soc; ++ struct intel_community *communities; ++ size_t ncommunities; ++ struct intel_pinctrl_context context; ++ int irq; ++}; ++ ++int wb_pinctrl_probe(struct platform_device *pdev, const struct intel_pinctrl_soc_data *soc_data); ++ ++#if 0 ++const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_device *pdev); ++int intel_pinctrl_probe_by_hid(struct platform_device *pdev); ++int intel_pinctrl_probe_by_uid(struct platform_device *pdev); ++#endif ++ ++#ifdef CONFIG_PM_SLEEP ++int wb_intel_pinctrl_suspend_noirq(struct device *dev); ++int wb_intel_pinctrl_resume_noirq(struct device *dev); ++#endif ++ ++#define INTEL_PINCTRL_PM_OPS(_name) \ ++const struct dev_pm_ops _name = { \ ++ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(wb_intel_pinctrl_suspend_noirq, \ ++ wb_intel_pinctrl_resume_noirq) \ ++} ++ ++#endif /* PINCTRL_INTEL_H */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/Makefile +new file mode 100644 +index 000000000..369b64605 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/Makefile +@@ -0,0 +1,20 @@ ++pes_parent_dir:=$(shell pwd)/$(lastword $(MAKEFILE_LIST)) ++pes_parent_dir:=$(shell dirname $(pes_parent_dir)) ++ ++SUBDIRS=$(shell ls -l | grep ^d | awk '{if($$9 != "build") print $$9}') ++INC = -I./inc ++ ++all : CHECK $(SUBDIRS) ++CHECK : ++ @echo $(pes_parent_dir) ++ ++$(SUBDIRS):ECHO ++ #@echo $@ ++ make -C $@ ++ ++ECHO: ++ @echo $(SUBDIRS) ++ ++.PHONY : clean ++clean : ++ -rm -rf $(SYSFS_OUT_PUT) +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/Makefile +new file mode 100644 +index 000000000..e516b70b3 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/Makefile +@@ -0,0 +1,25 @@ ++PWD = $(shell pwd) ++ ++EXTRA_CFLAGS:= -I$(M)/include ++EXTRA_CFLAGS+= -Wall ++SUBDIR_CFG = cfg ++plat_dfd-objs := dfd_module.o dfd_fan_driver.o \ ++dfd_slot_driver.o \ ++dfd_sensors_driver.o \ ++dfd_psu_driver.o \ ++dfd_sff_driver.o \ ++$(SUBDIR_CFG)/dfd_cfg.o \ ++$(SUBDIR_CFG)/dfd_cfg_adapter.o \ ++$(SUBDIR_CFG)/dfd_cfg_file.o \ ++$(SUBDIR_CFG)/dfd_cfg_info.o \ ++$(SUBDIR_CFG)/dfd_cfg_listnode.o \ ++ ++obj-m := plat_dfd.o ++all: ++ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules ++ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi ++ cp -p $(PWD)/*.ko $(module_out_put_dir) ++clean: ++ rm -f $(PWD)/*.o $(PWD)/$(SUBDIR_CFG)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/$(SUBDIR_CFG)/.*.cmd $(PWD)/*.mod ++ rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order ++ rm -rf $(PWD)/.tmp_versions +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c +new file mode 100644 +index 000000000..3d05621ef +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c +@@ -0,0 +1,815 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../include/dfd_module.h" ++#include "../include/dfd_cfg_file.h" ++#include "../include/dfd_cfg_listnode.h" ++#include "../include/dfd_cfg_info.h" ++#include "../include/dfd_cfg_adapter.h" ++#include "../include/dfd_cfg.h" ++#include "../../dev_sysfs/include/sysfs_common.h" ++ ++#ifdef DFD_CFG_ITEM ++#undef DFD_CFG_ITEM ++#endif ++#define DFD_CFG_ITEM(_id, _name, _index_min, _index_max) _name, ++static char *dfd_cfg_item_name[] = { ++ DFD_CFG_ITEM_ALL ++}; ++ ++#ifdef DFD_CFG_ITEM ++#undef DFD_CFG_ITEM ++#endif ++#define DFD_CFG_ITEM(_id, _name, _index_min, _index_max) {_index_min, _index_max}, ++static index_range_t dfd_cfg_item_index_range[] = { ++ DFD_CFG_ITEM_ALL ++}; ++ ++static lnode_root_t dfd_ko_cfg_list_root; ++ ++static void dfd_ko_cfg_del_space_lf_cr(char *str) ++{ ++ int i, j; ++ int len; ++ ++ len = strlen(str); ++ for (i = 0; i < len; i++) { ++ if (str[i] == '\r' || str[i] == '\n' || str[i] == ' ') { ++ for (j = i; j < len - 1; j++) { ++ str[j] = str[j + 1]; ++ } ++ str[j] = '\0'; ++ len--; ++ i--; ++ } ++ } ++} ++ ++static int dfd_ko_cfg_get_value_from_char(char *value_str, int32_t *value, int line_num) ++{ ++ int value_tmp = 0; ++ ++ if (strlen(value_str) == 0) { ++ DBG_DEBUG(DBG_WARN, "line%d: value str is empty\n", line_num); ++ *value = DFD_CFG_EMPTY_VALUE; ++ return 0; ++ } ++ ++ if ((strlen(value_str) > 2) && (value_str[0] == '0') ++ && (value_str[1] == 'x' || value_str[1] == 'X')) { ++ value_tmp = (int32_t)simple_strtol(value_str, NULL, 16); ++ } else { ++ value_tmp = (int32_t)simple_strtol(value_str, NULL, 10); ++ } ++ ++ *value = value_tmp; ++ return 0; ++} ++ ++static int dfd_ko_cfg_analyse_index(char *index_str, int *index1, int *index2, int line_num) ++{ ++ int rv; ++ char *index1_begin_char, *index2_begin_char; ++ ++ if (index_str[0] != '_') { ++ DBG_DEBUG(DBG_ERROR, "line%d: no '-' between name and index1\n", line_num); ++ return -1; ++ } ++ ++ index1_begin_char = index_str; ++ rv = dfd_ko_cfg_get_value_from_char(++index1_begin_char, index1, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ ++ if (index2 == NULL) { ++ return 0; ++ } ++ ++ index2_begin_char = strchr(index1_begin_char, '_'); ++ if (index2_begin_char == NULL) { ++ DBG_DEBUG(DBG_ERROR, "line%d: no '-' between index1 and index2\n", line_num); ++ return -1; ++ } else { ++ rv = dfd_ko_cfg_get_value_from_char(++index2_begin_char, index2, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++static int dfd_ko_cfg_check_array_index(index_range_t *index_range, int *index1, int *index2, ++ int line_num) ++{ ++ ++ if ((*index1 < 0) || (*index1 > index_range->index1_max)) { ++ DBG_DEBUG(DBG_ERROR, "line%d: index1[%d] invalid, max=%d\n", line_num, *index1, ++ index_range->index1_max); ++ return -1; ++ } ++ ++ if (index2 == NULL) { ++ return 0; ++ } ++ ++ if ((*index2 < 0) || (*index2 > index_range->index2_max)) { ++ DBG_DEBUG(DBG_ERROR, "line%d: index2[%d] invalid, max=%d\n", line_num, *index2, ++ index_range->index2_max); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int dfd_ko_cfg_get_index(char *index_str, index_range_t *index_range, int *index1, ++ int *index2, int line_num) ++{ ++ int rv; ++ ++ if (index_range->index2_max == INDEX_NOT_EXIST) { ++ index2 = NULL; ++ } ++ ++ rv = dfd_ko_cfg_analyse_index(index_str, index1, index2, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ ++ rv = dfd_ko_cfg_check_array_index(index_range, index1, index2, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int dfd_ko_cfg_add_int_item(int key, int value, int line_num) ++{ ++ int rv; ++ int *int_cfg; ++ ++ int_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); ++ if (int_cfg == NULL) { ++ ++ int_cfg = (int *)kmalloc(sizeof(int), GFP_KERNEL); ++ if (int_cfg == NULL) { ++ DBG_DEBUG(DBG_ERROR, "line%d: kmalloc int fail\n", line_num); ++ return -1; ++ } ++ ++ *int_cfg = value; ++ rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, int_cfg); ++ if (rv == 0) { ++ DBG_DEBUG(DBG_VERBOSE, "line%d: add int item[%d] success, key=0x%08x\n", line_num, value, key); ++ } else { ++ kfree(int_cfg); ++ int_cfg = NULL; ++ DBG_DEBUG(DBG_ERROR, "line%d: add int item[%d] fail, key=0x%08x rv=%d \n", line_num, value, key, rv); ++ return -1; ++ } ++ } else { ++ ++ DBG_DEBUG(DBG_WARN, "line%d: replace int item[%d->%d], key=0x%08x\n", line_num, *int_cfg, value, key); ++ *int_cfg = value; ++ } ++ ++ return 0; ++} ++ ++static int dfd_ko_cfg_analyse_int_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, char *arg_value, ++ char *cfg_pre, index_range_t *index_range, int line_num) ++{ ++ int rv; ++ int index1 = 0, index2 = 0; ++ int value, key; ++ char *arg_name_tmp; ++ ++ if (index_range->index1_max != INDEX_NOT_EXIST) { ++ arg_name_tmp = arg_name + strlen(cfg_pre); ++ rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ } ++ ++ rv = dfd_ko_cfg_get_value_from_char(arg_value, &value, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ ++ key = DFD_CFG_KEY(cfg_item_id, index1, index2); ++ rv = dfd_ko_cfg_add_int_item(key, value, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int dfd_ko_cfg_add_str_item(int key, char *str, int line_num) ++{ ++ int rv; ++ char *str_cfg; ++ ++ str_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); ++ if (str_cfg == NULL) { ++ ++ str_cfg = (char *)kmalloc(DFD_CFG_STR_MAX_LEN, GFP_KERNEL); ++ if (str_cfg == NULL) { ++ DBG_DEBUG(DBG_ERROR, "line%d: kmalloc str[%lu] fail\n", line_num, strlen(str)); ++ return -1; ++ } ++ mem_clear(str_cfg, DFD_CFG_STR_MAX_LEN); ++ strncpy(str_cfg, str, DFD_CFG_STR_MAX_LEN - 1); ++ ++ rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, str_cfg); ++ if (rv == 0) { ++ DBG_DEBUG(DBG_VERBOSE, "line%d: add string item[%s] success, key=0x%08x\n", line_num, str_cfg, key); ++ } else { ++ kfree(str_cfg); ++ str_cfg = NULL; ++ DBG_DEBUG(DBG_ERROR, "line%d: add string item[%s] fail, key=0x%08x rv=%d \n", line_num, str_cfg, key, rv); ++ return -1; ++ } ++ } else { ++ DBG_DEBUG(DBG_WARN, "line%d: replace string item[%s->%s], key=0x%08x\n", line_num, str_cfg, str, key); ++ mem_clear(str_cfg, DFD_CFG_STR_MAX_LEN); ++ strncpy(str_cfg, str, DFD_CFG_STR_MAX_LEN - 1); ++ } ++ ++ return 0; ++} ++ ++static int dfd_ko_cfg_analyse_str_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, char *arg_value, ++ char *cfg_pre, index_range_t *index_range, int line_num) ++{ ++ int rv; ++ int index1 = 0, index2 = 0; ++ int btree_key; ++ char *arg_name_tmp; ++ ++ if (index_range->index1_max != INDEX_NOT_EXIST) { ++ arg_name_tmp = arg_name + strlen(cfg_pre); ++ rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ } ++ ++ if (strlen(arg_value) >= DFD_CFG_STR_MAX_LEN) { ++ DBG_DEBUG(DBG_ERROR, "line%d: string item[%s] is too long \n", line_num, arg_value); ++ return -1; ++ } ++ ++ btree_key = DFD_CFG_KEY(cfg_item_id, index1, index2); ++ rv = dfd_ko_cfg_add_str_item(btree_key, arg_value, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int dfd_ko_cfg_get_i2c_dev_member(char *member_str, dfd_i2c_dev_mem_t *member, int line_num) ++{ ++ dfd_i2c_dev_mem_t mem_index; ++ ++ for (mem_index = DFD_I2C_DEV_MEM_BUS; mem_index < DFD_I2C_DEV_MEM_END; mem_index++) { ++ if (memcmp(member_str, g_dfd_i2c_dev_mem_str[mem_index], ++ strlen(g_dfd_i2c_dev_mem_str[mem_index])) == 0) { ++ *member = mem_index; ++ return 0; ++ } ++ } ++ ++ DBG_DEBUG(DBG_ERROR, "line%d: i2c dev member[%s] invalid\n", line_num, member_str); ++ return -1; ++} ++ ++static void dfd_ko_cfg_set_i2c_dev_mem_value(dfd_i2c_dev_t *i2c_dev, dfd_i2c_dev_mem_t member, ++ int value) ++{ ++ switch (member) { ++ case DFD_I2C_DEV_MEM_BUS: ++ i2c_dev->bus = value; ++ break; ++ case DFD_I2C_DEV_MEM_ADDR: ++ i2c_dev->addr = value; ++ break; ++ default: ++ break; ++ } ++} ++ ++static int dfd_ko_cfg_add_i2c_dev_item(int key, dfd_i2c_dev_mem_t member, int value, int line_num) ++{ ++ int rv; ++ dfd_i2c_dev_t *i2c_dev_cfg; ++ ++ i2c_dev_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); ++ if (i2c_dev_cfg == NULL) { ++ ++ i2c_dev_cfg = (dfd_i2c_dev_t *)kmalloc(sizeof(dfd_i2c_dev_t), GFP_KERNEL); ++ if (i2c_dev_cfg == NULL) { ++ DBG_DEBUG(DBG_ERROR, "line%d: kmalloc i2c_dev fail\n", line_num); ++ return -1; ++ } ++ mem_clear(i2c_dev_cfg, sizeof(dfd_i2c_dev_t)); ++ ++ dfd_ko_cfg_set_i2c_dev_mem_value(i2c_dev_cfg, member, value); ++ rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, i2c_dev_cfg); ++ if (rv == 0) { ++ DBG_DEBUG(DBG_VERBOSE, "line%d: add i2c_dev item[%s=%d] success, key=0x%08x\n", line_num, ++ g_dfd_i2c_dev_mem_str[member], value, key); ++ } else { ++ kfree(i2c_dev_cfg); ++ i2c_dev_cfg = NULL; ++ DBG_DEBUG(DBG_ERROR, "line%d: add i2c_dev item[%s=%d] fail, key=0x%08x rv=%d\n", line_num, ++ g_dfd_i2c_dev_mem_str[member], value, key, rv); ++ return -1; ++ } ++ } else { ++ ++ DBG_DEBUG(DBG_VERBOSE, "line%d: replace i2c_dev item[%s=%d], key=0x%08x\n", line_num, ++ g_dfd_i2c_dev_mem_str[member], value, key); ++ dfd_ko_cfg_set_i2c_dev_mem_value(i2c_dev_cfg, member, value); ++ } ++ ++ return 0; ++} ++ ++static int dfd_ko_cfg_analyse_i2c_dev_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, ++ char *arg_value, char *cfg_pre, index_range_t *index_range, int line_num) ++{ ++ int rv; ++ int index1 = 0, index2 = 0; ++ int value, key; ++ char *arg_name_tmp; ++ dfd_i2c_dev_mem_t member; ++ ++ arg_name_tmp = arg_name + strlen(cfg_pre); ++ rv = dfd_ko_cfg_get_i2c_dev_member(arg_name_tmp, &member, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ ++ if (index_range->index1_max != INDEX_NOT_EXIST) { ++ arg_name_tmp += strlen(g_dfd_i2c_dev_mem_str[member]); ++ rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ } ++ ++ rv = dfd_ko_cfg_get_value_from_char(arg_value, &value, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ ++ key = DFD_CFG_KEY(cfg_item_id, index1, index2); ++ rv = dfd_ko_cfg_add_i2c_dev_item(key, member, value, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int dfd_ko_cfg_get_enum_value_by_str(char *enum_val_str[], int enum_val_end, char *buf) ++{ ++ int i; ++ int enum_val; ++ ++ enum_val = DFD_CFG_INVALID_VALUE; ++ for (i = 0; i < enum_val_end; i++) { ++ if (memcmp(buf, enum_val_str[i], strlen(enum_val_str[i])) == 0) { ++ enum_val = i; ++ break; ++ } ++ } ++ ++ return enum_val; ++} ++ ++static int dfd_ko_cfg_get_info_ctrl_member(char *member_str, info_ctrl_mem_t *member, int line_num) ++{ ++ info_ctrl_mem_t mem_index; ++ ++ for (mem_index = INFO_CTRL_MEM_MODE; mem_index < INFO_CTRL_MEM_END; mem_index++) { ++ if (memcmp(member_str, g_info_ctrl_mem_str[mem_index], ++ strlen(g_info_ctrl_mem_str[mem_index])) == 0) { ++ *member = mem_index; ++ return 0; ++ } ++ } ++ ++ DBG_DEBUG(DBG_ERROR, "line%d: info ctrl member[%s] invalid\n", line_num, member_str); ++ return -1; ++} ++ ++static void dfd_ko_cfg_set_info_ctrl_mem_value(info_ctrl_t *info_ctrl, info_ctrl_mem_t member, ++ char *buf_val, int line_num) ++{ ++ switch (member) { ++ case INFO_CTRL_MEM_MODE: ++ info_ctrl->mode = dfd_ko_cfg_get_enum_value_by_str(g_info_ctrl_mode_str, INFO_CTRL_MODE_END, buf_val);; ++ break; ++ case INFO_CTRL_MEM_INT_CONS: ++ dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_cons), line_num); ++ break; ++ case INFO_CTRL_MEM_SRC: ++ info_ctrl->src = dfd_ko_cfg_get_enum_value_by_str(g_info_src_str, INFO_SRC_END, buf_val); ++ break; ++ case INFO_CTRL_MEM_FRMT: ++ info_ctrl->frmt = dfd_ko_cfg_get_enum_value_by_str(g_info_frmt_str, INFO_FRMT_END, buf_val); ++ break; ++ case INFO_CTRL_MEM_POLA: ++ info_ctrl->pola = dfd_ko_cfg_get_enum_value_by_str(g_info_pola_str, INFO_POLA_END, buf_val); ++ break; ++ case INFO_CTRL_MEM_FPATH: ++ mem_clear(info_ctrl->fpath, sizeof(info_ctrl->fpath)); ++ strncpy(info_ctrl->fpath, buf_val, sizeof(info_ctrl->fpath) - 1); ++ break; ++ case INFO_CTRL_MEM_ADDR: ++ dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->addr), line_num); ++ break; ++ case INFO_CTRL_MEM_LEN: ++ dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->len), line_num); ++ break; ++ case INFO_CTRL_MEM_BIT_OFFSET: ++ dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->bit_offset), line_num); ++ break; ++ case INFO_CTRL_MEM_STR_CONS: ++ mem_clear(info_ctrl->str_cons, sizeof(info_ctrl->str_cons)); ++ strncpy(info_ctrl->str_cons, buf_val, sizeof(info_ctrl->str_cons) - 1); ++ break; ++ case INFO_CTRL_MEM_INT_EXTRA1: ++ dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_extra1), line_num); ++ break; ++ case INFO_CTRL_MEM_INT_EXTRA2: ++ dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_extra2), line_num); ++ break; ++ case INFO_CTRL_MEM_INT_EXTRA3: ++ dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_extra3), line_num); ++ break; ++ default: ++ break; ++ } ++} ++ ++static int dfd_ko_cfg_add_info_ctrl_item(int key, info_ctrl_mem_t member, char *buf_val, ++ int line_num) ++{ ++ int rv; ++ info_ctrl_t *info_ctrl_cfg; ++ ++ info_ctrl_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); ++ if (info_ctrl_cfg == NULL) { ++ ++ info_ctrl_cfg = (info_ctrl_t *)kmalloc(sizeof(info_ctrl_t), GFP_KERNEL); ++ if (info_ctrl_cfg == NULL) { ++ DBG_DEBUG(DBG_ERROR, "line%d: kmalloc info_ctrl fail\n", line_num); ++ return -1; ++ } ++ mem_clear(info_ctrl_cfg, sizeof(info_ctrl_t)); ++ ++ dfd_ko_cfg_set_info_ctrl_mem_value(info_ctrl_cfg, member, buf_val, line_num); ++ rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, info_ctrl_cfg); ++ if (rv == 0) { ++ DBG_DEBUG(DBG_VERBOSE, "line%d: add info_ctrl item[%s=%s] success, key=0x%08x\n", line_num, ++ g_info_ctrl_mem_str[member], buf_val, key); ++ } else { ++ kfree(info_ctrl_cfg); ++ info_ctrl_cfg = NULL; ++ DBG_DEBUG(DBG_ERROR, "line%d: add info_ctrl item[%s=%s] fail, key=0x%08x rv=%d\n", line_num, ++ g_info_ctrl_mem_str[member], buf_val, key, rv); ++ return -1; ++ } ++ } else { ++ ++ DBG_DEBUG(DBG_VERBOSE, "line%d: replace info_ctrl item[%s=%s], key=0x%08x\n", line_num, ++ g_info_ctrl_mem_str[member], buf_val, key); ++ dfd_ko_cfg_set_info_ctrl_mem_value(info_ctrl_cfg, member, buf_val, line_num); ++ } ++ ++ return 0; ++} ++ ++static int dfd_ko_cfg_analyse_info_ctrl_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, ++ char *arg_value, char *cfg_pre, index_range_t *index_range, int line_num) ++{ ++ int rv; ++ int index1 = 0, index2 = 0; ++ int key; ++ char *arg_name_tmp; ++ info_ctrl_mem_t member; ++ ++ arg_name_tmp = arg_name + strlen(cfg_pre); ++ rv = dfd_ko_cfg_get_info_ctrl_member(arg_name_tmp, &member, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ ++ if (index_range->index1_max != INDEX_NOT_EXIST) { ++ arg_name_tmp += strlen(g_info_ctrl_mem_str[member]); ++ rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ } ++ ++ key = DFD_CFG_KEY(cfg_item_id, index1, index2); ++ rv = dfd_ko_cfg_add_info_ctrl_item(key, member, arg_value, line_num); ++ if (rv < 0) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int dfd_ko_cfg_analyse_config(char *arg_name, char*arg_value, int line_num) ++{ ++ int i, rv = 0; ++ int cfg_item_num; ++ ++ cfg_item_num = sizeof(dfd_cfg_item_name) / sizeof(dfd_cfg_item_name[0]); ++ for (i = 0; i < cfg_item_num; i++) { ++ if (memcmp(arg_name, dfd_cfg_item_name[i], strlen(dfd_cfg_item_name[i])) == 0){ ++ if (DFD_CFG_ITEM_IS_INT(i)) { ++ rv = dfd_ko_cfg_analyse_int_item(i, arg_name, arg_value, dfd_cfg_item_name[i], ++ &(dfd_cfg_item_index_range[i]), line_num); ++ } else if (DFD_CFG_ITEM_IS_STRING(i)) { ++ rv = dfd_ko_cfg_analyse_str_item(i, arg_name, arg_value, dfd_cfg_item_name[i], ++ &(dfd_cfg_item_index_range[i]), line_num); ++ } else if (DFD_CFG_ITEM_IS_I2C_DEV(i)) { ++ rv = dfd_ko_cfg_analyse_i2c_dev_item(i, arg_name, arg_value, dfd_cfg_item_name[i], ++ &(dfd_cfg_item_index_range[i]), line_num); ++ } else if (DFD_CFG_ITEM_IS_INFO_CTRL(i)) { ++ rv = dfd_ko_cfg_analyse_info_ctrl_item(i, arg_name, arg_value, dfd_cfg_item_name[i], ++ &(dfd_cfg_item_index_range[i]), line_num); ++ } else { ++ rv = -1; ++ } ++ break; ++ } ++ } ++ ++ return rv; ++} ++ ++static int dfd_ko_cfg_cut_config_line(char *config_line, char *arg_name, char *arg_value) ++{ ++ int i, j = 0, k = 0; ++ int len, name_value_flag = 0; ++ ++ len = strlen(config_line); ++ for (i = 0; i < len; i++) { ++ if (config_line[i] == '=') { ++ name_value_flag = 1; ++ continue; ++ } ++ ++ if (name_value_flag == 0) { ++ arg_name[j++] = config_line[i]; ++ } else { ++ arg_value[k++] = config_line[i]; ++ } ++ } ++ ++ if (name_value_flag == 0) { ++ return -1; ++ } else { ++ return 0; ++ } ++} ++ ++static int dfd_ko_cfg_analyse_config_line(char *config_line, int line_num) ++{ ++ int rv; ++ char arg_name[DFD_CFG_NAME_MAX_LEN] = {0}; ++ char arg_value[DFD_CFG_VALUE_MAX_LEN] = {0}; ++ ++ dfd_ko_cfg_del_space_lf_cr(config_line); ++ ++ if (strlen(config_line) == 0) { ++ DBG_DEBUG(DBG_VERBOSE, "line%d: space line\n", line_num); ++ return 0; ++ } ++ ++ if (config_line[0] == '#') { ++ DBG_DEBUG(DBG_VERBOSE, "line%d: comment line[%s]\n", line_num, config_line); ++ return 0; ++ } ++ ++ rv = dfd_ko_cfg_cut_config_line(config_line, arg_name, arg_value); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_VERBOSE, "line%d: [%s]no '=' between name and value\n", line_num, config_line); ++ return -1; ++ } ++ ++ DBG_DEBUG(DBG_VERBOSE, "line%d: config_line[%s] name[%s] value[%s]\n", line_num, config_line, arg_name, arg_value); ++ return dfd_ko_cfg_analyse_config(arg_name, arg_value, line_num); ++} ++ ++static int dfd_ko_cfg_analyse_config_file(char *fpath) ++{ ++ int rv; ++ int line_num = 1; ++ kfile_ctrl_t kfile_ctrl; ++ char config_line[DFD_CFG_CMDLINE_MAX_LEN] = {0}; ++ ++ rv = kfile_open(fpath, &kfile_ctrl); ++ if (rv != KFILE_RV_OK) { ++ DBG_DEBUG(DBG_ERROR, "open config file[%s] fail, rv=%d\n", fpath, rv); ++ return -1; ++ } ++ ++ while(kfile_gets(config_line, sizeof(config_line), &kfile_ctrl) > 0){ ++ rv = dfd_ko_cfg_analyse_config_line(config_line, line_num++); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "!!!!file[%s] config line[%d %s] analyse fail\n", fpath, line_num - 1, ++ config_line); ++ break; ++ } ++ ++ (void)mem_clear(config_line, sizeof(config_line)); ++ ++ } ++ kfile_close(&kfile_ctrl); ++ ++ return rv; ++} ++ ++void *dfd_ko_cfg_get_item(int key) ++{ ++ return lnode_find_node(&dfd_ko_cfg_list_root, key); ++} ++ ++static void dfd_ko_cfg_print_item(int key, const void *cfg) ++{ ++ int item_id; ++ dfd_i2c_dev_t *i2c_dev; ++ info_ctrl_t *info_ctrl; ++ ++ if (cfg == NULL) { ++ DBG_DEBUG(DBG_ERROR, "input arguments error\n"); ++ return; ++ } ++ printk(KERN_INFO "**************************\n"); ++ printk(KERN_INFO "key=0x%08x\n", key); ++ ++ item_id = DFD_CFG_ITEM_ID(key); ++ if (DFD_CFG_ITEM_IS_INT(item_id)) { ++ printk(KERN_INFO "int=%d\n", *((int *)cfg)); ++ } else if (DFD_CFG_ITEM_IS_I2C_DEV(item_id)) { ++ i2c_dev = (dfd_i2c_dev_t *)cfg; ++ printk(KERN_INFO ".bus=0x%02x\n", i2c_dev->bus); ++ printk(KERN_INFO ".addr=0x%02x\n", i2c_dev->addr); ++ } else if (DFD_CFG_ITEM_IS_INFO_CTRL(item_id)) { ++ info_ctrl = (info_ctrl_t *)cfg; ++ printk(KERN_INFO ".mode=%s\n", g_info_ctrl_mode_str[info_ctrl->mode]); ++ printk(KERN_INFO ".int_cons=%d\n", info_ctrl->int_cons); ++ printk(KERN_INFO ".src=%s\n", g_info_src_str[info_ctrl->src]); ++ printk(KERN_INFO ".frmt=%s\n", g_info_frmt_str[info_ctrl->frmt]); ++ printk(KERN_INFO ".pola=%s\n", g_info_pola_str[info_ctrl->pola]); ++ printk(KERN_INFO ".fpath=%s\n", info_ctrl->fpath); ++ printk(KERN_INFO ".addr=0x%02x\n", info_ctrl->addr); ++ printk(KERN_INFO ".len=%d\n", info_ctrl->len); ++ printk(KERN_INFO ".bit_offset=%d\n", info_ctrl->bit_offset); ++ } else { ++ printk(KERN_INFO "item[%d] error!\n", item_id); ++ } ++} ++ ++void dfd_ko_cfg_show_item(int key) ++{ ++ void *cfg; ++ ++ cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); ++ if (cfg == 0) { ++ printk(KERN_INFO "item[0x%08x] not exist\n", key); ++ return; ++ } ++ ++ dfd_ko_cfg_print_item(key, cfg); ++} ++ ++static int dfd_get_my_dev_type_by_file(void) ++{ ++ struct file *fp; ++ loff_t pos; ++ int card_type; ++ char buf[DFD_PID_BUF_LEN]; ++ int ret; ++ ++ fp= filp_open(DFD_PUB_CARDTYPE_FILE, O_RDONLY, 0); ++ if (IS_ERR(fp)) { ++ DBG_DEBUG(DBG_VERBOSE, "open file fail!\n"); ++ return -1; ++ } ++ mem_clear(buf, DFD_PID_BUF_LEN); ++ pos = 0; ++ ret = kernel_read(fp, buf, DFD_PRODUCT_ID_LENGTH + 1, &pos); ++ if (ret < 0) { ++ DBG_DEBUG(DBG_VERBOSE, "kernel_read failed, path=%s, addr=0, size=%d, ret=%d\n", ++ DFD_PUB_CARDTYPE_FILE, DFD_PRODUCT_ID_LENGTH + 1, ret); ++ filp_close(fp, NULL); ++ return -1; ++ } ++ ++ card_type = simple_strtoul(buf, NULL, 10); ++ DBG_DEBUG(DBG_VERBOSE, "card_type 0x%x.\n", card_type); ++ ++ filp_close(fp, NULL); ++ return card_type; ++} ++ ++static int drv_get_my_dev_type(void) ++{ ++ static int type = -1; ++ ++ if (type > 0) { ++ return type; ++ } ++ type = dfd_get_my_dev_type_by_file(); ++ DBG_DEBUG(DBG_VERBOSE, "ko board type %d\n", type); ++ return type; ++} ++ ++static int dfd_ko_cfg_init(void) ++{ ++ int rv; ++ int card_type; ++ char file_name[32] = {0}; ++ char fpath[128] = {0}; ++ kfile_ctrl_t kfile_ctrl; ++ ++ rv = lnode_init_root(&dfd_ko_cfg_list_root); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "init list root fail, rv=%d\n", rv); ++ return -1; ++ } ++ ++ card_type = drv_get_my_dev_type(); ++ if (card_type > 0) { ++ snprintf(fpath, sizeof(fpath), "%s0x%x", DFD_KO_CFG_FILE_DIR, card_type); ++ rv = kfile_open(fpath, &kfile_ctrl); ++ if (rv != KFILE_RV_OK) { ++ DBG_DEBUG(DBG_VERBOSE, "open config file[%s] fail, rv=%d, maybe not exist\n", ++ fpath, rv); ++ ++ rv = kfile_open(DFD_KO_CFG_FILE_NAME, &kfile_ctrl); ++ if (rv != KFILE_RV_OK) { ++ DBG_DEBUG(DBG_ERROR, "open config file[%s] fail, rv=%d\n", DFD_KO_CFG_FILE_NAME, ++ rv); ++ return -1; ++ } ++ DBG_DEBUG(DBG_ERROR, "get config file from: %s, success.\n", DFD_KO_CFG_FILE_NAME); ++ } else { ++ DBG_DEBUG(DBG_VERBOSE, "get config file from: %s, success.\n", fpath); ++ } ++ } else { ++ DBG_DEBUG(DBG_VERBOSE, "get board id failed, try to get config file from: %s\n", ++ DFD_KO_CFG_FILE_NAME); ++ ++ rv = kfile_open(DFD_KO_CFG_FILE_NAME, &kfile_ctrl); ++ if (rv != KFILE_RV_OK) { ++ DBG_DEBUG(DBG_ERROR, "open config file[%s] fail, rv=%d\n", DFD_KO_CFG_FILE_NAME, rv); ++ return -1; ++ } ++ DBG_DEBUG(DBG_ERROR, "get config file from: %s, success.\n", DFD_KO_CFG_FILE_NAME); ++ } ++ ++ while (kfile_gets(file_name, sizeof(file_name), &kfile_ctrl) > 0) { ++ ++ dfd_ko_cfg_del_space_lf_cr(file_name); ++ mem_clear(fpath, sizeof(fpath)); ++ snprintf(fpath, sizeof(fpath), "%s%s.cfg", DFD_KO_CFG_FILE_DIR, file_name); ++ DBG_DEBUG(DBG_VERBOSE, ">>>>start parsing config file[%s]\n", fpath); ++ ++ rv = dfd_ko_cfg_analyse_config_file(fpath); ++ if (rv < 0) { ++ break; ++ } ++ } ++ kfile_close(&kfile_ctrl); ++ ++ return 0; ++} ++ ++int32_t dfd_dev_cfg_init(void) ++{ ++ return dfd_ko_cfg_init(); ++} ++ ++void dfd_dev_cfg_exit(void) ++{ ++ lnode_free_list(&dfd_ko_cfg_list_root); ++ return; ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c +new file mode 100644 +index 000000000..1d5ca7072 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c +@@ -0,0 +1,351 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../include/dfd_module.h" ++#include "../include/dfd_cfg_file.h" ++#include "../include/dfd_cfg.h" ++#include "../include/dfd_cfg_adapter.h" ++#include "../../dev_sysfs/include/sysfs_common.h" ++ ++char *g_dfd_i2c_dev_mem_str[DFD_I2C_DEV_MEM_END] = { ++ ".bus", ++ ".addr", ++}; ++ ++static dfd_i2c_dev_t* dfd_ko_get_cpld_i2c_dev(int sub_slot, int cpld_id) ++{ ++ int key; ++ dfd_i2c_dev_t *i2c_dev; ++ ++ key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_I2C_DEV, sub_slot, cpld_id); ++ i2c_dev = dfd_ko_cfg_get_item(key); ++ if (i2c_dev == NULL) { ++ DBG_DEBUG(DBG_ERROR, "get cpld[%d] i2c dev config fail, key=0x%08x\n", cpld_id, key); ++ return NULL; ++ } ++ ++ return i2c_dev; ++} ++ ++static int32_t dfd_ko_i2c_smbus_transfer(int read_write, int bus, int addr, int offset, uint8_t *buf, uint32_t size) ++{ ++ int rv; ++ struct i2c_adapter *i2c_adap; ++ union i2c_smbus_data data; ++ ++ i2c_adap = i2c_get_adapter(bus); ++ if (i2c_adap == NULL) { ++ DBG_DEBUG(DBG_ERROR, "get i2c bus[%d] adapter fail\n", bus); ++ return -DFD_RV_DEV_FAIL; ++ } ++ ++ if (read_write == I2C_SMBUS_WRITE) { ++ data.byte = *buf; ++ } else { ++ data.byte = 0; ++ } ++ rv = i2c_smbus_xfer(i2c_adap, addr, 0, read_write, offset, I2C_SMBUS_BYTE_DATA, &data); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "i2c dev[bus=%d addr=0x%x offset=0x%x size=%d rw=%d] transfer fail, rv=%d\n", ++ bus, addr, offset, size, read_write, rv); ++ rv = -DFD_RV_DEV_FAIL; ++ } else { ++ DBG_DEBUG(DBG_VERBOSE, "i2c dev[bus=%d addr=0x%x offset=0x%x size=%d rw=%d] transfer success\n", ++ bus, addr, offset, size, read_write); ++ rv = DFD_RV_OK; ++ } ++ ++ if (read_write == I2C_SMBUS_READ) { ++ if (rv == DFD_RV_OK) { ++ *buf = data.byte; ++ } else { ++ *buf = 0; ++ } ++ } ++ ++ i2c_put_adapter(i2c_adap); ++ return rv; ++} ++ ++static int32_t dfd_ko_i2c_read_data(int bus, int addr, int offset, uint8_t *buf, uint32_t size) ++{ ++ int i, rv; ++ for (i = 0; i < DFD_KO_CPLD_I2C_RETRY_TIMES; i++) { ++ rv = dfd_ko_i2c_smbus_transfer(I2C_SMBUS_READ, bus, addr, offset, buf, size); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "[%d]cpld read[offset=0x%x] fail, rv %d\n", i, addr, rv); ++ msleep(DFD_KO_CPLD_I2C_RETRY_SLEEP); ++ } else { ++ DBG_DEBUG(DBG_VERBOSE, "[%d]cpld read[offset=0x%x] success, value=0x%x\n", ++ i, addr, *buf); ++ break; ++ } ++ } ++ return rv; ++} ++ ++static int32_t dfd_ko_i2c_write_data(int bus, int addr, int offset, uint8_t data, uint32_t size) ++{ ++ int i, rv; ++ for (i = 0; i < DFD_KO_CPLD_I2C_RETRY_TIMES; i++) { ++ rv = dfd_ko_i2c_smbus_transfer(I2C_SMBUS_WRITE, bus, addr, offset, &data, size); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "[%d]cpld write[offset=0x%x] fail, rv=%d\n", i, addr, rv); ++ msleep(DFD_KO_CPLD_I2C_RETRY_SLEEP); ++ } else { ++ DBG_DEBUG(DBG_VERBOSE, "[%d]cpld write[offset=0x%x, data=%d] success\n", i, addr, data); ++ break; ++ } ++ } ++ ++ return rv; ++} ++ ++static int32_t dfd_ko_cpld_i2c_read(int32_t addr, uint8_t *buf) ++{ ++ int rv; ++ int sub_slot, cpld_id, cpld_addr; ++ dfd_i2c_dev_t *i2c_dev; ++ ++ if (buf == NULL) { ++ DBG_DEBUG(DBG_ERROR, "input arguments error\n"); ++ return -DFD_RV_INDEX_INVALID; ++ } ++ ++ sub_slot = DFD_KO_CPLD_GET_SLOT(addr); ++ cpld_id = DFD_KO_CPLD_GET_ID(addr); ++ cpld_addr = DFD_KO_CPLD_GET_INDEX(addr); ++ ++ i2c_dev = dfd_ko_get_cpld_i2c_dev(sub_slot, cpld_id); ++ if (i2c_dev == NULL) { ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ rv = dfd_ko_i2c_read_data(i2c_dev->bus, i2c_dev->addr, cpld_addr, buf, sizeof(uint8_t)); ++ ++ return rv; ++} ++ ++static int32_t dfd_ko_cpld_i2c_write(int32_t addr, uint8_t data) ++{ ++ int rv; ++ int sub_slot, cpld_id, cpld_addr; ++ dfd_i2c_dev_t *i2c_dev; ++ ++ sub_slot = DFD_KO_CPLD_GET_SLOT(addr); ++ cpld_id = DFD_KO_CPLD_GET_ID(addr); ++ cpld_addr = DFD_KO_CPLD_GET_INDEX(addr); ++ ++ i2c_dev = dfd_ko_get_cpld_i2c_dev(sub_slot, cpld_id); ++ if (i2c_dev == NULL) { ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ ++ rv = dfd_ko_i2c_write_data(i2c_dev->bus, i2c_dev->addr, cpld_addr, data, sizeof(uint8_t)); ++ ++ return rv; ++} ++ ++static int32_t dfd_ko_cpld_io_read(int32_t addr, uint8_t *buf) ++{ ++ int cpld_id, sub_slot, offset; ++ int key; ++ int *tmp; ++ uint16_t io_port; ++ ++ sub_slot = DFD_KO_CPLD_GET_SLOT(addr); ++ cpld_id = DFD_KO_CPLD_GET_ID(addr); ++ offset = DFD_KO_CPLD_GET_INDEX(addr); ++ ++ key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_LPC_DEV, sub_slot, cpld_id); ++ tmp = dfd_ko_cfg_get_item(key); ++ if (tmp == NULL) { ++ DBG_DEBUG(DBG_ERROR,"get cpld io base config fail, key=0x%08x\n", key); ++ return -1; ++ } ++ ++ io_port = (u16)(*tmp) + offset; ++ *buf = inb(io_port); ++ DBG_DEBUG(DBG_VERBOSE, "read cpld io port addr 0x%x, data 0x%x\n", io_port, *buf); ++ ++ return DFD_RV_OK; ++ ++} ++ ++static int32_t dfd_ko_cpld_io_write(int32_t addr, uint8_t data) ++{ ++ int cpld_id, sub_slot, offset; ++ int key; ++ int *tmp; ++ uint16_t io_port; ++ ++ sub_slot = DFD_KO_CPLD_GET_SLOT(addr); ++ cpld_id = DFD_KO_CPLD_GET_ID(addr); ++ offset = DFD_KO_CPLD_GET_INDEX(addr); ++ ++ key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_LPC_DEV, sub_slot, cpld_id); ++ tmp = dfd_ko_cfg_get_item(key); ++ if (tmp == NULL) { ++ DBG_DEBUG(DBG_ERROR, "get cpld io base config fail, key=0x%08x\n", key); ++ return -1; ++ } ++ ++ io_port = (u16)(*tmp) + offset; ++ DBG_DEBUG(DBG_VERBOSE, "write cpld io port addr 0x%x, data 0x%x\n", io_port, data); ++ outb(data, (u16)io_port); ++ ++ return DFD_RV_OK; ++} ++ ++static int dfd_cfg_get_cpld_mode(int sub_slot, int cpld_id, int *mode) ++{ ++ int key; ++ char *name; ++ ++ if (mode == NULL) { ++ DBG_DEBUG(DBG_ERROR, "input arguments error\n"); ++ return -DFD_RV_TYPE_ERR; ++ } ++ ++ key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_MODE, sub_slot, cpld_id); ++ name = dfd_ko_cfg_get_item(key); ++ if (name == NULL) { ++ DBG_DEBUG(DBG_ERROR, "get cpld[%d] mode info ctrl fail, key=0x%08x\n", cpld_id, key); ++ return -DFD_RV_NODE_FAIL; ++ } ++ ++ DBG_DEBUG(DBG_VERBOSE, "cpld_id %d mode_name %s.\n", cpld_id, name); ++ if (!strncmp(name, DFD_KO_CPLD_MODE_I2C_STRING, strlen(DFD_KO_CPLD_MODE_I2C_STRING))) { ++ *mode = DFD_CPLD_MODE_I2C; ++ } else if (!strncmp(name, DFD_KO_CPLD_MODE_LPC_STRING, strlen(DFD_KO_CPLD_MODE_LPC_STRING))) { ++ *mode = DFD_CPLD_MODE_LPC; ++ } else { ++ ++ *mode = DFD_CPLD_MODE_I2C; ++ } ++ ++ DBG_DEBUG(DBG_VERBOSE, "cpld_id %d mode %d.\n", cpld_id, *mode); ++ return 0; ++} ++ ++int32_t dfd_ko_cpld_read(int32_t addr, uint8_t *buf) ++{ ++ int ret; ++ int sub_slot, cpld_id; ++ int cpld_mode; ++ ++ sub_slot = DFD_KO_CPLD_GET_SLOT(addr); ++ cpld_id = DFD_KO_CPLD_GET_ID(addr); ++ ++ ret = dfd_cfg_get_cpld_mode(sub_slot, cpld_id, &cpld_mode); ++ if (ret) { ++ DBG_DEBUG(DBG_WARN, "drv_get_cpld_mode sub_slot %d cpldid %d faile, set default i2c mode.\n", sub_slot, cpld_id); ++ cpld_mode = DFD_CPLD_MODE_I2C; ++ } ++ ++ if (cpld_mode == DFD_CPLD_MODE_I2C) { ++ ret = dfd_ko_cpld_i2c_read(addr, buf); ++ } else if (cpld_mode == DFD_CPLD_MODE_LPC) { ++ ret = dfd_ko_cpld_io_read(addr, buf); ++ } else { ++ DBG_DEBUG(DBG_ERROR, "cpld_mode %d invalid.\n", cpld_mode); ++ ret = -DFD_RV_DEV_NOTSUPPORT; ++ } ++ ++ DBG_DEBUG(DBG_VERBOSE, "addr 0x%x val 0x%x ret %d\n", addr, *buf, ret); ++ return ret; ++} ++ ++int32_t dfd_ko_cpld_write(int32_t addr, uint8_t val) ++{ ++ int ret; ++ int sub_slot, cpld_id, cpld_mode; ++ ++ sub_slot = DFD_KO_CPLD_GET_SLOT(addr); ++ cpld_id = DFD_KO_CPLD_GET_ID(addr); ++ ++ ret = dfd_cfg_get_cpld_mode(sub_slot, cpld_id, &cpld_mode); ++ if (ret) { ++ DBG_DEBUG(DBG_ERROR, "drv_get_cpld_mode sub_slot %d cpldid %d faile, set default local_bus mode.\n", sub_slot, cpld_id); ++ cpld_mode = DFD_CPLD_MODE_I2C; ++ } ++ ++ if (cpld_mode == DFD_CPLD_MODE_I2C) { ++ ret = dfd_ko_cpld_i2c_write(addr, val); ++ } else if (cpld_mode == DFD_CPLD_MODE_LPC) { ++ ret = dfd_ko_cpld_io_write(addr, val); ++ } else { ++ DBG_DEBUG(DBG_ERROR, "cpld_mode %d invalid.\n", cpld_mode); ++ ret = -DFD_RV_DEV_NOTSUPPORT; ++ } ++ ++ DBG_DEBUG(DBG_VERBOSE, "addr 0x%x val 0x%x ret %d\n", addr, val, ret); ++ return ret; ++} ++ ++int32_t dfd_ko_i2c_read(int bus, int addr, int offset, uint8_t *buf, uint32_t size) ++{ ++ int i, rv; ++ ++ for (i = 0; i < size; i++) { ++ rv = dfd_ko_i2c_read_data(bus, addr, offset, &buf[i], sizeof(uint8_t)); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "dfd_ko_i2c_read[bus=%d addr=0x%x offset=0x%x]fail, rv=%d\n", ++ bus, addr, offset, rv); ++ return rv; ++ } ++ offset++; ++ } ++ ++ return size; ++} ++ ++int32_t dfd_ko_i2c_write(int bus, int addr, int offset, uint8_t *buf, uint32_t size) ++{ ++ int i, rv; ++ ++ for (i = 0; i < size; i++) { ++ rv = dfd_ko_i2c_write_data(bus, addr, offset, buf[i], sizeof(uint8_t)); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "dfd_ko_i2c_write[bus=%d addr=0x%x offset=0x%x]fail, rv=%d\n", ++ bus, addr, offset, rv); ++ return rv; ++ } ++ offset++; ++ } ++ ++ return size; ++ ++} ++ ++int32_t dfd_ko_read_file(char *fpath, int32_t addr, uint8_t *val, int32_t read_bytes) ++{ ++ int32_t ret; ++ struct file *filp; ++ loff_t pos; ++ ++ if ((fpath == NULL) || (val == NULL) || (addr < 0) || (read_bytes < 0)) { ++ DBG_DEBUG(DBG_ERROR, "input arguments error, addr=%d read_bytes=%d\n", addr, read_bytes); ++ return -DFD_RV_INDEX_INVALID; ++ } ++ ++ filp = filp_open(fpath, O_RDONLY, 0); ++ if (IS_ERR(filp)){ ++ DBG_DEBUG(DBG_ERROR, "open file[%s] fail\n", fpath); ++ return -DFD_RV_DEV_FAIL; ++ } ++ ++ pos = addr; ++ ret = kernel_read(filp, val, read_bytes, &pos); ++ if (ret < 0) { ++ DBG_DEBUG(DBG_ERROR, "kernel_read failed, path=%s, addr=%d, size=%d, ret=%d\n", fpath, addr, read_bytes, ret); ++ ret = -DFD_RV_DEV_FAIL; ++ } ++ ++ filp_close(filp, NULL); ++ return ret; ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c +new file mode 100644 +index 000000000..8d77759ba +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c +@@ -0,0 +1,236 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../include/dfd_cfg_file.h" ++#include "../include/dfd_module.h" ++#include "../../dev_sysfs/include/sysfs_common.h" ++ ++struct getdents_callback { ++ struct dir_context ctx; ++ const char *obj_name; ++ char *match_name; ++ int dir_len; ++ int found; ++}; ++ ++int kfile_open(char *fname, kfile_ctrl_t *kfile_ctrl) ++{ ++ int ret; ++ struct file *filp; ++ loff_t pos; ++ ++ if ((fname == NULL) || (kfile_ctrl == NULL)) { ++ return KFILE_RV_INPUT_ERR; ++ } ++ ++ filp = filp_open(fname, O_RDONLY, 0); ++ if (IS_ERR(filp)){ ++ return KFILE_RV_OPEN_FAIL; ++ } ++ ++ kfile_ctrl->size = filp->f_inode->i_size; ++ ++ kfile_ctrl->buf = kmalloc(kfile_ctrl->size, GFP_KERNEL); ++ if (kfile_ctrl->buf == NULL) { ++ ret = KFILE_RV_MALLOC_FAIL; ++ goto close_fp; ++ } ++ mem_clear(kfile_ctrl->buf, kfile_ctrl->size); ++ ++ pos = 0; ++ ret = kernel_read(filp, kfile_ctrl->buf, kfile_ctrl->size, &pos); ++ if (ret < 0) { ++ ret = KFILE_RV_RD_FAIL; ++ goto free_buf; ++ } ++ ++ kfile_ctrl->pos = 0; ++ ++ ret = KFILE_RV_OK; ++ goto close_fp; ++ ++free_buf: ++ kfree(kfile_ctrl->buf); ++ kfile_ctrl->buf = NULL; ++ ++close_fp: ++ filp_close(filp, NULL); ++ return ret; ++} ++ ++void kfile_close(kfile_ctrl_t *kfile_ctrl) ++{ ++ if (kfile_ctrl == NULL) { ++ return; ++ } ++ ++ kfile_ctrl->size = 0; ++ kfile_ctrl->pos = 0; ++ if (kfile_ctrl->buf) { ++ kfree(kfile_ctrl->buf); ++ kfile_ctrl->buf = NULL; ++ } ++} ++ ++int kfile_gets(char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl) ++{ ++ int i; ++ int has_cr = 0; ++ ++ if ((buf == NULL) || (buf_size <= 0) || (kfile_ctrl == NULL) || (kfile_ctrl->buf == NULL) ++ || (kfile_ctrl->size <= 0)) { ++ return KFILE_RV_INPUT_ERR; ++ } ++ ++ mem_clear(buf, buf_size); ++ for (i = 0; i < buf_size; i++) { ++ ++ if (kfile_ctrl->pos >= kfile_ctrl->size) { ++ break; ++ } ++ ++ if (has_cr) { ++ break; ++ } ++ ++ if (IS_CR(kfile_ctrl->buf[kfile_ctrl->pos])) { ++ has_cr = 1; ++ } ++ ++ buf[i] = kfile_ctrl->buf[kfile_ctrl->pos]; ++ kfile_ctrl->pos++; ++ } ++ ++ return i; ++} ++ ++int kfile_read(int32_t addr, char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl) ++{ ++ int i; ++ ++ if ((buf == NULL) || (buf_size <= 0) || (kfile_ctrl == NULL) || (kfile_ctrl->buf == NULL) ++ || (kfile_ctrl->size <= 0)) { ++ return KFILE_RV_INPUT_ERR; ++ } ++ ++ if ((addr < 0) || (addr >= kfile_ctrl->size)) { ++ return KFILE_RV_ADDR_ERR; ++ } ++ ++ mem_clear(buf, buf_size); ++ ++ kfile_ctrl->pos = addr; ++ for (i = 0; i < buf_size; i++) { ++ ++ if (kfile_ctrl->pos >= kfile_ctrl->size) { ++ break; ++ } ++ ++ buf[i] = kfile_ctrl->buf[kfile_ctrl->pos]; ++ kfile_ctrl->pos++; ++ } ++ ++ return i; ++} ++ ++static int kfile_filldir_one(struct dir_context *ctx, const char * name, int len, ++ loff_t pos, u64 ino, unsigned int d_type) ++{ ++ struct getdents_callback *buf ; ++ int result; ++ buf = container_of(ctx, struct getdents_callback, ctx); ++ result = 0; ++ if (strncmp(buf->obj_name, name, strlen(buf->obj_name)) == 0) { ++ if (buf->dir_len < len) { ++ DBG_DEBUG(DBG_ERROR, "match ok. dir name:%s, but buf_len %d small than dir len %d.\n", ++ name, buf->dir_len, len); ++ buf->found = 0; ++ return -1; ++ } ++ mem_clear(buf->match_name, buf->dir_len); ++ memcpy(buf->match_name, name, len); ++ buf->found = 1; ++ result = -1; ++ } ++ return result; ++} ++ ++int kfile_iterate_dir(const char *dir_path, const char *obj_name, char *match_name, int len) ++{ ++ int ret; ++ struct file *dir; ++ struct getdents_callback buffer = { ++ .ctx.actor = kfile_filldir_one, ++ }; ++ ++ if(!dir_path || !obj_name || !match_name) { ++ DBG_DEBUG(DBG_ERROR, "params error. \n"); ++ return KFILE_RV_INPUT_ERR; ++ } ++ buffer.obj_name = obj_name; ++ buffer.match_name = match_name; ++ buffer.dir_len = len; ++ buffer.found = 0; ++ ++ dir = filp_open(dir_path, O_RDONLY, 0); ++ if (IS_ERR(dir)) { ++ DBG_DEBUG(DBG_ERROR, "filp_open error, dir path:%s\n", dir_path); ++ return KFILE_RV_OPEN_FAIL; ++ } ++ ret = iterate_dir(dir, &buffer.ctx); ++ if (buffer.found) { ++ DBG_DEBUG(DBG_VERBOSE, "match ok, dir name:%s\n", match_name); ++ filp_close(dir, NULL); ++ return DFD_RV_OK; ++ } ++ filp_close(dir, NULL); ++ return -DFD_RV_NODE_FAIL; ++} ++ ++#if 0 ++ ++int kfile_write(char *fpath, int32_t addr, char *buf, int buf_size) ++{ ++ int ret = KFILE_RV_OK; ++ struct file *filp; ++ mm_segment_t old_fs; ++ int wlen; ++ ++ if ((fpath == NULL) || (buf == NULL) || (buf_size <= 0)) { ++ return KFILE_RV_INPUT_ERR; ++ } ++ ++ if (addr < 0) { ++ return KFILE_RV_ADDR_ERR; ++ } ++ ++ filp = filp_open(fpath, O_RDWR, 0); ++ if (IS_ERR(filp)){ ++ return KFILE_RV_OPEN_FAIL; ++ } ++ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ filp->f_op->llseek(filp,0,0); ++ filp->f_pos = addr; ++ ++ wlen = filp->f_op->write(filp, buf, buf_size, &(filp->f_pos)); ++ if (wlen < 0) { ++ ret = KFILE_RV_WR_FAIL; ++ } ++ ++ filp->f_op->llseek(filp,0,0); ++ set_fs(old_fs); ++ filp_close(filp, NULL); ++ ++ return ret; ++} ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c +new file mode 100644 +index 000000000..f8d64dcac +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c +@@ -0,0 +1,771 @@ ++#include ++#include ++#include ++ ++#include "../include/dfd_module.h" ++#include "../include/dfd_cfg_adapter.h" ++#include "../include/dfd_cfg.h" ++#include "../include/dfd_cfg_info.h" ++#include "../include/dfd_cfg_file.h" ++#include "../../dev_sysfs/include/sysfs_common.h" ++ ++#define DFD_HWMON_NAME "hwmon" ++/* CPLD_VOLATGE_VALUE_MODE1 */ ++#define DFD_GET_CPLD_VOLATGE_CODE_VALUE(value) ((value >> 4)& 0xfff) ++/* ((code_val * 16 * 33 * k) / ((65536 - 5000) * 10)) = ((code_val * 33 * k) / 37835) */ ++#define DFD_GET_CPLD_VOLATGE_REAL_VALUE(code_val, k) ((code_val * 33 * k) / 37835) ++ ++ ++/* CPLD_VOLATGE_VALUE_MODE2 */ ++/* high 8 bit + low 4 bit(bit0-bit3) */ ++#define DFD_GET_CPLD_VOLATGE_CODE_VALUE2(value) (((value & 0xff00) >> 4) + (value & 0xf)) ++#define DFD_GET_CPLD_VOLATGE_REAL_VALUE2(code_val, k) ((code_val * 33 * k) / 40950) ++ ++typedef enum cpld_volatge_value_s { ++ CPLD_VOLATGE_VALUE_MODE1, ++ CPLD_VOLATGE_VALUE_MODE2, ++} cpld_volatge_value_t; ++ ++char *g_info_ctrl_mem_str[INFO_CTRL_MEM_END] = { ++ ".mode", ++ ".int_cons", ++ ".src", ++ ".frmt", ++ ".pola", ++ ".fpath", ++ ".addr", ++ ".len", ++ ".bit_offset", ++ ".str_cons", ++ ".int_extra1", ++ ".int_extra2", ++ ".int_extra3", ++}; ++ ++char *g_info_ctrl_mode_str[INFO_CTRL_MODE_END] = { ++ "none", ++ "config", ++ "constant", ++ "tlv", ++ "str_constant", ++}; ++ ++char *g_info_src_str[INFO_SRC_END] = { ++ "none", ++ "cpld", ++ "fpga", ++ "other_i2c", ++ "file", ++}; ++ ++char *g_info_frmt_str[INFO_FRMT_END] = { ++ "none", ++ "bit", ++ "byte", ++ "num_bytes", ++ "num_str", ++ "num_buf", ++ "buf", ++}; ++ ++char *g_info_pola_str[INFO_POLA_END] = { ++ "none", ++ "positive", ++ "negative", ++}; ++ ++static int dfd_read_info_from_cpld(int32_t addr, int read_bytes, uint8_t *val) ++{ ++ int i, rv; ++ ++ for (i = 0; i < read_bytes; i++) { ++ rv = dfd_ko_cpld_read(addr, &(val[i])); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "read info[addr=0x%x read_bytes=%d] from cpld fail, reading_byte=%d rv=%d\n", ++ addr, read_bytes, i, rv); ++ return rv; ++ } ++ addr++; ++ } ++ ++ return read_bytes; ++} ++ ++static int dfd_write_info_to_cpld(int32_t addr, int write_bytes, uint8_t *val, uint8_t bit_mask) ++{ ++ int rv; ++ uint8_t val_tmp; ++ ++ if (bit_mask != 0xff) { ++ rv = dfd_ko_cpld_read(addr, &val_tmp); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "read original info[addr=0x%x] from cpld fail, rv=%d\n", addr, rv); ++ return -1; ++ } ++ ++ val_tmp = (val_tmp & (~bit_mask)) | (val[0] & bit_mask); ++ } else { ++ val_tmp = val[0]; ++ } ++ ++ rv = dfd_ko_cpld_write(addr, val_tmp); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "write info[addr=0x%x val=0x%x] to cpld fail, rv=%d\n", addr, val_tmp, rv); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int dfd_read_info(info_src_t src, char *fpath, int32_t addr, int read_bytes, uint8_t *val) ++{ ++ int rv = 0; ++ ++ switch (src) { ++ case INFO_SRC_CPLD: ++ rv = dfd_read_info_from_cpld(addr, read_bytes, val); ++ break; ++ case INFO_SRC_FPGA: ++ rv = -1; ++ DBG_DEBUG(DBG_ERROR, "not support read info from fpga\n"); ++ break; ++ case INFO_SRC_OTHER_I2C: ++ rv = -1; ++ DBG_DEBUG(DBG_ERROR, "not support read info from other i2c\n"); ++ break; ++ case INFO_SRC_FILE: ++ rv = dfd_ko_read_file(fpath, addr, val, read_bytes); ++ break; ++ default: ++ rv = -1; ++ DBG_DEBUG(DBG_ERROR, "info src[%d] error\n", src); ++ break; ++ } ++ ++ return rv; ++} ++ ++static int dfd_write_info(info_src_t src, char *fpath, int32_t addr, int write_bytes, uint8_t *val, uint8_t bit_mask) ++{ ++ int rv = 0; ++ ++ switch (src) { ++ case INFO_SRC_CPLD: ++ rv = dfd_write_info_to_cpld(addr, write_bytes, val, bit_mask); ++ break; ++ case INFO_SRC_FPGA: ++ rv = -1; ++ DBG_DEBUG(DBG_ERROR, "not support write info to fpga\n"); ++ break; ++ case INFO_SRC_OTHER_I2C: ++ rv = -1; ++ DBG_DEBUG(DBG_ERROR, "not support write info to other i2c\n"); ++ break; ++ case INFO_SRC_FILE: ++ rv = -1; ++ DBG_DEBUG(DBG_ERROR, "not support write info to file\n"); ++ break; ++ default: ++ rv = -1; ++ DBG_DEBUG(DBG_ERROR, "info src[%d] error\n", src); ++ break; ++ } ++ ++ return rv; ++} ++ ++static int dfd_get_info_value(info_ctrl_t *info_ctrl, int *ret, info_num_buf_to_value_f pfun) ++{ ++ int i, rv; ++ int read_bytes, readed_bytes, int_tmp; ++ uint8_t byte_tmp, val[INFO_INT_MAX_LEN + 1] = {0}; ++ ++ if (info_ctrl->mode == INFO_CTRL_MODE_CONS) { ++ *ret = info_ctrl->int_cons; ++ return DFD_RV_OK; ++ } ++ if (info_ctrl->mode == INFO_CTRL_MODE_TLV) { ++ return INFO_CTRL_MODE_TLV; ++ } ++ ++ if (IS_INFO_FRMT_BIT(info_ctrl->frmt)) { ++ if (!INFO_BIT_OFFSET_VALID(info_ctrl->bit_offset)) { ++ DBG_DEBUG(DBG_ERROR, "info ctrl bit_offsest[%d] invalid\n", ++ info_ctrl->bit_offset); ++ return -DFD_RV_TYPE_ERR; ++ } ++ read_bytes = 1; ++ } else if (IS_INFO_FRMT_BYTE(info_ctrl->frmt) || IS_INFO_FRMT_NUM_STR(info_ctrl->frmt) ++ || IS_INFO_FRMT_NUM_BUF(info_ctrl->frmt)) { ++ if (!INFO_INT_LEN_VALAID(info_ctrl->len)) { ++ DBG_DEBUG(DBG_ERROR, "info ctrl len[%d] invalid\n", info_ctrl->len); ++ return -DFD_RV_TYPE_ERR; ++ } ++ read_bytes = info_ctrl->len; ++ } else { ++ DBG_DEBUG(DBG_ERROR, "info ctrl info format[%d] error\n", info_ctrl->frmt); ++ return -DFD_RV_TYPE_ERR; ++ } ++ ++ readed_bytes = dfd_read_info(info_ctrl->src, info_ctrl->fpath, info_ctrl->addr, read_bytes, &(val[0])); ++ if (readed_bytes <= 0) { ++ DBG_DEBUG(DBG_ERROR, "read int info[src=%s frmt=%s fpath=%s addr=0x%x read_bytes=%d] fail, rv=%d\n", ++ g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], info_ctrl->fpath, ++ info_ctrl->addr, read_bytes, readed_bytes); ++ return -DFD_RV_DEV_FAIL; ++ } ++ ++ if (IS_INFO_FRMT_BIT(info_ctrl->frmt)) { ++ if (info_ctrl->pola == INFO_POLA_NEGA) { ++ val[0] = ~val[0]; ++ } ++ byte_tmp = (val[0] >> info_ctrl->bit_offset) & (~(0xff << info_ctrl->len)); ++ if (pfun) { ++ rv = pfun(&byte_tmp, sizeof(byte_tmp), &int_tmp); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "info ctrl bit process fail, rv=%d\n", rv); ++ return rv; ++ } ++ } else { ++ int_tmp = (int)byte_tmp; ++ } ++ } else if (IS_INFO_FRMT_BYTE(info_ctrl->frmt)) { ++ int_tmp = 0; ++ for (i = 0; i < info_ctrl->len; i++) { ++ if (info_ctrl->pola == INFO_POLA_NEGA) { ++ int_tmp |= val[info_ctrl->len - i - 1]; ++ } else { ++ int_tmp |= val[i]; ++ } ++ if (i != (info_ctrl->len - 1)) { ++ int_tmp <<= 8; ++ } ++ } ++ } else if (IS_INFO_FRMT_NUM_STR(info_ctrl->frmt)) { ++ val[readed_bytes] = '\0'; ++ int_tmp = simple_strtol((char *)(&(val[0])), NULL, 10); ++ } else { ++ if (pfun == NULL) { ++ DBG_DEBUG(DBG_ERROR, "info ctrl number buf process function is null\n"); ++ return -DFD_RV_INDEX_INVALID; ++ } ++ rv = pfun(val, readed_bytes, &int_tmp); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "info ctrl number buf process fail, rv=%d\n", rv); ++ return rv; ++ } ++ } ++ ++ *ret = int_tmp; ++ DBG_DEBUG(DBG_VERBOSE, "read int info[src=%s frmt=%s pola=%s fpath=%s addr=0x%x len=%d bit_offset=%d] success, ret=%d\n", ++ g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], g_info_pola_str[info_ctrl->pola], ++ info_ctrl->fpath, info_ctrl->addr, info_ctrl->len, info_ctrl->bit_offset, *ret); ++ return DFD_RV_OK; ++} ++ ++int dfd_info_get_int(int key, int *ret, info_num_buf_to_value_f pfun) ++{ ++ int rv; ++ info_ctrl_t *info_ctrl; ++ ++ if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key)) || (ret == NULL)) { ++ DBG_DEBUG(DBG_ERROR, "input arguments error, key=0x%08x\n", key); ++ return -DFD_RV_INDEX_INVALID; ++ } ++ ++ info_ctrl = dfd_ko_cfg_get_item(key); ++ if (info_ctrl == NULL) { ++ DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ ++ DBG_DEBUG(DBG_VERBOSE, "get info ctrl value, key=0x%08x\n", key); ++ rv = dfd_get_info_value(info_ctrl, ret, pfun); ++ return rv; ++} ++ ++int dfd_info_get_buf(int key, uint8_t *buf, int buf_len, info_buf_to_buf_f pfun) ++{ ++ int rv; ++ int read_bytes, buf_real_len; ++ uint8_t buf_tmp[INFO_BUF_MAX_LEN]; ++ info_ctrl_t *info_ctrl; ++ ++ if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key)) || (buf == NULL)) { ++ DBG_DEBUG(DBG_ERROR, "input arguments error, key=0x%08x\n", key); ++ return -DFD_RV_INDEX_INVALID; ++ } ++ ++ info_ctrl = dfd_ko_cfg_get_item(key); ++ if (info_ctrl == NULL) { ++ DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ ++ if (info_ctrl->mode != INFO_CTRL_MODE_CFG) { ++ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] mode[%d] invalid\n", key, info_ctrl->mode); ++ return -DFD_RV_TYPE_ERR; ++ } ++ ++ if (!IS_INFO_FRMT_BUF(info_ctrl->frmt) || !INFO_BUF_LEN_VALAID(info_ctrl->len) ++ || (buf_len <= info_ctrl->len)) { ++ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] format=%d or len=%d invlaid, buf_len=%d\n", ++ key, info_ctrl->frmt, info_ctrl->len, buf_len); ++ return -DFD_RV_TYPE_ERR; ++ } ++ ++ read_bytes = dfd_read_info(info_ctrl->src, info_ctrl->fpath, info_ctrl->addr, info_ctrl->len, buf_tmp); ++ if (read_bytes <= 0) { ++ DBG_DEBUG(DBG_ERROR, "read buf info[key=0x%08x src=%s frmt=%s fpath=%s addr=0x%x len=%d] fail, rv=%d\n", ++ key, g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], info_ctrl->fpath, ++ info_ctrl->addr, info_ctrl->len, read_bytes); ++ return -DFD_RV_DEV_FAIL; ++ } ++ ++ if (pfun) { ++ buf_real_len = buf_len; ++ rv = pfun(buf_tmp, read_bytes, buf, &buf_real_len); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] buf process fail, rv=%d\n", key, rv); ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ } else { ++ buf_real_len = read_bytes; ++ memcpy(buf, buf_tmp, read_bytes); ++ } ++ ++ return buf_real_len; ++} ++ ++static int dfd_2key_info_get_buf(info_ctrl_t *info_ctrl, uint8_t *buf, int buf_len, info_hwmon_buf_f pfun) ++{ ++ int rv; ++ int read_bytes, buf_real_len; ++ uint8_t buf_tmp[INFO_BUF_MAX_LEN]; ++ char temp_fpath[INFO_FPATH_MAX_LEN]; ++ ++ if (!IS_INFO_FRMT_BUF(info_ctrl->frmt) || !INFO_BUF_LEN_VALAID(info_ctrl->len) ++ || (buf_len <= info_ctrl->len)) { ++ DBG_DEBUG(DBG_ERROR, "key_path info ctrl format=%d or len=%d invlaid, buf_len=%d\n", ++ info_ctrl->frmt, info_ctrl->len, buf_len); ++ return -DFD_RV_TYPE_ERR; ++ } ++ ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ rv = kfile_iterate_dir(info_ctrl->fpath, DFD_HWMON_NAME, buf_tmp, INFO_BUF_MAX_LEN); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "dir patch:%s ,can find name %s dir \n", ++ info_ctrl->fpath, DFD_HWMON_NAME); ++ return -DFD_RV_NO_NODE; ++ } ++ mem_clear(temp_fpath, sizeof(temp_fpath)); ++ snprintf(temp_fpath, sizeof(temp_fpath), "%s%s/%s", ++ info_ctrl->fpath, buf_tmp, info_ctrl->str_cons); ++ DBG_DEBUG(DBG_VERBOSE, "match ok path = %s \n", temp_fpath); ++ ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ ++ read_bytes = dfd_read_info(info_ctrl->src, temp_fpath, info_ctrl->addr, info_ctrl->len, buf_tmp); ++ if (read_bytes <= 0) { ++ DBG_DEBUG(DBG_ERROR, "read buf info[src=%s frmt=%s fpath=%s addr=0x%x len=%d] fail, rv=%d\n", ++ g_info_src_str[info_ctrl->src], g_info_src_str[info_ctrl->frmt], temp_fpath, ++ info_ctrl->addr, info_ctrl->len, read_bytes); ++ return -DFD_RV_DEV_FAIL; ++ } ++ ++ if (pfun) { ++ buf_real_len = buf_len; ++ rv = pfun(buf_tmp, read_bytes, buf, &buf_real_len, info_ctrl); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "info ctrl buf process fail, rv=%d\n", rv); ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ } else { ++ buf_real_len = read_bytes; ++ memcpy(buf, buf_tmp, buf_real_len); ++ } ++ return buf_real_len; ++} ++ ++int dfd_info_set_int(int key, int val) ++{ ++ int rv; ++ int write_bytes; ++ uint8_t byte_tmp, bit_mask; ++ info_ctrl_t *info_ctrl; ++ ++ if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key))) { ++ DBG_DEBUG(DBG_ERROR, "input arguments error, key=0x%08x\n", key); ++ return -DFD_RV_INDEX_INVALID; ++ } ++ ++ info_ctrl = dfd_ko_cfg_get_item(key); ++ if (info_ctrl == NULL) { ++ DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ ++ if (info_ctrl->mode != INFO_CTRL_MODE_CFG) { ++ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] mode[%d] warnning\n", key, info_ctrl->mode); ++ return -DFD_RV_TYPE_ERR; ++ } ++ ++ if (IS_INFO_FRMT_BIT(info_ctrl->frmt)) { ++ ++ if (!INFO_BIT_OFFSET_VALID(info_ctrl->bit_offset)) { ++ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] bit_offsest[%d] invalid\n", ++ key, info_ctrl->bit_offset); ++ return -DFD_RV_TYPE_ERR; ++ } ++ ++ write_bytes = 1; ++ ++ byte_tmp = (uint8_t)(val & 0xff); ++ byte_tmp <<= info_ctrl->bit_offset; ++ if (info_ctrl->pola == INFO_POLA_NEGA) { ++ byte_tmp = ~byte_tmp; ++ } ++ ++ bit_mask = (~(0xff << info_ctrl->len)) << info_ctrl->bit_offset; ++ } else if (IS_INFO_FRMT_BYTE(info_ctrl->frmt)) { ++ ++ if (!INFO_INT_LEN_VALAID(info_ctrl->len)) { ++ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] len[%d] invalid\n", key, info_ctrl->len); ++ return -DFD_RV_TYPE_ERR; ++ } ++ ++ write_bytes = 1; ++ ++ byte_tmp = (uint8_t)(val & 0xff); ++ ++ bit_mask = 0xff; ++ } else if (IS_INFO_FRMT_NUM_STR(info_ctrl->frmt)) { ++ ++ DBG_DEBUG(DBG_ERROR, "not support str int set\n"); ++ return -1; ++ } else if (IS_INFO_FRMT_NUM_BUF(info_ctrl->frmt)) { ++ ++ if (!INFO_INT_LEN_VALAID(info_ctrl->len)) { ++ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] len[%d] invalid\n", key, info_ctrl->len); ++ return -DFD_RV_TYPE_ERR; ++ } ++ ++ write_bytes = 1; ++ ++ byte_tmp = (uint8_t)(val & 0xff); ++ ++ bit_mask = 0xff; ++ } else { ++ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] format[%d] error\n", key, info_ctrl->frmt); ++ return -DFD_RV_TYPE_ERR; ++ } ++ ++ rv = dfd_write_info(info_ctrl->src, info_ctrl->fpath, info_ctrl->addr, write_bytes, ++ &byte_tmp, bit_mask); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "write int info[src=%s frmt=%s fpath=%s addr=0x%x len=%d val=%d] fail, rv=%d\n", ++ g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], info_ctrl->fpath, ++ info_ctrl->addr, info_ctrl->len, val, rv); ++ return -DFD_RV_DEV_FAIL; ++ } ++ ++ DBG_DEBUG(DBG_VERBOSE, "write int info[src=%s frmt=%s pola=%s fpath=%s addr=0x%x len=%d bit_offset=%d val=%d] success\n", ++ g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], g_info_pola_str[info_ctrl->pola], ++ info_ctrl->fpath, info_ctrl->addr, info_ctrl->len, info_ctrl->bit_offset, val); ++ return DFD_RV_OK; ++} ++ ++static int dfd_info_reg2data_linear(int key, int data, int *temp_value) ++{ ++ s16 exponent; ++ s32 mantissa; ++ int val; ++ info_ctrl_t *info_ctrl; ++ ++ info_ctrl = dfd_ko_cfg_get_item(key); ++ if (info_ctrl == NULL) { ++ DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=%d\n", key); ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ ++ switch (info_ctrl->int_extra1) { ++ case LINEAR11: ++ exponent = ((s16)data) >> 11; ++ mantissa = ((s16)((data & 0x7ff) << 5)) >> 5; ++ val = mantissa; ++ val = val * 1000L; ++ break; ++ case LINEAR16: ++ break; ++ default: ++ break; ++ } ++ ++ if (DFD_CFG_ITEM_ID(key) == DFD_CFG_ITEM_HWMON_POWER) { ++ val = val * 1000L; ++ } ++ ++ if (exponent >= 0) { ++ val <<= exponent; ++ } else { ++ val >>= -exponent; ++ } ++ *temp_value = val; ++ ++ return DFD_RV_OK; ++} ++ ++static int dfd_info_reg2data_tmp464(int data, int *temp_value) ++{ ++ s16 tmp_val; ++ int val; ++ ++ DBG_DEBUG(DBG_VERBOSE, "reg2data_tmp464, data=%d\n", data); ++ ++ if (data >= 0) { ++ val = data*625/80; ++ } else { ++ tmp_val = ~(data & 0x7ff) + 1; ++ val = tmp_val*625/80; ++ } ++ *temp_value = val; ++ ++ return DFD_RV_OK; ++} ++ ++static int dfd_info_reg2data_mac_th5(int data, int *temp_value) ++{ ++ int tmp_val; ++ int val; ++ ++ DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_th5, data=%d\n", data); ++ ++ tmp_val = data >> 4; ++ val = 476359 - (((tmp_val - 2) * 317704) / 2000); ++ ++ DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_th5, val=%d\n", val); ++ *temp_value = val; ++ ++ return DFD_RV_OK; ++} ++ ++static int dfd_info_reg2data_mac_td3(int data, int *temp_value) ++{ ++ int val; ++ ++ if (data == 0) { ++ DBG_DEBUG(DBG_ERROR,"invalid cpld data=%d\n", data); ++ *temp_value = -READ_TEMP_FAIL; ++ return DFD_RV_OK; ++ } ++ ++ DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_td3, data=%d\n", data); ++ val = 434100 - (12500000 / (data * 100 - 1) *535); ++ if ((val / 1000 < -70) || (val / 1000 > 200)) { ++ DBG_DEBUG(DBG_ERROR,"out of range cpld val=%d\n", val); ++ *temp_value = -READ_TEMP_FAIL; ++ return DFD_RV_OK; ++ } ++ DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_td3, val=%d\n", val); ++ *temp_value = val; ++ ++ return DFD_RV_OK; ++} ++ ++static int dfd_info_get_cpld_voltage(int key, uint32_t *value) ++{ ++ int rv; ++ uint32_t vol_ref_tmp, vol_ref; ++ uint32_t vol_curr_tmp, vol_curr; ++ info_ctrl_t *info_ctrl; ++ info_ctrl_t info_ctrl_tmp; ++ uint32_t vol_coefficient; ++ ++ info_ctrl = dfd_ko_cfg_get_item(key); ++ if (info_ctrl == NULL) { ++ DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ ++ vol_coefficient = (uint32_t)info_ctrl->int_extra2; ++ ++ rv = dfd_get_info_value(info_ctrl, &vol_curr_tmp, NULL); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "get cpld current voltage error, addr:0x%x, rv = %d\n", info_ctrl->addr, rv); ++ return rv; ++ } ++ if (info_ctrl->int_extra3 == CPLD_VOLATGE_VALUE_MODE2) { ++ vol_curr_tmp = DFD_GET_CPLD_VOLATGE_CODE_VALUE2(vol_curr_tmp); ++ vol_curr = DFD_GET_CPLD_VOLATGE_REAL_VALUE2(vol_curr_tmp, vol_coefficient); ++ DBG_DEBUG(DBG_VERBOSE, "vol_curr_tmp = 0x%x, vol_curr = 0x%x, is same.\n", vol_curr_tmp, vol_curr); ++ } else { ++ vol_curr_tmp = DFD_GET_CPLD_VOLATGE_CODE_VALUE(vol_curr_tmp); ++ if (info_ctrl->addr == info_ctrl->int_extra1) { ++ vol_curr = DFD_GET_CPLD_VOLATGE_REAL_VALUE(vol_curr_tmp, vol_coefficient); ++ DBG_DEBUG(DBG_VERBOSE, "current voltage is reference voltage, vol_curr_tmp: 0x%x, coefficient: %u, vol_curr: %u\n", ++ vol_curr_tmp, vol_coefficient, vol_curr); ++ } else { ++ memcpy(&info_ctrl_tmp, info_ctrl, sizeof(info_ctrl_t)); ++ info_ctrl_tmp.addr = info_ctrl->int_extra1; ++ rv = dfd_get_info_value(&info_ctrl_tmp, &vol_ref_tmp, NULL); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "get cpld reference voltage error, addr: 0x%x, rv: %d\n", info_ctrl_tmp.addr, rv); ++ return rv; ++ } ++ vol_ref = DFD_GET_CPLD_VOLATGE_CODE_VALUE(vol_ref_tmp); ++ DBG_DEBUG(DBG_VERBOSE, "vol_ref_tmp: 0x%x, vol_ref: 0x%x\n", vol_ref_tmp, vol_ref); ++ vol_curr = (vol_curr_tmp * vol_coefficient) / vol_ref; ++ DBG_DEBUG(DBG_VERBOSE, "vol_curr_tmp: 0x%x, vol_ref: 0x%x, coefficient: %u, vol_curr: %u\n", ++ vol_curr_tmp, vol_ref, vol_coefficient, vol_curr); ++ } ++ } ++ *value = vol_curr; ++ return DFD_RV_OK; ++} ++ ++static int dfd_info_get_cpld_temperature(int key, int *value) ++{ ++ int rv; ++ int temp_reg; ++ int temp_value; ++ info_ctrl_t *info_ctrl; ++ ++ info_ctrl = dfd_ko_cfg_get_item(key); ++ if (info_ctrl == NULL) { ++ DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ ++ rv = dfd_info_get_int(key, &temp_reg, NULL); ++ if(rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "get cpld current temperature error, addr:0x%x, rv =%d\n", info_ctrl->addr, rv); ++ return rv; ++ } ++ DBG_DEBUG(DBG_VERBOSE, "get cpld temp:0x%08x, extra1 0x%x\n", temp_reg, info_ctrl->int_extra1); ++ ++ switch (info_ctrl->int_extra1) { ++ case LINEAR11: ++ rv = dfd_info_reg2data_linear(key, temp_reg, &temp_value); ++ break; ++ case TMP464: ++ rv = dfd_info_reg2data_tmp464(temp_reg, &temp_value); ++ break; ++ case MAC_TH5: ++ rv = dfd_info_reg2data_mac_th5(temp_reg, &temp_value); ++ break; ++ case MAC_TD3: ++ rv = dfd_info_reg2data_mac_td3(temp_reg, &temp_value); ++ break; ++ default: ++ temp_value = temp_reg; ++ rv = DFD_RV_OK; ++ break; ++ } ++ ++ DBG_DEBUG(DBG_VERBOSE, "calc temp:%d \n", temp_value); ++ *value = temp_value; ++ ++ return rv; ++} ++ ++static int dfd_info_get_sensor_value(int key, uint8_t *buf, int buf_len, info_hwmon_buf_f pfun) ++{ ++ int rv, buf_real_len; ++ uint32_t value; ++ uint8_t buf_tmp[INFO_BUF_MAX_LEN]; ++ info_ctrl_t *info_ctrl; ++ ++ info_ctrl = dfd_ko_cfg_get_item(key); ++ if (info_ctrl == NULL) { ++ DBG_DEBUG(DBG_ERROR, "get info ctrl fail, key=0x%08x\n", key); ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ ++ if ( DFD_CFG_ITEM_ID(key) == DFD_CFG_ITEM_HWMON_IN && info_ctrl->src == INFO_SRC_CPLD) { ++ rv = dfd_info_get_cpld_voltage(key, &value); ++ if(rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "get cpld voltage failed.key=0x%08x, rv:%d\n", key, rv); ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ DBG_DEBUG(DBG_VERBOSE, "get cpld voltage ok, value:%u\n", value); ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ snprintf(buf_tmp, sizeof(buf_tmp), "%u\n", value); ++ buf_real_len = strlen(buf_tmp); ++ if(buf_len <= buf_real_len) { ++ DBG_DEBUG(DBG_ERROR, "length not enough.buf_len:%d,need length:%d\n", buf_len, buf_real_len); ++ return -DFD_RV_DEV_FAIL; ++ } ++ if (pfun) { ++ buf_real_len = buf_len; ++ rv = pfun(buf_tmp, strlen(buf_tmp), buf, &buf_real_len, info_ctrl); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "deal date error.org value:%s, buf_len:%d, rv=%d\n", ++ buf_tmp, buf_len, rv); ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ } else { ++ memcpy(buf, buf_tmp, buf_real_len); ++ } ++ return buf_real_len; ++ } else if ( DFD_CFG_ITEM_ID(key) == DFD_CFG_ITEM_HWMON_TEMP && info_ctrl->src == INFO_SRC_CPLD ) { ++ rv = dfd_info_get_cpld_temperature(key, &value); ++ if(rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "get cpld temperature failed.key=0x%08x, rv:%d\n", key, rv); ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ DBG_DEBUG(DBG_VERBOSE, "get cpld temperature ok, value:%d buf_len %d\n", value, buf_len); ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ snprintf(buf_tmp, sizeof(buf_tmp), "%d\n", value); ++ buf_real_len = strlen(buf_tmp); ++ if(buf_len <= buf_real_len) { ++ DBG_DEBUG(DBG_ERROR, "length not enough.buf_len:%d,need length:%d\n", buf_len, buf_real_len); ++ return -DFD_RV_DEV_FAIL; ++ } ++ DBG_DEBUG(DBG_VERBOSE, "buf_real_len %d\n", buf_real_len); ++ memcpy(buf, buf_tmp, buf_real_len); ++ return buf_real_len; ++ } ++ ++ DBG_DEBUG(DBG_ERROR, "not support mode. key:0x%08x\n", key); ++ return -DFD_RV_MODE_NOTSUPPORT; ++} ++ ++int dfd_info_get_sensor(uint32_t key, char *buf, int buf_len, info_hwmon_buf_f pfun) ++{ ++ info_ctrl_t *key_info_ctrl; ++ int rv; ++ ++ if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key)) || ++ (buf == NULL) || buf_len <= 0) { ++ DBG_DEBUG(DBG_ERROR, "input arguments error, key_path=0x%08x, buf_len:%d.\n", ++ key, buf_len); ++ return -DFD_RV_INVALID_VALUE; ++ } ++ ++ key_info_ctrl = dfd_ko_cfg_get_item(key); ++ if (key_info_ctrl == NULL) { ++ DBG_DEBUG(DBG_ERROR, "key_path info error, key=0x%08x\n", key); ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ mem_clear(buf, buf_len); ++ ++ if (key_info_ctrl->mode == INFO_CTRL_MODE_SRT_CONS) { ++ snprintf(buf, buf_len, "%s\n", key_info_ctrl->str_cons); ++ DBG_DEBUG(DBG_VERBOSE, "get sensor value through string config, key=0x%08x, value:%s\n", key, buf); ++ return strlen(buf); ++ } ++ ++ if (key_info_ctrl->mode == INFO_CTRL_MODE_CFG && key_info_ctrl->src == INFO_SRC_FILE) { ++ DBG_DEBUG(DBG_VERBOSE, "get sensor value through hwmon, key:0x%08x\n", key); ++ rv = dfd_2key_info_get_buf(key_info_ctrl, buf, buf_len, pfun); ++ if (rv < 0) { ++ DBG_DEBUG(DBG_VERBOSE, "get sensor value through hwmon failed, key:0x%08x, rv:%d\n", key, rv); ++ } ++ return rv; ++ } ++ rv = dfd_info_get_sensor_value(key, buf, buf_len, pfun); ++ if( rv < 0) { ++ DBG_DEBUG(DBG_ERROR, "get sensor value failed, key=0x%08x, rv:%d.\n", key, rv); ++ } ++ return rv; ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c +new file mode 100644 +index 000000000..d6fd7e104 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c +@@ -0,0 +1,82 @@ ++#include ++#include ++ ++#include "../include/dfd_cfg_listnode.h" ++#include "../../dev_sysfs/include/sysfs_common.h" ++ ++void *lnode_find_node(lnode_root_t *root, int key) ++{ ++ lnode_node_t *lnode; ++ ++ if (root == NULL){ ++ return NULL; ++ } ++ ++ list_for_each_entry(lnode, &(root->root), lst) { ++ if (lnode->key == key) { ++ return lnode->data; ++ } ++ } ++ ++ return NULL; ++} ++ ++int lnode_insert_node(lnode_root_t *root, int key, void *data) ++{ ++ lnode_node_t *lnode; ++ void *data_tmp; ++ ++ if ((root == NULL) || (data == NULL)) { ++ return LNODE_RV_INPUT_ERR; ++ } ++ ++ data_tmp = lnode_find_node(root, key); ++ if (data_tmp != NULL) { ++ return LNODE_RV_NODE_EXIST; ++ } ++ ++ lnode = kmalloc(sizeof(lnode_node_t), GFP_KERNEL); ++ if (lnode == NULL) { ++ return LNODE_RV_NOMEM; ++ } ++ ++ lnode->key = key; ++ lnode->data = data; ++ list_add_tail(&(lnode->lst), &(root->root)); ++ ++ return LNODE_RV_OK; ++} ++ ++int lnode_init_root(lnode_root_t *root) ++{ ++ if (root == NULL) { ++ return LNODE_RV_INPUT_ERR; ++ } ++ ++ INIT_LIST_HEAD(&(root->root)); ++ ++ return LNODE_RV_OK; ++} ++ ++void lnode_free_list(lnode_root_t *root) ++{ ++ lnode_node_t *lnode, *lnode_next; ++ ++ if (root == NULL){ ++ return ; ++ } ++ ++ list_for_each_entry_safe(lnode, lnode_next, &(root->root), lst) { ++ if ( lnode->data ) { ++ kfree(lnode->data); ++ lnode->data = NULL; ++ lnode->key = 0; ++ } ++ list_del(&lnode->lst); ++ kfree(lnode); ++ lnode = NULL; ++ } ++ ++ return ; ++ ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_fan_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_fan_driver.c +new file mode 100644 +index 000000000..d8965d75c +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_fan_driver.c +@@ -0,0 +1,201 @@ ++#include ++#include ++ ++#include "./include/dfd_module.h" ++#include "./include/dfd_cfg.h" ++#include "./include/dfd_cfg_adapter.h" ++#include "./include/dfd_cfg_info.h" ++#include "../dev_sysfs/include/sysfs_common.h" ++ ++#define FAN_SIZE (256) ++ ++int g_dfd_fan_dbg_level = 0; ++module_param(g_dfd_fan_dbg_level, int, S_IRUGO | S_IWUSR); ++ ++typedef enum fan_speed_format_mem_s { ++ LINEAR120 = 1, ++} fan_speed_format_mem_t; ++ ++int dfd_get_fan_roll_status(unsigned int fan_index, unsigned int motor_index) ++{ ++ int key, ret; ++ int status; ++ ++ key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_ROLL_STATUS, fan_index, motor_index); ++ ret = dfd_info_get_int(key, &status, NULL); ++ if (ret < 0) { ++ DFD_FAN_DEBUG(DBG_ERROR, "get fan roll status error, fan:%d,motor:%d\n", ++ fan_index, motor_index); ++ return ret; ++ } ++ ++ DFD_FAN_DEBUG(DBG_VERBOSE, "fan%u motor%u get fan roll status success, status:%d.\n", ++ fan_index, motor_index, status); ++ return status; ++} ++ ++int dfd_get_fan_present_status(unsigned int fan_index) ++{ ++ int key, ret; ++ int status; ++ ++ key = DFD_CFG_KEY(DFD_CFG_ITEM_DEV_PRESENT_STATUS, WB_MAIN_DEV_FAN, fan_index); ++ ret = dfd_info_get_int(key, &status, NULL); ++ if (ret < 0) { ++ DFD_FAN_DEBUG(DBG_ERROR, "fan%u get present status error, key:0x%x\n", fan_index, key); ++ return ret; ++ } ++ ++ DFD_FAN_DEBUG(DBG_VERBOSE, "fan%u get present status success, status:%d.\n", fan_index, status); ++ return status; ++} ++ ++static int dfd_get_fan_speed_linear120(int origin_data, int *speed) ++{ ++ *speed = origin_data * 120; ++ DFD_FAN_DEBUG(DBG_VERBOSE, "get fan speed by linear120 origin_data: %d, speed: %d\n", ++ origin_data, *speed); ++ return 0; ++} ++ ++static int dfd_get_fan_speed_default(int origin_data, int *speed) ++{ ++ if (origin_data == 0 || origin_data == 0xffff) { ++ *speed = 0; ++ } else { ++ *speed = 15000000 / origin_data; ++ } ++ DFD_FAN_DEBUG(DBG_VERBOSE, "get fan speed by default origin_data: %d, speed: %d\n", ++ origin_data, *speed); ++ return 0; ++} ++ ++ssize_t dfd_get_fan_speed(unsigned int fan_index, unsigned int motor_index,unsigned int *speed) ++{ ++ int key, ret, speed_tmp; ++ info_ctrl_t *info_ctrl; ++ ++ if (speed == NULL) { ++ DFD_FAN_DEBUG(DBG_ERROR, "param error. fan index:%d, motor index:%d.\n", ++ fan_index, motor_index); ++ return -DFD_RV_INVALID_VALUE; ++ } ++ ++ key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_SPEED, fan_index, motor_index); ++ ret = dfd_info_get_int(key, &speed_tmp, NULL); ++ if (ret < 0) { ++ DFD_FAN_DEBUG(DBG_ERROR, "get fan speed error, key:0x%x,ret:%d\n",key, ret); ++ return ret; ++ } ++ DFD_FAN_DEBUG(DBG_VERBOSE, "get fan origin data: 0x%x\n", speed_tmp); ++ ++ info_ctrl = dfd_ko_cfg_get_item(key); ++ switch (info_ctrl->int_extra1) { ++ case LINEAR120: ++ ret = dfd_get_fan_speed_linear120(speed_tmp, speed); ++ break; ++ default: ++ ret = dfd_get_fan_speed_default(speed_tmp, speed); ++ break; ++ } ++ ++ return ret; ++} ++ ++int dfd_set_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int level) ++{ ++ int key, ret; ++ ++ if (level < 0 || level > 0xff) { ++ DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, can not set fan speed level: %d.\n", ++ fan_index, motor_index, level); ++ return -DFD_RV_INVALID_VALUE; ++ } ++ ++ key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_RATIO, fan_index, motor_index); ++ ret = dfd_info_set_int(key, level); ++ if (ret < 0) { ++ DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, set fan level 0x%02x error, key:0x%x,ret:%d\n", ++ fan_index, motor_index, level, key, ret); ++ return ret; ++ } ++ ++ DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, set fan speed level 0x%02x success.\n", ++ fan_index, motor_index, level); ++ return DFD_RV_OK; ++} ++ ++int dfd_set_fan_pwm(unsigned int fan_index, unsigned int motor_index, int pwm) ++{ ++ int ret, data; ++ ++ if (pwm < 0 || pwm > 100) { ++ DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, can't set pwm: %d.\n", ++ fan_index, motor_index, pwm); ++ return -DFD_RV_INVALID_VALUE; ++ } ++ ++ data = pwm * 255 / 100; ++ ret = dfd_set_fan_speed_level(fan_index, motor_index, data); ++ if (ret < 0) { ++ DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, set fan ratio:%d error, ret:%d\n", ++ fan_index, motor_index, data, ret); ++ return ret; ++ } ++ ++ DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, set fan ratio %d success.\n", ++ fan_index, motor_index, data); ++ return DFD_RV_OK; ++} ++ ++int dfd_get_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int *level) ++{ ++ int key, ret, speed_level; ++ ++ if (level == NULL) { ++ DFD_FAN_DEBUG(DBG_ERROR, "param error. fan index:%d, motor index:%d.\n", ++ fan_index, motor_index); ++ return -DFD_RV_INVALID_VALUE; ++ } ++ ++ key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_RATIO, fan_index, motor_index); ++ ret = dfd_info_get_int(key, &speed_level, NULL); ++ if (ret < 0) { ++ DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, get fan speed level error, key:0x%x,ret:%d\n", ++ fan_index, motor_index, key, ret); ++ return ret; ++ } ++ ++ DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, get fan speed level success, value:0x%02x.\n", ++ fan_index, motor_index, speed_level); ++ *level = speed_level; ++ return DFD_RV_OK; ++} ++ ++int dfd_get_fan_pwm(unsigned int fan_index, unsigned int motor_index, int *pwm) ++{ ++ int ret, level; ++ ++ if (pwm == NULL) { ++ DFD_FAN_DEBUG(DBG_ERROR, "param error. fan index:%d, motor index:%d.\n", ++ fan_index, motor_index); ++ return -DFD_RV_INVALID_VALUE; ++ } ++ ++ ret = dfd_get_fan_speed_level(fan_index, motor_index, &level); ++ if (ret < 0) { ++ DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, get fan pwm error, ret:%d\n", ++ fan_index, motor_index, ret); ++ return ret; ++ } ++ ++ if ((level * 100) % 255 > 0) { ++ *pwm = level * 100 / 255 + 1; ++ } else { ++ *pwm = level * 100 / 255; ++ } ++ ++ DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, get fan pwm success, value:%d.\n", ++ fan_index, motor_index, *pwm); ++ return DFD_RV_OK; ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_module.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_module.c +new file mode 100644 +index 000000000..9e5b00b79 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_module.c +@@ -0,0 +1,95 @@ ++#include ++ ++#include "../dev_sysfs/include/sysfs_common.h" ++#include "./include/dfd_module.h" ++#include "./include/dfd_cfg.h" ++#include "./include/dfd_fan_driver.h" ++#include "./include/dfd_slot_driver.h" ++#include "./include/dfd_sensors_driver.h" ++#include "./include/dfd_psu_driver.h" ++#include "./include/dfd_sff_driver.h" ++ ++typedef enum dfd_dev_init_fail_s { ++ DFD_KO_INIT_CPLD_FAIL = 1, ++ DFD_KO_INIT_FPGA_FAIL = 2, ++ DFD_KO_INIT_IRQ_FAIL = 3, ++ DFD_KO_INIT_CFG_FAIL = 4, ++ DFD_KO_INIT_DATA_FAIL = 5, ++} dfd_dev_init_fail_t; ++ ++int g_dfd_dbg_level = 0; ++ ++int dfd_get_dev_number(unsigned int main_dev_id, unsigned int minor_dev_id) ++{ ++ int key,dev_num; ++ int *p_dev_num; ++ ++ key = DFD_CFG_KEY(DFD_CFG_ITEM_DEV_NUM, main_dev_id, minor_dev_id); ++ p_dev_num = dfd_ko_cfg_get_item(key); ++ if (p_dev_num == NULL) { ++ DBG_DEBUG(DBG_ERROR, "get device number failed, key:0x%x\n",key); ++ return -DFD_RV_DEV_NOTSUPPORT; ++ } ++ dev_num = *p_dev_num; ++ DBG_DEBUG(DBG_VERBOSE, "get device number ok, number:%d\n",dev_num); ++ return dev_num; ++} ++ ++static struct switch_drivers_t switch_drivers= { ++ .get_dev_number = dfd_get_dev_number, ++ /* fan */ ++ .get_fan_speed = dfd_get_fan_speed, ++ .get_fan_pwm = dfd_get_fan_pwm, ++ .set_fan_pwm = dfd_set_fan_pwm, ++ .get_fan_present_status = dfd_get_fan_present_status, ++ .get_fan_roll_status = dfd_get_fan_roll_status, ++ .get_fan_speed_level = dfd_get_fan_speed_level, ++ .set_fan_speed_level = dfd_set_fan_speed_level, ++ /* slot */ ++ .get_slot_present_status = dfd_get_slot_present_status, ++ /* sensors */ ++ .get_temp_info = dfd_get_temp_info, ++ .get_voltage_info = dfd_get_voltage_info, ++ /* psu */ ++ .get_psu_present_status = dfd_get_psu_present_status, ++ .get_psu_output_status = dfd_get_psu_output_status, ++ .get_psu_alert_status = dfd_get_psu_alert_status, ++ /* sff */ ++ .get_sff_cpld_info = dfd_get_sff_cpld_info, ++ .get_sff_dir_name = dfd_get_sff_dir_name, ++}; ++ ++struct switch_drivers_t * dfd_plat_driver_get(void) { ++ return &switch_drivers; ++} ++ ++static int32_t __init dfd_dev_init(void) ++{ ++ int ret; ++ ++ DBG_DEBUG(DBG_VERBOSE, "Enter.\n"); ++ ++ ret = dfd_dev_cfg_init(); ++ if (ret != 0) { ++ DBG_DEBUG(DBG_ERROR, "dfd_dev_cfg_init failed ret %d.\n", ret); ++ ret = -DFD_KO_INIT_CFG_FAIL; ++ return ret; ++ } ++ ++ DBG_DEBUG(DBG_VERBOSE, "success.\n"); ++ return 0; ++} ++ ++static void __exit dfd_dev_exit(void) ++{ ++ DBG_DEBUG(DBG_VERBOSE, "dfd_dev_exit.\n"); ++ dfd_dev_cfg_exit(); ++ return ; ++} ++ ++module_init(dfd_dev_init); ++module_exit(dfd_dev_exit); ++module_param(g_dfd_dbg_level, int, S_IRUGO | S_IWUSR); ++EXPORT_SYMBOL(dfd_plat_driver_get); ++MODULE_AUTHOR("support"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_psu_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_psu_driver.c +new file mode 100644 +index 000000000..55e2e4339 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_psu_driver.c +@@ -0,0 +1,70 @@ ++#include ++#include ++ ++#include "./include/dfd_module.h" ++#include "./include/dfd_cfg.h" ++#include "./include/dfd_cfg_adapter.h" ++#include "./include/dfd_cfg_info.h" ++#include "../dev_sysfs/include/sysfs_common.h" ++ ++#define PSU_SIZE (256) ++ ++typedef enum dfd_psu_status_e { ++ DFD_PSU_PRESENT_STATUS = 0, ++ DFD_PSU_OUTPUT_STATUS = 1, ++ DFD_PSU_ALERT_STATUS = 2, ++} dfd_psu_status_t; ++ ++int g_dfd_psu_dbg_level = 0; ++module_param(g_dfd_psu_dbg_level, int, S_IRUGO | S_IWUSR); ++ ++int dfd_get_psu_present_status(unsigned int psu_index) ++{ ++ int ret, present_key, present_status; ++ ++ present_key = DFD_CFG_KEY(DFD_CFG_ITEM_PSU_STATUS, psu_index, DFD_PSU_PRESENT_STATUS); ++ ret = dfd_info_get_int(present_key, &present_status, NULL); ++ if (ret < 0) { ++ DFD_PSU_DEBUG(DBG_ERROR, "dfd_get_psu_present_status error. psu_index:%d, ret:%d\n", ++ psu_index, ret); ++ return ret; ++ } ++ ++ DFD_PSU_DEBUG(DBG_VERBOSE, "dfd_get_psu_present_status success. psu_index:%d, status:%d\n", ++ psu_index, present_status); ++ return present_status; ++} ++ ++int dfd_get_psu_output_status(unsigned int psu_index) ++{ ++ int ret, output_key, output_status; ++ ++ output_key = DFD_CFG_KEY(DFD_CFG_ITEM_PSU_STATUS, psu_index, DFD_PSU_OUTPUT_STATUS); ++ ret = dfd_info_get_int(output_key, &output_status, NULL); ++ if (ret < 0) { ++ DFD_PSU_DEBUG(DBG_ERROR, "dfd_get_psu_output_status error. psu_index:%d, ret:%d\n", ++ psu_index, ret); ++ return ret; ++ } ++ ++ DFD_PSU_DEBUG(DBG_VERBOSE, "dfd_get_psu_output_status success. psu_index:%d, status:%d\n", ++ psu_index, output_status); ++ return output_status; ++} ++ ++int dfd_get_psu_alert_status(unsigned int psu_index) ++{ ++ int ret, alert_key, alert_status; ++ ++ alert_key = DFD_CFG_KEY(DFD_CFG_ITEM_PSU_STATUS, psu_index, DFD_PSU_ALERT_STATUS); ++ ret = dfd_info_get_int(alert_key, &alert_status, NULL); ++ if (ret < 0) { ++ DFD_PSU_DEBUG(DBG_ERROR, "dfd_get_psu_alert_status error. psu_index:%d, ret:%d\n", ++ psu_index, ret); ++ return ret; ++ } ++ ++ DFD_PSU_DEBUG(DBG_VERBOSE, "dfd_get_psu_alert_status success. psu_index:%d, status:%d\n", ++ psu_index, alert_status); ++ return alert_status; ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sensors_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sensors_driver.c +new file mode 100644 +index 000000000..bfca20290 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sensors_driver.c +@@ -0,0 +1,149 @@ ++#include ++#include ++ ++#include "./include/dfd_module.h" ++#include "./include/dfd_cfg.h" ++#include "./include/dfd_cfg_adapter.h" ++#include "./include/dfd_cfg_info.h" ++#include "./include/dfd_cfg_file.h" ++#include "../dev_sysfs/include/sysfs_common.h" ++ ++#define DFD_GET_TEMP_SENSOR_KEY1(dev_index, temp_index) \ ++ (((dev_index & 0xff) << 8) | (temp_index & 0xff)) ++#define DFD_GET_TEMP_SENSOR_KEY2(main_dev_id, temp_type) \ ++ (((main_dev_id & 0x0f) << 4) | (temp_type & 0x0f)) ++#define DFD_FORMAT_STR_MAX_LEN (32) ++ ++int g_dfd_sensor_dbg_level = 0; ++module_param(g_dfd_sensor_dbg_level, int, S_IRUGO | S_IWUSR); ++ ++static int dfd_deal_hwmon_buf(uint8_t *buf, int buf_len, uint8_t *buf_new, int *buf_len_new, info_ctrl_t *info_ctrl) ++{ ++ int i, tmp_len; ++ int exp, decimal, divisor; ++ int org_value, tmp_value; ++ int div_result, div_mod; ++ char fmt_str[DFD_FORMAT_STR_MAX_LEN]; ++ ++ exp = info_ctrl->int_cons; ++ decimal = info_ctrl->bit_offset; ++ ++ if (exp <= 0) { ++ DBG_DEBUG(DBG_VERBOSE, "exponent %d, don't need transform. buf_len:%d, buf_len_new:%d\n", ++ exp, buf_len, *buf_len_new); ++ snprintf(buf_new, *buf_len_new, "%s", buf); ++ *buf_len_new = strlen(buf_new); ++ return DFD_RV_OK; ++ } ++ divisor = 1; ++ for (i = 0; i < exp; i++) { ++ divisor *= 10; ++ } ++ org_value = simple_strtol(buf, NULL, 10); ++ if (org_value < 0) { ++ tmp_value = 0 - org_value; ++ } else { ++ tmp_value = org_value; ++ } ++ div_result = tmp_value / divisor; ++ div_mod = tmp_value % divisor; ++ DBG_DEBUG(DBG_VERBOSE, "exp:%d, decimal:%d, original value:%d, divisor:%d, result :%d, mod:%d\n", ++ exp, decimal, org_value, divisor, div_result, div_mod); ++ ++ mem_clear(fmt_str, sizeof(fmt_str)); ++ if (org_value < 0) { ++ snprintf(fmt_str, sizeof(fmt_str), "-%%d.%%0%dd\n",exp); ++ } else { ++ snprintf(fmt_str, sizeof(fmt_str), "%%d.%%0%dd\n",exp); ++ } ++ DBG_DEBUG(DBG_VERBOSE, "format string:%s",fmt_str); ++ snprintf(buf_new, *buf_len_new, fmt_str, div_result, div_mod); ++ *buf_len_new = strlen(buf_new); ++ tmp_len = *buf_len_new; ++ ++ if ( decimal > 0) { ++ for(i = 0; i < *buf_len_new; i++) { ++ if (buf_new[i] == '.') { ++ if( i + decimal + 2 <= *buf_len_new ) { ++ buf_new[i + decimal + 1 ] = '\n'; ++ buf_new[i + decimal + 2 ] = '\0'; ++ *buf_len_new = strlen(buf_new); ++ DBG_DEBUG(DBG_VERBOSE, "deal decimal[%d] ok, str len:%d, value:%s\n", ++ decimal, *buf_len_new, buf_new); ++ } ++ break; ++ } ++ } ++ if (tmp_len == *buf_len_new) { ++ DBG_DEBUG(DBG_WARN, "deal decimal[%d] failed, use original value:%s\n", decimal, buf_new); ++ } ++ } ++ return DFD_RV_OK; ++} ++ ++static int dfd_get_sensor_info(uint8_t main_dev_id, uint8_t dev_index, uint8_t sensor_type, ++ uint8_t sensor_index, uint8_t sensor_attr, char *buf) ++{ ++ uint32_t key; ++ uint16_t key_index1; ++ uint8_t key_index2; ++ int rv; ++ info_hwmon_buf_f pfunc; ++ ++ key_index1 = DFD_GET_TEMP_SENSOR_KEY1(dev_index, sensor_index); ++ key_index2 = DFD_GET_TEMP_SENSOR_KEY2(main_dev_id, sensor_attr); ++ if (sensor_type == WB_MINOR_DEV_TEMP ) { ++ key = DFD_CFG_KEY(DFD_CFG_ITEM_HWMON_TEMP, key_index1, key_index2); ++ } else if (sensor_type == WB_MINOR_DEV_IN) { ++ key = DFD_CFG_KEY(DFD_CFG_ITEM_HWMON_IN, key_index1, key_index2); ++ } else { ++ DFD_SENSOR_DEBUG(DBG_ERROR, "unknow sensor type:%d.\n",sensor_type); ++ return -DFD_RV_INVALID_VALUE; ++ } ++ ++ DFD_SENSOR_DEBUG(DBG_VERBOSE, "get sensor info.main_dev_id:%d, dev_index:0x%x, sensor_index:0x%x, sensor_attr:0x%x, key:0x%x,\n", ++ main_dev_id, dev_index, sensor_index, sensor_attr, key); ++ ++ pfunc = dfd_deal_hwmon_buf; ++ mem_clear(buf, PAGE_SIZE); ++ rv = dfd_info_get_sensor(key, buf, PAGE_SIZE, pfunc); ++ return rv; ++} ++ ++ssize_t dfd_get_temp_info(uint8_t main_dev_id, uint8_t dev_index, ++ uint8_t temp_index, uint8_t temp_attr, char *buf) ++{ ++ int rv; ++ ++ if (buf == NULL) { ++ DFD_SENSOR_DEBUG(DBG_ERROR, "param error. buf is NULL.\n"); ++ return -DFD_RV_INVALID_VALUE; ++ } ++ ++ rv = dfd_get_sensor_info(main_dev_id, dev_index, WB_MINOR_DEV_TEMP, temp_index, temp_attr, buf); ++ if (rv < 0) { ++ DFD_SENSOR_DEBUG(DBG_ERROR, "get temp info error. rv:%d\n", rv); ++ } else { ++ DFD_SENSOR_DEBUG(DBG_VERBOSE, "get temp info ok.value:%s\n", buf); ++ } ++ return rv; ++} ++ ++ssize_t dfd_get_voltage_info(uint8_t main_dev_id, uint8_t dev_index, ++ uint8_t in_index, uint8_t in_attr, char *buf) ++{ ++ int rv; ++ ++ if (buf == NULL) { ++ DFD_SENSOR_DEBUG(DBG_ERROR, "param error. buf is NULL.\n"); ++ return -DFD_RV_INVALID_VALUE; ++ } ++ ++ rv = dfd_get_sensor_info(main_dev_id, dev_index, WB_MINOR_DEV_IN, in_index, in_attr, buf); ++ if (rv < 0) { ++ DFD_SENSOR_DEBUG(DBG_ERROR, "get voltage info error. rv:%d\n", rv); ++ } else { ++ DFD_SENSOR_DEBUG(DBG_VERBOSE, "get voltage info ok.value:%s\n", buf); ++ } ++ return rv; ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sff_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sff_driver.c +new file mode 100644 +index 000000000..5c1faff97 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sff_driver.c +@@ -0,0 +1,56 @@ ++#include ++ ++#include "./include/dfd_module.h" ++#include "./include/dfd_cfg.h" ++#include "./include/dfd_cfg_info.h" ++#include "./include/dfd_cfg_adapter.h" ++#include "../dev_sysfs/include/sysfs_common.h" ++ ++int g_dfd_sff_dbg_level = 0; ++module_param(g_dfd_sff_dbg_level, int, S_IRUGO | S_IWUSR); ++ ++ssize_t dfd_get_sff_cpld_info(unsigned int sff_index, int cpld_reg_type, char *buf, int len) ++{ ++ int key, ret, value; ++ ++ if(buf == NULL) { ++ DFD_SFF_DEBUG(DBG_ERROR, "param error, buf is NULL. sff_index:%d, cpld_reg_type:%d.\n", ++ sff_index, cpld_reg_type); ++ return -DFD_RV_INVALID_VALUE; ++ } ++ ++ key = DFD_CFG_KEY(DFD_CFG_ITEM_SFF_CPLD_REG, sff_index, cpld_reg_type); ++ ret = dfd_info_get_int(key, &value, NULL); ++ if (ret < 0) { ++ DFD_SFF_DEBUG(DBG_ERROR, "get sff cpld reg error, key:0x%x,ret:%d.\n", key, ret); ++ return ret; ++ } ++ ++ mem_clear(buf, len); ++ return (ssize_t)snprintf(buf, len, "%d\n", value); ++} ++ ++ssize_t dfd_get_sff_dir_name(unsigned int sff_index, char *buf, int buf_len) ++{ ++ int key; ++ char *sff_dir_name; ++ ++ if (buf == NULL) { ++ DFD_SFF_DEBUG(DBG_ERROR, "param error. buf is NULL.sff index:%d", sff_index); ++ return -DFD_RV_INVALID_VALUE; ++ } ++ ++ mem_clear(buf, buf_len); ++ ++ key = DFD_CFG_KEY(DFD_CFG_ITEM_SFF_DIR_NAME, sff_index, 0); ++ sff_dir_name = dfd_ko_cfg_get_item(key); ++ if (sff_dir_name == NULL) { ++ DFD_SFF_DEBUG(DBG_ERROR, "sff dir name config error, key=0x%08x\n", key); ++ return -DFD_RV_NODE_FAIL; ++ } ++ ++ DFD_SFF_DEBUG(DBG_VERBOSE, "%s\n", sff_dir_name); ++ snprintf(buf, buf_len, "%s", sff_dir_name); ++ return strlen(buf); ++ ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_slot_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_slot_driver.c +new file mode 100644 +index 000000000..69c82adab +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_slot_driver.c +@@ -0,0 +1,27 @@ ++#include ++#include ++ ++#include "./include/dfd_module.h" ++#include "./include/dfd_cfg.h" ++#include "./include/dfd_cfg_adapter.h" ++#include "./include/dfd_cfg_info.h" ++#include "../dev_sysfs/include/sysfs_common.h" ++ ++#define SLOT_SIZE (256) ++ ++int g_dfd_slot_dbg_level = 0; ++module_param(g_dfd_slot_dbg_level, int, S_IRUGO | S_IWUSR); ++ ++int dfd_get_slot_present_status(unsigned int slot_index) ++{ ++ int key, ret; ++ int status; ++ ++ key = DFD_CFG_KEY(DFD_CFG_ITEM_DEV_PRESENT_STATUS, WB_MAIN_DEV_SLOT, slot_index); ++ ret = dfd_info_get_int(key, &status, NULL); ++ if (ret < 0) { ++ DFD_SLOT_DEBUG(DBG_ERROR, "get slot status error, key:0x%x\n",key); ++ return ret; ++ } ++ return status; ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg.h +new file mode 100644 +index 000000000..af3de1ca9 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg.h +@@ -0,0 +1,99 @@ ++#ifndef __DFD_CFG_H__ ++#define __DFD_CFG_H__ ++ ++#include ++ ++#define DFD_KO_CFG_FILE_NAME "/etc/plat_sysfs_cfg/cfg_file_name" ++#define DFD_KO_CFG_FILE_DIR "/etc/plat_sysfs_cfg/" ++#define DFD_PUB_CARDTYPE_FILE "/sys/module/platform_common/parameters/dfd_my_type" ++ ++#define DFD_CFG_CMDLINE_MAX_LEN (256) ++#define DFD_CFG_NAME_MAX_LEN (256) ++#define DFD_CFG_VALUE_MAX_LEN (256) ++#define DFD_CFG_STR_MAX_LEN (64) ++#define DFD_CFG_CPLD_NUM_MAX (16) ++#define DFD_PRODUCT_ID_LENGTH (8) ++#define DFD_PID_BUF_LEN (32) ++#define DFD_TEMP_NAME_BUF_LEN (32) ++ ++#define DFD_CFG_EMPTY_VALUE (-1) ++#define DFD_CFG_INVALID_VALUE (0) ++ ++#define DFD_CFG_KEY(item, index1, index2) \ ++ ((((item) & 0xff) << 24) | (((index1) & 0xffff) << 8) | ((index2) & 0xff)) ++#define DFD_CFG_ITEM_ID(key) (((key) >> 24) & 0xff) ++#define DFD_CFG_INDEX1(key) (((key) >> 8) & 0xffff) ++#define DFD_CFG_INDEX2(key) ((key)& 0xff) ++ ++#define INDEX_NOT_EXIST (-1) ++#define INDEX1_MAX (0xffff) ++#define INDEX2_MAX (0xff) ++#define READ_TEMP_FAIL 1000000 ++ ++#define DFD_CFG_ITEM_ALL \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_NONE, "none", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_DEV_NUM, "dev_num", INDEX1_MAX, INDEX2_MAX) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_CPLD_LPC_DEV, "cpld_lpc_dev", INDEX1_MAX, DFD_CFG_CPLD_NUM_MAX) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_INT_END, "end_int", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ ++ \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_CPLD_MODE, "mode_cpld", INDEX1_MAX, DFD_CFG_CPLD_NUM_MAX) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_SFF_DIR_NAME, "sff_dir_name", INDEX1_MAX, INDEX_NOT_EXIST) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_STRING_END, "end_string", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ ++ \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_CPLD_I2C_DEV, "cpld_i2c_dev", INDEX1_MAX, INDEX2_MAX) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_OTHER_I2C_DEV, "other_i2c_dev", INDEX1_MAX, INDEX2_MAX) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_I2C_DEV_END, "end_i2c_dev", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ ++ \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_FAN_ROLL_STATUS, "fan_roll_status", INDEX1_MAX, INDEX2_MAX) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_FAN_SPEED, "fan_speed", INDEX1_MAX, INDEX2_MAX) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_FAN_RATIO, "fan_ratio", INDEX1_MAX, INDEX2_MAX) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_DEV_PRESENT_STATUS, "dev_present_status", INDEX1_MAX, INDEX2_MAX) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_PSU_STATUS, "psu_status", INDEX1_MAX, INDEX2_MAX) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_HWMON_TEMP, "hwmon_temp", INDEX1_MAX, INDEX2_MAX) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_HWMON_IN, "hwmon_in", INDEX1_MAX, INDEX2_MAX) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_SFF_CPLD_REG, "sff_cpld_reg", INDEX1_MAX, INDEX2_MAX) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_INFO_CTRL_END, "end_info_ctrl", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ ++ DFD_CFG_ITEM(DFD_CFG_ITEM_HWMON_POWER, "hwmon_power", INDEX1_MAX, INDEX2_MAX) \ ++ ++#ifdef DFD_CFG_ITEM ++#undef DFD_CFG_ITEM ++#endif ++#define DFD_CFG_ITEM(_id, _name, _index_min, _index_max) _id, ++typedef enum dfd_cfg_item_id_s { ++ DFD_CFG_ITEM_ALL ++} dfd_cfg_item_id_t; ++ ++#define DFD_CFG_ITEM_IS_INT(item_id) \ ++ (((item_id) > DFD_CFG_ITEM_NONE) && ((item_id) < DFD_CFG_ITEM_INT_END)) ++ ++#define DFD_CFG_ITEM_IS_STRING(item_id) \ ++ (((item_id) > DFD_CFG_ITEM_INT_END) && ((item_id) < DFD_CFG_ITEM_STRING_END)) ++ ++#define DFD_CFG_ITEM_IS_I2C_DEV(item_id) \ ++ (((item_id) > DFD_CFG_ITEM_STRING_END) && ((item_id) < DFD_CFG_ITEM_I2C_DEV_END)) ++ ++#define DFD_CFG_ITEM_IS_INFO_CTRL(item_id) \ ++ (((item_id) > DFD_CFG_ITEM_I2C_DEV_END) && ((item_id) < DFD_CFG_ITEM_INFO_CTRL_END)) ++ ++typedef struct index_range_s { ++ int index1_max; ++ int index2_max; ++} index_range_t; ++ ++typedef struct val_convert_node_s { ++ struct list_head lst; ++ int int_val; ++ char str_val[DFD_CFG_STR_MAX_LEN]; ++ int index1; ++ int index2; ++} val_convert_node_t; ++ ++void *dfd_ko_cfg_get_item(int key); ++ ++void dfd_ko_cfg_show_item(int key); ++ ++int32_t dfd_dev_cfg_init(void); ++ ++void dfd_dev_cfg_exit(void); ++ ++#endif /* __DFD_CFG_H__ */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_adapter.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_adapter.h +new file mode 100644 +index 000000000..70d8b536c +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_adapter.h +@@ -0,0 +1,46 @@ ++#ifndef __DFD_CFG_ADAPTER_H__ ++#define __DFD_CFG_ADAPTER_H__ ++ ++#define DFD_KO_CPLD_I2C_RETRY_SLEEP (10) /* ms */ ++#define DFD_KO_CPLD_I2C_RETRY_TIMES (50 / DFD_KO_CPLD_I2C_RETRY_SLEEP) ++ ++#define DFD_KO_CPLD_GET_SLOT(addr) ((addr >> 24) & 0xff) ++#define DFD_KO_CPLD_GET_ID(addr) ((addr >> 16) & 0xff) ++#define DFD_KO_CPLD_GET_INDEX(addr) (addr & 0xffff) ++#define DFD_KO_CPLD_MODE_I2C_STRING "i2c" ++#define DFD_KO_CPLD_MODE_LPC_STRING "lpc" ++ ++typedef struct dfd_i2c_dev_s { ++ int bus; ++ int addr; ++} dfd_i2c_dev_t; ++ ++typedef enum dfd_i2c_dev_mem_s { ++ DFD_I2C_DEV_MEM_BUS, ++ DFD_I2C_DEV_MEM_ADDR, ++ DFD_I2C_DEV_MEM_END ++} dfd_i2c_dev_mem_t; ++ ++typedef enum cpld_mode_e { ++ DFD_CPLD_MODE_I2C, ++ DFD_CPLD_MODE_LPC, ++} cpld_mode_t; ++ ++typedef enum i2c_mode_e { ++ DFD_I2C_MODE_NORMAL_I2C, ++ DFD_I2C_MODE_SMBUS, ++} i2c_mode_t; ++ ++extern char *g_dfd_i2c_dev_mem_str[DFD_I2C_DEV_MEM_END]; ++ ++int32_t dfd_ko_cpld_read(int32_t addr, uint8_t *buf); ++ ++int32_t dfd_ko_cpld_write(int32_t addr, uint8_t val); ++ ++int32_t dfd_ko_i2c_read(int bus, int addr, int offset, uint8_t *buf, uint32_t size); ++ ++int32_t dfd_ko_i2c_write(int bus, int addr, int offset, uint8_t *buf, uint32_t size); ++ ++int32_t dfd_ko_read_file(char *fpath, int32_t addr, uint8_t *val, int32_t read_bytes); ++ ++#endif /* __DFD_CFG_ADAPTER_H__ */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_file.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_file.h +new file mode 100644 +index 000000000..50d7a42d5 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_file.h +@@ -0,0 +1,37 @@ ++#ifndef __DFD_CFG_FILE_H__ ++#define __DFD_CFG_FILE_H__ ++ ++#include ++ ++#define KFILE_RV_OK (0) ++#define KFILE_RV_INPUT_ERR (-1) ++#define KFILE_RV_STAT_FAIL (-2) ++#define KFILE_RV_OPEN_FAIL (-3) ++#define KFILE_RV_MALLOC_FAIL (-4) ++#define KFILE_RV_RD_FAIL (-5) ++#define KFILE_RV_ADDR_ERR (-6) ++#define KFILE_RV_WR_FAIL (-7) ++ ++#define IS_CR(c) ((c) == '\n') ++ ++typedef struct kfile_ctrl_s { ++ int32_t size; ++ int32_t pos; ++ char *buf; ++} kfile_ctrl_t; ++ ++int kfile_open(char *fname, kfile_ctrl_t *kfile_ctrl); ++ ++void kfile_close(kfile_ctrl_t *kfile_ctrl); ++ ++int kfile_gets(char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl); ++ ++int kfile_read(int32_t addr, char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl); ++ ++int kfile_iterate_dir(const char *dir_path, const char *obj_name, char *match_name, int len); ++ ++#if 0 ++ ++int kfile_write(char *fpath, int32_t addr, char *buf, int buf_size); ++#endif ++#endif /* __DFD_CFG_FILE_H__ */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_info.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_info.h +new file mode 100644 +index 000000000..88e8f92c1 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_info.h +@@ -0,0 +1,119 @@ ++#ifndef __DFD_CFG_INFO_H__ ++#define __DFD_CFG_INFO_H__ ++ ++#include ++ ++typedef int (*info_num_buf_to_value_f)(uint8_t *num_buf, int buf_len, int *num_val); ++ ++typedef int (*info_buf_to_buf_f)(uint8_t *buf, int buf_len, uint8_t *buf_new, int *buf_len_new); ++ ++#define IS_INFO_FRMT_BIT(frmt) ((frmt) == INFO_FRMT_BIT) ++#define IS_INFO_FRMT_BYTE(frmt) (((frmt) == INFO_FRMT_BYTE) || ((frmt) == INFO_FRMT_NUM_BYTES)) ++#define IS_INFO_FRMT_NUM_STR(frmt) ((frmt) == INFO_FRMT_NUM_STR) ++#define IS_INFO_FRMT_NUM_BUF(frmt) ((frmt) == INFO_FRMT_NUM_BUF) ++#define IS_INFO_FRMT_BUF(frmt) ((frmt) == INFO_FRMT_BUF) ++ ++#define INFO_INT_MAX_LEN (32) ++#define INFO_INT_LEN_VALAID(len) (((len) > 0) && ((len) < INFO_INT_MAX_LEN)) ++ ++#define INFO_BUF_MAX_LEN (128) ++#define INFO_BUF_LEN_VALAID(len) (((len) > 0) && ((len) < INFO_BUF_MAX_LEN)) ++ ++#define INFO_BIT_OFFSET_VALID(bit_offset) (((bit_offset) >= 0) && ((bit_offset) < 8)) ++ ++typedef enum info_ctrl_mode_e { ++ INFO_CTRL_MODE_NONE, ++ INFO_CTRL_MODE_CFG, ++ INFO_CTRL_MODE_CONS, ++ INFO_CTRL_MODE_TLV, ++ INFO_CTRL_MODE_SRT_CONS, ++ INFO_CTRL_MODE_END ++} info_ctrl_mode_t; ++ ++typedef enum info_frmt_e { ++ INFO_FRMT_NONE, ++ INFO_FRMT_BIT, ++ INFO_FRMT_BYTE, ++ INFO_FRMT_NUM_BYTES, ++ INFO_FRMT_NUM_STR, ++ INFO_FRMT_NUM_BUF, ++ INFO_FRMT_BUF, ++ INFO_FRMT_END ++} info_frmt_t; ++ ++typedef enum info_src_e { ++ INFO_SRC_NONE, ++ INFO_SRC_CPLD, ++ INFO_SRC_FPGA, ++ INFO_SRC_OTHER_I2C, ++ INFO_SRC_FILE, ++ INFO_SRC_END ++} info_src_t; ++ ++typedef enum info_pola_e { ++ INFO_POLA_NONE, ++ INFO_POLA_POSI, ++ INFO_POLA_NEGA, ++ INFO_POLA_END ++} info_pola_t; ++ ++#define INFO_FPATH_MAX_LEN (128) ++#define INFO_STR_CONS_MAX_LEN (64) ++typedef struct info_ctrl_s { ++ info_ctrl_mode_t mode; ++ int32_t int_cons; ++ info_src_t src; ++ info_frmt_t frmt; ++ info_pola_t pola; ++ char fpath[INFO_FPATH_MAX_LEN]; ++ int32_t addr; ++ int32_t len; ++ int32_t bit_offset; ++ char str_cons[INFO_STR_CONS_MAX_LEN]; ++ int32_t int_extra1; ++ int32_t int_extra2; ++ int32_t int_extra3; /* cpld voltage mode */ ++} info_ctrl_t; ++ ++typedef enum info_ctrl_mem_s { ++ INFO_CTRL_MEM_MODE, ++ INFO_CTRL_MEM_INT_CONS, ++ INFO_CTRL_MEM_SRC, ++ INFO_CTRL_MEM_FRMT, ++ INFO_CTRL_MEM_POLA, ++ INFO_CTRL_MEM_FPATH, ++ INFO_CTRL_MEM_ADDR, ++ INFO_CTRL_MEM_LEN, ++ INFO_CTRL_MEM_BIT_OFFSET, ++ INFO_CTRL_MEM_STR_CONS, ++ INFO_CTRL_MEM_INT_EXTRA1, ++ INFO_CTRL_MEM_INT_EXTRA2, ++ INFO_CTRL_MEM_INT_EXTRA3, ++ INFO_CTRL_MEM_END ++} info_ctrl_mem_t; ++ ++typedef enum sensor_format_mem_s { ++ LINEAR11 = 1, ++ LINEAR16, ++ TMP464, ++ MAC_TH5, ++ MAC_TD3 ++} sensor_format_mem_t; ++ ++typedef int (*info_hwmon_buf_f)(uint8_t *buf, int buf_len, uint8_t *buf_new, int *buf_len_new, info_ctrl_t *info_ctrl); ++ ++extern char *g_info_ctrl_mem_str[INFO_CTRL_MEM_END]; ++extern char *g_info_src_str[INFO_SRC_END]; ++extern char *g_info_frmt_str[INFO_FRMT_END]; ++extern char *g_info_pola_str[INFO_POLA_END]; ++extern char *g_info_ctrl_mode_str[INFO_CTRL_MODE_END]; ++ ++int dfd_info_get_int(int key, int *ret, info_num_buf_to_value_f pfun); ++ ++int dfd_info_get_buf(int key, uint8_t *buf, int buf_len, info_buf_to_buf_f pfun); ++ ++int dfd_info_set_int(int key, int val); ++ ++int dfd_info_get_sensor(uint32_t key, char *buf, int buf_len, info_hwmon_buf_f pfun); ++ ++#endif /* __DFD_CFG_INFO_H__ */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_listnode.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_listnode.h +new file mode 100644 +index 000000000..955dfa96e +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_listnode.h +@@ -0,0 +1,30 @@ ++#ifndef __DFD_CFG_LISTNODE_H__ ++#define __DFD_CFG_LISTNODE_H__ ++ ++#include ++ ++#define LNODE_RV_OK (0) ++#define LNODE_RV_INPUT_ERR (-1) ++#define LNODE_RV_NODE_EXIST (-2) ++#define LNODE_RV_NOMEM (-3) ++ ++typedef struct lnode_root_s { ++ struct list_head root; ++} lnode_root_t; ++ ++typedef struct lnode_node_s { ++ struct list_head lst; ++ ++ int key; ++ void *data; ++} lnode_node_t; ++ ++void *lnode_find_node(lnode_root_t *root, int key); ++ ++int lnode_insert_node(lnode_root_t *root, int key, void *data); ++ ++int lnode_init_root(lnode_root_t *root); ++ ++void lnode_free_list(lnode_root_t *root); ++ ++#endif /* __DFD_CFG_LISTNODE_H__ */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_fan_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_fan_driver.h +new file mode 100644 +index 000000000..1065fd9ee +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_fan_driver.h +@@ -0,0 +1,18 @@ ++#ifndef _DFD_FAN_DRIVER_H_ ++#define _DFD_FAN_DRIVER_H_ ++ ++ssize_t dfd_get_fan_speed(unsigned int fan_index, unsigned int motor_index,unsigned int *speed); ++ ++int dfd_set_fan_pwm(unsigned int fan_index, unsigned int motor_index, int pwm); ++ ++int dfd_get_fan_pwm(unsigned int fan_index, unsigned int motor_index, int *pwm); ++ ++int dfd_get_fan_present_status(unsigned int fan_index); ++ ++int dfd_get_fan_roll_status(unsigned int fan_index, unsigned int motor_index); ++ ++int dfd_get_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int *level); ++ ++int dfd_set_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int level); ++ ++#endif /* _DFD_FAN_DRIVER_H_ */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_module.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_module.h +new file mode 100644 +index 000000000..a547255cf +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_module.h +@@ -0,0 +1,96 @@ ++#ifndef __DFD_MODULE_H__ ++#define __DFD_MODULE_H__ ++ ++typedef enum dfd_rv_s { ++ DFD_RV_OK = 0, ++ DFD_RV_INIT_ERR = 1, ++ DFD_RV_SLOT_INVALID = 2, ++ DFD_RV_MODE_INVALID = 3, ++ DFD_RV_MODE_NOTSUPPORT = 4, ++ DFD_RV_TYPE_ERR = 5, ++ DFD_RV_DEV_NOTSUPPORT = 6, ++ DFD_RV_DEV_FAIL = 7, ++ DFD_RV_INDEX_INVALID = 8, ++ DFD_RV_NO_INTF = 9, ++ DFD_RV_NO_NODE = 10, ++ DFD_RV_NODE_FAIL = 11, ++ DFD_RV_INVALID_VALUE = 12, ++ DFD_RV_NO_MEMORY = 13, ++} dfd_rv_t; ++ ++typedef enum { ++ DBG_VERBOSE = 0x01, ++ DBG_WARN = 0x02, ++ DBG_ERROR = 0x04, ++} dbg_level_t; ++ ++extern int g_dfd_dbg_level; ++extern int g_dfd_fan_dbg_level; ++extern int g_dfd_slot_dbg_level; ++extern int g_dfd_sensor_dbg_level; ++extern int g_dfd_psu_dbg_level; ++extern int g_dfd_sff_dbg_level; ++ ++#define DBG_DEBUG(level, fmt, arg...) do { \ ++ if (g_dfd_dbg_level & level) { \ ++ if(level >= DBG_ERROR) { \ ++ printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ ++ } else { \ ++ printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ ++ } \ ++ } \ ++} while (0) ++ ++#define DFD_FAN_DEBUG(level, fmt, arg...) do { \ ++ if (g_dfd_fan_dbg_level & level) { \ ++ if(level >= DBG_ERROR) { \ ++ printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ ++ } else { \ ++ printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ ++ } \ ++ } \ ++} while (0) ++ ++#define DFD_SLOT_DEBUG(level, fmt, arg...) do { \ ++ if (g_dfd_slot_dbg_level & level) { \ ++ if(level >= DBG_ERROR) { \ ++ printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ ++ } else { \ ++ printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ ++ } \ ++ } \ ++} while (0) ++ ++#define DFD_SENSOR_DEBUG(level, fmt, arg...) do { \ ++ if (g_dfd_sensor_dbg_level & level) { \ ++ if(level >= DBG_ERROR) { \ ++ printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ ++ } else { \ ++ printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ ++ } \ ++ } \ ++} while (0) ++ ++#define DFD_PSU_DEBUG(level, fmt, arg...) do { \ ++ if (g_dfd_psu_dbg_level & level) { \ ++ if(level >= DBG_ERROR) { \ ++ printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ ++ } else { \ ++ printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ ++ } \ ++ } \ ++} while (0) ++ ++#define DFD_SFF_DEBUG(level, fmt, arg...) do { \ ++ if (g_dfd_sff_dbg_level & level) { \ ++ if(level >= DBG_ERROR) { \ ++ printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ ++ } else { \ ++ printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ ++ } \ ++ } \ ++} while (0) ++ ++int dfd_get_dev_number(unsigned int main_dev_id, unsigned int minor_dev_id); ++ ++#endif /* __DFD_MODULE_H__ */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_psu_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_psu_driver.h +new file mode 100644 +index 000000000..ce7199660 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_psu_driver.h +@@ -0,0 +1,10 @@ ++#ifndef _DFD_PSU_DRIVER_H_ ++#define _DFD_PSU_DRIVER_H_ ++ ++int dfd_get_psu_present_status(unsigned int psu_index); ++ ++int dfd_get_psu_output_status(unsigned int psu_index); ++ ++int dfd_get_psu_alert_status(unsigned int psu_index); ++ ++#endif /* _DFD_PSU_DRIVER_H_ */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sensors_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sensors_driver.h +new file mode 100644 +index 000000000..16733b260 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sensors_driver.h +@@ -0,0 +1,10 @@ ++#ifndef _DFD_SENSORS_DRIVER_H_ ++#define _DFD_SENSORS_DRIVER_H_ ++ ++ssize_t dfd_get_temp_info(uint8_t main_dev_id, uint8_t dev_index, ++ uint8_t temp_index, uint8_t temp_attr, char *buf); ++ ++ssize_t dfd_get_voltage_info(uint8_t main_dev_id, uint8_t dev_index, ++ uint8_t in_index, uint8_t in_attr, char *buf); ++ ++#endif /* _DFD_SENSORS_DRIVER_H_ */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sff_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sff_driver.h +new file mode 100644 +index 000000000..7107b72ee +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sff_driver.h +@@ -0,0 +1,8 @@ ++#ifndef _DFD_SFF_DRIVER_H_ ++#define _DFD_SFF_DRIVER_H_ ++ ++ssize_t dfd_get_sff_cpld_info(unsigned int sff_index, int cpld_reg_type, char *buf, int len); ++ ++ssize_t dfd_get_sff_dir_name(unsigned int sff_index, char *buf, int buf_len); ++ ++#endif /* _DFD_SFF_DRIVER_H_ */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_slot_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_slot_driver.h +new file mode 100644 +index 000000000..c68caecd2 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_slot_driver.h +@@ -0,0 +1,6 @@ ++#ifndef _DFD_SLOT_DRIVER_H_ ++#define _DFD_SLOT_DRIVER_H_ ++ ++int dfd_get_slot_present_status(unsigned int slot_index); ++ ++#endif /* _DFD_SLOT_DRIVER_H_ */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/Makefile +new file mode 100644 +index 000000000..1a1044bb1 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/Makefile +@@ -0,0 +1,21 @@ ++PWD = $(shell pwd) ++ ++EXTRA_CFLAGS:= -I$(M)/include ++EXTRA_CFLAGS+= -Wall ++KBUILD_EXTRA_SYMBOLS += $(PLAT_SYSFS_DIR)/dev_cfg/Module.symvers ++ ++obj-m := plat_switch.o ++obj-m += plat_fan.o ++obj-m += plat_psu.o ++obj-m += plat_sff.o ++obj-m += plat_sensor.o ++obj-m += plat_slot.o ++ ++all: ++ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules ++ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi ++ cp -p $(PWD)/*.ko $(module_out_put_dir) ++clean: ++ rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/*.mod ++ rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order ++ rm -rf $(PWD)/.tmp_versions +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/plat_switch.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/plat_switch.h +new file mode 100644 +index 000000000..bbd813e87 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/plat_switch.h +@@ -0,0 +1,86 @@ ++#ifndef _PLAT_SWITCH_H_ ++#define _PLAT_SWITCH_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++enum LOG_LEVEL{ ++ INFO = 0x1, ++ ERR = 0x2, ++ DBG = 0x4, ++ ALL = 0xf ++}; ++ ++#define LOG_INFO(_prefix, fmt, args...) \ ++ do { \ ++ if (g_loglevel & INFO) \ ++ { \ ++ printk( KERN_INFO _prefix "%s "fmt, __FUNCTION__, ##args); \ ++ } \ ++ } while (0) ++ ++#define LOG_ERR(_prefix, fmt, args...) \ ++ do { \ ++ if (g_loglevel & ERR) \ ++ { \ ++ printk( KERN_ERR _prefix "%s "fmt, __FUNCTION__, ##args); \ ++ } \ ++ } while (0) ++ ++#define LOG_DBG(_prefix, fmt, args...) \ ++ do { \ ++ if (g_loglevel & DBG) \ ++ { \ ++ printk( KERN_DEBUG _prefix "%s "fmt, __FUNCTION__, ##args); \ ++ } \ ++ } while (0) ++ ++#define check_pfun(p) \ ++ do { \ ++ if (p == NULL) { \ ++ printk( KERN_ERR "%s, %s = NULL.\n", __FUNCTION__, #p); \ ++ return -ENOSYS; \ ++ } \ ++ }while(0) ++ ++#define check_p(p) check_pfun(p) ++ ++#define to_switch_obj(x) container_of(x, struct switch_obj, kobj) ++#define to_switch_attr(x) container_of(x, struct switch_attribute, attr) ++#define to_switch_device_attr(x) container_of(x, struct switch_device_attribute, switch_attr) ++ ++#define SWITCH_ATTR(_name, _mode, _show, _store, _type) \ ++ { .switch_attr = __ATTR(_name, _mode, _show, _store), \ ++ .type = _type } ++ ++#define SWITCH_DEVICE_ATTR(_name, _mode, _show, _store, _type) \ ++struct switch_device_attribute switch_dev_attr_##_name \ ++ = SWITCH_ATTR(_name, _mode, _show, _store, _type) ++ ++struct switch_obj { ++ struct kobject kobj; ++ unsigned int index; ++}; ++ ++/* a custom attribute that works just for a struct switch_obj. */ ++struct switch_attribute { ++ struct attribute attr; ++ ssize_t (*show)(struct switch_obj *foo, struct switch_attribute *attr, char *buf); ++ ssize_t (*store)(struct switch_obj *foo, struct switch_attribute *attr, const char *buf, size_t count); ++}; ++ ++struct switch_device_attribute { ++ struct switch_attribute switch_attr; ++ int type; ++}; ++ ++extern struct switch_obj *wb_plat_kobject_create(const char *name, struct kobject *parent); ++extern void wb_plat_kobject_delete(struct switch_obj **obj); ++ ++#endif /* _PLAT_SWITCH_H_ */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/sysfs_common.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/sysfs_common.h +new file mode 100644 +index 000000000..5b73731e1 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/sysfs_common.h +@@ -0,0 +1,90 @@ ++#ifndef _SYSFS_COMMON_H_ ++#define _SYSFS_COMMON_H_ ++ ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++ ++#define DIR_NAME_MAX_LEN (64) ++ ++#define WB_SYSFS_DEV_ERROR "NA" ++/* sysfs directory name */ ++#define FAN_SYSFS_NAME "fan" ++#define PSU_SYSFS_NAME "psu" ++#define SLOT_SYSFS_NAME "slot" ++#define VOLTAGE_SYSFS_NAME "in" ++#define TEMP_SYSFS_NAME "temp" ++#define SFF_SYSFS_NAME "sff" ++ ++typedef enum wb_main_dev_type_e { ++ WB_MAIN_DEV_MAINBOARD = 0, ++ WB_MAIN_DEV_FAN = 1, ++ WB_MAIN_DEV_PSU = 2, ++ WB_MAIN_DEV_SFF = 3, ++ WB_MAIN_DEV_CPLD = 4, ++ WB_MAIN_DEV_SLOT = 5, ++} wb_main_dev_type_t; ++ ++typedef enum wb_minor_dev_type_e { ++ WB_MINOR_DEV_NONE = 0, /* None */ ++ WB_MINOR_DEV_TEMP = 1, ++ WB_MINOR_DEV_IN = 2, ++ WB_MINOR_DEV_CURR = 3, ++ WB_MINOR_DEV_POWER = 4, ++ WB_MINOR_DEV_MOTOR = 5, ++ WB_MINOR_DEV_PSU = 6, ++} wb_minor_dev_type_t; ++ ++typedef enum wb_sensor_type_e { ++ WB_SENSOR_INPUT = 0, ++ WB_SENSOR_ALIAS = 1, ++ WB_SENSOR_TYPE = 2, ++ WB_SENSOR_MAX = 3, ++ WB_SENSOR_MAX_HYST = 4, ++ WB_SENSOR_MIN = 5, ++ WB_SENSOR_CRIT = 6, ++} wb_sensor_type_t; ++ ++typedef enum wb_sff_cpld_attr_e { ++ WB_SFF_POWER_ON = 0x01, ++ WB_SFF_TX_FAULT, ++ WB_SFF_TX_DIS, ++ WB_SFF_PRE_N, ++ WB_SFF_RX_LOS, ++ WB_SFF_RESET, ++ WB_SFF_LPMODE, ++ WB_SFF_MODULE_PRESENT, ++ WB_SFF_INTERRUPT, ++} wb_sff_cpld_attr_t; ++ ++struct switch_drivers_t{ ++ /* device */ ++ int (*get_dev_number) (unsigned int main_dev_id, unsigned int minor_dev_id); ++ /* fan */ ++ int (*get_fan_number) (void); ++ ssize_t (*get_fan_speed) (unsigned int fan_index, unsigned int motor_index, unsigned int *speed); ++ int (*get_fan_pwm) (unsigned int fan_index, unsigned int motor_index, int *pwm); ++ int (*set_fan_pwm) (unsigned int fan_index, unsigned int motor_index, int pwm); ++ int (*get_fan_present_status)(unsigned int fan_index); ++ int (*get_fan_roll_status)(unsigned int fan_index, unsigned int motor_index); ++ int (*get_fan_speed_level)(unsigned int fan_index, unsigned int motor_index, int *level); ++ int (*set_fan_speed_level)(unsigned int fan_index, unsigned int motor_index, int level); ++ /* slot */ ++ int (*get_slot_present_status) (unsigned int slot_index); ++ /* sensors */ ++ ssize_t (*get_temp_info)( uint8_t main_dev_id, uint8_t dev_index, ++ uint8_t temp_index, uint8_t temp_attr, char *buf); ++ ssize_t (*get_voltage_info)( uint8_t main_dev_id, uint8_t dev_index, ++ uint8_t in_index, uint8_t in_attr, char *buf); ++ /* psu */ ++ int (*get_psu_present_status)(unsigned int psu_index); ++ int (*get_psu_output_status)(unsigned int psu_index); ++ int (*get_psu_alert_status)(unsigned int psu_index); ++ /* sff */ ++ ssize_t (*get_sff_cpld_info)( unsigned int sff_index, int cpld_reg_type, char *buf, int len); ++ ssize_t (*get_sff_dir_name)(unsigned int sff_index, char *buf, int buf_len); ++}; ++ ++extern struct switch_drivers_t * dfd_plat_driver_get(void); ++ ++#endif /*_SYSFS_COMMON_H_ */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_fan.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_fan.c +new file mode 100644 +index 000000000..931c7c243 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_fan.c +@@ -0,0 +1,501 @@ ++/* ++ * plat_fan.c ++ * ++ * This module create fan kobjects and attributes in /sys/wb_plat/fan ++ * ++ */ ++ ++#include ++ ++#include "./include/plat_switch.h" ++#include "./include/sysfs_common.h" ++ ++#define FAN_INFO(fmt, args...) LOG_INFO("fan: ", fmt, ##args) ++#define FAN_ERR(fmt, args...) LOG_ERR("fan: ", fmt, ##args) ++#define FAN_DBG(fmt, args...) LOG_DBG("fan: ", fmt, ##args) ++ ++struct motor_obj_t{ ++ struct switch_obj *obj; ++}; ++ ++struct fan_obj_t{ ++ unsigned int motor_number; ++ struct motor_obj_t *motor; ++ struct switch_obj *obj; ++}; ++ ++struct fan_t{ ++ unsigned int fan_number; ++ struct fan_obj_t *fan; ++}; ++ ++static int g_loglevel = 0; ++static struct fan_t g_fan; ++static struct switch_obj *g_fan_obj = NULL; ++static struct switch_drivers_t *g_drv = NULL; ++ ++static ssize_t fan_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_fan.fan_number); ++} ++ ++static ssize_t fan_motor_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int index; ++ ++ index = obj->index; ++ FAN_DBG("fan_motor_number_show,fan index:%d\n",index); ++ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_fan.fan[index-1].motor_number); ++} ++ ++static ssize_t fan_roll_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int fan_index, motor_index; ++ struct switch_obj *p_obj; ++ int ret; ++ ++ check_p(g_drv); ++ check_p(g_drv->get_fan_roll_status); ++ ++ p_obj = to_switch_obj(obj->kobj.parent); ++ check_p(p_obj); ++ ++ fan_index = p_obj->index; ++ motor_index = obj->index; ++ ++ ret = g_drv->get_fan_roll_status(fan_index, motor_index); ++ if (ret < 0 ) { ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); ++ } ++ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); ++} ++ ++static ssize_t fan_present_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int fan_index; ++ int ret; ++ ++ fan_index = obj->index; ++ FAN_DBG("fan_present_status_show, fan index:%d\n",fan_index); ++ check_p(g_drv); ++ check_p(g_drv->get_fan_present_status); ++ ++ ret = g_drv->get_fan_present_status(fan_index); ++ if(ret < 0) { ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); ++ } ++ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); ++} ++ ++static ssize_t fan_speed_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int fan_index, motor_index, speed; ++ int ret; ++ struct switch_obj *p_obj; ++ ++ check_p(g_drv); ++ check_p(g_drv->get_fan_speed); ++ ++ p_obj = to_switch_obj(obj->kobj.parent); ++ check_p(p_obj); ++ ++ fan_index = p_obj->index; ++ motor_index = obj->index; ++ ++ ret = g_drv->get_fan_speed(fan_index, motor_index, &speed); ++ if(ret < 0) { ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); ++ } ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", speed); ++} ++ ++static ssize_t fan_motor_ratio_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int fan_index, motor_index; ++ struct switch_obj *p_obj; ++ int ret, pwm; ++ ++ check_p(g_drv); ++ check_p(g_drv->get_fan_pwm); ++ ++ p_obj = to_switch_obj(obj->kobj.parent); ++ check_p(p_obj); ++ fan_index = p_obj->index; ++ motor_index = obj->index; ++ ret = g_drv->get_fan_pwm(fan_index, motor_index, &pwm); ++ ++ if (ret < 0 ) { ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); ++ } ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", pwm); ++} ++ ++static ssize_t fan_motor_ratio_store(struct switch_obj *obj, struct switch_attribute *attr, ++ const char* buf, size_t count) ++{ ++ unsigned int fan_index, motor_index; ++ struct switch_obj *p_obj; ++ int ret, pwm; ++ ++ check_p(g_drv); ++ check_p(g_drv->set_fan_pwm); ++ ++ p_obj = to_switch_obj(obj->kobj.parent); ++ check_p(p_obj); ++ ++ fan_index = p_obj->index; ++ motor_index = obj->index; ++ sscanf(buf, "%d", &pwm); ++ ++ if (pwm < 0 || pwm > 100) { ++ FAN_ERR("can not set pwm = %d.\n", pwm); ++ return -EINVAL; ++ } ++ ret = g_drv->set_fan_pwm(fan_index, motor_index, pwm); ++ if (ret < 0) { ++ FAN_ERR("can not set pwm = %d.\n", pwm); ++ return -EIO; ++ } ++ return count; ++} ++ ++/************************************fan dir and attrs*******************************************/ ++static struct switch_attribute fan_number_att = __ATTR(num_fans, S_IRUGO, fan_number_show, NULL); ++ ++static struct attribute *fan_dir_attrs[] = { ++ &fan_number_att.attr, ++ NULL, ++}; ++ ++static struct attribute_group fan_root_attr_group = { ++ .attrs = fan_dir_attrs, ++}; ++ ++/*******************************fan1 fan2 dir and attrs*******************************************/ ++static struct switch_attribute fan_num_motors_att = __ATTR(num_motors, S_IRUGO, fan_motor_number_show, NULL); ++static struct switch_attribute fan_present_att = __ATTR(present, S_IRUGO, fan_present_status_show, NULL); ++ ++static struct attribute *fan_attrs[] = { ++ &fan_num_motors_att.attr, ++ &fan_present_att.attr, ++ NULL, ++}; ++ ++static struct attribute_group fan_attr_group = { ++ .attrs = fan_attrs, ++}; ++ ++/*******************************motor0 motor1 dir and attrs*******************************************/ ++static struct switch_attribute motor_speed_att = __ATTR(speed, S_IRUGO, fan_speed_show, NULL); ++static struct switch_attribute motor_status_att = __ATTR(status, S_IRUGO, fan_roll_status_show, NULL); ++static struct switch_attribute motor_ratio_att = __ATTR(ratio, S_IRUGO | S_IWUSR, fan_motor_ratio_show, fan_motor_ratio_store); ++ ++static struct attribute *motor_attrs[] = { ++ &motor_speed_att.attr, ++ &motor_status_att.attr, ++ &motor_ratio_att.attr, ++ NULL, ++}; ++ ++static struct attribute_group motor_attr_group = { ++ .attrs = motor_attrs, ++}; ++ ++static void fanindex_single_motor_remove_kobj_and_attrs(struct fan_obj_t * curr_fan, unsigned int motor_index) ++{ ++ struct motor_obj_t *curr_motor; /* point to motor0 motor1...*/ ++ ++ curr_motor = &curr_fan->motor[motor_index]; ++ if (curr_motor->obj) { ++ sysfs_remove_group(&curr_motor->obj->kobj, &motor_attr_group); ++ wb_plat_kobject_delete(&curr_motor->obj); ++ FAN_DBG("delete fan:%d motor%d.\n", curr_fan->obj->index, motor_index); ++ } ++ return; ++} ++ ++static int fanindex_single_motor_create_kobj_and_attrs(struct fan_obj_t * curr_fan, unsigned int motor_index) ++{ ++ char name[DIR_NAME_MAX_LEN]; ++ struct motor_obj_t *curr_motor; /* point to motor0 motor1...*/ ++ ++ FAN_DBG("create fan_index:%d, motor%d ...\n", curr_fan->obj->index, motor_index); ++ ++ curr_motor = &curr_fan->motor[motor_index]; ++ mem_clear(name, sizeof(name)); ++ snprintf(name, sizeof(name), "motor%d", motor_index); ++ curr_motor->obj = wb_plat_kobject_create(name, &curr_fan->obj->kobj); ++ if (!curr_motor->obj) { ++ FAN_ERR("create fan_index:%d, motor%d object error!\n", curr_fan->obj->index, motor_index); ++ return -EBADRQC; ++ } ++ curr_motor->obj->index = motor_index; ++ if (sysfs_create_group(&curr_motor->obj->kobj, &motor_attr_group) != 0) { ++ FAN_ERR("create fan_index:%d, motor%d attrs error.\n", curr_fan->obj->index, motor_index); ++ wb_plat_kobject_delete(&curr_motor->obj); ++ return -EBADRQC; ++ } ++ FAN_DBG("create fan_index:%d, motor%d ok.\n", curr_fan->obj->index, motor_index); ++ return 0; ++} ++ ++static int fanindex_motor_create_kobj_and_attrs(struct fan_obj_t * curr_fan, int motor_num) ++{ ++ int motor_index, i; ++ ++ curr_fan->motor = kzalloc(sizeof(struct motor_obj_t) * motor_num, GFP_KERNEL); ++ if (!curr_fan->motor) { ++ FAN_ERR("kzalloc motor error, fan index = %d, motor number = %d.\n", curr_fan->obj->index, motor_num); ++ return -ENOMEM; ++ } ++ curr_fan->motor_number = motor_num; ++ for (motor_index = 0; motor_index < motor_num; motor_index++) { ++ if (fanindex_single_motor_create_kobj_and_attrs(curr_fan, motor_index) != 0) { ++ goto motor_error; ++ } ++ } ++ return 0; ++motor_error: ++ for(i = motor_index - 1; i >= 0; i--) { ++ fanindex_single_motor_remove_kobj_and_attrs(curr_fan, i); ++ } ++ if(curr_fan->motor) { ++ kfree(curr_fan->motor); ++ curr_fan->motor = NULL; ++ } ++ return -EBADRQC; ++} ++ ++static void fanindex_motor_remove_kobj_and_attrs(struct fan_obj_t *curr_fan, int motor_num) ++{ ++ int motor_index; ++ ++ for (motor_index = motor_num - 1; motor_index >= 0; motor_index--) { ++ fanindex_single_motor_remove_kobj_and_attrs(curr_fan, motor_index); ++ } ++ return; ++} ++ ++static int fan_motor_create(void) ++{ ++ int fan_num, motor_num; ++ unsigned int fan_index, i; ++ struct fan_obj_t *curr_fan; /* point to fan1 fan2...*/ ++ ++ check_p(g_drv->get_dev_number); ++ ++ motor_num = g_drv->get_dev_number(WB_MAIN_DEV_FAN, WB_MINOR_DEV_MOTOR); ++ if (motor_num <= 0) { ++ FAN_ERR("get fan motor number error, motor_num:%d error.\n", motor_num); ++ return -ENODEV; ++ } ++ ++ fan_num = g_fan.fan_number; ++ for (fan_index = 1; fan_index <= fan_num; fan_index++) { ++ curr_fan = &g_fan.fan[fan_index - 1]; ++ if (fanindex_motor_create_kobj_and_attrs(curr_fan, motor_num) != 0) { ++ goto error; ++ } ++ } ++ return 0; ++error: ++ for (i = fan_index - 1; i > 0; i--) { ++ curr_fan = &g_fan.fan[i - 1]; ++ motor_num = curr_fan->motor_number; ++ fanindex_motor_remove_kobj_and_attrs(curr_fan, motor_num); ++ } ++ return -EBADRQC; ++} ++ ++static void fan_motor_remove(void) ++{ ++ unsigned int fan_index; ++ struct fan_obj_t *curr_fan; ++ ++ if (g_fan.fan) { ++ for (fan_index = g_fan.fan_number; fan_index > 0; fan_index--) { ++ curr_fan = &g_fan.fan[fan_index - 1]; ++ if (curr_fan->motor) { ++ fanindex_motor_remove_kobj_and_attrs(curr_fan, curr_fan->motor_number); ++ kfree(curr_fan->motor); ++ curr_fan->motor = NULL; ++ curr_fan->motor_number = 0; ++ } ++ } ++ } ++ return; ++} ++ ++static void fan_sub_single_remove_kobj_and_attrs(unsigned int index) ++{ ++ struct fan_obj_t *curr_fan; ++ ++ curr_fan = &g_fan.fan[index - 1]; ++ if (curr_fan->obj) { ++ sysfs_remove_group(&curr_fan->obj->kobj, &fan_attr_group); ++ wb_plat_kobject_delete(&curr_fan->obj); ++ FAN_DBG("delete fan%d.\n", index); ++ } ++ return; ++} ++ ++static int fan_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) ++{ ++ char name[DIR_NAME_MAX_LEN]; ++ struct fan_obj_t *curr_fan; ++ ++ curr_fan = &g_fan.fan[index - 1]; ++ FAN_DBG("create fan%d ...\n", index); ++ mem_clear(name, sizeof(name)); ++ snprintf(name, sizeof(name), "fan%d", index); ++ curr_fan->obj = wb_plat_kobject_create(name, parent); ++ if (!curr_fan->obj) { ++ FAN_ERR("create fan%d object error!\n", index); ++ return -EBADRQC; ++ } ++ curr_fan->obj->index = index; ++ if (sysfs_create_group(&curr_fan->obj->kobj, &fan_attr_group) != 0) { ++ FAN_ERR("create fan%d attrs error.\n", index); ++ wb_plat_kobject_delete(&curr_fan->obj); ++ return -EBADRQC; ++ } ++ FAN_DBG("create fan%d ok.\n", index); ++ return 0; ++} ++ ++static int fan_sub_create_kobj_and_attrs(struct kobject *parent, int fan_num) ++{ ++ unsigned int fan_index, i; ++ ++ g_fan.fan = kzalloc(sizeof(struct fan_obj_t) * fan_num, GFP_KERNEL); ++ if (!g_fan.fan) { ++ FAN_ERR("kzalloc fan.fan error, fan number = %d.\n", fan_num); ++ return -ENOMEM; ++ } ++ ++ for (fan_index = 1; fan_index <= fan_num; fan_index++) { ++ if(fan_sub_single_create_kobj_and_attrs(parent, fan_index) != 0 ) { ++ goto error; ++ } ++ } ++ return 0; ++error: ++ for (i = fan_index - 1; i > 0; i--) { ++ fan_sub_single_remove_kobj_and_attrs(i); ++ } ++ if (g_fan.fan) { ++ kfree(g_fan.fan); ++ g_fan.fan = NULL; ++ } ++ return -EBADRQC; ++} ++ ++static int fan_sub_create(void) ++{ ++ int ret, fan_num; ++ ++ check_p(g_drv->get_dev_number); ++ fan_num = g_drv->get_dev_number(WB_MAIN_DEV_FAN, WB_MINOR_DEV_NONE); ++ if (fan_num < 0) { ++ FAN_ERR("fan number = %d error.\n", fan_num); ++ return -EINVAL; ++ } ++ g_fan.fan_number = fan_num; ++ ret = fan_sub_create_kobj_and_attrs(&g_fan_obj->kobj, fan_num); ++ return ret; ++} ++ ++static void fan_sub_remove(void) ++{ ++ unsigned int fan_index; ++ ++ if (g_fan.fan) { ++ for (fan_index = g_fan.fan_number; fan_index > 0; fan_index--) { ++ fan_sub_single_remove_kobj_and_attrs(fan_index); ++ } ++ kfree(g_fan.fan); ++ } ++ mem_clear(&g_fan, sizeof(struct fan_t)); ++ return; ++} ++ ++static int fan_root_create(void) ++{ ++ g_fan_obj = wb_plat_kobject_create("fan", NULL); ++ if (!g_fan_obj) { ++ FAN_ERR("wb_plat_kobject_create fan error!\n"); ++ return -ENOMEM; ++ } ++ ++ if (sysfs_create_group(&g_fan_obj->kobj, &fan_root_attr_group) != 0) { ++ wb_plat_kobject_delete(&g_fan_obj); ++ FAN_ERR("create fan dir attrs error!\n"); ++ return -EBADRQC; ++ } ++ FAN_DBG("wb_plat_kobject_create fan directory and attribute success.\n"); ++ return 0; ++} ++ ++static void fan_root_remove(void) ++{ ++ if (g_fan_obj) { ++ sysfs_remove_group(&g_fan_obj->kobj, &fan_root_attr_group); ++ wb_plat_kobject_delete(&g_fan_obj); ++ FAN_DBG("delete fan root success\n"); ++ } ++ ++ return; ++} ++ ++static int fan_init(void) ++{ ++ int ret; ++ ++ FAN_INFO("fan_init...\n"); ++ g_drv = dfd_plat_driver_get(); ++ check_p(g_drv); ++ ++ ret = fan_root_create(); ++ if (ret < 0) { ++ goto fan_root_error; ++ } ++ ++ ret = fan_sub_create(); ++ if (ret < 0) { ++ goto fan_sub_error; ++ } ++ ++ ret = fan_motor_create(); ++ if (ret < 0) { ++ goto fan_motor_error; ++ } ++ ++ FAN_INFO("fan_init ok.\n"); ++ return 0; ++fan_motor_error: ++ fan_sub_remove(); ++fan_sub_error: ++ fan_root_remove(); ++fan_root_error: ++ return ret; ++} ++ ++static void fan_exit(void) ++{ ++ fan_motor_remove(); ++ fan_sub_remove(); ++ fan_root_remove(); ++ FAN_INFO("fan_exit ok.\n"); ++ return ; ++} ++ ++module_init(fan_init); ++module_exit(fan_exit); ++module_param(g_loglevel, int, 0644); ++MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("fan sysfs driver"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_psu.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_psu.c +new file mode 100644 +index 000000000..197f94b64 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_psu.c +@@ -0,0 +1,426 @@ ++/* ++ * plat_psu.c ++ * ++ * This module create psu kobjects and attributes in /sys/wb_plat/psu ++ * ++ */ ++ ++#include ++ ++#include "./include/plat_switch.h" ++#include "./include/sysfs_common.h" ++ ++#define PSU_INFO(fmt, args...) LOG_INFO("psu: ", fmt, ##args) ++#define PSU_ERR(fmt, args...) LOG_ERR("psu: ", fmt, ##args) ++#define PSU_DBG(fmt, args...) LOG_DBG("psu: ", fmt, ##args) ++ ++struct temp_obj_t{ ++ struct switch_obj *obj; ++}; ++ ++struct psu_obj_t{ ++ unsigned int temp_number; ++ struct temp_obj_t *temp; ++ struct switch_obj *obj; ++}; ++ ++struct psu_t{ ++ unsigned int psu_number; ++ struct psu_obj_t *psu; ++}; ++ ++static int g_loglevel = 0; ++static struct psu_t g_psu; ++static struct switch_obj *g_psu_obj = NULL; ++static struct switch_drivers_t *g_drv = NULL; ++ ++static ssize_t psu_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_psu.psu_number); ++} ++ ++static ssize_t psu_present_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int psu_index; ++ int ret; ++ ++ psu_index = obj->index; ++ PSU_DBG("psu_present_status_show, psu index:%d\n",psu_index); ++ check_p(g_drv); ++ check_p(g_drv->get_psu_present_status); ++ ++ ret = g_drv->get_psu_present_status(psu_index); ++ if(ret < 0) { ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); ++ } ++ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); ++} ++ ++static ssize_t psu_output_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int psu_index; ++ int ret; ++ ++ psu_index = obj->index; ++ PSU_DBG("psu_output_status_show, psu index:%d\n",psu_index); ++ check_p(g_drv); ++ check_p(g_drv->get_psu_output_status); ++ ++ ret = g_drv->get_psu_output_status(psu_index); ++ if(ret < 0) { ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); ++ } ++ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); ++} ++ ++static ssize_t psu_alert_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int psu_index; ++ int ret; ++ ++ psu_index = obj->index; ++ PSU_DBG("psu_alert_status_show, psu index:%d\n",psu_index); ++ check_p(g_drv); ++ check_p(g_drv->get_psu_alert_status); ++ ++ ret = g_drv->get_psu_alert_status(psu_index); ++ if(ret < 0) { ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); ++ } ++ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); ++} ++ ++/************************************psu dir and attrs*******************************************/ ++static struct switch_attribute psu_number_att = __ATTR(num_psus, S_IRUGO, psu_number_show, NULL); ++ ++static struct attribute *psu_dir_attrs[] = { ++ &psu_number_att.attr, ++ NULL, ++}; ++ ++static struct attribute_group psu_root_attr_group = { ++ .attrs = psu_dir_attrs, ++}; ++ ++/*******************************psu1 psu2 dir and attrs*******************************************/ ++static struct switch_attribute psu_present_status_att = __ATTR(present, S_IRUGO, psu_present_status_show, NULL); ++static struct switch_attribute psu_output_status_att = __ATTR(output, S_IRUGO, psu_output_status_show, NULL); ++static struct switch_attribute psu_alert_status_att = __ATTR(alert, S_IRUGO, psu_alert_status_show, NULL); ++ ++static struct attribute *psu_attrs[] = { ++ &psu_present_status_att.attr, ++ &psu_output_status_att.attr, ++ &psu_alert_status_att.attr, ++ NULL, ++}; ++ ++static struct attribute_group psu_attr_group = { ++ .attrs = psu_attrs, ++}; ++ ++/*******************************psu temp0 temp1 dir and attrs*******************************************/ ++static struct attribute *psu_temp_attrs[] = { ++ NULL, ++}; ++ ++static struct attribute_group psu_temp_attr_group = { ++ .attrs = psu_temp_attrs, ++}; ++ ++static void psuindex_single_temp_remove_kobj_and_attrs(struct psu_obj_t * curr_psu, unsigned int temp_index) ++{ ++ ++ struct temp_obj_t *curr_temp; /* point to temp0 temp1...*/ ++ ++ curr_temp = &curr_psu->temp[temp_index]; ++ if (curr_temp->obj) { ++ sysfs_remove_group(&curr_temp->obj->kobj, &psu_temp_attr_group); ++ wb_plat_kobject_delete(&curr_temp->obj); ++ PSU_DBG("delete psu:%d temp%d.\n", curr_psu->obj->index, temp_index); ++ } ++ return; ++} ++ ++static int psuindex_single_temp_create_kobj_and_attrs(struct psu_obj_t * curr_psu, unsigned int temp_index) ++{ ++ char name[DIR_NAME_MAX_LEN]; ++ struct temp_obj_t *curr_temp; /* point to temp0 temp1...*/ ++ ++ PSU_DBG("create psu_index:%d, temp%d ...\n", curr_psu->obj->index, temp_index); ++ ++ curr_temp = &curr_psu->temp[temp_index]; ++ mem_clear(name, sizeof(name)); ++ snprintf(name, sizeof(name), "temp%d", temp_index); ++ curr_temp->obj = wb_plat_kobject_create(name, &curr_psu->obj->kobj); ++ if (!curr_temp->obj) { ++ PSU_ERR("create psu_index:%d, temp%d object error!\n", curr_psu->obj->index, temp_index); ++ return -EBADRQC; ++ } ++ curr_temp->obj->index = temp_index; ++ if (sysfs_create_group(&curr_temp->obj->kobj, &psu_temp_attr_group) != 0) { ++ PSU_ERR("create psu_index:%d, temp%d attrs error.\n", curr_psu->obj->index, temp_index); ++ wb_plat_kobject_delete(&curr_temp->obj); ++ return -EBADRQC; ++ } ++ PSU_DBG("create psu_index:%d, temp%d ok.\n", curr_psu->obj->index, temp_index); ++ return 0; ++} ++ ++static int psuindex_temp_create_kobj_and_attrs(struct psu_obj_t * curr_psu, int temp_num) ++{ ++ int temp_index, i; ++ ++ curr_psu->temp = kzalloc(sizeof(struct temp_obj_t) * temp_num, GFP_KERNEL); ++ if (!curr_psu->temp) { ++ PSU_ERR("kzalloc temp error, psu index = %d, temp number = %d.\n", curr_psu->obj->index, temp_num); ++ return -ENOMEM; ++ } ++ curr_psu->temp_number = temp_num; ++ for (temp_index = 0; temp_index < temp_num; temp_index++) { ++ if (psuindex_single_temp_create_kobj_and_attrs(curr_psu, temp_index) != 0) { ++ goto temp_error; ++ } ++ } ++ return 0; ++temp_error: ++ for (i = temp_index - 1; i >= 0; i--) { ++ psuindex_single_temp_remove_kobj_and_attrs(curr_psu, i); ++ } ++ if (curr_psu->temp) { ++ kfree(curr_psu->temp); ++ curr_psu->temp = NULL; ++ } ++ return -EBADRQC; ++} ++ ++static void psuindex_temp_remove_kobj_and_attrs(struct psu_obj_t * curr_psu, int temp_num) ++{ ++ unsigned int temp_index; ++ ++ for (temp_index = temp_num - 1; temp_index >= 0; temp_index--) { ++ psuindex_single_temp_remove_kobj_and_attrs(curr_psu, temp_index); ++ } ++ return; ++} ++ ++static int psu_temp_create(void) ++{ ++ int psu_num, temp_num; ++ unsigned int psu_index, i; ++ struct psu_obj_t *curr_psu; /* point to psu1 psu2...*/ ++ ++ check_p(g_drv->get_dev_number); ++ temp_num = g_drv->get_dev_number(WB_MAIN_DEV_PSU, WB_MINOR_DEV_TEMP); ++ if (temp_num <= 0) { ++ PSU_INFO("psu temp_num:%d, don't need creat temp directory.\n", temp_num); ++ return 0; ++ } ++ ++ psu_num = g_psu.psu_number; ++ for(psu_index = 1; psu_index <= psu_num; psu_index++) { ++ curr_psu = &g_psu.psu[psu_index - 1]; ++ if(psuindex_temp_create_kobj_and_attrs(curr_psu, temp_num) != 0) { ++ goto error; ++ } ++ } ++ return 0; ++error: ++ for(i = psu_index - 1; i > 0; i--) { ++ curr_psu = &g_psu.psu[i - 1]; ++ temp_num = curr_psu->temp_number; ++ psuindex_temp_remove_kobj_and_attrs(curr_psu, temp_num); ++ } ++ return -EBADRQC; ++} ++ ++static void psu_temp_remove(void) ++{ ++ unsigned int psu_index; ++ struct psu_obj_t *curr_psu; ++ ++ if (g_psu.psu) { ++ for (psu_index = g_psu.psu_number; psu_index > 0; psu_index--) { ++ curr_psu = &g_psu.psu[psu_index - 1]; ++ if (curr_psu->temp) { ++ psuindex_temp_remove_kobj_and_attrs(curr_psu,curr_psu->temp_number); ++ kfree(curr_psu->temp); ++ curr_psu->temp = NULL; ++ curr_psu->temp_number = 0; ++ } ++ } ++ } ++ return; ++} ++ ++static void psu_sub_single_remove_kobj_and_attrs(unsigned int index) ++{ ++ struct psu_obj_t *curr_psu; ++ ++ curr_psu = &g_psu.psu[index - 1]; ++ if (curr_psu->obj) { ++ sysfs_remove_group(&curr_psu->obj->kobj, &psu_attr_group); ++ wb_plat_kobject_delete(&curr_psu->obj); ++ PSU_DBG("delete psu%d.\n", index); ++ } ++ return; ++} ++ ++static int psu_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) ++{ ++ char name[DIR_NAME_MAX_LEN]; ++ struct psu_obj_t *curr_psu; ++ ++ curr_psu = &g_psu.psu[index-1]; ++ PSU_DBG("create psu%d ...\n", index); ++ mem_clear(name, sizeof(name)); ++ snprintf(name, sizeof(name), "%s%d",PSU_SYSFS_NAME, index); ++ curr_psu->obj = wb_plat_kobject_create(name, parent); ++ if (!curr_psu->obj) { ++ PSU_ERR("create psu%d object error!\n", index); ++ return -EBADRQC; ++ } ++ curr_psu->obj->index = index; ++ if (sysfs_create_group(&curr_psu->obj->kobj, &psu_attr_group) != 0) { ++ PSU_ERR("create psu%d attrs error.\n", index); ++ wb_plat_kobject_delete(&curr_psu->obj); ++ return -EBADRQC; ++ } ++ PSU_DBG("create psu%d ok.\n", index); ++ return 0; ++} ++ ++static int psu_sub_create_kobj_and_attrs(struct kobject *parent, int psu_num) ++{ ++ unsigned int psu_index, i; ++ ++ g_psu.psu = kzalloc(sizeof(struct psu_obj_t) * psu_num, GFP_KERNEL); ++ if (!g_psu.psu) { ++ PSU_ERR("kzalloc psu.psu error, psu number = %d.\n", psu_num); ++ return -ENOMEM; ++ } ++ ++ for (psu_index = 1; psu_index <= psu_num; psu_index++) { ++ if (psu_sub_single_create_kobj_and_attrs(parent, psu_index) != 0) { ++ goto error; ++ } ++ } ++ return 0; ++error: ++ for(i = psu_index - 1; i > 0; i--) { ++ psu_sub_single_remove_kobj_and_attrs(i); ++ } ++ if(g_psu.psu) { ++ kfree(g_psu.psu); ++ g_psu.psu = NULL; ++ } ++ return -EBADRQC; ++} ++ ++static int psu_sub_create(void) ++{ ++ int ret, psu_num; ++ ++ check_p(g_drv->get_dev_number); ++ psu_num = g_drv->get_dev_number(WB_MAIN_DEV_PSU, WB_MINOR_DEV_NONE); ++ if (psu_num < 0) { ++ PSU_ERR("psu number = %d error.\n", psu_num); ++ return -EINVAL; ++ } ++ g_psu.psu_number = psu_num; ++ ret = psu_sub_create_kobj_and_attrs(&g_psu_obj->kobj, psu_num); ++ return ret; ++} ++ ++static void psu_sub_remove(void) ++{ ++ unsigned int psu_index; ++ ++ if (g_psu.psu) { ++ for (psu_index = g_psu.psu_number; psu_index > 0; psu_index--) { ++ psu_sub_single_remove_kobj_and_attrs(psu_index); ++ } ++ kfree(g_psu.psu); ++ } ++ mem_clear(&g_psu, sizeof(struct psu_t)); ++ return ; ++} ++ ++static int psu_root_create(void) ++{ ++ g_psu_obj = wb_plat_kobject_create(PSU_SYSFS_NAME, NULL); ++ if (!g_psu_obj) { ++ PSU_ERR("wb_plat_kobject_create psu error!\n"); ++ return -ENOMEM; ++ } ++ ++ if (sysfs_create_group(&g_psu_obj->kobj, &psu_root_attr_group) != 0) { ++ wb_plat_kobject_delete(&g_psu_obj); ++ PSU_ERR("create psu dir attrs error!\n"); ++ return -EBADRQC; ++ } ++ PSU_DBG("wb_plat_kobject_create psu directory and attribute success.\n"); ++ return 0; ++} ++ ++static void psu_root_remove(void) ++{ ++ if (g_psu_obj) { ++ sysfs_remove_group(&g_psu_obj->kobj, &psu_root_attr_group); ++ wb_plat_kobject_delete(&g_psu_obj); ++ PSU_DBG("delete psu root success\n"); ++ } ++ return; ++} ++ ++static int wb_psu_init(void) ++{ ++ int ret; ++ ++ PSU_INFO("wb_psu_init...\n"); ++ g_drv = dfd_plat_driver_get(); ++ check_p(g_drv); ++ ++ ret = psu_root_create(); ++ if (ret < 0) { ++ goto psu_root_error; ++ } ++ ++ ret = psu_sub_create(); ++ if (ret < 0) { ++ goto psu_sub_error; ++ } ++ ++ ret = psu_temp_create(); ++ if (ret < 0) { ++ goto psu_temp_error; ++ } ++ ++ PSU_INFO("wb_psu_init ok.\n"); ++ return 0; ++psu_temp_error: ++ psu_sub_remove(); ++psu_sub_error: ++ psu_root_remove(); ++psu_root_error: ++ return ret; ++} ++ ++static void wb_psu_exit(void) ++{ ++ psu_temp_remove(); ++ psu_sub_remove(); ++ psu_root_remove(); ++ PSU_INFO("wb_psu_exit ok.\n"); ++ return ; ++} ++ ++module_init(wb_psu_init); ++module_exit(wb_psu_exit); ++module_param(g_loglevel, int, 0644); ++MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("psu sysfs driver"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sensor.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sensor.c +new file mode 100644 +index 000000000..aaf62f4c1 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sensor.c +@@ -0,0 +1,452 @@ ++/* ++ * plat_sensor.c ++ * ++ * This module create sensor kobjects and attributes in /sys/wb_plat/sensor ++ */ ++ ++#include ++ ++#include "./include/plat_switch.h" ++#include "./include/sysfs_common.h" ++ ++#define SENSOR_INFO(fmt, args...) LOG_INFO("sensor: ", fmt, ##args) ++#define SENSOR_ERR(fmt, args...) LOG_ERR("sensor: ", fmt, ##args) ++#define SENSOR_DBG(fmt, args...) LOG_DBG("sensor: ", fmt, ##args) ++ ++struct sensor_t { ++ unsigned int in_number; ++ unsigned int temp_number; ++ struct sensor_in_t *in; ++ struct sensor_temp_t *temp; ++}; ++ ++struct sensor_temp_t { ++ struct switch_obj *obj; ++}; ++ ++struct sensor_in_t { ++ struct switch_obj *obj; ++}; ++ ++static int g_loglevel = 0; ++static struct switch_drivers_t *g_drv = NULL; ++static struct sensor_t g_sensor; ++static struct switch_obj *g_sensor_obj = NULL; ++ ++static ssize_t sensor_temp_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_sensor.temp_number); ++} ++ ++static ssize_t sensor_in_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_sensor.in_number); ++} ++ ++static ssize_t sensor_voltage_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int in_index; ++ int ret; ++ struct switch_device_attribute *in_attr; ++ ++ check_p(g_drv); ++ check_p(g_drv->get_voltage_info); ++ in_index = obj->index; ++ ++ in_attr = to_switch_device_attr(attr); ++ check_p(in_attr); ++ SENSOR_DBG("sensor_in_show, in index:0x%x, in type:0x%x\n",in_index, in_attr->type); ++ ret = g_drv->get_voltage_info(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_NONE, in_index, in_attr->type, buf); ++ if (ret < 0) { ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); ++ } ++ return ret; ++} ++ ++static ssize_t sensor_temp_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int temp_index; ++ int ret; ++ struct switch_device_attribute *temp_attr; ++ ++ check_p(g_drv); ++ check_p(g_drv->get_temp_info); ++ temp_index = obj->index; ++ ++ temp_attr = to_switch_device_attr(attr); ++ check_p(temp_attr); ++ SENSOR_DBG("sensor_temp_show, temp index:0x%x, temp type:0x%x\n", temp_index, temp_attr->type); ++ ret = g_drv->get_temp_info(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_NONE, temp_index, temp_attr->type, buf); ++ if (ret < 0) { ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); ++ } ++ return ret; ++} ++ ++/************************************sensor dir and attrs*******************************************/ ++static struct switch_attribute num_temp_att = __ATTR(num_temp_sensors, S_IRUGO, sensor_temp_number_show, NULL); ++static struct switch_attribute num_in_att = __ATTR(num_in_sensors, S_IRUGO, sensor_in_number_show, NULL); ++ ++static struct attribute *sensor_dir_attrs[] = { ++ &num_temp_att.attr, ++ &num_in_att.attr, ++ NULL, ++}; ++ ++static struct attribute_group sensor_root_attr_group = { ++ .attrs = sensor_dir_attrs, ++}; ++ ++/*******************************temp0 temp1 dir and attrs*******************************************/ ++static SWITCH_DEVICE_ATTR(temp_input, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_INPUT); ++static SWITCH_DEVICE_ATTR(temp_alias, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_ALIAS); ++static SWITCH_DEVICE_ATTR(temp_type, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_TYPE); ++static SWITCH_DEVICE_ATTR(temp_max, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_MAX); ++static SWITCH_DEVICE_ATTR(temp_max_hyst, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_MAX_HYST); ++static SWITCH_DEVICE_ATTR(temp_min, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_MIN); ++ ++static struct attribute *sensor_temp_attrs[] = { ++ &switch_dev_attr_temp_input.switch_attr.attr, ++ &switch_dev_attr_temp_alias.switch_attr.attr, ++ &switch_dev_attr_temp_type.switch_attr.attr, ++ &switch_dev_attr_temp_max.switch_attr.attr, ++ &switch_dev_attr_temp_max_hyst.switch_attr.attr, ++ &switch_dev_attr_temp_min.switch_attr.attr, ++ NULL, ++}; ++ ++static struct attribute_group sensor_temp_attr_group = { ++ .attrs = sensor_temp_attrs, ++}; ++ ++/*******************************in0 in1 dir and attrs*******************************************/ ++static SWITCH_DEVICE_ATTR(in_input, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_INPUT); ++static SWITCH_DEVICE_ATTR(in_alias, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_ALIAS); ++static SWITCH_DEVICE_ATTR(in_type, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_TYPE); ++static SWITCH_DEVICE_ATTR(in_max, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_MAX); ++static SWITCH_DEVICE_ATTR(in_min, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_MIN); ++static SWITCH_DEVICE_ATTR(in_crit, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_CRIT); ++ ++static struct attribute *sensor_in_attrs[] = { ++ &switch_dev_attr_in_input.switch_attr.attr, ++ &switch_dev_attr_in_alias.switch_attr.attr, ++ &switch_dev_attr_in_type.switch_attr.attr, ++ &switch_dev_attr_in_max.switch_attr.attr, ++ &switch_dev_attr_in_min.switch_attr.attr, ++ &switch_dev_attr_in_crit.switch_attr.attr, ++ NULL, ++}; ++ ++static struct attribute_group sensor_in_attr_group = { ++ .attrs = sensor_in_attrs, ++}; ++ ++static int sensor_in_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) ++{ ++ char name[DIR_NAME_MAX_LEN]; ++ struct sensor_in_t *curr_sensor; ++ ++ curr_sensor = &g_sensor.in[index - 1]; ++ SENSOR_DBG("create sensor in%d ...\n", index); ++ mem_clear(name, sizeof(name)); ++ snprintf(name, sizeof(name), "in%d", index); ++ curr_sensor->obj = wb_plat_kobject_create(name, parent); ++ if (!curr_sensor->obj) { ++ SENSOR_ERR("create sensor in%d object error!\n", index); ++ return -EBADRQC; ++ } ++ curr_sensor->obj->index = index; ++ if (sysfs_create_group(&curr_sensor->obj->kobj, &sensor_in_attr_group) != 0) { ++ SENSOR_ERR("create sensor in%d attrs error.\n", index); ++ wb_plat_kobject_delete(&curr_sensor->obj); ++ return -EBADRQC; ++ } ++ SENSOR_DBG("create sensor in%d ok.\n", index); ++ return 0; ++ ++} ++ ++static void sensor_in_sub_single_remove_kobj_and_attrs(unsigned int index) ++{ ++ struct sensor_in_t *curr_in; ++ ++ curr_in = &g_sensor.in[index - 1]; ++ if (curr_in->obj) { ++ sysfs_remove_group(&curr_in->obj->kobj, &sensor_in_attr_group); ++ wb_plat_kobject_delete(&curr_in->obj); ++ SENSOR_DBG("delete in%d.\n", index); ++ } ++ return; ++} ++ ++static int sensor_temp_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) ++{ ++ char name[DIR_NAME_MAX_LEN]; ++ struct sensor_temp_t *curr_sensor; ++ ++ curr_sensor = &g_sensor.temp[index - 1]; ++ SENSOR_DBG("create sensor temp%d ...\n", index); ++ mem_clear(name, sizeof(name)); ++ snprintf(name, sizeof(name), "temp%d", index); ++ curr_sensor->obj = wb_plat_kobject_create(name, parent); ++ if (!curr_sensor->obj) { ++ SENSOR_ERR("create sensor temp%d object error!\n", index); ++ return -EBADRQC; ++ } ++ curr_sensor->obj->index = index; ++ if (sysfs_create_group(&curr_sensor->obj->kobj, &sensor_temp_attr_group) != 0) { ++ SENSOR_ERR("create sensor temp%d attrs error.\n", index); ++ wb_plat_kobject_delete(&curr_sensor->obj); ++ return -EBADRQC; ++ } ++ SENSOR_DBG("create sensor temp%d ok.\n", index); ++ return 0; ++ ++} ++ ++static void sensor_temp_sub_single_remove_kobj_and_attrs(unsigned int index) ++{ ++ struct sensor_temp_t *curr_temp; ++ ++ curr_temp = &g_sensor.temp[index - 1]; ++ if (curr_temp->obj) { ++ sysfs_remove_group(&curr_temp->obj->kobj, &sensor_temp_attr_group); ++ wb_plat_kobject_delete(&curr_temp->obj); ++ SENSOR_DBG("delete temp%d.\n", index); ++ } ++ return; ++} ++ ++static int sensor_temp_sub_create_kobj_and_attrs(struct kobject *parent, int temp_num) ++{ ++ unsigned int temp_index, i; ++ ++ g_sensor.temp = kzalloc(sizeof(struct sensor_temp_t) * temp_num, GFP_KERNEL); ++ if (!g_sensor.temp ) { ++ SENSOR_ERR("kzalloc g_sensor.temp error, temp number = %d.\n", temp_num); ++ return -ENOMEM; ++ } ++ for (temp_index = 1; temp_index <= temp_num; temp_index++) { ++ if (sensor_temp_sub_single_create_kobj_and_attrs(parent, temp_index) != 0 ) { ++ goto error; ++ } ++ } ++ return 0; ++error: ++ for (i = temp_index - 1; i > 0; i--) { ++ sensor_temp_sub_single_remove_kobj_and_attrs(i); ++ } ++ ++ if (g_sensor.temp) { ++ kfree(g_sensor.temp); ++ g_sensor.temp = NULL; ++ } ++ return -EBADRQC; ++} ++ ++static int sensor_in_sub_create_kobj_and_attrs(struct kobject *parent, int in_num) ++{ ++ unsigned int in_index, i; ++ ++ g_sensor.in = kzalloc(sizeof(struct sensor_in_t) * in_num, GFP_KERNEL); ++ if (!g_sensor.in) { ++ SENSOR_ERR("kzalloc g_sensor.in error, in number = %d.\n", in_num); ++ return -ENOMEM; ++ } ++ ++ for (in_index = 1; in_index <= in_num; in_index++) { ++ if (sensor_in_sub_single_create_kobj_and_attrs(parent, in_index) != 0 ) { ++ goto error; ++ } ++ } ++ return 0; ++error: ++ for (i = in_index - 1; i > 0; i--) { ++ sensor_in_sub_single_remove_kobj_and_attrs(i); ++ } ++ ++ if (g_sensor.in) { ++ kfree(g_sensor.in); ++ g_sensor.in = NULL; ++ } ++ return -EBADRQC; ++} ++ ++static int sensor_temp_sub_create(void) ++{ ++ int ret, temp_num; ++ ++ check_p(g_drv->get_dev_number); ++ temp_num = g_drv->get_dev_number(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_TEMP); ++ g_sensor.temp_number = temp_num; ++ if (temp_num <= 0) { ++ SENSOR_DBG("Warning:sensor temp number = %d \n", temp_num); ++ return 0; ++ } ++ ret = sensor_temp_sub_create_kobj_and_attrs(&g_sensor_obj->kobj, temp_num); ++ return ret; ++} ++ ++static int sensor_in_sub_create(void) ++{ ++ int ret, in_num; ++ ++ check_p(g_drv->get_dev_number); ++ in_num = g_drv->get_dev_number(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_IN); ++ g_sensor.in_number = in_num; ++ ++ if (in_num <= 0) { ++ SENSOR_DBG("Warning:sensor in number = %d \n", in_num); ++ return 0; ++ } ++ ret = sensor_in_sub_create_kobj_and_attrs(&g_sensor_obj->kobj, in_num); ++ return ret; ++} ++ ++static void temp_sub_single_remove_kobj_and_attrs(unsigned int index) ++{ ++ struct sensor_temp_t * curr_temp; ++ ++ curr_temp = &g_sensor.temp[index - 1]; ++ if (curr_temp->obj) { ++ sysfs_remove_group(&curr_temp->obj->kobj, &sensor_temp_attr_group); ++ wb_plat_kobject_delete(&curr_temp->obj); ++ SENSOR_DBG("delete sensor temp%d.\n", index); ++ } ++ return; ++} ++ ++static void in_sub_single_remove_kobj_and_attrs(unsigned int index) ++{ ++ struct sensor_in_t * curr_in; ++ ++ curr_in = &g_sensor.in[index - 1]; ++ if (curr_in->obj) { ++ sysfs_remove_group(&curr_in->obj->kobj, &sensor_in_attr_group); ++ wb_plat_kobject_delete(&curr_in->obj); ++ SENSOR_DBG("delete sensor in%d.\n", index); ++ } ++ return; ++} ++ ++static void sensor_temp_sub_remove(void) ++{ ++ unsigned int temp_index; ++ ++ if (g_sensor.temp) { ++ for (temp_index = g_sensor.temp_number; temp_index > 0; temp_index--) { ++ temp_sub_single_remove_kobj_and_attrs(temp_index); ++ } ++ kfree(g_sensor.temp); ++ g_sensor.temp = NULL; ++ } ++ return; ++} ++ ++static void sensor_in_sub_remove(void) ++{ ++ unsigned int in_index; ++ ++ if (g_sensor.in) { ++ for (in_index = g_sensor.in_number; in_index > 0; in_index--) { ++ in_sub_single_remove_kobj_and_attrs(in_index); ++ } ++ kfree(g_sensor.in); ++ g_sensor.in = NULL; ++ } ++ return; ++} ++ ++static void sensor_sub_remove(void) ++{ ++ sensor_temp_sub_remove(); ++ sensor_in_sub_remove(); ++} ++ ++static int sensor_sub_create(void) ++{ ++ int ret; ++ /* temp creat */ ++ ret = sensor_temp_sub_create(); ++ if (ret < 0) { ++ goto temp_err; ++ } ++ /* Voltage creat */ ++ ret = sensor_in_sub_create(); ++ if (ret < 0) { ++ goto in_err; ++ } ++ return 0; ++in_err: ++ sensor_temp_sub_remove(); ++temp_err: ++ return ret; ++} ++static void sensor_root_remove(void) ++{ ++ if (g_sensor_obj) { ++ sysfs_remove_group(&g_sensor_obj->kobj, &sensor_root_attr_group); ++ wb_plat_kobject_delete(&g_sensor_obj); ++ SENSOR_DBG("delete sensor root success\n"); ++ } ++ ++ return; ++} ++ ++static int sensor_root_create(void) ++{ ++ g_sensor_obj = wb_plat_kobject_create("sensor", NULL); ++ if (!g_sensor_obj) { ++ SENSOR_ERR("wb_plat_kobject_create sensor error!\n"); ++ return -ENOMEM; ++ } ++ ++ if (sysfs_create_group(&g_sensor_obj->kobj, &sensor_root_attr_group) != 0) { ++ wb_plat_kobject_delete(&g_sensor_obj); ++ SENSOR_ERR("create sensor dir attrs error!\n"); ++ return -EBADRQC; ++ } ++ SENSOR_DBG("wb_plat_kobject_create sensor directory and attribute success.\n"); ++ return 0; ++} ++ ++static int wb_sensor_init(void) ++{ ++ int ret; ++ ++ SENSOR_INFO("wb_sensor_init...\n"); ++ g_drv = dfd_plat_driver_get(); ++ check_p(g_drv); ++ ++ ret = sensor_root_create(); ++ if (ret < 0) { ++ goto sensor_root_error; ++ } ++ ++ ret = sensor_sub_create(); ++ if (ret < 0) { ++ goto sensor_sub_error; ++ } ++ SENSOR_INFO("sensor_init ok.\n"); ++ return 0; ++sensor_sub_error: ++ sensor_root_remove(); ++sensor_root_error: ++ return ret; ++} ++ ++static void wb_sensor_exit(void) ++{ ++ sensor_sub_remove(); ++ sensor_root_remove(); ++ SENSOR_INFO("sensor_exit ok.\n"); ++ return; ++} ++ ++module_init(wb_sensor_init); ++module_exit(wb_sensor_exit); ++module_param(g_loglevel, int, 0644); ++MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("sensors sysfs driver"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sff.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sff.c +new file mode 100644 +index 000000000..50c0f78ae +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sff.c +@@ -0,0 +1,287 @@ ++/* ++ * plat_sff.c ++ * ++ * This module create sff kobjects and attributes in /sys/wb_plat/sff ++ * ++ */ ++ ++#include ++ ++#include "./include/plat_switch.h" ++#include "./include/sysfs_common.h" ++ ++#define SFF_INFO(fmt, args...) LOG_INFO("sff: ", fmt, ##args) ++#define SFF_ERR(fmt, args...) LOG_ERR("sff: ", fmt, ##args) ++#define SFF_DBG(fmt, args...) LOG_DBG("sff: ", fmt, ##args) ++ ++struct sff_obj_t{ ++ struct switch_obj *sff_obj; ++ struct bin_attribute bin; ++ int sff_creat_bin_flag; ++}; ++ ++struct sff_t{ ++ unsigned int sff_number; ++ struct sff_obj_t *sff; ++}; ++ ++static int g_loglevel = 0; ++static struct sff_t g_sff; ++static struct switch_obj *g_sff_obj = NULL; ++static struct switch_drivers_t *g_drv = NULL; ++ ++static ssize_t sff_cpld_info_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int sff_index; ++ int ret; ++ struct switch_device_attribute *sff_cpld_attr; ++ ++ check_p(g_drv); ++ check_p(g_drv->get_sff_cpld_info); ++ ++ sff_index = obj->index; ++ sff_cpld_attr = to_switch_device_attr(attr); ++ check_p(sff_cpld_attr); ++ SFF_DBG("sff_cpld_info_show, sff index:0x%x, sff cpld attr type:0x%x\n", sff_index, sff_cpld_attr->type); ++ ret = g_drv->get_sff_cpld_info(sff_index, sff_cpld_attr->type, buf, PAGE_SIZE); ++ if(ret < 0) { ++ SFF_ERR("sff_cpld_info_show error. sff index:0x%x, sff cpld attr type:0x%x, ret:%d\n", ++ sff_index, sff_cpld_attr->type,ret ); ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); ++ } ++ SFF_DBG("sff_cpld_info_show ok. sff index:0x%x, sff cpld attr type:0x%x, ret:%d\n", sff_index, sff_cpld_attr->type, ret); ++ return ret; ++} ++ ++static ssize_t sff_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_sff.sff_number); ++} ++ ++/************************************sff attrs*******************************************/ ++static struct switch_attribute sff_number_att = __ATTR(num_sffs, S_IRUGO, sff_number_show, NULL); ++static SWITCH_DEVICE_ATTR(present, S_IRUGO, sff_cpld_info_show, NULL, WB_SFF_MODULE_PRESENT); ++ ++/*******************************xcvr dir and attrs*******************************************/ ++static struct attribute *xcvr_dir_attrs[] = { ++ &sff_number_att.attr, ++ NULL, ++}; ++ ++static struct attribute_group sff_xcvr_attr_group = { ++ .attrs = xcvr_dir_attrs, ++}; ++ ++/*******************************sff dir and attrs*******************************************/ ++static struct attribute *sff_attrs[] = { ++ &switch_dev_attr_present.switch_attr.attr, ++ NULL, ++}; ++ ++static struct attribute_group sff_attr_group = { ++ .attrs = sff_attrs, ++}; ++ ++static int sff_sub_single_create_attrs(unsigned int index) ++{ ++ struct sff_obj_t *curr_sff; ++ ++ curr_sff = &g_sff.sff[index-1]; ++ if (sysfs_create_group(&curr_sff->sff_obj->kobj, &sff_attr_group) != 0) { ++ SFF_ERR("create sff%d dir attrs error!\n", index); ++ wb_plat_kobject_delete(&curr_sff->sff_obj); ++ return -EBADRQC; ++ } ++ SFF_DBG("create sff%d dir attrs ok!\n", index); ++ return 0; ++} ++ ++static int sff_sub_single_create_kobj(struct kobject *parent, unsigned int index) ++{ ++ struct sff_obj_t *curr_sff; ++ char sff_dir_name[DIR_NAME_MAX_LEN]; ++ int ret; ++ ++ check_p(g_drv->get_sff_dir_name); ++ ret = g_drv->get_sff_dir_name(index, sff_dir_name, sizeof(sff_dir_name)); ++ if (ret < 0) { ++ SFF_ERR("sff index:%d, get sff dir name error. please check sff config.\n", index); ++ return -ENOSYS; ++ } ++ ++ curr_sff = &g_sff.sff[index - 1]; ++ ++ curr_sff->sff_obj = wb_plat_kobject_create(sff_dir_name, parent); ++ if (!curr_sff->sff_obj) { ++ SFF_ERR("sff index:%d, create %s object error! \n", index, sff_dir_name); ++ return -EBADRQC; ++ } ++ ++ SFF_DBG("create sff kobj ok. sff index:%d, dir name:%s\n",index, sff_dir_name); ++ curr_sff->sff_obj->index = index; ++ ++ return 0; ++} ++ ++static void sff_sub_single_remove_kobj_and_attrs(unsigned int index) ++{ ++ struct sff_obj_t *curr_sff; ++ ++ curr_sff = &g_sff.sff[index - 1]; ++ /* remove sff dir and attr */ ++ if (curr_sff->sff_obj) { ++ SFF_DBG("delete sff%d attrs.\n", curr_sff->sff_obj->index); ++ curr_sff->sff_obj->index = 0; ++ sysfs_remove_group(&curr_sff->sff_obj->kobj, &sff_attr_group); ++ wb_plat_kobject_delete(&curr_sff->sff_obj); ++ } ++ ++ return; ++} ++ ++static int sff_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) ++{ ++ int ret; ++ ++ ret = sff_sub_single_create_kobj(parent, index); ++ if (ret < 0) { ++ SFF_ERR("sff index:%d, create sff dir error.\n", index); ++ return ret; ++ } ++ ++ ret = sff_sub_single_create_attrs(index); ++ if (ret < 0) { ++ SFF_ERR("sff index:%d, create sff attr error.\n", index); ++ return ret; ++ } ++ return 0; ++} ++ ++static int sff_sub_create_kobj_and_attrs(struct kobject *parent, int sff_num) ++{ ++ unsigned int sff_index, i; ++ ++ g_sff.sff = kzalloc(sizeof(struct sff_obj_t) * sff_num, GFP_KERNEL); ++ if (!g_sff.sff) { ++ SFF_ERR("kzalloc g_sff.sff error, sff number = %d.\n", sff_num); ++ return -ENOMEM; ++ } ++ ++ for (sff_index = 1; sff_index <= sff_num; sff_index++) { ++ if (sff_sub_single_create_kobj_and_attrs(parent, sff_index) != 0 ) { ++ goto error; ++ } ++ } ++ return 0; ++error: ++ for (i = sff_index - 1; i > 0; i--) { ++ sff_sub_single_remove_kobj_and_attrs(i); ++ } ++ if (g_sff.sff) { ++ kfree(g_sff.sff); ++ g_sff.sff = NULL; ++ } ++ return -EBADRQC; ++} ++ ++static int sff_sub_create(void) ++{ ++ int ret, sff_num; ++ ++ check_p(g_drv->get_dev_number); ++ sff_num = g_drv->get_dev_number(WB_MAIN_DEV_SFF, WB_MINOR_DEV_NONE); ++ g_sff.sff_number = sff_num; ++ if (sff_num <= 0) { ++ SFF_ERR("ERROR. port number:%d\n", sff_num); ++ return -EINVAL; ++ } ++ ++ ret = sff_sub_create_kobj_and_attrs(&g_sff_obj->kobj, sff_num); ++ ++ return ret; ++} ++ ++static void sff_sub_remove(void) ++{ ++ unsigned int sff_index; ++ ++ if (g_sff.sff) { ++ for (sff_index = g_sff.sff_number; sff_index > 0; sff_index--) { ++ sff_sub_single_remove_kobj_and_attrs(sff_index); ++ } ++ kfree(g_sff.sff); ++ } ++ mem_clear(&g_sff, sizeof(struct sff_t)); ++ return ; ++} ++ ++static int sff_xcvr_create(void) ++{ ++ g_sff_obj = wb_plat_kobject_create(SFF_SYSFS_NAME, NULL); ++ if (!g_sff_obj) { ++ SFF_ERR("wb_plat_kobject_create sff error!\n"); ++ return -ENOMEM; ++ } ++ ++ g_sff_obj->index = 0; ++ if (sysfs_create_group(&g_sff_obj->kobj, &sff_xcvr_attr_group) != 0) { ++ wb_plat_kobject_delete(&g_sff_obj); ++ SFF_ERR("create sff dir attrs error!\n"); ++ return -EBADRQC; ++ } ++ SFF_DBG("wb_plat_kobject_create sff directory and attribute success.\n"); ++ return 0; ++} ++ ++static void sff_xcvr_remove(void) ++{ ++ if (g_sff_obj) { ++ sysfs_remove_group(&g_sff_obj->kobj, &sff_xcvr_attr_group); ++ wb_plat_kobject_delete(&g_sff_obj); ++ SFF_DBG("delete sff root success\n"); ++ } ++ ++ return; ++} ++ ++static int wb_sff_init(void) ++{ ++ int ret; ++ ++ SFF_INFO("wb_sff_init...\n"); ++ g_drv = dfd_plat_driver_get(); ++ check_p(g_drv); ++ ++ ret = sff_xcvr_create(); ++ if (ret < 0) { ++ goto sff_root_error; ++ } ++ ++ ret = sff_sub_create(); ++ if (ret < 0) { ++ goto sff_sub_error; ++ } ++ SFF_INFO("wb_sff_init ok.\n"); ++ return 0; ++ ++sff_sub_error: ++ sff_xcvr_remove(); ++sff_root_error: ++ return ret; ++} ++ ++static void wb_sff_exit(void) ++{ ++ sff_sub_remove(); ++ sff_xcvr_remove(); ++ SFF_INFO("wb_sff_exit ok.\n"); ++ return ; ++} ++ ++module_init(wb_sff_init); ++module_exit(wb_sff_exit); ++module_param(g_loglevel, int, 0644); ++MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("sff sysfs driver"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_slot.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_slot.c +new file mode 100644 +index 000000000..7c50f283b +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_slot.c +@@ -0,0 +1,663 @@ ++/* ++ * plat_slot.c ++ * ++ * This module create sff kobjects and attributes in /sys/wb_plat/slot ++ * ++ */ ++ ++#include ++ ++#include "./include/plat_switch.h" ++#include "./include/sysfs_common.h" ++ ++#define SLOT_INFO(fmt, args...) LOG_INFO("slot: ", fmt, ##args) ++#define SLOT_ERR(fmt, args...) LOG_ERR("slot: ", fmt, ##args) ++#define SLOT_DBG(fmt, args...) LOG_DBG("slot: ", fmt, ##args) ++ ++struct slot_temp_obj_t{ ++ struct switch_obj *obj; ++}; ++ ++struct slot_in_obj_t{ ++ struct switch_obj *obj; ++}; ++ ++struct slot_obj_t{ ++ unsigned int temp_number; ++ unsigned int in_number; ++ struct slot_temp_obj_t *temp; ++ struct slot_in_obj_t *in; ++ struct switch_obj *obj; ++}; ++ ++struct slot_t{ ++ unsigned int slot_number; ++ struct slot_obj_t *slot; ++}; ++ ++static int g_loglevel = 0; ++static struct slot_t g_slot; ++static struct switch_obj *g_slot_obj = NULL; ++static struct switch_drivers_t *g_drv = NULL; ++ ++static ssize_t slot_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_slot.slot_number); ++} ++ ++static ssize_t slot_temp_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int index; ++ ++ index = obj->index; ++ SLOT_DBG("slot_temp_number_show,slot index:%d\n",index); ++ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_slot.slot[index-1].temp_number); ++} ++ ++static ssize_t slot_in_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int index; ++ ++ index = obj->index; ++ SLOT_DBG("slot_in_number_show,slot index:%d\n",index); ++ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_slot.slot[index-1].in_number); ++} ++ ++static ssize_t slot_present_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int slot_index; ++ int ret; ++ ++ slot_index = obj->index; ++ SLOT_DBG("slot_present_status_show, slot index:%d\n",slot_index); ++ check_p(g_drv); ++ check_p(g_drv->get_slot_present_status); ++ ++ ret = g_drv->get_slot_present_status(slot_index); ++ if(ret < 0) { ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); ++ } ++ ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); ++} ++ ++static ssize_t slot_voltage_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int slot_index, in_index; ++ int ret; ++ struct switch_obj *p_obj; ++ struct switch_device_attribute *in_attr; ++ ++ check_p(g_drv); ++ check_p(g_drv->get_voltage_info); ++ ++ p_obj = to_switch_obj(obj->kobj.parent); ++ check_p(p_obj); ++ ++ slot_index = p_obj->index; ++ in_index = obj->index; ++ ++ in_attr = to_switch_device_attr(attr); ++ check_p(in_attr); ++ SLOT_DBG("slot_voltage_show, slot index:0x%x, temp index:0x%x, temp type:0x%x\n",slot_index, in_index, in_attr->type); ++ ret = g_drv->get_voltage_info(WB_MAIN_DEV_SLOT, slot_index, in_index, in_attr->type, buf); ++ if(ret < 0) { ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); ++ } ++ return ret; ++} ++ ++static ssize_t slot_temp_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) ++{ ++ unsigned int slot_index, temp_index; ++ int ret; ++ struct switch_obj *p_obj; ++ struct switch_device_attribute *temp_attr; ++ ++ check_p(g_drv); ++ check_p(g_drv->get_temp_info); ++ ++ p_obj = to_switch_obj(obj->kobj.parent); ++ check_p(p_obj); ++ ++ slot_index = p_obj->index; ++ temp_index = obj->index; ++ ++ temp_attr = to_switch_device_attr(attr); ++ check_p(temp_attr); ++ SLOT_DBG("slot_temp_show, slot index:0x%x, temp index:0x%x, temp type:0x%x\n",slot_index, temp_index, temp_attr->type); ++ ret = g_drv->get_temp_info(WB_MAIN_DEV_SLOT, slot_index, temp_index, temp_attr->type, buf); ++ if(ret < 0) { ++ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); ++ } ++ return ret; ++} ++ ++/************************************slot dir and attrs*******************************************/ ++static struct switch_attribute slot_number_att = __ATTR(num_slots, S_IRUGO, slot_number_show, NULL); ++ ++static struct attribute *slot_dir_attrs[] = { ++ &slot_number_att.attr, ++ NULL, ++}; ++ ++static struct attribute_group slot_root_attr_group = { ++ .attrs = slot_dir_attrs, ++}; ++ ++/*******************************slot1 slot2 dir and attrs*******************************************/ ++static struct switch_attribute num_temp_sensors_att = __ATTR(num_temp_sensors, S_IRUGO, slot_temp_number_show, NULL); ++static struct switch_attribute num_in_sensors_att = __ATTR(num_in_sensors, S_IRUGO, slot_in_number_show, NULL); ++static struct switch_attribute slot_present_status_att = __ATTR(present, S_IRUGO, slot_present_status_show, NULL); ++ ++static struct attribute *slot_attrs[] = { ++ &num_temp_sensors_att.attr, ++ &num_in_sensors_att.attr, ++ &slot_present_status_att.attr, ++ NULL, ++}; ++ ++static struct attribute_group slot_attr_group = { ++ .attrs = slot_attrs, ++}; ++ ++/*******************************temp dir and attrs*******************************************/ ++static SWITCH_DEVICE_ATTR(temp_alias, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_ALIAS); ++static SWITCH_DEVICE_ATTR(temp_type, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_TYPE); ++static SWITCH_DEVICE_ATTR(temp_max, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_MAX); ++static SWITCH_DEVICE_ATTR(temp_max_hyst, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_MAX_HYST); ++static SWITCH_DEVICE_ATTR(temp_min, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_MIN); ++static SWITCH_DEVICE_ATTR(temp_input, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_INPUT); ++ ++static struct attribute *temp_attrs[] = { ++ &switch_dev_attr_temp_alias.switch_attr.attr, ++ &switch_dev_attr_temp_type.switch_attr.attr, ++ &switch_dev_attr_temp_max.switch_attr.attr, ++ &switch_dev_attr_temp_max_hyst.switch_attr.attr, ++ &switch_dev_attr_temp_min.switch_attr.attr, ++ &switch_dev_attr_temp_input.switch_attr.attr, ++ NULL, ++}; ++ ++static struct attribute_group temp_attr_group = { ++ .attrs = temp_attrs, ++}; ++ ++/*******************************Voltage dir and attrs*******************************************/ ++static SWITCH_DEVICE_ATTR(in_alias, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_ALIAS); ++static SWITCH_DEVICE_ATTR(in_type, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_TYPE); ++static SWITCH_DEVICE_ATTR(in_max, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_MAX); ++static SWITCH_DEVICE_ATTR(in_crit, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_CRIT); ++static SWITCH_DEVICE_ATTR(in_min, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_MIN); ++static SWITCH_DEVICE_ATTR(in_input, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_INPUT); ++ ++static struct attribute *in_attrs[] = { ++ &switch_dev_attr_in_alias.switch_attr.attr, ++ &switch_dev_attr_in_type.switch_attr.attr, ++ &switch_dev_attr_in_max.switch_attr.attr, ++ &switch_dev_attr_in_crit.switch_attr.attr, ++ &switch_dev_attr_in_min.switch_attr.attr, ++ &switch_dev_attr_in_input.switch_attr.attr, ++ NULL, ++}; ++ ++static struct attribute_group in_attr_group = { ++ .attrs = in_attrs, ++}; ++ ++static void slotindex_single_temp_remove_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int temp_index) ++{ ++ ++ struct slot_temp_obj_t *curr_temp; /* point to temp1 temp2...*/ ++ ++ curr_temp = &curr_slot->temp[temp_index - 1]; ++ if (curr_temp->obj) { ++ sysfs_remove_group(&curr_temp->obj->kobj, &temp_attr_group); ++ wb_plat_kobject_delete(&curr_temp->obj); ++ SLOT_DBG("delete slot:%d temp%d.\n", curr_slot->obj->index, temp_index); ++ } ++ return; ++} ++ ++static int slotindex_single_temp_create_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int temp_index) ++{ ++ char name[DIR_NAME_MAX_LEN]; ++ struct slot_temp_obj_t *curr_temp; /* point to temp1 temp2...*/ ++ ++ curr_temp = &curr_slot->temp[temp_index - 1]; ++ mem_clear(name, sizeof(name)); ++ snprintf(name, sizeof(name), "%s%d", TEMP_SYSFS_NAME, temp_index); ++ ++ curr_temp->obj = wb_plat_kobject_create(name, &curr_slot->obj->kobj); ++ if (!curr_temp->obj) { ++ SLOT_ERR("create slot_index:%d, temp%d object error!\n", curr_slot->obj->index, temp_index); ++ return -EBADRQC; ++ } ++ curr_temp->obj->index = temp_index; ++ if (sysfs_create_group(&curr_temp->obj->kobj, &temp_attr_group) != 0) { ++ SLOT_ERR("create slot_index:%d, temp%d attrs error.\n", curr_slot->obj->index, temp_index); ++ wb_plat_kobject_delete(&curr_temp->obj); ++ return -EBADRQC; ++ } ++ SLOT_DBG("create slot_index:%d, temp%d ok.\n", curr_slot->obj->index, temp_index); ++ return 0; ++} ++ ++static void slotindex_temp_remove_kobj_and_attrs(struct slot_obj_t * curr_slot) ++{ ++ int temp_index; ++ ++ for(temp_index = curr_slot->temp_number; temp_index > 0; temp_index--) { ++ slotindex_single_temp_remove_kobj_and_attrs(curr_slot, temp_index); ++ } ++ ++ if(curr_slot->temp) { ++ kfree(curr_slot->temp); ++ curr_slot->temp = NULL; ++ curr_slot->temp_number = 0; ++ } ++ return; ++} ++ ++static int slotindex_temp_create_kobj_and_attrs(struct slot_obj_t * curr_slot, int temp_num) ++{ ++ int temp_index, i; ++ ++ curr_slot->temp_number = temp_num; ++ curr_slot->temp = kzalloc(sizeof(struct slot_temp_obj_t) * temp_num, GFP_KERNEL); ++ if (!curr_slot->temp) { ++ SLOT_ERR("kzalloc slot temp error, slot index = %d, temp number = %d.\n", curr_slot->obj->index, temp_num); ++ return -ENOMEM; ++ } ++ ++ for (temp_index = 1; temp_index <= temp_num; temp_index++) { ++ if (slotindex_single_temp_create_kobj_and_attrs(curr_slot, temp_index) != 0) { ++ goto error; ++ } ++ } ++ return 0; ++error: ++ for (i = temp_index - 1; i > 0; i--) { ++ slotindex_single_temp_remove_kobj_and_attrs(curr_slot, i); ++ } ++ ++ if (curr_slot->temp) { ++ kfree(curr_slot->temp); ++ curr_slot->temp = NULL; ++ curr_slot->temp_number = 0; ++ } ++ return -EBADRQC; ++} ++ ++static void slotindex_single_in_remove_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int in_index) ++{ ++ ++ struct slot_in_obj_t *curr_in; /* point to in1 in2...*/ ++ ++ curr_in = &curr_slot->in[in_index - 1]; ++ if (curr_in->obj) { ++ sysfs_remove_group(&curr_in->obj->kobj, &in_attr_group); ++ wb_plat_kobject_delete(&curr_in->obj); ++ SLOT_DBG("delete slot:%d in%d.\n", curr_slot->obj->index, in_index); ++ } ++ return; ++} ++ ++static int slotindex_single_in_create_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int in_index) ++{ ++ char name[DIR_NAME_MAX_LEN]; ++ struct slot_in_obj_t *curr_in; /* point to in1 in2...*/ ++ ++ curr_in = &curr_slot->in[in_index - 1]; ++ mem_clear(name, sizeof(name)); ++ snprintf(name, sizeof(name), "%s%d", VOLTAGE_SYSFS_NAME, in_index); ++ curr_in->obj = wb_plat_kobject_create(name, &curr_slot->obj->kobj); ++ if (!curr_in->obj) { ++ SLOT_ERR("create slot_index:%d, in%d object error!\n", curr_slot->obj->index, in_index); ++ return -EBADRQC; ++ } ++ curr_in->obj->index = in_index; ++ if (sysfs_create_group(&curr_in->obj->kobj, &in_attr_group) != 0) { ++ SLOT_ERR("create slot_index:%d, in%d attrs error.\n", curr_slot->obj->index, in_index); ++ wb_plat_kobject_delete(&curr_in->obj); ++ return -EBADRQC; ++ } ++ SLOT_DBG("create slot_index:%d, in%d ok.\n", curr_slot->obj->index, in_index); ++ return 0; ++} ++ ++static void slotindex_in_remove_kobj_and_attrs(struct slot_obj_t * curr_slot) ++{ ++ int in_index; ++ ++ for(in_index = curr_slot->in_number; in_index > 0; in_index--) { ++ slotindex_single_in_remove_kobj_and_attrs(curr_slot, in_index); ++ } ++ ++ if(curr_slot->in) { ++ kfree(curr_slot->in); ++ curr_slot->in = NULL; ++ curr_slot->in_number = 0; ++ } ++ return; ++} ++ ++static int slotindex_in_create_kobj_and_attrs(struct slot_obj_t * curr_slot, int in_num) ++{ ++ int in_index, i; ++ ++ curr_slot->in_number = in_num; ++ curr_slot->in = kzalloc(sizeof(struct slot_in_obj_t) * in_num, GFP_KERNEL); ++ if (!curr_slot->in) { ++ SLOT_ERR("kzalloc slot Voltage error, slot index = %d, Voltage number = %d.\n", curr_slot->obj->index, in_num); ++ return -ENOMEM; ++ } ++ ++ for (in_index = 1; in_index <= in_num; in_index++) { ++ if (slotindex_single_in_create_kobj_and_attrs(curr_slot, in_index) != 0 ) { ++ goto error; ++ } ++ } ++ return 0; ++error: ++ for (i = in_index - 1; i > 0; i++) { ++ slotindex_single_in_remove_kobj_and_attrs(curr_slot, i); ++ } ++ ++ if (curr_slot->in) { ++ kfree(curr_slot->in); ++ curr_slot->in = NULL; ++ curr_slot->in_number = 0; ++ } ++ return -EBADRQC; ++} ++ ++static void slotindex_obj_remove_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int obj_id) ++{ ++ switch (obj_id) { ++ case WB_MINOR_DEV_TEMP: ++ slotindex_temp_remove_kobj_and_attrs(curr_slot); ++ break; ++ case WB_MINOR_DEV_IN: ++ slotindex_in_remove_kobj_and_attrs(curr_slot); ++ break; ++ default: ++ SLOT_ERR("Unknow obj id:%d\n", obj_id); ++ } ++ return ; ++} ++ ++static int slotindex_obj_create_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int obj_id, int obj_num) ++{ ++ int ret; ++ ++ switch (obj_id) { ++ case WB_MINOR_DEV_TEMP: ++ ret = slotindex_temp_create_kobj_and_attrs(curr_slot, obj_num); ++ break; ++ case WB_MINOR_DEV_IN: ++ ret = slotindex_in_create_kobj_and_attrs(curr_slot, obj_num); ++ break; ++ default: ++ SLOT_ERR("Unknow obj id:%d\n", obj_id); ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++static void slot_child_obj_remove_by_id(unsigned int obj_id) ++{ ++ int slot_num; ++ unsigned int slot_index; ++ struct slot_obj_t *curr_slot; /* point to slot1 slot2...*/ ++ ++ slot_num = g_slot.slot_number; ++ if (slot_num <= 0 || !g_slot.slot) { ++ SLOT_DBG("Warning:slot number = %d\n", slot_num); ++ return; ++ } ++ ++ for(slot_index = slot_num; slot_index > 0; slot_index--) { ++ curr_slot = &g_slot.slot[slot_index - 1]; ++ slotindex_obj_remove_kobj_and_attrs(curr_slot, obj_id); ++ } ++ return; ++} ++ ++static int slot_child_obj_create_by_id(unsigned int obj_id) ++{ ++ int slot_num, obj_num; ++ unsigned int slot_index, i; ++ struct slot_obj_t *curr_slot; /* point to slot1 slot2...*/ ++ ++ check_p(g_drv->get_dev_number); ++ obj_num = g_drv->get_dev_number(WB_MAIN_DEV_SLOT,obj_id); ++ slot_num = g_slot.slot_number; ++ if (obj_num <= 0 || slot_num <= 0 || !g_slot.slot) { ++ SLOT_DBG("Warning:slot number = %d, object number:%d.obj_id:%d\n", slot_num, obj_num, obj_id); ++ return 0; ++ } ++ ++ for (slot_index = 1; slot_index <= slot_num; slot_index++) { ++ curr_slot = &g_slot.slot[slot_index - 1]; ++ if (slotindex_obj_create_kobj_and_attrs(curr_slot, obj_id, obj_num) != 0) { ++ goto error; ++ } ++ } ++ return 0; ++error: ++ for(i = slot_index - 1; i > 0; i++) { ++ curr_slot = &g_slot.slot[i - 1]; ++ slotindex_obj_remove_kobj_and_attrs(curr_slot, obj_id); ++ } ++ return -EBADRQC; ++} ++ ++static void slot_child_obj_remove(void) ++{ ++ /* temp remove */ ++ slot_child_obj_remove_by_id(WB_MINOR_DEV_TEMP); ++ ++ /* in creat */ ++ slot_child_obj_remove_by_id(WB_MINOR_DEV_IN); ++ return; ++} ++ ++static int slot_child_obj_create(void) ++{ ++ int ret; ++ ++ /* temp creat */ ++ ret = slot_child_obj_create_by_id(WB_MINOR_DEV_TEMP); ++ if (ret < 0) { ++ goto temp_err; ++ } ++ /* Voltage creat */ ++ ret = slot_child_obj_create_by_id(WB_MINOR_DEV_IN); ++ if(ret < 0) { ++ goto in_err; ++ } ++ return 0; ++in_err: ++ slot_child_obj_remove_by_id(WB_MINOR_DEV_TEMP); ++temp_err: ++ return ret; ++} ++ ++static void slot_sub_single_remove_kobj_and_attrs(unsigned int index) ++{ ++ struct slot_obj_t *curr_slot; ++ ++ curr_slot = &g_slot.slot[index - 1]; ++ if (curr_slot->obj) { ++ sysfs_remove_group(&curr_slot->obj->kobj, &slot_attr_group); ++ wb_plat_kobject_delete(&curr_slot->obj); ++ SLOT_DBG("delete slot%d.\n", index); ++ } ++ return; ++} ++ ++static int slot_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) ++{ ++ char name[DIR_NAME_MAX_LEN]; ++ struct slot_obj_t *curr_slot; ++ ++ curr_slot = &g_slot.slot[index - 1]; ++ SLOT_DBG("create %s%d ...\n", SLOT_SYSFS_NAME, index); ++ mem_clear(name, sizeof(name)); ++ snprintf(name, sizeof(name), "%s%d", SLOT_SYSFS_NAME, index); ++ curr_slot->obj = wb_plat_kobject_create(name, parent); ++ if (!curr_slot->obj) { ++ SLOT_ERR("create slot%d object error!\n", index); ++ return -EBADRQC; ++ } ++ curr_slot->obj->index = index; ++ if (sysfs_create_group(&curr_slot->obj->kobj, &slot_attr_group) != 0) { ++ SLOT_ERR("create slot%d attrs error.\n", index); ++ wb_plat_kobject_delete(&curr_slot->obj); ++ return -EBADRQC; ++ } ++ SLOT_DBG("create slot%d ok.\n", index); ++ return 0; ++} ++ ++static int slot_sub_create_kobj_and_attrs(struct kobject *parent, int slot_num) ++{ ++ unsigned int slot_index, i; ++ ++ g_slot.slot = kzalloc(sizeof(struct slot_obj_t) * slot_num, GFP_KERNEL); ++ if (!g_slot.slot) { ++ SLOT_ERR("kzalloc slot.slot error, slot number = %d.\n", slot_num); ++ return -ENOMEM; ++ } ++ ++ for (slot_index = 1; slot_index <= slot_num; slot_index++) { ++ if (slot_sub_single_create_kobj_and_attrs(parent, slot_index) != 0) { ++ goto error; ++ } ++ } ++ return 0; ++error: ++ for (i = slot_index - 1; i > 0; i--) { ++ slot_sub_single_remove_kobj_and_attrs(i); ++ } ++ if (g_slot.slot) { ++ kfree(g_slot.slot); ++ g_slot.slot = NULL; ++ } ++ return -EBADRQC; ++} ++ ++/* create slot1 slot2...dir and attrs */ ++static int slot_sub_create(void) ++{ ++ int ret, slot_num; ++ ++ check_p(g_drv->get_dev_number); ++ slot_num = g_drv->get_dev_number(WB_MAIN_DEV_SLOT, WB_MINOR_DEV_NONE); ++ g_slot.slot_number = slot_num; ++ if (slot_num <= 0) { ++ SLOT_DBG("Warning:slot number = %d \n", slot_num); ++ return 0; ++ } ++ ret = slot_sub_create_kobj_and_attrs(&g_slot_obj->kobj, slot_num); ++ return ret; ++} ++ ++/** ++ * slot_sub_remove - delete slot1 slot2...dir and attrs ++ */ ++static void slot_sub_remove(void) ++{ ++ unsigned int slot_index; ++ ++ if (g_slot.slot) { ++ for (slot_index = g_slot.slot_number; slot_index > 0; slot_index--) { ++ slot_sub_single_remove_kobj_and_attrs(slot_index); ++ } ++ kfree(g_slot.slot); ++ } ++ mem_clear(&g_slot, sizeof(struct slot_t)); ++ return ; ++} ++ ++/* create slot dir and num_slots attr */ ++static int slot_root_create(void) ++{ ++ g_slot_obj = wb_plat_kobject_create(SLOT_SYSFS_NAME, NULL); ++ if (!g_slot_obj) { ++ SLOT_ERR("wb_plat_kobject_create slot error!\n"); ++ return -ENOMEM; ++ } ++ ++ if (sysfs_create_group(&g_slot_obj->kobj, &slot_root_attr_group) != 0) { ++ wb_plat_kobject_delete(&g_slot_obj); ++ SLOT_ERR("create slot dir attrs error!\n"); ++ return -EBADRQC; ++ } ++ SLOT_DBG("wb_plat_kobject_create slot directory and attribute success.\n"); ++ return 0; ++} ++ ++static void slot_root_remove(void) ++{ ++ if (g_slot_obj) { ++ sysfs_remove_group(&g_slot_obj->kobj, &slot_root_attr_group); ++ wb_plat_kobject_delete(&g_slot_obj); ++ SLOT_DBG("delete slot root success\n"); ++ } ++ ++ return; ++} ++ ++static int wb_slot_init(void) ++{ ++ int ret; ++ ++ SLOT_INFO("wb_slot_init...\n"); ++ g_drv = dfd_plat_driver_get(); ++ check_p(g_drv); ++ ++ ret = slot_root_create(); ++ if (ret < 0) { ++ goto slot_root_error; ++ } ++ ++ ret = slot_sub_create(); ++ if (ret < 0) { ++ goto slot_sub_error; ++ } ++ ++ ret = slot_child_obj_create(); ++ if (ret < 0) { ++ goto slot_child_obj_error; ++ } ++ ++ SLOT_INFO("wb_slot_init ok.\n"); ++ return 0; ++slot_child_obj_error: ++ slot_sub_remove(); ++slot_sub_error: ++ slot_root_remove(); ++slot_root_error: ++ return ret; ++} ++ ++static void wb_slot_exit(void) ++{ ++ slot_child_obj_remove(); ++ slot_sub_remove(); ++ slot_root_remove(); ++ SLOT_INFO("wb_slot_exit ok.\n"); ++ return ; ++} ++ ++module_init(wb_slot_init); ++module_exit(wb_slot_exit); ++module_param(g_loglevel, int, 0644); ++MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("slot sysfs driver"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_switch.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_switch.c +new file mode 100644 +index 000000000..9563260f3 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_switch.c +@@ -0,0 +1,131 @@ ++/* ++ * plat_switch.c ++ * ++ * This module create a kset in sysfs called /sys/wb_plat ++ * Then other switch kobjects are created and assigned to this kset, ++ * such as "board", "cpld", "fan", "psu", "sff", ... ++ * ++ */ ++#include "./include/plat_switch.h" ++ ++#define SWITCH_INFO(fmt, args...) LOG_INFO("switch: ", fmt, ##args) ++#define SWITCH_ERR(fmt, args...) LOG_ERR("switch: ", fmt, ##args) ++#define SWITCH_DBG(fmt, args...) LOG_DBG("switch: ", fmt, ##args) ++ ++static int g_loglevel = 0; ++ ++static ssize_t switch_attr_show(struct kobject *kobj, ++ struct attribute *attr, char *buf) ++{ ++ struct switch_attribute *attribute; ++ struct switch_obj *device; ++ ++ attribute = to_switch_attr(attr); ++ device = to_switch_obj(kobj); ++ ++ if (!attribute->show) ++ return -ENOSYS; ++ ++ return attribute->show(device, attribute, buf); ++} ++ ++static ssize_t switch_attr_store(struct kobject *kobj, ++ struct attribute *attr, const char *buf, size_t len) ++{ ++ struct switch_attribute *attribute; ++ struct switch_obj *obj; ++ ++ attribute = to_switch_attr(attr); ++ obj = to_switch_obj(kobj); ++ ++ if (!attribute->store) ++ return -ENOSYS; ++ ++ return attribute->store(obj, attribute, buf, len); ++} ++ ++static const struct sysfs_ops switch_sysfs_ops = { ++ .show = switch_attr_show, ++ .store = switch_attr_store, ++}; ++ ++static void switch_obj_release(struct kobject *kobj) ++{ ++ struct switch_obj *obj; ++ ++ obj = to_switch_obj(kobj); ++ kfree(obj); ++} ++ ++static struct kobj_type switch_ktype = { ++ .sysfs_ops = &switch_sysfs_ops, ++ .release = switch_obj_release, ++ .default_attrs = NULL, ++}; ++ ++static struct kset *switch_kset; ++ ++struct switch_obj *wb_plat_kobject_create(const char *name, struct kobject *parent) ++{ ++ struct switch_obj *obj = NULL; ++ int ret = 0; ++ ++ obj = kzalloc(sizeof(*obj), GFP_KERNEL); ++ if (!obj) { ++ SWITCH_DBG("wb_plat_kobject_create %s kzalloc error", name); ++ return NULL; ++ } ++ ++ obj->kobj.kset = switch_kset; ++ ++ ret = kobject_init_and_add(&obj->kobj, &switch_ktype, parent, "%s", name); ++ if (ret) { ++ kobject_put(&obj->kobj); ++ SWITCH_DBG("kobject_init_and_add %s error", name); ++ return NULL; ++ } ++ ++ return obj; ++} ++ ++void wb_plat_kobject_delete(struct switch_obj **obj) ++{ ++ if (*obj) { ++ SWITCH_DBG("%s delete %s.\n", (*obj)->kobj.parent->name, (*obj)->kobj.name); ++ kobject_put(&((*obj)->kobj)); ++ *obj = NULL; ++ } ++} ++ ++static int __init switch_init(void) ++{ ++ SWITCH_INFO("...\n"); ++ ++ switch_kset = kset_create_and_add("wb_plat", NULL, NULL); ++ if (!switch_kset) { ++ SWITCH_ERR("create switch_kset error.\n"); ++ return -ENOMEM; ++ } ++ ++ SWITCH_INFO("ok.\n"); ++ return 0; ++} ++ ++static void __exit switch_exit(void) ++{ ++ if (switch_kset) { ++ kset_unregister(switch_kset); ++ } ++ ++ SWITCH_INFO("ok.\n"); ++} ++ ++module_init(switch_init); ++module_exit(switch_exit); ++EXPORT_SYMBOL(wb_plat_kobject_create); ++EXPORT_SYMBOL(wb_plat_kobject_delete); ++module_param(g_loglevel, int, 0644); ++MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("Switch driver"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common.h +new file mode 100644 +index 000000000..9e4a4fae0 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common.h +@@ -0,0 +1,74 @@ ++#ifndef __PLATFORM_COMMON_H__ ++#define __PLATFORM_COMMON_H__ ++ ++#include ++#include ++#include ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++ ++typedef enum { ++ DBG_START, ++ DBG_VERBOSE, ++ DBG_KEY, ++ DBG_WARN, ++ DBG_ERROR, ++ DBG_END, ++} dbg_level_t; ++ ++ typedef struct dfd_i2c_dev_s { ++ int bus; ++ int addr; ++ } dfd_i2c_dev_t; ++ ++typedef struct dfd_dev_head_info_s { ++ uint8_t ver; ++ uint8_t flag; ++ uint8_t hw_ver; ++ uint8_t type; ++ int16_t tlv_len; ++} dfd_dev_head_info_t; ++ ++typedef struct dfd_dev_tlv_info_s { ++ uint8_t type; ++ uint8_t len; ++ uint8_t data[0]; ++} dfd_dev_tlv_info_t; ++ ++typedef enum dfd_dev_info_type_e { ++ DFD_DEV_INFO_TYPE_MAC = 1, ++ DFD_DEV_INFO_TYPE_NAME = 2, ++ DFD_DEV_INFO_TYPE_SN = 3, ++ DFD_DEV_INFO_TYPE_PWR_CONS = 4, ++ DFD_DEV_INFO_TYPE_HW_INFO = 5, ++ DFD_DEV_INFO_TYPE_DEV_TYPE = 6, ++} dfd_dev_tlv_type_t; ++ ++extern int debuglevel; ++extern s32 platform_i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command); ++extern s32 platform_i2c_smbus_read_i2c_block_data(const struct i2c_client *client, ++ u8 command, u8 length, u8 *values); ++extern s32 platform_i2c_smbus_read_word_data(const struct i2c_client *client, u8 command); ++ ++#define DBG_DEBUG(fmt, arg...) do { \ ++ if ( debuglevel > DBG_START && debuglevel < DBG_ERROR) { \ ++ printk(KERN_INFO "[DEBUG]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ ++ } else if ( debuglevel >= DBG_ERROR ) { \ ++ printk(KERN_ERR "[DEBUG]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ ++ } else { } \ ++} while (0) ++ ++#define DBG_INFO(fmt, arg...) do { \ ++ if ( debuglevel > DBG_KEY) { \ ++ printk(KERN_INFO "[INFO]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ ++ } \ ++ } while (0) ++ ++#define DBG_ERROR(fmt, arg...) do { \ ++ if ( debuglevel > DBG_START) { \ ++ printk(KERN_ERR "[ERROR]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ ++ } \ ++ } while (0) ++ ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common_module.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common_module.c +new file mode 100644 +index 000000000..189a3aa05 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common_module.c +@@ -0,0 +1,210 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,152) ++#include ++#else ++#include ++#endif ++#include ++#include ++#include ++#include ++#include "platform_common.h" ++#include "dfd_tlveeprom.h" ++ ++#define PLATFORM_I2C_RETRY_TIMES 3 ++ ++#define DFD_TLVEEPROM_I2C_BUS (0) ++#define DFD_TLVEEPROM_I2C_ADDR (0x56) ++#define DFD_E2PROM_MAX_LEN (256) ++#define DFD_CARDTYPE_EXT_TLVLEN (4) ++ ++#define PLATFORM_CARDTYPE_RETRY_CNT (10) ++#define PLATFORM_CARDTYPE_RETRY_TIMES (1000) ++ ++int debuglevel = 0; ++module_param(debuglevel, int, S_IRUGO | S_IWUSR); ++ ++static int dfd_my_type = 0; ++module_param(dfd_my_type, int, S_IRUGO | S_IWUSR); ++ ++int g_common_debug_error = 0; ++module_param(g_common_debug_error, int, S_IRUGO | S_IWUSR); ++ ++int g_common_debug_verbose = 0; ++module_param(g_common_debug_verbose, int, S_IRUGO | S_IWUSR); ++ ++uint32_t dfd_my_type_i2c_bus = 0; ++module_param(dfd_my_type_i2c_bus, int, S_IRUGO | S_IWUSR); ++ ++uint32_t dfd_my_type_i2c_addr = 0; ++module_param(dfd_my_type_i2c_addr, int, S_IRUGO | S_IWUSR); ++ ++#define PLATFORM_COMMON_DEBUG_VERBOSE(fmt, args...) do { \ ++ if (g_common_debug_verbose) { \ ++ printk(KERN_ERR "[PLATFORM_COMMON][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define PLATFORM_COMMON_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_common_debug_error) { \ ++ printk(KERN_ERR "[PLATFORM_COMMON][ERROR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static int32_t dfd_i2c_read(char *dev, uint32_t addr, uint32_t offset_addr, unsigned char * ++buf, int32_t size) ++{ ++ struct file *fp; ++ struct i2c_client client; ++ int i ,j; ++ int rv; ++ s32 val_t; ++ ++ val_t = -1; ++ rv = 0; ++ fp = filp_open(dev, O_RDWR, S_IRUSR | S_IWUSR); ++ if (IS_ERR(fp)) { ++ DBG_ERROR("i2c open fail.\n"); ++ PLATFORM_COMMON_DEBUG_ERROR("i2c open fail.\n"); ++ return -1; ++ } ++ memcpy(&client, fp->private_data, sizeof(struct i2c_client)); ++ client.addr = addr; ++ for (j = 0 ;j < size ;j++){ ++ for (i = 0; i < PLATFORM_I2C_RETRY_TIMES; i++) { ++ if ((val_t = i2c_smbus_read_byte_data(&client, (offset_addr + j)))< 0) { ++ DBG_DEBUG("read try(%d)time offset_addr:%x \n", i, offset_addr); ++ continue; ++ } else { ++ * (buf + j) = val_t; ++ break; ++ } ++ } ++ if (val_t < 0) { ++ rv = -1; ++ break; ++ } ++ } ++ filp_close(fp, NULL); ++ return rv; ++} ++ ++static int dfd_tlvinfo_get_cardtype(void) ++{ ++ char i2c_path[16] = {0}; ++ int ret; ++ int cardtype; ++ u_int8_t eeprom[DFD_E2PROM_MAX_LEN]; ++ dfd_i2c_dev_t i2c_dev; ++ uint8_t buf[DFD_CARDTYPE_EXT_TLVLEN]; ++ uint8_t len; ++ dfd_tlv_type_t tlv_type; ++ ++ if (dfd_my_type_i2c_bus != 0) { ++ i2c_dev.bus = dfd_my_type_i2c_bus; ++ } else { ++ i2c_dev.bus = DFD_TLVEEPROM_I2C_BUS; ++ } ++ ++ if (dfd_my_type_i2c_addr != 0) { ++ i2c_dev.addr = dfd_my_type_i2c_addr; ++ } else { ++ i2c_dev.addr = DFD_TLVEEPROM_I2C_ADDR; ++ } ++ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_dev.bus); ++ PLATFORM_COMMON_DEBUG_VERBOSE("Read device eeprom info:(dev:%s, addr:%02x).\n", i2c_path, i2c_dev.addr); ++ ++ ret = dfd_i2c_read(i2c_path, i2c_dev.addr, 0, eeprom, DFD_E2PROM_MAX_LEN); ++ if (ret != 0) { ++ DBG_ERROR("Read eeprom info error(dev: %s, addr: %02x).\n", i2c_path, i2c_dev.addr); ++ PLATFORM_COMMON_DEBUG_ERROR("Read eeprom info error(dev: %s, addr: %02x).\n", i2c_path, i2c_dev.addr); ++ return ret; ++ } ++ ++ tlv_type.main_type = TLV_CODE_VENDOR_EXT; ++ tlv_type.ext_type = DFD_TLVINFO_EXT_TLV_TYPE_DEV_TYPE; ++ len = sizeof(buf); ++ mem_clear(buf, len); ++ ret = dfd_tlvinfo_get_e2prom_info(eeprom, DFD_E2PROM_MAX_LEN, &tlv_type, buf, &len); ++ if (ret) { ++ DBG_ERROR("dfd_tlvinfo_get_e2prom_info failed ret %d.\n", ret); ++ return -1; ++ } ++ for (ret = 0; ret < 4; ret++) { ++ DBG_DEBUG("buf 0x%02x.\n", buf[ret]); ++ } ++ ++ cardtype = ntohl(*((uint32_t *)buf)); ++ DBG_DEBUG("cardtype 0x%x.\n", cardtype); ++ return cardtype; ++} ++ ++static int __dfd_get_my_card_type(void) ++{ ++ return dfd_tlvinfo_get_cardtype(); ++} ++ ++int dfd_get_my_card_type(void) ++{ ++ int type; ++ int cnt; ++ ++ if (dfd_my_type != 0) { ++ DBG_DEBUG("my_type = 0x%x\r\n", dfd_my_type); ++ return dfd_my_type; ++ } ++ ++ cnt = PLATFORM_CARDTYPE_RETRY_CNT; ++ while (cnt--) { ++ type = __dfd_get_my_card_type(); ++ if (type < 0) { ++ PLATFORM_COMMON_DEBUG_ERROR("__dfd_get_my_card_type fail cnt %d, ret %d.\n", cnt, type); ++ msleep(PLATFORM_CARDTYPE_RETRY_TIMES); ++ continue; ++ } ++ PLATFORM_COMMON_DEBUG_VERBOSE("success to get type 0x%x.\n", type); ++ break; ++ } ++ ++ dfd_my_type = type; ++ return dfd_my_type; ++} ++EXPORT_SYMBOL(dfd_get_my_card_type); ++ ++static int __init platform_common_init(void) ++{ ++ int ret; ++ ++ PLATFORM_COMMON_DEBUG_VERBOSE("Enter.\n"); ++ ret = dfd_get_my_card_type(); ++ if (ret <= 0) { ++ PLATFORM_COMMON_DEBUG_ERROR("dfd_get_my_card_type failed, ret %d.\n", ret); ++ printk(KERN_ERR "Warning: Device type get failed, please check the TLV-EEPROM!\n"); ++ return -1; ++ } ++ ++ PLATFORM_COMMON_DEBUG_VERBOSE("Leave success type 0x%x.\n", ret); ++ return 0; ++} ++ ++static void __exit platform_common_exit(void) ++{ ++ PLATFORM_COMMON_DEBUG_VERBOSE("Exit.\n"); ++} ++ ++module_init(platform_common_init); ++module_exit(platform_common_exit); ++ ++MODULE_DESCRIPTION("Platform Support"); ++MODULE_AUTHOR("support"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/Makefile +new file mode 100644 +index 000000000..6831a03a6 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/Makefile +@@ -0,0 +1,18 @@ ++PWD = $(shell pwd) ++ ++EXTRA_CFLAGS:= -I$(M)/include ++EXTRA_CFLAGS+= -Wall ++ ++sdhci_pci-objs := sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \ ++ sdhci-pci-dwc-mshc.o sdhci-pci-gli.o ++obj-m += sdhci_pci.o ++ ++ ++all: ++ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules ++ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi ++ @if [ -f $(PWD)/*.ko ]; then cp -p $(PWD)/*.ko $(module_out_put_dir);fi ++clean: ++ rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd ++ rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order ++ rm -rf $(PWD)/.tmp_versions +\ No newline at end of file +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/cqhci.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/cqhci.h +new file mode 100644 +index 000000000..89bf6adbc +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/cqhci.h +@@ -0,0 +1,242 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* Copyright (c) 2015, The Linux Foundation. All rights reserved. ++ */ ++#ifndef LINUX_MMC_CQHCI_H ++#define LINUX_MMC_CQHCI_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* registers */ ++/* version */ ++#define CQHCI_VER 0x00 ++#define CQHCI_VER_MAJOR(x) (((x) & GENMASK(11, 8)) >> 8) ++#define CQHCI_VER_MINOR1(x) (((x) & GENMASK(7, 4)) >> 4) ++#define CQHCI_VER_MINOR2(x) ((x) & GENMASK(3, 0)) ++ ++/* capabilities */ ++#define CQHCI_CAP 0x04 ++/* configuration */ ++#define CQHCI_CFG 0x08 ++#define CQHCI_DCMD 0x00001000 ++#define CQHCI_TASK_DESC_SZ 0x00000100 ++#define CQHCI_ENABLE 0x00000001 ++ ++/* control */ ++#define CQHCI_CTL 0x0C ++#define CQHCI_CLEAR_ALL_TASKS 0x00000100 ++#define CQHCI_HALT 0x00000001 ++ ++/* interrupt status */ ++#define CQHCI_IS 0x10 ++#define CQHCI_IS_HAC BIT(0) ++#define CQHCI_IS_TCC BIT(1) ++#define CQHCI_IS_RED BIT(2) ++#define CQHCI_IS_TCL BIT(3) ++ ++#define CQHCI_IS_MASK (CQHCI_IS_TCC | CQHCI_IS_RED) ++ ++/* interrupt status enable */ ++#define CQHCI_ISTE 0x14 ++ ++/* interrupt signal enable */ ++#define CQHCI_ISGE 0x18 ++ ++/* interrupt coalescing */ ++#define CQHCI_IC 0x1C ++#define CQHCI_IC_ENABLE BIT(31) ++#define CQHCI_IC_RESET BIT(16) ++#define CQHCI_IC_ICCTHWEN BIT(15) ++#define CQHCI_IC_ICCTH(x) (((x) & 0x1F) << 8) ++#define CQHCI_IC_ICTOVALWEN BIT(7) ++#define CQHCI_IC_ICTOVAL(x) ((x) & 0x7F) ++ ++/* task list base address */ ++#define CQHCI_TDLBA 0x20 ++ ++/* task list base address upper */ ++#define CQHCI_TDLBAU 0x24 ++ ++/* door-bell */ ++#define CQHCI_TDBR 0x28 ++ ++/* task completion notification */ ++#define CQHCI_TCN 0x2C ++ ++/* device queue status */ ++#define CQHCI_DQS 0x30 ++ ++/* device pending tasks */ ++#define CQHCI_DPT 0x34 ++ ++/* task clear */ ++#define CQHCI_TCLR 0x38 ++ ++/* send status config 1 */ ++#define CQHCI_SSC1 0x40 ++#define CQHCI_SSC1_CBC_MASK GENMASK(19, 16) ++ ++/* send status config 2 */ ++#define CQHCI_SSC2 0x44 ++ ++/* response for dcmd */ ++#define CQHCI_CRDCT 0x48 ++ ++/* response mode error mask */ ++#define CQHCI_RMEM 0x50 ++ ++/* task error info */ ++#define CQHCI_TERRI 0x54 ++ ++#define CQHCI_TERRI_C_INDEX(x) ((x) & GENMASK(5, 0)) ++#define CQHCI_TERRI_C_TASK(x) (((x) & GENMASK(12, 8)) >> 8) ++#define CQHCI_TERRI_C_VALID(x) ((x) & BIT(15)) ++#define CQHCI_TERRI_D_INDEX(x) (((x) & GENMASK(21, 16)) >> 16) ++#define CQHCI_TERRI_D_TASK(x) (((x) & GENMASK(28, 24)) >> 24) ++#define CQHCI_TERRI_D_VALID(x) ((x) & BIT(31)) ++ ++/* command response index */ ++#define CQHCI_CRI 0x58 ++ ++/* command response argument */ ++#define CQHCI_CRA 0x5C ++ ++#define CQHCI_INT_ALL 0xF ++#define CQHCI_IC_DEFAULT_ICCTH 31 ++#define CQHCI_IC_DEFAULT_ICTOVAL 1 ++ ++/* attribute fields */ ++#define CQHCI_VALID(x) (((x) & 1) << 0) ++#define CQHCI_END(x) (((x) & 1) << 1) ++#define CQHCI_INT(x) (((x) & 1) << 2) ++#define CQHCI_ACT(x) (((x) & 0x7) << 3) ++ ++/* data command task descriptor fields */ ++#define CQHCI_FORCED_PROG(x) (((x) & 1) << 6) ++#define CQHCI_CONTEXT(x) (((x) & 0xF) << 7) ++#define CQHCI_DATA_TAG(x) (((x) & 1) << 11) ++#define CQHCI_DATA_DIR(x) (((x) & 1) << 12) ++#define CQHCI_PRIORITY(x) (((x) & 1) << 13) ++#define CQHCI_QBAR(x) (((x) & 1) << 14) ++#define CQHCI_REL_WRITE(x) (((x) & 1) << 15) ++#define CQHCI_BLK_COUNT(x) (((x) & 0xFFFF) << 16) ++#define CQHCI_BLK_ADDR(x) (((x) & 0xFFFFFFFF) << 32) ++ ++/* direct command task descriptor fields */ ++#define CQHCI_CMD_INDEX(x) (((x) & 0x3F) << 16) ++#define CQHCI_CMD_TIMING(x) (((x) & 1) << 22) ++#define CQHCI_RESP_TYPE(x) (((x) & 0x3) << 23) ++ ++/* transfer descriptor fields */ ++#define CQHCI_DAT_LENGTH(x) (((x) & 0xFFFF) << 16) ++#define CQHCI_DAT_ADDR_LO(x) (((x) & 0xFFFFFFFF) << 32) ++#define CQHCI_DAT_ADDR_HI(x) (((x) & 0xFFFFFFFF) << 0) ++ ++struct cqhci_host_ops; ++struct mmc_host; ++struct mmc_request; ++struct cqhci_slot; ++ ++struct cqhci_host { ++ const struct cqhci_host_ops *ops; ++ void __iomem *mmio; ++ struct mmc_host *mmc; ++ ++ spinlock_t lock; ++ ++ /* relative card address of device */ ++ unsigned int rca; ++ ++ /* 64 bit DMA */ ++ bool dma64; ++ int num_slots; ++ int qcnt; ++ ++ u32 dcmd_slot; ++ u32 caps; ++#define CQHCI_TASK_DESC_SZ_128 0x1 ++ ++ u32 quirks; ++#define CQHCI_QUIRK_SHORT_TXFR_DESC_SZ 0x1 ++ ++ bool enabled; ++ bool halted; ++ bool init_done; ++ bool activated; ++ bool waiting_for_idle; ++ bool recovery_halt; ++ ++ size_t desc_size; ++ size_t data_size; ++ ++ u8 *desc_base; ++ ++ /* total descriptor size */ ++ u8 slot_sz; ++ ++ /* 64/128 bit depends on CQHCI_CFG */ ++ u8 task_desc_len; ++ ++ /* 64 bit on 32-bit arch, 128 bit on 64-bit */ ++ u8 link_desc_len; ++ ++ u8 *trans_desc_base; ++ /* same length as transfer descriptor */ ++ u8 trans_desc_len; ++ ++ dma_addr_t desc_dma_base; ++ dma_addr_t trans_desc_dma_base; ++ ++ struct completion halt_comp; ++ wait_queue_head_t wait_queue; ++ struct cqhci_slot *slot; ++}; ++ ++struct cqhci_host_ops { ++ void (*dumpregs)(struct mmc_host *mmc); ++ void (*write_l)(struct cqhci_host *host, u32 val, int reg); ++ u32 (*read_l)(struct cqhci_host *host, int reg); ++ void (*enable)(struct mmc_host *mmc); ++ void (*disable)(struct mmc_host *mmc, bool recovery); ++ void (*update_dcmd_desc)(struct mmc_host *mmc, struct mmc_request *mrq, ++ u64 *data); ++ void (*pre_enable)(struct mmc_host *mmc); ++ void (*post_disable)(struct mmc_host *mmc); ++}; ++ ++static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg) ++{ ++ if (unlikely(host->ops->write_l)) ++ host->ops->write_l(host, val, reg); ++ else ++ writel_relaxed(val, host->mmio + reg); ++} ++ ++static inline u32 cqhci_readl(struct cqhci_host *host, int reg) ++{ ++ if (unlikely(host->ops->read_l)) ++ return host->ops->read_l(host, reg); ++ else ++ return readl_relaxed(host->mmio + reg); ++} ++ ++struct platform_device; ++ ++irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error, ++ int data_error); ++int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc, bool dma64); ++struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev); ++int cqhci_deactivate(struct mmc_host *mmc); ++static inline int cqhci_suspend(struct mmc_host *mmc) ++{ ++ return cqhci_deactivate(mmc); ++} ++int cqhci_resume(struct mmc_host *mmc); ++ ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-arasan.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-arasan.c +new file mode 100644 +index 000000000..499f3205e +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-arasan.c +@@ -0,0 +1,331 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * sdhci-pci-arasan.c - Driver for Arasan PCI Controller with ++ * integrated phy. ++ * ++ * Copyright (C) 2017 Arasan Chip Systems Inc. ++ * ++ * Author: Atul Garg ++ */ ++ ++#include ++#include ++ ++#include "sdhci.h" ++#include "sdhci-pci.h" ++ ++/* Extra registers for Arasan SD/SDIO/MMC Host Controller with PHY */ ++#define PHY_ADDR_REG 0x300 ++#define PHY_DAT_REG 0x304 ++ ++#define PHY_WRITE BIT(8) ++#define PHY_BUSY BIT(9) ++#define DATA_MASK 0xFF ++ ++/* PHY Specific Registers */ ++#define DLL_STATUS 0x00 ++#define IPAD_CTRL1 0x01 ++#define IPAD_CTRL2 0x02 ++#define IPAD_STS 0x03 ++#define IOREN_CTRL1 0x06 ++#define IOREN_CTRL2 0x07 ++#define IOPU_CTRL1 0x08 ++#define IOPU_CTRL2 0x09 ++#define ITAP_DELAY 0x0C ++#define OTAP_DELAY 0x0D ++#define STRB_SEL 0x0E ++#define CLKBUF_SEL 0x0F ++#define MODE_CTRL 0x11 ++#define DLL_TRIM 0x12 ++#define CMD_CTRL 0x20 ++#define DATA_CTRL 0x21 ++#define STRB_CTRL 0x22 ++#define CLK_CTRL 0x23 ++#define PHY_CTRL 0x24 ++ ++#define DLL_ENBL BIT(3) ++#define RTRIM_EN BIT(1) ++#define PDB_ENBL BIT(1) ++#define RETB_ENBL BIT(6) ++#define ODEN_CMD BIT(1) ++#define ODEN_DAT 0xFF ++#define REN_STRB BIT(0) ++#define REN_CMND BIT(1) ++#define REN_DATA 0xFF ++#define PU_CMD BIT(1) ++#define PU_DAT 0xFF ++#define ITAPDLY_EN BIT(0) ++#define OTAPDLY_EN BIT(0) ++#define OD_REL_CMD BIT(1) ++#define OD_REL_DAT 0xFF ++#define DLLTRM_ICP 0x8 ++#define PDB_CMND BIT(0) ++#define PDB_DATA 0xFF ++#define PDB_STRB BIT(0) ++#define PDB_CLOCK BIT(0) ++#define CALDONE_MASK 0x10 ++#define DLL_RDY_MASK 0x10 ++#define MAX_CLK_BUF 0x7 ++ ++/* Mode Controls */ ++#define ENHSTRB_MODE BIT(0) ++#define HS400_MODE BIT(1) ++#define LEGACY_MODE BIT(2) ++#define DDR50_MODE BIT(3) ++ ++/* ++ * Controller has no specific bits for HS200/HS. ++ * Used BIT(4), BIT(5) for software programming. ++ */ ++#define HS200_MODE BIT(4) ++#define HISPD_MODE BIT(5) ++ ++#define OTAPDLY(x) (((x) << 1) | OTAPDLY_EN) ++#define ITAPDLY(x) (((x) << 1) | ITAPDLY_EN) ++#define FREQSEL(x) (((x) << 5) | DLL_ENBL) ++#define IOPAD(x, y) ((x) | ((y) << 2)) ++ ++/* Arasan private data */ ++struct arasan_host { ++ u32 chg_clk; ++}; ++ ++static int arasan_phy_addr_poll(struct sdhci_host *host, u32 offset, u32 mask) ++{ ++ ktime_t timeout = ktime_add_us(ktime_get(), 100); ++ bool failed; ++ u8 val = 0; ++ ++ while (1) { ++ failed = ktime_after(ktime_get(), timeout); ++ val = sdhci_readw(host, PHY_ADDR_REG); ++ if (!(val & mask)) ++ return 0; ++ if (failed) ++ return -EBUSY; ++ } ++} ++ ++static int arasan_phy_write(struct sdhci_host *host, u8 data, u8 offset) ++{ ++ sdhci_writew(host, data, PHY_DAT_REG); ++ sdhci_writew(host, (PHY_WRITE | offset), PHY_ADDR_REG); ++ return arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY); ++} ++ ++static int arasan_phy_read(struct sdhci_host *host, u8 offset, u8 *data) ++{ ++ int ret; ++ ++ sdhci_writew(host, 0, PHY_DAT_REG); ++ sdhci_writew(host, offset, PHY_ADDR_REG); ++ ret = arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY); ++ ++ /* Masking valid data bits */ ++ *data = sdhci_readw(host, PHY_DAT_REG) & DATA_MASK; ++ return ret; ++} ++ ++static int arasan_phy_sts_poll(struct sdhci_host *host, u32 offset, u32 mask) ++{ ++ int ret; ++ ktime_t timeout = ktime_add_us(ktime_get(), 100); ++ bool failed; ++ u8 val = 0; ++ ++ while (1) { ++ failed = ktime_after(ktime_get(), timeout); ++ ret = arasan_phy_read(host, offset, &val); ++ if (ret) ++ return -EBUSY; ++ else if (val & mask) ++ return 0; ++ if (failed) ++ return -EBUSY; ++ } ++} ++ ++/* Initialize the Arasan PHY */ ++static int arasan_phy_init(struct sdhci_host *host) ++{ ++ int ret; ++ u8 val; ++ ++ /* Program IOPADs and wait for calibration to be done */ ++ if (arasan_phy_read(host, IPAD_CTRL1, &val) || ++ arasan_phy_write(host, val | RETB_ENBL | PDB_ENBL, IPAD_CTRL1) || ++ arasan_phy_read(host, IPAD_CTRL2, &val) || ++ arasan_phy_write(host, val | RTRIM_EN, IPAD_CTRL2)) ++ return -EBUSY; ++ ret = arasan_phy_sts_poll(host, IPAD_STS, CALDONE_MASK); ++ if (ret) ++ return -EBUSY; ++ ++ /* Program CMD/Data lines */ ++ if (arasan_phy_read(host, IOREN_CTRL1, &val) || ++ arasan_phy_write(host, val | REN_CMND | REN_STRB, IOREN_CTRL1) || ++ arasan_phy_read(host, IOPU_CTRL1, &val) || ++ arasan_phy_write(host, val | PU_CMD, IOPU_CTRL1) || ++ arasan_phy_read(host, CMD_CTRL, &val) || ++ arasan_phy_write(host, val | PDB_CMND, CMD_CTRL) || ++ arasan_phy_read(host, IOREN_CTRL2, &val) || ++ arasan_phy_write(host, val | REN_DATA, IOREN_CTRL2) || ++ arasan_phy_read(host, IOPU_CTRL2, &val) || ++ arasan_phy_write(host, val | PU_DAT, IOPU_CTRL2) || ++ arasan_phy_read(host, DATA_CTRL, &val) || ++ arasan_phy_write(host, val | PDB_DATA, DATA_CTRL) || ++ arasan_phy_read(host, STRB_CTRL, &val) || ++ arasan_phy_write(host, val | PDB_STRB, STRB_CTRL) || ++ arasan_phy_read(host, CLK_CTRL, &val) || ++ arasan_phy_write(host, val | PDB_CLOCK, CLK_CTRL) || ++ arasan_phy_read(host, CLKBUF_SEL, &val) || ++ arasan_phy_write(host, val | MAX_CLK_BUF, CLKBUF_SEL) || ++ arasan_phy_write(host, LEGACY_MODE, MODE_CTRL)) ++ return -EBUSY; ++ return 0; ++} ++ ++/* Set Arasan PHY for different modes */ ++static int arasan_phy_set(struct sdhci_host *host, u8 mode, u8 otap, ++ u8 drv_type, u8 itap, u8 trim, u8 clk) ++{ ++ u8 val; ++ int ret; ++ ++ if (mode == HISPD_MODE || mode == HS200_MODE) ++ ret = arasan_phy_write(host, 0x0, MODE_CTRL); ++ else ++ ret = arasan_phy_write(host, mode, MODE_CTRL); ++ if (ret) ++ return ret; ++ if (mode == HS400_MODE || mode == HS200_MODE) { ++ ret = arasan_phy_read(host, IPAD_CTRL1, &val); ++ if (ret) ++ return ret; ++ ret = arasan_phy_write(host, IOPAD(val, drv_type), IPAD_CTRL1); ++ if (ret) ++ return ret; ++ } ++ if (mode == LEGACY_MODE) { ++ ret = arasan_phy_write(host, 0x0, OTAP_DELAY); ++ if (ret) ++ return ret; ++ ret = arasan_phy_write(host, 0x0, ITAP_DELAY); ++ } else { ++ ret = arasan_phy_write(host, OTAPDLY(otap), OTAP_DELAY); ++ if (ret) ++ return ret; ++ if (mode != HS200_MODE) ++ ret = arasan_phy_write(host, ITAPDLY(itap), ITAP_DELAY); ++ else ++ ret = arasan_phy_write(host, 0x0, ITAP_DELAY); ++ } ++ if (ret) ++ return ret; ++ if (mode != LEGACY_MODE) { ++ ret = arasan_phy_write(host, trim, DLL_TRIM); ++ if (ret) ++ return ret; ++ } ++ ret = arasan_phy_write(host, 0, DLL_STATUS); ++ if (ret) ++ return ret; ++ if (mode != LEGACY_MODE) { ++ ret = arasan_phy_write(host, FREQSEL(clk), DLL_STATUS); ++ if (ret) ++ return ret; ++ ret = arasan_phy_sts_poll(host, DLL_STATUS, DLL_RDY_MASK); ++ if (ret) ++ return -EBUSY; ++ } ++ return 0; ++} ++ ++static int arasan_select_phy_clock(struct sdhci_host *host) ++{ ++ struct sdhci_pci_slot *slot = sdhci_priv(host); ++ struct arasan_host *arasan_host = sdhci_pci_priv(slot); ++ u8 clk; ++ ++ if (arasan_host->chg_clk == host->mmc->ios.clock) ++ return 0; ++ ++ arasan_host->chg_clk = host->mmc->ios.clock; ++ if (host->mmc->ios.clock == 200000000) ++ clk = 0x0; ++ else if (host->mmc->ios.clock == 100000000) ++ clk = 0x2; ++ else if (host->mmc->ios.clock == 50000000) ++ clk = 0x1; ++ else ++ clk = 0x0; ++ ++ if (host->mmc_host_ops.hs400_enhanced_strobe) { ++ arasan_phy_set(host, ENHSTRB_MODE, 1, 0x0, 0x0, ++ DLLTRM_ICP, clk); ++ } else { ++ switch (host->mmc->ios.timing) { ++ case MMC_TIMING_LEGACY: ++ arasan_phy_set(host, LEGACY_MODE, 0x0, 0x0, 0x0, ++ 0x0, 0x0); ++ break; ++ case MMC_TIMING_MMC_HS: ++ case MMC_TIMING_SD_HS: ++ arasan_phy_set(host, HISPD_MODE, 0x3, 0x0, 0x2, ++ DLLTRM_ICP, clk); ++ break; ++ case MMC_TIMING_MMC_HS200: ++ case MMC_TIMING_UHS_SDR104: ++ arasan_phy_set(host, HS200_MODE, 0x2, ++ host->mmc->ios.drv_type, 0x0, ++ DLLTRM_ICP, clk); ++ break; ++ case MMC_TIMING_MMC_DDR52: ++ case MMC_TIMING_UHS_DDR50: ++ arasan_phy_set(host, DDR50_MODE, 0x1, 0x0, ++ 0x0, DLLTRM_ICP, clk); ++ break; ++ case MMC_TIMING_MMC_HS400: ++ arasan_phy_set(host, HS400_MODE, 0x1, ++ host->mmc->ios.drv_type, 0xa, ++ DLLTRM_ICP, clk); ++ break; ++ default: ++ break; ++ } ++ } ++ return 0; ++} ++ ++static int arasan_pci_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ int err; ++ ++ slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | MMC_CAP_8_BIT_DATA; ++ err = arasan_phy_init(slot->host); ++ if (err) ++ return -ENODEV; ++ return 0; ++} ++ ++static void arasan_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) ++{ ++ sdhci_set_clock(host, clock); ++ ++ /* Change phy settings for the new clock */ ++ arasan_select_phy_clock(host); ++} ++ ++static const struct sdhci_ops arasan_sdhci_pci_ops = { ++ .set_clock = arasan_sdhci_set_clock, ++ .enable_dma = sdhci_pci_enable_dma, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, ++}; ++ ++const struct sdhci_pci_fixes sdhci_arasan = { ++ .probe_slot = arasan_pci_probe_slot, ++ .ops = &arasan_sdhci_pci_ops, ++ .priv_size = sizeof(struct arasan_host), ++}; +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-core.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-core.c +new file mode 100644 +index 000000000..5fe00b537 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-core.c +@@ -0,0 +1,2566 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* linux/drivers/mmc/host/sdhci-pci.c - SDHCI on PCI bus interface ++ * ++ * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. ++ * ++ * Thanks to the following companies for their support: ++ * ++ * - JMicron (hardware and technical support) ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_X86 ++#include ++#endif ++ ++#include "cqhci.h" ++ ++#include "sdhci.h" ++#include "sdhci-pci.h" ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++ ++static int wb_sdhci_pci = 0; ++module_param(wb_sdhci_pci, int, S_IRUGO); ++ ++static void sdhci_pci_hw_reset(struct sdhci_host *host); ++ ++#ifdef CONFIG_PM_SLEEP ++static int sdhci_pci_init_wakeup(struct sdhci_pci_chip *chip) ++{ ++ mmc_pm_flag_t pm_flags = 0; ++ bool cap_cd_wake = false; ++ int i; ++ ++ for (i = 0; i < chip->num_slots; i++) { ++ struct sdhci_pci_slot *slot = chip->slots[i]; ++ ++ if (slot) { ++ pm_flags |= slot->host->mmc->pm_flags; ++ if (slot->host->mmc->caps & MMC_CAP_CD_WAKE) ++ cap_cd_wake = true; ++ } ++ } ++ ++ if ((pm_flags & MMC_PM_KEEP_POWER) && (pm_flags & MMC_PM_WAKE_SDIO_IRQ)) ++ return device_wakeup_enable(&chip->pdev->dev); ++ else if (!cap_cd_wake) ++ return device_wakeup_disable(&chip->pdev->dev); ++ ++ return 0; ++} ++ ++static int sdhci_pci_suspend_host(struct sdhci_pci_chip *chip) ++{ ++ int i, ret; ++ ++ sdhci_pci_init_wakeup(chip); ++ ++ for (i = 0; i < chip->num_slots; i++) { ++ struct sdhci_pci_slot *slot = chip->slots[i]; ++ struct sdhci_host *host; ++ ++ if (!slot) ++ continue; ++ ++ host = slot->host; ++ ++ if (chip->pm_retune && host->tuning_mode != SDHCI_TUNING_MODE_3) ++ mmc_retune_needed(host->mmc); ++ ++ ret = sdhci_suspend_host(host); ++ if (ret) ++ goto err_pci_suspend; ++ ++ if (device_may_wakeup(&chip->pdev->dev)) ++ mmc_gpio_set_cd_wake(host->mmc, true); ++ } ++ ++ return 0; ++ ++err_pci_suspend: ++ while (--i >= 0) ++ sdhci_resume_host(chip->slots[i]->host); ++ return ret; ++} ++ ++int sdhci_pci_resume_host(struct sdhci_pci_chip *chip) ++{ ++ struct sdhci_pci_slot *slot; ++ int i, ret; ++ ++ for (i = 0; i < chip->num_slots; i++) { ++ slot = chip->slots[i]; ++ if (!slot) ++ continue; ++ ++ ret = sdhci_resume_host(slot->host); ++ if (ret) ++ return ret; ++ ++ mmc_gpio_set_cd_wake(slot->host->mmc, false); ++ } ++ ++ return 0; ++} ++ ++static int sdhci_cqhci_suspend(struct sdhci_pci_chip *chip) ++{ ++ int ret; ++ ++ ret = cqhci_suspend(chip->slots[0]->host->mmc); ++ if (ret) ++ return ret; ++ ++ return sdhci_pci_suspend_host(chip); ++} ++ ++static int sdhci_cqhci_resume(struct sdhci_pci_chip *chip) ++{ ++ int ret; ++ ++ ret = sdhci_pci_resume_host(chip); ++ if (ret) ++ return ret; ++ ++ return cqhci_resume(chip->slots[0]->host->mmc); ++} ++#endif ++ ++#ifdef CONFIG_PM ++static int sdhci_pci_runtime_suspend_host(struct sdhci_pci_chip *chip) ++{ ++ struct sdhci_pci_slot *slot; ++ struct sdhci_host *host; ++ int i, ret; ++ ++ for (i = 0; i < chip->num_slots; i++) { ++ slot = chip->slots[i]; ++ if (!slot) ++ continue; ++ ++ host = slot->host; ++ ++ ret = sdhci_runtime_suspend_host(host); ++ if (ret) ++ goto err_pci_runtime_suspend; ++ ++ if (chip->rpm_retune && ++ host->tuning_mode != SDHCI_TUNING_MODE_3) ++ mmc_retune_needed(host->mmc); ++ } ++ ++ return 0; ++ ++err_pci_runtime_suspend: ++ while (--i >= 0) ++ sdhci_runtime_resume_host(chip->slots[i]->host, 0); ++ return ret; ++} ++ ++static int sdhci_pci_runtime_resume_host(struct sdhci_pci_chip *chip) ++{ ++ struct sdhci_pci_slot *slot; ++ int i, ret; ++ ++ for (i = 0; i < chip->num_slots; i++) { ++ slot = chip->slots[i]; ++ if (!slot) ++ continue; ++ ++ ret = sdhci_runtime_resume_host(slot->host, 0); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int sdhci_cqhci_runtime_suspend(struct sdhci_pci_chip *chip) ++{ ++ int ret; ++ ++ ret = cqhci_suspend(chip->slots[0]->host->mmc); ++ if (ret) ++ return ret; ++ ++ return sdhci_pci_runtime_suspend_host(chip); ++} ++ ++static int sdhci_cqhci_runtime_resume(struct sdhci_pci_chip *chip) ++{ ++ int ret; ++ ++ ret = sdhci_pci_runtime_resume_host(chip); ++ if (ret) ++ return ret; ++ ++ return cqhci_resume(chip->slots[0]->host->mmc); ++} ++#endif ++ ++static u32 sdhci_cqhci_irq(struct sdhci_host *host, u32 intmask) ++{ ++ int cmd_error = 0; ++ int data_error = 0; ++ ++ if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) ++ return intmask; ++ ++ cqhci_irq(host->mmc, intmask, cmd_error, data_error); ++ ++ return 0; ++} ++ ++static void sdhci_pci_dumpregs(struct mmc_host *mmc) ++{ ++ sdhci_dumpregs(mmc_priv(mmc)); ++} ++ ++static void sdhci_cqhci_reset(struct sdhci_host *host, u8 mask) ++{ ++ if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) && ++ host->mmc->cqe_private) ++ cqhci_deactivate(host->mmc); ++ sdhci_reset(host, mask); ++} ++ ++/*****************************************************************************\ ++ * * ++ * Hardware specific quirk handling * ++ * * ++\*****************************************************************************/ ++ ++static int ricoh_probe(struct sdhci_pci_chip *chip) ++{ ++ if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG || ++ chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SONY) ++ chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET; ++ return 0; ++} ++ ++static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ slot->host->caps = ++ FIELD_PREP(SDHCI_TIMEOUT_CLK_MASK, 0x21) | ++ FIELD_PREP(SDHCI_CLOCK_BASE_MASK, 0x21) | ++ SDHCI_TIMEOUT_CLK_UNIT | ++ SDHCI_CAN_VDD_330 | ++ SDHCI_CAN_DO_HISPD | ++ SDHCI_CAN_DO_SDMA; ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int ricoh_mmc_resume(struct sdhci_pci_chip *chip) ++{ ++ /* Apply a delay to allow controller to settle */ ++ /* Otherwise it becomes confused if card state changed ++ during suspend */ ++ msleep(500); ++ return sdhci_pci_resume_host(chip); ++} ++#endif ++ ++static const struct sdhci_pci_fixes sdhci_ricoh = { ++ .probe = ricoh_probe, ++ .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | ++ SDHCI_QUIRK_FORCE_DMA | ++ SDHCI_QUIRK_CLOCK_BEFORE_RESET, ++}; ++ ++static const struct sdhci_pci_fixes sdhci_ricoh_mmc = { ++ .probe_slot = ricoh_mmc_probe_slot, ++#ifdef CONFIG_PM_SLEEP ++ .resume = ricoh_mmc_resume, ++#endif ++ .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | ++ SDHCI_QUIRK_CLOCK_BEFORE_RESET | ++ SDHCI_QUIRK_NO_CARD_NO_RESET | ++ SDHCI_QUIRK_MISSING_CAPS ++}; ++ ++static const struct sdhci_pci_fixes sdhci_ene_712 = { ++ .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE | ++ SDHCI_QUIRK_BROKEN_DMA, ++}; ++ ++static const struct sdhci_pci_fixes sdhci_ene_714 = { ++ .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE | ++ SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS | ++ SDHCI_QUIRK_BROKEN_DMA, ++}; ++ ++static const struct sdhci_pci_fixes sdhci_cafe = { ++ .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | ++ SDHCI_QUIRK_NO_BUSY_IRQ | ++ SDHCI_QUIRK_BROKEN_CARD_DETECTION | ++ SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, ++}; ++ ++static const struct sdhci_pci_fixes sdhci_intel_qrk = { ++ .quirks = SDHCI_QUIRK_NO_HISPD_BIT, ++}; ++ ++static int mrst_hc_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; ++ return 0; ++} ++ ++/* ++ * ADMA operation is disabled for Moorestown platform due to ++ * hardware bugs. ++ */ ++static int mrst_hc_probe(struct sdhci_pci_chip *chip) ++{ ++ /* ++ * slots number is fixed here for MRST as SDIO3/5 are never used and ++ * have hardware bugs. ++ */ ++ chip->num_slots = 1; ++ return 0; ++} ++ ++static int pch_hc_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++ ++static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id) ++{ ++ struct sdhci_pci_slot *slot = dev_id; ++ struct sdhci_host *host = slot->host; ++ ++ mmc_detect_change(host->mmc, msecs_to_jiffies(200)); ++ return IRQ_HANDLED; ++} ++ ++static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) ++{ ++ int err, irq, gpio = slot->cd_gpio; ++ ++ slot->cd_gpio = -EINVAL; ++ slot->cd_irq = -EINVAL; ++ ++ if (!gpio_is_valid(gpio)) ++ return; ++ ++ err = devm_gpio_request(&slot->chip->pdev->dev, gpio, "sd_cd"); ++ if (err < 0) ++ goto out; ++ ++ err = gpio_direction_input(gpio); ++ if (err < 0) ++ goto out_free; ++ ++ irq = gpio_to_irq(gpio); ++ if (irq < 0) ++ goto out_free; ++ ++ err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING | ++ IRQF_TRIGGER_FALLING, "sd_cd", slot); ++ if (err) ++ goto out_free; ++ ++ slot->cd_gpio = gpio; ++ slot->cd_irq = irq; ++ ++ return; ++ ++out_free: ++ devm_gpio_free(&slot->chip->pdev->dev, gpio); ++out: ++ dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n"); ++} ++ ++static void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) ++{ ++ if (slot->cd_irq >= 0) ++ free_irq(slot->cd_irq, slot); ++} ++ ++#else ++ ++static inline void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) ++{ ++} ++ ++static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) ++{ ++} ++ ++#endif ++ ++static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE; ++ slot->host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC; ++ return 0; ++} ++ ++static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE; ++ return 0; ++} ++ ++static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = { ++ .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, ++ .probe_slot = mrst_hc_probe_slot, ++}; ++ ++static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = { ++ .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, ++ .probe = mrst_hc_probe, ++}; ++ ++static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { ++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, ++ .allow_runtime_pm = true, ++ .own_cd_for_runtime_pm = true, ++}; ++ ++static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { ++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, ++ .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, ++ .allow_runtime_pm = true, ++ .probe_slot = mfd_sdio_probe_slot, ++}; ++ ++static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = { ++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, ++ .allow_runtime_pm = true, ++ .probe_slot = mfd_emmc_probe_slot, ++}; ++ ++static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = { ++ .quirks = SDHCI_QUIRK_BROKEN_ADMA, ++ .probe_slot = pch_hc_probe_slot, ++}; ++ ++#ifdef CONFIG_X86 ++ ++#define BYT_IOSF_SCCEP 0x63 ++#define BYT_IOSF_OCP_NETCTRL0 0x1078 ++#define BYT_IOSF_OCP_TIMEOUT_BASE GENMASK(10, 8) ++ ++static void byt_ocp_setting(struct pci_dev *pdev) ++{ ++ u32 val = 0; ++ ++ if (pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC && ++ pdev->device != PCI_DEVICE_ID_INTEL_BYT_SDIO && ++ pdev->device != PCI_DEVICE_ID_INTEL_BYT_SD && ++ pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC2) ++ return; ++ ++ if (iosf_mbi_read(BYT_IOSF_SCCEP, MBI_CR_READ, BYT_IOSF_OCP_NETCTRL0, ++ &val)) { ++ dev_err(&pdev->dev, "%s read error\n", __func__); ++ return; ++ } ++ ++ if (!(val & BYT_IOSF_OCP_TIMEOUT_BASE)) ++ return; ++ ++ val &= ~BYT_IOSF_OCP_TIMEOUT_BASE; ++ ++ if (iosf_mbi_write(BYT_IOSF_SCCEP, MBI_CR_WRITE, BYT_IOSF_OCP_NETCTRL0, ++ val)) { ++ dev_err(&pdev->dev, "%s write error\n", __func__); ++ return; ++ } ++ ++ dev_dbg(&pdev->dev, "%s completed\n", __func__); ++} ++ ++#else ++ ++static inline void byt_ocp_setting(struct pci_dev *pdev) ++{ ++} ++ ++#endif ++ ++enum { ++ INTEL_DSM_FNS = 0, ++ INTEL_DSM_V18_SWITCH = 3, ++ INTEL_DSM_V33_SWITCH = 4, ++ INTEL_DSM_DRV_STRENGTH = 9, ++ INTEL_DSM_D3_RETUNE = 10, ++}; ++ ++struct intel_host { ++ u32 dsm_fns; ++ int drv_strength; ++ bool d3_retune; ++ bool rpm_retune_ok; ++ bool needs_pwr_off; ++ u32 glk_rx_ctrl1; ++ u32 glk_tun_val; ++ u32 active_ltr; ++ u32 idle_ltr; ++}; ++ ++static const guid_t intel_dsm_guid = ++ GUID_INIT(0xF6C13EA5, 0x65CD, 0x461F, ++ 0xAB, 0x7A, 0x29, 0xF7, 0xE8, 0xD5, 0xBD, 0x61); ++ ++static int __intel_dsm(struct intel_host *intel_host, struct device *dev, ++ unsigned int fn, u32 *result) ++{ ++ union acpi_object *obj; ++ int err = 0; ++ size_t len; ++ ++ obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &intel_dsm_guid, 0, fn, NULL); ++ if (!obj) ++ return -EOPNOTSUPP; ++ ++ if (obj->type != ACPI_TYPE_BUFFER || obj->buffer.length < 1) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ len = min_t(size_t, obj->buffer.length, 4); ++ ++ *result = 0; ++ memcpy(result, obj->buffer.pointer, len); ++out: ++ ACPI_FREE(obj); ++ ++ return err; ++} ++ ++static int intel_dsm(struct intel_host *intel_host, struct device *dev, ++ unsigned int fn, u32 *result) ++{ ++ if (fn > 31 || !(intel_host->dsm_fns & (1 << fn))) ++ return -EOPNOTSUPP; ++ ++ return __intel_dsm(intel_host, dev, fn, result); ++} ++ ++static void intel_dsm_init(struct intel_host *intel_host, struct device *dev, ++ struct mmc_host *mmc) ++{ ++ int err; ++ u32 val; ++ ++ intel_host->d3_retune = true; ++ ++ err = __intel_dsm(intel_host, dev, INTEL_DSM_FNS, &intel_host->dsm_fns); ++ if (err) { ++ pr_debug("%s: DSM not supported, error %d\n", ++ mmc_hostname(mmc), err); ++ return; ++ } ++ ++ pr_debug("%s: DSM function mask %#x\n", ++ mmc_hostname(mmc), intel_host->dsm_fns); ++ ++ err = intel_dsm(intel_host, dev, INTEL_DSM_DRV_STRENGTH, &val); ++ intel_host->drv_strength = err ? 0 : val; ++ ++ err = intel_dsm(intel_host, dev, INTEL_DSM_D3_RETUNE, &val); ++ intel_host->d3_retune = err ? true : !!val; ++} ++ ++static void sdhci_pci_int_hw_reset(struct sdhci_host *host) ++{ ++ u8 reg; ++ ++ reg = sdhci_readb(host, SDHCI_POWER_CONTROL); ++ reg |= 0x10; ++ sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); ++ /* For eMMC, minimum is 1us but give it 9us for good measure */ ++ udelay(9); ++ reg &= ~0x10; ++ sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); ++ /* For eMMC, minimum is 200us but give it 300us for good measure */ ++ usleep_range(300, 1000); ++} ++ ++static int intel_select_drive_strength(struct mmc_card *card, ++ unsigned int max_dtr, int host_drv, ++ int card_drv, int *drv_type) ++{ ++ struct sdhci_host *host = mmc_priv(card->host); ++ struct sdhci_pci_slot *slot = sdhci_priv(host); ++ struct intel_host *intel_host = sdhci_pci_priv(slot); ++ ++ if (!(mmc_driver_type_mask(intel_host->drv_strength) & card_drv)) ++ return 0; ++ ++ return intel_host->drv_strength; ++} ++ ++static int bxt_get_cd(struct mmc_host *mmc) ++{ ++ int gpio_cd = mmc_gpio_get_cd(mmc); ++ struct sdhci_host *host = mmc_priv(mmc); ++ unsigned long flags; ++ int ret = 0; ++ ++ if (!gpio_cd) ++ return 0; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ if (host->flags & SDHCI_DEVICE_DEAD) ++ goto out; ++ ++ ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); ++out: ++ spin_unlock_irqrestore(&host->lock, flags); ++ ++ return ret; ++} ++ ++#define SDHCI_INTEL_PWR_TIMEOUT_CNT 20 ++#define SDHCI_INTEL_PWR_TIMEOUT_UDELAY 100 ++ ++static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode, ++ unsigned short vdd) ++{ ++ struct sdhci_pci_slot *slot = sdhci_priv(host); ++ struct intel_host *intel_host = sdhci_pci_priv(slot); ++ int cntr; ++ u8 reg; ++ ++ /* ++ * Bus power may control card power, but a full reset still may not ++ * reset the power, whereas a direct write to SDHCI_POWER_CONTROL can. ++ * That might be needed to initialize correctly, if the card was left ++ * powered on previously. ++ */ ++ if (intel_host->needs_pwr_off) { ++ intel_host->needs_pwr_off = false; ++ if (mode != MMC_POWER_OFF) { ++ sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); ++ usleep_range(10000, 12500); ++ } ++ } ++ ++ sdhci_set_power(host, mode, vdd); ++ ++ if (mode == MMC_POWER_OFF) ++ return; ++ ++ /* ++ * Bus power might not enable after D3 -> D0 transition due to the ++ * present state not yet having propagated. Retry for up to 2ms. ++ */ ++ for (cntr = 0; cntr < SDHCI_INTEL_PWR_TIMEOUT_CNT; cntr++) { ++ reg = sdhci_readb(host, SDHCI_POWER_CONTROL); ++ if (reg & SDHCI_POWER_ON) ++ break; ++ udelay(SDHCI_INTEL_PWR_TIMEOUT_UDELAY); ++ reg |= SDHCI_POWER_ON; ++ sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); ++ } ++} ++ ++static void sdhci_intel_set_uhs_signaling(struct sdhci_host *host, ++ unsigned int timing) ++{ ++ /* Set UHS timing to SDR25 for High Speed mode */ ++ if (timing == MMC_TIMING_MMC_HS || timing == MMC_TIMING_SD_HS) ++ timing = MMC_TIMING_UHS_SDR25; ++ sdhci_set_uhs_signaling(host, timing); ++} ++ ++#define INTEL_HS400_ES_REG 0x78 ++#define INTEL_HS400_ES_BIT BIT(0) ++ ++static void intel_hs400_enhanced_strobe(struct mmc_host *mmc, ++ struct mmc_ios *ios) ++{ ++ struct sdhci_host *host = mmc_priv(mmc); ++ u32 val; ++ ++ val = sdhci_readl(host, INTEL_HS400_ES_REG); ++ if (ios->enhanced_strobe) ++ val |= INTEL_HS400_ES_BIT; ++ else ++ val &= ~INTEL_HS400_ES_BIT; ++ sdhci_writel(host, val, INTEL_HS400_ES_REG); ++} ++ ++static int intel_start_signal_voltage_switch(struct mmc_host *mmc, ++ struct mmc_ios *ios) ++{ ++ struct device *dev = mmc_dev(mmc); ++ struct sdhci_host *host = mmc_priv(mmc); ++ struct sdhci_pci_slot *slot = sdhci_priv(host); ++ struct intel_host *intel_host = sdhci_pci_priv(slot); ++ unsigned int fn; ++ u32 result = 0; ++ int err; ++ ++ err = sdhci_start_signal_voltage_switch(mmc, ios); ++ if (err) ++ return err; ++ ++ switch (ios->signal_voltage) { ++ case MMC_SIGNAL_VOLTAGE_330: ++ fn = INTEL_DSM_V33_SWITCH; ++ break; ++ case MMC_SIGNAL_VOLTAGE_180: ++ fn = INTEL_DSM_V18_SWITCH; ++ break; ++ default: ++ return 0; ++ } ++ ++ err = intel_dsm(intel_host, dev, fn, &result); ++ pr_debug("%s: %s DSM fn %u error %d result %u\n", ++ mmc_hostname(mmc), __func__, fn, err, result); ++ ++ return 0; ++} ++ ++static const struct sdhci_ops sdhci_intel_byt_ops = { ++ .set_clock = sdhci_set_clock, ++ .set_power = sdhci_intel_set_power, ++ .enable_dma = sdhci_pci_enable_dma, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_intel_set_uhs_signaling, ++ .hw_reset = sdhci_pci_hw_reset, ++}; ++ ++static const struct sdhci_ops sdhci_intel_glk_ops = { ++ .set_clock = sdhci_set_clock, ++ .set_power = sdhci_intel_set_power, ++ .enable_dma = sdhci_pci_enable_dma, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_cqhci_reset, ++ .set_uhs_signaling = sdhci_intel_set_uhs_signaling, ++ .hw_reset = sdhci_pci_hw_reset, ++ .irq = sdhci_cqhci_irq, ++}; ++ ++static void byt_read_dsm(struct sdhci_pci_slot *slot) ++{ ++ struct intel_host *intel_host = sdhci_pci_priv(slot); ++ struct device *dev = &slot->chip->pdev->dev; ++ struct mmc_host *mmc = slot->host->mmc; ++ ++ intel_dsm_init(intel_host, dev, mmc); ++ slot->chip->rpm_retune = intel_host->d3_retune; ++} ++ ++static int intel_execute_tuning(struct mmc_host *mmc, u32 opcode) ++{ ++ int err = sdhci_execute_tuning(mmc, opcode); ++ struct sdhci_host *host = mmc_priv(mmc); ++ ++ if (err) ++ return err; ++ ++ /* ++ * Tuning can leave the IP in an active state (Buffer Read Enable bit ++ * set) which prevents the entry to low power states (i.e. S0i3). Data ++ * reset will clear it. ++ */ ++ sdhci_reset(host, SDHCI_RESET_DATA); ++ ++ return 0; ++} ++ ++#define INTEL_ACTIVELTR 0x804 ++#define INTEL_IDLELTR 0x808 ++ ++#define INTEL_LTR_REQ BIT(15) ++#define INTEL_LTR_SCALE_MASK GENMASK(11, 10) ++#define INTEL_LTR_SCALE_1US (2 << 10) ++#define INTEL_LTR_SCALE_32US (3 << 10) ++#define INTEL_LTR_VALUE_MASK GENMASK(9, 0) ++ ++static void intel_cache_ltr(struct sdhci_pci_slot *slot) ++{ ++ struct intel_host *intel_host = sdhci_pci_priv(slot); ++ struct sdhci_host *host = slot->host; ++ ++ intel_host->active_ltr = readl(host->ioaddr + INTEL_ACTIVELTR); ++ intel_host->idle_ltr = readl(host->ioaddr + INTEL_IDLELTR); ++} ++ ++static void intel_ltr_set(struct device *dev, s32 val) ++{ ++ struct sdhci_pci_chip *chip = dev_get_drvdata(dev); ++ struct sdhci_pci_slot *slot = chip->slots[0]; ++ struct intel_host *intel_host = sdhci_pci_priv(slot); ++ struct sdhci_host *host = slot->host; ++ u32 ltr; ++ ++ pm_runtime_get_sync(dev); ++ ++ /* ++ * Program latency tolerance (LTR) accordingly what has been asked ++ * by the PM QoS layer or disable it in case we were passed ++ * negative value or PM_QOS_LATENCY_ANY. ++ */ ++ ltr = readl(host->ioaddr + INTEL_ACTIVELTR); ++ ++ if (val == PM_QOS_LATENCY_ANY || val < 0) { ++ ltr &= ~INTEL_LTR_REQ; ++ } else { ++ ltr |= INTEL_LTR_REQ; ++ ltr &= ~INTEL_LTR_SCALE_MASK; ++ ltr &= ~INTEL_LTR_VALUE_MASK; ++ ++ if (val > INTEL_LTR_VALUE_MASK) { ++ val >>= 5; ++ if (val > INTEL_LTR_VALUE_MASK) ++ val = INTEL_LTR_VALUE_MASK; ++ ltr |= INTEL_LTR_SCALE_32US | val; ++ } else { ++ ltr |= INTEL_LTR_SCALE_1US | val; ++ } ++ } ++ ++ if (ltr == intel_host->active_ltr) ++ goto out; ++ ++ writel(ltr, host->ioaddr + INTEL_ACTIVELTR); ++ writel(ltr, host->ioaddr + INTEL_IDLELTR); ++ ++ /* Cache the values into lpss structure */ ++ intel_cache_ltr(slot); ++out: ++ pm_runtime_put_autosuspend(dev); ++} ++ ++static bool intel_use_ltr(struct sdhci_pci_chip *chip) ++{ ++ switch (chip->pdev->device) { ++ case PCI_DEVICE_ID_INTEL_BYT_EMMC: ++ case PCI_DEVICE_ID_INTEL_BYT_EMMC2: ++ case PCI_DEVICE_ID_INTEL_BYT_SDIO: ++ case PCI_DEVICE_ID_INTEL_BYT_SD: ++ case PCI_DEVICE_ID_INTEL_BSW_EMMC: ++ case PCI_DEVICE_ID_INTEL_BSW_SDIO: ++ case PCI_DEVICE_ID_INTEL_BSW_SD: ++ return false; ++ default: ++ return true; ++ } ++} ++ ++static void intel_ltr_expose(struct sdhci_pci_chip *chip) ++{ ++ struct device *dev = &chip->pdev->dev; ++ ++ if (!intel_use_ltr(chip)) ++ return; ++ ++ dev->power.set_latency_tolerance = intel_ltr_set; ++ dev_pm_qos_expose_latency_tolerance(dev); ++} ++ ++static void intel_ltr_hide(struct sdhci_pci_chip *chip) ++{ ++ struct device *dev = &chip->pdev->dev; ++ ++ if (!intel_use_ltr(chip)) ++ return; ++ ++ dev_pm_qos_hide_latency_tolerance(dev); ++ dev->power.set_latency_tolerance = NULL; ++} ++ ++static void byt_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ struct mmc_host_ops *ops = &slot->host->mmc_host_ops; ++ struct device *dev = &slot->chip->pdev->dev; ++ struct mmc_host *mmc = slot->host->mmc; ++ ++ byt_read_dsm(slot); ++ ++ byt_ocp_setting(slot->chip->pdev); ++ ++ ops->execute_tuning = intel_execute_tuning; ++ ops->start_signal_voltage_switch = intel_start_signal_voltage_switch; ++ ++ device_property_read_u32(dev, "max-frequency", &mmc->f_max); ++ ++ if (!mmc->slotno) { ++ slot->chip->slots[mmc->slotno] = slot; ++ intel_ltr_expose(slot->chip); ++ } ++} ++ ++static void byt_add_debugfs(struct sdhci_pci_slot *slot) ++{ ++ struct intel_host *intel_host = sdhci_pci_priv(slot); ++ struct mmc_host *mmc = slot->host->mmc; ++ struct dentry *dir = mmc->debugfs_root; ++ ++ if (!intel_use_ltr(slot->chip)) ++ return; ++ ++ debugfs_create_x32("active_ltr", 0444, dir, &intel_host->active_ltr); ++ debugfs_create_x32("idle_ltr", 0444, dir, &intel_host->idle_ltr); ++ ++ intel_cache_ltr(slot); ++} ++ ++static int byt_add_host(struct sdhci_pci_slot *slot) ++{ ++ int ret = sdhci_add_host(slot->host); ++ ++ if (!ret) ++ byt_add_debugfs(slot); ++ return ret; ++} ++ ++static void byt_remove_slot(struct sdhci_pci_slot *slot, int dead) ++{ ++ struct mmc_host *mmc = slot->host->mmc; ++ ++ if (!mmc->slotno) ++ intel_ltr_hide(slot->chip); ++} ++ ++static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ byt_probe_slot(slot); ++ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | ++ MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR | ++ MMC_CAP_CMD_DURING_TFR | ++ MMC_CAP_WAIT_WHILE_BUSY; ++ slot->hw_reset = sdhci_pci_int_hw_reset; ++ if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BSW_EMMC) ++ slot->host->timeout_clk = 1000; /* 1000 kHz i.e. 1 MHz */ ++ slot->host->mmc_host_ops.select_drive_strength = ++ intel_select_drive_strength; ++ return 0; ++} ++ ++static int dnv_emmc_hs_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ /* Remove 1.8V capability, if 1.8V is supported, it will be negotiated to DDR mode */ ++ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | ++ MMC_CAP_HW_RESET | ++ MMC_CAP_CMD_DURING_TFR | ++ MMC_CAP_WAIT_WHILE_BUSY; ++ slot->hw_reset = sdhci_pci_int_hw_reset; ++ return 0; ++} ++ ++static bool glk_broken_cqhci(struct sdhci_pci_slot *slot) ++{ ++ return slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC && ++ (dmi_match(DMI_BIOS_VENDOR, "LENOVO") || ++ dmi_match(DMI_SYS_VENDOR, "IRBIS")); ++} ++ ++static int glk_emmc_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ int ret = byt_emmc_probe_slot(slot); ++ ++ if (!glk_broken_cqhci(slot)) ++ slot->host->mmc->caps2 |= MMC_CAP2_CQE; ++ ++ if (slot->chip->pdev->device != PCI_DEVICE_ID_INTEL_GLK_EMMC) { ++ slot->host->mmc->caps2 |= MMC_CAP2_HS400_ES, ++ slot->host->mmc_host_ops.hs400_enhanced_strobe = ++ intel_hs400_enhanced_strobe; ++ slot->host->mmc->caps2 |= MMC_CAP2_CQE_DCMD; ++ } ++ ++ return ret; ++} ++ ++static const struct cqhci_host_ops glk_cqhci_ops = { ++ .enable = sdhci_cqe_enable, ++ .disable = sdhci_cqe_disable, ++ .dumpregs = sdhci_pci_dumpregs, ++}; ++ ++static int glk_emmc_add_host(struct sdhci_pci_slot *slot) ++{ ++ struct device *dev = &slot->chip->pdev->dev; ++ struct sdhci_host *host = slot->host; ++ struct cqhci_host *cq_host; ++ bool dma64; ++ int ret; ++ ++ ret = sdhci_setup_host(host); ++ if (ret) ++ return ret; ++ ++ cq_host = devm_kzalloc(dev, sizeof(*cq_host), GFP_KERNEL); ++ if (!cq_host) { ++ ret = -ENOMEM; ++ goto cleanup; ++ } ++ ++ cq_host->mmio = host->ioaddr + 0x200; ++ cq_host->quirks |= CQHCI_QUIRK_SHORT_TXFR_DESC_SZ; ++ cq_host->ops = &glk_cqhci_ops; ++ ++ dma64 = host->flags & SDHCI_USE_64_BIT_DMA; ++ if (dma64) ++ cq_host->caps |= CQHCI_TASK_DESC_SZ_128; ++ ++ ret = cqhci_init(cq_host, host->mmc, dma64); ++ if (ret) ++ goto cleanup; ++ ++ ret = __sdhci_add_host(host); ++ if (ret) ++ goto cleanup; ++ ++ byt_add_debugfs(slot); ++ ++ return 0; ++ ++cleanup: ++ sdhci_cleanup_host(host); ++ return ret; ++} ++ ++#ifdef CONFIG_PM ++#define GLK_RX_CTRL1 0x834 ++#define GLK_TUN_VAL 0x840 ++#define GLK_PATH_PLL GENMASK(13, 8) ++#define GLK_DLY GENMASK(6, 0) ++/* Workaround firmware failing to restore the tuning value */ ++static void glk_rpm_retune_wa(struct sdhci_pci_chip *chip, bool susp) ++{ ++ struct sdhci_pci_slot *slot = chip->slots[0]; ++ struct intel_host *intel_host = sdhci_pci_priv(slot); ++ struct sdhci_host *host = slot->host; ++ u32 glk_rx_ctrl1; ++ u32 glk_tun_val; ++ u32 dly; ++ ++ if (intel_host->rpm_retune_ok || !mmc_can_retune(host->mmc)) ++ return; ++ ++ glk_rx_ctrl1 = sdhci_readl(host, GLK_RX_CTRL1); ++ glk_tun_val = sdhci_readl(host, GLK_TUN_VAL); ++ ++ if (susp) { ++ intel_host->glk_rx_ctrl1 = glk_rx_ctrl1; ++ intel_host->glk_tun_val = glk_tun_val; ++ return; ++ } ++ ++ if (!intel_host->glk_tun_val) ++ return; ++ ++ if (glk_rx_ctrl1 != intel_host->glk_rx_ctrl1) { ++ intel_host->rpm_retune_ok = true; ++ return; ++ } ++ ++ dly = FIELD_PREP(GLK_DLY, FIELD_GET(GLK_PATH_PLL, glk_rx_ctrl1) + ++ (intel_host->glk_tun_val << 1)); ++ if (dly == FIELD_GET(GLK_DLY, glk_rx_ctrl1)) ++ return; ++ ++ glk_rx_ctrl1 = (glk_rx_ctrl1 & ~GLK_DLY) | dly; ++ sdhci_writel(host, glk_rx_ctrl1, GLK_RX_CTRL1); ++ ++ intel_host->rpm_retune_ok = true; ++ chip->rpm_retune = true; ++ mmc_retune_needed(host->mmc); ++ pr_info("%s: Requiring re-tune after rpm resume", mmc_hostname(host->mmc)); ++} ++ ++static void glk_rpm_retune_chk(struct sdhci_pci_chip *chip, bool susp) ++{ ++ if (chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC && ++ !chip->rpm_retune) ++ glk_rpm_retune_wa(chip, susp); ++} ++ ++static int glk_runtime_suspend(struct sdhci_pci_chip *chip) ++{ ++ glk_rpm_retune_chk(chip, true); ++ ++ return sdhci_cqhci_runtime_suspend(chip); ++} ++ ++static int glk_runtime_resume(struct sdhci_pci_chip *chip) ++{ ++ glk_rpm_retune_chk(chip, false); ++ ++ return sdhci_cqhci_runtime_resume(chip); ++} ++#endif ++ ++#ifdef CONFIG_ACPI ++static int ni_set_max_freq(struct sdhci_pci_slot *slot) ++{ ++ acpi_status status; ++ unsigned long long max_freq; ++ ++ status = acpi_evaluate_integer(ACPI_HANDLE(&slot->chip->pdev->dev), ++ "MXFQ", NULL, &max_freq); ++ if (ACPI_FAILURE(status)) { ++ dev_err(&slot->chip->pdev->dev, ++ "MXFQ not found in acpi table\n"); ++ return -EINVAL; ++ } ++ ++ slot->host->mmc->f_max = max_freq * 1000000; ++ ++ return 0; ++} ++#else ++static inline int ni_set_max_freq(struct sdhci_pci_slot *slot) ++{ ++ return 0; ++} ++#endif ++ ++static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ int err; ++ ++ byt_probe_slot(slot); ++ ++ err = ni_set_max_freq(slot); ++ if (err) ++ return err; ++ ++ slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE | ++ MMC_CAP_WAIT_WHILE_BUSY; ++ return 0; ++} ++ ++static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ byt_probe_slot(slot); ++ slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE | ++ MMC_CAP_WAIT_WHILE_BUSY; ++ return 0; ++} ++ ++static void byt_needs_pwr_off(struct sdhci_pci_slot *slot) ++{ ++ struct intel_host *intel_host = sdhci_pci_priv(slot); ++ u8 reg = sdhci_readb(slot->host, SDHCI_POWER_CONTROL); ++ ++ intel_host->needs_pwr_off = reg & SDHCI_POWER_ON; ++} ++ ++static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ byt_probe_slot(slot); ++ slot->host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | ++ MMC_CAP_AGGRESSIVE_PM | MMC_CAP_CD_WAKE; ++ slot->cd_idx = 0; ++ slot->cd_override_level = true; ++ if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXT_SD || ++ slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXTM_SD || ++ slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_APL_SD || ++ slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_SD) ++ slot->host->mmc_host_ops.get_cd = bxt_get_cd; ++ ++ if (slot->chip->pdev->subsystem_vendor == PCI_VENDOR_ID_NI && ++ slot->chip->pdev->subsystem_device == PCI_SUBDEVICE_ID_NI_78E3) ++ slot->host->mmc->caps2 |= MMC_CAP2_AVOID_3_3V; ++ ++ byt_needs_pwr_off(slot); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++ ++static int byt_resume(struct sdhci_pci_chip *chip) ++{ ++ byt_ocp_setting(chip->pdev); ++ ++ return sdhci_pci_resume_host(chip); ++} ++ ++#endif ++ ++#ifdef CONFIG_PM ++ ++static int byt_runtime_resume(struct sdhci_pci_chip *chip) ++{ ++ byt_ocp_setting(chip->pdev); ++ ++ return sdhci_pci_runtime_resume_host(chip); ++} ++ ++#endif ++ ++static struct sdhci_pci_fixes sdhci_intel_dnv_emmc = { ++#ifdef CONFIG_PM_SLEEP ++ .resume = byt_resume, ++#endif ++#ifdef CONFIG_PM ++ .runtime_resume = byt_runtime_resume, ++#endif ++ .allow_runtime_pm = true, ++ .probe_slot = byt_emmc_probe_slot, ++ .add_host = byt_add_host, ++ .remove_slot = byt_remove_slot, ++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | ++ SDHCI_QUIRK_NO_LED, ++ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | ++ SDHCI_QUIRK2_STOP_WITH_TC, ++ .ops = &sdhci_intel_byt_ops, ++ .priv_size = sizeof(struct intel_host), ++}; ++ ++static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = { ++#ifdef CONFIG_PM_SLEEP ++ .resume = byt_resume, ++#endif ++#ifdef CONFIG_PM ++ .runtime_resume = byt_runtime_resume, ++#endif ++ .allow_runtime_pm = true, ++ .probe_slot = byt_emmc_probe_slot, ++ .add_host = byt_add_host, ++ .remove_slot = byt_remove_slot, ++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | ++ SDHCI_QUIRK_NO_LED, ++ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | ++ SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 | ++ SDHCI_QUIRK2_STOP_WITH_TC, ++ .ops = &sdhci_intel_byt_ops, ++ .priv_size = sizeof(struct intel_host), ++}; ++ ++static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = { ++ .allow_runtime_pm = true, ++ .probe_slot = glk_emmc_probe_slot, ++ .add_host = glk_emmc_add_host, ++ .remove_slot = byt_remove_slot, ++#ifdef CONFIG_PM_SLEEP ++ .suspend = sdhci_cqhci_suspend, ++ .resume = sdhci_cqhci_resume, ++#endif ++#ifdef CONFIG_PM ++ .runtime_suspend = glk_runtime_suspend, ++ .runtime_resume = glk_runtime_resume, ++#endif ++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | ++ SDHCI_QUIRK_NO_LED, ++ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | ++ SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 | ++ SDHCI_QUIRK2_STOP_WITH_TC, ++ .ops = &sdhci_intel_glk_ops, ++ .priv_size = sizeof(struct intel_host), ++}; ++ ++static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = { ++#ifdef CONFIG_PM_SLEEP ++ .resume = byt_resume, ++#endif ++#ifdef CONFIG_PM ++ .runtime_resume = byt_runtime_resume, ++#endif ++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | ++ SDHCI_QUIRK_NO_LED, ++ .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON | ++ SDHCI_QUIRK2_PRESET_VALUE_BROKEN, ++ .allow_runtime_pm = true, ++ .probe_slot = ni_byt_sdio_probe_slot, ++ .add_host = byt_add_host, ++ .remove_slot = byt_remove_slot, ++ .ops = &sdhci_intel_byt_ops, ++ .priv_size = sizeof(struct intel_host), ++}; ++ ++static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { ++#ifdef CONFIG_PM_SLEEP ++ .resume = byt_resume, ++#endif ++#ifdef CONFIG_PM ++ .runtime_resume = byt_runtime_resume, ++#endif ++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | ++ SDHCI_QUIRK_NO_LED, ++ .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON | ++ SDHCI_QUIRK2_PRESET_VALUE_BROKEN, ++ .allow_runtime_pm = true, ++ .probe_slot = byt_sdio_probe_slot, ++ .add_host = byt_add_host, ++ .remove_slot = byt_remove_slot, ++ .ops = &sdhci_intel_byt_ops, ++ .priv_size = sizeof(struct intel_host), ++}; ++ ++static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { ++#ifdef CONFIG_PM_SLEEP ++ .resume = byt_resume, ++#endif ++#ifdef CONFIG_PM ++ .runtime_resume = byt_runtime_resume, ++#endif ++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | ++ SDHCI_QUIRK_NO_LED, ++ .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | ++ SDHCI_QUIRK2_PRESET_VALUE_BROKEN | ++ SDHCI_QUIRK2_STOP_WITH_TC, ++ .allow_runtime_pm = true, ++ .own_cd_for_runtime_pm = true, ++ .probe_slot = byt_sd_probe_slot, ++ .add_host = byt_add_host, ++ .remove_slot = byt_remove_slot, ++ .ops = &sdhci_intel_byt_ops, ++ .priv_size = sizeof(struct intel_host), ++}; ++ ++/* Define Host controllers for Intel Merrifield platform */ ++#define INTEL_MRFLD_EMMC_0 0 ++#define INTEL_MRFLD_EMMC_1 1 ++#define INTEL_MRFLD_SD 2 ++#define INTEL_MRFLD_SDIO 3 ++ ++#ifdef CONFIG_ACPI ++static void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot) ++{ ++ struct acpi_device *device, *child; ++ ++ device = ACPI_COMPANION(&slot->chip->pdev->dev); ++ if (!device) ++ return; ++ ++ acpi_device_fix_up_power(device); ++ list_for_each_entry(child, &device->children, node) ++ if (child->status.present && child->status.enabled) ++ acpi_device_fix_up_power(child); ++} ++#else ++static inline void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot) {} ++#endif ++ ++static int intel_mrfld_mmc_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ unsigned int func = PCI_FUNC(slot->chip->pdev->devfn); ++ ++ switch (func) { ++ case INTEL_MRFLD_EMMC_0: ++ case INTEL_MRFLD_EMMC_1: ++ slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | ++ MMC_CAP_8_BIT_DATA | ++ MMC_CAP_1_8V_DDR; ++ break; ++ case INTEL_MRFLD_SD: ++ slot->host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; ++ break; ++ case INTEL_MRFLD_SDIO: ++ /* Advertise 2.0v for compatibility with the SDIO card's OCR */ ++ slot->host->ocr_mask = MMC_VDD_20_21 | MMC_VDD_165_195; ++ slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | ++ MMC_CAP_POWER_OFF_CARD; ++ break; ++ default: ++ return -ENODEV; ++ } ++ ++ intel_mrfld_mmc_fix_up_power_slot(slot); ++ return 0; ++} ++ ++static const struct sdhci_pci_fixes sdhci_intel_mrfld_mmc = { ++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, ++ .quirks2 = SDHCI_QUIRK2_BROKEN_HS200 | ++ SDHCI_QUIRK2_PRESET_VALUE_BROKEN, ++ .allow_runtime_pm = true, ++ .probe_slot = intel_mrfld_mmc_probe_slot, ++}; ++ ++static int jmicron_pmos(struct sdhci_pci_chip *chip, int on) ++{ ++ u8 scratch; ++ int ret; ++ ++ ret = pci_read_config_byte(chip->pdev, 0xAE, &scratch); ++ if (ret) ++ return ret; ++ ++ /* ++ * Turn PMOS on [bit 0], set over current detection to 2.4 V ++ * [bit 1:2] and enable over current debouncing [bit 6]. ++ */ ++ if (on) ++ scratch |= 0x47; ++ else ++ scratch &= ~0x47; ++ ++ return pci_write_config_byte(chip->pdev, 0xAE, scratch); ++} ++ ++static int jmicron_probe(struct sdhci_pci_chip *chip) ++{ ++ int ret; ++ u16 mmcdev = 0; ++ ++ if (chip->pdev->revision == 0) { ++ chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR | ++ SDHCI_QUIRK_32BIT_DMA_SIZE | ++ SDHCI_QUIRK_32BIT_ADMA_SIZE | ++ SDHCI_QUIRK_RESET_AFTER_REQUEST | ++ SDHCI_QUIRK_BROKEN_SMALL_PIO; ++ } ++ ++ /* ++ * JMicron chips can have two interfaces to the same hardware ++ * in order to work around limitations in Microsoft's driver. ++ * We need to make sure we only bind to one of them. ++ * ++ * This code assumes two things: ++ * ++ * 1. The PCI code adds subfunctions in order. ++ * ++ * 2. The MMC interface has a lower subfunction number ++ * than the SD interface. ++ */ ++ if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_SD) ++ mmcdev = PCI_DEVICE_ID_JMICRON_JMB38X_MMC; ++ else if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD) ++ mmcdev = PCI_DEVICE_ID_JMICRON_JMB388_ESD; ++ ++ if (mmcdev) { ++ struct pci_dev *sd_dev; ++ ++ sd_dev = NULL; ++ while ((sd_dev = pci_get_device(PCI_VENDOR_ID_JMICRON, ++ mmcdev, sd_dev)) != NULL) { ++ if ((PCI_SLOT(chip->pdev->devfn) == ++ PCI_SLOT(sd_dev->devfn)) && ++ (chip->pdev->bus == sd_dev->bus)) ++ break; ++ } ++ ++ if (sd_dev) { ++ pci_dev_put(sd_dev); ++ dev_info(&chip->pdev->dev, "Refusing to bind to " ++ "secondary interface.\n"); ++ return -ENODEV; ++ } ++ } ++ ++ /* ++ * JMicron chips need a bit of a nudge to enable the power ++ * output pins. ++ */ ++ ret = jmicron_pmos(chip, 1); ++ if (ret) { ++ dev_err(&chip->pdev->dev, "Failure enabling card power\n"); ++ return ret; ++ } ++ ++ /* quirk for unsable RO-detection on JM388 chips */ ++ if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD || ++ chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) ++ chip->quirks |= SDHCI_QUIRK_UNSTABLE_RO_DETECT; ++ ++ return 0; ++} ++ ++static void jmicron_enable_mmc(struct sdhci_host *host, int on) ++{ ++ u8 scratch; ++ ++ scratch = readb(host->ioaddr + 0xC0); ++ ++ if (on) ++ scratch |= 0x01; ++ else ++ scratch &= ~0x01; ++ ++ writeb(scratch, host->ioaddr + 0xC0); ++} ++ ++static int jmicron_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ if (slot->chip->pdev->revision == 0) { ++ u16 version; ++ ++ version = readl(slot->host->ioaddr + SDHCI_HOST_VERSION); ++ version = (version & SDHCI_VENDOR_VER_MASK) >> ++ SDHCI_VENDOR_VER_SHIFT; ++ ++ /* ++ * Older versions of the chip have lots of nasty glitches ++ * in the ADMA engine. It's best just to avoid it ++ * completely. ++ */ ++ if (version < 0xAC) ++ slot->host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; ++ } ++ ++ /* JM388 MMC doesn't support 1.8V while SD supports it */ ++ if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) { ++ slot->host->ocr_avail_sd = MMC_VDD_32_33 | MMC_VDD_33_34 | ++ MMC_VDD_29_30 | MMC_VDD_30_31 | ++ MMC_VDD_165_195; /* allow 1.8V */ ++ slot->host->ocr_avail_mmc = MMC_VDD_32_33 | MMC_VDD_33_34 | ++ MMC_VDD_29_30 | MMC_VDD_30_31; /* no 1.8V for MMC */ ++ } ++ ++ /* ++ * The secondary interface requires a bit set to get the ++ * interrupts. ++ */ ++ if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || ++ slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) ++ jmicron_enable_mmc(slot->host, 1); ++ ++ slot->host->mmc->caps |= MMC_CAP_BUS_WIDTH_TEST; ++ ++ return 0; ++} ++ ++static void jmicron_remove_slot(struct sdhci_pci_slot *slot, int dead) ++{ ++ if (dead) ++ return; ++ ++ if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || ++ slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) ++ jmicron_enable_mmc(slot->host, 0); ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int jmicron_suspend(struct sdhci_pci_chip *chip) ++{ ++ int i, ret; ++ ++ ret = sdhci_pci_suspend_host(chip); ++ if (ret) ++ return ret; ++ ++ if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || ++ chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) { ++ for (i = 0; i < chip->num_slots; i++) ++ jmicron_enable_mmc(chip->slots[i]->host, 0); ++ } ++ ++ return 0; ++} ++ ++static int jmicron_resume(struct sdhci_pci_chip *chip) ++{ ++ int ret, i; ++ ++ if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || ++ chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) { ++ for (i = 0; i < chip->num_slots; i++) ++ jmicron_enable_mmc(chip->slots[i]->host, 1); ++ } ++ ++ ret = jmicron_pmos(chip, 1); ++ if (ret) { ++ dev_err(&chip->pdev->dev, "Failure enabling card power\n"); ++ return ret; ++ } ++ ++ return sdhci_pci_resume_host(chip); ++} ++#endif ++ ++static const struct sdhci_pci_fixes sdhci_jmicron = { ++ .probe = jmicron_probe, ++ ++ .probe_slot = jmicron_probe_slot, ++ .remove_slot = jmicron_remove_slot, ++ ++#ifdef CONFIG_PM_SLEEP ++ .suspend = jmicron_suspend, ++ .resume = jmicron_resume, ++#endif ++}; ++ ++/* SysKonnect CardBus2SDIO extra registers */ ++#define SYSKT_CTRL 0x200 ++#define SYSKT_RDFIFO_STAT 0x204 ++#define SYSKT_WRFIFO_STAT 0x208 ++#define SYSKT_POWER_DATA 0x20c ++#define SYSKT_POWER_330 0xef ++#define SYSKT_POWER_300 0xf8 ++#define SYSKT_POWER_184 0xcc ++#define SYSKT_POWER_CMD 0x20d ++#define SYSKT_POWER_START (1 << 7) ++#define SYSKT_POWER_STATUS 0x20e ++#define SYSKT_POWER_STATUS_OK (1 << 0) ++#define SYSKT_BOARD_REV 0x210 ++#define SYSKT_CHIP_REV 0x211 ++#define SYSKT_CONF_DATA 0x212 ++#define SYSKT_CONF_DATA_1V8 (1 << 2) ++#define SYSKT_CONF_DATA_2V5 (1 << 1) ++#define SYSKT_CONF_DATA_3V3 (1 << 0) ++ ++static int syskt_probe(struct sdhci_pci_chip *chip) ++{ ++ if ((chip->pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) { ++ chip->pdev->class &= ~0x0000FF; ++ chip->pdev->class |= PCI_SDHCI_IFDMA; ++ } ++ return 0; ++} ++ ++static int syskt_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ int tm, ps; ++ ++ u8 board_rev = readb(slot->host->ioaddr + SYSKT_BOARD_REV); ++ u8 chip_rev = readb(slot->host->ioaddr + SYSKT_CHIP_REV); ++ dev_info(&slot->chip->pdev->dev, "SysKonnect CardBus2SDIO, " ++ "board rev %d.%d, chip rev %d.%d\n", ++ board_rev >> 4, board_rev & 0xf, ++ chip_rev >> 4, chip_rev & 0xf); ++ if (chip_rev >= 0x20) ++ slot->host->quirks |= SDHCI_QUIRK_FORCE_DMA; ++ ++ writeb(SYSKT_POWER_330, slot->host->ioaddr + SYSKT_POWER_DATA); ++ writeb(SYSKT_POWER_START, slot->host->ioaddr + SYSKT_POWER_CMD); ++ udelay(50); ++ tm = 10; /* Wait max 1 ms */ ++ do { ++ ps = readw(slot->host->ioaddr + SYSKT_POWER_STATUS); ++ if (ps & SYSKT_POWER_STATUS_OK) ++ break; ++ udelay(100); ++ } while (--tm); ++ if (!tm) { ++ dev_err(&slot->chip->pdev->dev, ++ "power regulator never stabilized"); ++ writeb(0, slot->host->ioaddr + SYSKT_POWER_CMD); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static const struct sdhci_pci_fixes sdhci_syskt = { ++ .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER, ++ .probe = syskt_probe, ++ .probe_slot = syskt_probe_slot, ++}; ++ ++static int via_probe(struct sdhci_pci_chip *chip) ++{ ++ if (chip->pdev->revision == 0x10) ++ chip->quirks |= SDHCI_QUIRK_DELAY_AFTER_POWER; ++ ++ return 0; ++} ++ ++static const struct sdhci_pci_fixes sdhci_via = { ++ .probe = via_probe, ++}; ++ ++static int rtsx_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ slot->host->mmc->caps2 |= MMC_CAP2_HS200; ++ return 0; ++} ++ ++static const struct sdhci_pci_fixes sdhci_rtsx = { ++ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | ++ SDHCI_QUIRK2_BROKEN_64_BIT_DMA | ++ SDHCI_QUIRK2_BROKEN_DDR50, ++ .probe_slot = rtsx_probe_slot, ++}; ++ ++/*AMD chipset generation*/ ++enum amd_chipset_gen { ++ AMD_CHIPSET_BEFORE_ML, ++ AMD_CHIPSET_CZ, ++ AMD_CHIPSET_NL, ++ AMD_CHIPSET_UNKNOWN, ++}; ++ ++/* AMD registers */ ++#define AMD_SD_AUTO_PATTERN 0xB8 ++#define AMD_MSLEEP_DURATION 4 ++#define AMD_SD_MISC_CONTROL 0xD0 ++#define AMD_MAX_TUNE_VALUE 0x0B ++#define AMD_AUTO_TUNE_SEL 0x10800 ++#define AMD_FIFO_PTR 0x30 ++#define AMD_BIT_MASK 0x1F ++ ++static void amd_tuning_reset(struct sdhci_host *host) ++{ ++ unsigned int val; ++ ++ val = sdhci_readw(host, SDHCI_HOST_CONTROL2); ++ val |= SDHCI_CTRL_PRESET_VAL_ENABLE | SDHCI_CTRL_EXEC_TUNING; ++ sdhci_writew(host, val, SDHCI_HOST_CONTROL2); ++ ++ val = sdhci_readw(host, SDHCI_HOST_CONTROL2); ++ val &= ~SDHCI_CTRL_EXEC_TUNING; ++ sdhci_writew(host, val, SDHCI_HOST_CONTROL2); ++} ++ ++static void amd_config_tuning_phase(struct pci_dev *pdev, u8 phase) ++{ ++ unsigned int val; ++ ++ pci_read_config_dword(pdev, AMD_SD_AUTO_PATTERN, &val); ++ val &= ~AMD_BIT_MASK; ++ val |= (AMD_AUTO_TUNE_SEL | (phase << 1)); ++ pci_write_config_dword(pdev, AMD_SD_AUTO_PATTERN, val); ++} ++ ++static void amd_enable_manual_tuning(struct pci_dev *pdev) ++{ ++ unsigned int val; ++ ++ pci_read_config_dword(pdev, AMD_SD_MISC_CONTROL, &val); ++ val |= AMD_FIFO_PTR; ++ pci_write_config_dword(pdev, AMD_SD_MISC_CONTROL, val); ++} ++ ++static int amd_execute_tuning_hs200(struct sdhci_host *host, u32 opcode) ++{ ++ struct sdhci_pci_slot *slot = sdhci_priv(host); ++ struct pci_dev *pdev = slot->chip->pdev; ++ u8 valid_win = 0; ++ u8 valid_win_max = 0; ++ u8 valid_win_end = 0; ++ u8 ctrl, tune_around; ++ ++ amd_tuning_reset(host); ++ ++ for (tune_around = 0; tune_around < 12; tune_around++) { ++ amd_config_tuning_phase(pdev, tune_around); ++ ++ if (mmc_send_tuning(host->mmc, opcode, NULL)) { ++ valid_win = 0; ++ msleep(AMD_MSLEEP_DURATION); ++ ctrl = SDHCI_RESET_CMD | SDHCI_RESET_DATA; ++ sdhci_writeb(host, ctrl, SDHCI_SOFTWARE_RESET); ++ } else if (++valid_win > valid_win_max) { ++ valid_win_max = valid_win; ++ valid_win_end = tune_around; ++ } ++ } ++ ++ if (!valid_win_max) { ++ dev_err(&pdev->dev, "no tuning point found\n"); ++ return -EIO; ++ } ++ ++ amd_config_tuning_phase(pdev, valid_win_end - valid_win_max / 2); ++ ++ amd_enable_manual_tuning(pdev); ++ ++ host->mmc->retune_period = 0; ++ ++ return 0; ++} ++ ++static int amd_execute_tuning(struct mmc_host *mmc, u32 opcode) ++{ ++ struct sdhci_host *host = mmc_priv(mmc); ++ ++ /* AMD requires custom HS200 tuning */ ++ if (host->timing == MMC_TIMING_MMC_HS200) ++ return amd_execute_tuning_hs200(host, opcode); ++ ++ /* Otherwise perform standard SDHCI tuning */ ++ return sdhci_execute_tuning(mmc, opcode); ++} ++ ++static int amd_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ struct mmc_host_ops *ops = &slot->host->mmc_host_ops; ++ ++ ops->execute_tuning = amd_execute_tuning; ++ ++ return 0; ++} ++ ++static int amd_probe(struct sdhci_pci_chip *chip) ++{ ++ struct pci_dev *smbus_dev; ++ enum amd_chipset_gen gen; ++ ++ smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, ++ PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL); ++ if (smbus_dev) { ++ gen = AMD_CHIPSET_BEFORE_ML; ++ } else { ++ smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, ++ PCI_DEVICE_ID_AMD_KERNCZ_SMBUS, NULL); ++ if (smbus_dev) { ++ if (smbus_dev->revision < 0x51) ++ gen = AMD_CHIPSET_CZ; ++ else ++ gen = AMD_CHIPSET_NL; ++ } else { ++ gen = AMD_CHIPSET_UNKNOWN; ++ } ++ } ++ ++ if (smbus_dev) { ++ pci_dev_put(smbus_dev); ++ } ++ ++ if (gen == AMD_CHIPSET_BEFORE_ML || gen == AMD_CHIPSET_CZ) ++ chip->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD; ++ ++ return 0; ++} ++ ++static u32 sdhci_read_present_state(struct sdhci_host *host) ++{ ++ return sdhci_readl(host, SDHCI_PRESENT_STATE); ++} ++ ++static void amd_sdhci_reset(struct sdhci_host *host, u8 mask) ++{ ++ struct sdhci_pci_slot *slot = sdhci_priv(host); ++ struct pci_dev *pdev = slot->chip->pdev; ++ u32 present_state; ++ ++ /* ++ * SDHC 0x7906 requires a hard reset to clear all internal state. ++ * Otherwise it can get into a bad state where the DATA lines are always ++ * read as zeros. ++ */ ++ if (pdev->device == 0x7906 && (mask & SDHCI_RESET_ALL)) { ++ pci_clear_master(pdev); ++ ++ pci_save_state(pdev); ++ ++ pci_set_power_state(pdev, PCI_D3cold); ++ pr_debug("%s: power_state=%u\n", mmc_hostname(host->mmc), ++ pdev->current_state); ++ pci_set_power_state(pdev, PCI_D0); ++ ++ pci_restore_state(pdev); ++ ++ /* ++ * SDHCI_RESET_ALL says the card detect logic should not be ++ * reset, but since we need to reset the entire controller ++ * we should wait until the card detect logic has stabilized. ++ * ++ * This normally takes about 40ms. ++ */ ++ readx_poll_timeout( ++ sdhci_read_present_state, ++ host, ++ present_state, ++ present_state & SDHCI_CD_STABLE, ++ 10000, ++ 100000 ++ ); ++ } ++ ++ return sdhci_reset(host, mask); ++} ++ ++static const struct sdhci_ops amd_sdhci_pci_ops = { ++ .set_clock = sdhci_set_clock, ++ .enable_dma = sdhci_pci_enable_dma, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = amd_sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, ++}; ++ ++static const struct sdhci_pci_fixes sdhci_amd = { ++ .probe = amd_probe, ++ .ops = &amd_sdhci_pci_ops, ++ .probe_slot = amd_probe_slot, ++}; ++ ++static const struct pci_device_id pci_ids[] = { ++ SDHCI_PCI_DEVICE(RICOH, R5C822, ricoh), ++ SDHCI_PCI_DEVICE(RICOH, R5C843, ricoh_mmc), ++ SDHCI_PCI_DEVICE(RICOH, R5CE822, ricoh_mmc), ++ SDHCI_PCI_DEVICE(RICOH, R5CE823, ricoh_mmc), ++ SDHCI_PCI_DEVICE(ENE, CB712_SD, ene_712), ++ SDHCI_PCI_DEVICE(ENE, CB712_SD_2, ene_712), ++ SDHCI_PCI_DEVICE(ENE, CB714_SD, ene_714), ++ SDHCI_PCI_DEVICE(ENE, CB714_SD_2, ene_714), ++ SDHCI_PCI_DEVICE(MARVELL, 88ALP01_SD, cafe), ++ SDHCI_PCI_DEVICE(JMICRON, JMB38X_SD, jmicron), ++ SDHCI_PCI_DEVICE(JMICRON, JMB38X_MMC, jmicron), ++ SDHCI_PCI_DEVICE(JMICRON, JMB388_SD, jmicron), ++ SDHCI_PCI_DEVICE(JMICRON, JMB388_ESD, jmicron), ++ SDHCI_PCI_DEVICE(SYSKONNECT, 8000, syskt), ++ SDHCI_PCI_DEVICE(VIA, 95D0, via), ++ SDHCI_PCI_DEVICE(REALTEK, 5250, rtsx), ++ SDHCI_PCI_DEVICE(INTEL, QRK_SD, intel_qrk), ++ SDHCI_PCI_DEVICE(INTEL, MRST_SD0, intel_mrst_hc0), ++ SDHCI_PCI_DEVICE(INTEL, MRST_SD1, intel_mrst_hc1_hc2), ++ SDHCI_PCI_DEVICE(INTEL, MRST_SD2, intel_mrst_hc1_hc2), ++ SDHCI_PCI_DEVICE(INTEL, MFD_SD, intel_mfd_sd), ++ SDHCI_PCI_DEVICE(INTEL, MFD_SDIO1, intel_mfd_sdio), ++ SDHCI_PCI_DEVICE(INTEL, MFD_SDIO2, intel_mfd_sdio), ++ SDHCI_PCI_DEVICE(INTEL, MFD_EMMC0, intel_mfd_emmc), ++ SDHCI_PCI_DEVICE(INTEL, MFD_EMMC1, intel_mfd_emmc), ++ SDHCI_PCI_DEVICE(INTEL, PCH_SDIO0, intel_pch_sdio), ++ SDHCI_PCI_DEVICE(INTEL, PCH_SDIO1, intel_pch_sdio), ++ SDHCI_PCI_DEVICE(INTEL, BYT_EMMC, intel_byt_emmc), ++ SDHCI_PCI_SUBDEVICE(INTEL, BYT_SDIO, NI, 7884, ni_byt_sdio), ++ SDHCI_PCI_DEVICE(INTEL, BYT_SDIO, intel_byt_sdio), ++ SDHCI_PCI_DEVICE(INTEL, BYT_SD, intel_byt_sd), ++ SDHCI_PCI_DEVICE(INTEL, BYT_EMMC2, intel_byt_emmc), ++ SDHCI_PCI_DEVICE(INTEL, BSW_EMMC, intel_byt_emmc), ++ SDHCI_PCI_DEVICE(INTEL, BSW_SDIO, intel_byt_sdio), ++ SDHCI_PCI_DEVICE(INTEL, BSW_SD, intel_byt_sd), ++ SDHCI_PCI_DEVICE(INTEL, CLV_SDIO0, intel_mfd_sd), ++ SDHCI_PCI_DEVICE(INTEL, CLV_SDIO1, intel_mfd_sdio), ++ SDHCI_PCI_DEVICE(INTEL, CLV_SDIO2, intel_mfd_sdio), ++ SDHCI_PCI_DEVICE(INTEL, CLV_EMMC0, intel_mfd_emmc), ++ SDHCI_PCI_DEVICE(INTEL, CLV_EMMC1, intel_mfd_emmc), ++ SDHCI_PCI_DEVICE(INTEL, MRFLD_MMC, intel_mrfld_mmc), ++ SDHCI_PCI_DEVICE(INTEL, SPT_EMMC, intel_byt_emmc), ++ SDHCI_PCI_DEVICE(INTEL, SPT_SDIO, intel_byt_sdio), ++ SDHCI_PCI_DEVICE(INTEL, SPT_SD, intel_byt_sd), ++ SDHCI_PCI_DEVICE(INTEL, DNV_EMMC, intel_dnv_emmc), ++ SDHCI_PCI_DEVICE(INTEL, CDF_EMMC, intel_glk_emmc), ++ SDHCI_PCI_DEVICE(INTEL, BXT_EMMC, intel_byt_emmc), ++ SDHCI_PCI_DEVICE(INTEL, BXT_SDIO, intel_byt_sdio), ++ SDHCI_PCI_DEVICE(INTEL, BXT_SD, intel_byt_sd), ++ SDHCI_PCI_DEVICE(INTEL, BXTM_EMMC, intel_byt_emmc), ++ SDHCI_PCI_DEVICE(INTEL, BXTM_SDIO, intel_byt_sdio), ++ SDHCI_PCI_DEVICE(INTEL, BXTM_SD, intel_byt_sd), ++ SDHCI_PCI_DEVICE(INTEL, APL_EMMC, intel_byt_emmc), ++ SDHCI_PCI_DEVICE(INTEL, APL_SDIO, intel_byt_sdio), ++ SDHCI_PCI_DEVICE(INTEL, APL_SD, intel_byt_sd), ++ SDHCI_PCI_DEVICE(INTEL, GLK_EMMC, intel_glk_emmc), ++ SDHCI_PCI_DEVICE(INTEL, GLK_SDIO, intel_byt_sdio), ++ SDHCI_PCI_DEVICE(INTEL, GLK_SD, intel_byt_sd), ++ SDHCI_PCI_DEVICE(INTEL, CNP_EMMC, intel_glk_emmc), ++ SDHCI_PCI_DEVICE(INTEL, CNP_SD, intel_byt_sd), ++ SDHCI_PCI_DEVICE(INTEL, CNPH_SD, intel_byt_sd), ++ SDHCI_PCI_DEVICE(INTEL, ICP_EMMC, intel_glk_emmc), ++ SDHCI_PCI_DEVICE(INTEL, ICP_SD, intel_byt_sd), ++ SDHCI_PCI_DEVICE(INTEL, EHL_EMMC, intel_glk_emmc), ++ SDHCI_PCI_DEVICE(INTEL, EHL_SD, intel_byt_sd), ++ SDHCI_PCI_DEVICE(INTEL, CML_EMMC, intel_glk_emmc), ++ SDHCI_PCI_DEVICE(INTEL, CML_SD, intel_byt_sd), ++ SDHCI_PCI_DEVICE(INTEL, CMLH_SD, intel_byt_sd), ++ SDHCI_PCI_DEVICE(INTEL, JSL_EMMC, intel_glk_emmc), ++ SDHCI_PCI_DEVICE(INTEL, JSL_SD, intel_byt_sd), ++ SDHCI_PCI_DEVICE(INTEL, LKF_EMMC, intel_glk_emmc), ++ SDHCI_PCI_DEVICE(INTEL, LKF_SD, intel_byt_sd), ++ SDHCI_PCI_DEVICE(O2, 8120, o2), ++ SDHCI_PCI_DEVICE(O2, 8220, o2), ++ SDHCI_PCI_DEVICE(O2, 8221, o2), ++ SDHCI_PCI_DEVICE(O2, 8320, o2), ++ SDHCI_PCI_DEVICE(O2, 8321, o2), ++ SDHCI_PCI_DEVICE(O2, FUJIN2, o2), ++ SDHCI_PCI_DEVICE(O2, SDS0, o2), ++ SDHCI_PCI_DEVICE(O2, SDS1, o2), ++ SDHCI_PCI_DEVICE(O2, SEABIRD0, o2), ++ SDHCI_PCI_DEVICE(O2, SEABIRD1, o2), ++ SDHCI_PCI_DEVICE(ARASAN, PHY_EMMC, arasan), ++ SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps), ++ SDHCI_PCI_DEVICE(GLI, 9750, gl9750), ++ SDHCI_PCI_DEVICE(GLI, 9755, gl9755), ++ SDHCI_PCI_DEVICE(GLI, 9763E, gl9763e), ++ SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd), ++ /* Generic SD host controller */ ++ {PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)}, ++ { /* end: all zeroes */ }, ++}; ++ ++MODULE_DEVICE_TABLE(pci, pci_ids); ++ ++/*****************************************************************************\ ++ * * ++ * SDHCI core callbacks * ++ * * ++\*****************************************************************************/ ++ ++int sdhci_pci_enable_dma(struct sdhci_host *host) ++{ ++ struct sdhci_pci_slot *slot; ++ struct pci_dev *pdev; ++ ++ slot = sdhci_priv(host); ++ pdev = slot->chip->pdev; ++ ++ if (((pdev->class & 0xFFFF00) == (PCI_CLASS_SYSTEM_SDHCI << 8)) && ++ ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) && ++ (host->flags & SDHCI_USE_SDMA)) { ++ dev_warn(&pdev->dev, "Will use DMA mode even though HW " ++ "doesn't fully claim to support it.\n"); ++ } ++ ++ pci_set_master(pdev); ++ ++ return 0; ++} ++ ++static void sdhci_pci_gpio_hw_reset(struct sdhci_host *host) ++{ ++ struct sdhci_pci_slot *slot = sdhci_priv(host); ++ int rst_n_gpio = slot->rst_n_gpio; ++ ++ if (!gpio_is_valid(rst_n_gpio)) ++ return; ++ gpio_set_value_cansleep(rst_n_gpio, 0); ++ /* For eMMC, minimum is 1us but give it 10us for good measure */ ++ udelay(10); ++ gpio_set_value_cansleep(rst_n_gpio, 1); ++ /* For eMMC, minimum is 200us but give it 300us for good measure */ ++ usleep_range(300, 1000); ++} ++ ++static void sdhci_pci_hw_reset(struct sdhci_host *host) ++{ ++ struct sdhci_pci_slot *slot = sdhci_priv(host); ++ ++ if (slot->hw_reset) ++ slot->hw_reset(host); ++} ++ ++static const struct sdhci_ops sdhci_pci_ops = { ++ .set_clock = sdhci_set_clock, ++ .enable_dma = sdhci_pci_enable_dma, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, ++ .hw_reset = sdhci_pci_hw_reset, ++}; ++ ++/*****************************************************************************\ ++ * * ++ * Suspend/resume * ++ * * ++\*****************************************************************************/ ++ ++#ifdef CONFIG_PM_SLEEP ++static int sdhci_pci_suspend(struct device *dev) ++{ ++ struct sdhci_pci_chip *chip = dev_get_drvdata(dev); ++ ++ if (!chip) ++ return 0; ++ ++ if (chip->fixes && chip->fixes->suspend) ++ return chip->fixes->suspend(chip); ++ ++ return sdhci_pci_suspend_host(chip); ++} ++ ++static int sdhci_pci_resume(struct device *dev) ++{ ++ struct sdhci_pci_chip *chip = dev_get_drvdata(dev); ++ ++ if (!chip) ++ return 0; ++ ++ if (chip->fixes && chip->fixes->resume) ++ return chip->fixes->resume(chip); ++ ++ return sdhci_pci_resume_host(chip); ++} ++#endif ++ ++#ifdef CONFIG_PM ++static int sdhci_pci_runtime_suspend(struct device *dev) ++{ ++ struct sdhci_pci_chip *chip = dev_get_drvdata(dev); ++ ++ if (!chip) ++ return 0; ++ ++ if (chip->fixes && chip->fixes->runtime_suspend) ++ return chip->fixes->runtime_suspend(chip); ++ ++ return sdhci_pci_runtime_suspend_host(chip); ++} ++ ++static int sdhci_pci_runtime_resume(struct device *dev) ++{ ++ struct sdhci_pci_chip *chip = dev_get_drvdata(dev); ++ ++ if (!chip) ++ return 0; ++ ++ if (chip->fixes && chip->fixes->runtime_resume) ++ return chip->fixes->runtime_resume(chip); ++ ++ return sdhci_pci_runtime_resume_host(chip); ++} ++#endif ++ ++static const struct dev_pm_ops sdhci_pci_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(sdhci_pci_suspend, sdhci_pci_resume) ++ SET_RUNTIME_PM_OPS(sdhci_pci_runtime_suspend, ++ sdhci_pci_runtime_resume, NULL) ++}; ++ ++/*****************************************************************************\ ++ * * ++ * Device probing/removal * ++ * * ++\*****************************************************************************/ ++ ++static struct sdhci_pci_slot *sdhci_pci_probe_slot( ++ struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar, ++ int slotno) ++{ ++ struct sdhci_pci_slot *slot; ++ struct sdhci_host *host; ++ int ret, bar = first_bar + slotno; ++ size_t priv_size = chip->fixes ? chip->fixes->priv_size : 0; ++ ++ if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { ++ dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ if (pci_resource_len(pdev, bar) < 0x100) { ++ dev_err(&pdev->dev, "Invalid iomem size. You may " ++ "experience problems.\n"); ++ } ++ ++ if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) { ++ dev_err(&pdev->dev, "Vendor specific interface. Aborting.\n"); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) { ++ dev_err(&pdev->dev, "Unknown interface. Aborting.\n"); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ host = sdhci_alloc_host(&pdev->dev, sizeof(*slot) + priv_size); ++ if (IS_ERR(host)) { ++ dev_err(&pdev->dev, "cannot allocate host\n"); ++ return ERR_CAST(host); ++ } ++ ++ slot = sdhci_priv(host); ++ ++ slot->chip = chip; ++ slot->host = host; ++ slot->rst_n_gpio = -EINVAL; ++ slot->cd_gpio = -EINVAL; ++ slot->cd_idx = -1; ++ ++ /* Retrieve platform data if there is any */ ++ if (*sdhci_pci_get_data) ++ slot->data = sdhci_pci_get_data(pdev, slotno); ++ ++ if (slot->data) { ++ if (slot->data->setup) { ++ ret = slot->data->setup(slot->data); ++ if (ret) { ++ dev_err(&pdev->dev, "platform setup failed\n"); ++ goto free; ++ } ++ } ++ slot->rst_n_gpio = slot->data->rst_n_gpio; ++ slot->cd_gpio = slot->data->cd_gpio; ++ } ++ ++ host->hw_name = "PCI"; ++ host->ops = chip->fixes && chip->fixes->ops ? ++ chip->fixes->ops : ++ &sdhci_pci_ops; ++ host->quirks = chip->quirks; ++ host->quirks2 = chip->quirks2; ++ ++ host->irq = pdev->irq; ++ ++ ret = pcim_iomap_regions(pdev, BIT(bar), mmc_hostname(host->mmc)); ++ if (ret) { ++ dev_err(&pdev->dev, "cannot request region\n"); ++ goto cleanup; ++ } ++ ++ host->ioaddr = pcim_iomap_table(pdev)[bar]; ++ ++ if (chip->fixes && chip->fixes->probe_slot) { ++ ret = chip->fixes->probe_slot(slot); ++ if (ret) ++ goto cleanup; ++ } ++ ++ if (gpio_is_valid(slot->rst_n_gpio)) { ++ if (!devm_gpio_request(&pdev->dev, slot->rst_n_gpio, "eMMC_reset")) { ++ gpio_direction_output(slot->rst_n_gpio, 1); ++ slot->host->mmc->caps |= MMC_CAP_HW_RESET; ++ slot->hw_reset = sdhci_pci_gpio_hw_reset; ++ } else { ++ dev_warn(&pdev->dev, "failed to request rst_n_gpio\n"); ++ slot->rst_n_gpio = -EINVAL; ++ } ++ } ++ ++ host->mmc->pm_caps = MMC_PM_KEEP_POWER; ++ host->mmc->slotno = slotno; ++ host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP; ++ ++ if (device_can_wakeup(&pdev->dev)) ++ host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; ++ ++ if (host->mmc->caps & MMC_CAP_CD_WAKE) ++ device_init_wakeup(&pdev->dev, true); ++ ++ if (slot->cd_idx >= 0) { ++ ret = mmc_gpiod_request_cd(host->mmc, "cd", slot->cd_idx, ++ slot->cd_override_level, 0); ++ if (ret && ret != -EPROBE_DEFER) ++ ret = mmc_gpiod_request_cd(host->mmc, NULL, ++ slot->cd_idx, ++ slot->cd_override_level, ++ 0); ++ if (ret == -EPROBE_DEFER) ++ goto remove; ++ ++ if (ret) { ++ dev_warn(&pdev->dev, "failed to setup card detect gpio\n"); ++ slot->cd_idx = -1; ++ } ++ } ++ ++ if (chip->fixes && chip->fixes->add_host) ++ ret = chip->fixes->add_host(slot); ++ else ++ ret = sdhci_add_host(host); ++ if (ret) ++ goto remove; ++ ++ sdhci_pci_add_own_cd(slot); ++ ++ /* ++ * Check if the chip needs a separate GPIO for card detect to wake up ++ * from runtime suspend. If it is not there, don't allow runtime PM. ++ * Note sdhci_pci_add_own_cd() sets slot->cd_gpio to -EINVAL on failure. ++ */ ++ if (chip->fixes && chip->fixes->own_cd_for_runtime_pm && ++ !gpio_is_valid(slot->cd_gpio) && slot->cd_idx < 0) ++ chip->allow_runtime_pm = false; ++ ++ return slot; ++ ++remove: ++ if (chip->fixes && chip->fixes->remove_slot) ++ chip->fixes->remove_slot(slot, 0); ++ ++cleanup: ++ if (slot->data && slot->data->cleanup) ++ slot->data->cleanup(slot->data); ++ ++free: ++ sdhci_free_host(host); ++ ++ return ERR_PTR(ret); ++} ++ ++static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) ++{ ++ int dead; ++ u32 scratch; ++ ++ sdhci_pci_remove_own_cd(slot); ++ ++ dead = 0; ++ scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS); ++ if (scratch == (u32)-1) ++ dead = 1; ++ ++ sdhci_remove_host(slot->host, dead); ++ ++ if (slot->chip->fixes && slot->chip->fixes->remove_slot) ++ slot->chip->fixes->remove_slot(slot, dead); ++ ++ if (slot->data && slot->data->cleanup) ++ slot->data->cleanup(slot->data); ++ ++ sdhci_free_host(slot->host); ++} ++ ++static void sdhci_pci_runtime_pm_allow(struct device *dev) ++{ ++ pm_suspend_ignore_children(dev, 1); ++ pm_runtime_set_autosuspend_delay(dev, 50); ++ pm_runtime_use_autosuspend(dev); ++ pm_runtime_allow(dev); ++ /* Stay active until mmc core scans for a card */ ++ pm_runtime_put_noidle(dev); ++} ++ ++static void sdhci_pci_runtime_pm_forbid(struct device *dev) ++{ ++ pm_runtime_forbid(dev); ++ pm_runtime_get_noresume(dev); ++} ++ ++/* define by gohi, set in bios acpi dsdt table */ ++#define EMMC_DSDT_MODE_HS400 0 ++#define EMMC_DSDT_MODE_HS200 1 ++#define EMMC_DSDT_MODE_DDR52 2 ++#define EMMC_DSDT_MODE_SDR52 3 ++ ++static int sdhci_set_quirks2_by_dsdt(struct pci_dev *pdev) ++{ ++ struct acpi_device *acpi_dev; ++ struct fwnode_handle *pfwnod = pdev->dev.fwnode; ++ u64 mode; ++ int ret; ++ ++ /* Find acpi node through pci, ++ * the relationship between pci and acpi devices can be viewed through the /sys/bus file */ ++ acpi_dev = container_of(pfwnod, struct acpi_device, fwnode); ++ ++ /* DSDT need take node as: "Name (MODE, 0x0-)" */ ++ ret = acpi_evaluate_integer(acpi_dev->handle, "MODE", NULL, &mode); ++ if (ACPI_SUCCESS(ret)) { ++ dev_info(&pdev->dev, "SD controller get bus mode:0x%lld from dsts success.\n", mode); ++ switch(mode) { ++ case EMMC_DSDT_MODE_SDR52: ++ sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_BROKEN_DDR50 | SDHCI_QUIRK2_BROKEN_HS200; ++ sdhci_intel_dnv_emmc.probe_slot = dnv_emmc_hs_probe_slot; ++ dev_info(&pdev->dev, "Configure SDHCI as SDR52 attribute through dsdt.\n"); ++ break; ++ case EMMC_DSDT_MODE_DDR52: ++ sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; ++ dev_info(&pdev->dev, "Configure SDHCI as DDR52 attribute through dsdt.\n"); ++ break; ++ case EMMC_DSDT_MODE_HS200: ++ dev_info(&pdev->dev, "Configure SDHCI as HS200 attribute through dsdt.\n"); ++ break; ++ case EMMC_DSDT_MODE_HS400: ++ sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400; ++ dev_info(&pdev->dev, "Configure SDHCI as HS400 attribute through dsdt.\n"); ++ break; ++ default: ++ ret = EINVAL; ++ break; ++ } ++ } else { ++ ret = EINVAL; ++ } ++ ++ return ret; ++} ++ ++#ifndef COMMAND_LINE_SIZE ++#define COMMAND_LINE_SIZE 1024 ++#endif ++ ++int sdhci_cmdline_read(char *cmdline) ++{ ++ struct file *filp; ++ int ret = 0; ++ loff_t pos; ++ ++ /* Basically, the kernel parameters with arch are not exported. ++ * In order to not have too much influence and generalization, ++ * use the proc file to obtain parameter information. */ ++ filp = filp_open("/proc/cmdline", O_RDONLY, 0); ++ if (IS_ERR(filp)) { ++ filp = NULL; ++ goto exit; ++ } ++ pos = 0; ++ ret = kernel_read(filp, cmdline, COMMAND_LINE_SIZE, &pos); ++ if (ret < 0) { ++ goto exit; ++ } ++ filp_close(filp, NULL); ++ ++ return 0; ++ ++exit: ++ if (filp != NULL) { ++ filp_close(filp, NULL); ++ } ++ return -1; ++} ++ ++static int sdhci_set_quirks2_by_cmdline(struct pci_dev *pdev) ++{ ++ char *option, cmdline[COMMAND_LINE_SIZE]; ++ int ret = 0; ++ ++ mem_clear(cmdline, COMMAND_LINE_SIZE); ++ ++ ret = sdhci_cmdline_read(cmdline); ++ if (ret) { ++ return ret; ++ } ++ ++ option = strstr(cmdline, "sdhcimode="); ++ if (option == NULL) { ++ return EINVAL; ++ } ++ ++ /* Count, sdhcimode= is it 10 bytes? */ ++ option += 10; ++ ++ if (!strncmp(option, "sdr52", 5)) { ++ sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_BROKEN_DDR50 | SDHCI_QUIRK2_BROKEN_HS200; ++ /* Remove 1.8V ability */ ++ sdhci_intel_dnv_emmc.probe_slot = dnv_emmc_hs_probe_slot; ++ dev_info(&pdev->dev, "Configure SDHCI as SDR52 attribute through cmdline.\n"); ++ } else if (!strncmp(option, "ddr52", 5)) { ++ sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; ++ dev_info(&pdev->dev, "Configure SDHCI as DDR52 attribute through cmdline.\n"); ++ } else if (!strncmp(option, "hs200", 5)) { ++ dev_info(&pdev->dev, "Configure SDHCI as HS200 attribute through cmdline.\n"); ++ ; ++ } else if (!strncmp(option, "hs400", 5)) { ++ sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400; ++ dev_info(&pdev->dev, "Configure SDHCI as HS400 attribute through cmdline.\n"); ++ } else { ++ dev_info(&pdev->dev, "CSDHCI: Unknown cmdline option.\n"); ++ return EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int sdhci_pci_probe(struct pci_dev *pdev, ++ const struct pci_device_id *ent) ++{ ++ struct sdhci_pci_chip *chip; ++ struct sdhci_pci_slot *slot; ++ ++ u8 slots, first_bar; ++ int ret, i; ++ ++ BUG_ON(pdev == NULL); ++ BUG_ON(ent == NULL); ++ ++ dev_info(&pdev->dev, "SDHCI controller found [%04x:%04x] (rev %x)\n", ++ (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); ++ ++ /* cmdline setting priority, the kernel parameters can be changed flexibly, ++ * and Bios upgrades are not convenient or secure. */ ++ ret = sdhci_set_quirks2_by_cmdline(pdev); ++ if (ret) { ++ ret = sdhci_set_quirks2_by_dsdt(pdev); ++ if (ret) { ++ sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400; ++ dev_info(&pdev->dev, "Configure SDHCI as default[HS400].\n"); ++ } ++ } ++ ++ ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots); ++ if (ret) ++ return ret; ++ ++ slots = PCI_SLOT_INFO_SLOTS(slots) + 1; ++ dev_dbg(&pdev->dev, "found %d slot(s)\n", slots); ++ ++ BUG_ON(slots > MAX_SLOTS); ++ ++ ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar); ++ if (ret) ++ return ret; ++ ++ first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK; ++ ++ if (first_bar > 5) { ++ dev_err(&pdev->dev, "Invalid first BAR. Aborting.\n"); ++ return -ENODEV; ++ } ++ ++ ret = pcim_enable_device(pdev); ++ if (ret) ++ return ret; ++ ++ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); ++ if (!chip) ++ return -ENOMEM; ++ ++ chip->pdev = pdev; ++ chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data; ++ if (chip->fixes) { ++ chip->quirks = chip->fixes->quirks; ++ chip->quirks2 = chip->fixes->quirks2; ++ chip->allow_runtime_pm = chip->fixes->allow_runtime_pm; ++ } ++ chip->num_slots = slots; ++ chip->pm_retune = true; ++ chip->rpm_retune = true; ++ ++ pci_set_drvdata(pdev, chip); ++ ++ if (chip->fixes && chip->fixes->probe) { ++ ret = chip->fixes->probe(chip); ++ if (ret) ++ return ret; ++ } ++ ++ slots = chip->num_slots; /* Quirk may have changed this */ ++ ++ for (i = 0; i < slots; i++) { ++ slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i); ++ if (IS_ERR(slot)) { ++ for (i--; i >= 0; i--) ++ sdhci_pci_remove_slot(chip->slots[i]); ++ return PTR_ERR(slot); ++ } ++ ++ chip->slots[i] = slot; ++ } ++ ++ if (chip->allow_runtime_pm) ++ sdhci_pci_runtime_pm_allow(&pdev->dev); ++ ++ return 0; ++} ++ ++static void sdhci_pci_remove(struct pci_dev *pdev) ++{ ++ int i; ++ struct sdhci_pci_chip *chip = pci_get_drvdata(pdev); ++ ++ if (chip->allow_runtime_pm) ++ sdhci_pci_runtime_pm_forbid(&pdev->dev); ++ ++ for (i = 0; i < chip->num_slots; i++) ++ sdhci_pci_remove_slot(chip->slots[i]); ++} ++ ++static struct pci_driver sdhci_driver = { ++ .name = "sdhci-pci", ++ .id_table = pci_ids, ++ .probe = sdhci_pci_probe, ++ .remove = sdhci_pci_remove, ++ .driver = { ++ .pm = &sdhci_pci_pm_ops ++ }, ++}; ++ ++module_pci_driver(sdhci_driver); ++ ++MODULE_AUTHOR("Pierre Ossman "); ++MODULE_DESCRIPTION("Secure Digital Host Controller Interface PCI driver"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-dwc-mshc.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-dwc-mshc.c +new file mode 100644 +index 000000000..f78d65448 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-dwc-mshc.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * SDHCI driver for Synopsys DWC_MSHC controller ++ * ++ * Copyright (C) 2018 Synopsys, Inc. (www.synopsys.com) ++ * ++ * Authors: ++ * Prabu Thangamuthu ++ * Manjunath M B ++ */ ++ ++#include "sdhci.h" ++#include "sdhci-pci.h" ++ ++#define SDHCI_VENDOR_PTR_R 0xE8 ++ ++/* Synopsys vendor specific registers */ ++#define SDHC_GPIO_OUT 0x34 ++#define SDHC_AT_CTRL_R 0x40 ++#define SDHC_SW_TUNE_EN 0x00000010 ++ ++/* MMCM DRP */ ++#define SDHC_MMCM_DIV_REG 0x1020 ++#define DIV_REG_100_MHZ 0x1145 ++#define DIV_REG_200_MHZ 0x1083 ++#define SDHC_MMCM_CLKFBOUT 0x1024 ++#define CLKFBOUT_100_MHZ 0x0000 ++#define CLKFBOUT_200_MHZ 0x0080 ++#define SDHC_CCLK_MMCM_RST 0x00000001 ++ ++static void sdhci_snps_set_clock(struct sdhci_host *host, unsigned int clock) ++{ ++ u16 clk; ++ u32 reg, vendor_ptr; ++ ++ vendor_ptr = sdhci_readw(host, SDHCI_VENDOR_PTR_R); ++ ++ /* Disable software managed rx tuning */ ++ reg = sdhci_readl(host, (SDHC_AT_CTRL_R + vendor_ptr)); ++ reg &= ~SDHC_SW_TUNE_EN; ++ sdhci_writel(host, reg, (SDHC_AT_CTRL_R + vendor_ptr)); ++ ++ if (clock <= 52000000) { ++ sdhci_set_clock(host, clock); ++ } else { ++ /* Assert reset to MMCM */ ++ reg = sdhci_readl(host, (SDHC_GPIO_OUT + vendor_ptr)); ++ reg |= SDHC_CCLK_MMCM_RST; ++ sdhci_writel(host, reg, (SDHC_GPIO_OUT + vendor_ptr)); ++ ++ /* Configure MMCM */ ++ if (clock == 100000000) { ++ sdhci_writel(host, DIV_REG_100_MHZ, SDHC_MMCM_DIV_REG); ++ sdhci_writel(host, CLKFBOUT_100_MHZ, ++ SDHC_MMCM_CLKFBOUT); ++ } else { ++ sdhci_writel(host, DIV_REG_200_MHZ, SDHC_MMCM_DIV_REG); ++ sdhci_writel(host, CLKFBOUT_200_MHZ, ++ SDHC_MMCM_CLKFBOUT); ++ } ++ ++ /* De-assert reset to MMCM */ ++ reg = sdhci_readl(host, (SDHC_GPIO_OUT + vendor_ptr)); ++ reg &= ~SDHC_CCLK_MMCM_RST; ++ sdhci_writel(host, reg, (SDHC_GPIO_OUT + vendor_ptr)); ++ ++ /* Enable clock */ ++ clk = SDHCI_PROG_CLOCK_MODE | SDHCI_CLOCK_INT_EN | ++ SDHCI_CLOCK_CARD_EN; ++ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); ++ } ++} ++ ++static const struct sdhci_ops sdhci_snps_ops = { ++ .set_clock = sdhci_snps_set_clock, ++ .enable_dma = sdhci_pci_enable_dma, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, ++}; ++ ++const struct sdhci_pci_fixes sdhci_snps = { ++ .ops = &sdhci_snps_ops, ++}; +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-gli.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-gli.c +new file mode 100644 +index 000000000..23b89b4ca +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-gli.c +@@ -0,0 +1,865 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2019 Genesys Logic, Inc. ++ * ++ * Authors: Ben Chuang ++ * ++ * Version: v0.9.0 (2019-08-08) ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "sdhci.h" ++#include "sdhci-pci.h" ++#include "cqhci.h" ++ ++/* Genesys Logic extra registers */ ++#define SDHCI_GLI_9750_WT 0x800 ++#define SDHCI_GLI_9750_WT_EN BIT(0) ++#define GLI_9750_WT_EN_ON 0x1 ++#define GLI_9750_WT_EN_OFF 0x0 ++ ++#define SDHCI_GLI_9750_DRIVING 0x860 ++#define SDHCI_GLI_9750_DRIVING_1 GENMASK(11, 0) ++#define SDHCI_GLI_9750_DRIVING_2 GENMASK(27, 26) ++#define GLI_9750_DRIVING_1_VALUE 0xFFF ++#define GLI_9750_DRIVING_2_VALUE 0x3 ++#define SDHCI_GLI_9750_SEL_1 BIT(29) ++#define SDHCI_GLI_9750_SEL_2 BIT(31) ++#define SDHCI_GLI_9750_ALL_RST (BIT(24)|BIT(25)|BIT(28)|BIT(30)) ++ ++#define SDHCI_GLI_9750_PLL 0x864 ++#define SDHCI_GLI_9750_PLL_LDIV GENMASK(9, 0) ++#define SDHCI_GLI_9750_PLL_PDIV GENMASK(14, 12) ++#define SDHCI_GLI_9750_PLL_DIR BIT(15) ++#define SDHCI_GLI_9750_PLL_TX2_INV BIT(23) ++#define SDHCI_GLI_9750_PLL_TX2_DLY GENMASK(22, 20) ++#define GLI_9750_PLL_TX2_INV_VALUE 0x1 ++#define GLI_9750_PLL_TX2_DLY_VALUE 0x0 ++#define SDHCI_GLI_9750_PLLSSC_STEP GENMASK(28, 24) ++#define SDHCI_GLI_9750_PLLSSC_EN BIT(31) ++ ++#define SDHCI_GLI_9750_PLLSSC 0x86C ++#define SDHCI_GLI_9750_PLLSSC_PPM GENMASK(31, 16) ++ ++#define SDHCI_GLI_9750_SW_CTRL 0x874 ++#define SDHCI_GLI_9750_SW_CTRL_4 GENMASK(7, 6) ++#define GLI_9750_SW_CTRL_4_VALUE 0x3 ++ ++#define SDHCI_GLI_9750_MISC 0x878 ++#define SDHCI_GLI_9750_MISC_TX1_INV BIT(2) ++#define SDHCI_GLI_9750_MISC_RX_INV BIT(3) ++#define SDHCI_GLI_9750_MISC_TX1_DLY GENMASK(6, 4) ++#define GLI_9750_MISC_TX1_INV_VALUE 0x0 ++#define GLI_9750_MISC_RX_INV_ON 0x1 ++#define GLI_9750_MISC_RX_INV_OFF 0x0 ++#define GLI_9750_MISC_RX_INV_VALUE GLI_9750_MISC_RX_INV_OFF ++#define GLI_9750_MISC_TX1_DLY_VALUE 0x5 ++ ++#define SDHCI_GLI_9750_TUNING_CONTROL 0x540 ++#define SDHCI_GLI_9750_TUNING_CONTROL_EN BIT(4) ++#define GLI_9750_TUNING_CONTROL_EN_ON 0x1 ++#define GLI_9750_TUNING_CONTROL_EN_OFF 0x0 ++#define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1 BIT(16) ++#define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2 GENMASK(20, 19) ++#define GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE 0x1 ++#define GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE 0x2 ++ ++#define SDHCI_GLI_9750_TUNING_PARAMETERS 0x544 ++#define SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY GENMASK(2, 0) ++#define GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE 0x1 ++ ++#define SDHCI_GLI_9763E_CTRL_HS400 0x7 ++ ++#define SDHCI_GLI_9763E_HS400_ES_REG 0x52C ++#define SDHCI_GLI_9763E_HS400_ES_BIT BIT(8) ++ ++#define PCIE_GLI_9763E_VHS 0x884 ++#define GLI_9763E_VHS_REV GENMASK(19, 16) ++#define GLI_9763E_VHS_REV_R 0x0 ++#define GLI_9763E_VHS_REV_M 0x1 ++#define GLI_9763E_VHS_REV_W 0x2 ++#define PCIE_GLI_9763E_MB 0x888 ++#define GLI_9763E_MB_CMDQ_OFF BIT(19) ++#define PCIE_GLI_9763E_SCR 0x8E0 ++#define GLI_9763E_SCR_AXI_REQ BIT(9) ++ ++#define SDHCI_GLI_9763E_CQE_BASE_ADDR 0x200 ++#define GLI_9763E_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \ ++ SDHCI_TRNS_BLK_CNT_EN | \ ++ SDHCI_TRNS_DMA) ++ ++#define PCI_GLI_9755_WT 0x800 ++#define PCI_GLI_9755_WT_EN BIT(0) ++#define GLI_9755_WT_EN_ON 0x1 ++#define GLI_9755_WT_EN_OFF 0x0 ++ ++#define PCI_GLI_9755_PLL 0x64 ++#define PCI_GLI_9755_PLL_LDIV GENMASK(9, 0) ++#define PCI_GLI_9755_PLL_PDIV GENMASK(14, 12) ++#define PCI_GLI_9755_PLL_DIR BIT(15) ++#define PCI_GLI_9755_PLLSSC_STEP GENMASK(28, 24) ++#define PCI_GLI_9755_PLLSSC_EN BIT(31) ++ ++#define PCI_GLI_9755_PLLSSC 0x68 ++#define PCI_GLI_9755_PLLSSC_PPM GENMASK(15, 0) ++ ++#define GLI_MAX_TUNING_LOOP 40 ++ ++/* Genesys Logic chipset */ ++static inline void gl9750_wt_on(struct sdhci_host *host) ++{ ++ u32 wt_value; ++ u32 wt_enable; ++ ++ wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT); ++ wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value); ++ ++ if (wt_enable == GLI_9750_WT_EN_ON) ++ return; ++ ++ wt_value &= ~SDHCI_GLI_9750_WT_EN; ++ wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_ON); ++ ++ sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT); ++} ++ ++static inline void gl9750_wt_off(struct sdhci_host *host) ++{ ++ u32 wt_value; ++ u32 wt_enable; ++ ++ wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT); ++ wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value); ++ ++ if (wt_enable == GLI_9750_WT_EN_OFF) ++ return; ++ ++ wt_value &= ~SDHCI_GLI_9750_WT_EN; ++ wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_OFF); ++ ++ sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT); ++} ++ ++static void gli_set_9750(struct sdhci_host *host) ++{ ++ u32 driving_value; ++ u32 pll_value; ++ u32 sw_ctrl_value; ++ u32 misc_value; ++ u32 parameter_value; ++ u32 control_value; ++ u16 ctrl2; ++ ++ gl9750_wt_on(host); ++ ++ driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING); ++ pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL); ++ sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL); ++ misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC); ++ parameter_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_PARAMETERS); ++ control_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_CONTROL); ++ ++ driving_value &= ~(SDHCI_GLI_9750_DRIVING_1); ++ driving_value &= ~(SDHCI_GLI_9750_DRIVING_2); ++ driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_1, ++ GLI_9750_DRIVING_1_VALUE); ++ driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_2, ++ GLI_9750_DRIVING_2_VALUE); ++ driving_value &= ~(SDHCI_GLI_9750_SEL_1|SDHCI_GLI_9750_SEL_2|SDHCI_GLI_9750_ALL_RST); ++ driving_value |= SDHCI_GLI_9750_SEL_2; ++ sdhci_writel(host, driving_value, SDHCI_GLI_9750_DRIVING); ++ ++ sw_ctrl_value &= ~SDHCI_GLI_9750_SW_CTRL_4; ++ sw_ctrl_value |= FIELD_PREP(SDHCI_GLI_9750_SW_CTRL_4, ++ GLI_9750_SW_CTRL_4_VALUE); ++ sdhci_writel(host, sw_ctrl_value, SDHCI_GLI_9750_SW_CTRL); ++ ++ /* reset the tuning flow after reinit and before starting tuning */ ++ pll_value &= ~SDHCI_GLI_9750_PLL_TX2_INV; ++ pll_value &= ~SDHCI_GLI_9750_PLL_TX2_DLY; ++ pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_INV, ++ GLI_9750_PLL_TX2_INV_VALUE); ++ pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_DLY, ++ GLI_9750_PLL_TX2_DLY_VALUE); ++ ++ misc_value &= ~SDHCI_GLI_9750_MISC_TX1_INV; ++ misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV; ++ misc_value &= ~SDHCI_GLI_9750_MISC_TX1_DLY; ++ misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_INV, ++ GLI_9750_MISC_TX1_INV_VALUE); ++ misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, ++ GLI_9750_MISC_RX_INV_VALUE); ++ misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_DLY, ++ GLI_9750_MISC_TX1_DLY_VALUE); ++ ++ parameter_value &= ~SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY; ++ parameter_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY, ++ GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE); ++ ++ control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1; ++ control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2; ++ control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1, ++ GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE); ++ control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2, ++ GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE); ++ ++ sdhci_writel(host, pll_value, SDHCI_GLI_9750_PLL); ++ sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC); ++ ++ /* disable tuned clk */ ++ ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); ++ ctrl2 &= ~SDHCI_CTRL_TUNED_CLK; ++ sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); ++ ++ /* enable tuning parameters control */ ++ control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN; ++ control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN, ++ GLI_9750_TUNING_CONTROL_EN_ON); ++ sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL); ++ ++ /* write tuning parameters */ ++ sdhci_writel(host, parameter_value, SDHCI_GLI_9750_TUNING_PARAMETERS); ++ ++ /* disable tuning parameters control */ ++ control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN; ++ control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN, ++ GLI_9750_TUNING_CONTROL_EN_OFF); ++ sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL); ++ ++ /* clear tuned clk */ ++ ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); ++ ctrl2 &= ~SDHCI_CTRL_TUNED_CLK; ++ sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); ++ ++ gl9750_wt_off(host); ++} ++ ++static void gli_set_9750_rx_inv(struct sdhci_host *host, bool b) ++{ ++ u32 misc_value; ++ ++ gl9750_wt_on(host); ++ ++ misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC); ++ misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV; ++ if (b) { ++ misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, ++ GLI_9750_MISC_RX_INV_ON); ++ } else { ++ misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, ++ GLI_9750_MISC_RX_INV_OFF); ++ } ++ sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC); ++ ++ gl9750_wt_off(host); ++} ++ ++static int __sdhci_execute_tuning_9750(struct sdhci_host *host, u32 opcode) ++{ ++ int i; ++ int rx_inv; ++ ++ for (rx_inv = 0; rx_inv < 2; rx_inv++) { ++ gli_set_9750_rx_inv(host, !!rx_inv); ++ sdhci_start_tuning(host); ++ ++ for (i = 0; i < GLI_MAX_TUNING_LOOP; i++) { ++ u16 ctrl; ++ ++ sdhci_send_tuning(host, opcode); ++ ++ if (!host->tuning_done) { ++ sdhci_abort_tuning(host, opcode); ++ break; ++ } ++ ++ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); ++ if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { ++ if (ctrl & SDHCI_CTRL_TUNED_CLK) ++ return 0; /* Success! */ ++ break; ++ } ++ } ++ } ++ if (!host->tuning_done) { ++ pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n", ++ mmc_hostname(host->mmc)); ++ return -ETIMEDOUT; ++ } ++ ++ pr_info("%s: Tuning failed, falling back to fixed sampling clock\n", ++ mmc_hostname(host->mmc)); ++ sdhci_reset_tuning(host); ++ ++ return -EAGAIN; ++} ++ ++static int gl9750_execute_tuning(struct sdhci_host *host, u32 opcode) ++{ ++ host->mmc->retune_period = 0; ++ if (host->tuning_mode == SDHCI_TUNING_MODE_1) ++ host->mmc->retune_period = host->tuning_count; ++ ++ gli_set_9750(host); ++ host->tuning_err = __sdhci_execute_tuning_9750(host, opcode); ++ sdhci_end_tuning(host); ++ ++ return 0; ++} ++ ++static void gl9750_disable_ssc_pll(struct sdhci_host *host) ++{ ++ u32 pll; ++ ++ gl9750_wt_on(host); ++ pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); ++ pll &= ~(SDHCI_GLI_9750_PLL_DIR | SDHCI_GLI_9750_PLLSSC_EN); ++ sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); ++ gl9750_wt_off(host); ++} ++ ++static void gl9750_set_pll(struct sdhci_host *host, u8 dir, u16 ldiv, u8 pdiv) ++{ ++ u32 pll; ++ ++ gl9750_wt_on(host); ++ pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); ++ pll &= ~(SDHCI_GLI_9750_PLL_LDIV | ++ SDHCI_GLI_9750_PLL_PDIV | ++ SDHCI_GLI_9750_PLL_DIR); ++ pll |= FIELD_PREP(SDHCI_GLI_9750_PLL_LDIV, ldiv) | ++ FIELD_PREP(SDHCI_GLI_9750_PLL_PDIV, pdiv) | ++ FIELD_PREP(SDHCI_GLI_9750_PLL_DIR, dir); ++ sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); ++ gl9750_wt_off(host); ++ ++ /* wait for pll stable */ ++ mdelay(1); ++} ++ ++static void gl9750_set_ssc(struct sdhci_host *host, u8 enable, u8 step, u16 ppm) ++{ ++ u32 pll; ++ u32 ssc; ++ ++ gl9750_wt_on(host); ++ pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); ++ ssc = sdhci_readl(host, SDHCI_GLI_9750_PLLSSC); ++ pll &= ~(SDHCI_GLI_9750_PLLSSC_STEP | ++ SDHCI_GLI_9750_PLLSSC_EN); ++ ssc &= ~SDHCI_GLI_9750_PLLSSC_PPM; ++ pll |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_STEP, step) | ++ FIELD_PREP(SDHCI_GLI_9750_PLLSSC_EN, enable); ++ ssc |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_PPM, ppm); ++ sdhci_writel(host, ssc, SDHCI_GLI_9750_PLLSSC); ++ sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); ++ gl9750_wt_off(host); ++} ++ ++static void gl9750_set_ssc_pll_205mhz(struct sdhci_host *host) ++{ ++ /* set pll to 205MHz and enable ssc */ ++ gl9750_set_ssc(host, 0x1, 0x1F, 0xFFE7); ++ gl9750_set_pll(host, 0x1, 0x246, 0x0); ++} ++ ++static void sdhci_gl9750_set_clock(struct sdhci_host *host, unsigned int clock) ++{ ++ struct mmc_ios *ios = &host->mmc->ios; ++ u16 clk; ++ ++ host->mmc->actual_clock = 0; ++ ++ gl9750_disable_ssc_pll(host); ++ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); ++ ++ if (clock == 0) ++ return; ++ ++ clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); ++ if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) { ++ host->mmc->actual_clock = 205000000; ++ gl9750_set_ssc_pll_205mhz(host); ++ } ++ ++ sdhci_enable_clk(host, clk); ++} ++ ++static void gli_pcie_enable_msi(struct sdhci_pci_slot *slot) ++{ ++ int ret; ++ ++ ret = pci_alloc_irq_vectors(slot->chip->pdev, 1, 1, ++ PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ if (ret < 0) { ++ pr_warn("%s: enable PCI MSI failed, error=%d\n", ++ mmc_hostname(slot->host->mmc), ret); ++ return; ++ } ++ ++ slot->host->irq = pci_irq_vector(slot->chip->pdev, 0); ++} ++ ++static inline void gl9755_wt_on(struct pci_dev *pdev) ++{ ++ u32 wt_value; ++ u32 wt_enable; ++ ++ pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value); ++ wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value); ++ ++ if (wt_enable == GLI_9755_WT_EN_ON) ++ return; ++ ++ wt_value &= ~PCI_GLI_9755_WT_EN; ++ wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_ON); ++ ++ pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value); ++} ++ ++static inline void gl9755_wt_off(struct pci_dev *pdev) ++{ ++ u32 wt_value; ++ u32 wt_enable; ++ ++ pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value); ++ wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value); ++ ++ if (wt_enable == GLI_9755_WT_EN_OFF) ++ return; ++ ++ wt_value &= ~PCI_GLI_9755_WT_EN; ++ wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_OFF); ++ ++ pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value); ++} ++ ++static void gl9755_disable_ssc_pll(struct pci_dev *pdev) ++{ ++ u32 pll; ++ ++ gl9755_wt_on(pdev); ++ pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); ++ pll &= ~(PCI_GLI_9755_PLL_DIR | PCI_GLI_9755_PLLSSC_EN); ++ pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); ++ gl9755_wt_off(pdev); ++} ++ ++static void gl9755_set_pll(struct pci_dev *pdev, u8 dir, u16 ldiv, u8 pdiv) ++{ ++ u32 pll; ++ ++ gl9755_wt_on(pdev); ++ pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); ++ pll &= ~(PCI_GLI_9755_PLL_LDIV | ++ PCI_GLI_9755_PLL_PDIV | ++ PCI_GLI_9755_PLL_DIR); ++ pll |= FIELD_PREP(PCI_GLI_9755_PLL_LDIV, ldiv) | ++ FIELD_PREP(PCI_GLI_9755_PLL_PDIV, pdiv) | ++ FIELD_PREP(PCI_GLI_9755_PLL_DIR, dir); ++ pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); ++ gl9755_wt_off(pdev); ++ ++ /* wait for pll stable */ ++ mdelay(1); ++} ++ ++static void gl9755_set_ssc(struct pci_dev *pdev, u8 enable, u8 step, u16 ppm) ++{ ++ u32 pll; ++ u32 ssc; ++ ++ gl9755_wt_on(pdev); ++ pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); ++ pci_read_config_dword(pdev, PCI_GLI_9755_PLLSSC, &ssc); ++ pll &= ~(PCI_GLI_9755_PLLSSC_STEP | ++ PCI_GLI_9755_PLLSSC_EN); ++ ssc &= ~PCI_GLI_9755_PLLSSC_PPM; ++ pll |= FIELD_PREP(PCI_GLI_9755_PLLSSC_STEP, step) | ++ FIELD_PREP(PCI_GLI_9755_PLLSSC_EN, enable); ++ ssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_PPM, ppm); ++ pci_write_config_dword(pdev, PCI_GLI_9755_PLLSSC, ssc); ++ pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); ++ gl9755_wt_off(pdev); ++} ++ ++static void gl9755_set_ssc_pll_205mhz(struct pci_dev *pdev) ++{ ++ /* set pll to 205MHz and enable ssc */ ++ gl9755_set_ssc(pdev, 0x1, 0x1F, 0xFFE7); ++ gl9755_set_pll(pdev, 0x1, 0x246, 0x0); ++} ++ ++static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock) ++{ ++ struct sdhci_pci_slot *slot = sdhci_priv(host); ++ struct mmc_ios *ios = &host->mmc->ios; ++ struct pci_dev *pdev; ++ u16 clk; ++ ++ pdev = slot->chip->pdev; ++ host->mmc->actual_clock = 0; ++ ++ gl9755_disable_ssc_pll(pdev); ++ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); ++ ++ if (clock == 0) ++ return; ++ ++ clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); ++ if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) { ++ host->mmc->actual_clock = 205000000; ++ gl9755_set_ssc_pll_205mhz(pdev); ++ } ++ ++ sdhci_enable_clk(host, clk); ++} ++ ++static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot) ++{ ++ struct sdhci_host *host = slot->host; ++ ++ gli_pcie_enable_msi(slot); ++ slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO; ++ sdhci_enable_v4_mode(host); ++ ++ return 0; ++} ++ ++static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot) ++{ ++ struct sdhci_host *host = slot->host; ++ ++ gli_pcie_enable_msi(slot); ++ slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO; ++ sdhci_enable_v4_mode(host); ++ ++ return 0; ++} ++ ++static void sdhci_gli_voltage_switch(struct sdhci_host *host) ++{ ++ /* ++ * According to Section 3.6.1 signal voltage switch procedure in ++ * SD Host Controller Simplified Spec. 4.20, steps 6~8 are as ++ * follows: ++ * (6) Set 1.8V Signal Enable in the Host Control 2 register. ++ * (7) Wait 5ms. 1.8V voltage regulator shall be stable within this ++ * period. ++ * (8) If 1.8V Signal Enable is cleared by Host Controller, go to ++ * step (12). ++ * ++ * Wait 5ms after set 1.8V signal enable in Host Control 2 register ++ * to ensure 1.8V signal enable bit is set by GL9750/GL9755. ++ * ++ * ...however, the controller in the NUC10i3FNK4 (a 9755) requires ++ * slightly longer than 5ms before the control register reports that ++ * 1.8V is ready, and far longer still before the card will actually ++ * work reliably. ++ */ ++ usleep_range(100000, 110000); ++} ++ ++static void sdhci_gl9750_reset(struct sdhci_host *host, u8 mask) ++{ ++ sdhci_reset(host, mask); ++ gli_set_9750(host); ++} ++ ++static u32 sdhci_gl9750_readl(struct sdhci_host *host, int reg) ++{ ++ u32 value; ++ ++ value = readl(host->ioaddr + reg); ++ if (unlikely(reg == SDHCI_MAX_CURRENT && !(value & 0xff))) ++ value |= 0xc8; ++ ++ return value; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip) ++{ ++ struct sdhci_pci_slot *slot = chip->slots[0]; ++ ++ pci_free_irq_vectors(slot->chip->pdev); ++ gli_pcie_enable_msi(slot); ++ ++ return sdhci_pci_resume_host(chip); ++} ++ ++static int sdhci_cqhci_gli_resume(struct sdhci_pci_chip *chip) ++{ ++ struct sdhci_pci_slot *slot = chip->slots[0]; ++ int ret; ++ ++ ret = sdhci_pci_gli_resume(chip); ++ if (ret) ++ return ret; ++ ++ return cqhci_resume(slot->host->mmc); ++} ++ ++static int sdhci_cqhci_gli_suspend(struct sdhci_pci_chip *chip) ++{ ++ struct sdhci_pci_slot *slot = chip->slots[0]; ++ int ret; ++ ++ ret = cqhci_suspend(slot->host->mmc); ++ if (ret) ++ return ret; ++ ++ return sdhci_suspend_host(slot->host); ++} ++#endif ++ ++static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc, ++ struct mmc_ios *ios) ++{ ++ struct sdhci_host *host = mmc_priv(mmc); ++ u32 val; ++ ++ val = sdhci_readl(host, SDHCI_GLI_9763E_HS400_ES_REG); ++ if (ios->enhanced_strobe) ++ val |= SDHCI_GLI_9763E_HS400_ES_BIT; ++ else ++ val &= ~SDHCI_GLI_9763E_HS400_ES_BIT; ++ ++ sdhci_writel(host, val, SDHCI_GLI_9763E_HS400_ES_REG); ++} ++ ++static void sdhci_set_gl9763e_signaling(struct sdhci_host *host, ++ unsigned int timing) ++{ ++ u16 ctrl_2; ++ ++ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); ++ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; ++ if (timing == MMC_TIMING_MMC_HS200) ++ ctrl_2 |= SDHCI_CTRL_UHS_SDR104; ++ else if (timing == MMC_TIMING_MMC_HS) ++ ctrl_2 |= SDHCI_CTRL_UHS_SDR25; ++ else if (timing == MMC_TIMING_MMC_DDR52) ++ ctrl_2 |= SDHCI_CTRL_UHS_DDR50; ++ else if (timing == MMC_TIMING_MMC_HS400) ++ ctrl_2 |= SDHCI_GLI_9763E_CTRL_HS400; ++ ++ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); ++} ++ ++static void sdhci_gl9763e_dumpregs(struct mmc_host *mmc) ++{ ++ sdhci_dumpregs(mmc_priv(mmc)); ++} ++ ++static void sdhci_gl9763e_cqe_pre_enable(struct mmc_host *mmc) ++{ ++ struct cqhci_host *cq_host = mmc->cqe_private; ++ u32 value; ++ ++ value = cqhci_readl(cq_host, CQHCI_CFG); ++ value |= CQHCI_ENABLE; ++ cqhci_writel(cq_host, value, CQHCI_CFG); ++} ++ ++static void sdhci_gl9763e_cqe_enable(struct mmc_host *mmc) ++{ ++ struct sdhci_host *host = mmc_priv(mmc); ++ ++ sdhci_writew(host, GLI_9763E_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE); ++ sdhci_cqe_enable(mmc); ++} ++ ++static u32 sdhci_gl9763e_cqhci_irq(struct sdhci_host *host, u32 intmask) ++{ ++ int cmd_error = 0; ++ int data_error = 0; ++ ++ if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) ++ return intmask; ++ ++ cqhci_irq(host->mmc, intmask, cmd_error, data_error); ++ ++ return 0; ++} ++ ++static void sdhci_gl9763e_cqe_post_disable(struct mmc_host *mmc) ++{ ++ struct sdhci_host *host = mmc_priv(mmc); ++ struct cqhci_host *cq_host = mmc->cqe_private; ++ u32 value; ++ ++ value = cqhci_readl(cq_host, CQHCI_CFG); ++ value &= ~CQHCI_ENABLE; ++ cqhci_writel(cq_host, value, CQHCI_CFG); ++ sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE); ++} ++ ++static const struct cqhci_host_ops sdhci_gl9763e_cqhci_ops = { ++ .enable = sdhci_gl9763e_cqe_enable, ++ .disable = sdhci_cqe_disable, ++ .dumpregs = sdhci_gl9763e_dumpregs, ++ .pre_enable = sdhci_gl9763e_cqe_pre_enable, ++ .post_disable = sdhci_gl9763e_cqe_post_disable, ++}; ++ ++static int gl9763e_add_host(struct sdhci_pci_slot *slot) ++{ ++ struct device *dev = &slot->chip->pdev->dev; ++ struct sdhci_host *host = slot->host; ++ struct cqhci_host *cq_host; ++ bool dma64; ++ int ret; ++ ++ ret = sdhci_setup_host(host); ++ if (ret) ++ return ret; ++ ++ cq_host = devm_kzalloc(dev, sizeof(*cq_host), GFP_KERNEL); ++ if (!cq_host) { ++ ret = -ENOMEM; ++ goto cleanup; ++ } ++ ++ cq_host->mmio = host->ioaddr + SDHCI_GLI_9763E_CQE_BASE_ADDR; ++ cq_host->ops = &sdhci_gl9763e_cqhci_ops; ++ ++ dma64 = host->flags & SDHCI_USE_64_BIT_DMA; ++ if (dma64) ++ cq_host->caps |= CQHCI_TASK_DESC_SZ_128; ++ ++ ret = cqhci_init(cq_host, host->mmc, dma64); ++ if (ret) ++ goto cleanup; ++ ++ ret = __sdhci_add_host(host); ++ if (ret) ++ goto cleanup; ++ ++ return 0; ++ ++cleanup: ++ sdhci_cleanup_host(host); ++ return ret; ++} ++ ++static void sdhci_gl9763e_reset(struct sdhci_host *host, u8 mask) ++{ ++ if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) && ++ host->mmc->cqe_private) ++ cqhci_deactivate(host->mmc); ++ sdhci_reset(host, mask); ++} ++ ++static void gli_set_gl9763e(struct sdhci_pci_slot *slot) ++{ ++ struct pci_dev *pdev = slot->chip->pdev; ++ u32 value; ++ ++ pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); ++ value &= ~GLI_9763E_VHS_REV; ++ value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_W); ++ pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); ++ ++ pci_read_config_dword(pdev, PCIE_GLI_9763E_SCR, &value); ++ value |= GLI_9763E_SCR_AXI_REQ; ++ pci_write_config_dword(pdev, PCIE_GLI_9763E_SCR, value); ++ ++ pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); ++ value &= ~GLI_9763E_VHS_REV; ++ value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R); ++ pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); ++} ++ ++static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot) ++{ ++ struct pci_dev *pdev = slot->chip->pdev; ++ struct sdhci_host *host = slot->host; ++ u32 value; ++ ++ host->mmc->caps |= MMC_CAP_8_BIT_DATA | ++ MMC_CAP_1_8V_DDR | ++ MMC_CAP_NONREMOVABLE; ++ host->mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR | ++ MMC_CAP2_HS400_1_8V | ++ MMC_CAP2_HS400_ES | ++ MMC_CAP2_NO_SDIO | ++ MMC_CAP2_NO_SD; ++ ++ pci_read_config_dword(pdev, PCIE_GLI_9763E_MB, &value); ++ if (!(value & GLI_9763E_MB_CMDQ_OFF)) ++ host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; ++ ++ gli_pcie_enable_msi(slot); ++ host->mmc_host_ops.hs400_enhanced_strobe = ++ gl9763e_hs400_enhanced_strobe; ++ gli_set_gl9763e(slot); ++ sdhci_enable_v4_mode(host); ++ ++ return 0; ++} ++ ++static const struct sdhci_ops sdhci_gl9755_ops = { ++ .set_clock = sdhci_gl9755_set_clock, ++ .enable_dma = sdhci_pci_enable_dma, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, ++ .voltage_switch = sdhci_gli_voltage_switch, ++}; ++ ++const struct sdhci_pci_fixes sdhci_gl9755 = { ++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, ++ .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, ++ .probe_slot = gli_probe_slot_gl9755, ++ .ops = &sdhci_gl9755_ops, ++#ifdef CONFIG_PM_SLEEP ++ .resume = sdhci_pci_gli_resume, ++#endif ++}; ++ ++static const struct sdhci_ops sdhci_gl9750_ops = { ++ .read_l = sdhci_gl9750_readl, ++ .set_clock = sdhci_gl9750_set_clock, ++ .enable_dma = sdhci_pci_enable_dma, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_gl9750_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, ++ .voltage_switch = sdhci_gli_voltage_switch, ++ .platform_execute_tuning = gl9750_execute_tuning, ++}; ++ ++const struct sdhci_pci_fixes sdhci_gl9750 = { ++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, ++ .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, ++ .probe_slot = gli_probe_slot_gl9750, ++ .ops = &sdhci_gl9750_ops, ++#ifdef CONFIG_PM_SLEEP ++ .resume = sdhci_pci_gli_resume, ++#endif ++}; ++ ++static const struct sdhci_ops sdhci_gl9763e_ops = { ++ .set_clock = sdhci_set_clock, ++ .enable_dma = sdhci_pci_enable_dma, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_gl9763e_reset, ++ .set_uhs_signaling = sdhci_set_gl9763e_signaling, ++ .voltage_switch = sdhci_gli_voltage_switch, ++ .irq = sdhci_gl9763e_cqhci_irq, ++}; ++ ++const struct sdhci_pci_fixes sdhci_gl9763e = { ++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, ++ .probe_slot = gli_probe_slot_gl9763e, ++ .ops = &sdhci_gl9763e_ops, ++#ifdef CONFIG_PM_SLEEP ++ .resume = sdhci_cqhci_gli_resume, ++ .suspend = sdhci_cqhci_gli_suspend, ++#endif ++ .add_host = gl9763e_add_host, ++}; +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-o2micro.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-o2micro.c +new file mode 100644 +index 000000000..94e3f72f6 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-o2micro.c +@@ -0,0 +1,862 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2013 BayHub Technology Ltd. ++ * ++ * Authors: Peter Guo ++ * Adam Lee ++ * Ernest Zhang ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "sdhci.h" ++#include "sdhci-pci.h" ++ ++/* ++ * O2Micro device registers ++ */ ++ ++#define O2_SD_MISC_REG5 0x64 ++#define O2_SD_LD0_CTRL 0x68 ++#define O2_SD_DEV_CTRL 0x88 ++#define O2_SD_LOCK_WP 0xD3 ++#define O2_SD_TEST_REG 0xD4 ++#define O2_SD_FUNC_REG0 0xDC ++#define O2_SD_MULTI_VCC3V 0xEE ++#define O2_SD_CLKREQ 0xEC ++#define O2_SD_CAPS 0xE0 ++#define O2_SD_ADMA1 0xE2 ++#define O2_SD_ADMA2 0xE7 ++#define O2_SD_INF_MOD 0xF1 ++#define O2_SD_MISC_CTRL4 0xFC ++#define O2_SD_MISC_CTRL 0x1C0 ++#define O2_SD_PWR_FORCE_L0 0x0002 ++#define O2_SD_TUNING_CTRL 0x300 ++#define O2_SD_PLL_SETTING 0x304 ++#define O2_SD_MISC_SETTING 0x308 ++#define O2_SD_CLK_SETTING 0x328 ++#define O2_SD_CAP_REG2 0x330 ++#define O2_SD_CAP_REG0 0x334 ++#define O2_SD_UHS1_CAP_SETTING 0x33C ++#define O2_SD_DELAY_CTRL 0x350 ++#define O2_SD_UHS2_L1_CTRL 0x35C ++#define O2_SD_FUNC_REG3 0x3E0 ++#define O2_SD_FUNC_REG4 0x3E4 ++#define O2_SD_LED_ENABLE BIT(6) ++#define O2_SD_FREG0_LEDOFF BIT(13) ++#define O2_SD_FREG4_ENABLE_CLK_SET BIT(22) ++ ++#define O2_SD_VENDOR_SETTING 0x110 ++#define O2_SD_VENDOR_SETTING2 0x1C8 ++#define O2_SD_HW_TUNING_DISABLE BIT(4) ++ ++#define O2_PLL_DLL_WDT_CONTROL1 0x1CC ++#define O2_PLL_FORCE_ACTIVE BIT(18) ++#define O2_PLL_LOCK_STATUS BIT(14) ++#define O2_PLL_SOFT_RESET BIT(12) ++#define O2_DLL_LOCK_STATUS BIT(11) ++ ++#define O2_SD_DETECT_SETTING 0x324 ++ ++static const u32 dmdn_table[] = {0x2B1C0000, ++ 0x2C1A0000, 0x371B0000, 0x35100000}; ++#define DMDN_SZ ARRAY_SIZE(dmdn_table) ++ ++struct o2_host { ++ u8 dll_adjust_count; ++}; ++ ++static void sdhci_o2_wait_card_detect_stable(struct sdhci_host *host) ++{ ++ ktime_t timeout; ++ u32 scratch32; ++ ++ /* Wait max 50 ms */ ++ timeout = ktime_add_ms(ktime_get(), 50); ++ while (1) { ++ bool timedout = ktime_after(ktime_get(), timeout); ++ ++ scratch32 = sdhci_readl(host, SDHCI_PRESENT_STATE); ++ if ((scratch32 & SDHCI_CARD_PRESENT) >> SDHCI_CARD_PRES_SHIFT ++ == (scratch32 & SDHCI_CD_LVL) >> SDHCI_CD_LVL_SHIFT) ++ break; ++ ++ if (timedout) { ++ pr_err("%s: Card Detect debounce never finished.\n", ++ mmc_hostname(host->mmc)); ++ sdhci_dumpregs(host); ++ return; ++ } ++ udelay(10); ++ } ++} ++ ++static void sdhci_o2_enable_internal_clock(struct sdhci_host *host) ++{ ++ ktime_t timeout; ++ u16 scratch; ++ u32 scratch32; ++ ++ /* PLL software reset */ ++ scratch32 = sdhci_readl(host, O2_PLL_DLL_WDT_CONTROL1); ++ scratch32 |= O2_PLL_SOFT_RESET; ++ sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); ++ udelay(1); ++ scratch32 &= ~(O2_PLL_SOFT_RESET); ++ sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); ++ ++ /* PLL force active */ ++ scratch32 |= O2_PLL_FORCE_ACTIVE; ++ sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); ++ ++ /* Wait max 20 ms */ ++ timeout = ktime_add_ms(ktime_get(), 20); ++ while (1) { ++ bool timedout = ktime_after(ktime_get(), timeout); ++ ++ scratch = sdhci_readw(host, O2_PLL_DLL_WDT_CONTROL1); ++ if (scratch & O2_PLL_LOCK_STATUS) ++ break; ++ if (timedout) { ++ pr_err("%s: Internal clock never stabilised.\n", ++ mmc_hostname(host->mmc)); ++ sdhci_dumpregs(host); ++ goto out; ++ } ++ udelay(10); ++ } ++ ++ /* Wait for card detect finish */ ++ udelay(1); ++ sdhci_o2_wait_card_detect_stable(host); ++ ++out: ++ /* Cancel PLL force active */ ++ scratch32 = sdhci_readl(host, O2_PLL_DLL_WDT_CONTROL1); ++ scratch32 &= ~O2_PLL_FORCE_ACTIVE; ++ sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); ++} ++ ++static int sdhci_o2_get_cd(struct mmc_host *mmc) ++{ ++ struct sdhci_host *host = mmc_priv(mmc); ++ ++ if (!(sdhci_readw(host, O2_PLL_DLL_WDT_CONTROL1) & O2_PLL_LOCK_STATUS)) ++ sdhci_o2_enable_internal_clock(host); ++ ++ return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); ++} ++ ++static void o2_pci_set_baseclk(struct sdhci_pci_chip *chip, u32 value) ++{ ++ u32 scratch_32; ++ ++ pci_read_config_dword(chip->pdev, ++ O2_SD_PLL_SETTING, &scratch_32); ++ ++ scratch_32 &= 0x0000FFFF; ++ scratch_32 |= value; ++ ++ pci_write_config_dword(chip->pdev, ++ O2_SD_PLL_SETTING, scratch_32); ++} ++ ++static u32 sdhci_o2_pll_dll_wdt_control(struct sdhci_host *host) ++{ ++ return sdhci_readl(host, O2_PLL_DLL_WDT_CONTROL1); ++} ++ ++/* ++ * This function is used to detect dll lock status. ++ * Since the dll lock status bit will toggle randomly ++ * with very short interval which needs to be polled ++ * as fast as possible. Set sleep_us as 1 microsecond. ++ */ ++static int sdhci_o2_wait_dll_detect_lock(struct sdhci_host *host) ++{ ++ u32 scratch32 = 0; ++ ++ return readx_poll_timeout(sdhci_o2_pll_dll_wdt_control, host, ++ scratch32, !(scratch32 & O2_DLL_LOCK_STATUS), 1, 1000000); ++} ++ ++static void sdhci_o2_set_tuning_mode(struct sdhci_host *host) ++{ ++ u16 reg; ++ ++ /* enable hardware tuning */ ++ reg = sdhci_readw(host, O2_SD_VENDOR_SETTING); ++ reg &= ~O2_SD_HW_TUNING_DISABLE; ++ sdhci_writew(host, reg, O2_SD_VENDOR_SETTING); ++} ++ ++static void __sdhci_o2_execute_tuning(struct sdhci_host *host, u32 opcode) ++{ ++ int i; ++ ++ sdhci_send_tuning(host, opcode); ++ ++ for (i = 0; i < 150; i++) { ++ u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); ++ ++ if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { ++ if (ctrl & SDHCI_CTRL_TUNED_CLK) { ++ host->tuning_done = true; ++ return; ++ } ++ pr_warn("%s: HW tuning failed !\n", ++ mmc_hostname(host->mmc)); ++ break; ++ } ++ ++ mdelay(1); ++ } ++ ++ pr_info("%s: Tuning failed, falling back to fixed sampling clock\n", ++ mmc_hostname(host->mmc)); ++ sdhci_reset_tuning(host); ++} ++ ++/* ++ * This function is used to fix o2 dll shift issue. ++ * It isn't necessary to detect card present before recovery. ++ * Firstly, it is used by bht emmc card, which is embedded. ++ * Second, before call recovery card present will be detected ++ * outside of the execute tuning function. ++ */ ++static int sdhci_o2_dll_recovery(struct sdhci_host *host) ++{ ++ int ret = 0; ++ u8 scratch_8 = 0; ++ u32 scratch_32 = 0; ++ struct sdhci_pci_slot *slot = sdhci_priv(host); ++ struct sdhci_pci_chip *chip = slot->chip; ++ struct o2_host *o2_host = sdhci_pci_priv(slot); ++ ++ /* UnLock WP */ ++ pci_read_config_byte(chip->pdev, ++ O2_SD_LOCK_WP, &scratch_8); ++ scratch_8 &= 0x7f; ++ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8); ++ while (o2_host->dll_adjust_count < DMDN_SZ && !ret) { ++ /* Disable clock */ ++ sdhci_writeb(host, 0, SDHCI_CLOCK_CONTROL); ++ ++ /* PLL software reset */ ++ scratch_32 = sdhci_readl(host, O2_PLL_DLL_WDT_CONTROL1); ++ scratch_32 |= O2_PLL_SOFT_RESET; ++ sdhci_writel(host, scratch_32, O2_PLL_DLL_WDT_CONTROL1); ++ ++ pci_read_config_dword(chip->pdev, ++ O2_SD_FUNC_REG4, ++ &scratch_32); ++ /* Enable Base Clk setting change */ ++ scratch_32 |= O2_SD_FREG4_ENABLE_CLK_SET; ++ pci_write_config_dword(chip->pdev, O2_SD_FUNC_REG4, scratch_32); ++ o2_pci_set_baseclk(chip, dmdn_table[o2_host->dll_adjust_count]); ++ ++ /* Enable internal clock */ ++ scratch_8 = SDHCI_CLOCK_INT_EN; ++ sdhci_writeb(host, scratch_8, SDHCI_CLOCK_CONTROL); ++ ++ if (sdhci_o2_get_cd(host->mmc)) { ++ /* ++ * need wait at least 5ms for dll status stable, ++ * after enable internal clock ++ */ ++ usleep_range(5000, 6000); ++ if (sdhci_o2_wait_dll_detect_lock(host)) { ++ scratch_8 |= SDHCI_CLOCK_CARD_EN; ++ sdhci_writeb(host, scratch_8, ++ SDHCI_CLOCK_CONTROL); ++ ret = 1; ++ } else { ++ pr_warn("%s: DLL unlocked when dll_adjust_count is %d.\n", ++ mmc_hostname(host->mmc), ++ o2_host->dll_adjust_count); ++ } ++ } else { ++ pr_err("%s: card present detect failed.\n", ++ mmc_hostname(host->mmc)); ++ break; ++ } ++ ++ o2_host->dll_adjust_count++; ++ } ++ if (!ret && o2_host->dll_adjust_count == DMDN_SZ) ++ pr_err("%s: DLL adjust over max times\n", ++ mmc_hostname(host->mmc)); ++ /* Lock WP */ ++ pci_read_config_byte(chip->pdev, ++ O2_SD_LOCK_WP, &scratch_8); ++ scratch_8 |= 0x80; ++ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8); ++ return ret; ++} ++ ++static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode) ++{ ++ struct sdhci_host *host = mmc_priv(mmc); ++ int current_bus_width = 0; ++ u32 scratch32 = 0; ++ u16 scratch = 0; ++ ++ /* ++ * This handler only implements the eMMC tuning that is specific to ++ * this controller. Fall back to the standard method for other TIMING. ++ */ ++ if ((host->timing != MMC_TIMING_MMC_HS200) && ++ (host->timing != MMC_TIMING_UHS_SDR104)) ++ return sdhci_execute_tuning(mmc, opcode); ++ ++ if (WARN_ON((opcode != MMC_SEND_TUNING_BLOCK_HS200) && ++ (opcode != MMC_SEND_TUNING_BLOCK))) ++ return -EINVAL; ++ ++ /* Force power mode enter L0 */ ++ scratch = sdhci_readw(host, O2_SD_MISC_CTRL); ++ scratch |= O2_SD_PWR_FORCE_L0; ++ sdhci_writew(host, scratch, O2_SD_MISC_CTRL); ++ ++ /* wait DLL lock, timeout value 5ms */ ++ if (readx_poll_timeout(sdhci_o2_pll_dll_wdt_control, host, ++ scratch32, (scratch32 & O2_DLL_LOCK_STATUS), 1, 5000)) ++ pr_warn("%s: DLL can't lock in 5ms after force L0 during tuning.\n", ++ mmc_hostname(host->mmc)); ++ /* ++ * Judge the tuning reason, whether caused by dll shift ++ * If cause by dll shift, should call sdhci_o2_dll_recovery ++ */ ++ if (!sdhci_o2_wait_dll_detect_lock(host)) ++ if (!sdhci_o2_dll_recovery(host)) { ++ pr_err("%s: o2 dll recovery failed\n", ++ mmc_hostname(host->mmc)); ++ return -EINVAL; ++ } ++ /* ++ * o2 sdhci host didn't support 8bit emmc tuning ++ */ ++ if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) { ++ current_bus_width = mmc->ios.bus_width; ++ mmc->ios.bus_width = MMC_BUS_WIDTH_4; ++ sdhci_set_bus_width(host, MMC_BUS_WIDTH_4); ++ } ++ ++ sdhci_o2_set_tuning_mode(host); ++ ++ sdhci_start_tuning(host); ++ ++ __sdhci_o2_execute_tuning(host, opcode); ++ ++ sdhci_end_tuning(host); ++ ++ if (current_bus_width == MMC_BUS_WIDTH_8) { ++ mmc->ios.bus_width = MMC_BUS_WIDTH_8; ++ sdhci_set_bus_width(host, current_bus_width); ++ } ++ ++ /* Cancel force power mode enter L0 */ ++ scratch = sdhci_readw(host, O2_SD_MISC_CTRL); ++ scratch &= ~(O2_SD_PWR_FORCE_L0); ++ sdhci_writew(host, scratch, O2_SD_MISC_CTRL); ++ ++ sdhci_reset(host, SDHCI_RESET_CMD); ++ sdhci_reset(host, SDHCI_RESET_DATA); ++ ++ host->flags &= ~SDHCI_HS400_TUNING; ++ return 0; ++} ++ ++static void o2_pci_led_enable(struct sdhci_pci_chip *chip) ++{ ++ int ret; ++ u32 scratch_32; ++ ++ /* Set led of SD host function enable */ ++ ret = pci_read_config_dword(chip->pdev, ++ O2_SD_FUNC_REG0, &scratch_32); ++ if (ret) ++ return; ++ ++ scratch_32 &= ~O2_SD_FREG0_LEDOFF; ++ pci_write_config_dword(chip->pdev, ++ O2_SD_FUNC_REG0, scratch_32); ++ ++ ret = pci_read_config_dword(chip->pdev, ++ O2_SD_TEST_REG, &scratch_32); ++ if (ret) ++ return; ++ ++ scratch_32 |= O2_SD_LED_ENABLE; ++ pci_write_config_dword(chip->pdev, ++ O2_SD_TEST_REG, scratch_32); ++} ++ ++static void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip) ++{ ++ u32 scratch_32; ++ int ret; ++ /* Improve write performance for SD3.0 */ ++ ret = pci_read_config_dword(chip->pdev, O2_SD_DEV_CTRL, &scratch_32); ++ if (ret) ++ return; ++ scratch_32 &= ~((1 << 12) | (1 << 13) | (1 << 14)); ++ pci_write_config_dword(chip->pdev, O2_SD_DEV_CTRL, scratch_32); ++ ++ /* Enable Link abnormal reset generating Reset */ ++ ret = pci_read_config_dword(chip->pdev, O2_SD_MISC_REG5, &scratch_32); ++ if (ret) ++ return; ++ scratch_32 &= ~((1 << 19) | (1 << 11)); ++ scratch_32 |= (1 << 10); ++ pci_write_config_dword(chip->pdev, O2_SD_MISC_REG5, scratch_32); ++ ++ /* set card power over current protection */ ++ ret = pci_read_config_dword(chip->pdev, O2_SD_TEST_REG, &scratch_32); ++ if (ret) ++ return; ++ scratch_32 |= (1 << 4); ++ pci_write_config_dword(chip->pdev, O2_SD_TEST_REG, scratch_32); ++ ++ /* adjust the output delay for SD mode */ ++ pci_write_config_dword(chip->pdev, O2_SD_DELAY_CTRL, 0x00002492); ++ ++ /* Set the output voltage setting of Aux 1.2v LDO */ ++ ret = pci_read_config_dword(chip->pdev, O2_SD_LD0_CTRL, &scratch_32); ++ if (ret) ++ return; ++ scratch_32 &= ~(3 << 12); ++ pci_write_config_dword(chip->pdev, O2_SD_LD0_CTRL, scratch_32); ++ ++ /* Set Max power supply capability of SD host */ ++ ret = pci_read_config_dword(chip->pdev, O2_SD_CAP_REG0, &scratch_32); ++ if (ret) ++ return; ++ scratch_32 &= ~(0x01FE); ++ scratch_32 |= 0x00CC; ++ pci_write_config_dword(chip->pdev, O2_SD_CAP_REG0, scratch_32); ++ /* Set DLL Tuning Window */ ++ ret = pci_read_config_dword(chip->pdev, ++ O2_SD_TUNING_CTRL, &scratch_32); ++ if (ret) ++ return; ++ scratch_32 &= ~(0x000000FF); ++ scratch_32 |= 0x00000066; ++ pci_write_config_dword(chip->pdev, O2_SD_TUNING_CTRL, scratch_32); ++ ++ /* Set UHS2 T_EIDLE */ ++ ret = pci_read_config_dword(chip->pdev, ++ O2_SD_UHS2_L1_CTRL, &scratch_32); ++ if (ret) ++ return; ++ scratch_32 &= ~(0x000000FC); ++ scratch_32 |= 0x00000084; ++ pci_write_config_dword(chip->pdev, O2_SD_UHS2_L1_CTRL, scratch_32); ++ ++ /* Set UHS2 Termination */ ++ ret = pci_read_config_dword(chip->pdev, O2_SD_FUNC_REG3, &scratch_32); ++ if (ret) ++ return; ++ scratch_32 &= ~((1 << 21) | (1 << 30)); ++ ++ pci_write_config_dword(chip->pdev, O2_SD_FUNC_REG3, scratch_32); ++ ++ /* Set L1 Entrance Timer */ ++ ret = pci_read_config_dword(chip->pdev, O2_SD_CAPS, &scratch_32); ++ if (ret) ++ return; ++ scratch_32 &= ~(0xf0000000); ++ scratch_32 |= 0x30000000; ++ pci_write_config_dword(chip->pdev, O2_SD_CAPS, scratch_32); ++ ++ ret = pci_read_config_dword(chip->pdev, ++ O2_SD_MISC_CTRL4, &scratch_32); ++ if (ret) ++ return; ++ scratch_32 &= ~(0x000f0000); ++ scratch_32 |= 0x00080000; ++ pci_write_config_dword(chip->pdev, O2_SD_MISC_CTRL4, scratch_32); ++} ++ ++static void sdhci_pci_o2_enable_msi(struct sdhci_pci_chip *chip, ++ struct sdhci_host *host) ++{ ++ int ret; ++ ++ ret = pci_find_capability(chip->pdev, PCI_CAP_ID_MSI); ++ if (!ret) { ++ pr_info("%s: unsupport msi, use INTx irq\n", ++ mmc_hostname(host->mmc)); ++ return; ++ } ++ ++ ret = pci_alloc_irq_vectors(chip->pdev, 1, 1, ++ PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ if (ret < 0) { ++ pr_err("%s: enable PCI MSI failed, err=%d\n", ++ mmc_hostname(host->mmc), ret); ++ return; ++ } ++ ++ host->irq = pci_irq_vector(chip->pdev, 0); ++} ++ ++static void sdhci_o2_enable_clk(struct sdhci_host *host, u16 clk) ++{ ++ /* Enable internal clock */ ++ clk |= SDHCI_CLOCK_INT_EN; ++ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); ++ ++ sdhci_o2_enable_internal_clock(host); ++ if (sdhci_o2_get_cd(host->mmc)) { ++ clk |= SDHCI_CLOCK_CARD_EN; ++ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); ++ } ++} ++ ++static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock) ++{ ++ u16 clk; ++ u8 scratch; ++ u32 scratch_32; ++ struct sdhci_pci_slot *slot = sdhci_priv(host); ++ struct sdhci_pci_chip *chip = slot->chip; ++ ++ host->mmc->actual_clock = 0; ++ ++ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); ++ ++ if (clock == 0) ++ return; ++ ++ if ((host->timing == MMC_TIMING_UHS_SDR104) && (clock == 200000000)) { ++ pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); ++ ++ scratch &= 0x7f; ++ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); ++ ++ pci_read_config_dword(chip->pdev, O2_SD_PLL_SETTING, &scratch_32); ++ ++ if ((scratch_32 & 0xFFFF0000) != 0x2c280000) ++ o2_pci_set_baseclk(chip, 0x2c280000); ++ ++ pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); ++ ++ scratch |= 0x80; ++ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); ++ } ++ ++ clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); ++ sdhci_o2_enable_clk(host, clk); ++} ++ ++static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ struct sdhci_pci_chip *chip; ++ struct sdhci_host *host; ++ struct o2_host *o2_host = sdhci_pci_priv(slot); ++ u32 reg, caps; ++ int ret; ++ ++ chip = slot->chip; ++ host = slot->host; ++ ++ o2_host->dll_adjust_count = 0; ++ caps = sdhci_readl(host, SDHCI_CAPABILITIES); ++ ++ /* ++ * mmc_select_bus_width() will test the bus to determine the actual bus ++ * width. ++ */ ++ if (caps & SDHCI_CAN_DO_8BIT) ++ host->mmc->caps |= MMC_CAP_8_BIT_DATA; ++ ++ switch (chip->pdev->device) { ++ case PCI_DEVICE_ID_O2_SDS0: ++ case PCI_DEVICE_ID_O2_SEABIRD0: ++ case PCI_DEVICE_ID_O2_SEABIRD1: ++ case PCI_DEVICE_ID_O2_SDS1: ++ case PCI_DEVICE_ID_O2_FUJIN2: ++ reg = sdhci_readl(host, O2_SD_VENDOR_SETTING); ++ if (reg & 0x1) ++ host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; ++ ++ sdhci_pci_o2_enable_msi(chip, host); ++ ++ if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD0) { ++ ret = pci_read_config_dword(chip->pdev, ++ O2_SD_MISC_SETTING, ®); ++ if (ret) ++ return -EIO; ++ if (reg & (1 << 4)) { ++ pr_info("%s: emmc 1.8v flag is set, force 1.8v signaling voltage\n", ++ mmc_hostname(host->mmc)); ++ host->flags &= ~SDHCI_SIGNALING_330; ++ host->flags |= SDHCI_SIGNALING_180; ++ host->mmc->caps2 |= MMC_CAP2_NO_SD; ++ host->mmc->caps2 |= MMC_CAP2_NO_SDIO; ++ pci_write_config_dword(chip->pdev, ++ O2_SD_DETECT_SETTING, 3); ++ } ++ ++ slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd; ++ } ++ ++ if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD1) { ++ slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd; ++ host->mmc->caps2 |= MMC_CAP2_NO_SDIO; ++ host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; ++ } ++ ++ host->mmc_host_ops.execute_tuning = sdhci_o2_execute_tuning; ++ ++ if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2) ++ break; ++ /* set dll watch dog timer */ ++ reg = sdhci_readl(host, O2_SD_VENDOR_SETTING2); ++ reg |= (1 << 12); ++ sdhci_writel(host, reg, O2_SD_VENDOR_SETTING2); ++ ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip) ++{ ++ int ret; ++ u8 scratch; ++ u32 scratch_32; ++ ++ switch (chip->pdev->device) { ++ case PCI_DEVICE_ID_O2_8220: ++ case PCI_DEVICE_ID_O2_8221: ++ case PCI_DEVICE_ID_O2_8320: ++ case PCI_DEVICE_ID_O2_8321: ++ /* This extra setup is required due to broken ADMA. */ ++ ret = pci_read_config_byte(chip->pdev, ++ O2_SD_LOCK_WP, &scratch); ++ if (ret) ++ return ret; ++ scratch &= 0x7f; ++ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); ++ ++ /* Set Multi 3 to VCC3V# */ ++ pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08); ++ ++ /* Disable CLK_REQ# support after media DET */ ++ ret = pci_read_config_byte(chip->pdev, ++ O2_SD_CLKREQ, &scratch); ++ if (ret) ++ return ret; ++ scratch |= 0x20; ++ pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch); ++ ++ /* Choose capabilities, enable SDMA. We have to write 0x01 ++ * to the capabilities register first to unlock it. ++ */ ++ ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch); ++ if (ret) ++ return ret; ++ scratch |= 0x01; ++ pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch); ++ pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73); ++ ++ /* Disable ADMA1/2 */ ++ pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39); ++ pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08); ++ ++ /* Disable the infinite transfer mode */ ++ ret = pci_read_config_byte(chip->pdev, ++ O2_SD_INF_MOD, &scratch); ++ if (ret) ++ return ret; ++ scratch |= 0x08; ++ pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch); ++ ++ /* Lock WP */ ++ ret = pci_read_config_byte(chip->pdev, ++ O2_SD_LOCK_WP, &scratch); ++ if (ret) ++ return ret; ++ scratch |= 0x80; ++ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); ++ break; ++ case PCI_DEVICE_ID_O2_SDS0: ++ case PCI_DEVICE_ID_O2_SDS1: ++ case PCI_DEVICE_ID_O2_FUJIN2: ++ /* UnLock WP */ ++ ret = pci_read_config_byte(chip->pdev, ++ O2_SD_LOCK_WP, &scratch); ++ if (ret) ++ return ret; ++ ++ scratch &= 0x7f; ++ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); ++ ++ /* DevId=8520 subId= 0x11 or 0x12 Type Chip support */ ++ if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2) { ++ ret = pci_read_config_dword(chip->pdev, ++ O2_SD_FUNC_REG0, ++ &scratch_32); ++ scratch_32 = ((scratch_32 & 0xFF000000) >> 24); ++ ++ /* Check Whether subId is 0x11 or 0x12 */ ++ if ((scratch_32 == 0x11) || (scratch_32 == 0x12)) { ++ scratch_32 = 0x25100000; ++ ++ o2_pci_set_baseclk(chip, scratch_32); ++ ret = pci_read_config_dword(chip->pdev, ++ O2_SD_FUNC_REG4, ++ &scratch_32); ++ ++ /* Enable Base Clk setting change */ ++ scratch_32 |= O2_SD_FREG4_ENABLE_CLK_SET; ++ pci_write_config_dword(chip->pdev, ++ O2_SD_FUNC_REG4, ++ scratch_32); ++ ++ /* Set Tuning Window to 4 */ ++ pci_write_config_byte(chip->pdev, ++ O2_SD_TUNING_CTRL, 0x44); ++ ++ break; ++ } ++ } ++ ++ /* Enable 8520 led function */ ++ o2_pci_led_enable(chip); ++ ++ /* Set timeout CLK */ ++ ret = pci_read_config_dword(chip->pdev, ++ O2_SD_CLK_SETTING, &scratch_32); ++ if (ret) ++ return ret; ++ ++ scratch_32 &= ~(0xFF00); ++ scratch_32 |= 0x07E0C800; ++ pci_write_config_dword(chip->pdev, ++ O2_SD_CLK_SETTING, scratch_32); ++ ++ ret = pci_read_config_dword(chip->pdev, ++ O2_SD_CLKREQ, &scratch_32); ++ if (ret) ++ return ret; ++ scratch_32 |= 0x3; ++ pci_write_config_dword(chip->pdev, O2_SD_CLKREQ, scratch_32); ++ ++ ret = pci_read_config_dword(chip->pdev, ++ O2_SD_PLL_SETTING, &scratch_32); ++ if (ret) ++ return ret; ++ ++ scratch_32 &= ~(0x1F3F070E); ++ scratch_32 |= 0x18270106; ++ pci_write_config_dword(chip->pdev, ++ O2_SD_PLL_SETTING, scratch_32); ++ ++ /* Disable UHS1 funciton */ ++ ret = pci_read_config_dword(chip->pdev, ++ O2_SD_CAP_REG2, &scratch_32); ++ if (ret) ++ return ret; ++ scratch_32 &= ~(0xE0); ++ pci_write_config_dword(chip->pdev, ++ O2_SD_CAP_REG2, scratch_32); ++ ++ if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2) ++ sdhci_pci_o2_fujin2_pci_init(chip); ++ ++ /* Lock WP */ ++ ret = pci_read_config_byte(chip->pdev, ++ O2_SD_LOCK_WP, &scratch); ++ if (ret) ++ return ret; ++ scratch |= 0x80; ++ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); ++ break; ++ case PCI_DEVICE_ID_O2_SEABIRD0: ++ case PCI_DEVICE_ID_O2_SEABIRD1: ++ /* UnLock WP */ ++ ret = pci_read_config_byte(chip->pdev, ++ O2_SD_LOCK_WP, &scratch); ++ if (ret) ++ return ret; ++ ++ scratch &= 0x7f; ++ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); ++ ++ ret = pci_read_config_dword(chip->pdev, ++ O2_SD_PLL_SETTING, &scratch_32); ++ ++ if ((scratch_32 & 0xff000000) == 0x01000000) { ++ scratch_32 &= 0x0000FFFF; ++ scratch_32 |= 0x1F340000; ++ ++ pci_write_config_dword(chip->pdev, ++ O2_SD_PLL_SETTING, scratch_32); ++ } else { ++ scratch_32 &= 0x0000FFFF; ++ scratch_32 |= 0x25100000; ++ ++ pci_write_config_dword(chip->pdev, ++ O2_SD_PLL_SETTING, scratch_32); ++ ++ ret = pci_read_config_dword(chip->pdev, ++ O2_SD_FUNC_REG4, ++ &scratch_32); ++ scratch_32 |= (1 << 22); ++ pci_write_config_dword(chip->pdev, ++ O2_SD_FUNC_REG4, scratch_32); ++ } ++ ++ /* Set Tuning Windows to 5 */ ++ pci_write_config_byte(chip->pdev, ++ O2_SD_TUNING_CTRL, 0x55); ++ /* Lock WP */ ++ ret = pci_read_config_byte(chip->pdev, ++ O2_SD_LOCK_WP, &scratch); ++ if (ret) ++ return ret; ++ scratch |= 0x80; ++ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); ++ break; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip) ++{ ++ sdhci_pci_o2_probe(chip); ++ return sdhci_pci_resume_host(chip); ++} ++#endif ++ ++static const struct sdhci_ops sdhci_pci_o2_ops = { ++ .set_clock = sdhci_pci_o2_set_clock, ++ .enable_dma = sdhci_pci_enable_dma, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, ++}; ++ ++const struct sdhci_pci_fixes sdhci_o2 = { ++ .probe = sdhci_pci_o2_probe, ++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, ++ .quirks2 = SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD, ++ .probe_slot = sdhci_pci_o2_probe_slot, ++#ifdef CONFIG_PM_SLEEP ++ .resume = sdhci_pci_o2_resume, ++#endif ++ .ops = &sdhci_pci_o2_ops, ++ .priv_size = sizeof(struct o2_host), ++}; +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci.h +new file mode 100644 +index 000000000..8f90c4163 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci.h +@@ -0,0 +1,203 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __SDHCI_PCI_H ++#define __SDHCI_PCI_H ++ ++/* ++ * PCI device IDs, sub IDs ++ */ ++ ++#define PCI_DEVICE_ID_O2_SDS0 0x8420 ++#define PCI_DEVICE_ID_O2_SDS1 0x8421 ++#define PCI_DEVICE_ID_O2_FUJIN2 0x8520 ++#define PCI_DEVICE_ID_O2_SEABIRD0 0x8620 ++#define PCI_DEVICE_ID_O2_SEABIRD1 0x8621 ++ ++#define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809 ++#define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a ++#define PCI_DEVICE_ID_INTEL_BYT_EMMC 0x0f14 ++#define PCI_DEVICE_ID_INTEL_BYT_SDIO 0x0f15 ++#define PCI_DEVICE_ID_INTEL_BYT_SD 0x0f16 ++#define PCI_DEVICE_ID_INTEL_BYT_EMMC2 0x0f50 ++#define PCI_DEVICE_ID_INTEL_BSW_EMMC 0x2294 ++#define PCI_DEVICE_ID_INTEL_BSW_SDIO 0x2295 ++#define PCI_DEVICE_ID_INTEL_BSW_SD 0x2296 ++#define PCI_DEVICE_ID_INTEL_MRFLD_MMC 0x1190 ++#define PCI_DEVICE_ID_INTEL_CLV_SDIO0 0x08f9 ++#define PCI_DEVICE_ID_INTEL_CLV_SDIO1 0x08fa ++#define PCI_DEVICE_ID_INTEL_CLV_SDIO2 0x08fb ++#define PCI_DEVICE_ID_INTEL_CLV_EMMC0 0x08e5 ++#define PCI_DEVICE_ID_INTEL_CLV_EMMC1 0x08e6 ++#define PCI_DEVICE_ID_INTEL_QRK_SD 0x08A7 ++#define PCI_DEVICE_ID_INTEL_SPT_EMMC 0x9d2b ++#define PCI_DEVICE_ID_INTEL_SPT_SDIO 0x9d2c ++#define PCI_DEVICE_ID_INTEL_SPT_SD 0x9d2d ++#define PCI_DEVICE_ID_INTEL_DNV_EMMC 0x19db ++#define PCI_DEVICE_ID_INTEL_CDF_EMMC 0x18db ++#define PCI_DEVICE_ID_INTEL_BXT_SD 0x0aca ++#define PCI_DEVICE_ID_INTEL_BXT_EMMC 0x0acc ++#define PCI_DEVICE_ID_INTEL_BXT_SDIO 0x0ad0 ++#define PCI_DEVICE_ID_INTEL_BXTM_SD 0x1aca ++#define PCI_DEVICE_ID_INTEL_BXTM_EMMC 0x1acc ++#define PCI_DEVICE_ID_INTEL_BXTM_SDIO 0x1ad0 ++#define PCI_DEVICE_ID_INTEL_APL_SD 0x5aca ++#define PCI_DEVICE_ID_INTEL_APL_EMMC 0x5acc ++#define PCI_DEVICE_ID_INTEL_APL_SDIO 0x5ad0 ++#define PCI_DEVICE_ID_INTEL_GLK_SD 0x31ca ++#define PCI_DEVICE_ID_INTEL_GLK_EMMC 0x31cc ++#define PCI_DEVICE_ID_INTEL_GLK_SDIO 0x31d0 ++#define PCI_DEVICE_ID_INTEL_CNP_EMMC 0x9dc4 ++#define PCI_DEVICE_ID_INTEL_CNP_SD 0x9df5 ++#define PCI_DEVICE_ID_INTEL_CNPH_SD 0xa375 ++#define PCI_DEVICE_ID_INTEL_ICP_EMMC 0x34c4 ++#define PCI_DEVICE_ID_INTEL_ICP_SD 0x34f8 ++#define PCI_DEVICE_ID_INTEL_EHL_EMMC 0x4b47 ++#define PCI_DEVICE_ID_INTEL_EHL_SD 0x4b48 ++#define PCI_DEVICE_ID_INTEL_CML_EMMC 0x02c4 ++#define PCI_DEVICE_ID_INTEL_CML_SD 0x02f5 ++#define PCI_DEVICE_ID_INTEL_CMLH_SD 0x06f5 ++#define PCI_DEVICE_ID_INTEL_JSL_EMMC 0x4dc4 ++#define PCI_DEVICE_ID_INTEL_JSL_SD 0x4df8 ++#define PCI_DEVICE_ID_INTEL_LKF_EMMC 0x98c4 ++#define PCI_DEVICE_ID_INTEL_LKF_SD 0x98f8 ++ ++#define PCI_DEVICE_ID_SYSKONNECT_8000 0x8000 ++#define PCI_DEVICE_ID_VIA_95D0 0x95d0 ++#define PCI_DEVICE_ID_REALTEK_5250 0x5250 ++ ++#define PCI_SUBDEVICE_ID_NI_7884 0x7884 ++#define PCI_SUBDEVICE_ID_NI_78E3 0x78e3 ++ ++#define PCI_VENDOR_ID_ARASAN 0x16e6 ++#define PCI_DEVICE_ID_ARASAN_PHY_EMMC 0x0670 ++ ++#define PCI_DEVICE_ID_SYNOPSYS_DWC_MSHC 0xc202 ++ ++#define PCI_DEVICE_ID_GLI_9755 0x9755 ++#define PCI_DEVICE_ID_GLI_9750 0x9750 ++#define PCI_DEVICE_ID_GLI_9763E 0xe763 ++ ++/* ++ * PCI device class and mask ++ */ ++ ++#define SYSTEM_SDHCI (PCI_CLASS_SYSTEM_SDHCI << 8) ++#define PCI_CLASS_MASK 0xFFFF00 ++ ++/* ++ * Macros for PCI device-description ++ */ ++ ++#define _PCI_VEND(vend) PCI_VENDOR_ID_##vend ++#define _PCI_DEV(vend, dev) PCI_DEVICE_ID_##vend##_##dev ++#define _PCI_SUBDEV(subvend, subdev) PCI_SUBDEVICE_ID_##subvend##_##subdev ++ ++#define SDHCI_PCI_DEVICE(vend, dev, cfg) { \ ++ .vendor = _PCI_VEND(vend), .device = _PCI_DEV(vend, dev), \ ++ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \ ++ .driver_data = (kernel_ulong_t)&(sdhci_##cfg) \ ++} ++ ++#define SDHCI_PCI_SUBDEVICE(vend, dev, subvend, subdev, cfg) { \ ++ .vendor = _PCI_VEND(vend), .device = _PCI_DEV(vend, dev), \ ++ .subvendor = _PCI_VEND(subvend), \ ++ .subdevice = _PCI_SUBDEV(subvend, subdev), \ ++ .driver_data = (kernel_ulong_t)&(sdhci_##cfg) \ ++} ++ ++#define SDHCI_PCI_DEVICE_CLASS(vend, cl, cl_msk, cfg) { \ ++ .vendor = _PCI_VEND(vend), .device = PCI_ANY_ID, \ ++ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \ ++ .class = (cl), .class_mask = (cl_msk), \ ++ .driver_data = (kernel_ulong_t)&(sdhci_##cfg) \ ++} ++ ++/* ++ * PCI registers ++ */ ++ ++#define PCI_SDHCI_IFPIO 0x00 ++#define PCI_SDHCI_IFDMA 0x01 ++#define PCI_SDHCI_IFVENDOR 0x02 ++ ++#define PCI_SLOT_INFO 0x40 /* 8 bits */ ++#define PCI_SLOT_INFO_SLOTS(x) ((x >> 4) & 7) ++#define PCI_SLOT_INFO_FIRST_BAR_MASK 0x07 ++ ++#define MAX_SLOTS 8 ++ ++struct sdhci_pci_chip; ++struct sdhci_pci_slot; ++ ++struct sdhci_pci_fixes { ++ unsigned int quirks; ++ unsigned int quirks2; ++ bool allow_runtime_pm; ++ bool own_cd_for_runtime_pm; ++ ++ int (*probe) (struct sdhci_pci_chip *); ++ ++ int (*probe_slot) (struct sdhci_pci_slot *); ++ int (*add_host) (struct sdhci_pci_slot *); ++ void (*remove_slot) (struct sdhci_pci_slot *, int); ++ ++#ifdef CONFIG_PM_SLEEP ++ int (*suspend) (struct sdhci_pci_chip *); ++ int (*resume) (struct sdhci_pci_chip *); ++#endif ++#ifdef CONFIG_PM ++ int (*runtime_suspend) (struct sdhci_pci_chip *); ++ int (*runtime_resume) (struct sdhci_pci_chip *); ++#endif ++ ++ const struct sdhci_ops *ops; ++ size_t priv_size; ++}; ++ ++struct sdhci_pci_slot { ++ struct sdhci_pci_chip *chip; ++ struct sdhci_host *host; ++ struct sdhci_pci_data *data; ++ ++ int rst_n_gpio; ++ int cd_gpio; ++ int cd_irq; ++ ++ int cd_idx; ++ bool cd_override_level; ++ ++ void (*hw_reset)(struct sdhci_host *host); ++ unsigned long private[] ____cacheline_aligned; ++}; ++ ++struct sdhci_pci_chip { ++ struct pci_dev *pdev; ++ ++ unsigned int quirks; ++ unsigned int quirks2; ++ bool allow_runtime_pm; ++ bool pm_retune; ++ bool rpm_retune; ++ const struct sdhci_pci_fixes *fixes; ++ ++ int num_slots; /* Slots on controller */ ++ struct sdhci_pci_slot *slots[MAX_SLOTS]; /* Pointers to host slots */ ++}; ++ ++static inline void *sdhci_pci_priv(struct sdhci_pci_slot *slot) ++{ ++ return (void *)slot->private; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++int sdhci_pci_resume_host(struct sdhci_pci_chip *chip); ++#endif ++int sdhci_pci_enable_dma(struct sdhci_host *host); ++ ++extern const struct sdhci_pci_fixes sdhci_arasan; ++extern const struct sdhci_pci_fixes sdhci_snps; ++extern const struct sdhci_pci_fixes sdhci_o2; ++extern const struct sdhci_pci_fixes sdhci_gl9750; ++extern const struct sdhci_pci_fixes sdhci_gl9755; ++extern const struct sdhci_pci_fixes sdhci_gl9763e; ++ ++#endif /* __SDHCI_PCI_H */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci.h +new file mode 100644 +index 000000000..0770c036e +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci.h +@@ -0,0 +1,811 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver ++ * ++ * Header file for Host Controller registers and I/O accessors. ++ * ++ * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. ++ */ ++#ifndef __SDHCI_HW_H ++#define __SDHCI_HW_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* ++ * Controller registers ++ */ ++ ++#define SDHCI_DMA_ADDRESS 0x00 ++#define SDHCI_ARGUMENT2 SDHCI_DMA_ADDRESS ++#define SDHCI_32BIT_BLK_CNT SDHCI_DMA_ADDRESS ++ ++#define SDHCI_BLOCK_SIZE 0x04 ++#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF)) ++ ++#define SDHCI_BLOCK_COUNT 0x06 ++ ++#define SDHCI_ARGUMENT 0x08 ++ ++#define SDHCI_TRANSFER_MODE 0x0C ++#define SDHCI_TRNS_DMA 0x01 ++#define SDHCI_TRNS_BLK_CNT_EN 0x02 ++#define SDHCI_TRNS_AUTO_CMD12 0x04 ++#define SDHCI_TRNS_AUTO_CMD23 0x08 ++#define SDHCI_TRNS_AUTO_SEL 0x0C ++#define SDHCI_TRNS_READ 0x10 ++#define SDHCI_TRNS_MULTI 0x20 ++ ++#define SDHCI_COMMAND 0x0E ++#define SDHCI_CMD_RESP_MASK 0x03 ++#define SDHCI_CMD_CRC 0x08 ++#define SDHCI_CMD_INDEX 0x10 ++#define SDHCI_CMD_DATA 0x20 ++#define SDHCI_CMD_ABORTCMD 0xC0 ++ ++#define SDHCI_CMD_RESP_NONE 0x00 ++#define SDHCI_CMD_RESP_LONG 0x01 ++#define SDHCI_CMD_RESP_SHORT 0x02 ++#define SDHCI_CMD_RESP_SHORT_BUSY 0x03 ++ ++#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff)) ++#define SDHCI_GET_CMD(c) ((c>>8) & 0x3f) ++ ++#define SDHCI_RESPONSE 0x10 ++ ++#define SDHCI_BUFFER 0x20 ++ ++#define SDHCI_PRESENT_STATE 0x24 ++#define SDHCI_CMD_INHIBIT 0x00000001 ++#define SDHCI_DATA_INHIBIT 0x00000002 ++#define SDHCI_DOING_WRITE 0x00000100 ++#define SDHCI_DOING_READ 0x00000200 ++#define SDHCI_SPACE_AVAILABLE 0x00000400 ++#define SDHCI_DATA_AVAILABLE 0x00000800 ++#define SDHCI_CARD_PRESENT 0x00010000 ++#define SDHCI_CARD_PRES_SHIFT 16 ++#define SDHCI_CD_STABLE 0x00020000 ++#define SDHCI_CD_LVL 0x00040000 ++#define SDHCI_CD_LVL_SHIFT 18 ++#define SDHCI_WRITE_PROTECT 0x00080000 ++#define SDHCI_DATA_LVL_MASK 0x00F00000 ++#define SDHCI_DATA_LVL_SHIFT 20 ++#define SDHCI_DATA_0_LVL_MASK 0x00100000 ++#define SDHCI_CMD_LVL 0x01000000 ++ ++#define SDHCI_HOST_CONTROL 0x28 ++#define SDHCI_CTRL_LED 0x01 ++#define SDHCI_CTRL_4BITBUS 0x02 ++#define SDHCI_CTRL_HISPD 0x04 ++#define SDHCI_CTRL_DMA_MASK 0x18 ++#define SDHCI_CTRL_SDMA 0x00 ++#define SDHCI_CTRL_ADMA1 0x08 ++#define SDHCI_CTRL_ADMA32 0x10 ++#define SDHCI_CTRL_ADMA64 0x18 ++#define SDHCI_CTRL_ADMA3 0x18 ++#define SDHCI_CTRL_8BITBUS 0x20 ++#define SDHCI_CTRL_CDTEST_INS 0x40 ++#define SDHCI_CTRL_CDTEST_EN 0x80 ++ ++#define SDHCI_POWER_CONTROL 0x29 ++#define SDHCI_POWER_ON 0x01 ++#define SDHCI_POWER_180 0x0A ++#define SDHCI_POWER_300 0x0C ++#define SDHCI_POWER_330 0x0E ++ ++#define SDHCI_BLOCK_GAP_CONTROL 0x2A ++ ++#define SDHCI_WAKE_UP_CONTROL 0x2B ++#define SDHCI_WAKE_ON_INT 0x01 ++#define SDHCI_WAKE_ON_INSERT 0x02 ++#define SDHCI_WAKE_ON_REMOVE 0x04 ++ ++#define SDHCI_CLOCK_CONTROL 0x2C ++#define SDHCI_DIVIDER_SHIFT 8 ++#define SDHCI_DIVIDER_HI_SHIFT 6 ++#define SDHCI_DIV_MASK 0xFF ++#define SDHCI_DIV_MASK_LEN 8 ++#define SDHCI_DIV_HI_MASK 0x300 ++#define SDHCI_PROG_CLOCK_MODE 0x0020 ++#define SDHCI_CLOCK_CARD_EN 0x0004 ++#define SDHCI_CLOCK_PLL_EN 0x0008 ++#define SDHCI_CLOCK_INT_STABLE 0x0002 ++#define SDHCI_CLOCK_INT_EN 0x0001 ++ ++#define SDHCI_TIMEOUT_CONTROL 0x2E ++ ++#define SDHCI_SOFTWARE_RESET 0x2F ++#define SDHCI_RESET_ALL 0x01 ++#define SDHCI_RESET_CMD 0x02 ++#define SDHCI_RESET_DATA 0x04 ++ ++#define SDHCI_INT_STATUS 0x30 ++#define SDHCI_INT_ENABLE 0x34 ++#define SDHCI_SIGNAL_ENABLE 0x38 ++#define SDHCI_INT_RESPONSE 0x00000001 ++#define SDHCI_INT_DATA_END 0x00000002 ++#define SDHCI_INT_BLK_GAP 0x00000004 ++#define SDHCI_INT_DMA_END 0x00000008 ++#define SDHCI_INT_SPACE_AVAIL 0x00000010 ++#define SDHCI_INT_DATA_AVAIL 0x00000020 ++#define SDHCI_INT_CARD_INSERT 0x00000040 ++#define SDHCI_INT_CARD_REMOVE 0x00000080 ++#define SDHCI_INT_CARD_INT 0x00000100 ++#define SDHCI_INT_RETUNE 0x00001000 ++#define SDHCI_INT_CQE 0x00004000 ++#define SDHCI_INT_ERROR 0x00008000 ++#define SDHCI_INT_TIMEOUT 0x00010000 ++#define SDHCI_INT_CRC 0x00020000 ++#define SDHCI_INT_END_BIT 0x00040000 ++#define SDHCI_INT_INDEX 0x00080000 ++#define SDHCI_INT_DATA_TIMEOUT 0x00100000 ++#define SDHCI_INT_DATA_CRC 0x00200000 ++#define SDHCI_INT_DATA_END_BIT 0x00400000 ++#define SDHCI_INT_BUS_POWER 0x00800000 ++#define SDHCI_INT_AUTO_CMD_ERR 0x01000000 ++#define SDHCI_INT_ADMA_ERROR 0x02000000 ++ ++#define SDHCI_INT_NORMAL_MASK 0x00007FFF ++#define SDHCI_INT_ERROR_MASK 0xFFFF8000 ++ ++#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \ ++ SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX | \ ++ SDHCI_INT_AUTO_CMD_ERR) ++#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ ++ SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ ++ SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ ++ SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \ ++ SDHCI_INT_BLK_GAP) ++#define SDHCI_INT_ALL_MASK ((unsigned int)-1) ++ ++#define SDHCI_CQE_INT_ERR_MASK ( \ ++ SDHCI_INT_ADMA_ERROR | SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | \ ++ SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | \ ++ SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT) ++ ++#define SDHCI_CQE_INT_MASK (SDHCI_CQE_INT_ERR_MASK | SDHCI_INT_CQE) ++ ++#define SDHCI_AUTO_CMD_STATUS 0x3C ++#define SDHCI_AUTO_CMD_TIMEOUT 0x00000002 ++#define SDHCI_AUTO_CMD_CRC 0x00000004 ++#define SDHCI_AUTO_CMD_END_BIT 0x00000008 ++#define SDHCI_AUTO_CMD_INDEX 0x00000010 ++ ++#define SDHCI_HOST_CONTROL2 0x3E ++#define SDHCI_CTRL_UHS_MASK 0x0007 ++#define SDHCI_CTRL_UHS_SDR12 0x0000 ++#define SDHCI_CTRL_UHS_SDR25 0x0001 ++#define SDHCI_CTRL_UHS_SDR50 0x0002 ++#define SDHCI_CTRL_UHS_SDR104 0x0003 ++#define SDHCI_CTRL_UHS_DDR50 0x0004 ++#define SDHCI_CTRL_HS400 0x0005 /* Non-standard */ ++#define SDHCI_CTRL_VDD_180 0x0008 ++#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 ++#define SDHCI_CTRL_DRV_TYPE_B 0x0000 ++#define SDHCI_CTRL_DRV_TYPE_A 0x0010 ++#define SDHCI_CTRL_DRV_TYPE_C 0x0020 ++#define SDHCI_CTRL_DRV_TYPE_D 0x0030 ++#define SDHCI_CTRL_EXEC_TUNING 0x0040 ++#define SDHCI_CTRL_TUNED_CLK 0x0080 ++#define SDHCI_CMD23_ENABLE 0x0800 ++#define SDHCI_CTRL_V4_MODE 0x1000 ++#define SDHCI_CTRL_64BIT_ADDR 0x2000 ++#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000 ++ ++#define SDHCI_CAPABILITIES 0x40 ++#define SDHCI_TIMEOUT_CLK_MASK GENMASK(5, 0) ++#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080 ++#define SDHCI_CLOCK_BASE_MASK GENMASK(13, 8) ++#define SDHCI_CLOCK_V3_BASE_MASK GENMASK(15, 8) ++#define SDHCI_MAX_BLOCK_MASK 0x00030000 ++#define SDHCI_MAX_BLOCK_SHIFT 16 ++#define SDHCI_CAN_DO_8BIT 0x00040000 ++#define SDHCI_CAN_DO_ADMA2 0x00080000 ++#define SDHCI_CAN_DO_ADMA1 0x00100000 ++#define SDHCI_CAN_DO_HISPD 0x00200000 ++#define SDHCI_CAN_DO_SDMA 0x00400000 ++#define SDHCI_CAN_DO_SUSPEND 0x00800000 ++#define SDHCI_CAN_VDD_330 0x01000000 ++#define SDHCI_CAN_VDD_300 0x02000000 ++#define SDHCI_CAN_VDD_180 0x04000000 ++#define SDHCI_CAN_64BIT_V4 0x08000000 ++#define SDHCI_CAN_64BIT 0x10000000 ++ ++#define SDHCI_CAPABILITIES_1 0x44 ++#define SDHCI_SUPPORT_SDR50 0x00000001 ++#define SDHCI_SUPPORT_SDR104 0x00000002 ++#define SDHCI_SUPPORT_DDR50 0x00000004 ++#define SDHCI_DRIVER_TYPE_A 0x00000010 ++#define SDHCI_DRIVER_TYPE_C 0x00000020 ++#define SDHCI_DRIVER_TYPE_D 0x00000040 ++#define SDHCI_RETUNING_TIMER_COUNT_MASK GENMASK(11, 8) ++#define SDHCI_USE_SDR50_TUNING 0x00002000 ++#define SDHCI_RETUNING_MODE_MASK GENMASK(15, 14) ++#define SDHCI_CLOCK_MUL_MASK GENMASK(23, 16) ++#define SDHCI_CAN_DO_ADMA3 0x08000000 ++#define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */ ++ ++#define SDHCI_MAX_CURRENT 0x48 ++#define SDHCI_MAX_CURRENT_LIMIT GENMASK(7, 0) ++#define SDHCI_MAX_CURRENT_330_MASK GENMASK(7, 0) ++#define SDHCI_MAX_CURRENT_300_MASK GENMASK(15, 8) ++#define SDHCI_MAX_CURRENT_180_MASK GENMASK(23, 16) ++#define SDHCI_MAX_CURRENT_MULTIPLIER 4 ++ ++/* 4C-4F reserved for more max current */ ++ ++#define SDHCI_SET_ACMD12_ERROR 0x50 ++#define SDHCI_SET_INT_ERROR 0x52 ++ ++#define SDHCI_ADMA_ERROR 0x54 ++ ++/* 55-57 reserved */ ++ ++#define SDHCI_ADMA_ADDRESS 0x58 ++#define SDHCI_ADMA_ADDRESS_HI 0x5C ++ ++/* 60-FB reserved */ ++ ++#define SDHCI_PRESET_FOR_SDR12 0x66 ++#define SDHCI_PRESET_FOR_SDR25 0x68 ++#define SDHCI_PRESET_FOR_SDR50 0x6A ++#define SDHCI_PRESET_FOR_SDR104 0x6C ++#define SDHCI_PRESET_FOR_DDR50 0x6E ++#define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */ ++#define SDHCI_PRESET_DRV_MASK GENMASK(15, 14) ++#define SDHCI_PRESET_CLKGEN_SEL BIT(10) ++#define SDHCI_PRESET_SDCLK_FREQ_MASK GENMASK(9, 0) ++ ++#define SDHCI_SLOT_INT_STATUS 0xFC ++ ++#define SDHCI_HOST_VERSION 0xFE ++#define SDHCI_VENDOR_VER_MASK 0xFF00 ++#define SDHCI_VENDOR_VER_SHIFT 8 ++#define SDHCI_SPEC_VER_MASK 0x00FF ++#define SDHCI_SPEC_VER_SHIFT 0 ++#define SDHCI_SPEC_100 0 ++#define SDHCI_SPEC_200 1 ++#define SDHCI_SPEC_300 2 ++#define SDHCI_SPEC_400 3 ++#define SDHCI_SPEC_410 4 ++#define SDHCI_SPEC_420 5 ++ ++/* ++ * End of controller registers. ++ */ ++ ++#define SDHCI_MAX_DIV_SPEC_200 256 ++#define SDHCI_MAX_DIV_SPEC_300 2046 ++ ++/* ++ * Host SDMA buffer boundary. Valid values from 4K to 512K in powers of 2. ++ */ ++#define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024) ++#define SDHCI_DEFAULT_BOUNDARY_ARG (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12) ++ ++/* ADMA2 32-bit DMA descriptor size */ ++#define SDHCI_ADMA2_32_DESC_SZ 8 ++ ++/* ADMA2 32-bit descriptor */ ++struct sdhci_adma2_32_desc { ++ __le16 cmd; ++ __le16 len; ++ __le32 addr; ++} __packed __aligned(4); ++ ++/* ADMA2 data alignment */ ++#define SDHCI_ADMA2_ALIGN 4 ++#define SDHCI_ADMA2_MASK (SDHCI_ADMA2_ALIGN - 1) ++ ++/* ++ * ADMA2 descriptor alignment. Some controllers (e.g. Intel) require 8 byte ++ * alignment for the descriptor table even in 32-bit DMA mode. Memory ++ * allocation is at least 8 byte aligned anyway, so just stipulate 8 always. ++ */ ++#define SDHCI_ADMA2_DESC_ALIGN 8 ++ ++/* ++ * ADMA2 64-bit DMA descriptor size ++ * According to SD Host Controller spec v4.10, there are two kinds of ++ * descriptors for 64-bit addressing mode: 96-bit Descriptor and 128-bit ++ * Descriptor, if Host Version 4 Enable is set in the Host Control 2 ++ * register, 128-bit Descriptor will be selected. ++ */ ++#define SDHCI_ADMA2_64_DESC_SZ(host) ((host)->v4_mode ? 16 : 12) ++ ++/* ++ * ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte ++ * aligned. ++ */ ++struct sdhci_adma2_64_desc { ++ __le16 cmd; ++ __le16 len; ++ __le32 addr_lo; ++ __le32 addr_hi; ++} __packed __aligned(4); ++ ++#define ADMA2_TRAN_VALID 0x21 ++#define ADMA2_NOP_END_VALID 0x3 ++#define ADMA2_END 0x2 ++ ++/* ++ * Maximum segments assuming a 512KiB maximum requisition size and a minimum ++ * 4KiB page size. ++ */ ++#define SDHCI_MAX_SEGS 128 ++ ++/* Allow for a a command request and a data request at the same time */ ++#define SDHCI_MAX_MRQS 2 ++ ++/* ++ * 48bit command and 136 bit response in 100KHz clock could take upto 2.48ms. ++ * However since the start time of the command, the time between ++ * command and response, and the time between response and start of data is ++ * not known, set the command transfer time to 10ms. ++ */ ++#define MMC_CMD_TRANSFER_TIME (10 * NSEC_PER_MSEC) /* max 10 ms */ ++ ++enum sdhci_cookie { ++ COOKIE_UNMAPPED, ++ COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */ ++ COOKIE_MAPPED, /* mapped by sdhci_prepare_data() */ ++}; ++ ++struct sdhci_host { ++ /* Data set by hardware interface driver */ ++ const char *hw_name; /* Hardware bus name */ ++ ++ unsigned int quirks; /* Deviations from spec. */ ++ ++/* Controller doesn't honor resets unless we touch the clock register */ ++#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) ++/* Controller has bad caps bits, but really supports DMA */ ++#define SDHCI_QUIRK_FORCE_DMA (1<<1) ++/* Controller doesn't like to be reset when there is no card inserted. */ ++#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) ++/* Controller doesn't like clearing the power reg before a change */ ++#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) ++/* Controller has flaky internal state so reset it on each ios change */ ++#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4) ++/* Controller has an unusable DMA engine */ ++#define SDHCI_QUIRK_BROKEN_DMA (1<<5) ++/* Controller has an unusable ADMA engine */ ++#define SDHCI_QUIRK_BROKEN_ADMA (1<<6) ++/* Controller can only DMA from 32-bit aligned addresses */ ++#define SDHCI_QUIRK_32BIT_DMA_ADDR (1<<7) ++/* Controller can only DMA chunk sizes that are a multiple of 32 bits */ ++#define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<8) ++/* Controller can only ADMA chunks that are a multiple of 32 bits */ ++#define SDHCI_QUIRK_32BIT_ADMA_SIZE (1<<9) ++/* Controller needs to be reset after each request to stay stable */ ++#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<10) ++/* Controller needs voltage and power writes to happen separately */ ++#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<11) ++/* Controller provides an incorrect timeout value for transfers */ ++#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12) ++/* Controller has an issue with buffer bits for small transfers */ ++#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13) ++/* Controller does not provide transfer-complete interrupt when not busy */ ++#define SDHCI_QUIRK_NO_BUSY_IRQ (1<<14) ++/* Controller has unreliable card detection */ ++#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15) ++/* Controller reports inverted write-protect state */ ++#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16) ++/* Controller has unusable command queue engine */ ++#define SDHCI_QUIRK_BROKEN_CQE (1<<17) ++/* Controller does not like fast PIO transfers */ ++#define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18) ++/* Controller does not have a LED */ ++#define SDHCI_QUIRK_NO_LED (1<<19) ++/* Controller has to be forced to use block size of 2048 bytes */ ++#define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20) ++/* Controller cannot do multi-block transfers */ ++#define SDHCI_QUIRK_NO_MULTIBLOCK (1<<21) ++/* Controller can only handle 1-bit data transfers */ ++#define SDHCI_QUIRK_FORCE_1_BIT_DATA (1<<22) ++/* Controller needs 10ms delay between applying power and clock */ ++#define SDHCI_QUIRK_DELAY_AFTER_POWER (1<<23) ++/* Controller uses SDCLK instead of TMCLK for data timeouts */ ++#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1<<24) ++/* Controller reports wrong base clock capability */ ++#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1<<25) ++/* Controller cannot support End Attribute in NOP ADMA descriptor */ ++#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1<<26) ++/* Controller is missing device caps. Use caps provided by host */ ++#define SDHCI_QUIRK_MISSING_CAPS (1<<27) ++/* Controller uses Auto CMD12 command to stop the transfer */ ++#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1<<28) ++/* Controller doesn't have HISPD bit field in HI-SPEED SD card */ ++#define SDHCI_QUIRK_NO_HISPD_BIT (1<<29) ++/* Controller treats ADMA descriptors with length 0000h incorrectly */ ++#define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC (1<<30) ++/* The read-only detection via SDHCI_PRESENT_STATE register is unstable */ ++#define SDHCI_QUIRK_UNSTABLE_RO_DETECT (1<<31) ++ ++ unsigned int quirks2; /* More deviations from spec. */ ++ ++#define SDHCI_QUIRK2_HOST_OFF_CARD_ON (1<<0) ++#define SDHCI_QUIRK2_HOST_NO_CMD23 (1<<1) ++/* The system physically doesn't support 1.8v, even if the host does */ ++#define SDHCI_QUIRK2_NO_1_8_V (1<<2) ++#define SDHCI_QUIRK2_PRESET_VALUE_BROKEN (1<<3) ++#define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON (1<<4) ++/* Controller has a non-standard host control register */ ++#define SDHCI_QUIRK2_BROKEN_HOST_CONTROL (1<<5) ++/* Controller does not support HS200 */ ++#define SDHCI_QUIRK2_BROKEN_HS200 (1<<6) ++/* Controller does not support DDR50 */ ++#define SDHCI_QUIRK2_BROKEN_DDR50 (1<<7) ++/* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */ ++#define SDHCI_QUIRK2_STOP_WITH_TC (1<<8) ++/* Controller does not support 64-bit DMA */ ++#define SDHCI_QUIRK2_BROKEN_64_BIT_DMA (1<<9) ++/* need clear transfer mode register before send cmd */ ++#define SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD (1<<10) ++/* Capability register bit-63 indicates HS400 support */ ++#define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 (1<<11) ++/* forced tuned clock */ ++#define SDHCI_QUIRK2_TUNING_WORK_AROUND (1<<12) ++/* disable the block count for single block transactions */ ++#define SDHCI_QUIRK2_SUPPORT_SINGLE (1<<13) ++/* Controller broken with using ACMD23 */ ++#define SDHCI_QUIRK2_ACMD23_BROKEN (1<<14) ++/* Broken Clock divider zero in controller */ ++#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15) ++/* Controller has CRC in 136 bit Command Response */ ++#define SDHCI_QUIRK2_RSP_136_HAS_CRC (1<<16) ++/* ++ * Disable HW timeout if the requested timeout is more than the maximum ++ * obtainable timeout. ++ */ ++#define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT (1<<17) ++/* ++ * 32-bit block count may not support eMMC where upper bits of CMD23 are used ++ * for other purposes. Consequently we support 16-bit block count by default. ++ * Otherwise, SDHCI_QUIRK2_USE_32BIT_BLK_CNT can be selected to use 32-bit ++ * block count. ++ */ ++#define SDHCI_QUIRK2_USE_32BIT_BLK_CNT (1<<18) ++ ++ int irq; /* Device IRQ */ ++ void __iomem *ioaddr; /* Mapped address */ ++ phys_addr_t mapbase; /* physical address base */ ++ char *bounce_buffer; /* For packing SDMA reads/writes */ ++ dma_addr_t bounce_addr; ++ unsigned int bounce_buffer_size; ++ ++ const struct sdhci_ops *ops; /* Low level hw interface */ ++ ++ /* Internal data */ ++ struct mmc_host *mmc; /* MMC structure */ ++ struct mmc_host_ops mmc_host_ops; /* MMC host ops */ ++ u64 dma_mask; /* custom DMA mask */ ++ ++#if IS_ENABLED(CONFIG_LEDS_CLASS) ++ struct led_classdev led; /* LED control */ ++ char led_name[32]; ++#endif ++ ++ spinlock_t lock; /* Mutex */ ++ ++ int flags; /* Host attributes */ ++#define SDHCI_USE_SDMA (1<<0) /* Host is SDMA capable */ ++#define SDHCI_USE_ADMA (1<<1) /* Host is ADMA capable */ ++#define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */ ++#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */ ++#define SDHCI_SDR50_NEEDS_TUNING (1<<4) /* SDR50 needs tuning */ ++#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */ ++#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */ ++#define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */ ++#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */ ++#define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */ ++#define SDHCI_SIGNALING_330 (1<<14) /* Host is capable of 3.3V signaling */ ++#define SDHCI_SIGNALING_180 (1<<15) /* Host is capable of 1.8V signaling */ ++#define SDHCI_SIGNALING_120 (1<<16) /* Host is capable of 1.2V signaling */ ++ ++ unsigned int version; /* SDHCI spec. version */ ++ ++ unsigned int max_clk; /* Max possible freq (MHz) */ ++ unsigned int timeout_clk; /* Timeout freq (KHz) */ ++ unsigned int clk_mul; /* Clock Muliplier value */ ++ ++ unsigned int clock; /* Current clock (MHz) */ ++ u8 pwr; /* Current voltage */ ++ ++ bool runtime_suspended; /* Host is runtime suspended */ ++ bool bus_on; /* Bus power prevents runtime suspend */ ++ bool preset_enabled; /* Preset is enabled */ ++ bool pending_reset; /* Cmd/data reset is pending */ ++ bool irq_wake_enabled; /* IRQ wakeup is enabled */ ++ bool v4_mode; /* Host Version 4 Enable */ ++ bool use_external_dma; /* Host selects to use external DMA */ ++ bool always_defer_done; /* Always defer to complete requests */ ++ ++ struct mmc_request *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */ ++ struct mmc_command *cmd; /* Current command */ ++ struct mmc_command *data_cmd; /* Current data command */ ++ struct mmc_command *deferred_cmd; /* Deferred command */ ++ struct mmc_data *data; /* Current data request */ ++ unsigned int data_early:1; /* Data finished before cmd */ ++ ++ struct sg_mapping_iter sg_miter; /* SG state for PIO */ ++ unsigned int blocks; /* remaining PIO blocks */ ++ ++ int sg_count; /* Mapped sg entries */ ++ ++ void *adma_table; /* ADMA descriptor table */ ++ void *align_buffer; /* Bounce buffer */ ++ ++ size_t adma_table_sz; /* ADMA descriptor table size */ ++ size_t align_buffer_sz; /* Bounce buffer size */ ++ ++ dma_addr_t adma_addr; /* Mapped ADMA descr. table */ ++ dma_addr_t align_addr; /* Mapped bounce buffer */ ++ ++ unsigned int desc_sz; /* ADMA current descriptor size */ ++ unsigned int alloc_desc_sz; /* ADMA descr. max size host supports */ ++ ++ struct workqueue_struct *complete_wq; /* Request completion wq */ ++ struct work_struct complete_work; /* Request completion work */ ++ ++ struct timer_list timer; /* Timer for timeouts */ ++ struct timer_list data_timer; /* Timer for data timeouts */ ++ ++#if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA) ++ struct dma_chan *rx_chan; ++ struct dma_chan *tx_chan; ++#endif ++ ++ u32 caps; /* CAPABILITY_0 */ ++ u32 caps1; /* CAPABILITY_1 */ ++ bool read_caps; /* Capability flags have been read */ ++ ++ bool sdhci_core_to_disable_vqmmc; /* sdhci core can disable vqmmc */ ++ unsigned int ocr_avail_sdio; /* OCR bit masks */ ++ unsigned int ocr_avail_sd; ++ unsigned int ocr_avail_mmc; ++ u32 ocr_mask; /* available voltages */ ++ ++ unsigned timing; /* Current timing */ ++ ++ u32 thread_isr; ++ ++ /* cached registers */ ++ u32 ier; ++ ++ bool cqe_on; /* CQE is operating */ ++ u32 cqe_ier; /* CQE interrupt mask */ ++ u32 cqe_err_ier; /* CQE error interrupt mask */ ++ ++ wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */ ++ unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */ ++ ++ unsigned int tuning_count; /* Timer count for re-tuning */ ++ unsigned int tuning_mode; /* Re-tuning mode supported by host */ ++ unsigned int tuning_err; /* Error code for re-tuning */ ++#define SDHCI_TUNING_MODE_1 0 ++#define SDHCI_TUNING_MODE_2 1 ++#define SDHCI_TUNING_MODE_3 2 ++ /* Delay (ms) between tuning commands */ ++ int tuning_delay; ++ int tuning_loop_count; ++ ++ /* Host SDMA buffer boundary. */ ++ u32 sdma_boundary; ++ ++ /* Host ADMA table count */ ++ u32 adma_table_cnt; ++ ++ u64 data_timeout; ++ ++ unsigned long private[] ____cacheline_aligned; ++}; ++ ++struct sdhci_ops { ++#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS ++ u32 (*read_l)(struct sdhci_host *host, int reg); ++ u16 (*read_w)(struct sdhci_host *host, int reg); ++ u8 (*read_b)(struct sdhci_host *host, int reg); ++ void (*write_l)(struct sdhci_host *host, u32 val, int reg); ++ void (*write_w)(struct sdhci_host *host, u16 val, int reg); ++ void (*write_b)(struct sdhci_host *host, u8 val, int reg); ++#endif ++ ++ void (*set_clock)(struct sdhci_host *host, unsigned int clock); ++ void (*set_power)(struct sdhci_host *host, unsigned char mode, ++ unsigned short vdd); ++ ++ u32 (*irq)(struct sdhci_host *host, u32 intmask); ++ ++ int (*set_dma_mask)(struct sdhci_host *host); ++ int (*enable_dma)(struct sdhci_host *host); ++ unsigned int (*get_max_clock)(struct sdhci_host *host); ++ unsigned int (*get_min_clock)(struct sdhci_host *host); ++ /* get_timeout_clock should return clk rate in unit of Hz */ ++ unsigned int (*get_timeout_clock)(struct sdhci_host *host); ++ unsigned int (*get_max_timeout_count)(struct sdhci_host *host); ++ void (*set_timeout)(struct sdhci_host *host, ++ struct mmc_command *cmd); ++ void (*set_bus_width)(struct sdhci_host *host, int width); ++ void (*platform_send_init_74_clocks)(struct sdhci_host *host, ++ u8 power_mode); ++ unsigned int (*get_ro)(struct sdhci_host *host); ++ void (*reset)(struct sdhci_host *host, u8 mask); ++ int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode); ++ void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); ++ void (*hw_reset)(struct sdhci_host *host); ++ void (*adma_workaround)(struct sdhci_host *host, u32 intmask); ++ void (*card_event)(struct sdhci_host *host); ++ void (*voltage_switch)(struct sdhci_host *host); ++ void (*adma_write_desc)(struct sdhci_host *host, void **desc, ++ dma_addr_t addr, int len, unsigned int cmd); ++ void (*copy_to_bounce_buffer)(struct sdhci_host *host, ++ struct mmc_data *data, ++ unsigned int length); ++ void (*request_done)(struct sdhci_host *host, ++ struct mmc_request *mrq); ++ void (*dump_vendor_regs)(struct sdhci_host *host); ++}; ++ ++#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS ++ ++static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg) ++{ ++ if (unlikely(host->ops->write_l)) ++ host->ops->write_l(host, val, reg); ++ else ++ writel(val, host->ioaddr + reg); ++} ++ ++static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg) ++{ ++ if (unlikely(host->ops->write_w)) ++ host->ops->write_w(host, val, reg); ++ else ++ writew(val, host->ioaddr + reg); ++} ++ ++static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg) ++{ ++ if (unlikely(host->ops->write_b)) ++ host->ops->write_b(host, val, reg); ++ else ++ writeb(val, host->ioaddr + reg); ++} ++ ++static inline u32 sdhci_readl(struct sdhci_host *host, int reg) ++{ ++ if (unlikely(host->ops->read_l)) ++ return host->ops->read_l(host, reg); ++ else ++ return readl(host->ioaddr + reg); ++} ++ ++static inline u16 sdhci_readw(struct sdhci_host *host, int reg) ++{ ++ if (unlikely(host->ops->read_w)) ++ return host->ops->read_w(host, reg); ++ else ++ return readw(host->ioaddr + reg); ++} ++ ++static inline u8 sdhci_readb(struct sdhci_host *host, int reg) ++{ ++ if (unlikely(host->ops->read_b)) ++ return host->ops->read_b(host, reg); ++ else ++ return readb(host->ioaddr + reg); ++} ++ ++#else ++ ++static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg) ++{ ++ writel(val, host->ioaddr + reg); ++} ++ ++static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg) ++{ ++ writew(val, host->ioaddr + reg); ++} ++ ++static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg) ++{ ++ writeb(val, host->ioaddr + reg); ++} ++ ++static inline u32 sdhci_readl(struct sdhci_host *host, int reg) ++{ ++ return readl(host->ioaddr + reg); ++} ++ ++static inline u16 sdhci_readw(struct sdhci_host *host, int reg) ++{ ++ return readw(host->ioaddr + reg); ++} ++ ++static inline u8 sdhci_readb(struct sdhci_host *host, int reg) ++{ ++ return readb(host->ioaddr + reg); ++} ++ ++#endif /* CONFIG_MMC_SDHCI_IO_ACCESSORS */ ++ ++struct sdhci_host *sdhci_alloc_host(struct device *dev, size_t priv_size); ++void sdhci_free_host(struct sdhci_host *host); ++ ++static inline void *sdhci_priv(struct sdhci_host *host) ++{ ++ return host->private; ++} ++ ++void sdhci_card_detect(struct sdhci_host *host); ++void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver, ++ const u32 *caps, const u32 *caps1); ++int sdhci_setup_host(struct sdhci_host *host); ++void sdhci_cleanup_host(struct sdhci_host *host); ++int __sdhci_add_host(struct sdhci_host *host); ++int sdhci_add_host(struct sdhci_host *host); ++void sdhci_remove_host(struct sdhci_host *host, int dead); ++ ++static inline void sdhci_read_caps(struct sdhci_host *host) ++{ ++ __sdhci_read_caps(host, NULL, NULL, NULL); ++} ++ ++u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock, ++ unsigned int *actual_clock); ++void sdhci_set_clock(struct sdhci_host *host, unsigned int clock); ++void sdhci_enable_clk(struct sdhci_host *host, u16 clk); ++void sdhci_set_power(struct sdhci_host *host, unsigned char mode, ++ unsigned short vdd); ++void sdhci_set_power_and_bus_voltage(struct sdhci_host *host, ++ unsigned char mode, ++ unsigned short vdd); ++void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, ++ unsigned short vdd); ++void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq); ++int sdhci_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq); ++void sdhci_set_bus_width(struct sdhci_host *host, int width); ++void sdhci_reset(struct sdhci_host *host, u8 mask); ++void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); ++int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); ++void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); ++int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, ++ struct mmc_ios *ios); ++void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable); ++void sdhci_adma_write_desc(struct sdhci_host *host, void **desc, ++ dma_addr_t addr, int len, unsigned int cmd); ++ ++#ifdef CONFIG_PM ++int sdhci_suspend_host(struct sdhci_host *host); ++int sdhci_resume_host(struct sdhci_host *host); ++int sdhci_runtime_suspend_host(struct sdhci_host *host); ++int sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset); ++#endif ++ ++void sdhci_cqe_enable(struct mmc_host *mmc); ++void sdhci_cqe_disable(struct mmc_host *mmc, bool recovery); ++bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error, ++ int *data_error); ++ ++void sdhci_dumpregs(struct sdhci_host *host); ++void sdhci_enable_v4_mode(struct sdhci_host *host); ++ ++void sdhci_start_tuning(struct sdhci_host *host); ++void sdhci_end_tuning(struct sdhci_host *host); ++void sdhci_reset_tuning(struct sdhci_host *host); ++void sdhci_send_tuning(struct sdhci_host *host, u32 opcode); ++void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode); ++void sdhci_switch_external_dma(struct sdhci_host *host, bool en); ++void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable); ++void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd); ++ ++#endif /* __SDHCI_HW_H */ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/spi-bitbang-txrx.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/spi-bitbang-txrx.h +new file mode 100644 +index 000000000..47bb9b898 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/spi-bitbang-txrx.h +@@ -0,0 +1,107 @@ ++/* ++ * Mix this utility code with some glue code to get one of several types of ++ * simple SPI master driver. Two do polled word-at-a-time I/O: ++ * ++ * - GPIO/parport bitbangers. Provide chipselect() and txrx_word[](), ++ * expanding the per-word routines from the inline templates below. ++ * ++ * - Drivers for controllers resembling bare shift registers. Provide ++ * chipselect() and txrx_word[](), with custom setup()/cleanup() methods ++ * that use your controller's clock and chipselect registers. ++ * ++ * Some hardware works well with requests at spi_transfer scope: ++ * ++ * - Drivers leveraging smarter hardware, with fifos or DMA; or for half ++ * duplex (MicroWire) controllers. Provide chipselect() and txrx_bufs(), ++ * and custom setup()/cleanup() methods. ++ */ ++ ++/* ++ * The code that knows what GPIO pins do what should have declared four ++ * functions, ideally as inlines, before including this header: ++ * ++ * void setsck(struct spi_device *, int is_on); ++ * void setmosi(struct spi_device *, int is_on); ++ * int getmiso(struct spi_device *); ++ * void spidelay(unsigned); ++ * ++ * setsck()'s is_on parameter is a zero/nonzero boolean. ++ * ++ * setmosi()'s is_on parameter is a zero/nonzero boolean. ++ * ++ * getmiso() is required to return 0 or 1 only. Any other value is invalid ++ * and will result in improper operation. ++ * ++ * A non-inlined routine would call bitbang_txrx_*() routines. The ++ * main loop could easily compile down to a handful of instructions, ++ * especially if the delay is a NOP (to run at peak speed). ++ * ++ * Since this is software, the timings may not be exactly what your board's ++ * chips need ... there may be several reasons you'd need to tweak timings ++ * in these routines, not just to make it faster or slower to match a ++ * particular CPU clock rate. ++ */ ++ ++static inline u32 ++bitbang_txrx_be_cpha0(struct spi_device *spi, ++ unsigned nsecs, unsigned cpol, unsigned flags, ++ u32 word, u8 bits) ++{ ++ /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */ ++ ++ u32 oldbit = (!(word & (1<<(bits-1)))) << 31; ++ /* clock starts at inactive polarity */ ++ for (word <<= (32 - bits); likely(bits); bits--) { ++ ++ /* setup MSB (to slave) on trailing edge */ ++ if ((flags & SPI_MASTER_NO_TX) == 0) { ++ if ((word & (1 << 31)) != oldbit) { ++ setmosi(spi, word & (1 << 31)); ++ oldbit = word & (1 << 31); ++ } ++ } ++ spidelay(nsecs); /* T(setup) */ ++ ++ setsck(spi, !cpol); ++ spidelay(nsecs); ++ ++ /* sample MSB (from slave) on leading edge */ ++ word <<= 1; ++ if ((flags & SPI_MASTER_NO_RX) == 0) ++ word |= getmiso(spi); ++ setsck(spi, cpol); ++ } ++ return word; ++} ++ ++static inline u32 ++bitbang_txrx_be_cpha1(struct spi_device *spi, ++ unsigned nsecs, unsigned cpol, unsigned flags, ++ u32 word, u8 bits) ++{ ++ /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */ ++ ++ u32 oldbit = (!(word & (1<<(bits-1)))) << 31; ++ /* clock starts at inactive polarity */ ++ for (word <<= (32 - bits); likely(bits); bits--) { ++ ++ /* setup MSB (to slave) on leading edge */ ++ setsck(spi, !cpol); ++ if ((flags & SPI_MASTER_NO_TX) == 0) { ++ if ((word & (1 << 31)) != oldbit) { ++ setmosi(spi, word & (1 << 31)); ++ oldbit = word & (1 << 31); ++ } ++ } ++ spidelay(nsecs); /* T(setup) */ ++ ++ setsck(spi, cpol); ++ spidelay(nsecs); ++ ++ /* sample MSB (from slave) on trailing edge */ ++ word <<= 1; ++ if ((flags & SPI_MASTER_NO_RX) == 0) ++ word |= getmiso(spi); ++ } ++ return word; ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_eeprom_93xx46.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_eeprom_93xx46.c +new file mode 100644 +index 000000000..2ba7e7912 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_eeprom_93xx46.c +@@ -0,0 +1,558 @@ ++/* ++ * Driver for 93xx46 EEPROMs ++ * ++ * (C) 2011 DENX Software Engineering, Anatolij Gustschin ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++ ++#define OP_START 0x4 ++#define OP_WRITE (OP_START | 0x1) ++#define OP_READ (OP_START | 0x2) ++#define ADDR_EWDS 0x00 ++#define ADDR_ERAL 0x20 ++#define ADDR_EWEN 0x30 ++ ++static int g_wb_eeprom_93xx46_debug = 0; ++ ++module_param(g_wb_eeprom_93xx46_debug, int, S_IRUGO | S_IWUSR); ++ ++#define SPI_93xx46_DEBUG_VERBOSE(fmt, args...) do { \ ++ if (g_wb_eeprom_93xx46_debug) { \ ++ printk(KERN_INFO "[EEPROM-93xx46][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++struct eeprom_93xx46_devtype_data { ++ unsigned int quirks; ++}; ++ ++static const struct eeprom_93xx46_devtype_data atmel_at93c46d_data = { ++ .quirks = EEPROM_93XX46_QUIRK_SINGLE_WORD_READ | ++ EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH, ++}; ++ ++struct eeprom_93xx46_dev { ++ struct spi_device *spi; ++ struct eeprom_93xx46_platform_data *pdata; ++ struct mutex lock; ++ struct nvmem_config nvmem_config; ++ struct nvmem_device *nvmem; ++ int addrlen; ++ int size; ++}; ++ ++static inline bool has_quirk_single_word_read(struct eeprom_93xx46_dev *edev) ++{ ++ return edev->pdata->quirks & EEPROM_93XX46_QUIRK_SINGLE_WORD_READ; ++} ++ ++static inline bool has_quirk_instruction_length(struct eeprom_93xx46_dev *edev) ++{ ++ return edev->pdata->quirks & EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH; ++} ++ ++static int eeprom_93xx46_read(void *priv, unsigned int off, ++ void *val, size_t count) ++{ ++ struct eeprom_93xx46_dev *edev = priv; ++ char *buf = val; ++ int err = 0; ++ ++ if (unlikely(off >= edev->size)) ++ return 0; ++ if ((off + count) > edev->size) ++ count = edev->size - off; ++ if (unlikely(!count)) ++ return count; ++ ++ mutex_lock(&edev->lock); ++ ++ if (edev->pdata->prepare) ++ edev->pdata->prepare(edev); ++ ++ while (count) { ++ struct spi_message m; ++ struct spi_transfer t[2] = { { 0 } }; ++ u16 cmd_addr = OP_READ << edev->addrlen; ++ size_t nbytes = count; ++ int bits; ++ int data_bit; ++ ++ if (edev->addrlen == 7) { ++ cmd_addr |= off & 0x7f; ++ bits = 10; ++ data_bit = 8; ++ if (has_quirk_single_word_read(edev)) ++ nbytes = 1; ++ } else { ++ cmd_addr |= (off >> 1) & 0x3f; ++ bits = 9; ++ data_bit = 16; ++ if (has_quirk_single_word_read(edev)) ++ nbytes = 2; ++ } ++ ++ dev_dbg(&edev->spi->dev, "read cmd 0x%x, %d Hz\n", ++ cmd_addr, edev->spi->max_speed_hz); ++ ++ spi_message_init(&m); ++ ++ t[0].tx_buf = (char *)&cmd_addr; ++ t[0].len = 2; ++ t[0].bits_per_word = bits; ++ spi_message_add_tail(&t[0], &m); ++ ++ t[1].rx_buf = buf; ++ t[1].len = nbytes; ++ t[1].bits_per_word = data_bit; ++ spi_message_add_tail(&t[1], &m); ++ ++ err = spi_sync(edev->spi, &m); ++ /* have to wait at least Tcsl ns */ ++ ndelay(250); ++ ++ if (err) { ++ dev_err(&edev->spi->dev, "read %zu bytes at %d: err. %d\n", ++ nbytes, (int)off, err); ++ break; ++ } ++ ++ buf += nbytes; ++ off += nbytes; ++ count -= nbytes; ++ } ++ ++ if (edev->pdata->finish) ++ edev->pdata->finish(edev); ++ ++ mutex_unlock(&edev->lock); ++ ++ return err; ++} ++ ++static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on) ++{ ++ struct spi_message m; ++ struct spi_transfer t; ++ int bits, ret; ++ u16 cmd_addr; ++ ++ cmd_addr = OP_START << edev->addrlen; ++ if (edev->addrlen == 7) { ++ cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS) << 1; ++ bits = 10; ++ } else { ++ cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS); ++ bits = 9; ++ } ++ ++ if (has_quirk_instruction_length(edev)) { ++ cmd_addr <<= 2; ++ bits += 2; ++ } ++ ++ dev_dbg(&edev->spi->dev, "ew%s cmd 0x%04x, %d bits\n", ++ is_on ? "en" : "ds", cmd_addr, bits); ++ ++ spi_message_init(&m); ++ mem_clear(&t, sizeof(t)); ++ ++ t.tx_buf = &cmd_addr; ++ t.len = 2; ++ t.bits_per_word = bits; ++ spi_message_add_tail(&t, &m); ++ ++ mutex_lock(&edev->lock); ++ ++ if (edev->pdata->prepare) ++ edev->pdata->prepare(edev); ++ ++ ret = spi_sync(edev->spi, &m); ++ /* have to wait at least Tcsl ns */ ++ ndelay(250); ++ if (ret) ++ dev_err(&edev->spi->dev, "erase/write %sable error %d\n", ++ is_on ? "en" : "dis", ret); ++ ++ if (edev->pdata->finish) ++ edev->pdata->finish(edev); ++ ++ mutex_unlock(&edev->lock); ++ return ret; ++} ++ ++static ssize_t ++eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev, ++ char *buf, unsigned off) ++{ ++ struct spi_message m; ++ struct spi_transfer t[2]; ++ int bits, data_len, ret; ++ u16 cmd_addr; ++ int data_bit; ++ ++ cmd_addr = OP_WRITE << edev->addrlen; ++ ++ if (edev->addrlen == 7) { ++ cmd_addr |= off & 0x7f; ++ bits = 10; ++ data_len = 1; ++ data_bit = 8; ++ } else { ++ cmd_addr |= (off >> 1) & 0x3f; ++ bits = 9; ++ data_len = 2; ++ data_bit = 16; ++ } ++ ++ dev_dbg(&edev->spi->dev, "write cmd 0x%x\n", cmd_addr); ++ ++ spi_message_init(&m); ++ mem_clear(t, sizeof(t)); ++ ++ t[0].tx_buf = (char *)&cmd_addr; ++ t[0].len = 2; ++ t[0].bits_per_word = bits; ++ spi_message_add_tail(&t[0], &m); ++ ++ t[1].tx_buf = buf; ++ t[1].len = data_len; ++ t[1].bits_per_word = data_bit; ++ spi_message_add_tail(&t[1], &m); ++ ++ ret = spi_sync(edev->spi, &m); ++ /* have to wait program cycle time Twc ms */ ++ mdelay(6); ++ return ret; ++} ++ ++static int eeprom_93xx46_write(void *priv, unsigned int off, ++ void *val, size_t count) ++{ ++ struct eeprom_93xx46_dev *edev = priv; ++ char *buf = val; ++ int i, ret, step = 1; ++ ++ if (unlikely(off >= edev->size)) ++ return -EFBIG; ++ if ((off + count) > edev->size) ++ count = edev->size - off; ++ if (unlikely(!count)) ++ return count; ++ ++ /* only write even number of bytes on 16-bit devices */ ++ if (edev->addrlen == 6) { ++ step = 2; ++ count &= ~1; ++ } ++ ++ /* erase/write enable */ ++ ret = eeprom_93xx46_ew(edev, 1); ++ if (ret) ++ return ret; ++ ++ mutex_lock(&edev->lock); ++ ++ if (edev->pdata->prepare) ++ edev->pdata->prepare(edev); ++ ++ for (i = 0; i < count; i += step) { ++ ret = eeprom_93xx46_write_word(edev, &buf[i], off + i); ++ if (ret) { ++ dev_err(&edev->spi->dev, "write failed at %d: %d\n", ++ (int)off + i, ret); ++ break; ++ } ++ } ++ ++ if (edev->pdata->finish) ++ edev->pdata->finish(edev); ++ ++ mutex_unlock(&edev->lock); ++ ++ /* erase/write disable */ ++ eeprom_93xx46_ew(edev, 0); ++ return ret; ++} ++ ++static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev) ++{ ++ struct eeprom_93xx46_platform_data *pd = edev->pdata; ++ struct spi_message m; ++ struct spi_transfer t; ++ int bits, ret; ++ u16 cmd_addr; ++ ++ cmd_addr = OP_START << edev->addrlen; ++ if (edev->addrlen == 7) { ++ cmd_addr |= ADDR_ERAL << 1; ++ bits = 10; ++ } else { ++ cmd_addr |= ADDR_ERAL; ++ bits = 9; ++ } ++ ++ if (has_quirk_instruction_length(edev)) { ++ cmd_addr <<= 2; ++ bits += 2; ++ } ++ ++ dev_dbg(&edev->spi->dev, "eral cmd 0x%04x, %d bits\n", cmd_addr, bits); ++ ++ spi_message_init(&m); ++ mem_clear(&t, sizeof(t)); ++ ++ t.tx_buf = &cmd_addr; ++ t.len = 2; ++ t.bits_per_word = bits; ++ spi_message_add_tail(&t, &m); ++ ++ mutex_lock(&edev->lock); ++ ++ if (edev->pdata->prepare) ++ edev->pdata->prepare(edev); ++ ++ ret = spi_sync(edev->spi, &m); ++ if (ret) ++ dev_err(&edev->spi->dev, "erase error %d\n", ret); ++ /* have to wait erase cycle time Tec ms */ ++ mdelay(6); ++ ++ if (pd->finish) ++ pd->finish(edev); ++ ++ mutex_unlock(&edev->lock); ++ return ret; ++} ++ ++static ssize_t eeprom_93xx46_store_erase(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct eeprom_93xx46_dev *edev = dev_get_drvdata(dev); ++ int erase = 0, ret; ++ ++ sscanf(buf, "%d", &erase); ++ if (erase) { ++ ret = eeprom_93xx46_ew(edev, 1); ++ if (ret) ++ return ret; ++ ret = eeprom_93xx46_eral(edev); ++ if (ret) ++ return ret; ++ ret = eeprom_93xx46_ew(edev, 0); ++ if (ret) ++ return ret; ++ } ++ return count; ++} ++static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase); ++ ++static void select_assert(void *context) ++{ ++ struct eeprom_93xx46_dev *edev = context; ++ ++ gpiod_set_value_cansleep(edev->pdata->select, 1); ++} ++ ++static void select_deassert(void *context) ++{ ++ struct eeprom_93xx46_dev *edev = context; ++ ++ gpiod_set_value_cansleep(edev->pdata->select, 0); ++} ++ ++static const struct of_device_id eeprom_93xx46_of_table[] = { ++ { .compatible = "eeprom-93xx46", }, ++ { .compatible = "atmel,at93c46d", .data = &atmel_at93c46d_data, }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, eeprom_93xx46_of_table); ++ ++static int eeprom_93xx46_probe_dt(struct spi_device *spi) ++{ ++ const struct of_device_id *of_id = ++ of_match_device(eeprom_93xx46_of_table, &spi->dev); ++ struct device_node *np = spi->dev.of_node; ++ struct eeprom_93xx46_platform_data *pd; ++ u32 tmp; ++ int gpio; ++ enum of_gpio_flags of_flags; ++ int ret; ++ ++ pd = devm_kzalloc(&spi->dev, sizeof(*pd), GFP_KERNEL); ++ if (!pd) ++ return -ENOMEM; ++ ++ ret = of_property_read_u32(np, "data-size", &tmp); ++ if (ret < 0) { ++ dev_err(&spi->dev, "data-size property not found\n"); ++ return ret; ++ } ++ ++ if (tmp == 8) { ++ pd->flags |= EE_ADDR8; ++ } else if (tmp == 16) { ++ pd->flags |= EE_ADDR16; ++ } else { ++ dev_err(&spi->dev, "invalid data-size (%d)\n", tmp); ++ return -EINVAL; ++ } ++ ++ if (of_property_read_bool(np, "read-only")) ++ pd->flags |= EE_READONLY; ++ ++ gpio = of_get_named_gpio_flags(np, "select-gpios", 0, &of_flags); ++ if (gpio_is_valid(gpio)) { ++ unsigned long flags = ++ of_flags == OF_GPIO_ACTIVE_LOW ? GPIOF_ACTIVE_LOW : 0; ++ ++ ret = devm_gpio_request_one(&spi->dev, gpio, flags, ++ "eeprom_93xx46_select"); ++ if (ret) ++ return ret; ++ ++ pd->select = gpio_to_desc(gpio); ++ pd->prepare = select_assert; ++ pd->finish = select_deassert; ++ ++ gpiod_direction_output(pd->select, 0); ++ } ++ ++ if (of_id) { ++ if (of_id->data) { ++ const struct eeprom_93xx46_devtype_data *data = of_id->data; ++ ++ pd->quirks = data->quirks; ++ } ++ } ++ ++ spi->dev.platform_data = pd; ++ ++ return 0; ++} ++ ++static int eeprom_93xx46_probe(struct spi_device *spi) ++{ ++ struct eeprom_93xx46_platform_data *pd; ++ struct eeprom_93xx46_dev *edev; ++ int err; ++ ++ if (spi->dev.of_node) { ++ err = eeprom_93xx46_probe_dt(spi); ++ if (err < 0) ++ return err; ++ } ++ ++ pd = spi->dev.platform_data; ++ if (!pd) { ++ dev_err(&spi->dev, "missing platform data\n"); ++ return -ENODEV; ++ } ++ ++ edev = kzalloc(sizeof(*edev), GFP_KERNEL); ++ if (!edev) ++ return -ENOMEM; ++ ++ if (pd->flags & EE_ADDR8) ++ edev->addrlen = 7; ++ else if (pd->flags & EE_ADDR16) ++ edev->addrlen = 6; ++ else { ++ dev_err(&spi->dev, "unspecified address type\n"); ++ err = -EINVAL; ++ goto fail; ++ } ++ ++ mutex_init(&edev->lock); ++ ++ edev->spi = spi; ++ edev->pdata = pd; ++ ++ edev->size = 128; ++ edev->nvmem_config.name = dev_name(&spi->dev); ++ edev->nvmem_config.dev = &spi->dev; ++ edev->nvmem_config.read_only = pd->flags & EE_READONLY; ++ edev->nvmem_config.root_only = true; ++ edev->nvmem_config.owner = THIS_MODULE; ++ edev->nvmem_config.compat = true; ++ edev->nvmem_config.base_dev = &spi->dev; ++ edev->nvmem_config.reg_read = eeprom_93xx46_read; ++ edev->nvmem_config.reg_write = eeprom_93xx46_write; ++ edev->nvmem_config.priv = edev; ++ edev->nvmem_config.stride = 4; ++ edev->nvmem_config.word_size = 1; ++ edev->nvmem_config.size = edev->size; ++ ++ edev->nvmem = nvmem_register(&edev->nvmem_config); ++ if (IS_ERR(edev->nvmem)) { ++ err = PTR_ERR(edev->nvmem); ++ goto fail; ++ } ++ ++ if (g_wb_eeprom_93xx46_debug) { ++ dev_info(&spi->dev, "%d-bit eeprom %s\n", ++ (pd->flags & EE_ADDR8) ? 8 : 16, ++ (pd->flags & EE_READONLY) ? "(readonly)" : ""); ++ } ++ ++ if (!(pd->flags & EE_READONLY)) { ++ if (device_create_file(&spi->dev, &dev_attr_erase)) ++ dev_err(&spi->dev, "can't create erase interface\n"); ++ } ++ ++ spi_set_drvdata(spi, edev); ++ return 0; ++fail: ++ kfree(edev); ++ return err; ++} ++ ++static int eeprom_93xx46_remove(struct spi_device *spi) ++{ ++ struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi); ++ ++ nvmem_unregister(edev->nvmem); ++ ++ if (!(edev->pdata->flags & EE_READONLY)) ++ device_remove_file(&spi->dev, &dev_attr_erase); ++ ++ kfree(edev); ++ return 0; ++} ++ ++static struct spi_driver wb_eeprom_93xx46_driver = { ++ .driver = { ++ .name = "wb_93xx46", ++ .of_match_table = of_match_ptr(eeprom_93xx46_of_table), ++ }, ++ .probe = eeprom_93xx46_probe, ++ .remove = eeprom_93xx46_remove, ++}; ++ ++module_spi_driver(wb_eeprom_93xx46_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Driver for 93xx46 EEPROMs"); ++MODULE_AUTHOR("support"); ++MODULE_ALIAS("spi:93xx46"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_i2c_bus_drv.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_i2c_bus_drv.c +new file mode 100644 +index 000000000..3932cb26c +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_i2c_bus_drv.c +@@ -0,0 +1,1120 @@ ++/* ++ * fpga_i2c_bus_drv.c ++ * ko to create fpga i2c adapter ++ */ ++#include ++#include ++#include ++#include ++#include ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include "fpga_i2c.h" ++ ++#include ++#include ++ ++#define DRV_NAME "wb-fpga-i2c" ++#define DRV_VERSION "1.0" ++#define DTS_NO_CFG_FLAG (0) ++ ++extern int i2c_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); ++extern int i2c_device_func_read(const char *path, uint32_t pos, uint8_t *val, size_t size); ++extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int io_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); ++extern int io_device_func_read(const char *path, uint32_t pos, uint8_t *val, size_t size); ++extern int spi_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int spi_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++ ++#define FPGA_I2C_STRETCH_TIMEOUT (0x01) ++#define FPGA_I2C_DEADLOCK_FAILED (0x02) ++#define FPGA_I2C_SLAVE_NO_RESPOND (0x03) ++#define FPGA_I2C_STA_FAIL (0x01) ++#define FPGA_I2C_STA_BUSY (0x02) ++#define FPGA_I2C_CTL_BG (0x01 << 1) ++#define FPGA_I2C_CTL_NO_REG (0x01 << 2) ++#define FPGA_I2C_CTL_RD (0x01) ++#define FPGA_I2C_CTL_WR (0x00) ++#define I2C_READ_MSG_NUM (0x02) ++#define I2C_WRITE_MSG_NUM (0x01) ++#define FPGA_REG_WIDTH (4) ++ ++#define SYMBOL_I2C_DEV_MODE (1) ++#define FILE_MODE (2) ++#define SYMBOL_PCIE_DEV_MODE (3) ++#define SYMBOL_IO_DEV_MODE (4) ++#define SYMBOL_SPI_DEV_MODE (5) ++ ++int g_wb_fpga_i2c_debug = 0; ++int g_wb_fpga_i2c_error = 0; ++ ++module_param(g_wb_fpga_i2c_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_fpga_i2c_error, int, S_IRUGO | S_IWUSR); ++ ++#define FPGA_I2C_VERBOSE(fmt, args...) do { \ ++ if (g_wb_fpga_i2c_debug) { \ ++ printk(KERN_INFO "[FPFA_I2C_BUS][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define FPGA_I2C_ERROR(fmt, args...) do { \ ++ if (g_wb_fpga_i2c_error) { \ ++ printk(KERN_ERR "[FPFA_I2C_BUS][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static int fpga_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) ++{ ++ int ret; ++ struct file *filp; ++ loff_t tmp_pos; ++ ++ filp = filp_open(path, O_RDONLY, 0); ++ if (IS_ERR(filp)) { ++ FPGA_I2C_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); ++ filp = NULL; ++ goto exit; ++ } ++ ++ tmp_pos = (loff_t)pos; ++ ret = kernel_read(filp, val, size, &tmp_pos); ++ if (ret < 0) { ++ FPGA_I2C_ERROR("kernel_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); ++ goto exit; ++ } ++ ++ filp_close(filp, NULL); ++ ++ return ret; ++ ++exit: ++ if (filp != NULL) { ++ filp_close(filp, NULL); ++ } ++ ++ return -1; ++} ++ ++static int fpga_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) ++{ ++ int ret; ++ struct file *filp; ++ loff_t tmp_pos; ++ ++ filp = filp_open(path, O_RDWR, 777); ++ if (IS_ERR(filp)) { ++ FPGA_I2C_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); ++ filp = NULL; ++ goto exit; ++ } ++ ++ tmp_pos = (loff_t)pos; ++ ret = kernel_write(filp, val, size, &tmp_pos); ++ if (ret < 0) { ++ FPGA_I2C_ERROR("kernel_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); ++ goto exit; ++ } ++ vfs_fsync(filp, 1); ++ filp_close(filp, NULL); ++ ++ return ret; ++ ++exit: ++ if (filp != NULL) { ++ filp_close(filp, NULL); ++ } ++ ++ return -1; ++} ++ ++static int fpga_device_write(fpga_i2c_dev_t *fpga_i2c, uint32_t pos, uint8_t *val, size_t size) ++{ ++ int ret; ++ ++ switch (fpga_i2c->i2c_func_mode) { ++ case SYMBOL_I2C_DEV_MODE: ++ ret = i2c_device_func_write(fpga_i2c->dev_name, pos, val, size); ++ break; ++ case FILE_MODE: ++ ret = fpga_file_write(fpga_i2c->dev_name, pos, val, size); ++ break; ++ case SYMBOL_PCIE_DEV_MODE: ++ ret = pcie_device_func_write(fpga_i2c->dev_name, pos, val, size); ++ break; ++ case SYMBOL_IO_DEV_MODE: ++ ret = io_device_func_write(fpga_i2c->dev_name, pos, val, size); ++ break; ++ case SYMBOL_SPI_DEV_MODE: ++ ret = spi_device_func_write(fpga_i2c->dev_name, pos, val, size); ++ break; ++ default: ++ FPGA_I2C_ERROR("err func_mode %d, write failed.\n", fpga_i2c->i2c_func_mode); ++ return -EINVAL; ++ } ++ return ret; ++ ++} ++ ++static int fpga_device_read(fpga_i2c_dev_t *fpga_i2c, uint32_t pos, uint8_t *val, size_t size) ++{ ++ int ret; ++ ++ switch (fpga_i2c->i2c_func_mode) { ++ case SYMBOL_I2C_DEV_MODE: ++ ret = i2c_device_func_read(fpga_i2c->dev_name, pos, val, size); ++ break; ++ case FILE_MODE: ++ ret = fpga_file_read(fpga_i2c->dev_name, pos, val, size); ++ break; ++ case SYMBOL_PCIE_DEV_MODE: ++ ret = pcie_device_func_read(fpga_i2c->dev_name, pos, val, size); ++ break; ++ case SYMBOL_IO_DEV_MODE: ++ ret = io_device_func_read(fpga_i2c->dev_name, pos, val, size); ++ break; ++ case SYMBOL_SPI_DEV_MODE: ++ ret = spi_device_func_read(fpga_i2c->dev_name, pos, val, size); ++ break; ++ default: ++ FPGA_I2C_ERROR("err func_mode %d, read failed.\n", fpga_i2c->i2c_func_mode); ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int little_endian_dword_to_buf(uint8_t *buf, int len, uint32_t dword) ++{ ++ uint8_t tmp_buf[FPGA_REG_WIDTH]; ++ ++ if (len < 4) { ++ FPGA_I2C_ERROR("Not enough buf, dword to buf: len[%d], dword[0x%x]\n", len, dword); ++ return -1; ++ } ++ ++ mem_clear(tmp_buf, sizeof(tmp_buf)); ++ tmp_buf[0] = dword & 0xff; ++ tmp_buf[1] = (dword >> 8) & 0xff; ++ tmp_buf[2] = (dword >> 16) & 0xff; ++ tmp_buf[3] = (dword >> 24) & 0xff; ++ ++ memcpy(buf, tmp_buf, sizeof(tmp_buf)); ++ ++ return 0; ++} ++ ++static int little_endian_buf_to_dword(uint8_t *buf, int len, uint32_t *dword) ++{ ++ int i; ++ uint32_t dword_tmp; ++ ++ if (len != FPGA_REG_WIDTH) { ++ FPGA_I2C_ERROR("buf length %d error, can't convert to dowrd.\n", len); ++ return -1; ++ } ++ dword_tmp = 0; ++ for (i = 0; i < FPGA_REG_WIDTH; i++) { ++ dword_tmp |= (buf[i] << (i * 8)); ++ } ++ *dword = dword_tmp; ++ return 0; ++} ++ ++static int fpga_reg_write(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t val) ++{ ++ int ret; ++ ++ ret = fpga_device_write(fpga_i2c, addr, &val, sizeof(uint8_t)); ++ if (ret < 0) { ++ FPGA_I2C_ERROR("fpga reg write failed, dev name:%s, offset:0x%x, value:0x%x.\n", ++ fpga_i2c->dev_name, addr, val); ++ return -EIO; ++ } ++ ++ FPGA_I2C_VERBOSE("fpga reg write success, dev name:%s, offset:0x%x, value:0x%x.\n", ++ fpga_i2c->dev_name, addr, val); ++ return 0; ++} ++ ++static int fpga_reg_read(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t *val) ++{ ++ int ret; ++ ++ ret = fpga_device_read(fpga_i2c, addr, val, sizeof(uint8_t)); ++ if (ret < 0) { ++ FPGA_I2C_ERROR("fpga reg read failed, dev name:%s, offset:0x%x\n", ++ fpga_i2c->dev_name, addr); ++ return -EIO; ++ } ++ ++ FPGA_I2C_VERBOSE("fpga reg read success, dev name:%s, offset:0x%x, value:0x%x.\n", ++ fpga_i2c->dev_name, addr, *val); ++ return 0; ++} ++ ++static int fpga_data_write(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t *val, size_t size) ++{ ++ int ret; ++ ++ ret = fpga_device_write(fpga_i2c, addr, val, size); ++ if (ret < 0) { ++ FPGA_I2C_ERROR("fpga data write failed, dev name:%s, offset:0x%x, size:%lu.\n", ++ fpga_i2c->dev_name, addr, size); ++ return -EIO; ++ } ++ ++ FPGA_I2C_VERBOSE("fpga data write success, dev name:%s, offset:0x%x, size:%lu.\n", ++ fpga_i2c->dev_name, addr, size); ++ return 0; ++} ++ ++static int fpga_data_read(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t *val, size_t size) ++{ ++ int ret; ++ ++ ret = fpga_device_read(fpga_i2c, addr, val, size); ++ if (ret < 0) { ++ FPGA_I2C_ERROR("fpga data read failed, dev name:%s, offset:0x%x, size:%lu.\n", ++ fpga_i2c->dev_name, addr, size); ++ return -EIO; ++ } ++ ++ FPGA_I2C_VERBOSE("fpga data read success, dev name:%s, offset:0x%x, size:%lu.\n", ++ fpga_i2c->dev_name, addr, size); ++ return 0; ++} ++ ++static int fpga_reg_write_32(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint32_t val) ++{ ++ int ret; ++ uint8_t buf[FPGA_REG_WIDTH]; ++ ++ mem_clear(buf, sizeof(buf)); ++ little_endian_dword_to_buf(buf, sizeof(buf), val); ++ ret = fpga_device_write(fpga_i2c, addr, buf, sizeof(buf)); ++ if (ret < 0) { ++ FPGA_I2C_ERROR("fpga reg write failed, dev name: %s, offset: 0x%x, value: 0x%x.\n", ++ fpga_i2c->dev_name, addr, val); ++ return -EIO; ++ } ++ ++ FPGA_I2C_VERBOSE("fpga reg write success, dev name: %s, offset: 0x%x, value: 0x%x.\n", ++ fpga_i2c->dev_name, addr, val); ++ return 0; ++} ++ ++static int fpga_reg_read_32(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint32_t *val) ++{ ++ int ret; ++ uint8_t buf[FPGA_REG_WIDTH]; ++ ++ mem_clear(buf, sizeof(buf)); ++ ret = fpga_device_read(fpga_i2c, addr, buf, sizeof(buf)); ++ if (ret < 0) { ++ FPGA_I2C_ERROR("fpga reg read failed, dev name: %s, offset: 0x%x, ret: %d\n", ++ fpga_i2c->dev_name, addr, ret); ++ return -EIO; ++ } ++ little_endian_buf_to_dword(buf, sizeof(buf), val); ++ FPGA_I2C_VERBOSE("fpga reg read success, dev name: %s, offset: 0x%x, value: 0x%x.\n", ++ fpga_i2c->dev_name, addr, *val); ++ return 0; ++} ++ ++static int fpga_i2c_is_busy(fpga_i2c_dev_t *fpga_i2c) ++{ ++ uint8_t val; ++ int ret; ++ fpga_i2c_reg_t *reg; ++ ++ reg = &fpga_i2c->reg; ++ ret = fpga_reg_read(fpga_i2c, reg->i2c_status, &val); ++ if (ret < 0 ) { ++ FPGA_I2C_ERROR("read fpga i2c status reg failed, reg addr:0x%x, ret:%d.\n", ++ reg->i2c_status, ret); ++ return 1; ++ } ++ if (val & FPGA_I2C_STA_BUSY) { ++ FPGA_I2C_ERROR("fpga i2c status busy, reg addr:0x%x, value:0x%x.\n", ++ reg->i2c_status, val); ++ return 1; ++ } else { ++ return 0; ++ } ++} ++ ++static int fpga_i2c_wait(fpga_i2c_dev_t *fpga_i2c) ++{ ++ int retry_cnt; ++ ++ retry_cnt = FPGA_I2C_XFER_TIME_OUT/FPGA_I2C_SLEEP_TIME; ++ while (retry_cnt--) { ++ if (fpga_i2c_is_busy(fpga_i2c)) { ++ usleep_range(FPGA_I2C_SLEEP_TIME, FPGA_I2C_SLEEP_TIME + 1); ++ } else { ++ return 0; ++ } ++ } ++ ++ return -EBUSY; ++} ++ ++static int fpga_i2c_check_status(fpga_i2c_dev_t *fpga_i2c) ++{ ++ uint8_t data; ++ int ret; ++ fpga_i2c_reg_t *reg; ++ ++ reg = &fpga_i2c->reg; ++ ++ ret = fpga_reg_read(fpga_i2c, reg->i2c_status, &data); ++ if (ret) { ++ FPGA_I2C_ERROR("read fpga i2c status reg failed, reg addr:0x%x, ret:%d.\n", ++ reg->i2c_status, ret); ++ return ret; ++ } ++ ++ if (data & FPGA_I2C_STA_FAIL) { ++ FPGA_I2C_ERROR("fpga i2c status error, reg addr:0x%x, value:%d.\n", ++ reg->i2c_status, data); ++ ++ /* read i2c_err_vec to confirm err type*/ ++ if (reg->i2c_err_vec != DTS_NO_CFG_FLAG) { ++ /* read i2c_err_vec reg */ ++ ret = fpga_reg_read(fpga_i2c, reg->i2c_err_vec, &data); ++ if (ret) { ++ FPGA_I2C_ERROR("read fpga i2c err vec reg failed, reg addr:0x%x, ret:%d.\n", ++ reg->i2c_err_vec, ret); ++ return ret; ++ } ++ FPGA_I2C_VERBOSE("get i2c err vec, reg addr:0x%x, read value:0x%x\n", reg->i2c_err_vec, data); ++ ++ /* match i2c_err_vec reg value and err type*/ ++ switch (data) { ++ case FPGA_I2C_STRETCH_TIMEOUT: ++ ret = -ETIMEDOUT; ++ break; ++ case FPGA_I2C_DEADLOCK_FAILED: ++ ret = -EDEADLK; ++ break; ++ case FPGA_I2C_SLAVE_NO_RESPOND: ++ ret = -ENXIO; ++ break; ++ default: ++ FPGA_I2C_ERROR("get i2c err vec value out of range, reg addr:0x%x, read value:0x%x\n", ++ reg->i2c_err_vec, data); ++ ret = -EREMOTEIO; ++ break; ++ } ++ return ret; ++ } else { ++ FPGA_I2C_VERBOSE("i2c err vec not config, fpga i2c status check return -1\n"); ++ return -EREMOTEIO; ++ } ++ } ++ return 0; ++} ++ ++static int fpga_i2c_do_work(fpga_i2c_dev_t *fpga_i2c, int i2c_addr, ++ unsigned char *data, uint32_t length, int is_read) ++{ ++ int ret, i; ++ uint8_t op, i2c_reg_addr_len; ++ uint8_t *i2c_read_addr_buf; ++ fpga_i2c_reg_t *reg; ++ fpga_i2c_reg_addr_t *i2c_addr_desc; ++ ++ reg = &fpga_i2c->reg; ++ ++ ret = fpga_reg_write(fpga_i2c, reg->i2c_slave, i2c_addr); ++ if (ret) { ++ FPGA_I2C_ERROR("write fpga i2c slave reg failed, reg addr:0x%x, value:0x%x, ret:%d.\n", ++ reg->i2c_slave, i2c_addr, ret); ++ goto exit; ++ } ++ ++ i2c_addr_desc = &fpga_i2c->i2c_addr_desc; ++ i2c_reg_addr_len = i2c_addr_desc->reg_addr_len; ++ i2c_read_addr_buf = &i2c_addr_desc->read_reg_addr[0]; ++ ++ if (i2c_reg_addr_len > 0 && i2c_reg_addr_len <= I2C_REG_MAX_WIDTH) { ++ ret = fpga_data_write(fpga_i2c, reg->i2c_reg, i2c_read_addr_buf, i2c_reg_addr_len); ++ if (ret) { ++ FPGA_I2C_ERROR("write fpga i2c offset reg failed, fpga addr:0x%x, reg len:%d, ret:%d\n", ++ reg->i2c_reg, i2c_reg_addr_len, ret); ++ for (i = 0; i < i2c_reg_addr_len; i++) { ++ FPGA_I2C_ERROR("%02d : %02x\n", i, i2c_read_addr_buf[i]); ++ } ++ goto exit; ++ } ++ } ++ ++ ret = fpga_reg_write_32(fpga_i2c, reg->i2c_data_len, length); ++ if (ret) { ++ FPGA_I2C_ERROR("write fpga i2c date len reg failed, reg addr:0x%x, value:0x%x, ret:%d.\n", ++ reg->i2c_data_len, length, ret); ++ goto exit; ++ } ++ ++ ret = fpga_reg_write(fpga_i2c, reg->i2c_reg_len, i2c_reg_addr_len); ++ if (ret) { ++ FPGA_I2C_ERROR("write fpga i2c reg len reg failed, reg addr:0x%x, value:0x%x, ret:%d.\n", ++ reg->i2c_reg_len, i2c_reg_addr_len, ret); ++ goto exit; ++ } ++ ++ if (is_read) { ++ op = FPGA_I2C_CTL_RD | FPGA_I2C_CTL_BG; ++ } else { ++ ++ ret = fpga_data_write(fpga_i2c, reg->i2c_data_buf, data, length); ++ if (ret) { ++ FPGA_I2C_ERROR("write fpga i2c date buf failed, reg addr:0x%x, write len:%d, ret:%d.\n", ++ reg->i2c_data_buf, length, ret); ++ goto exit; ++ } ++ op = FPGA_I2C_CTL_WR | FPGA_I2C_CTL_BG ; ++ } ++ ++ ret = fpga_reg_write(fpga_i2c, reg->i2c_ctrl, op); ++ if (ret) { ++ FPGA_I2C_ERROR("write fpga i2c control reg failed, reg addr:0x%x, value:%d, ret:%d.\n", ++ reg->i2c_ctrl, op, ret); ++ goto exit; ++ } ++ ++ ret = fpga_i2c_wait(fpga_i2c); ++ if (ret) { ++ FPGA_I2C_ERROR("wait fpga i2c status timeout.\n"); ++ goto exit; ++ } ++ ++ ret = fpga_i2c_check_status(fpga_i2c); ++ if (ret) { ++ FPGA_I2C_ERROR("check fpga i2c status error.\n"); ++ goto exit; ++ } ++ ++ if (is_read) { ++ ++ ret = fpga_data_read(fpga_i2c, reg->i2c_data_buf, data, length); ++ if (ret) { ++ FPGA_I2C_ERROR("read fpga i2c data buf failed, reg addr:0x%x, read len:%d, ret:%d.\n", ++ reg->i2c_data_buf, length, ret); ++ goto exit; ++ } ++ } ++ ++exit: ++ return ret; ++} ++ ++static int fpga_i2c_write(fpga_i2c_dev_t *fpga_i2c, int target, ++ u8 *data, int length, int i2c_msg_num) ++{ ++ int ret, i; ++ fpga_i2c_reg_addr_t *i2c_addr_desc; ++ ++ if (i2c_msg_num == I2C_READ_MSG_NUM) { ++ ++ if (length > I2C_REG_MAX_WIDTH) { ++ FPGA_I2C_ERROR("read reg addr len %d, more than max length.\n", length); ++ return -EINVAL; ++ } ++ ++ i2c_addr_desc = &fpga_i2c->i2c_addr_desc; ++ for (i = 0; i < length; i++) { ++ i2c_addr_desc->read_reg_addr[i] = data[length -i -1]; ++ FPGA_I2C_VERBOSE("%02d : %02x\n", i, i2c_addr_desc->read_reg_addr[i]); ++ } ++ i2c_addr_desc->reg_addr_len = length; ++ ret = 0; ++ } else { ++ ++ ret = fpga_i2c_do_work(fpga_i2c, target, data, length, 0); ++ } ++ ++ return ret; ++} ++ ++/** ++ * fpga_i2c_read - receive data from the bus. ++ * @i2c: The struct fpga_i2c_dev_t. ++ * @target: Target address. ++ * @data: Pointer to the location to store the datae . ++ * @length: Length of the data. ++ * ++ * The address is sent over the bus, then the data is read. ++ * ++ * Returns 0 on success, otherwise a negative errno. ++ */ ++static int fpga_i2c_read(fpga_i2c_dev_t *fpga_i2c, int target, ++ u8 *data, int length) ++{ ++ int ret, offset_size; ++ int i, tmp_val; ++ fpga_i2c_reg_addr_t *i2c_addr_desc; ++ uint8_t i2c_reg_addr_len; ++ uint8_t *i2c_read_addr_buf; ++ ++ offset_size = 0; ++ i2c_addr_desc = &fpga_i2c->i2c_addr_desc; ++ i2c_reg_addr_len = i2c_addr_desc->reg_addr_len; ++ i2c_read_addr_buf = &i2c_addr_desc->read_reg_addr[0]; ++ ++ while (1) { ++ if (length <= fpga_i2c->reg.i2c_data_buf_len) { ++ return fpga_i2c_do_work(fpga_i2c, target, data + offset_size, length, 1); ++ } ++ ++ ret = fpga_i2c_do_work(fpga_i2c, target, data + offset_size, fpga_i2c->reg.i2c_data_buf_len, 1); ++ if (ret != 0) { ++ FPGA_I2C_ERROR("fpga_i2c_read failed, i2c addr:0x%x, offset:0x%x, ret:%d.\n", ++ target, offset_size, ret); ++ return ret; ++ } ++ ++ tmp_val = i2c_read_addr_buf[0]; ++ tmp_val += fpga_i2c->reg.i2c_data_buf_len; ++ if (tmp_val > 0xff) { ++ i2c_read_addr_buf[0] = tmp_val & 0xff; ++ for (i = 1; i < i2c_reg_addr_len; i++) { ++ if (i2c_read_addr_buf[i] == 0xff) { ++ i2c_read_addr_buf[i] = 0; ++ } else { ++ i2c_read_addr_buf[i]++; ++ break; ++ } ++ } ++ } else { ++ i2c_read_addr_buf[0] = tmp_val & 0xff; ++ } ++ offset_size += fpga_i2c->reg.i2c_data_buf_len; ++ length -= fpga_i2c->reg.i2c_data_buf_len; ++ } ++ ++ return ret; ++} ++ ++static void fpga_i2c_reset(fpga_i2c_dev_t *fpga_i2c) { ++ fpga_i2c_reset_cfg_t *reset_cfg; ++ uint32_t reset_addr; ++ ++ reset_cfg = &fpga_i2c->reset_cfg; ++ reset_addr = reset_cfg->reset_addr; ++ if (reset_cfg->reset_delay_b) { ++ usleep_range(reset_cfg->reset_delay_b, reset_cfg->reset_delay_b + 1); ++ } ++ ++ fpga_reg_write_32(fpga_i2c, reset_addr, reset_cfg->reset_on); ++ if (reset_cfg->reset_delay) { ++ usleep_range(reset_cfg->reset_delay, reset_cfg->reset_delay + 1); ++ } ++ ++ fpga_reg_write_32(fpga_i2c, reset_addr, reset_cfg->reset_off); ++ if (reset_cfg->reset_delay_a) { ++ usleep_range(reset_cfg->reset_delay_a, reset_cfg->reset_delay_a + 1); ++ } ++ ++ return; ++} ++ ++/** ++ * fpga_i2c_xfer - The driver's master_xfer function. ++ * @adap: Pointer to the i2c_adapter structure. ++ * @msgs: Pointer to the messages to be processed. ++ * @num: Length of the MSGS array. ++ * ++ * Returns the number of messages processed, or a negative errno on ++ * failure. ++ */ ++static int fpga_i2c_adapter_init(fpga_i2c_dev_t *fpga_i2c) ++{ ++ int ret; ++ fpga_i2c_reg_t *reg; ++ ++ reg = &fpga_i2c->reg; ++ ++ ret = 0; ++ ret += fpga_reg_write(fpga_i2c, reg->i2c_scale, fpga_i2c->i2c_scale_value); ++ ret += fpga_reg_write(fpga_i2c, reg->i2c_filter, fpga_i2c->i2c_filter_value); ++ ret += fpga_reg_write(fpga_i2c, reg->i2c_stretch, fpga_i2c->i2c_stretch_value); ++ if (ret < 0) { ++ FPGA_I2C_ERROR("fpga_i2c_init failed.\n"); ++ return ret; ++ } ++ ++ FPGA_I2C_VERBOSE("fpga_i2c_init ok.\n"); ++ return 0; ++} ++ ++static int fpga_i2c_params_check(fpga_i2c_dev_t *fpga_i2c) ++{ ++ int ret; ++ fpga_i2c_reg_t *reg; ++ uint8_t i2c_scale_value, i2c_filter_value, i2c_stretch_value; ++ ++ reg = &fpga_i2c->reg; ++ ret = 0; ++ ret += fpga_reg_read(fpga_i2c, reg->i2c_scale, &i2c_scale_value); ++ ret += fpga_reg_read(fpga_i2c, reg->i2c_filter, &i2c_filter_value); ++ ret += fpga_reg_read(fpga_i2c, reg->i2c_stretch, &i2c_stretch_value); ++ if (ret < 0) { ++ FPGA_I2C_ERROR("read fpga i2c params failed.\n"); ++ return 1; ++ } ++ ++ if ((i2c_scale_value != fpga_i2c->i2c_scale_value) ++ || (i2c_filter_value != fpga_i2c->i2c_filter_value) ++ || (i2c_stretch_value != fpga_i2c->i2c_stretch_value)) { ++ FPGA_I2C_ERROR("fpga i2c params check error, read value: i2c_scale 0x%x, i2c_filter:0x%x, i2c_stretch:0x%x.\n", ++ i2c_scale_value, i2c_filter_value, i2c_stretch_value); ++ FPGA_I2C_ERROR("fpga i2c params check error, config value: i2c_scale 0x%x, i2c_filter:0x%x, i2c_stretch:0x%x.\n", ++ fpga_i2c->i2c_scale_value, fpga_i2c->i2c_filter_value, fpga_i2c->i2c_stretch_value); ++ return 1; ++ } ++ ++ FPGA_I2C_VERBOSE("fpga i2c params check ok.\n"); ++ return 0; ++} ++ ++static int fpga_i2c_xfer(struct i2c_adapter *adap, ++ struct i2c_msg *msgs, int num) ++{ ++ struct i2c_msg *pmsg; ++ int i; ++ int ret; ++ fpga_i2c_dev_t *fpga_i2c; ++ fpga_i2c_reg_addr_t *i2c_addr_desc; ++ ++ fpga_i2c = i2c_get_adapdata(adap); ++ ++ if (num != I2C_READ_MSG_NUM && num != I2C_WRITE_MSG_NUM) { ++ FPGA_I2C_ERROR("unsupport i2c_msg len:%d.\n", num); ++ return -EINVAL; ++ } ++ ++ if ((num == I2C_WRITE_MSG_NUM) && (msgs[0].len > fpga_i2c->reg.i2c_data_buf_len)) { ++ FPGA_I2C_ERROR("unsupport i2c_msg type:msg[0].flag:0x%x, buf len:0x%x.\n", ++ msgs[0].flags, msgs[0].len); ++ return -EINVAL; ++ } ++ ++ if (num == I2C_READ_MSG_NUM ) { ++ if ((msgs[0].flags & I2C_M_RD) ||!(msgs[1].flags & I2C_M_RD)) { ++ FPGA_I2C_ERROR("unsupport i2c_msg type:msg[0].flag:0x%x, msg[1].flag:0x%x.\n", ++ msgs[0].flags, msgs[1].flags); ++ return -EINVAL; ++ } ++ } ++ ++ if (fpga_i2c_is_busy(fpga_i2c)) { ++ FPGA_I2C_ERROR("fpga i2c adapter %d is busy, do reset.\n", adap->nr); ++ if (fpga_i2c->reset_cfg.i2c_adap_reset_flag == 1) { ++ ++ fpga_i2c_reset(fpga_i2c); ++ ++ fpga_i2c_adapter_init(fpga_i2c); ++ } ++ return -EAGAIN; ++ } ++ ++ if (fpga_i2c->i2c_params_check && fpga_i2c_params_check(fpga_i2c)) { ++ FPGA_I2C_ERROR("fpga i2c params check failed, try to reinitialize.\n"); ++ fpga_i2c_adapter_init(fpga_i2c); ++ } ++ ++ ret = 0; ++ i2c_addr_desc = &fpga_i2c->i2c_addr_desc; ++ i2c_addr_desc->reg_addr_len = 0; ++ mem_clear(i2c_addr_desc->read_reg_addr, sizeof(i2c_addr_desc->read_reg_addr)); ++ ++ for (i = 0; ret == 0 && i < num; i++) { ++ pmsg = &msgs[i]; ++ FPGA_I2C_VERBOSE("Doing %s %d byte(s) to/from 0x%02x - %d of %d messages\n", ++ pmsg->flags & I2C_M_RD ? "read" : "write", pmsg->len, pmsg->addr, i + 1, num); ++ ++ if (pmsg->flags & I2C_M_RD) { ++ ret = fpga_i2c_read(fpga_i2c, pmsg->addr, pmsg->buf, pmsg->len); ++ ++ if ((pmsg->len == 1) && (pmsg->flags & I2C_M_RECV_LEN)) { ++ if ((ret != 0) || (pmsg->buf[0] > I2C_SMBUS_BLOCK_MAX)) { ++ FPGA_I2C_ERROR("smbus block data read failed, ret:%d, read len:%u.\n", ++ ret, pmsg->buf[0]); ++ return -EPROTO; ++ } ++ pmsg->len = 1 + pmsg->buf[0]; ++ FPGA_I2C_VERBOSE("smbus block data read, read len:%d.\n", pmsg->len); ++ ret = fpga_i2c_read(fpga_i2c, pmsg->addr, pmsg->buf, pmsg->len); ++ } ++ } else { ++ ret = fpga_i2c_write(fpga_i2c, pmsg->addr, pmsg->buf, pmsg->len, num); ++ } ++ } ++ ++ return (ret != 0) ? ret : num; ++} ++ ++static u32 fpga_i2c_functionality(struct i2c_adapter *adap) ++{ ++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; ++} ++ ++static const struct i2c_algorithm fpga_i2c_algo = { ++ .master_xfer = fpga_i2c_xfer, ++ .functionality = fpga_i2c_functionality, ++}; ++ ++static struct i2c_adapter fpga_i2c_ops = { ++ .owner = THIS_MODULE, ++ .name = "wb_fpga_i2c", ++ .algo = &fpga_i2c_algo, ++}; ++ ++static int fpga_i2c_config_init(fpga_i2c_dev_t *fpga_i2c) ++{ ++ int ret = 0, rv = 0; ++ fpga_i2c_reg_t *reg; ++ fpga_i2c_reset_cfg_t *reset_cfg; ++ struct device *dev; ++ uint32_t i2c_offset_reg, i2c_data_buf_len_reg; ++ int32_t i2c_offset_val; ++ ++ fpga_i2c_bus_device_t *fpga_i2c_bus_device; ++ ++ dev = fpga_i2c->dev; ++ reg = &fpga_i2c->reg; ++ reset_cfg = &fpga_i2c->reset_cfg; ++ ++ i2c_offset_val = 0; ++ ++ if (dev->of_node) { ++ ret = 0; ++ ret += of_property_read_u32(dev->of_node, "i2c_ext_9548_addr", ®->i2c_ext_9548_addr); ++ ret += of_property_read_u32(dev->of_node, "i2c_ext_9548_chan", ®->i2c_ext_9548_chan); ++ ret += of_property_read_u32(dev->of_node, "i2c_slave", ®->i2c_slave); ++ ret += of_property_read_u32(dev->of_node, "i2c_reg", ®->i2c_reg); ++ ret += of_property_read_u32(dev->of_node, "i2c_data_len", ®->i2c_data_len); ++ ret += of_property_read_u32(dev->of_node, "i2c_ctrl", ®->i2c_ctrl); ++ ret += of_property_read_u32(dev->of_node, "i2c_status", ®->i2c_status); ++ ret += of_property_read_u32(dev->of_node, "i2c_scale", ®->i2c_scale); ++ ret += of_property_read_u32(dev->of_node, "i2c_filter", ®->i2c_filter); ++ ret += of_property_read_u32(dev->of_node, "i2c_stretch", ®->i2c_stretch); ++ ret += of_property_read_u32(dev->of_node, "i2c_ext_9548_exits_flag", ®->i2c_ext_9548_exits_flag); ++ ret += of_property_read_u32(dev->of_node, "i2c_reg_len", ®->i2c_reg_len); ++ ret += of_property_read_u32(dev->of_node, "i2c_in_9548_chan", ®->i2c_in_9548_chan); ++ ret += of_property_read_u32(dev->of_node, "i2c_data_buf", ®->i2c_data_buf); ++ ret += of_property_read_string(dev->of_node, "dev_name", &fpga_i2c->dev_name); ++ ret += of_property_read_u32(dev->of_node, "i2c_scale_value", &fpga_i2c->i2c_scale_value); ++ ret += of_property_read_u32(dev->of_node, "i2c_filter_value", &fpga_i2c->i2c_filter_value); ++ ret += of_property_read_u32(dev->of_node, "i2c_stretch_value", &fpga_i2c->i2c_stretch_value); ++ ret += of_property_read_u32(dev->of_node, "i2c_timeout", &fpga_i2c->i2c_timeout); ++ ret += of_property_read_u32(dev->of_node, "i2c_func_mode", &fpga_i2c->i2c_func_mode); ++ ret += of_property_read_u32(dev->of_node, "i2c_reset_addr", &reset_cfg->reset_addr); ++ ret += of_property_read_u32(dev->of_node, "i2c_reset_on", &reset_cfg->reset_on); ++ ret += of_property_read_u32(dev->of_node, "i2c_reset_off", &reset_cfg->reset_off); ++ ret += of_property_read_u32(dev->of_node, "i2c_rst_delay_b", &reset_cfg->reset_delay_b); ++ ret += of_property_read_u32(dev->of_node, "i2c_rst_delay", &reset_cfg->reset_delay); ++ ret += of_property_read_u32(dev->of_node, "i2c_rst_delay_a", &reset_cfg->reset_delay_a); ++ ret += of_property_read_u32(dev->of_node, "i2c_adap_reset_flag", &reset_cfg->i2c_adap_reset_flag); ++ ++ if (ret != 0) { ++ FPGA_I2C_ERROR("dts config error, ret:%d.\n", ret); ++ ret = -ENXIO; ++ return ret; ++ } ++ ++ rv = of_property_read_u32(dev->of_node, "i2c_data_buf_len_reg", &i2c_data_buf_len_reg); ++ if (rv == 0) { ++ ret = fpga_reg_read_32(fpga_i2c, i2c_data_buf_len_reg, ®->i2c_data_buf_len); ++ if (ret < 0) { ++ dev_err(fpga_i2c->dev, "Failed to get fpga i2c data buf length, reg addr: 0x%x, ret: %d\n", ++ i2c_data_buf_len_reg, ret); ++ return ret; ++ } ++ FPGA_I2C_VERBOSE("fpga i2c data buf length reg addr: 0x%x, value: %d\n", ++ i2c_data_buf_len_reg, reg->i2c_data_buf_len); ++ if (reg->i2c_data_buf_len == 0) { ++ reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; ++ } ++ } else { ++ ret = of_property_read_u32(dev->of_node, "i2c_data_buf_len", ®->i2c_data_buf_len); ++ if (ret != 0) { ++ reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; ++ ret = 0; ++ } ++ } ++ ++ rv = of_property_read_u32(dev->of_node, "i2c_offset_reg", &i2c_offset_reg); ++ if (rv == 0) { ++ ret = fpga_reg_read_32(fpga_i2c, i2c_offset_reg, &i2c_offset_val); ++ if (ret < 0) { ++ dev_err(fpga_i2c->dev, "Failed to get fpga i2c adapter offset value, reg addr: 0x%x, ret: %d\n", ++ i2c_offset_reg, ret); ++ return ret; ++ } ++ FPGA_I2C_VERBOSE("fpga i2c adapter offset reg addr: 0x%x, value: %d\n", ++ i2c_offset_reg, i2c_offset_val); ++ reg->i2c_scale +=i2c_offset_val; ++ reg->i2c_filter += i2c_offset_val; ++ reg->i2c_stretch += i2c_offset_val; ++ reg->i2c_ext_9548_exits_flag += i2c_offset_val; ++ reg->i2c_ext_9548_addr += i2c_offset_val; ++ reg->i2c_ext_9548_chan += i2c_offset_val; ++ reg->i2c_in_9548_chan += i2c_offset_val; ++ reg->i2c_slave += i2c_offset_val; ++ reg->i2c_reg += i2c_offset_val; ++ reg->i2c_reg_len += i2c_offset_val; ++ reg->i2c_data_len += i2c_offset_val; ++ reg->i2c_ctrl += i2c_offset_val; ++ reg->i2c_status += i2c_offset_val; ++ reg->i2c_data_buf += i2c_offset_val; ++ } ++ ++ ret = of_property_read_u32(dev->of_node, "i2c_err_vec", ®->i2c_err_vec); ++ if (ret != 0) { ++ reg->i2c_err_vec = DTS_NO_CFG_FLAG; ++ FPGA_I2C_VERBOSE("not support i2c_err_vec cfg. ret: %d, set DTS_NO_CFG_FLAG: %d\n", ++ ret, reg->i2c_err_vec); ++ ret = 0; /* Not configuring i2c_err_vec is not an error */ ++ } else { ++ if (i2c_offset_val != 0) { ++ reg->i2c_err_vec += i2c_offset_val; ++ } ++ } ++ } else { ++ if (dev->platform_data == NULL) { ++ dev_err(fpga_i2c->dev, "Failed to get platform data config.\n"); ++ ret = -ENXIO; ++ return ret; ++ } ++ fpga_i2c_bus_device = dev->platform_data; ++ fpga_i2c->dev_name = fpga_i2c_bus_device->dev_name; ++ fpga_i2c->adap_nr = fpga_i2c_bus_device->adap_nr; ++ fpga_i2c->i2c_scale_value = fpga_i2c_bus_device->i2c_scale_value; ++ fpga_i2c->i2c_filter_value = fpga_i2c_bus_device->i2c_filter_value; ++ fpga_i2c->i2c_stretch_value = fpga_i2c_bus_device->i2c_stretch_value; ++ fpga_i2c->i2c_timeout = fpga_i2c_bus_device->i2c_timeout; ++ fpga_i2c->i2c_func_mode = fpga_i2c_bus_device->i2c_func_mode; ++ fpga_i2c->i2c_params_check = fpga_i2c_bus_device->i2c_params_check; ++ ++ reset_cfg->reset_addr = fpga_i2c_bus_device->i2c_reset_addr; ++ reset_cfg->reset_on = fpga_i2c_bus_device->i2c_reset_on; ++ reset_cfg->reset_off = fpga_i2c_bus_device->i2c_reset_off; ++ reset_cfg->reset_delay_b = fpga_i2c_bus_device->i2c_rst_delay_b; ++ reset_cfg->reset_delay = fpga_i2c_bus_device->i2c_rst_delay; ++ reset_cfg->reset_delay_a = fpga_i2c_bus_device->i2c_rst_delay_a; ++ reset_cfg->i2c_adap_reset_flag = fpga_i2c_bus_device->i2c_adap_reset_flag; ++ ++ reg->i2c_ext_9548_addr = fpga_i2c_bus_device->i2c_ext_9548_addr; ++ reg->i2c_ext_9548_chan = fpga_i2c_bus_device->i2c_ext_9548_chan; ++ reg->i2c_slave = fpga_i2c_bus_device->i2c_slave; ++ reg->i2c_reg = fpga_i2c_bus_device->i2c_reg; ++ reg->i2c_data_len = fpga_i2c_bus_device->i2c_data_len; ++ reg->i2c_ctrl = fpga_i2c_bus_device->i2c_ctrl; ++ reg->i2c_status = fpga_i2c_bus_device->i2c_status; ++ reg->i2c_scale = fpga_i2c_bus_device->i2c_scale; ++ reg->i2c_filter = fpga_i2c_bus_device->i2c_filter; ++ reg->i2c_stretch = fpga_i2c_bus_device->i2c_stretch; ++ reg->i2c_ext_9548_exits_flag = fpga_i2c_bus_device->i2c_ext_9548_exits_flag; ++ reg->i2c_reg_len = fpga_i2c_bus_device->i2c_reg_len; ++ reg->i2c_in_9548_chan = fpga_i2c_bus_device->i2c_in_9548_chan; ++ reg->i2c_data_buf = fpga_i2c_bus_device->i2c_data_buf; ++ ++ i2c_data_buf_len_reg = fpga_i2c_bus_device->i2c_data_buf_len_reg; ++ if (i2c_data_buf_len_reg > 0) { ++ ret = fpga_reg_read_32(fpga_i2c, i2c_data_buf_len_reg, ®->i2c_data_buf_len); ++ if (ret < 0) { ++ dev_err(fpga_i2c->dev, "Failed to get fpga i2c data buf length, reg addr: 0x%x, ret: %d\n", ++ i2c_data_buf_len_reg, ret); ++ return ret; ++ } ++ FPGA_I2C_VERBOSE("fpga i2c data buf length reg addr: 0x%x, value: %d\n", ++ i2c_data_buf_len_reg, reg->i2c_data_buf_len); ++ if (reg->i2c_data_buf_len == 0) { ++ reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; ++ } ++ } else { ++ if (fpga_i2c_bus_device->i2c_data_buf_len == 0) { ++ reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; ++ FPGA_I2C_VERBOSE("not support i2c_data_buf_len cfg, set default_val:%d\n", ++ reg->i2c_data_buf_len); ++ } else { ++ reg->i2c_data_buf_len = fpga_i2c_bus_device->i2c_data_buf_len; ++ } ++ } ++ ++ i2c_offset_reg = fpga_i2c_bus_device->i2c_offset_reg; ++ if (i2c_offset_reg > 0) { ++ rv = fpga_reg_read_32(fpga_i2c, i2c_offset_reg, &i2c_offset_val); ++ if (rv < 0) { ++ dev_err(fpga_i2c->dev, "Failed to get fpga i2c adapter offset value, reg addr: 0x%x, rv: %d\n", ++ i2c_offset_reg, rv); ++ return rv; ++ } ++ FPGA_I2C_VERBOSE("fpga i2c adapter offset reg addr: 0x%x, value: %d\n", ++ i2c_offset_reg, i2c_offset_val); ++ reg->i2c_scale +=i2c_offset_val; ++ reg->i2c_filter += i2c_offset_val; ++ reg->i2c_stretch += i2c_offset_val; ++ reg->i2c_ext_9548_exits_flag += i2c_offset_val; ++ reg->i2c_ext_9548_addr += i2c_offset_val; ++ reg->i2c_ext_9548_chan += i2c_offset_val; ++ reg->i2c_in_9548_chan += i2c_offset_val; ++ reg->i2c_slave += i2c_offset_val; ++ reg->i2c_reg += i2c_offset_val; ++ reg->i2c_reg_len += i2c_offset_val; ++ reg->i2c_data_len += i2c_offset_val; ++ reg->i2c_ctrl += i2c_offset_val; ++ reg->i2c_status += i2c_offset_val; ++ reg->i2c_data_buf += i2c_offset_val; ++ } ++ ++ if (fpga_i2c_bus_device->i2c_err_vec == 0) { ++ reg->i2c_err_vec = DTS_NO_CFG_FLAG; ++ FPGA_I2C_VERBOSE("not support i2c_err_vec cfg, set DTS_NO_CFG_FLAG:%d\n", ++ reg->i2c_err_vec); ++ } else { ++ reg->i2c_err_vec = fpga_i2c_bus_device->i2c_err_vec; ++ if (i2c_offset_val != 0) { ++ reg->i2c_err_vec += i2c_offset_val; ++ } ++ } ++ } ++ ++ FPGA_I2C_VERBOSE("i2c_ext_9548_addr:0x%x, i2c_ext_9548_chan:0x%x, i2c_slave:0x%x, i2c_reg:0x%x, i2c_data_len:0x%x.\n", ++ reg->i2c_ext_9548_addr, reg->i2c_ext_9548_chan, reg->i2c_slave, reg->i2c_reg, reg->i2c_data_len); ++ FPGA_I2C_VERBOSE("i2c_ctrl:0x%x, i2c_status:0x%x, i2c_scale:0x%x, i2c_filter:0x%x, i2c_stretch:0x%x.\n", ++ reg->i2c_ctrl, reg->i2c_status, reg->i2c_scale, reg->i2c_filter, reg->i2c_stretch); ++ FPGA_I2C_VERBOSE("i2c_ext_9548_exits_flag:0x%x, i2c_in_9548_chan:0x%x, i2c_data_buf:0x%x, i2c_reg_len:0x%x, i2c_data_buf_len:0x%x.\n", ++ reg->i2c_ext_9548_exits_flag, reg->i2c_in_9548_chan, reg->i2c_data_buf, reg->i2c_reg_len, reg->i2c_data_buf_len); ++ FPGA_I2C_VERBOSE("dev_name:%s, i2c_scale_value:0x%x, i2c_filter_value:0x%x, i2c_stretch_value:0x%x, i2c_timeout:0x%x.\n", ++ fpga_i2c->dev_name, fpga_i2c->i2c_scale_value, fpga_i2c->i2c_filter_value, fpga_i2c->i2c_stretch_value, fpga_i2c->i2c_timeout); ++ FPGA_I2C_VERBOSE("i2c_reset_addr:0x%x, i2c_reset_on:0x%x, i2c_reset_off:0x%x, i2c_rst_delay_b:0x%x, i2c_rst_delay:0x%x, i2c_rst_delay_a:0x%x.\n", ++ reset_cfg->reset_addr, reset_cfg->reset_on, reset_cfg->reset_off, reset_cfg->reset_delay_b, reset_cfg->reset_delay, reset_cfg->reset_delay_a); ++ FPGA_I2C_VERBOSE("i2c_adap_reset_flag:0x%x.\n", reset_cfg->i2c_adap_reset_flag); ++ FPGA_I2C_VERBOSE("i2c_err_vec:0x%x\n", reg->i2c_err_vec); ++ ++ return ret; ++} ++ ++static int fpga_i2c_probe(struct platform_device *pdev) ++{ ++ int ret; ++ fpga_i2c_dev_t *fpga_i2c; ++ struct device *dev; ++ ++ fpga_i2c = devm_kzalloc(&pdev->dev, sizeof(fpga_i2c_dev_t), GFP_KERNEL); ++ if (!fpga_i2c) { ++ dev_err(&pdev->dev, "devm_kzalloc failed.\n"); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ fpga_i2c->dev = &pdev->dev; ++ ++ ret = fpga_i2c_config_init(fpga_i2c); ++ if (ret !=0) { ++ dev_err(fpga_i2c->dev, "Failed to get fpga i2c dts config.\n"); ++ goto out; ++ } ++ ++ ret = fpga_i2c_adapter_init(fpga_i2c); ++ if (ret !=0) { ++ dev_err(fpga_i2c->dev, "Failed to init fpga i2c adapter.\n"); ++ goto out; ++ } ++ ++ if (fpga_i2c->dev->of_node) { ++ fpga_i2c->i2c_params_check = of_property_read_bool(fpga_i2c->dev->of_node, "i2c_params_check"); ++ } ++ FPGA_I2C_VERBOSE("fpga i2c params check flag:%d.\n", fpga_i2c->i2c_params_check); ++ ++ init_waitqueue_head(&fpga_i2c->queue); ++ ++ dev = fpga_i2c->dev; ++ fpga_i2c->adap = fpga_i2c_ops; ++ fpga_i2c->adap.timeout = msecs_to_jiffies(fpga_i2c->i2c_timeout); ++ fpga_i2c->adap.dev.parent = &pdev->dev; ++ fpga_i2c->adap.dev.of_node = pdev->dev.of_node; ++ i2c_set_adapdata(&fpga_i2c->adap, fpga_i2c); ++ platform_set_drvdata(pdev, fpga_i2c); ++ ++ if (fpga_i2c->dev->of_node) { ++ /* adap.nr get from dts aliases */ ++ ret = i2c_add_adapter(&fpga_i2c->adap); ++ } else { ++ fpga_i2c->adap.nr = fpga_i2c->adap_nr; ++ ret = i2c_add_numbered_adapter(&fpga_i2c->adap); ++ } ++ ++ if (ret < 0) { ++ dev_info(fpga_i2c->dev, "Failed to add adapter.\n"); ++ goto fail_add; ++ } ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) ++ of_i2c_register_devices(&fpga_i2c->adap); ++#endif ++ dev_info(fpga_i2c->dev, "registered i2c-%d for %s using mode %d with base address:0x%x, data buf len: %d success.\n", ++ fpga_i2c->adap.nr, fpga_i2c->dev_name, fpga_i2c->i2c_func_mode, fpga_i2c->reg.i2c_scale, ++ fpga_i2c->reg.i2c_data_buf_len); ++ return 0; ++ ++fail_add: ++ platform_set_drvdata(pdev, NULL); ++out: ++ return ret; ++}; ++ ++static int fpga_i2c_remove(struct platform_device *pdev) ++{ ++ fpga_i2c_dev_t *fpga_i2c; ++ ++ fpga_i2c = platform_get_drvdata(pdev); ++ i2c_del_adapter(&fpga_i2c->adap); ++ platform_set_drvdata(pdev, NULL); ++ return 0; ++}; ++ ++static struct of_device_id fpga_i2c_match[] = { ++ { ++ .compatible = "wb-fpga-i2c", ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, fpga_i2c_match); ++ ++static struct platform_driver wb_fpga_i2c_driver = { ++ .probe = fpga_i2c_probe, ++ .remove = fpga_i2c_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = DRV_NAME, ++ .of_match_table = fpga_i2c_match, ++ }, ++}; ++ ++static int __init wb_fpga_i2c_init(void) ++{ ++ return platform_driver_register(&wb_fpga_i2c_driver); ++} ++ ++static void __exit wb_fpga_i2c_exit(void) ++{ ++ platform_driver_unregister(&wb_fpga_i2c_driver); ++} ++ ++module_init(wb_fpga_i2c_init); ++module_exit(wb_fpga_i2c_exit); ++MODULE_DESCRIPTION("fpga i2c adapter driver"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pca954x_drv.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pca954x_drv.c +new file mode 100644 +index 000000000..8fd9e4f0f +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pca954x_drv.c +@@ -0,0 +1,534 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "fpga_i2c.h" ++ ++extern int i2c_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); ++extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int io_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); ++extern int spi_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++ ++#define PCA954X_MAX_NCHANS (8) ++#define FPGA_INTERNAL_PCA9548 (1) ++#define FPGA_EXTERNAL_PCA9548 (2) ++#define FPGA_I2C_EXT_9548_EXITS (0x01 << 0) ++#define FPGA_I2C_9548_NO_RESET (0x01 << 1) ++ ++#define SYMBOL_I2C_DEV_MODE (1) ++#define FILE_MODE (2) ++#define SYMBOL_PCIE_DEV_MODE (3) ++#define SYMBOL_IO_DEV_MODE (4) ++#define SYMBOL_SPI_DEV_MODE (5) ++ ++int g_fpga_pca954x_debug = 0; ++int g_fpga_pca954x_error = 0; ++ ++module_param(g_fpga_pca954x_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_fpga_pca954x_error, int, S_IRUGO | S_IWUSR); ++ ++#define FPGA_PCA954X_VERBOSE(fmt, args...) do { \ ++ if (g_fpga_pca954x_debug) { \ ++ printk(KERN_INFO "[FPGA_PCA954X][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define FPGA_PCA954X_ERROR(fmt, args...) do { \ ++ if (g_fpga_pca954x_error) { \ ++ printk(KERN_ERR "[FPGA_PCA954X][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++enum pca_type { ++ pca_9540, ++ pca_9541, ++ pca_9542, ++ pca_9543, ++ pca_9544, ++ pca_9545, ++ pca_9546, ++ pca_9547, ++ pca_9548, ++}; ++ ++struct pca954x { ++ enum pca_type type; ++ struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS]; ++ u8 last_chan; /* last register value */ ++ uint32_t fpga_9548_flag; ++ uint32_t fpga_9548_reset_flag; ++ uint32_t pca9548_base_nr; ++ struct i2c_client *client; ++}; ++ ++struct chip_desc { ++ u8 nchans; ++ u8 enable; /* used for muxes only */ ++ enum muxtype { ++ pca954x_ismux = 0, ++ pca954x_isswi ++ } muxtype; ++}; ++ ++/* Provide specs for the PCA954x types we know about */ ++static const struct chip_desc chips[] = { ++ [pca_9540] = { ++ .nchans = 2, ++ .enable = 0x4, ++ .muxtype = pca954x_ismux, ++ }, ++ [pca_9541] = { ++ .nchans = 1, ++ .muxtype = pca954x_isswi, ++ }, ++ [pca_9543] = { ++ .nchans = 2, ++ .muxtype = pca954x_isswi, ++ }, ++ [pca_9544] = { ++ .nchans = 4, ++ .enable = 0x4, ++ .muxtype = pca954x_ismux, ++ }, ++ [pca_9545] = { ++ .nchans = 4, ++ .muxtype = pca954x_isswi, ++ }, ++ [pca_9547] = { ++ .nchans = 8, ++ .enable = 0x8, ++ .muxtype = pca954x_ismux, ++ }, ++ [pca_9548] = { ++ .nchans = 8, ++ .muxtype = pca954x_isswi, ++ }, ++}; ++ ++static const struct i2c_device_id fpga_pca954x_id[] = { ++ { "wb_fpga_pca9540", pca_9540 }, ++ { "wb_fpga_pca9541", pca_9541 }, ++ { "wb_fpga_pca9542", pca_9543 }, ++ { "wb_fpga_pca9543", pca_9543 }, ++ { "wb_fpga_pca9544", pca_9544 }, ++ { "wb_fpga_pca9545", pca_9545 }, ++ { "wb_fpga_pca9546", pca_9545 }, ++ { "wb_fpga_pca9547", pca_9547 }, ++ { "wb_fpga_pca9548", pca_9548 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, fpga_pca954x_id); ++ ++static int fpga_file_write(const char *path, int pos, unsigned char *val, size_t size) ++{ ++ int ret; ++ struct file *filp; ++ loff_t tmp_pos; ++ ++ filp = filp_open(path, O_RDWR, 777); ++ if (IS_ERR(filp)) { ++ FPGA_PCA954X_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); ++ filp = NULL; ++ goto exit; ++ } ++ ++ tmp_pos = (loff_t)pos; ++ ret = kernel_write(filp, val, size, &tmp_pos); ++ if (ret < 0) { ++ FPGA_PCA954X_ERROR("kernel_write failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); ++ goto exit; ++ } ++ ++ vfs_fsync(filp, 1); ++ filp_close(filp, NULL); ++ ++ return ret; ++ ++exit: ++ if (filp != NULL) { ++ filp_close(filp, NULL); ++ } ++ ++ return -1; ++ ++} ++ ++static int fpga_device_write(fpga_i2c_dev_t *fpga_i2c, int pos, unsigned char *val, size_t size) ++{ ++ int ret; ++ ++ switch (fpga_i2c->i2c_func_mode) { ++ case SYMBOL_I2C_DEV_MODE: ++ ret = i2c_device_func_write(fpga_i2c->dev_name, pos, val, size); ++ break; ++ case FILE_MODE: ++ ret = fpga_file_write(fpga_i2c->dev_name, pos, val, size); ++ break; ++ case SYMBOL_PCIE_DEV_MODE: ++ ret = pcie_device_func_write(fpga_i2c->dev_name, pos, val, size); ++ break; ++ case SYMBOL_IO_DEV_MODE: ++ ret = io_device_func_write(fpga_i2c->dev_name, pos, val, size); ++ break; ++ case SYMBOL_SPI_DEV_MODE: ++ ret = spi_device_func_write(fpga_i2c->dev_name, pos, val, size); ++ break; ++ default: ++ FPGA_PCA954X_ERROR("err func_mode %d, write failed.\n", fpga_i2c->i2c_func_mode); ++ return -EINVAL; ++ } ++ return ret; ++} ++ ++static int fpga_reg_write(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t val) ++{ ++ int ret; ++ ++ ret = fpga_device_write(fpga_i2c, addr, &val, sizeof(uint8_t)); ++ if (ret < 0) { ++ FPGA_PCA954X_ERROR("fpga_device_write failed. name:%s, addr:0x%x, value:0x%x.\n", ++ fpga_i2c->dev_name, addr, val); ++ return ret; ++ } ++ ++ FPGA_PCA954X_VERBOSE("fpga reg write success, dev name:%s, offset:0x%x, value:0x%x.\n", ++ fpga_i2c->dev_name, addr, val); ++ return 0; ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,7) ++static int pca954x_select_chan(struct i2c_adapter *adap, void *client, u32 chan) ++{ ++ struct pca954x *data = i2c_get_clientdata(client); ++ fpga_i2c_dev_t *fpga_i2c; ++ fpga_i2c_reg_t *reg; ++ int ret; ++ u8 regval, i2c_9548_opt; ++ ++ while(i2c_parent_is_i2c_adapter(adap)){ ++ adap = to_i2c_adapter(adap->dev.parent); ++ } ++ ++ FPGA_PCA954X_VERBOSE("root bus:%d, chan:0x%x, 9548 flag:0x%x, 9548 addr:0x%x.\n", ++ adap->nr, chan, data->fpga_9548_flag, client->addr); ++ fpga_i2c = i2c_get_adapdata(adap); ++ reg = &fpga_i2c->reg; ++ ++ regval = 1 << chan; ++ if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { ++ ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, regval); ++ } else { ++ if (data->fpga_9548_reset_flag == 1) { ++ i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS & ~(FPGA_I2C_9548_NO_RESET); ++ } else { ++ i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS | FPGA_I2C_9548_NO_RESET; ++ } ++ FPGA_PCA954X_VERBOSE("fpga pca9548 reset flag:0x%x, opt:0x%x.\n", ++ data->fpga_9548_reset_flag, i2c_9548_opt); ++ ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, i2c_9548_opt); ++ ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_addr, client->addr); ++ ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, regval); ++ } ++ ++ return ret; ++} ++ ++static int pca954x_deselect_mux(struct i2c_adapter *adap, void *client, u32 chan) ++{ ++ struct pca954x *data = i2c_get_clientdata(client); ++ fpga_i2c_dev_t *fpga_i2c; ++ fpga_i2c_reg_t *reg; ++ int ret; ++ ++ while(i2c_parent_is_i2c_adapter(adap)){ ++ adap = to_i2c_adapter(adap->dev.parent); ++ } ++ ++ fpga_i2c = i2c_get_adapdata(adap); ++ reg = &fpga_i2c->reg; ++ /* Deselect active channel */ ++ data->last_chan = 0; ++ if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { ++ ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, 0); ++ } else { ++ ++ ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, FPGA_I2C_9548_NO_RESET); ++ ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, 0); ++ } ++ ++ return ret; ++} ++#else ++static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) ++{ ++ struct pca954x *data = i2c_mux_priv(muxc); ++ struct i2c_client *client = data->client; ++ struct i2c_adapter *adap; ++ fpga_i2c_dev_t *fpga_i2c; ++ fpga_i2c_reg_t *reg; ++ int ret; ++ u8 regval, i2c_9548_opt; ++ ++ adap = muxc->parent; ++ while(i2c_parent_is_i2c_adapter(adap)){ ++ adap = to_i2c_adapter(adap->dev.parent); ++ } ++ ++ FPGA_PCA954X_VERBOSE("root bus:%d, chan:0x%x, 9548 flag:0x%x, 9548 addr:0x%x.\n", ++ adap->nr, chan, data->fpga_9548_flag, client->addr); ++ fpga_i2c = i2c_get_adapdata(adap); ++ reg = &fpga_i2c->reg; ++ ++ regval = 1 << chan; ++ if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { ++ ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, regval); ++ } else { ++ if (data->fpga_9548_reset_flag == 1) { ++ i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS & ~(FPGA_I2C_9548_NO_RESET); ++ } else { ++ i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS | FPGA_I2C_9548_NO_RESET; ++ } ++ FPGA_PCA954X_VERBOSE("fpga pca9548 reset flag:0x%x, opt:0x%x.\n", ++ data->fpga_9548_reset_flag, i2c_9548_opt); ++ ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, i2c_9548_opt); ++ ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_addr, client->addr); ++ ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, regval); ++ } ++ ++ return ret; ++} ++ ++static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan) ++{ ++ struct pca954x *data = i2c_mux_priv(muxc); ++ struct i2c_adapter *adap; ++ fpga_i2c_dev_t *fpga_i2c; ++ fpga_i2c_reg_t *reg; ++ int ret; ++ ++ adap = muxc->parent; ++ while(i2c_parent_is_i2c_adapter(adap)){ ++ adap = to_i2c_adapter(adap->dev.parent); ++ } ++ ++ fpga_i2c = i2c_get_adapdata(adap); ++ reg = &fpga_i2c->reg; ++ ret = 0; ++ /* Deselect active channel */ ++ data->last_chan = 0; ++ ++ if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { ++ ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, 0); ++ } else { ++ ++ ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, FPGA_I2C_9548_NO_RESET); ++ ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, 0); ++ } ++ ++ return ret; ++} ++#endif ++/* ++ * I2C init/probing/exit functions ++ */ ++static int fpga_i2c_pca954x_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); ++ int num, force, class; ++ struct pca954x *data; ++ int ret = -ENODEV; ++ struct device *dev; ++ int dynamic_nr = 1; ++ fpga_pca954x_device_t *fpga_pca954x_device; ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(4,6,7) ++ struct i2c_mux_core *muxc; ++#endif ++ ++ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) { ++ dev_err(&client->dev, "i2c adapter:%d, unsupport I2C_FUNC_SMBUS_BYTE.\n", adap->nr); ++ goto err; ++ } ++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) ++ data = kzalloc(sizeof(struct pca954x), GFP_KERNEL); ++ if (!data) { ++ dev_err(&client->dev, "kzalloc failed.\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ i2c_set_clientdata(client, data); ++#else ++ muxc = i2c_mux_alloc(adap, &client->dev, ++ PCA954X_MAX_NCHANS, sizeof(*data), 0, ++ pca954x_select_chan, pca954x_deselect_mux); ++ if (!muxc) { ++ dev_err(&client->dev, "i2c_mux_alloc failed.\n"); ++ return -ENOMEM; ++ } ++ data = i2c_mux_priv(muxc); ++ i2c_set_clientdata(client, muxc); ++ data->client = client; ++#endif ++ ++ dev = &client->dev; ++ if (dev == NULL) { ++ dev_err(&client->dev, "dev is NULL.\n"); ++ ret = -ENODEV; ++ goto exit_free; ++ } ++ ++ if (dev->of_node == NULL) { ++ if (client->dev.platform_data == NULL) { ++ dev_err(&client->dev, "Failed to get 954x platform data config.\n"); ++ ret = -EINVAL; ++ goto exit_free; ++ } ++ fpga_pca954x_device = client->dev.platform_data; ++ data->fpga_9548_flag = fpga_pca954x_device->fpga_9548_flag; ++ data->fpga_9548_reset_flag = fpga_pca954x_device->fpga_9548_reset_flag; ++ data->pca9548_base_nr = fpga_pca954x_device->pca9548_base_nr; ++ if (data->pca9548_base_nr == 0) { ++ ++ dynamic_nr = 1; ++ } else { ++ dynamic_nr = 0; ++ FPGA_PCA954X_VERBOSE("pca9548_base_nr:%u.\n", data->pca9548_base_nr); ++ } ++ } else { ++ data->type = id->driver_data; ++ /* BUS ID */ ++ ret = of_property_read_u32(dev->of_node, "fpga_9548_flag", &data->fpga_9548_flag); ++ ret += of_property_read_u32(dev->of_node, "fpga_9548_reset_flag", &data->fpga_9548_reset_flag); ++ if (ret != 0) { ++ dev_err(&client->dev, "Failed to get 954x dts config, ret:%d.\n", ret); ++ ret = -EINVAL; ++ goto exit_free; ++ } ++ if (of_property_read_u32(dev->of_node, "pca9548_base_nr", &data->pca9548_base_nr)) { ++ ++ dynamic_nr = 1; ++ FPGA_PCA954X_VERBOSE("pca9548_base_nr not found, use dynamic adap number"); ++ } else { ++ dynamic_nr = 0; ++ FPGA_PCA954X_VERBOSE("pca9548_base_nr:%u.\n", data->pca9548_base_nr); ++ } ++ } ++ ++ if (data->fpga_9548_flag != FPGA_EXTERNAL_PCA9548 && data->fpga_9548_flag != FPGA_INTERNAL_PCA9548) { ++ dev_err(&client->dev, "Error: fpga 954x flag config error, value:0x%x.\n", data->fpga_9548_flag); ++ ret = -EINVAL; ++ goto exit_free; ++ } ++ ++ data->type = id->driver_data; ++ data->last_chan = 0; /* force the first selection */ ++ ++ /* Now create an adapter for each channel */ ++ for (num = 0; num < chips[data->type].nchans; num++) { ++ if (dynamic_nr == 1) { ++ force = 0; /* dynamic adap number */ ++ } else { ++ force = data->pca9548_base_nr + num; ++ } ++ class = 0; /* no class by default */ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) ++ data->virt_adaps[num] = ++ i2c_add_mux_adapter(adap, &client->dev, client, ++ force, num, class, pca954x_select_chan, pca954x_deselect_mux); ++ ++ if (data->virt_adaps[num] == NULL) { ++ ret = -ENODEV; ++ dev_err(&client->dev, "Failed to register multiplexed adapter %d as bus %d\n", ++ num, force); ++ goto virt_reg_failed; ++ } ++#else ++ ret = i2c_mux_add_adapter(muxc, force, num, class); ++ if (ret) { ++ dev_err(&client->dev, "Failed to register multiplexed adapter %d as bus %d\n", ++ num, force); ++ goto virt_reg_failed; ++ } ++#endif ++ } /* end for num = 0; num < chips[data->type].nchans... */ ++ ++ dev_info(&client->dev, "registered %d multiplexed busses for I2C %s %s\n", ++ num, chips[data->type].muxtype == pca954x_ismux ? "mux" : "switch", client->name); ++ ++ return 0; ++ ++virt_reg_failed: ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) ++ for (num--; num >= 0; num--) ++ i2c_del_mux_adapter(data->virt_adaps[num]); ++exit_free: ++ kfree(data); ++#else ++exit_free: ++ i2c_mux_del_adapters(muxc); ++#endif ++err: ++ return ret; ++} ++ ++static int fpga_i2c_pca954x_remove(struct i2c_client *client) ++{ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) ++ struct pca954x *data = i2c_get_clientdata(client); ++ const struct chip_desc *chip = &chips[data->type]; ++ int i; ++ ++ for (i = 0; i < chip->nchans; ++i) ++ if (data->virt_adaps[i]) { ++ i2c_del_mux_adapter(data->virt_adaps[i]); ++ data->virt_adaps[i] = NULL; ++ } ++ ++ kfree(data); ++#else ++ struct i2c_mux_core *muxc = i2c_get_clientdata(client); ++ ++ i2c_mux_del_adapters(muxc); ++#endif ++ ++ return 0; ++} ++ ++static struct i2c_driver fpga_i2c_pca954x_driver = { ++ .driver = { ++ .name = "wb_fpga_pca954x", ++ .owner = THIS_MODULE, ++ }, ++ .probe = fpga_i2c_pca954x_probe, ++ .remove = fpga_i2c_pca954x_remove, ++ .id_table = fpga_pca954x_id, ++}; ++ ++static int __init fpga_i2c_pca954x_init(void) ++{ ++ int ret; ++ ++ ret = i2c_add_driver(&fpga_i2c_pca954x_driver); ++ return ret; ++} ++ ++static void __exit fpga_i2c_pca954x_exit(void) ++{ ++ i2c_del_driver(&fpga_i2c_pca954x_driver); ++} ++ ++module_init(fpga_i2c_pca954x_init); ++module_exit(fpga_i2c_pca954x_exit); ++MODULE_DESCRIPTION("fpga pca954x driver"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pcie.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pcie.c +new file mode 100644 +index 000000000..aedcc78da +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pcie.c +@@ -0,0 +1,164 @@ ++/* ++ * wb_fpga_pcie.c ++ * ko to enable fpga pcie ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#define FPGA_MSI_IRQ_NUM (14) ++#define FPGA_MSI_IRQ_BEGIN (0) ++#define XILINX_FPGA_USE_MSI (0) ++#define XILINX_FPGA_NUSE_MSI (1) ++ ++int g_fpga_pcie_dev_debug = 0; ++int g_fpga_pcie_dev_error = 0; ++module_param(g_fpga_pcie_dev_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_fpga_pcie_dev_error, int, S_IRUGO | S_IWUSR); ++ ++#define FPGA_PCIE_DEV_VERBOSE(fmt, args...) do { \ ++ if (g_fpga_pcie_dev_debug) { \ ++ printk(KERN_INFO "[FPGA_PCIE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define FPGA_PCIE_DEV_ERROR(fmt, args...) do { \ ++ if (g_fpga_pcie_dev_error) { \ ++ printk(KERN_ERR "[FPGA_PCIE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++typedef struct wb_fpga_pcie_s { ++ struct pci_dev *pci_dev; ++ int driver_data; ++} wb_fpga_pcie_t; ++ ++static void fpga_pcie_recover(struct pci_dev *pdev, const struct pci_device_id *id) ++{ ++ struct resource *mem_base; ++ u32 bar0_val; ++ int ret; ++ ++ mem_base = &pdev->resource[0]; ++ ret = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0_val); ++ if (ret) { ++ FPGA_PCIE_DEV_ERROR("pci_read_config_dword failed ret %d.\n", ret); ++ return; ++ } ++ FPGA_PCIE_DEV_VERBOSE("mem_base->start[0x%llx], bar0_val[0x%x], ret %d.\n", ++ mem_base->start, bar0_val, ret); ++ ++ if (bar0_val != mem_base->start) { ++ ret = pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, mem_base->start); ++ if (ret) { ++ FPGA_PCIE_DEV_ERROR("pci_write_config_dword mem_base->start[0x%llx], failed ret %d.\n", mem_base->start, ret); ++ return; ++ } ++ FPGA_PCIE_DEV_VERBOSE("pci_write_config_dword mem_base->start[0x%llx] success.\n", mem_base->start); ++ } else { ++ FPGA_PCIE_DEV_VERBOSE("mem_base->start[0x%llx], bar0_val[0x%x], do nothing.\n", ++ mem_base->start, bar0_val); ++ } ++} ++ ++static int fpga_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) ++{ ++ int err; ++ wb_fpga_pcie_t *wb_fpga_pcie; ++ ++ FPGA_PCIE_DEV_VERBOSE("Enter vendor 0x%x, subsystem_vendor 0x%x.\n", pdev->vendor, pdev->subsystem_vendor); ++ ++ wb_fpga_pcie = devm_kzalloc(&pdev->dev, sizeof(wb_fpga_pcie_t), GFP_KERNEL); ++ if (!wb_fpga_pcie) { ++ dev_err(&pdev->dev, "devm_kzalloc failed.\n"); ++ return -ENOMEM; ++ } ++ ++ fpga_pcie_recover(pdev, id); ++ ++ /* enable device: ask low-level code to enable I/O and memory */ ++ FPGA_PCIE_DEV_VERBOSE("start pci_enable_device!\n"); ++ err = pci_enable_device(pdev); ++ if (err) { ++ dev_err(&pdev->dev, "Failed to enable pci device, ret:%d.\n", err); ++ return err; ++ } ++ ++ FPGA_PCIE_DEV_VERBOSE("start pci_set_master!\n"); ++ pci_set_master(pdev); ++ ++ wb_fpga_pcie->driver_data = id->driver_data; ++ wb_fpga_pcie->pci_dev = pdev; ++ pci_set_drvdata(pdev, wb_fpga_pcie); ++ ++ if (wb_fpga_pcie->driver_data == XILINX_FPGA_USE_MSI) { ++ FPGA_PCIE_DEV_VERBOSE("start pci_enable_msi_range!\n"); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,152) ++ err = pci_enable_msi_range(pdev, FPGA_MSI_IRQ_BEGIN + 1, FPGA_MSI_IRQ_NUM); ++#else ++ err = pci_alloc_irq_vectors_affinity(pdev, FPGA_MSI_IRQ_BEGIN + 1, ++ FPGA_MSI_IRQ_NUM, PCI_IRQ_MSI, NULL); ++#endif ++ if (err != FPGA_MSI_IRQ_NUM) { ++ FPGA_PCIE_DEV_ERROR("pci_enable_msi_block err %d FPGA_MSI_IRQ_NUM %d.\n", err, ++ FPGA_MSI_IRQ_NUM); ++ dev_err(&pdev->dev, "Failed to enable pci msi, ret:%d.\n", err); ++ return -EINVAL; ++ } ++ } ++ ++ dev_info(&pdev->dev, "fpga pci device init success.\n"); ++ return 0; ++} ++ ++static void fpga_pcie_remove(struct pci_dev *pdev) ++{ ++ wb_fpga_pcie_t *wb_fpga_pcie; ++ ++ FPGA_PCIE_DEV_VERBOSE("fpga_pcie_remove.\n"); ++ ++ wb_fpga_pcie = pci_get_drvdata(pdev); ++ if (wb_fpga_pcie->driver_data == XILINX_FPGA_USE_MSI) { ++ FPGA_PCIE_DEV_VERBOSE("start pci_disable_msi!\n"); ++ pci_disable_msi(pdev); ++ } ++ ++ pci_disable_device(pdev); ++ return; ++} ++ ++static const struct pci_device_id fpga_pci_ids[] = { ++ { PCI_DEVICE(0x10ee, 0x7022), .driver_data = XILINX_FPGA_USE_MSI}, ++ { PCI_DEVICE(0x10ee, 0x7011), .driver_data = XILINX_FPGA_NUSE_MSI}, ++ {0} ++}; ++MODULE_DEVICE_TABLE(pci, fpga_pci_ids); ++ ++static struct pci_driver wb_fpga_pcie_driver = { ++ .name = "wb_fpga_pcie", ++ .id_table = fpga_pci_ids,/* only dynamic id's */ ++ .probe = fpga_pcie_probe, ++ .remove = fpga_pcie_remove, ++}; ++ ++static int __init wb_fpga_pcie_init(void) ++{ ++ ++ FPGA_PCIE_DEV_VERBOSE("wb_fpga_pcie_init enter!\n"); ++ return pci_register_driver(&wb_fpga_pcie_driver); ++} ++ ++static void __exit wb_fpga_pcie_exit(void) ++{ ++ FPGA_PCIE_DEV_VERBOSE("wb_fpga_pcie_exit enter!\n"); ++ pci_unregister_driver(&wb_fpga_pcie_driver); ++ return; ++} ++ ++module_init(wb_fpga_pcie_init); ++module_exit(wb_fpga_pcie_exit); ++MODULE_DESCRIPTION("fpga pcie driver"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_d1500.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_d1500.c +new file mode 100644 +index 000000000..7d5d5da87 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_d1500.c +@@ -0,0 +1,367 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2011, 2012 Cavium Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define GPIO_NAME "wb_gpio_d1500" ++ ++#define GPIO_BASE (0x500) ++#define GP_IO_SEL (GPIO_BASE + 0x4) ++#define GP_LVL (GPIO_BASE + 0xC) ++#define GPI_NMI_EN (GPIO_BASE + 0x28) ++#define GPI_NMI_STS (GPIO_BASE + 0x2a) ++#define GPI_INV (GPIO_BASE + 0x2c) ++#define GPIO_USE_SEL2 (GPIO_BASE + 0x30) ++#define GP_IO_SEL2 (GPIO_BASE + 0x34) ++#define GP_LVL2 (GPIO_BASE + 0x38) ++#define GPI_NMI_EN_2 (GPIO_BASE + 0x3c) ++#define GPI_NMI_STS_2 (GPIO_BASE + 0x3e) ++#define GPIO_USE_SEL3 (GPIO_BASE + 0x40) ++#define GP_IO_SEL3 (GPIO_BASE + 0x44) ++#define GP_LVL3 (GPIO_BASE + 0x48) ++#define GPI_NMI_EN_3 (GPIO_BASE + 0x50) ++#define GPI_NMI_STS_3 (GPIO_BASE + 0x54) ++ ++#define GPIO_BASE_ID (0) ++#define BANKSIZE (32) ++#define D1500_GPIO_PIN_NUM (96) ++#define CELL_NUM (2) ++ ++int g_gpio_d1500_debug = 0; ++int g_gpio_d1500_error = 0; ++module_param(g_gpio_d1500_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_gpio_d1500_error, int, S_IRUGO | S_IWUSR); ++ ++#define GPIO_DEBUG_VERBOSE(fmt, args...) do { \ ++ if (g_gpio_d1500_debug) { \ ++ printk(KERN_ERR "[GPIO-D1500][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define GPIO_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_gpio_d1500_error) { \ ++ printk(KERN_ERR "[GPIO-D1500][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static DEFINE_SPINLOCK(sio_lock); ++ ++struct gpio_d1500_t { ++ struct gpio_chip chip; ++ u64 register_base; ++}; ++ ++static int wb_gpio_get(struct gpio_chip *gc, unsigned gpio_num) ++{ ++ u32 data = 0; ++ unsigned int bank, offset; ++ unsigned long flags; ++ ++ bank = gpio_num / BANKSIZE; ++ offset = gpio_num % BANKSIZE; ++ ++ spin_lock_irqsave(&sio_lock, flags); ++ if (bank == 0) { ++ data = inl(GP_LVL) & (1 << offset); ++ if (data) { ++ data = 1; ++ } ++ } else if (bank == 1) { ++ data = inl(GP_LVL2) & (1 << offset); ++ if (data) { ++ data = 1; ++ } ++ } else if (bank == 2) { ++ data = inl(GP_LVL3) & (1 << offset); ++ if (data) { ++ data = 1; ++ } ++ } ++ spin_unlock_irqrestore(&sio_lock, flags); ++ ++ return data; ++} ++ ++static int wb_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num) ++{ ++ u32 data; ++ unsigned int bank, offset; ++ unsigned long flags; ++ ++ bank = gpio_num / BANKSIZE; ++ offset = gpio_num % BANKSIZE; ++ ++ spin_lock_irqsave(&sio_lock, flags); ++ if (bank == 0) { ++ data = inl(GP_IO_SEL); ++ data = data | (1 << offset); ++ outl(data, GP_IO_SEL); ++ } else if (bank == 1) { ++ data = inl(GP_IO_SEL2); ++ data = data | (1 << offset); ++ outl(data, GP_IO_SEL2); ++ } else if (bank == 2) { ++ data = inl(GP_IO_SEL3); ++ data = data | (1 << offset); ++ outl(data, GP_IO_SEL3); ++ } ++ spin_unlock_irqrestore(&sio_lock, flags); ++ ++ return 0; ++} ++ ++static void wb_gpio_set(struct gpio_chip *gc, ++ unsigned gpio_num, int val) ++{ ++ u32 data; ++ unsigned int bank, offset; ++ unsigned long flags; ++ ++ bank = gpio_num / BANKSIZE; ++ offset = gpio_num % BANKSIZE; ++ ++ spin_lock_irqsave(&sio_lock, flags); ++ if (bank == 0) { ++ data = inl(GP_LVL); ++ if (val) { ++ data = data | (1 << offset); ++ } else { ++ data = data & ~(1 << offset); ++ } ++ outl(data, GP_LVL); ++ } else if (bank == 1) { ++ data = inl(GP_LVL2); ++ if (val) { ++ data = data | (1 << offset); ++ } else { ++ data = data & ~(1 << offset); ++ } ++ outl(data, GP_LVL2); ++ } else if (bank == 2) { ++ data = inl(GP_LVL3); ++ if (val) { ++ data = data | (1 << offset); ++ } else { ++ data = data & ~(1 << offset); ++ } ++ outl(data, GP_LVL3); ++ } ++ spin_unlock_irqrestore(&sio_lock, flags); ++ ++ return; ++} ++ ++static int wb_gpio_direction_out(struct gpio_chip *gc, ++ unsigned gpio_num, int val) ++{ ++ u32 data; ++ unsigned int bank, offset; ++ unsigned long flags; ++ ++ bank = gpio_num / BANKSIZE; ++ offset = gpio_num % BANKSIZE; ++ ++ spin_lock_irqsave(&sio_lock, flags); ++ if (bank == 0) { ++ data = inl(GP_IO_SEL); ++ data = data & ~(1 << offset); ++ outl(data, GP_IO_SEL); ++ ++ data = inl(GP_LVL); ++ if (val) { ++ data = data | (1 << offset); ++ } else { ++ data = data & ~(1 << offset); ++ } ++ outl(data, GP_LVL); ++ } else if (bank == 1) { ++ data = inl(GP_IO_SEL2); ++ data = data & ~(1 << offset); ++ outl(data, GP_IO_SEL2); ++ ++ data = inl(GP_LVL2); ++ if (val) { ++ data = data | (1 << offset); ++ } else { ++ data = data & ~(1 << offset); ++ } ++ outl(data, GP_LVL2); ++ } else if (bank == 2) { ++ data = inl(GP_IO_SEL3); ++ data = data & ~(1 << offset); ++ outl(data, GP_IO_SEL3); ++ ++ data = inl(GP_LVL3); ++ if (val) { ++ data = data | (1 << offset); ++ } else { ++ data = data & ~(1 << offset); ++ } ++ outl(data, GP_LVL3); ++ } ++ spin_unlock_irqrestore(&sio_lock, flags); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_OF ++static int wb_gpio_of_xlate(struct gpio_chip *chip, ++ const struct of_phandle_args *gpio_desc, ++ u32 *flags) ++{ ++ if (chip->of_gpio_n_cells < 2) { ++ return -EINVAL; ++ } ++ ++ if (flags) { ++ *flags = gpio_desc->args[1]; ++ } ++ ++ return gpio_desc->args[0]; ++} ++#endif ++ ++static int wb_gpio_request(struct gpio_chip *chip, unsigned int offset) ++{ ++ u32 data; ++ unsigned int bank, tmp_offset; ++ unsigned long flags; ++ ++ bank = offset / BANKSIZE; ++ tmp_offset = offset % BANKSIZE; ++ ++ spin_lock_irqsave(&sio_lock, flags); ++ if (bank == 0) { ++ data = inl(GPIO_BASE); ++ data = data | (1 << tmp_offset); ++ outl(data, GPIO_BASE); ++ } else if (bank == 1) { ++ data = inl(GPIO_USE_SEL2); ++ data = data | (1 << tmp_offset); ++ outl(data, GPIO_USE_SEL2); ++ } else if (bank == 2) { ++ data = inl(GPIO_USE_SEL3); ++ data = data | (1 << tmp_offset); ++ outl(data, GPIO_USE_SEL3); ++ } ++ spin_unlock_irqrestore(&sio_lock, flags); ++ ++ return 0; ++} ++ ++#if 0 ++static void wb_gpio_free(struct gpio_chip *chip, unsigned int offset) ++{ ++ u32 data; ++ unsigned int bank, tmp_offset; ++ unsigned long flags; ++ ++ bank = offset / BANKSIZE; ++ tmp_offset = offset % BANKSIZE; ++ ++ spin_lock_irqsave(&sio_lock, flags); ++ if (bank == 0) { ++ data = inl(GPIO_BASE); ++ data = data & ~(1 << tmp_offset); ++ outl(data, GPIO_BASE); ++ } else if (bank == 1) { ++ data = inl(GPIO_USE_SEL2); ++ data = data & ~(1 << tmp_offset); ++ outl(data, GPIO_USE_SEL2); ++ } else if (bank == 2) { ++ data = inl(GPIO_USE_SEL3); ++ data = data & ~(1 << tmp_offset); ++ outl(data, GPIO_USE_SEL3); ++ } ++ ++ spin_unlock_irqrestore(&sio_lock, flags); ++ ++ return; ++} ++#endif ++ ++static struct gpio_chip wb_gpio_chip = { ++ .label = GPIO_NAME, ++ .owner = THIS_MODULE, ++ .base = GPIO_BASE_ID, ++ .get = wb_gpio_get, ++ .direction_input = wb_gpio_direction_in, ++ .set = wb_gpio_set, ++ .direction_output = wb_gpio_direction_out, ++#ifdef CONFIG_OF ++ .of_xlate = wb_gpio_of_xlate, ++#endif ++ .request = wb_gpio_request, ++ .ngpio = D1500_GPIO_PIN_NUM, ++#ifdef CONFIG_OF ++ .of_gpio_n_cells = CELL_NUM, ++#endif ++ .can_sleep = false, ++}; ++ ++static int wb_gpio_probe(struct platform_device *pdev) ++{ ++ struct gpio_d1500_t *gpio; ++ int err; ++ ++ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); ++ if (!gpio) { ++ dev_err(&pdev->dev, "gpio kzalloc failed\n"); ++ return -ENOMEM; ++ } ++ ++ wb_gpio_chip.parent = &pdev->dev; ++ gpio->register_base = GPIO_BASE; ++ gpio->chip = wb_gpio_chip; ++ pdev->dev.platform_data = &wb_gpio_chip; ++ err = devm_gpiochip_add_data(&pdev->dev, &wb_gpio_chip, gpio); ++ if (err) { ++ dev_err(&pdev->dev, "gpiochip add failed\n"); ++ return err; ++ } ++ ++ dev_info(&pdev->dev, "register %llu gpio success.\n", gpio->register_base); ++ ++ return 0; ++} ++ ++static int wb_gpio_remove(struct platform_device *pdev) ++{ ++ dev_info(&pdev->dev, "unregister d1500 gpio success\n"); ++ return 0; ++} ++ ++static const struct of_device_id gpio_d1500_match[] = { ++ { ++ .compatible = "wb_gpio_d1500", ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, gpio_d1500_match); ++ ++static struct platform_driver wb_gpio_driver = { ++ .driver = { ++ .name = GPIO_NAME, ++ .of_match_table = gpio_d1500_match, ++ }, ++ .probe = wb_gpio_probe, ++ .remove = wb_gpio_remove, ++}; ++ ++module_platform_driver(wb_gpio_driver); ++ ++MODULE_DESCRIPTION("d1500 gpio driver"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_device.c +new file mode 100644 +index 000000000..75f883b59 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_device.c +@@ -0,0 +1,54 @@ ++#include ++#include ++#include ++#include ++#include ++ ++static int g_wb_gpio_device_debug = 0; ++static int g_wb_gpio_device_error = 0; ++ ++module_param(g_wb_gpio_device_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_gpio_device_error, int, S_IRUGO | S_IWUSR); ++ ++#define WB_GPIO_DEVICE_VERBOSE(fmt, args...) do { \ ++ if (g_wb_gpio_device_debug) { \ ++ printk(KERN_INFO "[WB_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_GPIO_DEVICE_ERROR(fmt, args...) do { \ ++ if (g_wb_gpio_device_error) { \ ++ printk(KERN_ERR "[WB_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static void wb_gpio_device_release(struct device *dev) ++{ ++ return; ++} ++ ++static struct platform_device wb_gpio_d1500_device = { ++ .name = "wb_gpio_d1500", ++ .id = -1, ++ .dev = { ++ .release = wb_gpio_device_release, ++ }, ++}; ++ ++static int __init wb_gpio_device_init(void) ++{ ++ WB_GPIO_DEVICE_VERBOSE("wb_gpio_device_init enter!\n"); ++ return platform_device_register(&wb_gpio_d1500_device); ++} ++ ++static void __exit wb_gpio_device_exit(void) ++{ ++ WB_GPIO_DEVICE_VERBOSE("wb_gpio_device_exit enter!\n"); ++ return platform_device_unregister(&wb_gpio_d1500_device); ++} ++ ++module_init(wb_gpio_device_init); ++module_exit(wb_gpio_device_exit); ++MODULE_DESCRIPTION("GPIO Devices"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.c +new file mode 100644 +index 000000000..4abdccabe +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.c +@@ -0,0 +1,815 @@ ++/* ++ * wb_io_dev.c ++ * ko to read/write i2c client through /dev/XXX device ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wb_i2c_dev.h" ++ ++#define MAX_I2C_DEV_NUM (256) ++#define FPGA_MAX_LEN (256) ++#define MAX_NAME_SIZE (20) ++#define MAX_BUS_WIDTH (16) ++#define TRANSFER_WRITE_BUFF (FPGA_MAX_LEN + MAX_BUS_WIDTH) ++ ++#define WIDTH_1Byte (1) ++#define WIDTH_2Byte (2) ++#define WIDTH_4Byte (4) ++ ++static int g_i2c_dev_debug = 0; ++static int g_i2c_dev_error = 0; ++ ++module_param(g_i2c_dev_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_i2c_dev_error, int, S_IRUGO | S_IWUSR); ++ ++#define I2C_DEV_DEBUG_DMESG(fmt, args...) do { \ ++ if (g_i2c_dev_debug) { \ ++ printk(KERN_ERR "[I2C_DEV][DEBUG][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define I2C_DEV_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_i2c_dev_error) { \ ++ printk(KERN_ERR "[I2C_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static struct i2c_dev_info* i2c_dev_arry[MAX_I2C_DEV_NUM]; ++ ++struct i2c_dev_info { ++ const char *name; ++ uint32_t data_bus_width; ++ uint32_t addr_bus_width; ++ uint32_t per_rd_len; ++ uint32_t per_wr_len; ++ uint32_t i2c_len; ++ struct miscdevice misc; ++ struct i2c_client *client; ++}; ++ ++static int transfer_read(struct i2c_client *client, u8 *buf, loff_t regaddr, size_t count) ++{ ++ struct i2c_adapter *adap; ++ union i2c_smbus_data data; ++ int i, j; ++ u8 offset_buf[MAX_BUS_WIDTH]; ++ struct i2c_msg msgs[2]; ++ int msgs_num, ret; ++ struct i2c_dev_info *i2c_dev; ++ u8 offset; ++ u8 length; ++ ++ if (!client) { ++ I2C_DEV_DEBUG_ERROR("can't get read client\n"); ++ return -ENODEV; ++ } ++ ++ adap = client->adapter; ++ if (!adap) { ++ I2C_DEV_DEBUG_ERROR("can't get read adap\n"); ++ return -ENODEV; ++ } ++ ++ i2c_dev = i2c_get_clientdata(client); ++ if (!i2c_dev) { ++ I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\n"); ++ return -ENODEV; ++ } ++ ++ i = 0; ++ ++ mem_clear(offset_buf, sizeof(offset_buf)); ++ ++ switch (i2c_dev->addr_bus_width) { ++ case WIDTH_4Byte: ++ offset_buf[i++] = (regaddr >> 24) & 0xFF; ++ offset_buf[i++] = (regaddr >> 16) & 0xFF; ++ offset_buf[i++] = (regaddr >> 8) & 0xFF; ++ offset_buf[i++] = regaddr & 0xFF; ++ break; ++ case WIDTH_2Byte: ++ offset_buf[i++] = (regaddr >> 8) & 0xFF; ++ offset_buf[i++] = regaddr & 0xFF; ++ break; ++ case WIDTH_1Byte: ++ offset_buf[i++] = regaddr & 0xFF; ++ break; ++ default: ++ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\n", ++ i2c_dev->addr_bus_width); ++ return -EINVAL; ++ } ++ ++ if (adap->algo->master_xfer) { ++ mem_clear(msgs, sizeof(msgs)); ++ msgs[0].addr = client->addr; ++ msgs[0].flags = 0; ++ msgs[0].len = i2c_dev->addr_bus_width; ++ msgs[0].buf = offset_buf; ++ ++ msgs[1].addr = client->addr; ++ msgs[1].flags = I2C_M_RD; ++ msgs[1].len = count; ++ msgs[1].buf = buf; ++ ++ msgs_num = 2; ++ ret = i2c_transfer(client->adapter, msgs, msgs_num); ++ if (ret != msgs_num) { ++ I2C_DEV_DEBUG_ERROR("i2c_transfer read error\n"); ++ return -EINVAL; ++ } ++ } else { ++ if (i2c_dev->addr_bus_width == WIDTH_1Byte) { ++ offset = regaddr & 0xFF; ++ if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { ++ for (j = 0; j < count; j += I2C_SMBUS_BLOCK_MAX) { ++ if (count - j > I2C_SMBUS_BLOCK_MAX) { ++ length = I2C_SMBUS_BLOCK_MAX; ++ } else { ++ length = count - j; ++ } ++ data.block[0] = length; ++ ret = adap->algo->smbus_xfer(adap, client->addr, ++ 0, ++ I2C_SMBUS_READ, ++ offset, I2C_SMBUS_I2C_BLOCK_DATA, &data); ++ if (ret) { ++ I2C_DEV_DEBUG_ERROR("smbus_xfer read block error, ret = %d\n", ret); ++ return -EFAULT; ++ } ++ memcpy(buf + j, data.block + 1, length); ++ offset += length; ++ } ++ } else { ++ for (j = 0; j < count; j++) { ++ ret = adap->algo->smbus_xfer(adap, client->addr, ++ 0, ++ I2C_SMBUS_READ, ++ offset, I2C_SMBUS_BYTE_DATA, &data); ++ ++ if (!ret) { ++ buf[j] = data.byte; ++ } else { ++ I2C_DEV_DEBUG_ERROR("smbus_xfer read byte error, ret = %d\n", ret); ++ return -EFAULT; ++ } ++ offset++; ++ } ++ } ++ } else { ++ I2C_DEV_DEBUG_ERROR("smbus_xfer not support addr_bus_width = %d\n", i2c_dev->addr_bus_width); ++ return -EINVAL; ++ } ++ } ++ return 0; ++} ++ ++static int transfer_write(struct i2c_client *client, u8 *buf, loff_t regaddr, size_t count) ++{ ++ struct i2c_adapter *adap; ++ int i; ++ u8 offset_buf[TRANSFER_WRITE_BUFF]; ++ struct i2c_msg msgs[1]; ++ int msgs_num, ret; ++ struct i2c_dev_info *i2c_dev; ++ ++ if (!client) { ++ I2C_DEV_DEBUG_ERROR("can't get write client\n"); ++ return -ENODEV; ++ } ++ ++ adap = client->adapter; ++ if (!adap) { ++ I2C_DEV_DEBUG_ERROR("can't get write adap\n"); ++ return -ENODEV; ++ } ++ ++ i2c_dev = i2c_get_clientdata(client); ++ if (!i2c_dev) { ++ I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\n"); ++ return -ENODEV; ++ } ++ ++ i = 0; ++ ++ mem_clear(offset_buf, sizeof(offset_buf)); ++ ++ switch (i2c_dev->addr_bus_width) { ++ case WIDTH_4Byte: ++ offset_buf[i++] = (regaddr >> 24) & 0xFF; ++ offset_buf[i++] = (regaddr >> 16) & 0xFF; ++ offset_buf[i++] = (regaddr >> 8) & 0xFF; ++ offset_buf[i++] = regaddr & 0xFF; ++ break; ++ case WIDTH_2Byte: ++ offset_buf[i++] = (regaddr >> 8) & 0xFF; ++ offset_buf[i++] = regaddr & 0xFF; ++ break; ++ case WIDTH_1Byte: ++ offset_buf[i++] = regaddr & 0xFF; ++ break; ++ default: ++ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\n", ++ i2c_dev->addr_bus_width); ++ return -EINVAL; ++ } ++ ++ memcpy(offset_buf + i2c_dev->addr_bus_width, buf, count); ++ ++ if (adap->algo->master_xfer) { ++ mem_clear(msgs, sizeof(msgs)); ++ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = 0; ++ msgs[0].len = i2c_dev->addr_bus_width + count; ++ msgs[0].buf = offset_buf; ++ ++ msgs_num = 1; ++ ret = i2c_transfer(adap, msgs, msgs_num); ++ if (ret != msgs_num) { ++ I2C_DEV_DEBUG_ERROR("i2c_transfer write error\n"); ++ return -EINVAL; ++ } ++ } else { ++ I2C_DEV_DEBUG_ERROR("don't find write master_xfer\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static long i2c_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ return 0; ++} ++ ++static int i2c_dev_open(struct inode *inode, struct file *file) ++{ ++ unsigned int minor = iminor(inode); ++ struct i2c_dev_info *i2c_dev; ++ ++ i2c_dev = i2c_dev_arry[minor]; ++ if (i2c_dev == NULL) { ++ return -ENODEV; ++ } ++ ++ file->private_data = i2c_dev; ++ ++ return 0; ++} ++ ++static int i2c_dev_release(struct inode *inode, struct file *file) ++{ ++ file->private_data = NULL; ++ ++ return 0; ++} ++ ++static int device_read(struct i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ int i, j, ret; ++ u8 tmp_offset; ++ u8 val[FPGA_MAX_LEN]; ++ u32 width, rd_len, per_len, tmp; ++ u32 max_per_len; ++ ++ if (offset > i2c_dev->i2c_len) { ++ I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, count: %lu, EOF.\n", ++ offset, i2c_dev->i2c_len, count); ++ return 0; ++ } ++ ++ if (count > (i2c_dev->i2c_len - offset)) { ++ I2C_DEV_DEBUG_DMESG("read count out of range. input len:%lu, read len:%u.\n", ++ count, i2c_dev->i2c_len - offset); ++ count = i2c_dev->i2c_len - offset; ++ } ++ ++ if (count == 0) { ++ I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, read len: %lu, EOF.\n", ++ offset, i2c_dev->i2c_len, count); ++ return 0; ++ } ++ ++ width = i2c_dev->data_bus_width; ++ switch (width) { ++ case WIDTH_4Byte: ++ tmp_offset = offset & 0x3; ++ if (tmp_offset) { ++ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", ++ width, offset, count); ++ return -EINVAL; ++ } ++ break; ++ case WIDTH_2Byte: ++ tmp_offset = offset & 0x1; ++ if (tmp_offset) { ++ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", ++ width, offset, count); ++ return -EINVAL; ++ } ++ break; ++ case WIDTH_1Byte: ++ break; ++ default: ++ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\n", width); ++ return -EINVAL; ++ } ++ ++ max_per_len = i2c_dev->per_rd_len; ++ tmp = (width - 1) & count; ++ rd_len = (tmp == 0) ? count : count + width - tmp; ++ per_len = (rd_len > max_per_len) ? (max_per_len) : (rd_len); ++ ++ mem_clear(val, sizeof(val)); ++ for (i = 0; i < rd_len; i += per_len) { ++ ret = transfer_read(i2c_dev->client, val + i, offset + i, per_len); ++ if (ret < 0) { ++ I2C_DEV_DEBUG_ERROR("read error.read offset = %u\n", (offset + i)); ++ return -EFAULT; ++ } ++ } ++ ++ if (width == WIDTH_1Byte) { ++ memcpy(buf, val, count); ++ } else { ++ for (i = 0; i < count; i += width) { ++ for (j = 0; (j < width) && (i + j < count); j++) { ++ buf[i + j] = val[i + width - j - 1]; ++ } ++ } ++ } ++ ++ return count; ++} ++ ++static int device_write(struct i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ int i, j, ret; ++ u8 tmp_offset; ++ u32 width; ++ u8 val[FPGA_MAX_LEN]; ++ u32 wr_len, per_len, tmp; ++ u32 max_per_len; ++ ++ if (offset > i2c_dev->i2c_len) { ++ I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, count: %lu, EOF.\n", ++ offset, i2c_dev->i2c_len, count); ++ return 0; ++ } ++ ++ if (count > (i2c_dev->i2c_len - offset)) { ++ I2C_DEV_DEBUG_DMESG("read count out of range. input len:%lu, read len:%u.\n", ++ count, i2c_dev->i2c_len - offset); ++ count = i2c_dev->i2c_len - offset; ++ } ++ ++ if (count == 0) { ++ I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, read len: %lu, EOF.\n", ++ offset, i2c_dev->i2c_len, count); ++ return 0; ++ } ++ ++ width = i2c_dev->data_bus_width; ++ switch (width) { ++ case WIDTH_4Byte: ++ tmp_offset = offset & 0x3; ++ if (tmp_offset) { ++ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", ++ width, offset, count); ++ return -EINVAL; ++ } ++ break; ++ case WIDTH_2Byte: ++ tmp_offset = offset & 0x1; ++ if (tmp_offset) { ++ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", ++ width, offset, count); ++ return -EINVAL; ++ } ++ break; ++ case WIDTH_1Byte: ++ break; ++ default: ++ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\n", width); ++ return -EINVAL; ++ } ++ ++ mem_clear(val, sizeof(val)); ++ ++ if (width == WIDTH_1Byte) { ++ memcpy(val, buf, count); ++ } else { ++ for (i = 0; i < count; i += width) { ++ for (j = 0; (j < width) && (i + j < count); j++) { ++ val[i + width - j - 1] = buf[i + j]; ++ } ++ } ++ } ++ ++ max_per_len = i2c_dev->per_wr_len; ++ tmp = (width - 1) & count; ++ wr_len = (tmp == 0) ? count : count + width - tmp; ++ per_len = (wr_len > max_per_len) ? (max_per_len) : (wr_len); ++ ++ for (i = 0; i < wr_len; i += per_len) { ++ ret = transfer_write(i2c_dev->client, val + i, offset + i, per_len); ++ if (ret < 0) { ++ I2C_DEV_DEBUG_ERROR("write error.offset = %u\n", (offset + i)); ++ return -EFAULT; ++ } ++ } ++ return count; ++} ++ ++static ssize_t i2c_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) ++{ ++ u8 val[FPGA_MAX_LEN]; ++ int ret, read_len; ++ struct i2c_dev_info *i2c_dev; ++ ++ i2c_dev = file->private_data; ++ if (i2c_dev == NULL) { ++ I2C_DEV_DEBUG_ERROR("can't get read private_data.\n"); ++ return -EINVAL; ++ } ++ ++ if (count == 0) { ++ I2C_DEV_DEBUG_ERROR("Invalid params, read count is 0.\n"); ++ return -EINVAL; ++ } ++ ++ if (count > sizeof(val)) { ++ I2C_DEV_DEBUG_DMESG("read count %lu exceed max %lu.\n", count, sizeof(val)); ++ count = sizeof(val); ++ } ++ ++ mem_clear(val, sizeof(val)); ++ read_len = device_read(i2c_dev, (uint32_t)*offset, val, count); ++ if (read_len < 0) { ++ I2C_DEV_DEBUG_ERROR("i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", ++ i2c_dev->name, (uint32_t)*offset, count); ++ return read_len; ++ } ++ ++ if (access_ok(buf, read_len)) { ++ I2C_DEV_DEBUG_DMESG("user space read, buf: %p, offset: %lld, read count %lu.\n", ++ buf, *offset, count); ++ if (copy_to_user(buf, val, read_len)) { ++ I2C_DEV_DEBUG_ERROR("copy_to_user failed.\n"); ++ return -EFAULT; ++ } ++ } else { ++ I2C_DEV_DEBUG_DMESG("kernel space read, buf: %p, offset: %lld, read count %lu.\n", ++ buf, *offset, count); ++ memcpy(buf, val, read_len); ++ } ++ ++ *offset += read_len; ++ ret = read_len; ++ return ret; ++} ++ ++static ssize_t i2c_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) ++{ ++ int ret; ++ ++ I2C_DEV_DEBUG_DMESG("i2c_dev_read_iter, file: %p, count: %lu, offset: %lld\n", ++ iocb->ki_filp, to->count, iocb->ki_pos); ++ ret = i2c_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos); ++ return ret; ++} ++ ++static ssize_t i2c_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) ++{ ++ u8 val[FPGA_MAX_LEN]; ++ int write_len; ++ struct i2c_dev_info *i2c_dev; ++ ++ i2c_dev = file->private_data; ++ if (i2c_dev == NULL) { ++ I2C_DEV_DEBUG_ERROR("get write private_data error.\n"); ++ return -EINVAL; ++ } ++ ++ if (count == 0) { ++ I2C_DEV_DEBUG_ERROR("Invalid params, write count is 0.\n"); ++ return -EINVAL; ++ } ++ ++ if (count > sizeof(val)) { ++ I2C_DEV_DEBUG_DMESG("write count %lu exceed max %lu.\n", count, sizeof(val)); ++ count = sizeof(val); ++ } ++ ++ mem_clear(val, sizeof(val)); ++ if (access_ok(buf, count)) { ++ I2C_DEV_DEBUG_DMESG("user space write, buf: %p, offset: %lld, write count %lu.\n", ++ buf, *offset, count); ++ if (copy_from_user(val, buf, count)) { ++ I2C_DEV_DEBUG_ERROR("copy_from_user failed.\n"); ++ return -EFAULT; ++ } ++ } else { ++ I2C_DEV_DEBUG_DMESG("kernel space write, buf: %p, offset: %lld, write count %lu.\n", ++ buf, *offset, count); ++ memcpy(val, buf, count); ++ } ++ ++ write_len = device_write(i2c_dev, (uint32_t)*offset, val, count); ++ if (write_len < 0) { ++ I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%llx, len:%lu.\n", ++ i2c_dev->name, *offset, count); ++ return write_len; ++ } ++ ++ *offset += write_len; ++ return write_len; ++} ++ ++static ssize_t i2c_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) ++{ ++ int ret; ++ ++ I2C_DEV_DEBUG_DMESG("i2c_dev_write_iter, file: %p, count: %lu, offset: %lld\n", ++ iocb->ki_filp, from->count, iocb->ki_pos); ++ ret = i2c_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos); ++ return ret; ++} ++ ++static loff_t i2c_dev_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t ret = 0; ++ struct i2c_dev_info *i2c_dev; ++ ++ i2c_dev = file->private_data; ++ if (i2c_dev == NULL) { ++ I2C_DEV_DEBUG_ERROR("i2c_dev is NULL, llseek failed.\n"); ++ return -EINVAL; ++ } ++ ++ switch (origin) { ++ case SEEK_SET: ++ if (offset < 0) { ++ I2C_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); ++ ret = -EINVAL; ++ break; ++ } ++ if (offset > i2c_dev->i2c_len) { ++ I2C_DEV_DEBUG_ERROR("SEEK_SET out of range, offset:%lld, i2c_len:0x%x.\n", ++ offset, i2c_dev->i2c_len); ++ ret = - EINVAL; ++ break; ++ } ++ file->f_pos = offset; ++ ret = file->f_pos; ++ break; ++ case SEEK_CUR: ++ if (((file->f_pos + offset) > i2c_dev->i2c_len) || ((file->f_pos + offset) < 0)) { ++ I2C_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld, i2c_len:0x%x.\n", ++ file->f_pos, offset, i2c_dev->i2c_len); ++ ret = - EINVAL; ++ break; ++ } ++ file->f_pos += offset; ++ ret = file->f_pos; ++ break; ++ default: ++ I2C_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++static const struct file_operations i2c_dev_fops = { ++ .owner = THIS_MODULE, ++ .llseek = i2c_dev_llseek, ++ .read_iter = i2c_dev_read_iter, ++ .write_iter = i2c_dev_write_iter, ++ .unlocked_ioctl = i2c_dev_ioctl, ++ .open = i2c_dev_open, ++ .release = i2c_dev_release, ++}; ++ ++static struct i2c_dev_info * dev_match(const char *path) ++{ ++ struct i2c_dev_info * i2c_dev; ++ char dev_name[MAX_NAME_SIZE]; ++ int i; ++ for (i = 0; i < MAX_I2C_DEV_NUM; i++) { ++ if (i2c_dev_arry[ i ] == NULL) { ++ continue; ++ } ++ i2c_dev = i2c_dev_arry[ i ]; ++ snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", i2c_dev->name); ++ if (!strcmp(path, dev_name)) { ++ I2C_DEV_DEBUG_DMESG("get dev_name = %s, minor = %d\n", dev_name, i); ++ return i2c_dev; ++ } ++ } ++ ++ return NULL; ++} ++ ++int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ struct i2c_dev_info *i2c_dev = NULL; ++ int ret; ++ ++ if(path == NULL){ ++ I2C_DEV_DEBUG_ERROR("path NULL"); ++ return -EINVAL; ++ } ++ ++ if(buf == NULL){ ++ I2C_DEV_DEBUG_ERROR("buf NULL"); ++ return -EINVAL; ++ } ++ ++ if (count > FPGA_MAX_LEN) { ++ I2C_DEV_DEBUG_ERROR("read count %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); ++ return -EINVAL; ++ } ++ ++ i2c_dev = dev_match(path); ++ if (i2c_dev == NULL) { ++ I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); ++ return -EINVAL; ++ } ++ ++ ret = device_read(i2c_dev, offset, buf, count); ++ if (ret < 0) { ++ I2C_DEV_DEBUG_ERROR("fpga i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", ++ i2c_dev->name, offset, count); ++ return -EINVAL; ++ } ++ ++ return count; ++} ++EXPORT_SYMBOL(i2c_device_func_read); ++ ++int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ struct i2c_dev_info *i2c_dev = NULL; ++ int ret; ++ ++ if(path == NULL){ ++ I2C_DEV_DEBUG_ERROR("path NULL"); ++ return -EINVAL; ++ } ++ ++ if(buf == NULL){ ++ I2C_DEV_DEBUG_ERROR("buf NULL"); ++ return -EINVAL; ++ } ++ ++ if (count > FPGA_MAX_LEN) { ++ I2C_DEV_DEBUG_ERROR("write count %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); ++ return -EINVAL; ++ } ++ ++ i2c_dev = dev_match(path); ++ if (i2c_dev == NULL) { ++ I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); ++ return -EINVAL; ++ } ++ ++ ret = device_write (i2c_dev, offset, buf, count); ++ if (ret < 0) { ++ I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%x, len:%lu.\n", ++ i2c_dev->name, offset, count); ++ return -EINVAL; ++ } ++ ++ return count; ++} ++EXPORT_SYMBOL(i2c_device_func_write); ++ ++static int i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ int ret = 0; ++ struct i2c_dev_info *i2c_dev; ++ struct miscdevice *misc; ++ i2c_dev_device_t *i2c_dev_device; ++ ++ i2c_dev = devm_kzalloc(&client->dev, sizeof(struct i2c_dev_info), GFP_KERNEL); ++ if (!i2c_dev) { ++ dev_err(&client->dev, "devm_kzalloc error. \n"); ++ return -ENOMEM; ++ } ++ ++ i2c_set_clientdata(client, i2c_dev); ++ i2c_dev->client = client; ++ ++ if (client->dev.of_node) { ++ ++ ret += of_property_read_string(client->dev.of_node, "i2c_name", &i2c_dev->name); ++ ret += of_property_read_u32(client->dev.of_node, "data_bus_width", &i2c_dev->data_bus_width); ++ ret += of_property_read_u32(client->dev.of_node, "addr_bus_width", &i2c_dev->addr_bus_width); ++ ret += of_property_read_u32(client->dev.of_node, "per_rd_len", &i2c_dev->per_rd_len); ++ ret += of_property_read_u32(client->dev.of_node, "per_wr_len", &i2c_dev->per_wr_len); ++ ret += of_property_read_u32(client->dev.of_node, "i2c_len", &i2c_dev->i2c_len); ++ if (ret != 0) { ++ dev_err(&client->dev, "dts config error.ret:%d.\n", ret); ++ return -ENXIO; ++ } ++ } else { ++ if (client->dev.platform_data == NULL) { ++ dev_err(&client->dev, "Failed to get platform data config.\n"); ++ return -ENXIO; ++ } ++ i2c_dev_device = client->dev.platform_data; ++ i2c_dev->name = i2c_dev_device->i2c_name; ++ i2c_dev->data_bus_width = i2c_dev_device->data_bus_width; ++ i2c_dev->addr_bus_width = i2c_dev_device->addr_bus_width; ++ i2c_dev->per_rd_len = i2c_dev_device->per_rd_len; ++ i2c_dev->per_wr_len = i2c_dev_device->per_wr_len; ++ i2c_dev->i2c_len = i2c_dev_device->i2c_len; ++ } ++ ++ if ((i2c_dev->per_rd_len & (i2c_dev->data_bus_width - 1)) || ++ (i2c_dev->per_wr_len & (i2c_dev->data_bus_width - 1))) { ++ dev_err(&client->dev, "Invalid config per_rd_len %d per_wr_len %d data bus_width %d.\n", ++ i2c_dev->per_rd_len, i2c_dev->per_wr_len, i2c_dev->data_bus_width); ++ return -ENXIO; ++ } ++ ++ if ((i2c_dev->i2c_len == 0) || (i2c_dev->i2c_len & (i2c_dev->data_bus_width - 1))) { ++ dev_err(&client->dev, "Invalid config i2c_len %d, data bus_width %d.\n", ++ i2c_dev->i2c_len, i2c_dev->data_bus_width); ++ return -ENXIO; ++ } ++ ++ misc = &i2c_dev->misc; ++ misc->minor = MISC_DYNAMIC_MINOR; ++ misc->name = i2c_dev->name; ++ misc->fops = &i2c_dev_fops; ++ misc->mode = 0666; ++ if (misc_register(misc) != 0) { ++ dev_err(&client->dev, "register %s faild.\n", misc->name); ++ return -ENXIO; ++ } ++ ++ if (misc->minor >= MAX_I2C_DEV_NUM) { ++ dev_err(&client->dev, "minor number beyond the limit! is %d.\n", misc->minor); ++ misc_deregister(misc); ++ return -ENXIO; ++ } ++ i2c_dev_arry[misc->minor] = i2c_dev; ++ ++ dev_info(&client->dev, "register %u addr_bus_width %u data_bus_width 0x%x i2c_len device %s with %u per_rd_len %u per_wr_len success.\n", ++ i2c_dev->addr_bus_width, i2c_dev->data_bus_width, i2c_dev->i2c_len, i2c_dev->name, i2c_dev->per_rd_len, i2c_dev->per_wr_len); ++ ++ return 0; ++} ++ ++static int i2c_dev_remove(struct i2c_client *client) ++{ ++ int i; ++ for (i = 0; i < MAX_I2C_DEV_NUM; i++) { ++ if (i2c_dev_arry[i] != NULL) { ++ misc_deregister(&i2c_dev_arry[i]->misc); ++ i2c_dev_arry[i] = NULL; ++ } ++ } ++ return 0; ++} ++ ++static const struct i2c_device_id i2c_dev_id[] = { ++ { "wb-i2c-dev", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, i2c_dev_id); ++ ++static const struct of_device_id i2c_dev_of_match[] = { ++ { .compatible = "wb-i2c-dev" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, i2c_dev_of_match); ++ ++static struct i2c_driver i2c_dev_driver = { ++ .driver = { ++ .name = "wb-i2c-dev", ++ .of_match_table = i2c_dev_of_match, ++ }, ++ .probe = i2c_dev_probe, ++ .remove = i2c_dev_remove, ++ .id_table = i2c_dev_id, ++}; ++module_i2c_driver(i2c_dev_driver); ++ ++MODULE_DESCRIPTION("i2c dev driver"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.h +new file mode 100644 +index 000000000..9cc95d88e +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.h +@@ -0,0 +1,20 @@ ++#ifndef __WB_I2C_DEV_H__ ++#define __WB_I2C_DEV_H__ ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++#define I2C_DEV_NAME_MAX_LEN (64) ++ ++typedef struct i2c_dev_device_s { ++ struct i2c_client *client; ++ uint32_t i2c_bus; ++ uint32_t i2c_addr; ++ char i2c_name[I2C_DEV_NAME_MAX_LEN]; ++ uint32_t data_bus_width; ++ uint32_t addr_bus_width; ++ uint32_t per_rd_len; ++ uint32_t per_wr_len; ++ uint32_t i2c_len; ++} i2c_dev_device_t; ++ ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.c +new file mode 100644 +index 000000000..1f69d96ba +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.c +@@ -0,0 +1,1143 @@ ++// 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 ++#include ++#include ++ ++#include "wb_i2c_ocores.h" ++ ++#define OCORES_FLAG_POLL BIT(0) ++ ++/* 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 OCORE_WAIT_SCH (40) ++#define REG_IO_WIDTH_1 (1) ++#define REG_IO_WIDTH_2 (2) ++#define REG_IO_WIDTH_4 (4) ++ ++#define SYMBOL_I2C_DEV_MODE (1) ++#define FILE_MODE (2) ++#define SYMBOL_PCIE_DEV_MODE (3) ++#define SYMBOL_IO_DEV_MODE (4) ++ ++typedef struct wb_pci_dev_s { ++ uint32_t domain; ++ uint32_t bus; ++ uint32_t slot; ++ uint32_t fn; ++} wb_pci_dev_t; ++ ++/* ++ * 'process_lock' exists because ocores_process() and ocores_process_timeout() ++ * can't run in parallel. ++ */ ++struct ocores_i2c { ++ uint32_t base_addr; ++ uint32_t reg_shift; ++ uint32_t reg_io_width; ++ unsigned long flags; ++ wait_queue_head_t wait; ++ struct i2c_adapter adap; ++ int adap_nr; ++ struct i2c_msg *msg; ++ int pos; ++ int nmsgs; ++ int state; ++ spinlock_t process_lock; ++ uint32_t ip_clock_khz; ++ uint32_t bus_clock_khz; ++ void (*setreg)(struct ocores_i2c *i2c, int reg, u32 value); ++ u32 (*getreg)(struct ocores_i2c *i2c, int reg); ++ const char *dev_name; ++ uint32_t reg_access_mode; ++ uint32_t big_endian; ++ uint32_t irq_offset; ++ wb_pci_dev_t wb_pci_dev; ++ struct device *dev; ++}; ++ ++int g_wb_ocores_i2c_debug = 0; ++int g_wb_ocores_i2c_error = 0; ++int g_wb_ocores_i2c_xfer = 0; ++ ++module_param(g_wb_ocores_i2c_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_ocores_i2c_error, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_ocores_i2c_xfer, int, S_IRUGO | S_IWUSR); ++ ++#define OCORES_I2C_VERBOSE(fmt, args...) do { \ ++ if (g_wb_ocores_i2c_debug) { \ ++ printk(KERN_INFO "[OCORES_I2C][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define OCORES_I2C_ERROR(fmt, args...) do { \ ++ if (g_wb_ocores_i2c_error) { \ ++ printk(KERN_ERR "[OCORES_I2C][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define OCORES_I2C_XFER(fmt, args...) do { \ ++ if (g_wb_ocores_i2c_xfer) { \ ++ printk(KERN_INFO "[OCORES_I2C][XFER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++extern int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++#if 0 ++int __attribute__((weak)) i2c_device_func_read(const char *path, uint32_t offset, ++ uint8_t *buf, size_t count) ++{ ++ OCORES_I2C_ERROR("enter __weak i2c func read\r\n"); ++ return -EINVAL; ++} ++ ++int __attribute__((weak)) i2c_device_func_write(const char *path, uint32_t offset, ++ uint8_t *buf, size_t count) ++{ ++ OCORES_I2C_ERROR("enter __weak i2c func write\r\n"); ++ return -EINVAL; ++} ++ ++int __attribute__((weak)) pcie_device_func_read(const char *path, uint32_t offset, ++ uint8_t *buf, size_t count) ++{ ++ OCORES_I2C_ERROR("enter __weak pcie func read\r\n"); ++ return -EINVAL; ++} ++ ++int __attribute__((weak)) pcie_device_func_write(const char *path, uint32_t offset, ++ uint8_t *buf, size_t count) ++{ ++ OCORES_I2C_ERROR("enter __weak pcie func write\r\n"); ++ return -EINVAL; ++} ++ ++int __attribute__((weak)) io_device_func_read(const char *path, uint32_t offset, ++ uint8_t *buf, size_t count) ++{ ++ OCORES_I2C_ERROR("enter __weak io func read\r\n"); ++ return -EINVAL; ++} ++ ++int __attribute__((weak)) io_device_func_write(const char *path, uint32_t offset, ++ uint8_t *buf, size_t count) ++{ ++ OCORES_I2C_ERROR("enter __weak io func write\r\n"); ++ return -EINVAL; ++} ++#endif ++static int ocores_i2c_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) ++{ ++ int ret; ++ struct file *filp; ++ loff_t tmp_pos; ++ ++ filp = filp_open(path, O_RDONLY, 0); ++ if (IS_ERR(filp)) { ++ OCORES_I2C_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); ++ filp = NULL; ++ goto exit; ++ } ++ ++ tmp_pos = (loff_t)pos; ++ ret = kernel_read(filp, val, size, &tmp_pos); ++ if (ret < 0) { ++ OCORES_I2C_ERROR("kernel_read failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); ++ goto exit; ++ } ++ ++ filp_close(filp, NULL); ++ ++ return ret; ++ ++exit: ++ if (filp != NULL) { ++ filp_close(filp, NULL); ++ } ++ ++ return -1; ++} ++ ++static int ocores_i2c_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) ++{ ++ ++ int ret; ++ struct file *filp; ++ loff_t tmp_pos; ++ ++ filp = filp_open(path, O_RDWR, 777); ++ if (IS_ERR(filp)) { ++ OCORES_I2C_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); ++ filp = NULL; ++ goto exit; ++ } ++ ++ tmp_pos = (loff_t)pos; ++ ret = kernel_write(filp, val, size, &tmp_pos); ++ if (ret < 0) { ++ OCORES_I2C_ERROR("kernel_write failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); ++ goto exit; ++ } ++ ++ vfs_fsync(filp, 1); ++ filp_close(filp, NULL); ++ ++ return ret; ++ ++exit: ++ if (filp != NULL) { ++ filp_close(filp, NULL); ++ } ++ ++ return -1; ++} ++ ++static int ocores_i2c_reg_write(struct ocores_i2c *i2c, uint32_t pos, uint8_t *val, size_t size) ++{ ++ int ret; ++ ++ switch (i2c->reg_access_mode) { ++ case SYMBOL_I2C_DEV_MODE: ++ ret = i2c_device_func_write(i2c->dev_name, pos, val, size); ++ break; ++ case FILE_MODE: ++ ret = ocores_i2c_file_write(i2c->dev_name, pos, val, size); ++ break; ++ case SYMBOL_PCIE_DEV_MODE: ++ ret = pcie_device_func_write(i2c->dev_name, pos, val, size); ++ break; ++ case SYMBOL_IO_DEV_MODE: ++ ret = io_device_func_write(i2c->dev_name, pos, val, size); ++ break; ++ default: ++ OCORES_I2C_ERROR("err func_mode, write failed.\n"); ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int ocores_i2c_reg_read(struct ocores_i2c *i2c, uint32_t pos, uint8_t *val, size_t size) ++{ ++ int ret; ++ ++ switch (i2c->reg_access_mode) { ++ case SYMBOL_I2C_DEV_MODE: ++ ret = i2c_device_func_read(i2c->dev_name, pos, val, size); ++ break; ++ case FILE_MODE: ++ ret = ocores_i2c_file_read(i2c->dev_name, pos, val, size); ++ break; ++ case SYMBOL_PCIE_DEV_MODE: ++ ret = pcie_device_func_read(i2c->dev_name, pos, val, size); ++ break; ++ case SYMBOL_IO_DEV_MODE: ++ ret = io_device_func_read(i2c->dev_name, pos, val, size); ++ break; ++ default: ++ OCORES_I2C_ERROR("err func_mode, read failed.\n"); ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u32 value) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_1]; ++ u32 pos; ++ ++ pos = i2c->base_addr + (reg << i2c->reg_shift); ++ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ i2c->dev_name, i2c->reg_access_mode, pos, value); ++ ++ buf_tmp[0] = (value & 0Xff); ++ ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_1); ++ return; ++} ++ ++static void oc_setreg_16(struct ocores_i2c *i2c, int reg, u32 value) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_2]; ++ u32 pos; ++ ++ pos = i2c->base_addr + (reg << i2c->reg_shift); ++ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ i2c->dev_name, i2c->reg_access_mode, pos, value); ++ ++ buf_tmp[0] = (value & 0Xff); ++ buf_tmp[1] = (value >> 8) & 0xff; ++ ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_2); ++ return; ++} ++ ++static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u32 value) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_4]; ++ u32 pos; ++ ++ pos = i2c->base_addr + (reg << i2c->reg_shift); ++ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ i2c->dev_name, i2c->reg_access_mode, pos, value); ++ ++ buf_tmp[0] = (value & 0xff); ++ buf_tmp[1] = (value >> 8) & 0xff; ++ buf_tmp[2] = (value >> 16) & 0xff; ++ buf_tmp[3] = (value >> 24) & 0xff; ++ ++ ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_4); ++ return; ++} ++ ++static void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u32 value) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_2]; ++ u32 pos; ++ ++ pos = i2c->base_addr + (reg << i2c->reg_shift); ++ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ i2c->dev_name, i2c->reg_access_mode, pos, value); ++ ++ buf_tmp[0] = (value >> 8) & 0xff; ++ buf_tmp[1] = (value & 0Xff); ++ ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_2); ++ return; ++} ++ ++static void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u32 value) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_4]; ++ u32 pos; ++ ++ pos = i2c->base_addr + (reg << i2c->reg_shift); ++ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ i2c->dev_name, i2c->reg_access_mode, pos, value); ++ ++ buf_tmp[0] = (value >> 24) & 0xff; ++ buf_tmp[1] = (value >> 16) & 0xff; ++ buf_tmp[2] = (value >> 8) & 0xff; ++ buf_tmp[3] = (value & 0xff); ++ ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_4); ++ return; ++} ++ ++static inline u32 oc_getreg_8(struct ocores_i2c *i2c, int reg) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_1]; ++ u32 value, pos; ++ ++ pos = i2c->base_addr + (reg << i2c->reg_shift); ++ ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_1); ++ value = buf_tmp[0]; ++ ++ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ i2c->dev_name, i2c->reg_access_mode, pos, value); ++ ++ return value; ++} ++ ++static inline u32 oc_getreg_16(struct ocores_i2c *i2c, int reg) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_2]; ++ u32 value, pos; ++ int i; ++ ++ pos = i2c->base_addr + (reg << i2c->reg_shift); ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_2); ++ ++ value = 0; ++ for (i = 0; i < REG_IO_WIDTH_2 ; i++) { ++ value |= buf_tmp[i] << (8 * i); ++ } ++ ++ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ i2c->dev_name, i2c->reg_access_mode, pos, value); ++ return value; ++} ++ ++static inline u32 oc_getreg_32(struct ocores_i2c *i2c, int reg) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_4]; ++ u32 value, pos; ++ int i; ++ ++ pos = i2c->base_addr + (reg << i2c->reg_shift); ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_4); ++ ++ value = 0; ++ for (i = 0; i < REG_IO_WIDTH_4 ; i++) { ++ value |= buf_tmp[i] << (8 * i); ++ } ++ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ i2c->dev_name, i2c->reg_access_mode, pos, value); ++ return value; ++} ++ ++static inline u32 oc_getreg_16be(struct ocores_i2c *i2c, int reg) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_2]; ++ u32 value, pos; ++ int i; ++ ++ pos = i2c->base_addr + (reg << i2c->reg_shift); ++ ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_2); ++ ++ value = 0; ++ for (i = 0; i < REG_IO_WIDTH_2 ; i++) { ++ value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_2 -i - 1)); ++ } ++ ++ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ i2c->dev_name, i2c->reg_access_mode, pos, value); ++ return value; ++} ++ ++static inline u32 oc_getreg_32be(struct ocores_i2c *i2c, int reg) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_4]; ++ u32 value, pos; ++ int i; ++ ++ pos = i2c->base_addr + (reg << i2c->reg_shift); ++ ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_4); ++ ++ value = 0; ++ for (i = 0; i < REG_IO_WIDTH_4 ; i++) { ++ value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_4 -i - 1)); ++ } ++ ++ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ i2c->dev_name, i2c->reg_access_mode, pos, value); ++ return value; ++ ++} ++ ++static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u32 value) ++{ ++ i2c->setreg(i2c, reg, value); ++ return; ++} ++ ++static inline u32 oc_getreg(struct ocores_i2c *i2c, int reg) ++{ ++ return i2c->getreg(i2c, reg); ++} ++ ++static int ocores_msg_check(struct i2c_msg *msgs, int num) ++{ ++ int i, ret = 0; ++ ++ if (!msgs) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ for (i = 0; i < num; ++i) { ++ if (!msgs[i].buf) { ++ ret = -EFAULT; ++ goto out; ++ } ++ } ++ ++out: ++ return ret; ++} ++ ++static void ocores_process(struct ocores_i2c *i2c, u8 stat) ++{ ++ struct i2c_msg *msg = i2c->msg; ++ ++ OCORES_I2C_XFER("Enter nr %d.\n", i2c->adap.nr); ++ 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); ++ OCORES_I2C_XFER("stop has been sent, exit.\n"); ++ goto out; ++ } ++ ++ /* error? */ ++ if (stat & OCI2C_STAT_ARBLOST) { ++ i2c->state = STATE_ERROR; ++ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); ++ OCORES_I2C_XFER("error exit, lose arbitration.\n"); ++ goto out; ++ } ++ ++ if (ocores_msg_check(i2c->msg, i2c->nmsgs) != 0) { ++ OCORES_I2C_XFER("msg buf is NULL\n"); ++ i2c->state = STATE_ERROR; ++ 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; ++ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); ++ OCORES_I2C_XFER("OCI2C_STAT_NACK, exit.\n"); ++ goto out; ++ } ++ } else { ++ msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA); ++ } ++ ++ /* end of msg? */ ++ if (i2c->pos == msg->len) { ++ OCORES_I2C_XFER("Enter end of msg.\n"); ++ 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); ++ OCORES_I2C_XFER("send start, exit.\n"); ++ 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); ++ OCORES_I2C_XFER("send OCI2C_CMD_STOP, exit.\n"); ++ 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: ++ OCORES_I2C_XFER("normal, exit nr %d.\n", i2c->adap.nr); ++ return; ++} ++ ++static irqreturn_t ocores_isr(int irq, void *dev_id) ++{ ++ struct ocores_i2c *i2c = dev_id; ++ u8 stat; ++ unsigned long flags; ++ ++ if (!i2c) { ++ return IRQ_NONE; ++ } ++ ++ spin_lock_irqsave(&i2c->process_lock, flags); ++ stat = oc_getreg(i2c, OCI2C_STATUS); ++ if (!(stat & OCI2C_STAT_IF)) { ++ spin_unlock_irqrestore(&i2c->process_lock, flags); ++ return IRQ_NONE; ++ } ++ OCORES_I2C_XFER("Enter, irq %d nr %d addr 0x%x.\n", irq, i2c->adap.nr, (!i2c->msg)? 0 : i2c->msg->addr); ++ ocores_process(i2c, stat); ++ OCORES_I2C_XFER("Leave, irq %d nr %d addr 0x%x.\n", irq, i2c->adap.nr, (!i2c->msg)? 0 : i2c->msg->addr); ++ spin_unlock_irqrestore(&i2c->process_lock, flags); ++ ++ 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); ++ mdelay(1); ++ spin_unlock_irqrestore(&i2c->process_lock, flags); ++ return; ++} ++ ++/** ++ * 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) ++{ ++ u8 status; ++ unsigned long j, jiffies_tmp; ++ unsigned int usleep; ++ ++ usleep = OCORE_WAIT_SCH; ++ j = jiffies + timeout; ++ while (1) { ++ jiffies_tmp = jiffies; ++ status = oc_getreg(i2c, reg); ++ ++ if ((status & mask) == val) { ++ break; ++ } ++ ++ if (time_after(jiffies_tmp, j)) { ++ OCORES_I2C_XFER("STATUS timeout, mask[0x%x] val[0x%x] status[0x%x]\n", mask, val, status); ++ return -ETIMEDOUT; ++ } ++ usleep_range(usleep,usleep + 1); ++ } ++ 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 100ms we timeout then something is broken. ++ */ ++ err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, msecs_to_jiffies(100)); ++ if (err) { ++ OCORES_I2C_XFER("STATUS timeout, bit 0x%x did not clear in 100ms, err %d\n", mask, err); ++ } ++ 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 int ocores_process_polling(struct ocores_i2c *i2c) ++{ ++ irqreturn_t ret; ++ int err; ++ ++ while (1) { ++ 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 */ ++ } ++ } ++ ++ return err; ++} ++ ++static int ocores_xfer_core(struct ocores_i2c *i2c, ++ struct i2c_msg *msgs, int num, ++ bool polling) ++{ ++ int ret; ++ u8 ctrl; ++ unsigned long flags; ++ ++ OCORES_I2C_VERBOSE("Enter ocores_xfer_core. polling mode:%d.\n", polling); ++ spin_lock_irqsave(&i2c->process_lock, flags); ++ ++ 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); ++ ++ spin_unlock_irqrestore(&i2c->process_lock, flags); ++ ++ if (polling) { ++ ret = ocores_process_polling(i2c); ++ if (ret) { ++ ocores_process_timeout(i2c); ++ return -ETIMEDOUT; ++ } ++ } 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(struct i2c_adapter *adap, ++ struct i2c_msg *msgs, int num) ++{ ++ struct ocores_i2c *i2c; ++ int ret; ++ ++ OCORES_I2C_VERBOSE("Enter ocores_xfer.\n"); ++ if (!adap || ocores_msg_check(msgs, num)) { ++ OCORES_I2C_ERROR("[MAY BE USER SPACE ERROR]:msg buf is NULL\n"); ++ return -EFAULT; ++ } ++ OCORES_I2C_VERBOSE("i2c bus:%d, msgs num:%d.\n", adap->nr, num); ++ ++ i2c = i2c_get_adapdata(adap); ++ ++ if (i2c->flags & OCORES_FLAG_POLL) { ++ ret = ocores_xfer_core(i2c, msgs, num, true); ++ } else { ++ ret = ocores_xfer_core(i2c, msgs, num, false); ++ } ++ ++ return ret; ++} ++ ++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 const struct i2c_algorithm ocores_algorithm = { ++ .master_xfer = ocores_xfer, ++ .functionality = ocores_func, ++}; ++ ++static const struct i2c_adapter ocores_adapter = { ++ .owner = THIS_MODULE, ++ .name = "wb-i2c-ocores", ++ .class = I2C_CLASS_DEPRECATED, ++ .algo = &ocores_algorithm, ++}; ++ ++static const struct of_device_id ocores_i2c_match[] = { ++ { ++ .compatible = "opencores,wb-i2c-ocores", ++ .data = (void *)TYPE_OCORES, ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ocores_i2c_match); ++ ++static int fpga_ocores_i2c_get_irq(struct ocores_i2c *i2c) ++{ ++ int devfn, irq; ++ struct device *dev; ++ wb_pci_dev_t *wb_pci_dev; ++ struct pci_dev *pci_dev; ++ i2c_ocores_device_t *i2c_ocores_device; ++ int ret; ++ ++ dev = i2c->dev; ++ wb_pci_dev = &i2c->wb_pci_dev; ++ ++ if (dev->of_node) { ++ ret = 0; ++ ret += of_property_read_u32(dev->of_node, "pci_domain", &wb_pci_dev->domain); ++ ret += of_property_read_u32(dev->of_node, "pci_bus", &wb_pci_dev->bus); ++ ret += of_property_read_u32(dev->of_node, "pci_slot", &wb_pci_dev->slot); ++ ret += of_property_read_u32(dev->of_node, "pci_fn", &wb_pci_dev->fn); ++ ++ if (ret != 0) { ++ OCORES_I2C_ERROR("dts config error, ret:%d.\n", ret); ++ ret = -EINVAL; ++ return ret; ++ } ++ } else { ++ if (i2c->dev->platform_data == NULL) { ++ OCORES_I2C_ERROR("Failed to get platform data config.\n"); ++ ret = -EINVAL; ++ return ret; ++ } ++ i2c_ocores_device = i2c->dev->platform_data; ++ wb_pci_dev->domain = i2c_ocores_device->pci_domain; ++ wb_pci_dev->bus = i2c_ocores_device->pci_bus; ++ wb_pci_dev->slot = i2c_ocores_device->pci_slot; ++ wb_pci_dev->fn = i2c_ocores_device->pci_fn; ++ } ++ ++ OCORES_I2C_VERBOSE("pci_domain:0x%x, pci_bus:0x%x, pci_slot:0x%x, pci_fn:0x%x.\n", ++ wb_pci_dev->domain, wb_pci_dev->bus, wb_pci_dev->slot, wb_pci_dev->fn); ++ ++ devfn = PCI_DEVFN(wb_pci_dev->slot, wb_pci_dev->fn); ++ pci_dev = pci_get_domain_bus_and_slot(wb_pci_dev->domain, wb_pci_dev->bus, devfn); ++ if (pci_dev == NULL) { ++ OCORES_I2C_ERROR("Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", ++ wb_pci_dev->domain, wb_pci_dev->bus, devfn); ++ return -ENODEV; ++ } ++ irq = pci_dev->irq + i2c->irq_offset; ++ OCORES_I2C_VERBOSE("get irq no:%d.\n", irq); ++ return irq; ++} ++ ++static int ocores_i2c_config_init(struct ocores_i2c *i2c) ++{ ++ int ret; ++ struct device *dev; ++ i2c_ocores_device_t *i2c_ocores_device; ++ ++ dev = i2c->dev; ++ ret = 0; ++ ++ if (dev->of_node) { ++ ret += of_property_read_string(dev->of_node, "dev_name", &i2c->dev_name); ++ ret += of_property_read_u32(dev->of_node, "dev_base", &i2c->base_addr); ++ ret += of_property_read_u32(dev->of_node, "reg_shift", &i2c->reg_shift); ++ ret += of_property_read_u32(dev->of_node, "reg_io_width", &i2c->reg_io_width); ++ ret += of_property_read_u32(dev->of_node, "ip_clock_khz", &i2c->ip_clock_khz); ++ ret += of_property_read_u32(dev->of_node, "bus_clock_khz", &i2c->bus_clock_khz); ++ ret += of_property_read_u32(dev->of_node, "reg_access_mode", &i2c->reg_access_mode); ++ ++ if (ret != 0) { ++ OCORES_I2C_ERROR("dts config error, ret:%d.\n", ret); ++ ret = -ENXIO; ++ return ret; ++ } ++ } else { ++ if (i2c->dev->platform_data == NULL) { ++ OCORES_I2C_ERROR("Failed to get platform data config.\n"); ++ ret = -ENXIO; ++ return ret; ++ } ++ i2c_ocores_device = i2c->dev->platform_data; ++ i2c->dev_name = i2c_ocores_device->dev_name; ++ i2c->adap_nr = i2c_ocores_device->adap_nr; ++ i2c->big_endian = i2c_ocores_device->big_endian; ++ i2c->base_addr = i2c_ocores_device->dev_base; ++ i2c->reg_shift = i2c_ocores_device->reg_shift; ++ i2c->reg_io_width = i2c_ocores_device->reg_io_width; ++ i2c->ip_clock_khz = i2c_ocores_device->ip_clock_khz; ++ i2c->bus_clock_khz = i2c_ocores_device->bus_clock_khz; ++ i2c->reg_access_mode = i2c_ocores_device->reg_access_mode; ++ } ++ ++ OCORES_I2C_VERBOSE("name:%s, base:0x%x, reg_shift:0x%x, io_width:0x%x, ip_clock_khz:0x%x, bus_clock_khz:0x%x.\n", ++ i2c->dev_name, i2c->base_addr, i2c->reg_shift, i2c->reg_io_width, i2c->ip_clock_khz, i2c->bus_clock_khz); ++ OCORES_I2C_VERBOSE("reg access mode:%d.\n", i2c->reg_access_mode); ++ return ret; ++} ++ ++static int ocores_i2c_probe(struct platform_device *pdev) ++{ ++ struct ocores_i2c *i2c; ++ int irq, ret; ++ bool be; ++ i2c_ocores_device_t *i2c_ocores_device; ++ ++ OCORES_I2C_VERBOSE("Enter main probe\n"); ++ ++ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); ++ if (!i2c) { ++ dev_err(&pdev->dev, "devm_kzalloc failed.\n"); ++ return -ENOMEM; ++ } ++ ++ spin_lock_init(&i2c->process_lock); ++ ++ i2c->dev = &pdev->dev; ++ ret = ocores_i2c_config_init(i2c); ++ if (ret !=0) { ++ dev_err(i2c->dev, "Failed to get ocores i2c dts config.\n"); ++ goto out; ++ } ++ ++ if (i2c->dev->of_node) { ++ if (of_property_read_u32(i2c->dev->of_node, "big_endian", &i2c->big_endian)) { ++ ++ be = 0; ++ } else { ++ be = i2c->big_endian; ++ } ++ } else { ++ be = i2c->big_endian; ++ } ++ ++ if (i2c->reg_io_width == 0) { ++ i2c->reg_io_width = 1; /* Set to default value */ ++ } ++ ++ if (!i2c->setreg || !i2c->getreg) { ++ switch (i2c->reg_io_width) { ++ case REG_IO_WIDTH_1: ++ i2c->setreg = oc_setreg_8; ++ i2c->getreg = oc_getreg_8; ++ break; ++ ++ case REG_IO_WIDTH_2: ++ i2c->setreg = be ? oc_setreg_16be : oc_setreg_16; ++ i2c->getreg = be ? oc_getreg_16be : oc_getreg_16; ++ break; ++ ++ case REG_IO_WIDTH_4: ++ i2c->setreg = be ? oc_setreg_32be : oc_setreg_32; ++ i2c->getreg = be ? oc_getreg_32be : oc_getreg_32; ++ break; ++ ++ default: ++ dev_err(i2c->dev, "Unsupported I/O width (%d)\n", ++ i2c->reg_io_width); ++ ret = -EINVAL; ++ goto out; ++ } ++ } ++ ++ init_waitqueue_head(&i2c->wait); ++ irq = -1; ++ ++ if (i2c->dev->of_node) { ++ if (of_property_read_u32(i2c->dev->of_node, "irq_offset", &i2c->irq_offset)) { ++ ++ i2c->flags |= OCORES_FLAG_POLL; ++ } else { ++ ++ irq = fpga_ocores_i2c_get_irq(i2c); ++ if (irq < 0 ) { ++ dev_err(i2c->dev, "Failed to get ocores i2c irq number, ret: %d.\n", irq); ++ ret = irq; ++ goto out; ++ } ++ } ++ } else { ++ if (i2c->dev->platform_data == NULL) { ++ ++ i2c->flags |= OCORES_FLAG_POLL; ++ OCORES_I2C_VERBOSE("Failed to get platform data config, set OCORES_FLAG_POLL.\n"); ++ } else { ++ i2c_ocores_device = i2c->dev->platform_data; ++ if (i2c_ocores_device->irq_type == 0) { ++ ++ i2c->flags |= OCORES_FLAG_POLL; ++ } else { ++ ++ irq = fpga_ocores_i2c_get_irq(i2c); ++ if (irq < 0 ) { ++ dev_err(i2c->dev, "Failed to get ocores i2c irq number, ret: %d.\n", irq); ++ ret = irq; ++ goto out; ++ } ++ } ++ } ++ } ++ ++ if (!(i2c->flags & OCORES_FLAG_POLL)) { ++ ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, ++ pdev->name, i2c); ++ if (ret) { ++ dev_err(i2c->dev, "Cannot claim IRQ\n"); ++ goto out; ++ } ++ } ++ ++ ret = ocores_init(i2c->dev, i2c); ++ if (ret) { ++ goto out; ++ } ++ ++ /* 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; ++ i2c->adap.dev.of_node = pdev->dev.of_node; ++ ++ if (i2c->dev->of_node) { ++ /* adap.nr get from dts aliases */ ++ ret = i2c_add_adapter(&i2c->adap); ++ } else { ++ i2c->adap.nr = i2c->adap_nr; ++ ret = i2c_add_numbered_adapter(&i2c->adap); ++ } ++ if (ret) { ++ goto fail_add; ++ } ++ OCORES_I2C_VERBOSE("Main probe out\n"); ++ dev_info(i2c->dev, "registered i2c-%d for %s with base address:0x%x success.\n", ++ i2c->adap.nr, i2c->dev_name, i2c->base_addr); ++ return 0; ++fail_add: ++ platform_set_drvdata(pdev, NULL); ++out: ++ return ret; ++} ++ ++static int 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); ++ return 0; ++} ++ ++static struct platform_driver ocores_i2c_driver = { ++ .probe = ocores_i2c_probe, ++ .remove = ocores_i2c_remove, ++ .driver = { ++ .name = "wb-ocores-i2c", ++ .of_match_table = ocores_i2c_match, ++ }, ++}; ++ ++module_platform_driver(ocores_i2c_driver); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("OpenCores I2C bus driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ocores-i2c"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.h +new file mode 100644 +index 000000000..acd2710a9 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.h +@@ -0,0 +1,28 @@ ++#ifndef __WB_I2C_OCORES_H__ ++#define __WB_I2C_OCORES_H__ ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++#define I2C_OCORES_DEV_NAME_MAX_LEN (64) ++ ++typedef struct i2c_ocores_device_s { ++ uint32_t big_endian; ++ char dev_name[I2C_OCORES_DEV_NAME_MAX_LEN]; ++ int adap_nr; ++ uint32_t dev_base; ++ uint32_t reg_shift; ++ uint32_t reg_io_width; ++ uint32_t ip_clock_khz; ++ uint32_t bus_clock_khz; ++ uint32_t reg_access_mode; ++ ++ uint32_t irq_type; ++ uint32_t irq_offset; ++ uint32_t pci_domain; ++ uint32_t pci_bus; ++ uint32_t pci_slot; ++ uint32_t pci_fn; ++ int device_flag; ++} i2c_ocores_device_t; ++ ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.c +new file mode 100644 +index 000000000..b1f5294b8 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.c +@@ -0,0 +1,571 @@ ++/* ++ * wb_io_dev.c ++ * ko to read/write ioports through /dev/XXX device ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wb_io_dev.h" ++ ++#define PROXY_NAME "wb-io-dev" ++#define MAX_IO_DEV_NUM (256) ++#define IO_RDWR_MAX_LEN (256) ++#define MAX_NAME_SIZE (20) ++#define IO_INDIRECT_ADDR_H(addr) ((addr >> 8) & 0xff) ++#define IO_INDIRECT_ADDR_L(addr) ((addr) & 0xff) ++#define IO_INDIRECT_OP_WRITE (0x2) ++#define IO_INDIRECT_OP_READ (0X3) ++ ++static int g_io_dev_debug = 0; ++static int g_io_dev_error = 0; ++ ++module_param(g_io_dev_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_io_dev_error, int, S_IRUGO | S_IWUSR); ++ ++#define IO_DEV_DEBUG_VERBOSE(fmt, args...) do { \ ++ if (g_io_dev_debug) { \ ++ printk(KERN_INFO "[IO_DEV][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define IO_DEV_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_io_dev_error) { \ ++ printk(KERN_ERR "[IO_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++typedef struct wb_io_dev_s { ++ const char *name; ++ uint32_t io_base; ++ uint32_t io_len; ++ uint32_t indirect_addr; ++ uint32_t wr_data; ++ uint32_t addr_low; ++ uint32_t addr_high; ++ uint32_t rd_data; ++ uint32_t opt_ctl; ++ spinlock_t io_dev_lock; ++ struct miscdevice misc; ++} wb_io_dev_t; ++ ++static wb_io_dev_t* io_dev_arry[MAX_IO_DEV_NUM]; ++ ++static int io_dev_open(struct inode *inode, struct file *file) ++{ ++ unsigned int minor = iminor(inode); ++ wb_io_dev_t *wb_io_dev; ++ ++ if (minor >= MAX_IO_DEV_NUM) { ++ IO_DEV_DEBUG_ERROR("minor out of range, minor = %d.\n", minor); ++ return -ENODEV; ++ } ++ ++ wb_io_dev = io_dev_arry[minor]; ++ if (wb_io_dev == NULL) { ++ IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, open failed, minor = %d\n", minor); ++ return -ENODEV; ++ } ++ ++ file->private_data = wb_io_dev; ++ return 0; ++} ++ ++static int io_dev_release(struct inode *inode, struct file *file) ++{ ++ file->private_data = NULL; ++ return 0; ++} ++ ++uint8_t io_indirect_addressing_read(wb_io_dev_t *wb_io_dev, uint32_t address) ++{ ++ uint8_t addr_l, addr_h, value; ++ unsigned long flags; ++ ++ addr_h = IO_INDIRECT_ADDR_H(address); ++ addr_l = IO_INDIRECT_ADDR_L(address); ++ IO_DEV_DEBUG_VERBOSE("read one count, addr = 0x%x\n", address); ++ ++ spin_lock_irqsave(&wb_io_dev->io_dev_lock, flags); ++ ++ outb(addr_l, wb_io_dev->io_base + wb_io_dev->addr_low); ++ ++ outb(addr_h, wb_io_dev->io_base + wb_io_dev->addr_high); ++ ++ outb(IO_INDIRECT_OP_READ, wb_io_dev->io_base + wb_io_dev->opt_ctl); ++ ++ value = inb(wb_io_dev->io_base + wb_io_dev->rd_data); ++ ++ spin_unlock_irqrestore(&wb_io_dev->io_dev_lock, flags); ++ ++ return value; ++} ++ ++static int io_dev_read_tmp(wb_io_dev_t *wb_io_dev, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ int i; ++ ++ if (offset > wb_io_dev->io_len) { ++ IO_DEV_DEBUG_VERBOSE("offset:0x%x, io len:0x%x, EOF.\n", offset, wb_io_dev->io_len); ++ return 0; ++ } ++ ++ if (count > wb_io_dev->io_len - offset) { ++ IO_DEV_DEBUG_VERBOSE("read count out of range. input len:%lu, read len:%u.\n", ++ count, wb_io_dev->io_len - offset); ++ count = wb_io_dev->io_len - offset; ++ } ++ if (wb_io_dev->indirect_addr) { ++ for (i = 0; i < count; i++) { ++ buf[i] = io_indirect_addressing_read(wb_io_dev, offset + i); ++ } ++ } else { ++ for (i = 0; i < count; i++) { ++ buf[i] = inb(wb_io_dev->io_base + offset + i); ++ } ++ } ++ ++ return count; ++} ++ ++static ssize_t io_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) ++{ ++ wb_io_dev_t *wb_io_dev; ++ int ret, read_len; ++ u8 buf_tmp[IO_RDWR_MAX_LEN]; ++ ++ wb_io_dev = file->private_data; ++ if (wb_io_dev == NULL) { ++ IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, read failed.\n"); ++ return -EINVAL; ++ } ++ ++ if (count == 0) { ++ IO_DEV_DEBUG_ERROR("Invalid params, read count is 0.\n"); ++ return -EINVAL; ++ } ++ ++ if (count > sizeof(buf_tmp)) { ++ IO_DEV_DEBUG_VERBOSE("read count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); ++ count = sizeof(buf_tmp); ++ } ++ ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ read_len = io_dev_read_tmp(wb_io_dev, *offset, buf_tmp, count); ++ if (read_len < 0) { ++ IO_DEV_DEBUG_ERROR("io_dev_read_tmp failed, ret:%d.\n", read_len); ++ return read_len; ++ } ++ ++ if (access_ok(buf, read_len)) { ++ IO_DEV_DEBUG_VERBOSE("user space read, buf: %p, offset: %lld, read count %lu.\n", ++ buf, *offset, count); ++ if (copy_to_user(buf, buf_tmp, read_len)) { ++ IO_DEV_DEBUG_ERROR("copy_to_user failed.\n"); ++ return -EFAULT; ++ } ++ } else { ++ IO_DEV_DEBUG_VERBOSE("kernel space read, buf: %p, offset: %lld, read count %lu.\n", ++ buf, *offset, count); ++ memcpy(buf, buf_tmp, read_len); ++ } ++ *offset += read_len; ++ ret = read_len; ++ return ret; ++} ++ ++static ssize_t io_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) ++{ ++ int ret; ++ ++ IO_DEV_DEBUG_VERBOSE("io_dev_read_iter, file: %p, count: %lu, offset: %lld\n", ++ iocb->ki_filp, to->count, iocb->ki_pos); ++ ret = io_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos); ++ return ret; ++} ++ ++void io_indirect_addressing_write(wb_io_dev_t *wb_io_dev, uint32_t address, uint8_t reg_val) ++{ ++ uint8_t addr_l, addr_h; ++ unsigned long flags; ++ ++ addr_h = IO_INDIRECT_ADDR_H(address); ++ addr_l = IO_INDIRECT_ADDR_L(address); ++ IO_DEV_DEBUG_VERBOSE("write one count, addr = 0x%x\n", address); ++ ++ spin_lock_irqsave(&wb_io_dev->io_dev_lock, flags); ++ ++ outb(reg_val, wb_io_dev->io_base + wb_io_dev->wr_data); ++ ++ outb(addr_l, wb_io_dev->io_base + wb_io_dev->addr_low); ++ ++ outb(addr_h, wb_io_dev->io_base + wb_io_dev->addr_high); ++ ++ outb(IO_INDIRECT_OP_WRITE, wb_io_dev->io_base + wb_io_dev->opt_ctl); ++ ++ spin_unlock_irqrestore(&wb_io_dev->io_dev_lock, flags); ++ ++ return; ++} ++ ++static int io_dev_write_tmp(wb_io_dev_t *wb_io_dev, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ int i; ++ ++ if (offset > wb_io_dev->io_len) { ++ IO_DEV_DEBUG_VERBOSE("offset:0x%x, io len:0x%x, EOF.\n", offset, wb_io_dev->io_len); ++ return 0; ++ } ++ ++ if (count > wb_io_dev->io_len - offset) { ++ IO_DEV_DEBUG_VERBOSE("write count out of range. input len:%lu, write len:%u.\n", ++ count, wb_io_dev->io_len - offset); ++ count = wb_io_dev->io_len - offset; ++ } ++ if (wb_io_dev->indirect_addr) { ++ for (i = 0; i < count; i++) { ++ io_indirect_addressing_write(wb_io_dev, offset + i, buf[i]); ++ } ++ } else { ++ for (i = 0; i < count; i++) { ++ outb(buf[i], wb_io_dev->io_base + offset + i); ++ } ++ } ++ ++ return count; ++} ++ ++static ssize_t io_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) ++{ ++ wb_io_dev_t *wb_io_dev; ++ int write_len; ++ u8 buf_tmp[IO_RDWR_MAX_LEN]; ++ ++ wb_io_dev = file->private_data; ++ if (wb_io_dev == NULL) { ++ IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, write failed.\n"); ++ return -EINVAL; ++ } ++ ++ if (count == 0) { ++ IO_DEV_DEBUG_ERROR("Invalid params, write count is 0.\n"); ++ return -EINVAL; ++ } ++ ++ if (count > sizeof(buf_tmp)) { ++ IO_DEV_DEBUG_VERBOSE("write count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); ++ count = sizeof(buf_tmp); ++ } ++ ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ if (access_ok(buf, count)) { ++ IO_DEV_DEBUG_VERBOSE("user space write, buf: %p, offset: %lld, write count %lu.\n", ++ buf, *offset, count); ++ if (copy_from_user(buf_tmp, buf, count)) { ++ IO_DEV_DEBUG_ERROR("copy_from_user failed.\n"); ++ return -EFAULT; ++ } ++ } else { ++ IO_DEV_DEBUG_VERBOSE("kernel space write, buf: %p, offset: %lld, write count %lu.\n", ++ buf, *offset, count); ++ memcpy(buf_tmp, buf, count); ++ } ++ ++ write_len = io_dev_write_tmp(wb_io_dev, *offset, buf_tmp, count); ++ if (write_len < 0) { ++ IO_DEV_DEBUG_ERROR("io_dev_write_tmp failed, ret:%d.\n", write_len); ++ return write_len; ++ } ++ ++ *offset += write_len; ++ return write_len; ++} ++ ++static ssize_t io_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) ++{ ++ int ret; ++ ++ IO_DEV_DEBUG_VERBOSE("io_dev_write_iter, file: %p, count: %lu, offset: %lld\n", ++ iocb->ki_filp, from->count, iocb->ki_pos); ++ ret = io_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos); ++ return ret; ++} ++ ++static loff_t io_dev_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t ret = 0; ++ wb_io_dev_t *wb_io_dev; ++ ++ wb_io_dev = file->private_data; ++ if (wb_io_dev == NULL) { ++ IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, llseek failed.\n"); ++ return -EINVAL; ++ } ++ ++ switch (origin) { ++ case SEEK_SET: ++ if (offset < 0) { ++ IO_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); ++ ret = -EINVAL; ++ break; ++ } ++ if (offset > wb_io_dev->io_len) { ++ IO_DEV_DEBUG_ERROR("SEEK_SET out of range, offset:%lld, io_len:0x%x.\n", ++ offset, wb_io_dev->io_len); ++ ret = - EINVAL; ++ break; ++ } ++ file->f_pos = offset; ++ ret = file->f_pos; ++ break; ++ case SEEK_CUR: ++ if (((file->f_pos + offset) > wb_io_dev->io_len) || ((file->f_pos + offset) < 0)) { ++ IO_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld, io_len:0x%x.\n", ++ file->f_pos, offset, wb_io_dev->io_len); ++ ret = - EINVAL; ++ break; ++ } ++ file->f_pos += offset; ++ ret = file->f_pos; ++ break; ++ default: ++ IO_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++static long io_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ return 0; ++} ++ ++static const struct file_operations io_dev_fops = { ++ .owner = THIS_MODULE, ++ .llseek = io_dev_llseek, ++ .read_iter = io_dev_read_iter, ++ .write_iter = io_dev_write_iter, ++ .unlocked_ioctl = io_dev_ioctl, ++ .open = io_dev_open, ++ .release = io_dev_release, ++}; ++ ++static wb_io_dev_t *dev_match(const char *path) ++{ ++ wb_io_dev_t *wb_io_dev; ++ char dev_name[MAX_NAME_SIZE]; ++ int i; ++ ++ for (i = 0; i < MAX_IO_DEV_NUM; i++) { ++ if (io_dev_arry[i] == NULL) { ++ continue; ++ } ++ wb_io_dev = io_dev_arry[i]; ++ snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", wb_io_dev->name); ++ if (!strcmp(path, dev_name)) { ++ IO_DEV_DEBUG_VERBOSE("get dev_name = %s, minor = %d\n", dev_name, i); ++ return wb_io_dev; ++ } ++ } ++ ++ return NULL; ++} ++ ++int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ wb_io_dev_t *wb_io_dev; ++ int read_len; ++ ++ if (path == NULL) { ++ IO_DEV_DEBUG_ERROR("path NULL"); ++ return -EINVAL; ++ } ++ ++ if (buf == NULL) { ++ IO_DEV_DEBUG_ERROR("buf NULL"); ++ return -EINVAL; ++ } ++ ++ wb_io_dev = dev_match(path); ++ if (wb_io_dev == NULL) { ++ IO_DEV_DEBUG_ERROR("io_dev match failed. dev path = %s", path); ++ return -EINVAL; ++ } ++ ++ read_len = io_dev_read_tmp(wb_io_dev, offset, buf, count); ++ if (read_len < 0) { ++ IO_DEV_DEBUG_ERROR("io_dev_read_tmp failed, ret:%d.\n", read_len); ++ } ++ return read_len; ++} ++EXPORT_SYMBOL(io_device_func_read); ++ ++int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ wb_io_dev_t *wb_io_dev; ++ int write_len; ++ ++ if (path == NULL) { ++ IO_DEV_DEBUG_ERROR("path NULL"); ++ return -EINVAL; ++ } ++ ++ if (buf == NULL) { ++ IO_DEV_DEBUG_ERROR("buf NULL"); ++ return -EINVAL; ++ } ++ ++ wb_io_dev = dev_match(path); ++ if (wb_io_dev == NULL) { ++ IO_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); ++ return -EINVAL; ++ } ++ ++ write_len = io_dev_write_tmp(wb_io_dev, offset, buf, count); ++ if (write_len < 0) { ++ IO_DEV_DEBUG_ERROR("io_dev_write_tmp failed, ret:%d.\n", write_len); ++ } ++ return write_len; ++} ++EXPORT_SYMBOL(io_device_func_write); ++ ++static int io_dev_probe(struct platform_device *pdev) ++{ ++ int ret; ++ wb_io_dev_t *wb_io_dev; ++ struct miscdevice *misc; ++ io_dev_device_t *io_dev_device; ++ ++ wb_io_dev = devm_kzalloc(&pdev->dev, sizeof(wb_io_dev_t), GFP_KERNEL); ++ if (!wb_io_dev) { ++ dev_err(&pdev->dev, "devm_kzalloc failed.\n"); ++ ret = -ENOMEM; ++ return ret; ++ } ++ spin_lock_init(&wb_io_dev->io_dev_lock); ++ ++ if (pdev->dev.of_node) { ++ ret = 0; ++ ret += of_property_read_string(pdev->dev.of_node, "io_dev_name", &wb_io_dev->name); ++ ret += of_property_read_u32(pdev->dev.of_node, "io_base", &wb_io_dev->io_base); ++ ret += of_property_read_u32(pdev->dev.of_node, "io_len", &wb_io_dev->io_len); ++ if (of_property_read_bool(pdev->dev.of_node, "indirect_addr")) { ++ ++ wb_io_dev->indirect_addr = 1; ++ ret += of_property_read_u32(pdev->dev.of_node, "wr_data", &wb_io_dev->wr_data); ++ ret += of_property_read_u32(pdev->dev.of_node, "addr_low", &wb_io_dev->addr_low); ++ ret += of_property_read_u32(pdev->dev.of_node, "addr_high", &wb_io_dev->addr_high); ++ ret += of_property_read_u32(pdev->dev.of_node, "rd_data", &wb_io_dev->rd_data); ++ ret += of_property_read_u32(pdev->dev.of_node, "opt_ctl", &wb_io_dev->opt_ctl); ++ } else { ++ ++ wb_io_dev->indirect_addr = 0; ++ } ++ if (ret != 0) { ++ dev_err(&pdev->dev, "Failed to get dts config, ret:%d.\n", ret); ++ return -ENXIO; ++ } ++ } else { ++ if (pdev->dev.platform_data == NULL) { ++ dev_err(&pdev->dev, "Failed to get platform data config.\n"); ++ return -ENXIO; ++ } ++ io_dev_device = pdev->dev.platform_data; ++ wb_io_dev->name = io_dev_device->io_dev_name; ++ wb_io_dev->io_base = io_dev_device->io_base; ++ wb_io_dev->io_len = io_dev_device->io_len; ++ wb_io_dev->indirect_addr = io_dev_device->indirect_addr; ++ if (wb_io_dev->indirect_addr == 1) { ++ wb_io_dev->wr_data = io_dev_device->wr_data; ++ wb_io_dev->addr_low = io_dev_device->addr_low; ++ wb_io_dev->addr_high = io_dev_device->addr_high; ++ wb_io_dev->rd_data = io_dev_device->rd_data; ++ wb_io_dev->opt_ctl = io_dev_device->opt_ctl; ++ } ++ } ++ ++ IO_DEV_DEBUG_VERBOSE("name:%s, io base:0x%x, io len:0x%x, addressing type:%s.\n", ++ wb_io_dev->name, wb_io_dev->io_base, wb_io_dev->io_len, ++ wb_io_dev->indirect_addr ? "indirect" : "direct"); ++ ++ misc = &wb_io_dev->misc; ++ misc->minor = MISC_DYNAMIC_MINOR; ++ misc->name = wb_io_dev->name; ++ misc->fops = &io_dev_fops; ++ misc->mode = 0666; ++ if (misc_register(misc) != 0) { ++ dev_err(&pdev->dev, "Failed to register %s device.\n", misc->name); ++ return -ENXIO; ++ } ++ if (misc->minor >= MAX_IO_DEV_NUM) { ++ dev_err(&pdev->dev, "Error: device minor[%d] more than max io device num[%d].\n", ++ misc->minor, MAX_IO_DEV_NUM); ++ misc_deregister(misc); ++ return -EINVAL; ++ } ++ io_dev_arry[misc->minor] = wb_io_dev; ++ dev_info(&pdev->dev, "register %s device [0x%x][0x%x] with minor %d using %s addressing success.\n", ++ misc->name, wb_io_dev->io_base, wb_io_dev->io_len, misc->minor, ++ wb_io_dev->indirect_addr ? "indirect" : "direct"); ++ ++ return 0; ++} ++ ++static int io_dev_remove(struct platform_device *pdev) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_IO_DEV_NUM ; i++) { ++ if (io_dev_arry[i] != NULL) { ++ misc_deregister(&io_dev_arry[i]->misc); ++ io_dev_arry[i] = NULL; ++ } ++ } ++ ++ return 0; ++} ++ ++static struct of_device_id io_dev_match[] = { ++ { ++ .compatible = "wb-io-dev", ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, io_dev_match); ++ ++static struct platform_driver wb_io_dev_driver = { ++ .probe = io_dev_probe, ++ .remove = io_dev_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = PROXY_NAME, ++ .of_match_table = io_dev_match, ++ }, ++}; ++ ++static int __init wb_io_dev_init(void) ++{ ++ return platform_driver_register(&wb_io_dev_driver); ++} ++ ++static void __exit wb_io_dev_exit(void) ++{ ++ platform_driver_unregister(&wb_io_dev_driver); ++} ++ ++module_init(wb_io_dev_init); ++module_exit(wb_io_dev_exit); ++MODULE_DESCRIPTION("IO device driver"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.h +new file mode 100644 +index 000000000..3a1a10f0f +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.h +@@ -0,0 +1,21 @@ ++#ifndef __WB_IO_DEV_H__ ++#define __WB_IO_DEV_H__ ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++#define IO_DEV_NAME_MAX_LEN (64) ++ ++typedef struct io_dev_device_s { ++ char io_dev_name[IO_DEV_NAME_MAX_LEN]; ++ uint32_t io_base; ++ uint32_t io_len; ++ uint32_t indirect_addr; ++ uint32_t wr_data; ++ uint32_t addr_low; ++ uint32_t addr_high; ++ uint32_t rd_data; ++ uint32_t opt_ctl; ++ int device_flag; ++} io_dev_device_t; ++ ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.c +new file mode 100644 +index 000000000..c079dc409 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.c +@@ -0,0 +1,166 @@ ++/* ++ * wb_lpc_drv.c ++ * ko to set lpc pcie config io addr and enable lpc ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wb_lpc_drv.h" ++ ++#define LPC_DRIVER_NAME "wb-lpc" ++#define LPC_MAKE_PCI_IO_RANGE(__base) ((0xfc0001) | ((__base) & (0xFFFC))) ++ ++int g_lpc_dev_debug = 0; ++int g_lpc_dev_error = 0; ++ ++module_param(g_lpc_dev_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_lpc_dev_error, int, S_IRUGO | S_IWUSR); ++ ++#define LPC_DEV_DEBUG_VERBOSE(fmt, args...) do { \ ++ if (g_lpc_dev_debug) { \ ++ printk(KERN_INFO "[LPC_DEV][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define LPC_DEV_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_lpc_dev_error) { \ ++ printk(KERN_ERR "[LPC_DEV][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++typedef struct wb_lpc_dev_s { ++ const char *lpc_io_name; ++ uint32_t domain; ++ uint32_t bus; ++ uint32_t slot; ++ uint32_t fn; ++ uint32_t lpc_io_base; ++ uint32_t lpc_io_size; ++ uint32_t lpc_gen_dec; ++} wb_lpc_dev_t; ++ ++static int wb_lpc_probe(struct platform_device *pdev) ++{ ++ int ret, devfn; ++ wb_lpc_dev_t *wb_lpc_dev; ++ struct pci_dev *pci_dev; ++ lpc_drv_device_t *lpc_drv_device; ++ ++ wb_lpc_dev = devm_kzalloc(&pdev->dev, sizeof(wb_lpc_dev_t), GFP_KERNEL); ++ if (!wb_lpc_dev) { ++ dev_err(&pdev->dev, "devm_kzalloc failed.\n"); ++ ret = -ENOMEM; ++ return ret; ++ } ++ ++ if (pdev->dev.of_node) { ++ ret = 0; ++ ret += of_property_read_string(pdev->dev.of_node, "lpc_io_name", &wb_lpc_dev->lpc_io_name); ++ ret += of_property_read_u32(pdev->dev.of_node, "pci_domain", &wb_lpc_dev->domain); ++ ret += of_property_read_u32(pdev->dev.of_node, "pci_bus", &wb_lpc_dev->bus); ++ ret += of_property_read_u32(pdev->dev.of_node, "pci_slot", &wb_lpc_dev->slot); ++ ret += of_property_read_u32(pdev->dev.of_node, "pci_fn", &wb_lpc_dev->fn); ++ ret += of_property_read_u32(pdev->dev.of_node, "lpc_io_base", &wb_lpc_dev->lpc_io_base); ++ ret += of_property_read_u32(pdev->dev.of_node, "lpc_io_size", &wb_lpc_dev->lpc_io_size); ++ ret += of_property_read_u32(pdev->dev.of_node, "lpc_gen_dec", &wb_lpc_dev->lpc_gen_dec); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "Failed to get dts config, ret:%d.\n", ret); ++ return -ENXIO; ++ } ++ } else { ++ if (pdev->dev.platform_data == NULL) { ++ dev_err(&pdev->dev, "Failed to get platform data config.\n"); ++ return -ENXIO; ++ } ++ lpc_drv_device = pdev->dev.platform_data; ++ wb_lpc_dev->lpc_io_name = lpc_drv_device->lpc_io_name; ++ wb_lpc_dev->domain = lpc_drv_device->pci_domain; ++ wb_lpc_dev->bus = lpc_drv_device->pci_bus; ++ wb_lpc_dev->slot = lpc_drv_device->pci_slot; ++ wb_lpc_dev->fn = lpc_drv_device->pci_fn; ++ wb_lpc_dev->lpc_io_base = lpc_drv_device->lpc_io_base; ++ wb_lpc_dev->lpc_io_size = lpc_drv_device->lpc_io_size; ++ wb_lpc_dev->lpc_gen_dec = lpc_drv_device->lpc_gen_dec; ++ } ++ ++ LPC_DEV_DEBUG_VERBOSE("domain:0x%04x, bus:0x%02x, slot:0x%02x, fn:%u\n", ++ wb_lpc_dev->domain,wb_lpc_dev->bus, wb_lpc_dev->slot, wb_lpc_dev->fn); ++ LPC_DEV_DEBUG_VERBOSE("lpc_io_name:%s, lpc_io_base:0x%x, lpc_io_size:%u, lpc_gen_dec:0x%x.\n", ++ wb_lpc_dev->lpc_io_name, wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size, wb_lpc_dev->lpc_gen_dec); ++ ++ devfn = PCI_DEVFN(wb_lpc_dev->slot, wb_lpc_dev->fn); ++ pci_dev = pci_get_domain_bus_and_slot(wb_lpc_dev->domain, wb_lpc_dev->bus, devfn); ++ if (pci_dev == NULL) { ++ dev_err(&pdev->dev, "Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", ++ wb_lpc_dev->domain, wb_lpc_dev->bus, devfn); ++ return -ENXIO; ++ } ++ ++ pci_write_config_dword(pci_dev, wb_lpc_dev->lpc_gen_dec, LPC_MAKE_PCI_IO_RANGE(wb_lpc_dev->lpc_io_base)); ++ if (!request_region(wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size, wb_lpc_dev->lpc_io_name)) { ++ dev_err(&pdev->dev, "Failed to request_region [0x%x][0x%x].\n", wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size); ++ return -EBUSY; ++ } ++ ++ platform_set_drvdata(pdev, wb_lpc_dev); ++ ++ dev_info(&pdev->dev, "lpc request_region [0x%x][0x%x] success.\n", wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size); ++ ++ return 0; ++} ++ ++static int wb_lpc_remove(struct platform_device *pdev) ++{ ++ wb_lpc_dev_t *wb_lpc_dev; ++ ++ wb_lpc_dev = platform_get_drvdata(pdev); ++ if (wb_lpc_dev) { ++ release_region(wb_lpc_dev->lpc_io_base , wb_lpc_dev->lpc_io_size); ++ LPC_DEV_DEBUG_VERBOSE("lpc base:0x%x, len:0x%x.\n", wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size); ++ } ++ LPC_DEV_DEBUG_VERBOSE("lpc remove.\n"); ++ ++ return 0; ++} ++ ++static struct of_device_id lpc_dev_match[] = { ++ { ++ .compatible = "wb-lpc", ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, lpc_dev_match); ++ ++static struct platform_driver wb_lpc_driver = { ++ .probe = wb_lpc_probe, ++ .remove = wb_lpc_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = LPC_DRIVER_NAME, ++ .of_match_table = lpc_dev_match, ++ }, ++}; ++ ++static int __init wb_lpc_init(void) ++{ ++ return platform_driver_register(&wb_lpc_driver); ++} ++ ++static void __exit wb_lpc_exit(void) ++{ ++ platform_driver_unregister(&wb_lpc_driver); ++} ++ ++module_init(wb_lpc_init); ++module_exit(wb_lpc_exit); ++MODULE_DESCRIPTION("lpc driver"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.h +new file mode 100644 +index 000000000..76e8c32c1 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.h +@@ -0,0 +1,18 @@ ++#ifndef __WB_LPC_DRV_H__ ++#define __WB_LPC_DRV_H__ ++ ++#define LPC_IO_NAME_MAX_LEN (64) ++ ++typedef struct lpc_drv_device_s { ++ char lpc_io_name[LPC_IO_NAME_MAX_LEN]; ++ int pci_domain; ++ int pci_bus; ++ int pci_slot; ++ int pci_fn; ++ int lpc_io_base; ++ int lpc_io_size; ++ int lpc_gen_dec; ++ int device_flag; ++} lpc_drv_device_t; ++ ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mac_bsc.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mac_bsc.c +new file mode 100644 +index 000000000..d72e91ace +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mac_bsc.c +@@ -0,0 +1,845 @@ ++/* ++ * ++ * Copyright (c) 1998, 1999 Frodo Looijaard ++ * ++ * 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 ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++ ++#define MAC_TEMP_INVALID (99999999) ++#define MAC_ID_REG (0x02000000) ++ ++#define MAC_REG_ADDR_WIDTH (4) ++#define MAC_REG_DATA_WIDTH (4) ++#define MAC_BSC_MAX_TEMP_NUM (16) ++#define MAC_BSC_MAX_READ_REG_STEP (6) ++#define MAC_BSC_MAX_SETUP_NUM (1) ++ ++static int g_wb_mac_bsc_debug = 0; ++static int g_wb_mac_bsc_error = 0; ++ ++module_param(g_wb_mac_bsc_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_mac_bsc_error, int, S_IRUGO | S_IWUSR); ++ ++#define WB_MAC_BSC_DEBUG(fmt, args...) do { \ ++ if (g_wb_mac_bsc_debug) { \ ++ printk(KERN_INFO "[MAC_BSC][VER][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_MAC_BSC_ERROR(fmt, args...) do { \ ++ if (g_wb_mac_bsc_error) { \ ++ printk(KERN_ERR "[MAC_BSC][ERR][func:%s line:%d]"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++typedef enum{ ++ MAC_TYPE_START, ++ TD4_X9 = 0xb780, ++ TD4_X9_8 = 0xb788, ++ TH3 = 0xb980, ++ TD3 = 0xb870, ++ TD3_X2 = 0xb274, ++ TD4 = 0xb880, ++ TH4 = 0xb990, ++ MAC_TYPE_END, ++} mac_id; ++ ++typedef enum { ++ MAC_TEMP_START, ++ MAC_TEMP_INDEX1, ++ MAC_TEMP_INDEX2, ++ MAC_TEMP_INDEX3, ++ MAC_TEMP_INDEX4, ++ MAC_TEMP_INDEX5, ++ MAC_TEMP_INDEX6, ++ MAC_TEMP_INDEX7, ++ MAC_TEMP_INDEX8, ++ MAC_TEMP_INDEX9, ++ MAC_TEMP_INDEX10, ++ MAC_TEMP_INDEX11, ++ MAC_TEMP_INDEX12, ++ MAC_TEMP_INDEX13, ++ MAC_TEMP_INDEX14, ++ MAC_TEMP_INDEX15, ++ MAC_TEMP_END, ++} mac_hwmon_index; ++ ++typedef enum action_e { ++ I2C_WRITE, ++ I2C_READ ++} action_t; ++ ++typedef struct i2c_op_s { ++ action_t op; ++ uint32_t reg_addr; ++ uint32_t reg_val; ++ int read_back; ++} i2c_op_t; ++ ++typedef struct dev_params_s { ++ int mac_id; ++ i2c_op_t sbus_setup[MAC_BSC_MAX_SETUP_NUM]; ++ i2c_op_t vtmon_read[MAC_BSC_MAX_READ_REG_STEP]; ++ uint32_t vtmon_reg_addrs[MAC_BSC_MAX_TEMP_NUM]; ++ uint8_t vtmon_instances; ++ uint32_t vtmon_data_width; ++ int vtmon_scalar; ++ int vtmon_offset; ++ uint8_t sbus_setup_ops; ++ int vtmon_read_ops; ++ int sbus_addr_op; ++ int sbus_error_op; ++ uint32_t sbus_error_mask; ++} dev_params_t; ++ ++static dev_params_t mac_temp_conf[] = { ++ { ++ .mac_id = TD3_X2, ++ /* CMIC_TOP_SBUS_RING_MAP_0_7 = 0x52222100 */ ++ .sbus_setup = {{I2C_WRITE, 0x1010000c, 0x52222100, 0}}, ++ .vtmon_read = { ++ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000000 */ ++ {I2C_WRITE, 0x10110400, 0x00000000, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[0] = 0x2c380200 */ ++ {I2C_WRITE, 0x1011040c, 0x2c380200, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] = TOP_PVTMON_RESULT_0 */ ++ {I2C_WRITE, 0x10110410, 0x02005300, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000001 */ ++ {I2C_WRITE, 0x10110400, 0x00000001, 0}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_ERR */ ++ {I2C_READ, 0x10110408}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] */ ++ {I2C_READ, 0x10110410} ++ }, ++ .vtmon_reg_addrs = { ++ 0x02005300, 0x02005400, 0x02005500, 0x02005600, 0x02005700, 0x02005800 ++ }, ++ .vtmon_instances = 6, ++ .vtmon_data_width = 10, ++ .vtmon_scalar = -5570, ++ .vtmon_offset = 4578289, ++ .sbus_setup_ops = 1, ++ .vtmon_read_ops = 6, ++ .sbus_addr_op = 2, ++ .sbus_error_op = 4, ++ .sbus_error_mask = 0x00000041, ++ }, ++ { ++ .mac_id = TD3, /* TD3_X7*/ ++ /* CMIC_TOP_SBUS_RING_MAP_0_7 = 0x52222100 */ ++ .sbus_setup = {{I2C_WRITE, 0x0320000c, 0x52222100, 0}}, ++ .vtmon_read = { ++ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000000 */ ++ {I2C_WRITE, 0x03210400, 0x00000000, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[0] = 0x2c380200 */ ++ {I2C_WRITE, 0x0321040c, 0x2c380200, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] = TOP_PVTMON_RESULT_0 */ ++ {I2C_WRITE, 0x03210410, 0x02004700, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000001 */ ++ {I2C_WRITE, 0x03210400, 0x00000001, 0}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_ERR */ ++ {I2C_READ, 0x03210408}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] */ ++ {I2C_READ, 0x03210410} ++ }, ++ .vtmon_reg_addrs = { ++ 0x02004700, 0x02004800, 0x02004900, 0x02004a00, 0x02004b00, 0x02004c00, ++ 0x02004d00, 0x02004e00, 0x02005200, 0x02005100, 0x02005000, 0x02004f00 ++ }, ++ .vtmon_instances = 12, ++ .vtmon_data_width = 10, ++ .vtmon_scalar = -5350, ++ .vtmon_offset = 4341000, ++ .sbus_setup_ops = 0, ++ .vtmon_read_ops = 6, ++ .sbus_addr_op = 2, ++ .sbus_error_op = 4, ++ .sbus_error_mask = 0x00000041, ++ }, ++ { ++ .mac_id = TH3, ++ .vtmon_read = { ++ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000000 */ ++ {I2C_WRITE, 0x03210400, 0x00000000, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[0] = 0x2c400200 */ ++ {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] = TOP_PVTMON_RESULT_0 */ ++ {I2C_WRITE, 0x03210410, 0x02004a00, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000001 */ ++ {I2C_WRITE, 0x03210400, 0x00000001, 0}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_ERR */ ++ {I2C_READ, 0x03210408}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] */ ++ {I2C_READ, 0x03210410} ++ }, ++ .vtmon_reg_addrs = { ++ 0x02004a00, 0x02004b00, 0x02004c00, 0x02004d00, 0x02004e00, 0x02004f00, ++ 0x02005000, 0x02005100, 0x02005200, 0x02005300, 0x02005400, 0x02005500, ++ 0x02005600, 0x02005700, 0x02005800 ++ }, ++ .vtmon_instances = 15, ++ .vtmon_data_width = 10, ++ .vtmon_scalar = -5350, ++ .vtmon_offset = 4341000, ++ .sbus_setup_ops = 0, ++ .vtmon_read_ops = 6, ++ .sbus_addr_op = 2, ++ .sbus_error_op = -1, ++ }, ++ { ++ .mac_id = TD4_X9, ++ /* CMIC_TOP_SBUS_RING_MAP_8_15r = 0x00000000 */ ++ .sbus_setup = {{I2C_WRITE, 0x03200010, 0x00000000, 0}}, ++ .vtmon_read = { ++ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ ++ {I2C_WRITE, 0x03210400, 0x00000000, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ ++ {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ ++ {I2C_WRITE, 0x03210410, 0x02005a00, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ ++ {I2C_WRITE, 0x03210400, 0x00000001, 0}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ ++ {I2C_READ, 0x03210408}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ ++ {I2C_READ, 0x03210410} ++ }, ++ .vtmon_reg_addrs = { ++ 0x02005a00, 0x02005c00, 0x02005e00, 0x02006000, 0x02006200, 0x02006400, ++ 0x02006600, 0x02006800, 0x02006a00 ++ }, ++ .vtmon_instances = 9, ++ .vtmon_data_width = 11, ++ .vtmon_scalar = -2454, ++ .vtmon_offset = 3668120, ++ .sbus_setup_ops = 0, ++ .vtmon_read_ops = 6, ++ .sbus_addr_op = 2, ++ .sbus_error_op = 4, ++ .sbus_error_mask = 0x00000041, ++ }, ++ { ++ .mac_id = TD4_X9_8, ++ /* CMIC_TOP_SBUS_RING_MAP_8_15r = 0x00000000 */ ++ .sbus_setup = {{I2C_WRITE, 0x03200010, 0x00000000, 0}}, ++ .vtmon_read = { ++ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ ++ {I2C_WRITE, 0x03210400, 0x00000000, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ ++ {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ ++ {I2C_WRITE, 0x03210410, 0x02005a00, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ ++ {I2C_WRITE, 0x03210400, 0x00000001, 0}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ ++ {I2C_READ, 0x03210408}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ ++ {I2C_READ, 0x03210410} ++ }, ++ .vtmon_reg_addrs = { ++ 0x02005a00, 0x02005c00, 0x02005e00, 0x02006000, 0x02006200, 0x02006400, ++ 0x02006600, 0x02006800, 0x02006a00 ++ }, ++ .vtmon_instances = 9, ++ .vtmon_data_width = 11, ++ .vtmon_scalar = -2454, ++ .vtmon_offset = 3668120, ++ .sbus_setup_ops = 0, ++ .vtmon_read_ops = 6, ++ .sbus_addr_op = 2, ++ .sbus_error_op = 4, ++ .sbus_error_mask = 0x00000041, ++ }, ++ { ++ .mac_id = TD4, /* TD4-X11 */ ++ /* CMIC_TOP_SBUS_RING_MAP_8_15r = 0x00000000 */ ++ .sbus_setup = {{I2C_WRITE, 0x03200010, 0x00000000, 0}}, ++ .vtmon_read = { ++ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ ++ {I2C_WRITE, 0x03210400, 0x00000000, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ ++ {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ ++ {I2C_WRITE, 0x03210410, 0x02004900, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ ++ {I2C_WRITE, 0x03210400, 0x00000001, 0}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ ++ {I2C_READ, 0x03210408}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ ++ {I2C_READ, 0x03210410} ++ }, ++ .vtmon_reg_addrs = { ++ 0x02004900, 0x02004b00, 0x02004d00, 0x02004f00, 0x02005100, 0x02005300, ++ 0x02005500, 0x02005700, 0x02005900, 0x02005b00, 0x02005d00, 0x02005f00, ++ 0x02006100, 0x02006300, 0x02006500 ++ }, ++ .vtmon_instances = 15, ++ .vtmon_data_width = 11, ++ .vtmon_scalar = -2454, ++ .vtmon_offset = 3668120, ++ .sbus_setup_ops = 0, ++ .vtmon_read_ops = 6, ++ .sbus_addr_op = 2, ++ .sbus_error_op = 4, ++ .sbus_error_mask = 0x00000041, ++ }, ++ { ++ .mac_id = TH4, ++ .vtmon_read = { ++ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ ++ {I2C_WRITE, 0x03210400, 0x00000000, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ ++ {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ ++ {I2C_WRITE, 0x03210410, 0x0201d800, 1}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ ++ {I2C_WRITE, 0x03210400, 0x00000001, 0}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ ++ {I2C_READ, 0x03210408}, ++ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ ++ {I2C_READ, 0x03210410} ++ }, ++ .vtmon_reg_addrs = { ++ 0x0201d800, 0x0201e000, 0x0201e800, 0x0201f000, 0x0201f800, 0x02020000, ++ 0x02020800, 0x02021000, 0x02021800, 0x02022000, 0x02022800, 0x02023000, ++ 0x02023800, 0x02024000, 0x02024800, ++ }, ++ .vtmon_instances = 15, ++ .vtmon_data_width = 11, ++ .vtmon_scalar = -2454, ++ .vtmon_offset = 3668120, ++ .sbus_setup_ops = 0, ++ .vtmon_read_ops = 6, ++ .sbus_addr_op = 2, ++ .sbus_error_op = -1, ++ }, ++}; ++ ++struct mac_data { ++ struct i2c_client *client; ++ struct device *hwmon_dev; ++ struct mutex update_lock; ++ dev_params_t dev_param; ++}; ++ ++static int bsc_i2c_read(struct i2c_client *client, uint32_t reg_addr, uint32_t *reg_val) ++{ ++ int msgs_num, ret, i; ++ uint8_t addr_buf[MAC_REG_ADDR_WIDTH]; ++ uint8_t data_buf[MAC_REG_DATA_WIDTH]; ++ uint32_t val; ++ struct i2c_msg msgs[2]; ++ ++ for (i = 0; i < MAC_REG_ADDR_WIDTH; i++) { ++ addr_buf[i] = (reg_addr >> ((MAC_REG_ADDR_WIDTH -i -1) * 8)) & 0xff; ++ } ++ ++ mem_clear(msgs, sizeof(msgs)); ++ msgs[0].addr = client->addr; ++ msgs[0].flags = 0; ++ msgs[0].len = MAC_REG_ADDR_WIDTH; ++ msgs[0].buf = addr_buf; ++ ++ msgs[1].addr = client->addr; ++ msgs[1].flags = I2C_M_RD; ++ msgs[1].len = MAC_REG_DATA_WIDTH; ++ msgs[1].buf = data_buf; ++ ++ msgs_num = 2; ++ ret = i2c_transfer(client->adapter, msgs, msgs_num); ++ if (ret != msgs_num) { ++ WB_MAC_BSC_ERROR("i2c_transfer read failed, reg_addr: 0x%x, ret: %d\n", reg_addr, ret); ++ return -EIO; ++ } ++ val = 0; ++ for (i = 0; i < MAC_REG_DATA_WIDTH; i++) { ++ val |= data_buf[i] << ((MAC_REG_DATA_WIDTH - i -1) * 8); ++ } ++ WB_MAC_BSC_DEBUG("bsc_i2c_read success, reg_addr: 0x%x, reg_val: 0x%x\n", reg_addr, val); ++ *reg_val = val; ++ return 0; ++} ++ ++static int bsc_i2c_write(struct i2c_client *client, uint32_t reg_addr, uint32_t reg_val) ++{ ++ int ret, i; ++ uint8_t write_buf[MAC_REG_ADDR_WIDTH + MAC_REG_DATA_WIDTH]; ++ struct i2c_msg msgs[1]; ++ ++ /* fill reg_addr first*/ ++ for (i = 0; i < MAC_REG_ADDR_WIDTH; i++) { ++ write_buf[i] = (reg_addr >> ((MAC_REG_ADDR_WIDTH -i -1) * 8)) & 0xff; ++ } ++ for (i = 0; i < MAC_REG_DATA_WIDTH; i++) { ++ write_buf[i + MAC_REG_ADDR_WIDTH] = (reg_val >> ((MAC_REG_DATA_WIDTH -i -1) * 8)) & 0xff; ++ } ++ ++ mem_clear(msgs, sizeof(msgs)); ++ msgs[0].len = MAC_REG_ADDR_WIDTH + MAC_REG_DATA_WIDTH; ++ msgs[0].buf = write_buf; ++ msgs[0].addr = client->addr; ++ msgs[0].flags = I2C_M_IGNORE_NAK; ++ ++ ret = i2c_transfer(client->adapter, msgs, 1); ++ if (ret < 0) { ++ WB_MAC_BSC_DEBUG("i2c_transfer write failed, reg_addr: 0x%x, reg_val: 0x%x, ret: %d\n", ++ reg_addr, reg_val, ret); ++ return ret; ++ } ++ WB_MAC_BSC_DEBUG("i2c_transfer write reg_addr: 0x%x, reg_val: 0x%x success\n", ++ reg_addr, reg_val); ++ return 0; ++} ++ ++static int handle_operation(struct i2c_client *client, i2c_op_t *operation) ++{ ++ int ret; ++ uint32_t rd_back_val; ++ ++ if (operation->op == I2C_WRITE) { ++ ret = bsc_i2c_write(client, operation->reg_addr, operation->reg_val); ++ WB_MAC_BSC_DEBUG("bsc_i2c_write reg_addr: 0x%x, set val: 0x%x, ret: %d\n", ++ operation->reg_addr, operation->reg_val, ret); ++ if (operation->read_back) { ++ ret = bsc_i2c_read(client, operation->reg_addr, &rd_back_val); ++ if (rd_back_val != operation->reg_val) { ++ WB_MAC_BSC_ERROR("bsc_i2c_write failed, reg_addr: 0x%x, set val: 0x%x, read back valu: 0x%x\n", ++ operation->reg_addr, operation->reg_val, rd_back_val); ++ return -1; ++ } ++ WB_MAC_BSC_DEBUG("bsc_i2c_write success, reg_addr: 0x%x, set val: 0x%x, read_back val: 0x%x\n", ++ operation->reg_addr, operation->reg_val, rd_back_val); ++ } ++ return 0; ++ } ++ ++ if (operation->op == I2C_READ) { ++ ret = bsc_i2c_read(client, operation->reg_addr, &operation->reg_val); ++ WB_MAC_BSC_DEBUG("bsc_i2c_read reg_addr: 0x%x, get val: 0x%x, ret: %d\n", ++ operation->reg_addr, operation->reg_val, ret); ++ return ret; ++ } ++ ++ WB_MAC_BSC_ERROR("Unsupport operation type: %d\n", operation->op); ++ return -EINVAL; ++} ++ ++static int get_mac_reg(struct i2c_client *client, uint32_t reg_addr, uint32_t *reg_value) ++{ ++ int i, ret; ++ i2c_op_t *op; ++ struct mac_data *data; ++ dev_params_t *dev_params; ++ uint32_t val_tmp; ++ ++ data = i2c_get_clientdata(client); ++ dev_params = &data->dev_param; ++ val_tmp = 0; ++ for (i = 0; i < dev_params->vtmon_read_ops; i++) { ++ op = &dev_params->vtmon_read[i]; ++ if (i == dev_params->sbus_addr_op) { ++ op->reg_val = reg_addr; ++ } ++ WB_MAC_BSC_DEBUG("Start to handle %s operation, step: %d, reg_addr: 0x%x, reg_value: 0x%x, read back flag: %d\n", ++ op->op == I2C_READ ? "I2C_READ" : "I2C_WRITE", i, op->reg_addr, op->reg_val, op->read_back); ++ ret = handle_operation(client, op); ++ if (ret < 0) { ++ WB_MAC_BSC_ERROR("handle operation %d failed, ret: %d\n", i, ret); ++ return ret; ++ } ++ if (op->op == I2C_READ) { ++ val_tmp = op->reg_val; ++ } ++ ++ if (i == dev_params->sbus_error_op) { ++ if (val_tmp & dev_params->sbus_error_mask) { ++ WB_MAC_BSC_ERROR("SBUS error seen, status value: 0x%x\n", op->reg_val); ++ return -EIO; ++ } ++ WB_MAC_BSC_DEBUG("Error status check ok, status: 0x%x, error_mask: 0x%x \n", ++ val_tmp, dev_params->sbus_error_mask); ++ } ++ } ++ ++ if (val_tmp == reg_addr) { ++ WB_MAC_BSC_ERROR("get mac register error, register value: 0x%x equal to reg_addr: 0x%x\n", ++ val_tmp, reg_addr); ++ return -EIO; ++ } ++ ++ *reg_value = val_tmp; ++ WB_MAC_BSC_DEBUG("get_mac_reg success, reg_addr: 0x%x, reg_value: 0x%x", reg_addr, *reg_value); ++ return 0; ++} ++ ++static int read_vtmon(struct i2c_client *client, uint8_t vtmon, int *temp) ++{ ++ struct mac_data *data; ++ dev_params_t *dev_params; ++ uint32_t reg_addr, reg_val; ++ uint32_t vtmon_val; ++ int ret; ++ ++ data = i2c_get_clientdata(client); ++ dev_params = &data->dev_param; ++ ++ if (vtmon >= dev_params->vtmon_instances) { ++ WB_MAC_BSC_ERROR("VTMON index [%d] greater or equal to VTMON instance number: %d\n", ++ vtmon, dev_params->vtmon_instances); ++ return -1; ++ } ++ reg_addr = dev_params->vtmon_reg_addrs[vtmon]; ++ ret = get_mac_reg(client, reg_addr, ®_val); ++ if (ret < 0) { ++ WB_MAC_BSC_ERROR("Read VTMON[%d] failed, reg_addr: 0x%x, ret: %d\n", ++ vtmon, reg_addr, ret); ++ return ret; ++ } ++ ++ vtmon_val = reg_val & ((1 << dev_params->vtmon_data_width) - 1); ++ *temp = ((dev_params->vtmon_scalar * vtmon_val) + dev_params->vtmon_offset) / 10; ++ ++ if ((*temp / 1000 < -40) || (*temp / 1000 > 120)) { ++ WB_MAC_BSC_ERROR("MAC temp invalid, vtmon: %d, temp: %d\n", vtmon, *temp); ++ return -EINVAL; ++ } ++ WB_MAC_BSC_DEBUG("Read mac temp success, index: %d, value: %d\n", vtmon + 1, *temp); ++ return 0; ++} ++ ++static ssize_t show_mac_temp(struct device *dev, struct device_attribute *da, char *buf) ++{ ++ struct mac_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ u32 temp_index = to_sensor_dev_attr(da)->index; ++ int ret, temp; ++ ++ mutex_lock(&data->update_lock); ++ ret = read_vtmon(client, temp_index - 1, &temp); ++ if (ret < 0) { ++ temp = -MAC_TEMP_INVALID; ++ WB_MAC_BSC_ERROR("get_mactemp index: %d failed, ret = %d\n", temp_index, ret); ++ } ++ mutex_unlock(&data->update_lock); ++ return snprintf(buf, PAGE_SIZE, "%d\n", temp); ++} ++ ++static ssize_t show_mac_max_temp(struct device *dev, struct device_attribute *da, char *buf) ++{ ++ struct mac_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ dev_params_t *dev_params; ++ int i, ret; ++ int tmp, temp; ++ ++ mutex_lock(&data->update_lock); ++ ++ dev_params = &data->dev_param; ++ temp = -MAC_TEMP_INVALID; ++ for (i = 0; i < dev_params->vtmon_instances ; i++) { ++ ret = read_vtmon(client, i, &tmp); ++ if (ret < 0) { ++ WB_MAC_BSC_ERROR("Get mactemp failed, temp index: %d, ret = %d\n", ++ i, ret); ++ tmp = -MAC_TEMP_INVALID; ++ } ++ ++ temp = (temp > tmp) ? temp : tmp; ++ } ++ ++ mutex_unlock(&data->update_lock); ++ return snprintf(buf, PAGE_SIZE, "%d\n", temp); ++} ++ ++static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX1); ++static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX2); ++static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX3); ++static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX4); ++static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX5); ++static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX6); ++static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX7); ++static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX8); ++static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX9); ++static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX10); ++static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX11); ++static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX12); ++static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX13); ++static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX14); ++static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX15); ++static SENSOR_DEVICE_ATTR(temp99_input, S_IRUGO, show_mac_max_temp, NULL, 0); ++ ++static struct attribute *mac_hwmon_attrs[] = { ++ &sensor_dev_attr_temp1_input.dev_attr.attr, ++ &sensor_dev_attr_temp2_input.dev_attr.attr, ++ &sensor_dev_attr_temp3_input.dev_attr.attr, ++ &sensor_dev_attr_temp4_input.dev_attr.attr, ++ &sensor_dev_attr_temp5_input.dev_attr.attr, ++ &sensor_dev_attr_temp6_input.dev_attr.attr, ++ &sensor_dev_attr_temp7_input.dev_attr.attr, ++ &sensor_dev_attr_temp8_input.dev_attr.attr, ++ &sensor_dev_attr_temp9_input.dev_attr.attr, ++ &sensor_dev_attr_temp10_input.dev_attr.attr, ++ &sensor_dev_attr_temp11_input.dev_attr.attr, ++ &sensor_dev_attr_temp12_input.dev_attr.attr, ++ &sensor_dev_attr_temp13_input.dev_attr.attr, ++ &sensor_dev_attr_temp14_input.dev_attr.attr, ++ &sensor_dev_attr_temp15_input.dev_attr.attr, ++ &sensor_dev_attr_temp99_input.dev_attr.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(mac_hwmon); ++ ++static void mac_bsc_setup(struct i2c_client *client) ++{ ++ int i, ret; ++ struct mac_data *data; ++ dev_params_t *dev_params; ++ uint32_t reg_value; ++ ++ data = i2c_get_clientdata(client); ++ dev_params = &data->dev_param; ++ ++ for (i = 0; i < dev_params->sbus_setup_ops; i++) { ++ ret = bsc_i2c_read(client, dev_params->sbus_setup[i].reg_addr, ®_value); ++ if ((ret < 0) || (reg_value != dev_params->sbus_setup[i].reg_val)) { ++ WB_MAC_BSC_DEBUG("bsc setup op%d, ret: %d, reg_addr: 0x%x, read value: 0x%x not equal to set value: 0x%x\n", ++ i, ret, dev_params->sbus_setup[i].reg_addr, reg_value, dev_params->sbus_setup[i].reg_val); ++ bsc_i2c_write(client, dev_params->sbus_setup[i].reg_addr, dev_params->sbus_setup[i].reg_val); ++ } else { ++ WB_MAC_BSC_DEBUG("bsc setup op%d, reg_addr: 0x%x, read value: 0x%x equal to set value: 0x%x\n", ++ i, dev_params->sbus_setup[i].reg_addr, reg_value, dev_params->sbus_setup[i].reg_val); ++ } ++ } ++ return; ++} ++ ++static int mac_bsc_init(struct i2c_client *client) ++{ ++ int ret, mac_id; ++ uint32_t reg_value; ++ ++ ret = get_mac_reg(client, MAC_ID_REG, ®_value); ++ if (ret < 0) { ++ WB_MAC_BSC_ERROR("Get MAC ID failed, reg_addr: 0x%x, ret = %d\n", ++ MAC_ID_REG, ret); ++ return ret; ++ } ++ ++ WB_MAC_BSC_DEBUG("Get MAC ID success, reg_addr: 0x%x, value: 0x%x \n", ++ MAC_ID_REG, reg_value); ++ mac_id = reg_value & 0xffff; ++ return mac_id; ++} ++ ++static int find_mac_config(int type, int *index) ++{ ++ int i, size; ++ ++ size = ARRAY_SIZE(mac_temp_conf); ++ for (i = 0; i < size; i++) { ++ if (mac_temp_conf[i].mac_id == type) { ++ *index = i; ++ return 0; ++ } ++ } ++ return -1; ++} ++ ++static int mac_bsc_config_check(dev_params_t *dev_params) ++{ ++ i2c_op_t *last_op; ++ i2c_op_t *err_op; ++ i2c_op_t *addr_op; ++ ++ /* vtmon_instances should not more than the MAC_BSC_MAX_TEMP_NUM */ ++ if ((dev_params->vtmon_instances > MAC_BSC_MAX_TEMP_NUM) || ++ (dev_params->vtmon_instances <= 0)) { ++ WB_MAC_BSC_ERROR("VTMON instance number %d more than the max number: %d\n", ++ dev_params->vtmon_instances, MAC_BSC_MAX_TEMP_NUM); ++ return -1; ++ } ++ ++ /* vtmon read operation steps should not more than the MAC_BSC_MAX_READ_REG_STEP */ ++ if ((dev_params->vtmon_read_ops > MAC_BSC_MAX_READ_REG_STEP) || ++ (dev_params->vtmon_read_ops <=0)) { ++ WB_MAC_BSC_ERROR("VTMON read ops number %d more than the max step: %d\n", ++ dev_params->vtmon_read_ops, MAC_BSC_MAX_READ_REG_STEP); ++ return -1; ++ } ++ ++ /* the last operation must be I2C_READ to get temperature register value */ ++ last_op = &dev_params->vtmon_read[dev_params->vtmon_read_ops - 1]; ++ if (last_op->op != I2C_READ) { ++ WB_MAC_BSC_ERROR("VTMON read ops config error, last operation not I2C_READ, last step: %d, op_code: %d\n", ++ dev_params->vtmon_read_ops - 1, last_op->op); ++ return -1; ++ } ++ ++ /* the address operation steps should not more than the vtmon_read_ops and not the last step */ ++ if ((dev_params->sbus_addr_op >= (dev_params->vtmon_read_ops - 1)) || ++ (dev_params->sbus_addr_op < 0)) { ++ WB_MAC_BSC_ERROR("VTMON addr op step invalid, index %d, read ops: %d\n", ++ dev_params->sbus_addr_op, dev_params->vtmon_read_ops); ++ return -1; ++ } ++ ++ /* the address operation must be I2C_WRITE to set temperature register address */ ++ addr_op = &dev_params->vtmon_read[dev_params->sbus_addr_op]; ++ if (addr_op->op != I2C_WRITE) { ++ WB_MAC_BSC_ERROR("VTMON addr op config error, addr operation not I2C_WRITE, addr op step: %d, op_code: %d\n", ++ dev_params->sbus_addr_op, addr_op->op); ++ return -1; ++ } ++ ++ /* the error status operation steps should not more than the vtmon_read_ops and not the last step */ ++ if (dev_params->sbus_error_op >= (dev_params->vtmon_read_ops - 1)) { ++ WB_MAC_BSC_ERROR("VTMON error op step invalid, index %d, read ops: %d\n", ++ dev_params->sbus_error_op, dev_params->vtmon_read_ops); ++ return -1; ++ } ++ ++ /* if error status operation exist, it must be I2C_READ to get error status register */ ++ if (dev_params->sbus_error_op >=0) { ++ err_op = &dev_params->vtmon_read[dev_params->sbus_error_op]; ++ if (err_op->op != I2C_READ) { ++ WB_MAC_BSC_ERROR("VTMON error op config error, error operation not I2C_READ, error op step: %d, op_code: %d\n", ++ dev_params->sbus_error_op, err_op->op); ++ return -1; ++ } ++ } ++ WB_MAC_BSC_DEBUG("dev_params check ok, instance number: %d, read_ops: %d, addr_op: %d, error_op: %d\n", ++ dev_params->vtmon_instances, dev_params->vtmon_read_ops, ++ dev_params->sbus_addr_op, dev_params->sbus_error_op); ++ return 0; ++} ++ ++static int mac_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ struct mac_data *data; ++ int ret, mac_id, index; ++ ++ WB_MAC_BSC_DEBUG("=========mac_probe(%d-%04x)===========\n", ++ client->adapter->nr, client->addr); ++ ++ if (!client->adapter->algo->master_xfer) { ++ dev_err(&client->adapter->dev, "I2C level transfers not supported\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ data = devm_kzalloc(&client->dev, sizeof(struct mac_data), GFP_KERNEL); ++ if (!data) { ++ dev_err(&client->dev, "Failed to devm_kzalloc.\n"); ++ return -ENOMEM; ++ } ++ ++ data->client = client; ++ i2c_set_clientdata(client, data); ++ ++ mac_id = id->driver_data; ++ ret = find_mac_config(mac_id, &index); ++ if (ret < 0) { ++ dev_err(&client->dev, "Failed to find mac config, mac id from driver_data: 0x%x\n", mac_id); ++ return -EINVAL; ++ } ++ data->dev_param = mac_temp_conf[index]; ++ ret = mac_bsc_config_check(&data->dev_param); ++ if (ret < 0) { ++ dev_err(&client->dev, "Invalid config parameter, mac id: 0x%x, config index: %d\n", ++ mac_id, index); ++ return -EINVAL; ++ } ++ ++ mac_bsc_setup(client); ++ ++ if (mac_id == TD4) { ++ ret = mac_bsc_init(client); ++ if (ret < 0) { ++ dev_err(&client->dev, "Failed to get mac id, ret: %d\n", ret); ++ return -EIO; ++ } ++ mac_id = ret; ++ ret = find_mac_config(mac_id, &index); ++ if (ret < 0) { ++ dev_err(&client->dev, "Failed to find mac config, mac id from chip: 0x%x\n", mac_id); ++ return -EINVAL; ++ } ++ data->dev_param = mac_temp_conf[index]; ++ ret = mac_bsc_config_check(&data->dev_param); ++ if (ret < 0) { ++ dev_err(&client->dev, "Invalid config parameter, mac id: 0x%x, config index: %d\n", ++ mac_id, index); ++ return -EINVAL; ++ } ++ } ++ ++ WB_MAC_BSC_DEBUG("mac_id: 0x%x, config index: %d\n", mac_id, index); ++ ++ mutex_init(&data->update_lock); ++ data->hwmon_dev = hwmon_device_register_with_groups(&client->dev, client->name, data, mac_hwmon_groups); ++ if (IS_ERR(data->hwmon_dev)) { ++ dev_err(&client->dev, "Failed to register mac bsc hwmon\n"); ++ return PTR_ERR(data->hwmon_dev); ++ } ++ ++ dev_info(&client->dev, "Register mac bsc %x with %d vtmon instance number success\n", ++ mac_id, data->dev_param.vtmon_instances); ++ return 0; ++} ++ ++static int mac_remove(struct i2c_client *client) ++{ ++ struct mac_data *data = i2c_get_clientdata(client); ++ ++ hwmon_device_unregister(data->hwmon_dev); ++ return 0; ++} ++ ++static const struct i2c_device_id mac_id_table[] = { ++ { "wb_mac_bsc_td3", TD3 }, ++ { "wb_mac_bsc_td3_x2", TD3_X2 }, ++ { "wb_mac_bsc_td4", TD4 }, ++ { "wb_mac_bsc_th3", TH3 }, ++ { "wb_mac_bsc_th4", TH4 }, ++ {} ++}; ++MODULE_DEVICE_TABLE(i2c, mac_id_table); ++ ++static struct i2c_driver wb_mac_bsc_driver = { ++ .driver = { ++ .name = "wb_mac_bsc", ++ }, ++ .probe = mac_probe, ++ .remove = mac_remove, ++ .id_table = mac_id_table, ++}; ++ ++module_i2c_driver(wb_mac_bsc_driver); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("mac bsc driver"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_optoe.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_optoe.c +new file mode 100644 +index 000000000..c09162368 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_optoe.c +@@ -0,0 +1,1192 @@ ++/* ++ * optoe.c - A driver to read and write the EEPROM on optical transceivers ++ * (SFP, QSFP and similar I2C based devices) ++ * ++ * Copyright (C) 2014 Cumulus networks Inc. ++ * Copyright (C) 2017 Finisar Corp. ++ * ++ * 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 Freeoftware Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++/* ++ * Description: ++ * a) Optical transceiver EEPROM read/write transactions are just like ++ * the at24 eeproms managed by the at24.c i2c driver ++ * b) The register/memory layout is up to 256 128 byte pages defined by ++ * a "pages valid" register and switched via a "page select" ++ * register as explained in below diagram. ++ * c) 256 bytes are mapped at a time. 'Lower page 00h' is the first 128 ++ * bytes of address space, and always references the same ++ * location, independent of the page select register. ++ * All mapped pages are mapped into the upper 128 bytes ++ * (offset 128-255) of the i2c address. ++ * d) Devices with one I2C address (eg QSFP) use I2C address 0x50 ++ * (A0h in the spec), and map all pages in the upper 128 bytes ++ * of that address. ++ * e) Devices with two I2C addresses (eg SFP) have 256 bytes of data ++ * at I2C address 0x50, and 256 bytes of data at I2C address ++ * 0x51 (A2h in the spec). Page selection and paged access ++ * only apply to this second I2C address (0x51). ++ * e) The address space is presented, by the driver, as a linear ++ * address space. For devices with one I2C client at address ++ * 0x50 (eg QSFP), offset 0-127 are in the lower ++ * half of address 50/A0h/client[0]. Offset 128-255 are in ++ * page 0, 256-383 are page 1, etc. More generally, offset ++ * 'n' resides in page (n/128)-1. ('page -1' is the lower ++ * half, offset 0-127). ++ * f) For devices with two I2C clients at address 0x50 and 0x51 (eg SFP), ++ * the address space places offset 0-127 in the lower ++ * half of 50/A0/client[0], offset 128-255 in the upper ++ * half. Offset 256-383 is in the lower half of 51/A2/client[1]. ++ * Offset 384-511 is in page 0, in the upper half of 51/A2/... ++ * Offset 512-639 is in page 1, in the upper half of 51/A2/... ++ * Offset 'n' is in page (n/128)-3 (for n > 383) ++ * ++ * One I2c addressed (eg QSFP) Memory Map ++ * ++ * 2-Wire Serial Address: 1010000x ++ * ++ * Lower Page 00h (128 bytes) ++ * ===================== ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * |Page Select Byte(127)| ++ * ===================== ++ * | ++ * | ++ * | ++ * | ++ * V ++ * ------------------------------------------------------------ ++ * | | | | ++ * | | | | ++ * | | | | ++ * | | | | ++ * | | | | ++ * | | | | ++ * | | | | ++ * | | | | ++ * | | | | ++ * V V V V ++ * ------------ -------------- --------------- -------------- ++ * | | | | | | | | ++ * | Upper | | Upper | | Upper | | Upper | ++ * | Page 00h | | Page 01h | | Page 02h | | Page 03h | ++ * | | | (Optional) | | (Optional) | | (Optional | ++ * | | | | | | | for Cable | ++ * | | | | | | | Assemblies) | ++ * | ID | | AST | | User | | | ++ * | Fields | | Table | | EEPROM Data | | | ++ * | | | | | | | | ++ * | | | | | | | | ++ * | | | | | | | | ++ * ------------ -------------- --------------- -------------- ++ * ++ * The SFF 8436 (QSFP) spec only defines the 4 pages described above. ++ * In anticipation of future applications and devices, this driver ++ * supports access to the full architected range, 256 pages. ++ * ++ * The CMIS (Common Management Interface Specification) defines use of ++ * considerably more pages (at least to page 0xAF), which this driver ++ * supports. ++ * ++ * NOTE: This version of the driver ONLY SUPPORTS BANK 0 PAGES on CMIS ++ * devices. ++ * ++ **/ ++ ++/* #define DEBUG 1 */ ++ ++#undef EEPROM_CLASS ++#ifdef CONFIG_EEPROM_CLASS ++#define EEPROM_CLASS ++#endif ++#ifdef CONFIG_EEPROM_CLASS_MODULE ++#define EEPROM_CLASS ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++#ifdef EEPROM_CLASS ++#include ++#endif ++ ++#include ++ ++/* The maximum length of a port name */ ++#define MAX_PORT_NAME_LEN 20 ++ ++struct optoe_platform_data { ++ u32 byte_len; /* size (sum of all addr) */ ++ u16 page_size; /* for writes */ ++ u8 flags; ++ void *dummy1; /* backward compatibility */ ++ void *dummy2; /* backward compatibility */ ++ ++#ifdef EEPROM_CLASS ++ struct eeprom_platform_data *eeprom_data; ++#endif ++ char port_name[MAX_PORT_NAME_LEN]; ++}; ++ ++/* fundamental unit of addressing for EEPROM */ ++#define OPTOE_PAGE_SIZE 128 ++/* ++ * Single address devices (eg QSFP) have 256 pages, plus the unpaged ++ * low 128 bytes. If the device does not support paging, it is ++ * only 2 'pages' long. ++ */ ++#define OPTOE_ARCH_PAGES 256 ++#define ONE_ADDR_EEPROM_SIZE ((1 + OPTOE_ARCH_PAGES) * OPTOE_PAGE_SIZE) ++#define ONE_ADDR_EEPROM_UNPAGED_SIZE (2 * OPTOE_PAGE_SIZE) ++/* ++ * Dual address devices (eg SFP) have 256 pages, plus the unpaged ++ * low 128 bytes, plus 256 bytes at 0x50. If the device does not ++ * support paging, it is 4 'pages' long. ++ */ ++#define TWO_ADDR_EEPROM_SIZE ((3 + OPTOE_ARCH_PAGES) * OPTOE_PAGE_SIZE) ++#define TWO_ADDR_EEPROM_UNPAGED_SIZE (4 * OPTOE_PAGE_SIZE) ++#define TWO_ADDR_NO_0X51_SIZE (2 * OPTOE_PAGE_SIZE) ++ ++/* a few constants to find our way around the EEPROM */ ++#define OPTOE_PAGE_SELECT_REG 0x7F ++#define ONE_ADDR_PAGEABLE_REG 0x02 ++#define QSFP_NOT_PAGEABLE (1<<2) ++#define CMIS_NOT_PAGEABLE (1<<7) ++#define TWO_ADDR_PAGEABLE_REG 0x40 ++#define TWO_ADDR_PAGEABLE (1<<4) ++#define TWO_ADDR_0X51_REG 92 ++#define TWO_ADDR_0X51_SUPP (1<<6) ++#define OPTOE_ID_REG 0 ++#define OPTOE_READ_OP 0 ++#define OPTOE_WRITE_OP 1 ++#define OPTOE_EOF 0 /* used for access beyond end of device */ ++ ++struct optoe_data { ++ struct optoe_platform_data chip; ++ int use_smbus; ++ char port_name[MAX_PORT_NAME_LEN]; ++ ++ /* ++ * Lock protects against activities from other Linux tasks, ++ * but not from changes by other I2C masters. ++ */ ++ struct mutex lock; ++ struct bin_attribute bin; ++ struct attribute_group attr_group; ++ ++ u8 *writebuf; ++ unsigned int write_max; ++ ++ unsigned int num_addresses; ++ ++#ifdef EEPROM_CLASS ++ struct eeprom_device *eeprom_dev; ++#endif ++ ++ /* dev_class: ONE_ADDR (QSFP) or TWO_ADDR (SFP) */ ++ int dev_class; ++ ++ struct i2c_client *client[]; ++}; ++ ++/* ++ * This parameter is to help this driver avoid blocking other drivers out ++ * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C ++ * clock, one 256 byte read takes about 1/43 second which is excessive; ++ * but the 1/170 second it takes at 400 kHz may be quite reasonable; and ++ * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible. ++ * ++ * This value is forced to be a power of two so that writes align on pages. ++ */ ++static unsigned int io_limit = OPTOE_PAGE_SIZE; ++ ++/* ++ * specs often allow 5 msec for a page write, sometimes 20 msec; ++ * it's important to recover from write timeouts. ++ */ ++static unsigned int write_timeout = 50; ++ ++/* ++ * flags to distinguish one-address (QSFP family) from two-address (SFP family) ++ * If the family is not known, figure it out when the device is accessed ++ */ ++#define ONE_ADDR 1 ++#define TWO_ADDR 2 ++#define CMIS_ADDR 3 ++ ++static const struct i2c_device_id optoe_ids[] = { ++ { "wb_optoe1", ONE_ADDR }, ++ { "wb_optoe2", TWO_ADDR }, ++ { "wb_optoe3", CMIS_ADDR }, ++ { "wb_sff8436", ONE_ADDR }, ++ { "wb_24c04", TWO_ADDR }, ++ { /* END OF LIST */ } ++}; ++MODULE_DEVICE_TABLE(i2c, optoe_ids); ++ ++/*-------------------------------------------------------------------------*/ ++/* ++ * This routine computes the addressing information to be used for ++ * a given r/w request. ++ * ++ * Task is to calculate the client (0 = i2c addr 50, 1 = i2c addr 51), ++ * the page, and the offset. ++ * ++ * Handles both single address (eg QSFP) and two address (eg SFP). ++ * For SFP, offset 0-255 are on client[0], >255 is on client[1] ++ * Offset 256-383 are on the lower half of client[1] ++ * Pages are accessible on the upper half of client[1]. ++ * Offset >383 are in 128 byte pages mapped into the upper half ++ * ++ * For QSFP, all offsets are on client[0] ++ * offset 0-127 are on the lower half of client[0] (no paging) ++ * Pages are accessible on the upper half of client[1]. ++ * Offset >127 are in 128 byte pages mapped into the upper half ++ * ++ * Callers must not read/write beyond the end of a client or a page ++ * without recomputing the client/page. Hence offset (within page) ++ * plus length must be less than or equal to 128. (Note that this ++ * routine does not have access to the length of the call, hence ++ * cannot do the validity check.) ++ * ++ * Offset within Lower Page 00h and Upper Page 00h are not recomputed ++ */ ++ ++static uint8_t optoe_translate_offset(struct optoe_data *optoe, ++ loff_t *offset, struct i2c_client **client) ++{ ++ unsigned int page = 0; ++ ++ *client = optoe->client[0]; ++ ++ /* if SFP style, offset > 255, shift to i2c addr 0x51 */ ++ if (optoe->dev_class == TWO_ADDR) { ++ if (*offset > 255) { ++ /* like QSFP, but shifted to client[1] */ ++ *client = optoe->client[1]; ++ *offset -= 256; ++ } ++ } ++ ++ /* ++ * if offset is in the range 0-128... ++ * page doesn't matter (using lower half), return 0. ++ * offset is already correct (don't add 128 to get to paged area) ++ */ ++ if (*offset < OPTOE_PAGE_SIZE) ++ return page; ++ ++ /* note, page will always be positive since *offset >= 128 */ ++ page = (*offset >> 7)-1; ++ /* 0x80 places the offset in the top half, offset is last 7 bits */ ++ *offset = OPTOE_PAGE_SIZE + (*offset & 0x7f); ++ ++ return page; /* note also returning client and offset */ ++} ++ ++static ssize_t optoe_eeprom_read(struct optoe_data *optoe, ++ struct i2c_client *client, ++ char *buf, unsigned int offset, size_t count) ++{ ++ struct i2c_msg msg[2]; ++ u8 msgbuf[2]; ++ unsigned long timeout, read_time; ++ int status, i; ++ ++ mem_clear(msg, sizeof(msg)); ++ ++ switch (optoe->use_smbus) { ++ case I2C_SMBUS_I2C_BLOCK_DATA: ++ /*smaller eeproms can work given some SMBus extension calls */ ++ if (count > I2C_SMBUS_BLOCK_MAX) ++ count = I2C_SMBUS_BLOCK_MAX; ++ break; ++ case I2C_SMBUS_WORD_DATA: ++ /* Check for odd length transaction */ ++ count = (count == 1) ? 1 : 2; ++ break; ++ case I2C_SMBUS_BYTE_DATA: ++ count = 1; ++ break; ++ default: ++ /* ++ * When we have a better choice than SMBus calls, use a ++ * combined I2C message. Write address; then read up to ++ * io_limit data bytes. msgbuf is u8 and will cast to our ++ * needs. ++ */ ++ i = 0; ++ msgbuf[i++] = offset; ++ ++ msg[0].addr = client->addr; ++ msg[0].buf = msgbuf; ++ msg[0].len = i; ++ ++ msg[1].addr = client->addr; ++ msg[1].flags = I2C_M_RD; ++ msg[1].buf = buf; ++ msg[1].len = count; ++ } ++ ++ /* ++ * Reads fail if the previous write didn't complete yet. We may ++ * loop a few times until this one succeeds, waiting at least ++ * long enough for one entire page write to work. ++ */ ++ timeout = jiffies + msecs_to_jiffies(write_timeout); ++ do { ++ read_time = jiffies; ++ ++ switch (optoe->use_smbus) { ++ case I2C_SMBUS_I2C_BLOCK_DATA: ++ status = i2c_smbus_read_i2c_block_data(client, offset, ++ count, buf); ++ break; ++ case I2C_SMBUS_WORD_DATA: ++ status = i2c_smbus_read_word_data(client, offset); ++ if (status >= 0) { ++ buf[0] = status & 0xff; ++ if (count == 2) ++ buf[1] = status >> 8; ++ status = count; ++ } ++ break; ++ case I2C_SMBUS_BYTE_DATA: ++ status = i2c_smbus_read_byte_data(client, offset); ++ if (status >= 0) { ++ buf[0] = status; ++ status = count; ++ } ++ break; ++ default: ++ status = i2c_transfer(client->adapter, msg, 2); ++ if (status == 2) ++ status = count; ++ } ++ ++ dev_dbg(&client->dev, "eeprom read %zu@%d --> %d (%ld)\n", ++ count, offset, status, jiffies); ++ ++ if (status == count) /* happy path */ ++ return count; ++ ++ /* REVISIT: at HZ=100, this is sloooow */ ++ usleep_range(1000, 2000); ++ } while (time_before(read_time, timeout)); ++ ++ return -ETIMEDOUT; ++} ++ ++static ssize_t optoe_eeprom_write(struct optoe_data *optoe, ++ struct i2c_client *client, ++ const char *buf, ++ unsigned int offset, size_t count) ++{ ++ struct i2c_msg msg; ++ ssize_t status; ++ unsigned long timeout, write_time; ++ unsigned int next_page_start; ++ int i = 0; ++ ++ /* write max is at most a page ++ * (In this driver, write_max is actually one byte!) ++ */ ++ if (count > optoe->write_max) ++ count = optoe->write_max; ++ ++ /* shorten count if necessary to avoid crossing page boundary */ ++ next_page_start = roundup(offset + 1, OPTOE_PAGE_SIZE); ++ if (offset + count > next_page_start) ++ count = next_page_start - offset; ++ ++ switch (optoe->use_smbus) { ++ case I2C_SMBUS_I2C_BLOCK_DATA: ++ /*smaller eeproms can work given some SMBus extension calls */ ++ if (count > I2C_SMBUS_BLOCK_MAX) ++ count = I2C_SMBUS_BLOCK_MAX; ++ break; ++ case I2C_SMBUS_WORD_DATA: ++ /* Check for odd length transaction */ ++ count = (count == 1) ? 1 : 2; ++ break; ++ case I2C_SMBUS_BYTE_DATA: ++ count = 1; ++ break; ++ default: ++ /* If we'll use I2C calls for I/O, set up the message */ ++ msg.addr = client->addr; ++ msg.flags = 0; ++ ++ /* msg.buf is u8 and casts will mask the values */ ++ msg.buf = optoe->writebuf; ++ ++ msg.buf[i++] = offset; ++ memcpy(&msg.buf[i], buf, count); ++ msg.len = i + count; ++ break; ++ } ++ ++ /* ++ * Reads fail if the previous write didn't complete yet. We may ++ * loop a few times until this one succeeds, waiting at least ++ * long enough for one entire page write to work. ++ */ ++ timeout = jiffies + msecs_to_jiffies(write_timeout); ++ do { ++ write_time = jiffies; ++ ++ switch (optoe->use_smbus) { ++ case I2C_SMBUS_I2C_BLOCK_DATA: ++ status = i2c_smbus_write_i2c_block_data(client, ++ offset, count, buf); ++ if (status == 0) ++ status = count; ++ break; ++ case I2C_SMBUS_WORD_DATA: ++ if (count == 2) { ++ status = i2c_smbus_write_word_data(client, ++ offset, (u16)((buf[0])|(buf[1] << 8))); ++ } else { ++ /* count = 1 */ ++ status = i2c_smbus_write_byte_data(client, ++ offset, buf[0]); ++ } ++ if (status == 0) ++ status = count; ++ break; ++ case I2C_SMBUS_BYTE_DATA: ++ status = i2c_smbus_write_byte_data(client, offset, ++ buf[0]); ++ if (status == 0) ++ status = count; ++ break; ++ default: ++ status = i2c_transfer(client->adapter, &msg, 1); ++ if (status == 1) ++ status = count; ++ break; ++ } ++ ++ dev_dbg(&client->dev, "eeprom write %zu@%d --> %ld (%lu)\n", ++ count, offset, (long int) status, jiffies); ++ ++ if (status == count) ++ return count; ++ ++ /* REVISIT: at HZ=100, this is sloooow */ ++ usleep_range(1000, 2000); ++ } while (time_before(write_time, timeout)); ++ ++ return -ETIMEDOUT; ++} ++ ++static ssize_t optoe_eeprom_update_client(struct optoe_data *optoe, ++ char *buf, loff_t off, ++ size_t count, int opcode) ++{ ++ struct i2c_client *client; ++ ssize_t retval = 0; ++ uint8_t page = 0; ++ uint8_t loc; ++ loff_t phy_offset = off; ++ int ret = 0; ++ ++ page = optoe_translate_offset(optoe, &phy_offset, &client); ++ dev_dbg(&client->dev, ++ "%s off %lld page:%d phy_offset:%lld, count:%ld, opcode:%d\n", ++ __func__, off, page, phy_offset, (long int) count, opcode); ++ ++ ret = optoe_eeprom_read(optoe, client, &loc, OPTOE_PAGE_SELECT_REG, 1); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "Read page register for get now location page failed. ret:%d\n", ret); ++ return ret; ++ } ++ ++ /* Only when read and now location page is inconsistent, will doing switch page */ ++ if (loc != page) { ++ ret = optoe_eeprom_write(optoe, client, &page, ++ OPTOE_PAGE_SELECT_REG, 1); ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "Write page register for page %d failed ret:%d!\n", ++ page, ret); ++ return ret; ++ } ++ } ++ ++ while (count) { ++ ssize_t status; ++ ++ if (opcode == OPTOE_READ_OP) { ++ status = optoe_eeprom_read(optoe, client, ++ buf, phy_offset, count); ++ } else { ++ status = optoe_eeprom_write(optoe, client, ++ buf, phy_offset, count); ++ } ++ if (status <= 0) { ++ if (retval == 0) ++ retval = status; ++ break; ++ } ++ buf += status; ++ phy_offset += status; ++ count -= status; ++ retval += status; ++ } ++ ++ return retval; ++} ++ ++/* ++ * Figure out if this access is within the range of supported pages. ++ * Note this is called on every access because we don't know if the ++ * module has been replaced since the last call. ++ * If/when modules support more pages, this is the routine to update ++ * to validate and allow access to additional pages. ++ * ++ * Returns updated len for this access: ++ * - entire access is legal, original len is returned. ++ * - access begins legal but is too long, len is truncated to fit. ++ * - initial offset exceeds supported pages, return OPTOE_EOF (zero) ++ */ ++static ssize_t optoe_page_legal(struct optoe_data *optoe, ++ loff_t off, size_t len) ++{ ++ struct i2c_client *client = optoe->client[0]; ++ u8 regval; ++ int not_pageable; ++ int status; ++ size_t maxlen; ++ ++ if (off < 0) ++ return -EINVAL; ++ if (optoe->dev_class == TWO_ADDR) { ++ /* SFP case */ ++ /* if only using addr 0x50 (first 256 bytes) we're good */ ++ if ((off + len) <= TWO_ADDR_NO_0X51_SIZE) ++ return len; ++ /* if offset exceeds possible pages, we're not good */ ++ if (off >= TWO_ADDR_EEPROM_SIZE) ++ return OPTOE_EOF; ++ /* in between, are pages supported? */ ++ status = optoe_eeprom_read(optoe, client, ®val, ++ TWO_ADDR_PAGEABLE_REG, 1); ++ if (status < 0) ++ return status; /* error out (no module?) */ ++ if (regval & TWO_ADDR_PAGEABLE) { ++ /* Pages supported, trim len to the end of pages */ ++ maxlen = TWO_ADDR_EEPROM_SIZE - off; ++ } else { ++ /* pages not supported, trim len to unpaged size */ ++ if (off >= TWO_ADDR_EEPROM_UNPAGED_SIZE) ++ return OPTOE_EOF; ++ ++ /* will be accessing addr 0x51, is that supported? */ ++ /* byte 92, bit 6 implies DDM support, 0x51 support */ ++ status = optoe_eeprom_read(optoe, client, ®val, ++ TWO_ADDR_0X51_REG, 1); ++ if (status < 0) ++ return status; ++ if (regval & TWO_ADDR_0X51_SUPP) { ++ /* addr 0x51 is OK */ ++ maxlen = TWO_ADDR_EEPROM_UNPAGED_SIZE - off; ++ } else { ++ /* addr 0x51 NOT supported, trim to 256 max */ ++ if (off >= TWO_ADDR_NO_0X51_SIZE) ++ return OPTOE_EOF; ++ maxlen = TWO_ADDR_NO_0X51_SIZE - off; ++ } ++ } ++ len = (len > maxlen) ? maxlen : len; ++ dev_dbg(&client->dev, ++ "page_legal, SFP, off %lld len %ld\n", ++ off, (long int) len); ++ } else { ++ /* QSFP case, CMIS case */ ++ /* if no pages needed, we're good */ ++ if ((off + len) <= ONE_ADDR_EEPROM_UNPAGED_SIZE) ++ return len; ++ /* if offset exceeds possible pages, we're not good */ ++ if (off >= ONE_ADDR_EEPROM_SIZE) ++ return OPTOE_EOF; ++ /* in between, are pages supported? */ ++ status = optoe_eeprom_read(optoe, client, ®val, ++ ONE_ADDR_PAGEABLE_REG, 1); ++ if (status < 0) ++ return status; /* error out (no module?) */ ++ ++ if (optoe->dev_class == ONE_ADDR) { ++ not_pageable = QSFP_NOT_PAGEABLE; ++ } else { ++ not_pageable = CMIS_NOT_PAGEABLE; ++ } ++ dev_dbg(&client->dev, ++ "Paging Register: 0x%x; not_pageable mask: 0x%x\n", ++ regval, not_pageable); ++ ++ if (regval & not_pageable) { ++ /* pages not supported, trim len to unpaged size */ ++ if (off >= ONE_ADDR_EEPROM_UNPAGED_SIZE) ++ return OPTOE_EOF; ++ maxlen = ONE_ADDR_EEPROM_UNPAGED_SIZE - off; ++ } else { ++ /* Pages supported, trim len to the end of pages */ ++ maxlen = ONE_ADDR_EEPROM_SIZE - off; ++ } ++ len = (len > maxlen) ? maxlen : len; ++ dev_dbg(&client->dev, ++ "page_legal, QSFP, off %lld len %ld\n", ++ off, (long int) len); ++ } ++ return len; ++} ++ ++static ssize_t optoe_read_write(struct optoe_data *optoe, ++ char *buf, loff_t off, size_t len, int opcode) ++{ ++ struct i2c_client *client = optoe->client[0]; ++ int chunk; ++ int status = 0; ++ ssize_t retval; ++ size_t pending_len = 0, chunk_len = 0; ++ loff_t chunk_offset = 0, chunk_start_offset = 0; ++ loff_t chunk_end_offset = 0; ++ ++ dev_dbg(&client->dev, ++ "%s: off %lld len:%ld, opcode:%s\n", ++ __func__, off, (long int) len, ++ (opcode == OPTOE_READ_OP) ? "r" : "w"); ++ if (unlikely(!len)) ++ return len; ++ ++ /* ++ * Read data from chip, protecting against concurrent updates ++ * from this host, but not from other I2C masters. ++ */ ++ mutex_lock(&optoe->lock); ++ ++ /* ++ * Confirm this access fits within the device suppored addr range ++ */ ++ status = optoe_page_legal(optoe, off, len); ++ if ((status == OPTOE_EOF) || (status < 0)) { ++ mutex_unlock(&optoe->lock); ++ return status; ++ } ++ len = status; ++ ++ /* ++ * For each (128 byte) chunk involved in this request, issue a ++ * separate call to sff_eeprom_update_client(), to ++ * ensure that each access recalculates the client/page ++ * and writes the page register as needed. ++ * Note that chunk to page mapping is confusing, is different for ++ * QSFP and SFP, and never needs to be done. Don't try! ++ */ ++ pending_len = len; /* amount remaining to transfer */ ++ retval = 0; /* amount transferred */ ++ for (chunk = off >> 7; chunk <= (off + len - 1) >> 7; chunk++) { ++ ++ /* ++ * Compute the offset and number of bytes to be read/write ++ * ++ * 1. start at an offset not equal to 0 (within the chunk) ++ * and read/write less than the rest of the chunk ++ * 2. start at an offset not equal to 0 and read/write the rest ++ * of the chunk ++ * 3. start at offset 0 (within the chunk) and read/write less ++ * than entire chunk ++ * 4. start at offset 0 (within the chunk), and read/write ++ * the entire chunk ++ */ ++ chunk_start_offset = chunk * OPTOE_PAGE_SIZE; ++ chunk_end_offset = chunk_start_offset + OPTOE_PAGE_SIZE; ++ ++ if (chunk_start_offset < off) { ++ chunk_offset = off; ++ if ((off + pending_len) < chunk_end_offset) ++ chunk_len = pending_len; ++ else ++ chunk_len = chunk_end_offset - off; ++ } else { ++ chunk_offset = chunk_start_offset; ++ if (pending_len < OPTOE_PAGE_SIZE) ++ chunk_len = pending_len; ++ else ++ chunk_len = OPTOE_PAGE_SIZE; ++ } ++ ++ dev_dbg(&client->dev, ++ "sff_r/w: off %lld, len %ld, chunk_start_offset %lld, chunk_offset %lld, chunk_len %ld, pending_len %ld\n", ++ off, (long int) len, chunk_start_offset, chunk_offset, ++ (long int) chunk_len, (long int) pending_len); ++ ++ /* ++ * note: chunk_offset is from the start of the EEPROM, ++ * not the start of the chunk ++ */ ++ status = optoe_eeprom_update_client(optoe, buf, ++ chunk_offset, chunk_len, opcode); ++ if (status != chunk_len) { ++ /* This is another 'no device present' path */ ++ dev_dbg(&client->dev, ++ "o_u_c: chunk %d c_offset %lld c_len %ld failed %d!\n", ++ chunk, chunk_offset, (long int) chunk_len, status); ++ if (status > 0) ++ retval += status; ++ if (retval == 0) ++ retval = status; ++ break; ++ } ++ buf += status; ++ pending_len -= status; ++ retval += status; ++ } ++ mutex_unlock(&optoe->lock); ++ ++ return retval; ++} ++ ++static ssize_t optoe_bin_read(struct file *filp, struct kobject *kobj, ++ struct bin_attribute *attr, ++ char *buf, loff_t off, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(container_of(kobj, ++ struct device, kobj)); ++ struct optoe_data *optoe = i2c_get_clientdata(client); ++ ++ return optoe_read_write(optoe, buf, off, count, OPTOE_READ_OP); ++} ++ ++static ssize_t optoe_bin_write(struct file *filp, struct kobject *kobj, ++ struct bin_attribute *attr, ++ char *buf, loff_t off, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(container_of(kobj, ++ struct device, kobj)); ++ struct optoe_data *optoe = i2c_get_clientdata(client); ++ ++ return optoe_read_write(optoe, buf, off, count, OPTOE_WRITE_OP); ++} ++ ++static int optoe_remove(struct i2c_client *client) ++{ ++ struct optoe_data *optoe; ++ int i; ++ ++ optoe = i2c_get_clientdata(client); ++ sysfs_remove_group(&client->dev.kobj, &optoe->attr_group); ++ sysfs_remove_bin_file(&client->dev.kobj, &optoe->bin); ++ ++ for (i = 1; i < optoe->num_addresses; i++) ++ i2c_unregister_device(optoe->client[i]); ++ ++#ifdef EEPROM_CLASS ++ eeprom_device_unregister(optoe->eeprom_dev); ++#endif ++ ++ kfree(optoe->writebuf); ++ kfree(optoe); ++ return 0; ++} ++ ++static ssize_t show_dev_class(struct device *dev, ++ struct device_attribute *dattr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct optoe_data *optoe = i2c_get_clientdata(client); ++ ssize_t count; ++ ++ mutex_lock(&optoe->lock); ++ count = sprintf(buf, "%d\n", optoe->dev_class); ++ mutex_unlock(&optoe->lock); ++ ++ return count; ++} ++ ++static ssize_t set_dev_class(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct optoe_data *optoe = i2c_get_clientdata(client); ++ int dev_class; ++ ++ /* ++ * dev_class is actually the number of i2c addresses used, thus ++ * legal values are "1" (QSFP class) and "2" (SFP class) ++ * And... CMIS spec is 1 i2c address, but puts the pageable ++ * bit in a different location, so CMIS devices are "3" ++ */ ++ ++ if (kstrtoint(buf, 0, &dev_class) != 0 || ++ dev_class < 1 || dev_class > 3) ++ return -EINVAL; ++ ++ mutex_lock(&optoe->lock); ++ if (dev_class == TWO_ADDR) { ++ /* SFP family */ ++ /* if it doesn't exist, create 0x51 i2c address */ ++ if (!optoe->client[1]) { ++ optoe->client[1] = i2c_new_dummy_device(client->adapter, 0x51); ++ if (!optoe->client[1]) { ++ dev_err(&client->dev, ++ "address 0x51 unavailable\n"); ++ mutex_unlock(&optoe->lock); ++ return -EADDRINUSE; ++ } ++ } ++ optoe->bin.size = TWO_ADDR_EEPROM_SIZE; ++ optoe->num_addresses = 2; ++ } else { ++ /* one-address (eg QSFP) and CMIS family */ ++ /* if it exists, remove 0x51 i2c address */ ++ if (optoe->client[1]) { ++ i2c_unregister_device(optoe->client[1]); ++ optoe->client[1] = NULL; ++ } ++ optoe->bin.size = ONE_ADDR_EEPROM_SIZE; ++ optoe->num_addresses = 1; ++ } ++ optoe->dev_class = dev_class; ++ mutex_unlock(&optoe->lock); ++ ++ return count; ++} ++ ++/* ++ * if using the EEPROM CLASS driver, we don't report a port_name, ++ * the EEPROM CLASS drive handles that. Hence all this code is ++ * only compiled if we are NOT using the EEPROM CLASS driver. ++ */ ++#ifndef EEPROM_CLASS ++ ++static ssize_t show_port_name(struct device *dev, ++ struct device_attribute *dattr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct optoe_data *optoe = i2c_get_clientdata(client); ++ ssize_t count; ++ ++ mutex_lock(&optoe->lock); ++ count = sprintf(buf, "%s\n", optoe->port_name); ++ mutex_unlock(&optoe->lock); ++ ++ return count; ++} ++ ++static ssize_t set_port_name(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct optoe_data *optoe = i2c_get_clientdata(client); ++ char port_name[MAX_PORT_NAME_LEN]; ++ ++ /* no checking, this value is not used except by show_port_name */ ++ ++ if (sscanf(buf, "%19s", port_name) != 1) ++ return -EINVAL; ++ ++ mutex_lock(&optoe->lock); ++ strcpy(optoe->port_name, port_name); ++ mutex_unlock(&optoe->lock); ++ ++ return count; ++} ++ ++static DEVICE_ATTR(port_name, 0644, show_port_name, set_port_name); ++#endif /* if NOT defined EEPROM_CLASS, the common case */ ++ ++static DEVICE_ATTR(dev_class, 0644, show_dev_class, set_dev_class); ++ ++static struct attribute *optoe_attrs[] = { ++#ifndef EEPROM_CLASS ++ &dev_attr_port_name.attr, ++#endif ++ &dev_attr_dev_class.attr, ++ NULL, ++}; ++ ++static struct attribute_group optoe_attr_group = { ++ .attrs = optoe_attrs, ++}; ++ ++static int optoe_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ int err; ++ int use_smbus = 0; ++ struct optoe_platform_data chip; ++ struct optoe_data *optoe; ++ int num_addresses = 0; ++ char port_name[MAX_PORT_NAME_LEN]; ++ ++ if (client->addr != 0x50) { ++ dev_dbg(&client->dev, "probe, bad i2c addr: 0x%x\n", ++ client->addr); ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ if (client->dev.platform_data) { ++ chip = *(struct optoe_platform_data *)client->dev.platform_data; ++ /* take the port name from the supplied platform data */ ++#ifdef EEPROM_CLASS ++ strncpy(port_name, chip.eeprom_data->label, MAX_PORT_NAME_LEN); ++#else ++ memcpy(port_name, chip.port_name, MAX_PORT_NAME_LEN); ++#endif ++ dev_dbg(&client->dev, ++ "probe, chip provided, flags:0x%x; name: %s\n", ++ chip.flags, client->name); ++ } else { ++ if (!id->driver_data) { ++ err = -ENODEV; ++ goto exit; ++ } ++ dev_dbg(&client->dev, "probe, building chip\n"); ++ strcpy(port_name, "unitialized"); ++ chip.flags = 0; ++#ifdef EEPROM_CLASS ++ chip.eeprom_data = NULL; ++#endif ++ } ++ ++ /* Use I2C operations unless we're stuck with SMBus extensions. */ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { ++ if (i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { ++ use_smbus = I2C_SMBUS_I2C_BLOCK_DATA; ++ } else if (i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_READ_WORD_DATA)) { ++ use_smbus = I2C_SMBUS_WORD_DATA; ++ } else if (i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_READ_BYTE_DATA)) { ++ use_smbus = I2C_SMBUS_BYTE_DATA; ++ } else { ++ err = -EPFNOSUPPORT; ++ goto exit; ++ } ++ } ++ ++ /* ++ * Make room for two i2c clients ++ */ ++ num_addresses = 2; ++ ++ optoe = kzalloc(sizeof(struct optoe_data) + ++ num_addresses * sizeof(struct i2c_client *), ++ GFP_KERNEL); ++ if (!optoe) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ mutex_init(&optoe->lock); ++ ++ /* determine whether this is a one-address or two-address module */ ++ if ((strcmp(client->name, "wb_optoe1") == 0) || ++ (strcmp(client->name, "wb_sff8436") == 0)) { ++ /* one-address (eg QSFP) family */ ++ optoe->dev_class = ONE_ADDR; ++ chip.byte_len = ONE_ADDR_EEPROM_SIZE; ++ num_addresses = 1; ++ } else if ((strcmp(client->name, "wb_optoe2") == 0) || ++ (strcmp(client->name, "wb_24c04") == 0)) { ++ /* SFP family */ ++ optoe->dev_class = TWO_ADDR; ++ chip.byte_len = TWO_ADDR_EEPROM_SIZE; ++ num_addresses = 2; ++ } else if (strcmp(client->name, "wb_optoe3") == 0) { ++ /* CMIS spec */ ++ optoe->dev_class = CMIS_ADDR; ++ chip.byte_len = ONE_ADDR_EEPROM_SIZE; ++ num_addresses = 1; ++ } else { /* those were the only choices */ ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ dev_dbg(&client->dev, "dev_class: %d\n", optoe->dev_class); ++ optoe->use_smbus = use_smbus; ++ optoe->chip = chip; ++ optoe->num_addresses = num_addresses; ++ memcpy(optoe->port_name, port_name, MAX_PORT_NAME_LEN); ++ ++ /* ++ * Export the EEPROM bytes through sysfs, since that's convenient. ++ * By default, only root should see the data (maybe passwords etc) ++ */ ++ sysfs_bin_attr_init(&optoe->bin); ++ optoe->bin.attr.name = "eeprom"; ++ optoe->bin.attr.mode = 0444; ++ optoe->bin.read = optoe_bin_read; ++ optoe->bin.size = chip.byte_len; ++ ++ if (!use_smbus || ++ (i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) || ++ i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_WRITE_WORD_DATA) || ++ i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { ++ /* ++ * NOTE: AN-2079 ++ * Finisar recommends that the host implement 1 byte writes ++ * only since this module only supports 32 byte page boundaries. ++ * 2 byte writes are acceptable for PE and Vout changes per ++ * Application Note AN-2071. ++ */ ++ unsigned int write_max = 1; ++ ++ optoe->bin.write = optoe_bin_write; ++ optoe->bin.attr.mode |= 0200; ++ ++ if (write_max > io_limit) ++ write_max = io_limit; ++ if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX) ++ write_max = I2C_SMBUS_BLOCK_MAX; ++ optoe->write_max = write_max; ++ ++ /* buffer (data + address at the beginning) */ ++ optoe->writebuf = kmalloc(write_max + 2, GFP_KERNEL); ++ if (!optoe->writebuf) { ++ err = -ENOMEM; ++ goto exit_kfree; ++ } ++ } else { ++ dev_warn(&client->dev, ++ "cannot write due to controller restrictions."); ++ } ++ ++ optoe->client[0] = client; ++ ++ /* SFF-8472 spec requires that the second I2C address be 0x51 */ ++ if (num_addresses == 2) { ++ optoe->client[1] = i2c_new_dummy_device(client->adapter, 0x51); ++ if (!optoe->client[1]) { ++ dev_err(&client->dev, "address 0x51 unavailable\n"); ++ err = -EADDRINUSE; ++ goto err_struct; ++ } ++ } ++ ++ /* create the sysfs eeprom file */ ++ err = sysfs_create_bin_file(&client->dev.kobj, &optoe->bin); ++ if (err) ++ goto err_struct; ++ ++ optoe->attr_group = optoe_attr_group; ++ ++ err = sysfs_create_group(&client->dev.kobj, &optoe->attr_group); ++ if (err) { ++ dev_err(&client->dev, "failed to create sysfs attribute group.\n"); ++ goto err_struct; ++ } ++ ++#ifdef EEPROM_CLASS ++ optoe->eeprom_dev = eeprom_device_register(&client->dev, ++ chip.eeprom_data); ++ if (IS_ERR(optoe->eeprom_dev)) { ++ dev_err(&client->dev, "error registering eeprom device.\n"); ++ err = PTR_ERR(optoe->eeprom_dev); ++ goto err_sysfs_cleanup; ++ } ++#endif ++ ++ i2c_set_clientdata(client, optoe); ++ ++ dev_info(&client->dev, "%zu byte %s EEPROM, %s\n", ++ optoe->bin.size, client->name, ++ optoe->bin.write ? "read/write" : "read-only"); ++ ++ if (use_smbus == I2C_SMBUS_WORD_DATA || ++ use_smbus == I2C_SMBUS_BYTE_DATA) { ++ dev_notice(&client->dev, ++ "Falling back to %s reads, performance will suffer\n", ++ use_smbus == I2C_SMBUS_WORD_DATA ? "word" : "byte"); ++ } ++ ++ return 0; ++ ++#ifdef EEPROM_CLASS ++err_sysfs_cleanup: ++ sysfs_remove_group(&client->dev.kobj, &optoe->attr_group); ++ sysfs_remove_bin_file(&client->dev.kobj, &optoe->bin); ++#endif ++ ++err_struct: ++ if (num_addresses == 2) { ++ if (optoe->client[1]) { ++ i2c_unregister_device(optoe->client[1]); ++ optoe->client[1] = NULL; ++ } ++ } ++ ++ kfree(optoe->writebuf); ++exit_kfree: ++ kfree(optoe); ++exit: ++ dev_dbg(&client->dev, "probe error %d\n", err); ++ ++ return err; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static struct i2c_driver optoe_driver = { ++ .driver = { ++ .name = "wb_optoe", ++ .owner = THIS_MODULE, ++ }, ++ .probe = optoe_probe, ++ .remove = optoe_remove, ++ .id_table = optoe_ids, ++}; ++ ++static int __init optoe_init(void) ++{ ++ ++ if (!io_limit) { ++ pr_err("optoe: io_limit must not be 0!\n"); ++ return -EINVAL; ++ } ++ ++ io_limit = rounddown_pow_of_two(io_limit); ++ return i2c_add_driver(&optoe_driver); ++} ++module_init(optoe_init); ++ ++static void __exit optoe_exit(void) ++{ ++ i2c_del_driver(&optoe_driver); ++} ++module_exit(optoe_exit); ++ ++MODULE_DESCRIPTION("Driver for optical transceiver (SFP, QSFP, ...) EEPROMs"); ++MODULE_AUTHOR("support"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.c +new file mode 100644 +index 000000000..757c100e4 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.c +@@ -0,0 +1,770 @@ ++/* ++ * wb_pcie_dev.c ++ * ko to read/write pcie iomem and ioports through /dev/XXX device ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wb_pcie_dev.h" ++ ++#define PROXY_NAME "wb-pci-dev" ++#define MAX_NAME_SIZE (20) ++#define MAX_PCIE_NUM (256) ++#define PCI_RDWR_MAX_LEN (256) ++#define PCIE_BUS_WIDTH_1 (1) ++#define PCIE_BUS_WIDTH_2 (2) ++#define PCIE_BUS_WIDTH_4 (4) ++ ++static int g_pcie_dev_debug = 0; ++static int g_pcie_dev_error = 0; ++ ++module_param(g_pcie_dev_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_pcie_dev_error, int, S_IRUGO | S_IWUSR); ++ ++#define PCIE_DEV_DEBUG_VERBOSE(fmt, args...) do { \ ++ if (g_pcie_dev_debug) { \ ++ printk(KERN_INFO "[PCIE_DEV][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define PCIE_DEV_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_pcie_dev_error) { \ ++ printk(KERN_ERR "[PCIE_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++typedef struct firmware_upg_s { ++ int upg_ctrl_base; ++ int upg_flash_base; ++} firmware_upg_t; ++ ++typedef struct wb_pci_dev_s { ++ const char *name; ++ uint32_t domain; ++ uint32_t bus; ++ uint32_t slot; ++ uint32_t fn; ++ uint32_t bar; ++ void __iomem *pci_mem_base; ++ uint32_t pci_io_base; ++ uint32_t bar_len; ++ uint32_t bar_flag; ++ uint32_t bus_width; ++ struct miscdevice misc; ++ void (*setreg)(struct wb_pci_dev_s *wb_pci_dev, int reg, u32 value); ++ u32 (*getreg)(struct wb_pci_dev_s *wb_pci_dev, int reg); ++ firmware_upg_t firmware_upg; ++} wb_pci_dev_t; ++ ++static wb_pci_dev_t* pcie_dev_arry[MAX_PCIE_NUM]; ++ ++static void pci_dev_setreg_8(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) ++{ ++ u8 w_value; ++ ++ w_value = (u8)(value & 0xff); ++ if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { ++ writeb(w_value, wb_pci_dev->pci_mem_base + reg); ++ } else { ++ outb(w_value, wb_pci_dev->pci_io_base + reg); ++ } ++ return; ++} ++ ++static void pci_dev_setreg_16(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) ++{ ++ u16 w_value; ++ ++ w_value = (u16)(value & 0xffff); ++ if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { ++ writew(w_value, wb_pci_dev->pci_mem_base + reg); ++ } else { ++ outw(w_value, wb_pci_dev->pci_io_base + reg); ++ } ++ ++ return; ++} ++ ++static void pci_dev_setreg_32(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) ++{ ++ ++ if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { ++ writel(value, wb_pci_dev->pci_mem_base + reg); ++ } else { ++ outl(value, wb_pci_dev->pci_io_base + reg); ++ } ++ return; ++} ++ ++static inline u32 pci_dev_getreg_8(wb_pci_dev_t *wb_pci_dev, int reg) ++{ ++ u32 value; ++ ++ if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { ++ value = readb(wb_pci_dev->pci_mem_base + reg); ++ } else { ++ value = inb(wb_pci_dev->pci_io_base + reg); ++ } ++ ++ return value; ++} ++ ++static inline u32 pci_dev_getreg_16(wb_pci_dev_t *wb_pci_dev, int reg) ++{ ++ u32 value; ++ ++ if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { ++ value = readw(wb_pci_dev->pci_mem_base + reg); ++ } else { ++ value = inw(wb_pci_dev->pci_io_base + reg); ++ } ++ ++ return value; ++} ++ ++static inline u32 pci_dev_getreg_32(wb_pci_dev_t *wb_pci_dev, int reg) ++{ ++ u32 value; ++ ++ if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { ++ value = readl(wb_pci_dev->pci_mem_base + reg); ++ } else { ++ value = inl(wb_pci_dev->pci_io_base + reg); ++ } ++ ++ return value; ++} ++ ++static inline void pci_dev_setreg(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) ++{ ++ wb_pci_dev->setreg(wb_pci_dev, reg, value); ++} ++ ++static inline u32 pci_dev_getreg(wb_pci_dev_t *wb_pci_dev, int reg) ++{ ++ return wb_pci_dev->getreg(wb_pci_dev, reg); ++} ++ ++static int pci_dev_open(struct inode *inode, struct file *file) ++{ ++ unsigned int minor = iminor(inode); ++ wb_pci_dev_t *wb_pci_dev; ++ ++ PCIE_DEV_DEBUG_VERBOSE("inode: %p, file: %p, minor: %u", inode, file, minor); ++ ++ if (minor >= MAX_PCIE_NUM) { ++ PCIE_DEV_DEBUG_ERROR("minor out of range, minor = %d.\n", minor); ++ return -ENODEV; ++ } ++ ++ wb_pci_dev = pcie_dev_arry[minor]; ++ if (wb_pci_dev == NULL) { ++ PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, open failed, minor = %d\n", minor); ++ return -ENODEV; ++ } ++ ++ file->private_data = wb_pci_dev; ++ return 0; ++} ++ ++static int pci_dev_release(struct inode *inode, struct file *file) ++{ ++ file->private_data = NULL; ++ return 0; ++} ++ ++static int pci_dev_read_tmp(wb_pci_dev_t *wb_pci_dev, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ int width, i, j; ++ u32 val; ++ ++ if (offset > wb_pci_dev->bar_len) { ++ PCIE_DEV_DEBUG_VERBOSE("offset:0x%x, bar len:0x%x, EOF.\n", offset, wb_pci_dev->bar_len); ++ return 0; ++ } ++ ++ width = wb_pci_dev->bus_width; ++ ++ if (offset % width) { ++ PCIE_DEV_DEBUG_ERROR("pci bus width:%d, offset:0x%x, read size %lu invalid.\n", ++ width, offset, count); ++ return -EINVAL; ++ } ++ ++ if (count > wb_pci_dev->bar_len - offset) { ++ PCIE_DEV_DEBUG_VERBOSE("read count out of range. input len:%lu, read len:%u.\n", ++ count, wb_pci_dev->bar_len - offset); ++ count = wb_pci_dev->bar_len - offset; ++ } ++ ++ for (i = 0; i < count; i += width) { ++ val = pci_dev_getreg(wb_pci_dev, offset + i); ++ for (j = 0; (j < width) && (i + j < count); j++) { ++ buf[i + j] = (val >> (8 * j)) & 0xff; ++ } ++ } ++ return count; ++} ++ ++static ssize_t pci_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) ++{ ++ wb_pci_dev_t *wb_pci_dev; ++ int ret, read_len; ++ u8 buf_tmp[PCI_RDWR_MAX_LEN]; ++ ++ wb_pci_dev = file->private_data; ++ if (wb_pci_dev == NULL) { ++ PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, read failed.\n"); ++ return -EINVAL; ++ } ++ ++ if (count == 0) { ++ PCIE_DEV_DEBUG_ERROR("Invalid params, read count is 0.\n"); ++ return -EINVAL; ++ } ++ ++ if (count > sizeof(buf_tmp)) { ++ PCIE_DEV_DEBUG_VERBOSE("read count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); ++ count = sizeof(buf_tmp); ++ } ++ ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ read_len = pci_dev_read_tmp(wb_pci_dev, *offset, buf_tmp, count); ++ if (read_len < 0) { ++ PCIE_DEV_DEBUG_ERROR("pci_dev_read_tmp failed, ret:%d.\n", read_len); ++ return read_len; ++ } ++ if (access_ok(buf, read_len)) { ++ PCIE_DEV_DEBUG_VERBOSE("user space read, buf: %p, offset: %lld, read count %lu.\n", ++ buf, *offset, count); ++ if (copy_to_user(buf, buf_tmp, read_len)) { ++ PCIE_DEV_DEBUG_ERROR("copy_to_user failed.\n"); ++ return -EFAULT; ++ } ++ } else { ++ PCIE_DEV_DEBUG_VERBOSE("kernel space read, buf: %p, offset: %lld, read count %lu.\n", ++ buf, *offset, count); ++ memcpy(buf, buf_tmp, read_len); ++ } ++ *offset += read_len; ++ ret = read_len; ++ return ret; ++} ++ ++static ssize_t pci_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) ++{ ++ int ret; ++ ++ PCIE_DEV_DEBUG_VERBOSE("pci_dev_read_iter, file: %p, count: %lu, offset: %lld\n", ++ iocb->ki_filp, to->count, iocb->ki_pos); ++ ret = pci_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos); ++ return ret; ++} ++ ++static int pci_dev_write_tmp(wb_pci_dev_t *wb_pci_dev, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ int width, i, j; ++ u32 val; ++ ++ if (offset > wb_pci_dev->bar_len) { ++ PCIE_DEV_DEBUG_VERBOSE("offset:0x%x, bar len:0x%x, EOF.\n", offset, wb_pci_dev->bar_len); ++ return 0; ++ } ++ ++ width = wb_pci_dev->bus_width; ++ ++ if (offset % width) { ++ PCIE_DEV_DEBUG_ERROR("pci bus width:%d, offset:0x%x, read size %lu invalid.\n", ++ width, offset, count); ++ return -EINVAL; ++ } ++ ++ if (count > wb_pci_dev->bar_len - offset) { ++ PCIE_DEV_DEBUG_VERBOSE("write count out of range. input len:%lu, write len:%u.\n", ++ count, wb_pci_dev->bar_len - offset); ++ count = wb_pci_dev->bar_len - offset; ++ } ++ ++ for (i = 0; i < count; i += width) { ++ val = 0; ++ for (j = 0; (j < width) && (i + j < count); j++) { ++ val |= buf[i + j] << (8 * j); ++ } ++ pci_dev_setreg(wb_pci_dev, i + offset, val); ++ } ++ ++ return count; ++} ++ ++static ssize_t pci_dev_write(struct file *file, const char __user *buf, size_t count, ++ loff_t *offset) ++{ ++ wb_pci_dev_t *wb_pci_dev; ++ u8 buf_tmp[PCI_RDWR_MAX_LEN]; ++ int write_len; ++ ++ wb_pci_dev = file->private_data; ++ if (wb_pci_dev == NULL) { ++ PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, write failed.\n"); ++ return -EINVAL; ++ } ++ ++ if (count == 0) { ++ PCIE_DEV_DEBUG_ERROR("Invalid params, write count is 0.\n"); ++ return -EINVAL; ++ } ++ ++ if (count > sizeof(buf_tmp)) { ++ PCIE_DEV_DEBUG_VERBOSE("write count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); ++ count = sizeof(buf_tmp); ++ } ++ ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ if (access_ok(buf, count)) { ++ PCIE_DEV_DEBUG_VERBOSE("user space write, buf: %p, offset: %lld, write count %lu.\n", ++ buf, *offset, count); ++ if (copy_from_user(buf_tmp, buf, count)) { ++ PCIE_DEV_DEBUG_ERROR("copy_from_user failed.\n"); ++ return -EFAULT; ++ } ++ } else { ++ PCIE_DEV_DEBUG_VERBOSE("kernel space write, buf: %p, offset: %lld, write count %lu.\n", ++ buf, *offset, count); ++ memcpy(buf_tmp, buf, count); ++ } ++ ++ write_len = pci_dev_write_tmp(wb_pci_dev, *offset, buf_tmp, count); ++ if (write_len < 0) { ++ PCIE_DEV_DEBUG_ERROR("pci_dev_write_tmp failed, ret:%d.\n", write_len); ++ return write_len; ++ } ++ ++ *offset += write_len; ++ return write_len; ++} ++ ++static ssize_t pci_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) ++{ ++ int ret; ++ ++ PCIE_DEV_DEBUG_VERBOSE("pci_dev_write_iter, file: %p, count: %lu, offset: %lld\n", ++ iocb->ki_filp, from->count, iocb->ki_pos); ++ ret = pci_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos); ++ return ret; ++} ++ ++static loff_t pci_dev_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t ret = 0; ++ wb_pci_dev_t *wb_pci_dev; ++ ++ wb_pci_dev = file->private_data; ++ if (wb_pci_dev == NULL) { ++ PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, llseek failed.\n"); ++ return -EINVAL; ++ } ++ ++ switch (origin) { ++ case SEEK_SET: ++ if (offset < 0) { ++ PCIE_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); ++ ret = -EINVAL; ++ break; ++ } ++ if (offset > wb_pci_dev->bar_len) { ++ PCIE_DEV_DEBUG_ERROR("SEEK_SET out of range, offset:%lld, bar len:0x%x.\n", ++ offset, wb_pci_dev->bar_len); ++ ret = - EINVAL; ++ break; ++ } ++ file->f_pos = offset; ++ ret = file->f_pos; ++ break; ++ case SEEK_CUR: ++ if (((file->f_pos + offset) > wb_pci_dev->bar_len) || ((file->f_pos + offset) < 0)) { ++ PCIE_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld, bar len:0x%x.\n", ++ file->f_pos, offset, wb_pci_dev->bar_len); ++ ret = - EINVAL; ++ break; ++ } ++ file->f_pos += offset; ++ ret = file->f_pos; ++ break; ++ default: ++ PCIE_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++static long pci_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ wb_pci_dev_t *wb_pci_dev; ++ void __user *argp; ++ firmware_upg_t *firmware_upg; ++ int upg_ctrl_base; ++ int upg_flash_base; ++ ++ PCIE_DEV_DEBUG_VERBOSE("ioctl, cmd=0x%02x, arg=0x%02lx\n",cmd, arg); ++ ++ wb_pci_dev = file->private_data; ++ if (wb_pci_dev == NULL) { ++ PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, ioctl failed.\n"); ++ return -EINVAL; ++ } ++ ++ firmware_upg = &wb_pci_dev->firmware_upg; ++ ++ argp = (void __user *)arg; ++ ++ switch (cmd) { ++ case GET_FPGA_UPG_CTL_BASE: ++ if (firmware_upg->upg_ctrl_base < 0) { ++ PCIE_DEV_DEBUG_ERROR("dts not adaptive upg_ctrl_base\n"); ++ return -EFAULT; ++ } else { ++ upg_ctrl_base = firmware_upg->upg_ctrl_base; ++ if (copy_to_user(argp, &upg_ctrl_base, sizeof(upg_ctrl_base))) { ++ PCIE_DEV_DEBUG_ERROR("upg_ctrl_base copy_from_user failed\n"); ++ return -EFAULT; ++ } ++ } ++ break; ++ case GET_FPGA_UPG_FLASH_BASE: ++ if (firmware_upg->upg_flash_base < 0) { ++ PCIE_DEV_DEBUG_ERROR("dts not adaptive upg_flash_base\n"); ++ return -EFAULT; ++ } else { ++ upg_flash_base = firmware_upg->upg_flash_base; ++ if (copy_to_user(argp, &upg_flash_base, sizeof(upg_flash_base))) { ++ PCIE_DEV_DEBUG_ERROR("upg_flash_base copy_from_user failed\n"); ++ return -EFAULT; ++ } ++ } ++ break; ++ default: ++ PCIE_DEV_DEBUG_ERROR("command unsupported \n"); ++ return -ENOTTY; ++ } ++ ++ return 0; ++} ++ ++static const struct file_operations pcie_dev_fops = { ++ .owner = THIS_MODULE, ++ .llseek = pci_dev_llseek, ++ .read_iter = pci_dev_read_iter, ++ .write_iter = pci_dev_write_iter, ++ .unlocked_ioctl = pci_dev_ioctl, ++ .open = pci_dev_open, ++ .release = pci_dev_release, ++}; ++ ++static wb_pci_dev_t *dev_match(const char *path) ++{ ++ wb_pci_dev_t *wb_pci_dev; ++ char dev_name[MAX_NAME_SIZE]; ++ int i; ++ ++ for (i = 0; i < MAX_PCIE_NUM; i++) { ++ if (pcie_dev_arry[i] == NULL) { ++ continue; ++ } ++ wb_pci_dev = pcie_dev_arry[i]; ++ snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", wb_pci_dev->name); ++ if (!strcmp(path, dev_name)) { ++ PCIE_DEV_DEBUG_VERBOSE("get dev_name = %s, minor = %d\n", dev_name, i); ++ return wb_pci_dev; ++ } ++ } ++ ++ return NULL; ++} ++ ++int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ wb_pci_dev_t *wb_pci_dev; ++ int read_len; ++ ++ if (path == NULL) { ++ PCIE_DEV_DEBUG_ERROR("path NULL"); ++ return -EINVAL; ++ } ++ ++ if (buf == NULL) { ++ PCIE_DEV_DEBUG_ERROR("buf NULL"); ++ return -EINVAL; ++ } ++ ++ wb_pci_dev = dev_match(path); ++ if (wb_pci_dev == NULL) { ++ PCIE_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); ++ return -EINVAL; ++ } ++ ++ read_len = pci_dev_read_tmp(wb_pci_dev, offset, buf, count); ++ if (read_len < 0) { ++ PCIE_DEV_DEBUG_ERROR("pci_dev_read_tmp failed, ret:%d.\n", read_len); ++ } ++ return read_len; ++} ++EXPORT_SYMBOL(pcie_device_func_read); ++ ++int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ wb_pci_dev_t *wb_pci_dev; ++ int write_len; ++ ++ if (path == NULL) { ++ PCIE_DEV_DEBUG_ERROR("path NULL"); ++ return -EINVAL; ++ } ++ ++ if (buf == NULL) { ++ PCIE_DEV_DEBUG_ERROR("buf NULL"); ++ return -EINVAL; ++ } ++ ++ wb_pci_dev = dev_match(path); ++ if (wb_pci_dev == NULL) { ++ PCIE_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); ++ return -EINVAL; ++ } ++ ++ write_len = pci_dev_write_tmp(wb_pci_dev, offset, buf, count); ++ if (write_len < 0) { ++ PCIE_DEV_DEBUG_ERROR("pci_dev_write_tmp failed, ret:%d.\n", write_len); ++ } ++ return write_len; ++} ++EXPORT_SYMBOL(pcie_device_func_write); ++ ++static int pci_setup_bars(wb_pci_dev_t *wb_pci_dev, struct pci_dev *dev) ++{ ++ int ret; ++ uint32_t addr, len, flags; ++ ++ ret = 0; ++ addr = pci_resource_start(dev, wb_pci_dev->bar); ++ len = pci_resource_len(dev, wb_pci_dev->bar); ++ if (addr == 0 || len == 0) { ++ PCIE_DEV_DEBUG_ERROR("get bar addr failed. bar:%d, addr:0x%x, len:0x%x.\n", ++ wb_pci_dev->bar, addr, len); ++ return -EFAULT; ++ } ++ wb_pci_dev->bar_len = len; ++ ++ flags = pci_resource_flags(dev, wb_pci_dev->bar); ++ PCIE_DEV_DEBUG_VERBOSE("bar:%d, flag:0x%08x, phys addr:0x%x, len:0x%x\n", ++ wb_pci_dev->bar, flags, addr, len); ++ if (flags & IORESOURCE_MEM) { ++ wb_pci_dev->bar_flag = IORESOURCE_MEM; ++ wb_pci_dev->pci_mem_base = ioremap(addr, len); ++ PCIE_DEV_DEBUG_VERBOSE("pci mem base:%p.\n", wb_pci_dev->pci_mem_base); ++ } else if (flags & IORESOURCE_IO) { ++ wb_pci_dev->bar_flag = IORESOURCE_IO; ++ wb_pci_dev->pci_io_base = addr; ++ PCIE_DEV_DEBUG_VERBOSE("pci io base:0x%x.\n", wb_pci_dev->pci_io_base); ++ } else { ++ PCIE_DEV_DEBUG_ERROR("unknow pci bar flag:0x%08x.\n", flags); ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int pci_dev_probe(struct platform_device *pdev) ++{ ++ int ret, devfn; ++ wb_pci_dev_t *wb_pci_dev; ++ struct pci_dev *pci_dev; ++ struct miscdevice *misc; ++ firmware_upg_t *firmware_upg; ++ pci_dev_device_t *pci_dev_device; ++ ++ wb_pci_dev = devm_kzalloc(&pdev->dev, sizeof(wb_pci_dev_t), GFP_KERNEL); ++ if (!wb_pci_dev) { ++ dev_err(&pdev->dev, "devm_kzalloc failed.\n"); ++ ret = -ENOMEM; ++ return ret; ++ } ++ ++ firmware_upg = &wb_pci_dev->firmware_upg; ++ ++ if (pdev->dev.of_node) { ++ ret = 0; ++ ret += of_property_read_string(pdev->dev.of_node, "pci_dev_name", &wb_pci_dev->name); ++ ret += of_property_read_u32(pdev->dev.of_node, "pci_domain", &wb_pci_dev->domain); ++ ret += of_property_read_u32(pdev->dev.of_node, "pci_bus", &wb_pci_dev->bus); ++ ret += of_property_read_u32(pdev->dev.of_node, "pci_slot", &wb_pci_dev->slot); ++ ret += of_property_read_u32(pdev->dev.of_node, "pci_fn", &wb_pci_dev->fn); ++ ret += of_property_read_u32(pdev->dev.of_node, "pci_bar", &wb_pci_dev->bar); ++ ret += of_property_read_u32(pdev->dev.of_node, "bus_width", &wb_pci_dev->bus_width); ++ ++ if (ret != 0) { ++ dev_err(&pdev->dev, "Failed to get dts config, ret:%d.\n", ret); ++ return -ENXIO; ++ } ++ ++ ret = 0; ++ ret += of_property_read_u32(pdev->dev.of_node, "upg_ctrl_base", &firmware_upg->upg_ctrl_base); ++ ret += of_property_read_u32(pdev->dev.of_node, "upg_flash_base", &firmware_upg->upg_flash_base); ++ if (ret != 0) { ++ PCIE_DEV_DEBUG_VERBOSE("dts don't adaptive fpga upg related, ret:%d.\n", ret); ++ firmware_upg->upg_ctrl_base = -1; ++ firmware_upg->upg_flash_base = -1; ++ } else { ++ PCIE_DEV_DEBUG_VERBOSE("upg_ctrl_base:0x%04x, upg_flash_base:0x%02x.\n", ++ firmware_upg->upg_ctrl_base, firmware_upg->upg_flash_base); ++ } ++ } else { ++ if (pdev->dev.platform_data == NULL) { ++ dev_err(&pdev->dev, "Failed to get platform data config.\n"); ++ return -ENXIO; ++ } ++ pci_dev_device = pdev->dev.platform_data; ++ wb_pci_dev->name = pci_dev_device->pci_dev_name; ++ wb_pci_dev->domain = pci_dev_device->pci_domain; ++ wb_pci_dev->bus = pci_dev_device->pci_bus; ++ wb_pci_dev->slot = pci_dev_device->pci_slot; ++ wb_pci_dev->fn = pci_dev_device->pci_fn; ++ wb_pci_dev->bar = pci_dev_device->pci_bar; ++ wb_pci_dev->bus_width = pci_dev_device->bus_width; ++ firmware_upg->upg_ctrl_base = pci_dev_device->upg_ctrl_base; ++ firmware_upg->upg_flash_base = pci_dev_device->upg_flash_base; ++ PCIE_DEV_DEBUG_VERBOSE("upg_ctrl_base:0x%04x, upg_flash_base:0x%02x.\n", ++ firmware_upg->upg_ctrl_base, firmware_upg->upg_flash_base); ++ } ++ ++ PCIE_DEV_DEBUG_VERBOSE("name:%s, domain:0x%04x, bus:0x%02x, slot:0x%02x, fn:%u, bar:%u, bus_width:%d.\n", ++ wb_pci_dev->name, wb_pci_dev->domain, wb_pci_dev->bus, wb_pci_dev->slot, wb_pci_dev->fn, ++ wb_pci_dev->bar, wb_pci_dev->bus_width); ++ ++ devfn = PCI_DEVFN(wb_pci_dev->slot, wb_pci_dev->fn); ++ pci_dev = pci_get_domain_bus_and_slot(wb_pci_dev->domain, wb_pci_dev->bus, devfn); ++ if (pci_dev == NULL) { ++ dev_err(&pdev->dev, "Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", ++ wb_pci_dev->domain, wb_pci_dev->bus, devfn); ++ return -ENXIO; ++ } ++ ret = pci_setup_bars(wb_pci_dev, pci_dev); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "Failed to get pci bar address.\n"); ++ return ret; ++ } ++ ++ if (!wb_pci_dev->setreg || !wb_pci_dev->getreg) { ++ switch (wb_pci_dev->bus_width) { ++ case 1: ++ wb_pci_dev->setreg = pci_dev_setreg_8; ++ wb_pci_dev->getreg = pci_dev_getreg_8; ++ break; ++ ++ case 2: ++ wb_pci_dev->setreg = pci_dev_setreg_16; ++ wb_pci_dev->getreg = pci_dev_getreg_16; ++ break; ++ ++ case 4: ++ wb_pci_dev->setreg = pci_dev_setreg_32; ++ wb_pci_dev->getreg = pci_dev_getreg_32; ++ break; ++ default: ++ dev_err(&pdev->dev, "Error: unsupported I/O width (%d).\n", wb_pci_dev->bus_width); ++ ret = -EINVAL; ++ goto io_unmap; ++ } ++ } ++ ++ misc = &wb_pci_dev->misc; ++ misc->minor = MISC_DYNAMIC_MINOR; ++ misc->name = wb_pci_dev->name; ++ misc->fops = &pcie_dev_fops; ++ misc->mode = 0666; ++ if (misc_register(misc) != 0) { ++ dev_err(&pdev->dev, "Failed to register %s device.\n", misc->name); ++ ret = -ENXIO; ++ goto io_unmap; ++ } ++ if (misc->minor >= MAX_PCIE_NUM) { ++ dev_err(&pdev->dev, "Error: device minor[%d] more than max pcie num[%d].\n", ++ misc->minor, MAX_PCIE_NUM); ++ misc_deregister(misc); ++ ret = -EINVAL; ++ goto io_unmap; ++ } ++ pcie_dev_arry[misc->minor] = wb_pci_dev; ++ dev_info(&pdev->dev, "%04x:%02x:%02x.%d[bar%d: %s]: register %s device with minor:%d success.\n", ++ wb_pci_dev->domain, wb_pci_dev->bus, wb_pci_dev->slot, wb_pci_dev->fn, wb_pci_dev->bar, ++ wb_pci_dev->bar_flag == IORESOURCE_MEM ? "IORESOURCE_MEM" : "IORESOURCE_IO", ++ misc->name, misc->minor ); ++ return 0; ++ ++io_unmap: ++ if (wb_pci_dev->pci_mem_base) { ++ iounmap(wb_pci_dev->pci_mem_base); ++ } ++ return ret; ++} ++ ++static int pci_dev_remove(struct platform_device *pdev) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_PCIE_NUM ; i++) { ++ if (pcie_dev_arry[i] != NULL) { ++ if (pcie_dev_arry[i]->pci_mem_base) { ++ iounmap(pcie_dev_arry[i]->pci_mem_base); ++ } ++ misc_deregister(&pcie_dev_arry[i]->misc); ++ pcie_dev_arry[i] = NULL; ++ } ++ } ++ ++ return 0; ++} ++ ++static struct of_device_id pci_dev_match[] = { ++ { ++ .compatible = "wb-pci-dev", ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, pci_dev_match); ++ ++static struct platform_driver wb_pci_dev_driver = { ++ .probe = pci_dev_probe, ++ .remove = pci_dev_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = PROXY_NAME, ++ .of_match_table = pci_dev_match, ++ }, ++}; ++ ++static int __init wb_pci_dev_init(void) ++{ ++ return platform_driver_register(&wb_pci_dev_driver); ++} ++ ++static void __exit wb_pci_dev_exit(void) ++{ ++ platform_driver_unregister(&wb_pci_dev_driver); ++} ++ ++module_init(wb_pci_dev_init); ++module_exit(wb_pci_dev_exit); ++MODULE_DESCRIPTION("pcie device driver"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.h +new file mode 100644 +index 000000000..9ba0f3b45 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.h +@@ -0,0 +1,26 @@ ++#ifndef __WB_PCIE_DEV_H__ ++#define __WB_PCIE_DEV_H__ ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++ ++#define UPG_TYPE 'U' ++#define GET_FPGA_UPG_CTL_BASE _IOR(UPG_TYPE, 0, int) ++#define GET_FPGA_UPG_FLASH_BASE _IOR(UPG_TYPE, 1, int) ++ ++#define PCI_DEV_NAME_MAX_LEN (64) ++ ++typedef struct pci_dev_device_s { ++ char pci_dev_name[PCI_DEV_NAME_MAX_LEN]; ++ int pci_domain; ++ int pci_bus; ++ int pci_slot; ++ int pci_fn; ++ int pci_bar; ++ int bus_width; ++ int upg_ctrl_base; ++ int upg_flash_base; ++ int device_flag; ++} pci_dev_device_t; ++ ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.c +new file mode 100644 +index 000000000..092c99da2 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.c +@@ -0,0 +1,749 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wb_platform_i2c_dev.h" ++ ++#define PROXY_NAME "wb-platform-i2c-dev" ++#define MAX_I2C_DEV_NUM (256) ++#define FPGA_MAX_LEN (256) ++#define MAX_NAME_SIZE (20) ++#define MAX_BUS_WIDTH (16) ++#define TRANSFER_WRITE_BUFF (FPGA_MAX_LEN + MAX_BUS_WIDTH) ++ ++#define WIDTH_1Byte (1) ++#define WIDTH_2Byte (2) ++#define WIDTH_4Byte (4) ++ ++int g_i2c_dev_debug = 0; ++int g_i2c_dev_error = 0; ++ ++module_param(g_i2c_dev_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_i2c_dev_error, int, S_IRUGO | S_IWUSR); ++ ++#define I2C_DEV_DEBUG_DMESG(fmt, args...) do { \ ++ if (g_i2c_dev_debug) { \ ++ printk(KERN_ERR "[I2C_DEV][DEBUG][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define I2C_DEV_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_i2c_dev_error) { \ ++ printk(KERN_ERR "[I2C_DEV][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static struct platform_i2c_dev_info* i2c_dev_arry[MAX_I2C_DEV_NUM]; ++ ++struct platform_i2c_dev_info { ++ uint32_t i2c_bus; ++ uint32_t i2c_addr; ++ const char *name; ++ uint32_t data_bus_width; ++ uint32_t addr_bus_width; ++ uint32_t per_rd_len; ++ uint32_t per_wr_len; ++ struct miscdevice misc; ++}; ++ ++static int transfer_read(struct platform_i2c_dev_info *i2c_dev, u8 *buf, loff_t regaddr, size_t count) ++{ ++ int i, j; ++ struct i2c_adapter *adap; ++ union i2c_smbus_data data; ++ u8 offset_buf[MAX_BUS_WIDTH]; ++ struct i2c_msg msgs[2]; ++ int msgs_num, ret; ++ u8 offset; ++ u8 length; ++ ++ if (!i2c_dev) { ++ I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\r\n"); ++ return -ENODEV; ++ } ++ ++ i = 0; ++ ++ mem_clear(offset_buf, sizeof(offset_buf)); ++ ++ switch (i2c_dev->addr_bus_width) { ++ case WIDTH_4Byte: ++ offset_buf[i++] = (regaddr >> 24) & 0xFF; ++ offset_buf[i++] = (regaddr >> 16) & 0xFF; ++ offset_buf[i++] = (regaddr >> 8) & 0xFF; ++ offset_buf[i++] = regaddr & 0xFF; ++ break; ++ case WIDTH_2Byte: ++ offset_buf[i++] = (regaddr >> 8) & 0xFF; ++ offset_buf[i++] = regaddr & 0xFF; ++ break; ++ case WIDTH_1Byte: ++ offset_buf[i++] = regaddr & 0xFF; ++ break; ++ default: ++ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\r\n", i2c_dev->addr_bus_width); ++ return -EINVAL; ++ } ++ ++ adap = i2c_get_adapter(i2c_dev->i2c_bus); ++ if (adap == NULL) { ++ I2C_DEV_DEBUG_ERROR("get i2c adapter %d faild.\n", i2c_dev->i2c_bus); ++ return -ENXIO; ++ } ++ ++ if (adap->algo->master_xfer) { ++ mem_clear(msgs, sizeof(msgs)); ++ msgs[0].addr = i2c_dev->i2c_addr; ++ msgs[0].flags = 0; ++ msgs[0].len = i2c_dev->addr_bus_width; ++ msgs[0].buf = offset_buf; ++ ++ msgs[1].addr = i2c_dev->i2c_addr; ++ msgs[1].flags = I2C_M_RD; ++ msgs[1].len = count; ++ msgs[1].buf = buf; ++ ++ msgs_num = 2; ++ ret = i2c_transfer(adap, msgs, msgs_num); ++ if (ret != msgs_num) { ++ I2C_DEV_DEBUG_ERROR("i2c_transfer read error\r\n"); ++ ret = -EFAULT; ++ goto error_exit; ++ } ++ } else { ++ if (i2c_dev->addr_bus_width == WIDTH_1Byte) { ++ offset = regaddr & 0xFF; ++ if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { ++ for (j = 0; j < count; j += I2C_SMBUS_BLOCK_MAX) { ++ if (count - j > I2C_SMBUS_BLOCK_MAX) { ++ length = I2C_SMBUS_BLOCK_MAX; ++ } else { ++ length = count - j; ++ } ++ data.block[0] = length; ++ ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, ++ 0, ++ I2C_SMBUS_READ, ++ offset, I2C_SMBUS_I2C_BLOCK_DATA, &data); ++ if (ret) { ++ I2C_DEV_DEBUG_ERROR("smbus_xfer read block error, ret = %d\n", ret); ++ ret = -EFAULT; ++ goto error_exit; ++ } ++ memcpy(buf + j, data.block + 1, length); ++ offset += length; ++ } ++ } else { ++ for (j = 0; j < count; j++) { ++ ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, ++ 0, ++ I2C_SMBUS_READ, ++ offset, I2C_SMBUS_BYTE_DATA, &data); ++ ++ if (!ret) { ++ buf[j] = data.byte; ++ } else { ++ I2C_DEV_DEBUG_ERROR("smbus_xfer read byte error, ret = %d\n", ret); ++ ret = -EFAULT; ++ goto error_exit; ++ } ++ offset++; ++ } ++ } ++ } else { ++ I2C_DEV_DEBUG_ERROR("smbus_xfer not support addr_bus_width = %d\n", i2c_dev->addr_bus_width); ++ ret = -EINVAL; ++ goto error_exit; ++ } ++ } ++ ++ i2c_put_adapter(adap); ++ return 0; ++error_exit: ++ i2c_put_adapter(adap); ++ return ret; ++} ++ ++static int transfer_write(struct platform_i2c_dev_info *i2c_dev, u8 *buf, loff_t regaddr, size_t count) ++{ ++ int i, j; ++ struct i2c_adapter *adap; ++ union i2c_smbus_data data; ++ u8 offset_buf[TRANSFER_WRITE_BUFF]; ++ struct i2c_msg msgs[1]; ++ int msgs_num, ret; ++ u8 offset; ++ u8 length; ++ ++ if (!i2c_dev) { ++ I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\r\n"); ++ return -ENODEV; ++ } ++ ++ i = 0; ++ ++ mem_clear(offset_buf, sizeof(offset_buf)); ++ ++ switch (i2c_dev->addr_bus_width) { ++ case WIDTH_4Byte: ++ offset_buf[i++] = (regaddr >> 24) & 0xFF; ++ offset_buf[i++] = (regaddr >> 16) & 0xFF; ++ offset_buf[i++] = (regaddr >> 8) & 0xFF; ++ offset_buf[i++] = regaddr & 0xFF; ++ break; ++ case WIDTH_2Byte: ++ offset_buf[i++] = (regaddr >> 8) & 0xFF; ++ offset_buf[i++] = regaddr & 0xFF; ++ break; ++ case WIDTH_1Byte: ++ offset_buf[i++] = regaddr & 0xFF; ++ break; ++ default: ++ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\r\n", i2c_dev->addr_bus_width); ++ return -EINVAL; ++ } ++ ++ memcpy(offset_buf + i2c_dev->addr_bus_width, buf, count); ++ ++ adap = i2c_get_adapter(i2c_dev->i2c_bus); ++ if (adap == NULL) { ++ I2C_DEV_DEBUG_ERROR("get i2c adapter %d faild.\n", i2c_dev->i2c_bus); ++ return -ENXIO; ++ } ++ ++ if (adap->algo->master_xfer) { ++ mem_clear(msgs, sizeof(msgs)); ++ ++ msgs[0].addr = i2c_dev->i2c_addr; ++ msgs[0].flags = 0; ++ msgs[0].len = i2c_dev->addr_bus_width + count; ++ msgs[0].buf = offset_buf; ++ ++ msgs_num = 1; ++ ret = i2c_transfer(adap, msgs, msgs_num); ++ if (ret != msgs_num) { ++ I2C_DEV_DEBUG_ERROR("i2c_transfer write error\r\n"); ++ ret = -EFAULT; ++ goto error_exit; ++ } ++ } else { ++ if (i2c_dev->addr_bus_width == WIDTH_1Byte) { ++ offset = regaddr & 0xFF; ++ if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { ++ for (j = 0; j < count; j += I2C_SMBUS_BLOCK_MAX) { ++ if (count - j > I2C_SMBUS_BLOCK_MAX) { ++ length = I2C_SMBUS_BLOCK_MAX; ++ } else { ++ length = count - j; ++ } ++ data.block[0] = length; ++ memcpy(data.block + 1, buf + j, length); ++ ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, ++ 0, ++ I2C_SMBUS_WRITE, ++ offset, I2C_SMBUS_I2C_BLOCK_DATA, &data); ++ if (ret) { ++ I2C_DEV_DEBUG_ERROR("smbus_xfer write block error, ret = %d\r\n", ret); ++ ret = -EFAULT; ++ goto error_exit; ++ } ++ offset += length; ++ } ++ } else { ++ for (j = 0; j < count; j++) { ++ data.byte = buf[j]; ++ ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, ++ 0, ++ I2C_SMBUS_WRITE, ++ offset, I2C_SMBUS_BYTE_DATA, &data); ++ if (ret) { ++ I2C_DEV_DEBUG_ERROR("smbus_xfer write byte error, ret = %d\r\n", ret); ++ ret = -EFAULT; ++ goto error_exit; ++ } ++ offset += 1; ++ } ++ } ++ } else { ++ I2C_DEV_DEBUG_ERROR("smbus_xfer not support addr_bus_width = %d\r\n", i2c_dev->addr_bus_width); ++ ret = -EINVAL; ++ goto error_exit; ++ } ++ } ++ ++ i2c_put_adapter(adap); ++ return 0; ++error_exit: ++ i2c_put_adapter(adap); ++ return ret; ++} ++ ++static long i2c_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ return 0; ++} ++ ++static int i2c_dev_open(struct inode *inode, struct file *file) ++{ ++ unsigned int minor = iminor(inode); ++ struct platform_i2c_dev_info *i2c_dev; ++ ++ i2c_dev = i2c_dev_arry[minor]; ++ if (i2c_dev == NULL) { ++ return -ENODEV; ++ } ++ ++ file->private_data = i2c_dev; ++ ++ return 0; ++} ++ ++static int i2c_dev_release(struct inode *inode, struct file *file) ++{ ++ file->private_data = NULL; ++ ++ return 0; ++} ++ ++static int device_read(struct platform_i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, int count) ++{ ++ int i, j, ret; ++ u8 tmp_offset; ++ u8 val[FPGA_MAX_LEN]; ++ u32 width, rd_len, per_len, tmp; ++ u32 max_per_len; ++ ++ width = i2c_dev->data_bus_width; ++ switch (width) { ++ case WIDTH_4Byte: ++ tmp_offset = offset & 0x3; ++ if (tmp_offset) { ++ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %d invalid.\r\n", width, offset, count); ++ return -EINVAL; ++ } ++ break; ++ case WIDTH_2Byte: ++ tmp_offset = offset & 0x1; ++ if (tmp_offset) { ++ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %d invalid.\r\n", width, offset, count); ++ return -EINVAL; ++ } ++ break; ++ case WIDTH_1Byte: ++ break; ++ default: ++ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\r\n", width); ++ return -EINVAL; ++ } ++ ++ max_per_len = i2c_dev->per_rd_len; ++ tmp = (width - 1) & count; ++ rd_len = (tmp == 0) ? count : count + width - tmp; ++ per_len = (rd_len > max_per_len) ? (max_per_len) : (rd_len); ++ ++ mem_clear(val, sizeof(val)); ++ for (i = 0; i < rd_len; i += per_len) { ++ ret = transfer_read(i2c_dev, val + i, offset + i, per_len); ++ if (ret < 0) { ++ I2C_DEV_DEBUG_ERROR("read error.read offset = %u\r\n", (offset + i)); ++ return -EFAULT; ++ } ++ } ++ ++ if (width == WIDTH_1Byte) { ++ memcpy(buf, val, count); ++ } else { ++ for (i = 0; i < count; i += width) { ++ for (j = 0; (j < width) && (i + j < count); j++) { ++ buf[i + j] = val[i + width - j - 1]; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int device_write(struct platform_i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ int i, j, ret; ++ u8 tmp_offset; ++ u32 width; ++ u8 val[FPGA_MAX_LEN]; ++ u32 wr_len, per_len, tmp; ++ u32 max_per_len; ++ ++ width = i2c_dev->data_bus_width; ++ switch (width) { ++ case WIDTH_4Byte: ++ tmp_offset = offset & 0x3; ++ if (tmp_offset) { ++ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\r\n", width, offset, count); ++ return -EINVAL; ++ } ++ break; ++ case WIDTH_2Byte: ++ tmp_offset = offset & 0x1; ++ if (tmp_offset) { ++ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\r\n", width, offset, count); ++ return -EINVAL; ++ } ++ break; ++ case WIDTH_1Byte: ++ break; ++ default: ++ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\r\n", width); ++ return -EINVAL; ++ } ++ ++ mem_clear(val, sizeof(val)); ++ ++ if (width == WIDTH_1Byte) { ++ memcpy(val, buf, count); ++ } else { ++ for (i = 0; i < count; i += width) { ++ for (j = 0; (j < width) && (i + j < count); j++) { ++ val[i + width - j - 1] = buf[i + j]; ++ } ++ } ++ } ++ ++ max_per_len = i2c_dev->per_wr_len; ++ tmp = (width - 1) & count; ++ wr_len = (tmp == 0) ? count : count + width - tmp; ++ per_len = (wr_len > max_per_len) ? (max_per_len) : (wr_len); ++ ++ for (i = 0; i < wr_len; i += per_len) { ++ ret = transfer_write(i2c_dev, val + i, offset + i, per_len); ++ if (ret < 0) { ++ I2C_DEV_DEBUG_ERROR("write error.offset = %u\r\n", (offset + i)); ++ return -EFAULT; ++ } ++ } ++ return 0; ++} ++ ++static ssize_t i2c_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) ++{ ++ u8 val[FPGA_MAX_LEN]; ++ int ret; ++ struct platform_i2c_dev_info *i2c_dev; ++ ++ if (count <= 0 || count > sizeof(val)) { ++ I2C_DEV_DEBUG_ERROR("read conut %lu , beyond max:%lu.\n", count, sizeof(val)); ++ return -EINVAL; ++ } ++ ++ i2c_dev = file->private_data; ++ if (i2c_dev == NULL) { ++ I2C_DEV_DEBUG_ERROR("can't get read private_data .\r\n"); ++ return -EINVAL; ++ } ++ ++ ret = device_read(i2c_dev, (uint32_t)*offset, val, count); ++ if (ret < 0) { ++ I2C_DEV_DEBUG_ERROR("i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", ++ i2c_dev->name, (uint32_t)*offset, count); ++ return -EINVAL; ++ } ++ ++ if (copy_to_user(buf, val, count)) { ++ I2C_DEV_DEBUG_ERROR("copy_to_user error \r\n"); ++ return -EFAULT; ++ } else{ ++ *offset += count; ++ } ++ ++ return count; ++} ++ ++static ssize_t i2c_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) ++{ ++ u8 val[FPGA_MAX_LEN]; ++ int ret; ++ struct platform_i2c_dev_info *i2c_dev; ++ ++ if (count <= 0 || count > sizeof(val)) { ++ I2C_DEV_DEBUG_ERROR("write conut %lu, beyond max val:%lu.\n", count, sizeof(val)); ++ return -EINVAL; ++ } ++ ++ i2c_dev = file->private_data; ++ if (i2c_dev == NULL) { ++ I2C_DEV_DEBUG_ERROR("get write private_data error.\r\n"); ++ return -EINVAL; ++ } ++ ++ mem_clear(val, sizeof(val)); ++ if (copy_from_user(val, buf, count)) { ++ I2C_DEV_DEBUG_ERROR("copy_from_user error.\r\n"); ++ return -EFAULT; ++ } ++ ++ ret = device_write (i2c_dev, (uint32_t)*offset, val, count); ++ if (ret < 0) { ++ I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%llx, len:%lu.\n", ++ i2c_dev->name, *offset, count); ++ return -EINVAL; ++ } ++ ++ *offset += count; ++ return count; ++} ++ ++static loff_t i2c_dev_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t ret = 0; ++ ++ switch (origin) { ++ case SEEK_SET: ++ if (offset < 0) { ++ I2C_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\r\n", offset); ++ ret = -EINVAL; ++ break; ++ } ++ file->f_pos = offset; ++ ret = file->f_pos; ++ break; ++ case SEEK_CUR: ++ if (file->f_pos + offset < 0) { ++ I2C_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld.\n", ++ file->f_pos, offset); ++ } ++ file->f_pos += offset; ++ ret = file->f_pos; ++ break; ++ default: ++ I2C_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++static const struct file_operations i2c_dev_fops = { ++ .owner = THIS_MODULE, ++ .llseek = i2c_dev_llseek, ++ .read = i2c_dev_read, ++ .write = i2c_dev_write, ++ .unlocked_ioctl = i2c_dev_ioctl, ++ .open = i2c_dev_open, ++ .release = i2c_dev_release, ++}; ++ ++static struct platform_i2c_dev_info * dev_match(const char *path) ++{ ++ struct platform_i2c_dev_info *i2c_dev; ++ char dev_name[MAX_NAME_SIZE]; ++ int i; ++ for (i = 0; i < MAX_I2C_DEV_NUM; i++) { ++ if (i2c_dev_arry[ i ] == NULL) { ++ continue; ++ } ++ i2c_dev = i2c_dev_arry[ i ]; ++ snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", i2c_dev->name); ++ if (!strcmp(path, dev_name)) { ++ I2C_DEV_DEBUG_DMESG("get dev_name = %s, minor = %d\n", dev_name, i); ++ return i2c_dev; ++ } ++ } ++ ++ return NULL; ++} ++ ++int platform_i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ struct platform_i2c_dev_info *i2c_dev = NULL; ++ int ret; ++ ++ if(path == NULL){ ++ I2C_DEV_DEBUG_ERROR("path NULL"); ++ return -EINVAL; ++ } ++ ++ if(buf == NULL){ ++ I2C_DEV_DEBUG_ERROR("buf NULL"); ++ return -EINVAL; ++ } ++ ++ if (count > FPGA_MAX_LEN) { ++ I2C_DEV_DEBUG_ERROR("read conut %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); ++ return -EINVAL; ++ } ++ ++ i2c_dev = dev_match(path); ++ if (i2c_dev == NULL) { ++ I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); ++ return -EINVAL; ++ } ++ ++ ret = device_read(i2c_dev, offset, buf, count); ++ if (ret < 0) { ++ I2C_DEV_DEBUG_ERROR("fpga i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", ++ i2c_dev->name, offset, count); ++ return -EINVAL; ++ } ++ ++ return count; ++} ++EXPORT_SYMBOL(platform_i2c_device_func_read); ++ ++int platform_i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ struct platform_i2c_dev_info *i2c_dev = NULL; ++ int ret; ++ ++ if(path == NULL){ ++ I2C_DEV_DEBUG_ERROR("path NULL"); ++ return -EINVAL; ++ } ++ ++ if(buf == NULL){ ++ I2C_DEV_DEBUG_ERROR("buf NULL"); ++ return -EINVAL; ++ } ++ ++ if (count > FPGA_MAX_LEN) { ++ I2C_DEV_DEBUG_ERROR("write conut %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); ++ return -EINVAL; ++ } ++ ++ i2c_dev = dev_match(path); ++ if (i2c_dev == NULL) { ++ I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); ++ return -EINVAL; ++ } ++ ++ ret = device_write (i2c_dev, offset, buf, count); ++ if (ret < 0) { ++ I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%x, len:%lu.\n", ++ i2c_dev->name, offset, count); ++ return -EINVAL; ++ } ++ ++ return count; ++} ++EXPORT_SYMBOL(platform_i2c_device_func_write); ++ ++static int platform_i2c_dev_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct platform_i2c_dev_info *i2c_dev; ++ struct miscdevice *misc; ++ platform_i2c_dev_device_t *platform_i2c_dev_device; ++ ++ i2c_dev = devm_kzalloc(&pdev->dev, sizeof(struct platform_i2c_dev_info), GFP_KERNEL); ++ if (!i2c_dev) { ++ dev_err(&pdev->dev, "devm_kzalloc error. \r\n"); ++ return -ENOMEM; ++ } ++ ++ if (pdev->dev.of_node) { ++ ++ ret += of_property_read_u32(pdev->dev.of_node, "i2c_bus", &i2c_dev->i2c_bus); ++ ret += of_property_read_u32(pdev->dev.of_node, "i2c_addr", &i2c_dev->i2c_addr); ++ ret += of_property_read_string(pdev->dev.of_node, "i2c_name", &i2c_dev->name); ++ ret += of_property_read_u32(pdev->dev.of_node, "data_bus_width", &i2c_dev->data_bus_width); ++ ret += of_property_read_u32(pdev->dev.of_node, "addr_bus_width", &i2c_dev->addr_bus_width); ++ ret += of_property_read_u32(pdev->dev.of_node, "per_rd_len", &i2c_dev->per_rd_len); ++ ret += of_property_read_u32(pdev->dev.of_node, "per_wr_len", &i2c_dev->per_wr_len); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "dts config error.ret:%d.\r\n", ret); ++ return -ENXIO; ++ } ++ } else { ++ if (pdev->dev.platform_data == NULL) { ++ dev_err(&pdev->dev, "Failed to get platform data config.\n"); ++ return -ENXIO; ++ } ++ platform_i2c_dev_device = pdev->dev.platform_data; ++ i2c_dev->i2c_bus = platform_i2c_dev_device->i2c_bus; ++ i2c_dev->i2c_addr = platform_i2c_dev_device->i2c_addr; ++ i2c_dev->name = platform_i2c_dev_device->i2c_name; ++ i2c_dev->data_bus_width = platform_i2c_dev_device->data_bus_width; ++ i2c_dev->addr_bus_width = platform_i2c_dev_device->addr_bus_width; ++ i2c_dev->per_rd_len = platform_i2c_dev_device->per_rd_len; ++ i2c_dev->per_wr_len = platform_i2c_dev_device->per_wr_len; ++ } ++ ++ if ((i2c_dev->per_rd_len & (i2c_dev->data_bus_width - 1)) || (i2c_dev->per_wr_len & (i2c_dev->data_bus_width - 1))) { ++ dev_err(&pdev->dev, "Invalid config per_rd_len %d per_wr_len %d data bus_width %d.\r\n", i2c_dev->per_rd_len, ++ i2c_dev->per_wr_len, i2c_dev->data_bus_width); ++ return -ENXIO; ++ } ++ ++ misc = &i2c_dev->misc; ++ misc->minor = MISC_DYNAMIC_MINOR; ++ misc->name = i2c_dev->name; ++ misc->fops = &i2c_dev_fops; ++ if (misc_register(misc) != 0) { ++ dev_err(&pdev->dev, "register %s faild.\r\n", misc->name); ++ return -ENXIO; ++ } ++ ++ if (misc->minor >= MAX_I2C_DEV_NUM) { ++ dev_err(&pdev->dev, "minor number beyond the limit! is %d.\r\n", misc->minor); ++ misc_deregister(misc); ++ return -ENXIO; ++ } ++ i2c_dev_arry[misc->minor] = i2c_dev; ++ ++ dev_info(&pdev->dev, "register %u addr_bus_width %u data_bus_width device %s with %u per_rd_len %u per_wr_len success.\r\n", ++ i2c_dev->addr_bus_width, i2c_dev->data_bus_width, i2c_dev->name, i2c_dev->per_rd_len, i2c_dev->per_wr_len); ++ ++ return 0; ++} ++ ++static int platform_i2c_dev_remove(struct platform_device *pdev) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_I2C_DEV_NUM ; i++) { ++ if (i2c_dev_arry[i] != NULL) { ++ misc_deregister(&i2c_dev_arry[i]->misc); ++ i2c_dev_arry[i] = NULL; ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id platform_i2c_dev_of_match[] = { ++ { .compatible = "wb-platform-i2c-dev" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, platform_i2c_dev_of_match); ++ ++static struct platform_driver wb_platform_i2c_dev_driver = { ++ .probe = platform_i2c_dev_probe, ++ .remove = platform_i2c_dev_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = PROXY_NAME, ++ .of_match_table = platform_i2c_dev_of_match, ++ }, ++}; ++ ++static int __init wb_platform_i2c_dev_init(void) ++{ ++ return platform_driver_register(&wb_platform_i2c_dev_driver); ++} ++ ++static void __exit wb_platform_i2c_dev_exit(void) ++{ ++ platform_driver_unregister(&wb_platform_i2c_dev_driver); ++} ++ ++module_init(wb_platform_i2c_dev_init); ++module_exit(wb_platform_i2c_dev_exit); ++ ++MODULE_DESCRIPTION("platform i2c dev driver"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.h +new file mode 100644 +index 000000000..b5158c9fe +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.h +@@ -0,0 +1,19 @@ ++#ifndef __WB_PLATFORM_I2C_DEV_H__ ++#define __WB_PLATFORM_I2C_DEV_H__ ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++#define I2C_DEV_NAME_MAX_LEN (64) ++ ++typedef struct platform_i2c_dev_device_s { ++ uint32_t i2c_bus; ++ uint32_t i2c_addr; ++ char i2c_name[I2C_DEV_NAME_MAX_LEN]; ++ uint32_t data_bus_width; ++ uint32_t addr_bus_width; ++ uint32_t per_rd_len; ++ uint32_t per_wr_len; ++ int device_flag; ++} platform_i2c_dev_device_t; ++ ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_93xx46.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_93xx46.c +new file mode 100644 +index 000000000..abc4f1567 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_93xx46.c +@@ -0,0 +1,111 @@ ++/* ++ * EEPROMs access control driver for display configuration EEPROMs ++ * on DigsyMTC board. ++ * ++ * (C) 2011 DENX Software Engineering, Anatolij Gustschin ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEFAULT_SPI_BUS_NUM (0) ++#define DEFAULT_SPI_CS_NUM (0) ++#define DEFAULT_SPI_HZ (100000) ++ ++#define GPIO_EEPROM_CS (-1) ++ ++int g_wb_spi_93xx46_debug = 0; ++int g_wb_spi_93xx46_error = 0; ++int spi_bus_num = DEFAULT_SPI_BUS_NUM; ++int spi_cs_gpio = GPIO_EEPROM_CS; ++ ++module_param(g_wb_spi_93xx46_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_spi_93xx46_error, int, S_IRUGO | S_IWUSR); ++module_param(spi_bus_num, int, S_IRUGO | S_IWUSR); ++module_param(spi_cs_gpio, int, S_IRUGO | S_IWUSR); ++ ++#define SPI_93xx46_DEBUG_VERBOSE(fmt, args...) do { \ ++ if (g_wb_spi_93xx46_debug) { \ ++ printk(KERN_INFO "[SPI-93xx46][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define SPI_93xx46_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_wb_spi_93xx46_error) { \ ++ printk(KERN_ERR "[SPI-93xx46][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++struct eeprom_93xx46_platform_data eeprom_data = { ++ .flags = EE_ADDR16, ++ .quirks = EEPROM_93XX46_QUIRK_SINGLE_WORD_READ, ++}; ++ ++struct spi_board_info eeprom_93xx46_info __initdata = { ++ .modalias = "wb_93xx46", ++ .max_speed_hz = DEFAULT_SPI_HZ, ++ .bus_num = DEFAULT_SPI_BUS_NUM, ++ .chip_select = DEFAULT_SPI_CS_NUM, ++ .mode = SPI_MODE_0 | SPI_CS_HIGH, ++ .controller_data = (void *)GPIO_EEPROM_CS, ++ .platform_data = &eeprom_data, ++}; ++ ++static struct spi_device *g_spi_device; ++ ++static int __init wb_spi_93xx46_init(void) ++{ ++ struct spi_master *master; ++ ++ SPI_93xx46_DEBUG_VERBOSE("Enter.\n"); ++ ++ eeprom_93xx46_info.bus_num = spi_bus_num; ++ eeprom_93xx46_info.controller_data = (void *)(long)spi_cs_gpio; ++ master = spi_busnum_to_master(eeprom_93xx46_info.bus_num); ++ if (!master) { ++ SPI_93xx46_DEBUG_ERROR("get bus_num %u spi master failed.\n", ++ eeprom_93xx46_info.bus_num); ++ return -EINVAL; ++ } ++ ++ g_spi_device = spi_new_device(master, &eeprom_93xx46_info); ++ put_device(&master->dev); ++ if (!g_spi_device) { ++ SPI_93xx46_DEBUG_ERROR("register spi new device failed.\n"); ++ return -EPERM; ++ } ++ ++ if (g_wb_spi_93xx46_debug) { ++ dev_info(&g_spi_device->dev, "register %u bus_num spi 93xx46 eeprom success\n", ++ eeprom_93xx46_info.bus_num); ++ } ++ ++ return 0; ++} ++ ++static void __exit wb_spi_93xx46_exit(void) ++{ ++ spi_unregister_device(g_spi_device); ++ ++ if (g_wb_spi_93xx46_debug) { ++ dev_info(&g_spi_device->dev, "unregister spi 93xx46 eeprom success\n"); ++ } ++ ++ return; ++} ++ ++module_init(wb_spi_93xx46_init); ++module_exit(wb_spi_93xx46_exit); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("create 93xx46 eeprom device"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.c +new file mode 100644 +index 000000000..b569ace32 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.c +@@ -0,0 +1,684 @@ ++/* ++ * wb_spi_dev.c ++ * ko to read/write spi device through /dev/XXX device ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wb_spi_dev.h" ++ ++#define MAX_SPI_DEV_NUM (256) ++#define MAX_RW_LEN (256) ++#define MAX_NAME_SIZE (20) ++#define MAX_ADDR_BUS_WIDTH (4) ++ ++#define TRANSFER_WRITE_BUFF (1 + MAX_ADDR_BUS_WIDTH + MAX_RW_LEN) ++ ++#define WIDTH_1Byte (1) ++#define WIDTH_2Byte (2) ++#define WIDTH_4Byte (4) ++ ++#define OP_READ (0x3) ++#define OP_WRITE (0x2) ++ ++static int g_spi_dev_debug = 0; ++static int g_spi_dev_error = 0; ++ ++module_param(g_spi_dev_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_spi_dev_error, int, S_IRUGO | S_IWUSR); ++ ++#define SPI_DEV_DEBUG(fmt, args...) do { \ ++ if (g_spi_dev_debug) { \ ++ printk(KERN_ERR "[SPI_DEV][DEBUG][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define SPI_DEV_ERROR(fmt, args...) do { \ ++ if (g_spi_dev_error) { \ ++ printk(KERN_ERR "[SPI_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static struct spi_dev_info* spi_dev_arry[MAX_SPI_DEV_NUM]; ++ ++struct spi_dev_info { ++ const char *name; ++ uint32_t data_bus_width; ++ uint32_t addr_bus_width; ++ uint32_t per_rd_len; ++ uint32_t per_wr_len; ++ uint32_t spi_len; ++ struct miscdevice misc; ++ struct spi_device *spi_device; ++}; ++ ++static int transfer_read(struct spi_dev_info *spi_dev, u8 *buf, uint32_t regaddr, size_t count) ++{ ++ int i, ret; ++ u8 tx_buf[MAX_ADDR_BUS_WIDTH + 1]; ++ struct spi_message m; ++ struct spi_transfer xfer[2]; ++ ++ i = 0; ++ mem_clear(tx_buf, sizeof(tx_buf)); ++ tx_buf[i++] = OP_READ; ++ ++ switch (spi_dev->addr_bus_width) { ++ case WIDTH_4Byte: ++ tx_buf[i++] = (regaddr >> 24) & 0xFF; ++ tx_buf[i++] = (regaddr >> 16) & 0xFF; ++ tx_buf[i++] = (regaddr >> 8) & 0xFF; ++ tx_buf[i++] = regaddr & 0xFF; ++ break; ++ case WIDTH_2Byte: ++ tx_buf[i++] = (regaddr >> 8) & 0xFF; ++ tx_buf[i++] = regaddr & 0xFF; ++ break; ++ case WIDTH_1Byte: ++ tx_buf[i++] = regaddr & 0xFF; ++ break; ++ default: ++ SPI_DEV_ERROR("Only support 1,2,4 Byte Width,but set width = %u\n", ++ spi_dev->addr_bus_width); ++ return -EINVAL; ++ } ++ ++ mem_clear(xfer, sizeof(xfer)); ++ spi_message_init(&m); ++ xfer[0].tx_buf = tx_buf; ++ xfer[0].len = spi_dev->addr_bus_width + 1; ++ spi_message_add_tail(&xfer[0], &m); ++ ++ xfer[1].rx_buf = buf; ++ xfer[1].len = count; ++ spi_message_add_tail(&xfer[1], &m); ++ ++ ret = spi_sync(spi_dev->spi_device, &m); ++ if (ret) { ++ SPI_DEV_ERROR("transfer_read failed, reg addr:0x%x, len:%lu, ret:%d.\n", ++ regaddr, count, ret); ++ return -EIO; ++ } ++ return 0; ++} ++ ++static int transfer_write(struct spi_dev_info *spi_dev, u8 *buf, uint32_t regaddr, size_t count) ++{ ++ int i, ret; ++ u8 tx_buf[TRANSFER_WRITE_BUFF]; ++ struct spi_message m; ++ struct spi_transfer xfer ; ++ ++ i = 0; ++ mem_clear(tx_buf, sizeof(tx_buf)); ++ tx_buf[i++] = OP_WRITE; ++ switch (spi_dev->addr_bus_width) { ++ case WIDTH_4Byte: ++ tx_buf[i++] = (regaddr >> 24) & 0xFF; ++ tx_buf[i++] = (regaddr >> 16) & 0xFF; ++ tx_buf[i++] = (regaddr >> 8) & 0xFF; ++ tx_buf[i++] = regaddr & 0xFF; ++ break; ++ case WIDTH_2Byte: ++ tx_buf[i++] = (regaddr >> 8) & 0xFF; ++ tx_buf[i++] = regaddr & 0xFF; ++ break; ++ case WIDTH_1Byte: ++ tx_buf[i++] = regaddr & 0xFF; ++ break; ++ default: ++ SPI_DEV_ERROR("Only support 1,2,4 Byte Width, but set width = %u\n", ++ spi_dev->addr_bus_width); ++ return -EINVAL; ++ } ++ ++ memcpy(tx_buf + i, buf, count); ++ ++ mem_clear(&xfer, sizeof(xfer)); ++ spi_message_init(&m); ++ xfer.tx_buf = tx_buf; ++ xfer.len = count + i; ++ spi_message_add_tail(&xfer, &m); ++ ++ ret = spi_sync(spi_dev->spi_device, &m); ++ if (ret) { ++ SPI_DEV_ERROR("transfer_write failed, reg addr:0x%x, len:%lu, ret:%d.\n", ++ regaddr, count, ret); ++ return -EIO; ++ } ++ return 0; ++} ++ ++static long spi_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ return 0; ++} ++ ++static int spi_dev_open(struct inode *inode, struct file *file) ++{ ++ unsigned int minor = iminor(inode); ++ struct spi_dev_info *spi_dev; ++ ++ if (minor >= MAX_SPI_DEV_NUM) { ++ SPI_DEV_ERROR("minor out of range, minor = %d.\n", minor); ++ return -ENODEV; ++ } ++ ++ spi_dev = spi_dev_arry[minor]; ++ if (spi_dev == NULL) { ++ SPI_DEV_ERROR("spi_dev is NULL, open failed, minor = %d\n", minor); ++ return -ENODEV; ++ } ++ ++ file->private_data = spi_dev; ++ ++ return 0; ++} ++ ++static int spi_dev_release(struct inode *inode, struct file *file) ++{ ++ file->private_data = NULL; ++ ++ return 0; ++} ++ ++static int device_read(struct spi_dev_info *spi_dev, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ int i, j, ret; ++ u8 val[MAX_RW_LEN]; ++ u32 data_width, rd_len, per_len, tmp; ++ u32 max_per_len; ++ ++ if (offset > spi_dev->spi_len) { ++ SPI_DEV_DEBUG("offset: 0x%x, spi len: 0x%x, count: %lu, EOF.\n", ++ offset, spi_dev->spi_len, count); ++ return 0; ++ } ++ ++ data_width = spi_dev->data_bus_width; ++ if (offset % data_width) { ++ SPI_DEV_ERROR("data bus width:%d, offset:0x%x, read size %lu invalid.\n", ++ data_width, offset, count); ++ return -EINVAL; ++ } ++ ++ if (count > (spi_dev->spi_len - offset)) { ++ SPI_DEV_DEBUG("read count out of range. input len:%lu, read len:%u.\n", ++ count, spi_dev->spi_len - offset); ++ count = spi_dev->spi_len - offset; ++ } ++ ++ if (count == 0) { ++ SPI_DEV_DEBUG("offset: 0x%x, spi len: 0x%x, read len: %lu, EOF.\n", ++ offset, spi_dev->spi_len, count); ++ return 0; ++ } ++ ++ max_per_len = spi_dev->per_rd_len; ++ tmp = (data_width - 1) & count; ++ rd_len = (tmp == 0) ? count : count + data_width - tmp; ++ per_len = (rd_len > max_per_len) ? (max_per_len) : (rd_len); ++ ++ mem_clear(val, sizeof(val)); ++ for (i = 0; i < rd_len; i += per_len) { ++ ret = transfer_read(spi_dev, val + i, offset + i, per_len); ++ if (ret < 0) { ++ SPI_DEV_ERROR("read error.read offset = %u\n", (offset + i)); ++ return -EFAULT; ++ } ++ } ++ ++ if (data_width == WIDTH_1Byte) { ++ memcpy(buf, val, count); ++ } else { ++ for (i = 0; i < count; i += data_width) { ++ for (j = 0; (j < data_width) && (i + j < count); j++) { ++ buf[i + j] = val[i + data_width - j - 1]; ++ } ++ } ++ } ++ ++ return count; ++} ++ ++static int device_write(struct spi_dev_info *spi_dev, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ int i, j, ret; ++ u32 data_width; ++ u8 val[MAX_RW_LEN]; ++ u32 wr_len, per_len, tmp; ++ u32 max_per_len; ++ ++ if (offset > spi_dev->spi_len) { ++ SPI_DEV_DEBUG("offset: 0x%x, spi len: 0x%x, count: %lu, EOF.\n", ++ offset, spi_dev->spi_len, count); ++ return 0; ++ } ++ ++ data_width = spi_dev->data_bus_width; ++ if (offset % data_width) { ++ SPI_DEV_ERROR("data bus width:%d, offset:0x%x, read size %lu invalid.\n", ++ data_width, offset, count); ++ return -EINVAL; ++ } ++ ++ if (count > (spi_dev->spi_len - offset)) { ++ SPI_DEV_DEBUG("read count out of range. input len:%lu, read len:%u.\n", ++ count, spi_dev->spi_len - offset); ++ count = spi_dev->spi_len - offset; ++ } ++ ++ if (count == 0) { ++ SPI_DEV_DEBUG("offset: 0x%x, i2c len: 0x%x, read len: %lu, EOF.\n", ++ offset, spi_dev->spi_len, count); ++ return 0; ++ } ++ ++ mem_clear(val, sizeof(val)); ++ ++ if (data_width == WIDTH_1Byte) { ++ memcpy(val, buf, count); ++ } else { ++ for (i = 0; i < count; i += data_width) { ++ for (j = 0; (j < data_width) && (i + j < count); j++) { ++ val[i + data_width - j - 1] = buf[i + j]; ++ } ++ } ++ } ++ ++ max_per_len = spi_dev->per_wr_len; ++ tmp = (data_width - 1) & count; ++ wr_len = (tmp == 0) ? count : count + data_width - tmp; ++ per_len = (wr_len > max_per_len) ? (max_per_len) : (wr_len); ++ ++ for (i = 0; i < wr_len; i += per_len) { ++ ret = transfer_write(spi_dev, val + i, offset + i, per_len); ++ if (ret < 0) { ++ SPI_DEV_ERROR("write error.offset = %u\n", (offset + i)); ++ return -EFAULT; ++ } ++ } ++ return count; ++} ++ ++static ssize_t spi_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) ++{ ++ u8 val[MAX_RW_LEN]; ++ int ret, read_len; ++ struct spi_dev_info *spi_dev; ++ ++ spi_dev = file->private_data; ++ if (spi_dev == NULL) { ++ SPI_DEV_ERROR("can't get read private_data.\n"); ++ return -EINVAL; ++ } ++ ++ if (count == 0) { ++ SPI_DEV_ERROR("Invalid params, read count is 0.\n"); ++ return -EINVAL; ++ } ++ ++ if (count > sizeof(val)) { ++ SPI_DEV_DEBUG("read count %lu exceed max %lu.\n", count, sizeof(val)); ++ count = sizeof(val); ++ } ++ ++ mem_clear(val, sizeof(val)); ++ read_len = device_read(spi_dev, (uint32_t)*offset, val, count); ++ if (read_len < 0) { ++ SPI_DEV_ERROR("spi dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", ++ spi_dev->name, (uint32_t)*offset, count); ++ return read_len; ++ } ++ ++ if (access_ok(buf, read_len)) { ++ SPI_DEV_DEBUG("user space read, buf: %p, offset: %lld, read count %lu.\n", ++ buf, *offset, count); ++ if (copy_to_user(buf, val, read_len)) { ++ SPI_DEV_ERROR("copy_to_user failed.\n"); ++ return -EFAULT; ++ } ++ } else { ++ SPI_DEV_DEBUG("kernel space read, buf: %p, offset: %lld, read count %lu.\n", ++ buf, *offset, count); ++ memcpy(buf, val, read_len); ++ } ++ ++ *offset += read_len; ++ ret = read_len; ++ return ret; ++} ++ ++static ssize_t spi_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) ++{ ++ int ret; ++ ++ SPI_DEV_DEBUG("spi_dev_read_iter, file: %p, count: %lu, offset: %lld\n", ++ iocb->ki_filp, to->count, iocb->ki_pos); ++ ret = spi_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos); ++ return ret; ++} ++ ++static ssize_t spi_dev_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *offset) ++{ ++ u8 val[MAX_RW_LEN]; ++ int write_len; ++ struct spi_dev_info *spi_dev; ++ ++ spi_dev = file->private_data; ++ if (spi_dev == NULL) { ++ SPI_DEV_ERROR("get write private_data error.\n"); ++ return -EINVAL; ++ } ++ ++ if (count == 0) { ++ SPI_DEV_ERROR("Invalid params, write count is 0.\n"); ++ return -EINVAL; ++ } ++ ++ if (count > sizeof(val)) { ++ SPI_DEV_DEBUG("write count %lu exceed max %lu.\n", count, sizeof(val)); ++ count = sizeof(val); ++ } ++ ++ mem_clear(val, sizeof(val)); ++ if (access_ok(buf, count)) { ++ SPI_DEV_DEBUG("user space write, buf: %p, offset: %lld, write count %lu.\n", ++ buf, *offset, count); ++ if (copy_from_user(val, buf, count)) { ++ SPI_DEV_ERROR("copy_from_user failed.\n"); ++ return -EFAULT; ++ } ++ } else { ++ SPI_DEV_DEBUG("kernel space write, buf: %p, offset: %lld, write count %lu.\n", ++ buf, *offset, count); ++ memcpy(val, buf, count); ++ } ++ ++ write_len = device_write(spi_dev, (uint32_t)*offset, val, count); ++ if (write_len < 0) { ++ SPI_DEV_ERROR("spi dev write failed, dev name:%s, offset:0x%llx, len:%lu.\n", ++ spi_dev->name, *offset, count); ++ return write_len; ++ } ++ ++ *offset += write_len; ++ return write_len; ++} ++ ++static ssize_t spi_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) ++{ ++ int ret; ++ ++ SPI_DEV_DEBUG("spi_dev_write_iter, file: %p, count: %lu, offset: %lld\n", ++ iocb->ki_filp, from->count, iocb->ki_pos); ++ ret = spi_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos); ++ return ret; ++} ++ ++static loff_t spi_dev_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t ret = 0; ++ struct spi_dev_info *spi_dev; ++ ++ spi_dev = file->private_data; ++ if (spi_dev == NULL) { ++ SPI_DEV_ERROR("spi_dev is NULL, llseek failed.\n"); ++ return -EINVAL; ++ } ++ ++ switch (origin) { ++ case SEEK_SET: ++ if (offset < 0) { ++ SPI_DEV_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); ++ ret = -EINVAL; ++ break; ++ } ++ if (offset > spi_dev->spi_len) { ++ SPI_DEV_ERROR("SEEK_SET out of range, offset:%lld, i2c_len:0x%x.\n", ++ offset, spi_dev->spi_len); ++ ret = - EINVAL; ++ break; ++ } ++ file->f_pos = offset; ++ ret = file->f_pos; ++ break; ++ case SEEK_CUR: ++ if (((file->f_pos + offset) > spi_dev->spi_len) || ((file->f_pos + offset) < 0)) { ++ SPI_DEV_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld.\n", ++ file->f_pos, offset); ++ } ++ file->f_pos += offset; ++ ret = file->f_pos; ++ break; ++ default: ++ SPI_DEV_ERROR("unsupport llseek type:%d.\n", origin); ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++static const struct file_operations spi_dev_fops = { ++ .owner = THIS_MODULE, ++ .llseek = spi_dev_llseek, ++ .read_iter = spi_dev_read_iter, ++ .write_iter = spi_dev_write_iter, ++ .unlocked_ioctl = spi_dev_ioctl, ++ .open = spi_dev_open, ++ .release = spi_dev_release, ++}; ++ ++static struct spi_dev_info * dev_match(const char *path) ++{ ++ struct spi_dev_info * spi_dev; ++ char dev_name[MAX_NAME_SIZE]; ++ int i; ++ for (i = 0; i < MAX_SPI_DEV_NUM; i++) { ++ if (spi_dev_arry[ i ] == NULL) { ++ continue; ++ } ++ spi_dev = spi_dev_arry[ i ]; ++ snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", spi_dev->name); ++ if (!strcmp(path, dev_name)) { ++ SPI_DEV_DEBUG("get dev_name = %s, minor = %d\n", dev_name, i); ++ return spi_dev; ++ } ++ } ++ ++ return NULL; ++} ++ ++int spi_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ struct spi_dev_info *spi_dev = NULL; ++ int ret; ++ ++ if(path == NULL){ ++ SPI_DEV_ERROR("path NULL"); ++ return -EINVAL; ++ } ++ ++ if(buf == NULL){ ++ SPI_DEV_ERROR("buf NULL"); ++ return -EINVAL; ++ } ++ ++ if (count > MAX_RW_LEN) { ++ SPI_DEV_ERROR("read count %lu, beyond max:%d.\n", count, MAX_RW_LEN); ++ return -EINVAL; ++ } ++ ++ spi_dev = dev_match(path); ++ if (spi_dev == NULL) { ++ SPI_DEV_ERROR("spi_dev match failed. dev path = %s", path); ++ return -EINVAL; ++ } ++ ++ ret = device_read(spi_dev, offset, buf, count); ++ if (ret < 0) { ++ SPI_DEV_ERROR("spi dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", ++ spi_dev->name, offset, count); ++ return -EINVAL; ++ } ++ ++ return count; ++} ++EXPORT_SYMBOL(spi_device_func_read); ++ ++int spi_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) ++{ ++ struct spi_dev_info *spi_dev = NULL; ++ int ret; ++ ++ if(path == NULL){ ++ SPI_DEV_ERROR("path NULL"); ++ return -EINVAL; ++ } ++ ++ if(buf == NULL){ ++ SPI_DEV_ERROR("buf NULL"); ++ return -EINVAL; ++ } ++ ++ if (count > MAX_RW_LEN) { ++ SPI_DEV_ERROR("write count %lu, beyond max:%d.\n", count, MAX_RW_LEN); ++ return -EINVAL; ++ } ++ ++ spi_dev = dev_match(path); ++ if (spi_dev == NULL) { ++ SPI_DEV_ERROR("i2c_dev match failed. dev path = %s", path); ++ return -EINVAL; ++ } ++ ++ ret = device_write (spi_dev, offset, buf, count); ++ if (ret < 0) { ++ SPI_DEV_ERROR("i2c dev write failed, dev name:%s, offset:0x%x, len:%lu.\n", ++ spi_dev->name, offset, count); ++ return -EINVAL; ++ } ++ ++ return count; ++} ++EXPORT_SYMBOL(spi_device_func_write); ++ ++static int spi_dev_probe(struct spi_device *spi) ++{ ++ int ret; ++ struct spi_dev_info *spi_dev; ++ struct miscdevice *misc; ++ spi_dev_device_t *spi_dev_device; ++ ++ spi_dev = devm_kzalloc(&spi->dev, sizeof(struct spi_dev_info), GFP_KERNEL); ++ if (!spi_dev) { ++ dev_err(&spi->dev, "devm_kzalloc error. \n"); ++ return -ENOMEM; ++ } ++ ++ spi_set_drvdata(spi, spi_dev); ++ spi_dev->spi_device = spi; ++ ++ if (spi->dev.of_node) { ++ ++ ret = 0; ++ ret += of_property_read_string(spi->dev.of_node, "spi_dev_name", &spi_dev->name); ++ ret += of_property_read_u32(spi->dev.of_node, "data_bus_width", &spi_dev->data_bus_width); ++ ret += of_property_read_u32(spi->dev.of_node, "addr_bus_width", &spi_dev->addr_bus_width); ++ ret += of_property_read_u32(spi->dev.of_node, "per_rd_len", &spi_dev->per_rd_len); ++ ret += of_property_read_u32(spi->dev.of_node, "per_wr_len", &spi_dev->per_wr_len); ++ ret += of_property_read_u32(spi->dev.of_node, "spi_len", &spi_dev->spi_len); ++ if (ret != 0) { ++ dev_err(&spi->dev, "dts config error.ret:%d.\n", ret); ++ return -ENXIO; ++ } ++ } else { ++ if (spi->dev.platform_data == NULL) { ++ dev_err(&spi->dev, "Failed to get platform data config.\n"); ++ return -ENXIO; ++ } ++ spi_dev_device = spi->dev.platform_data; ++ spi_dev->name = spi_dev_device->spi_dev_name; ++ spi_dev->data_bus_width = spi_dev_device->data_bus_width; ++ spi_dev->addr_bus_width = spi_dev_device->addr_bus_width; ++ spi_dev->per_rd_len = spi_dev_device->per_rd_len; ++ spi_dev->per_wr_len = spi_dev_device->per_wr_len; ++ spi_dev->spi_len = spi_dev_device->spi_len; ++ } ++ ++ if ((spi_dev->per_rd_len & (spi_dev->data_bus_width - 1)) ++ || (spi_dev->per_wr_len & (spi_dev->data_bus_width - 1))) { ++ dev_err(&spi->dev, "Invalid config per_rd_len [%u] per_wr_len [%u] data bus_width [%u], addr bus width [%u].\n", ++ spi_dev->per_rd_len, spi_dev->per_wr_len, spi_dev->data_bus_width, spi_dev->addr_bus_width); ++ return -ENXIO; ++ } ++ ++ misc = &spi_dev->misc; ++ misc->minor = MISC_DYNAMIC_MINOR; ++ misc->name = spi_dev->name; ++ misc->fops = &spi_dev_fops; ++ misc->mode = 0666; ++ if (misc_register(misc) != 0) { ++ dev_err(&spi->dev, "register %s faild.\n", misc->name); ++ return -ENXIO; ++ } ++ ++ if (misc->minor >= MAX_SPI_DEV_NUM) { ++ dev_err(&spi->dev, "minor number beyond the limit! is %d.\n", misc->minor); ++ misc_deregister(misc); ++ return -ENXIO; ++ } ++ spi_dev_arry[misc->minor] = spi_dev; ++ ++ dev_info(&spi->dev, "register %u data_bus_width %u addr_bus_witdh 0x%x spi_len device %s with %u per_rd_len %u per_wr_len success.\n", ++ spi_dev->data_bus_width, spi_dev->addr_bus_width, spi_dev->spi_len, spi_dev->name, spi_dev->per_rd_len, spi_dev->per_wr_len); ++ ++ return 0; ++} ++ ++static int spi_dev_remove(struct spi_device *spi) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_SPI_DEV_NUM; i++) { ++ if (spi_dev_arry[i] != NULL) { ++ misc_deregister(&spi_dev_arry[i]->misc); ++ spi_dev_arry[i] = NULL; ++ } ++ } ++ return 0; ++} ++ ++static const struct of_device_id spi_dev_of_match[] = { ++ { .compatible = "wb-spi-dev" }, ++ { }, ++}; ++ ++MODULE_DEVICE_TABLE(of, spi_dev_of_match); ++ ++static struct spi_driver spi_dev_driver = { ++ .driver = { ++ .name = "wb-spi-dev", ++ .of_match_table = of_match_ptr(spi_dev_of_match), ++ }, ++ .probe = spi_dev_probe, ++ .remove = spi_dev_remove, ++}; ++ ++module_spi_driver(spi_dev_driver); ++ ++MODULE_DESCRIPTION("spi dev driver"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.h +new file mode 100644 +index 000000000..fed5237e3 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.h +@@ -0,0 +1,17 @@ ++#ifndef __WB_SPI_DEV_H__ ++#define __WB_SPI_DEV_H__ ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++#define SPI_DEV_NAME_MAX_LEN (64) ++ ++typedef struct spi_dev_device_s { ++ char spi_dev_name[SPI_DEV_NAME_MAX_LEN]; ++ uint32_t data_bus_width; ++ uint32_t addr_bus_width; ++ uint32_t per_rd_len; ++ uint32_t per_wr_len; ++ uint32_t spi_len; ++} spi_dev_device_t; ++ ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio.c +new file mode 100644 +index 000000000..16408f067 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio.c +@@ -0,0 +1,477 @@ ++/* ++ * SPI master driver using generic bitbanged GPIO ++ * ++ * Copyright (C) 2006,2008 David Brownell ++ * Copyright (C) 2017 Linus Walleij ++ * ++ * 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. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* ++ * This bitbanging SPI master driver should help make systems usable ++ * when a native hardware SPI engine is not available, perhaps because ++ * its driver isn't yet working or because the I/O pins it requires ++ * are used for other purposes. ++ * ++ * platform_device->driver_data ... points to spi_gpio ++ * ++ * spi->controller_state ... reserved for bitbang framework code ++ * spi->controller_data ... holds chipselect GPIO ++ * ++ * spi->master->dev.driver_data ... points to spi_gpio->bitbang ++ */ ++ ++struct spi_gpio { ++ struct spi_bitbang bitbang; ++ struct spi_gpio_platform_data pdata; ++ struct platform_device *pdev; ++ struct gpio_desc *sck; ++ struct gpio_desc *miso; ++ struct gpio_desc *mosi; ++ struct gpio_desc **cs_gpios; ++ bool has_cs; ++}; ++ ++/*----------------------------------------------------------------------*/ ++ ++/* ++ * Because the overhead of going through four GPIO procedure calls ++ * per transferred bit can make performance a problem, this code ++ * is set up so that you can use it in either of two ways: ++ * ++ * - The slow generic way: set up platform_data to hold the GPIO ++ * numbers used for MISO/MOSI/SCK, and issue procedure calls for ++ * each of them. This driver can handle several such busses. ++ * ++ * - The quicker inlined way: only helps with platform GPIO code ++ * that inlines operations for constant GPIOs. This can give ++ * you tight (fast!) inner loops, but each such bus needs a ++ * new driver. You'll define a new C file, with Makefile and ++ * Kconfig support; the C code can be a total of six lines: ++ * ++ * #define DRIVER_NAME "myboard_spi2" ++ * #define SPI_MISO_GPIO 119 ++ * #define SPI_MOSI_GPIO 120 ++ * #define SPI_SCK_GPIO 121 ++ * #define SPI_N_CHIPSEL 4 ++ * #include "spi-gpio.c" ++ */ ++ ++#ifndef DRIVER_NAME ++#define DRIVER_NAME "wb_spi_gpio" ++ ++#define GENERIC_BITBANG /* vs tight inlines */ ++ ++#endif ++ ++/*----------------------------------------------------------------------*/ ++ ++static inline struct spi_gpio *__pure ++spi_to_spi_gpio(const struct spi_device *spi) ++{ ++ const struct spi_bitbang *bang; ++ struct spi_gpio *spi_gpio; ++ ++ bang = spi_master_get_devdata(spi->master); ++ spi_gpio = container_of(bang, struct spi_gpio, bitbang); ++ return spi_gpio; ++} ++ ++static inline struct spi_gpio_platform_data *__pure ++spi_to_pdata(const struct spi_device *spi) ++{ ++ return &spi_to_spi_gpio(spi)->pdata; ++} ++ ++/* These helpers are in turn called by the bitbang inlines */ ++static inline void setsck(const struct spi_device *spi, int is_on) ++{ ++ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); ++ ++ gpiod_set_value_cansleep(spi_gpio->sck, is_on); ++} ++ ++static inline void setmosi(const struct spi_device *spi, int is_on) ++{ ++ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); ++ ++ gpiod_set_value_cansleep(spi_gpio->mosi, is_on); ++} ++ ++static inline int getmiso(const struct spi_device *spi) ++{ ++ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); ++ ++ if (spi->mode & SPI_3WIRE) ++ return !!gpiod_get_value_cansleep(spi_gpio->mosi); ++ else ++ return !!gpiod_get_value_cansleep(spi_gpio->miso); ++} ++ ++/* ++ * NOTE: this clocks "as fast as we can". It "should" be a function of the ++ * requested device clock. Software overhead means we usually have trouble ++ * reaching even one Mbit/sec (except when we can inline bitops), so for now ++ * we'll just assume we never need additional per-bit slowdowns. ++ */ ++#define spidelay(nsecs) do {} while (0) ++ ++#include "spi-bitbang-txrx.h" ++ ++/* ++ * These functions can leverage inline expansion of GPIO calls to shrink ++ * costs for a txrx bit, often by factors of around ten (by instruction ++ * count). That is particularly visible for larger word sizes, but helps ++ * even with default 8-bit words. ++ * ++ * REVISIT overheads calling these functions for each word also have ++ * significant performance costs. Having txrx_bufs() calls that inline ++ * the txrx_word() logic would help performance, e.g. on larger blocks ++ * used with flash storage or MMC/SD. There should also be ways to make ++ * GCC be less stupid about reloading registers inside the I/O loops, ++ * even without inlined GPIO calls; __attribute__((hot)) on GCC 4.3? ++ */ ++ ++static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits, unsigned flags) ++{ ++ return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits); ++} ++ ++static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits, unsigned flags) ++{ ++ return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits); ++} ++ ++static u32 spi_gpio_txrx_word_mode2(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits, unsigned flags) ++{ ++ return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits); ++} ++ ++static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits, unsigned flags) ++{ ++ return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits); ++} ++ ++/* ++ * These functions do not call setmosi or getmiso if respective flag ++ * (SPI_MASTER_NO_RX or SPI_MASTER_NO_TX) is set, so they are safe to ++ * call when such pin is not present or defined in the controller. ++ * A separate set of callbacks is defined to get highest possible ++ * speed in the generic case (when both MISO and MOSI lines are ++ * available), as optimiser will remove the checks when argument is ++ * constant. ++ */ ++ ++static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits, unsigned flags) ++{ ++ flags = spi->master->flags; ++ return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits); ++} ++ ++static u32 spi_gpio_spec_txrx_word_mode1(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits, unsigned flags) ++{ ++ flags = spi->master->flags; ++ return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits); ++} ++ ++static u32 spi_gpio_spec_txrx_word_mode2(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits, unsigned flags) ++{ ++ flags = spi->master->flags; ++ return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits); ++} ++ ++static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits, unsigned flags) ++{ ++ flags = spi->master->flags; ++ return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits); ++} ++ ++/*----------------------------------------------------------------------*/ ++ ++static void spi_gpio_chipselect(struct spi_device *spi, int is_active) ++{ ++ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); ++ ++ /* set initial clock line level */ ++ if (is_active) ++ gpiod_set_value_cansleep(spi_gpio->sck, spi->mode & SPI_CPOL); ++ ++ /* Drive chip select line, if we have one */ ++ if (spi_gpio->has_cs) { ++ struct gpio_desc *cs = spi_gpio->cs_gpios[spi->chip_select]; ++ ++ /* SPI chip selects are normally active-low */ ++ gpiod_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active); ++ } ++} ++ ++static int spi_gpio_setup(struct spi_device *spi) ++{ ++ struct gpio_desc *cs; ++ int status = 0; ++ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); ++ ++ /* ++ * The CS GPIOs have already been ++ * initialized from the descriptor lookup. ++ */ ++ cs = spi_gpio->cs_gpios[spi->chip_select]; ++ if (!spi->controller_state && cs) ++ status = gpiod_direction_output(cs, ++ !(spi->mode & SPI_CS_HIGH)); ++ ++ if (!status) ++ status = spi_bitbang_setup(spi); ++ ++ return status; ++} ++ ++static int spi_gpio_set_direction(struct spi_device *spi, bool output) ++{ ++ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); ++ ++ if (output) ++ return gpiod_direction_output(spi_gpio->mosi, 1); ++ else ++ return gpiod_direction_input(spi_gpio->mosi); ++} ++ ++static void spi_gpio_cleanup(struct spi_device *spi) ++{ ++ spi_bitbang_cleanup(spi); ++} ++ ++/* ++ * It can be convenient to use this driver with pins that have alternate ++ * functions associated with a "native" SPI controller if a driver for that ++ * controller is not available, or is missing important functionality. ++ * ++ * On platforms which can do so, configure MISO with a weak pullup unless ++ * there's an external pullup on that signal. That saves power by avoiding ++ * floating signals. (A weak pulldown would save power too, but many ++ * drivers expect to see all-ones data as the no slave "response".) ++ */ ++static int spi_gpio_request(struct device *dev, ++ struct spi_gpio *spi_gpio, ++ unsigned int num_chipselects, ++ u16 *mflags) ++{ ++ int i; ++ ++ spi_gpio->mosi = devm_gpiod_get_optional(dev, "mosi", GPIOD_OUT_LOW); ++ if (IS_ERR(spi_gpio->mosi)) ++ return PTR_ERR(spi_gpio->mosi); ++ if (!spi_gpio->mosi) ++ /* HW configuration without MOSI pin */ ++ *mflags |= SPI_MASTER_NO_TX; ++ ++ spi_gpio->miso = devm_gpiod_get_optional(dev, "miso", GPIOD_IN); ++ if (IS_ERR(spi_gpio->miso)) ++ return PTR_ERR(spi_gpio->miso); ++ /* ++ * No setting SPI_MASTER_NO_RX here - if there is only a MOSI ++ * pin connected the host can still do RX by changing the ++ * direction of the line. ++ */ ++ ++ spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW); ++ if (IS_ERR(spi_gpio->sck)) ++ return PTR_ERR(spi_gpio->sck); ++ ++ for (i = 0; i < num_chipselects; i++) { ++ spi_gpio->cs_gpios[i] = devm_gpiod_get_index(dev, "cs", ++ i, GPIOD_OUT_HIGH); ++ if (IS_ERR(spi_gpio->cs_gpios[i])) ++ return PTR_ERR(spi_gpio->cs_gpios[i]); ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_OF ++static const struct of_device_id spi_gpio_dt_ids[] = { ++ { .compatible = "wb-spi-gpio" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids); ++ ++static int spi_gpio_probe_dt(struct platform_device *pdev) ++{ ++ int ret; ++ u32 tmp; ++ struct spi_gpio_platform_data *pdata; ++ struct device_node *np = pdev->dev.of_node; ++ const struct of_device_id *of_id = ++ of_match_device(spi_gpio_dt_ids, &pdev->dev); ++ ++ if (!of_id) ++ return 0; ++ ++ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); ++ if (!pdata) ++ return -ENOMEM; ++ ++ ret = of_property_read_u32(np, "num-chipselects", &tmp); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "num-chipselects property not found\n"); ++ goto error_free; ++ } ++ ++ pdata->num_chipselect = tmp; ++ pdev->dev.platform_data = pdata; ++ ++ return 1; ++ ++error_free: ++ devm_kfree(&pdev->dev, pdata); ++ return ret; ++} ++#else ++static inline int spi_gpio_probe_dt(struct platform_device *pdev) ++{ ++ return 0; ++} ++#endif ++ ++static int spi_gpio_probe(struct platform_device *pdev) ++{ ++ int status; ++ struct spi_master *master; ++ struct spi_gpio *spi_gpio; ++ struct spi_gpio_platform_data *pdata; ++ u16 master_flags = 0; ++ bool use_of = 0; ++ ++ status = spi_gpio_probe_dt(pdev); ++ if (status < 0) ++ return status; ++ if (status > 0) ++ use_of = 1; ++ ++ pdata = dev_get_platdata(&pdev->dev); ++#ifdef GENERIC_BITBANG ++ if (!pdata || (!use_of && !pdata->num_chipselect)) ++ return -ENODEV; ++#endif ++ ++ master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio)); ++ if (!master) ++ return -ENOMEM; ++ ++ spi_gpio = spi_master_get_devdata(master); ++ ++ spi_gpio->cs_gpios = devm_kcalloc(&pdev->dev, ++ pdata->num_chipselect, ++ sizeof(*spi_gpio->cs_gpios), ++ GFP_KERNEL); ++ if (!spi_gpio->cs_gpios) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, spi_gpio); ++ ++ /* Determine if we have chip selects connected */ ++ spi_gpio->has_cs = !!pdata->num_chipselect; ++ ++ spi_gpio->pdev = pdev; ++ if (pdata) ++ spi_gpio->pdata = *pdata; ++ ++ status = spi_gpio_request(&pdev->dev, spi_gpio, ++ pdata->num_chipselect, &master_flags); ++ if (status) ++ return status; ++ ++ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); ++ master->mode_bits = SPI_3WIRE | SPI_CPHA | SPI_CPOL | SPI_CS_HIGH; ++ master->flags = master_flags; ++ master->bus_num = pdev->id; ++ /* The master needs to think there is a chipselect even if not connected */ ++ master->num_chipselect = spi_gpio->has_cs ? pdata->num_chipselect : 1; ++ master->setup = spi_gpio_setup; ++ master->cleanup = spi_gpio_cleanup; ++ ++ if (pdev->dev.of_node) { ++ master->dev.of_node = pdev->dev.of_node; ++ } ++ ++ spi_gpio->bitbang.master = master; ++ spi_gpio->bitbang.chipselect = spi_gpio_chipselect; ++ spi_gpio->bitbang.set_line_direction = spi_gpio_set_direction; ++ ++ if ((master_flags & SPI_MASTER_NO_TX) == 0) { ++ spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0; ++ spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1; ++ spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2; ++ spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_word_mode3; ++ } else { ++ spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0; ++ spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_spec_txrx_word_mode1; ++ spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_spec_txrx_word_mode2; ++ spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_spec_txrx_word_mode3; ++ } ++ spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer; ++ ++ status = spi_bitbang_start(&spi_gpio->bitbang); ++ if (status) ++ spi_master_put(master); ++ ++ return status; ++} ++ ++static int spi_gpio_remove(struct platform_device *pdev) ++{ ++ struct spi_gpio *spi_gpio; ++ struct spi_gpio_platform_data *pdata; ++ ++ spi_gpio = platform_get_drvdata(pdev); ++ pdata = dev_get_platdata(&pdev->dev); ++ ++ /* stop() unregisters child devices too */ ++ spi_bitbang_stop(&spi_gpio->bitbang); ++ ++ spi_master_put(spi_gpio->bitbang.master); ++ ++ return 0; ++} ++ ++MODULE_ALIAS("platform:" DRIVER_NAME); ++ ++static struct platform_driver spi_gpio_driver = { ++ .driver = { ++ .name = DRIVER_NAME, ++ .of_match_table = of_match_ptr(spi_gpio_dt_ids), ++ }, ++ .probe = spi_gpio_probe, ++ .remove = spi_gpio_remove, ++}; ++module_platform_driver(spi_gpio_driver); ++ ++MODULE_DESCRIPTION("SPI master driver using generic bitbanged GPIO "); ++MODULE_AUTHOR("support"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio_device.c +new file mode 100644 +index 000000000..b073dac08 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio_device.c +@@ -0,0 +1,163 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++ ++#define DEFAULT_GPIO_SCK (67) ++#define DEFAULT_GPIO_MISO (32) ++#define DEFAULT_GPIO_MOSI (65) ++#define DEFAULT_GPIO_CS (6) ++#define DEFAULT_SPI_BUS (0) ++ ++static int sck = DEFAULT_GPIO_SCK; ++module_param(sck, int, S_IRUGO | S_IWUSR); ++ ++static int miso = DEFAULT_GPIO_MISO; ++module_param(miso, int, S_IRUGO | S_IWUSR); ++ ++static int mosi = DEFAULT_GPIO_MOSI; ++module_param(mosi, int, S_IRUGO | S_IWUSR); ++ ++static int cs = DEFAULT_GPIO_CS; ++module_param(cs, int, S_IRUGO | S_IWUSR); ++ ++static int bus = DEFAULT_SPI_BUS; ++module_param(bus, int, S_IRUGO | S_IWUSR); ++ ++static int g_wb_spi_gpio_device_debug = 0; ++static int g_wb_spi_gpio_device_error = 0; ++ ++module_param(g_wb_spi_gpio_device_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_spi_gpio_device_error, int, S_IRUGO | S_IWUSR); ++ ++static char gpiod_lookup_table_devid[64]; ++ ++static char *gpio_chip_name = NULL; ++module_param(gpio_chip_name, charp, 0644); ++MODULE_PARM_DESC(str_var, "A string variable for GPIO controller"); ++ ++#define WB_SPI_GPIO_DEVICE_VERBOSE(fmt, args...) do { \ ++ if (g_wb_spi_gpio_device_debug) { \ ++ printk(KERN_INFO "[WB_SPI_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_SPI_GPIO_DEVICE_ERROR(fmt, args...) do { \ ++ if (g_wb_spi_gpio_device_error) { \ ++ printk(KERN_ERR "[WB_SPI_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static struct gpiod_lookup_table wb_spi_gpio_table = { ++ .table = { ++ GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_SCK, ++ "sck", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_MOSI, ++ "mosi", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_MISO, ++ "miso", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_CS, ++ "cs", GPIO_ACTIVE_HIGH), ++ { }, ++ }, ++}; ++ ++static struct spi_gpio_platform_data spi_pdata = { ++ .num_chipselect = 1, ++}; ++ ++static void spi_gpio_release(struct device *dev) ++{ ++ return; ++} ++ ++static struct platform_device wb_spi_gpio_device = { ++ .name = "wb_spi_gpio", ++ .num_resources = 0, ++ .id = -1, ++ ++ .dev = { ++ .platform_data = &spi_pdata, ++ .release = spi_gpio_release, ++ } ++}; ++ ++static void wb_spi_gpio_table_devid_name_set(void) { ++ int size; ++ ++ size = sizeof(gpiod_lookup_table_devid); ++ wb_spi_gpio_device.id = bus; ++ ++ mem_clear(gpiod_lookup_table_devid, size); ++ switch (bus) { ++ case PLATFORM_DEVID_NONE: ++ snprintf(gpiod_lookup_table_devid, size, "%s", wb_spi_gpio_device.name); ++ break; ++ case PLATFORM_DEVID_AUTO: ++ snprintf(gpiod_lookup_table_devid, size, "%s.%d.auto", wb_spi_gpio_device.name, bus); ++ break; ++ default: ++ snprintf(gpiod_lookup_table_devid, size, "%s.%d", wb_spi_gpio_device.name, bus); ++ break; ++ } ++ ++ wb_spi_gpio_table.dev_id = gpiod_lookup_table_devid; ++ return ; ++} ++static int __init wb_spi_gpio_device_init(void) ++{ ++ int err; ++ struct gpiod_lookup *p; ++ ++ WB_SPI_GPIO_DEVICE_VERBOSE("enter!\n"); ++ wb_spi_gpio_table.table[0].chip_hwnum = sck; ++ wb_spi_gpio_table.table[1].chip_hwnum = mosi; ++ wb_spi_gpio_table.table[2].chip_hwnum = miso; ++ wb_spi_gpio_table.table[3].chip_hwnum = cs; ++ if (gpio_chip_name) { ++ wb_spi_gpio_table.table[0].key = gpio_chip_name; ++ wb_spi_gpio_table.table[1].key = gpio_chip_name; ++ wb_spi_gpio_table.table[2].key = gpio_chip_name; ++ wb_spi_gpio_table.table[3].key = gpio_chip_name; ++ } ++ wb_spi_gpio_table_devid_name_set(); ++ WB_SPI_GPIO_DEVICE_VERBOSE("spi gpi device table bus[%d] dev id[%s]\n", bus, wb_spi_gpio_table.dev_id); ++ for (p = &wb_spi_gpio_table.table[0]; p->key; p++) { ++ WB_SPI_GPIO_DEVICE_VERBOSE("con_id:%s gpio:%d\n", p->con_id, p->chip_hwnum); ++ } ++ ++ gpiod_add_lookup_table(&wb_spi_gpio_table); ++ err = platform_device_register(&wb_spi_gpio_device); ++ if (err < 0) { ++ printk(KERN_ERR "register spi gpio device fail(%d). \n", err); ++ gpiod_remove_lookup_table(&wb_spi_gpio_table); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void __exit wb_spi_gpio_device_exit(void) ++{ ++ WB_SPI_GPIO_DEVICE_VERBOSE("enter!\n"); ++ platform_device_unregister(&wb_spi_gpio_device); ++ gpiod_remove_lookup_table(&wb_spi_gpio_table); ++} ++ ++module_init(wb_spi_gpio_device_init); ++module_exit(wb_spi_gpio_device_exit); ++MODULE_DESCRIPTION("SPI GPIO Devices"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_nor_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_nor_device.c +new file mode 100644 +index 000000000..4196601f7 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_nor_device.c +@@ -0,0 +1,87 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* The SPI Bus number that the device is mounted on can be specified manually when this module is loaded */ ++#define DEFAULT_SPI_BUS_NUM (0) ++#define DEFAULT_SPI_CS_NUM (0) ++#define DEFAULT_SPI_HZ (100000) ++ ++int g_wb_spi_nor_dev_debug = 0; ++int g_wb_spi_nor_dev_error = 0; ++int spi_bus_num = DEFAULT_SPI_BUS_NUM; ++ ++module_param(g_wb_spi_nor_dev_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_spi_nor_dev_error, int, S_IRUGO | S_IWUSR); ++module_param(spi_bus_num, int, S_IRUGO | S_IWUSR); ++ ++#define SPI_NOR_DEV_DEBUG_VERBOSE(fmt, args...) do { \ ++ if (g_wb_spi_nor_dev_debug) { \ ++ printk(KERN_INFO "[SPI_NOR_DEV][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define SPI_NOR_DEV_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_wb_spi_nor_dev_error) { \ ++ printk(KERN_ERR "[SPI_NOR_DEV][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++struct spi_board_info spi_nor_device_info __initdata= { ++ .modalias = "mx25l6405d", ++ .bus_num = DEFAULT_SPI_BUS_NUM, ++ .chip_select = DEFAULT_SPI_CS_NUM, ++ .max_speed_hz = 10 * 1000 * 1000, ++}; ++ ++static struct spi_device *g_spi_device; ++ ++static int __init wb_spi_nor_dev_init(void) ++{ ++ struct spi_master *master; ++ ++ SPI_NOR_DEV_DEBUG_VERBOSE("Enter.\n"); ++ ++ spi_nor_device_info.bus_num = spi_bus_num; ++ master = spi_busnum_to_master(spi_nor_device_info.bus_num); /* Get the controller according to the SPI Bus number */ ++ if (!master) { ++ SPI_NOR_DEV_DEBUG_ERROR("get bus_num %u spi master failed.\n", ++ spi_nor_device_info.bus_num); ++ return -EINVAL; ++ } ++ ++ g_spi_device = spi_new_device(master, &spi_nor_device_info); ++ put_device(&master->dev); ++ if (!g_spi_device) { ++ SPI_NOR_DEV_DEBUG_ERROR("register spi new device failed.\n"); ++ return -EPERM; ++ } ++ ++ if (g_wb_spi_nor_dev_debug) { ++ dev_info(&g_spi_device->dev, "register %u bus_num spi nor device success\n", ++ spi_nor_device_info.bus_num); ++ } ++ ++ return 0; ++} ++ ++static void __exit wb_spi_nor_dev_exit(void) ++{ ++ spi_unregister_device(g_spi_device); ++ ++ if (g_wb_spi_nor_dev_debug) { ++ dev_info(&g_spi_device->dev, "unregister spi nor device success\n"); ++ } ++ ++ return; ++} ++ ++module_init(wb_spi_nor_dev_init); ++module_exit(wb_spi_nor_dev_exit); ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("create spi nor device"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.c +new file mode 100644 +index 000000000..a709427c5 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.c +@@ -0,0 +1,1025 @@ ++/* ++ * wb_spi_ocores.c ++ * ko to create ocores spi adapter ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wb_spi_ocores.h" ++ ++#define SPIOC_WAIT_SCH (5) ++#define SPIOC_CONF (0x00) ++#define SPIOC_LSBF BIT(0) /* 0:MSB 1:LSB */ ++#define SPIOC_IDLE_LOW BIT(1) ++#define SPIOC_INTREN BIT(2) /* 0:enable 1:disabel */ ++#define SPIOC_DIV_MASK (0xf0) ++#define SPIOC_MAX_DIV (0x0E) ++#define SPIOC_DIV(div) (((div) & 0x0f) << 4) ++ ++#define SPIOC_STS (0x01) ++#define SPIOC_INTR_STS BIT(0) ++#define SPIOC_BUSY_STS BIT(1) ++#define SPIOC_RXNUM_SHIFT (4) ++#define SPIOC_RXNUM_MASK (0xf << SPIOC_RXNUM_SHIFT) ++/* Just for read */ ++#define SPIOC_RXNUM(reg) (((reg) & SPIOC_RXNUM_MASK) >> SPIOC_RXNUM_SHIFT ) ++ ++#define SPIOC_TXTOT_NUM (0x02) ++#define SPIOC_TXNUM(reg) ((reg) & 0x0f) ++#define SPIOC_TOTNUM(reg) (((reg) & 0x0f) << 4) ++ ++#define SPIOC_TXCTL (0x03) ++#define SPIOC_CSLV BIT(0) /* 0:Deassert SPICS 1:Laeve SPICS */ ++#define SPIOC_TRSTART BIT(1) ++#define SPIOC_CSID_SHIFT (5) ++#define SPIOC_CSID_MASK (0x7 << SPIOC_CSID_SHIFT) ++/* Just for write */ ++#define SPIOC_CSID(id) (((id) << SPIOC_CSID_SHIFT) & SPIOC_CSID_MASK) ++ ++/* Just single byte */ ++#define SPIOC_RX(i) ((0x4) + i) ++#define SPIOC_TX(i) ((0x4) + i) ++ ++#define SPIOC_MAX_LEN ((unsigned int)8) ++#define SPIOC_TXRX_MAX_LEN ((unsigned int)7) ++ ++#define MODEBITS (SPI_CPHA |SPI_CPOL | SPI_LSB_FIRST |SPI_CS_HIGH) ++ ++#define REG_IO_WIDTH_1 (1) ++#define REG_IO_WIDTH_2 (2) ++#define REG_IO_WIDTH_4 (4) ++ ++#define SYMBOL_I2C_DEV_MODE (1) ++#define FILE_MODE (2) ++#define SYMBOL_PCIE_DEV_MODE (3) ++#define SYMBOL_IO_DEV_MODE (4) ++ ++int g_spi_oc_debug = 0; ++int g_spi_oc_error = 0; ++ ++module_param(g_spi_oc_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_spi_oc_error, int, S_IRUGO | S_IWUSR); ++ ++#define SPI_OC_VERBOSE(fmt, args...) do { \ ++ if (g_spi_oc_debug) { \ ++ printk(KERN_INFO "[OC_SPI_BUS][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define SPI_OC_ERROR(fmt, args...) do { \ ++ if (g_spi_oc_error) { \ ++ printk(KERN_ERR "[OC_SPI_BUS][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++struct spioc { ++ /* bitbang has to be first */ ++ struct spi_bitbang bitbang; ++ int irq; ++ struct completion done; ++ unsigned int reamin_len; ++ unsigned int cur_pos; ++ unsigned int cur_len; ++ const u8 *txp; ++ u8 *rxp; ++ u8 chip_select; ++ void (*setreg)(struct spioc *spioc, int reg, u32 value); ++ u32 (*getreg)(struct spioc *spioc, int reg); ++ uint32_t bus_num; ++ const char *dev_name; ++ uint32_t reg_access_mode; ++ uint32_t base_addr; ++ uint32_t reg_shift; ++ uint32_t reg_io_width; ++ uint32_t num_chipselect; ++ uint32_t freq; ++ uint32_t big_endian; ++ struct device *dev; ++ int transfer_busy_flag; ++}; ++ ++extern int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++ ++static int oc_spi_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) ++{ ++ int ret; ++ struct file *filp; ++ loff_t tmp_pos; ++ ++ filp = filp_open(path, O_RDONLY, 0); ++ if (IS_ERR(filp)) { ++ SPI_OC_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); ++ filp = NULL; ++ goto exit; ++ } ++ ++ tmp_pos = (loff_t)pos; ++ ret = kernel_read(filp, val, size, &tmp_pos); ++ if (ret < 0) { ++ SPI_OC_ERROR("kernel_read failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); ++ goto exit; ++ } ++ ++ filp_close(filp, NULL); ++ ++ return ret; ++ ++exit: ++ if (filp != NULL) { ++ filp_close(filp, NULL); ++ } ++ ++ return -1; ++} ++ ++static int oc_spi_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) ++{ ++ ++ int ret; ++ struct file *filp; ++ loff_t tmp_pos; ++ ++ filp = filp_open(path, O_RDWR, 777); ++ if (IS_ERR(filp)) { ++ SPI_OC_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); ++ filp = NULL; ++ goto exit; ++ } ++ ++ tmp_pos = (loff_t)pos; ++ ret = kernel_write(filp, val, size, &tmp_pos); ++ if (ret < 0) { ++ SPI_OC_ERROR("kernel_write failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); ++ goto exit; ++ } ++ ++ vfs_fsync(filp, 1); ++ filp_close(filp, NULL); ++ ++ return ret; ++ ++exit: ++ if (filp != NULL) { ++ filp_close(filp, NULL); ++ } ++ ++ return -1; ++} ++ ++static int oc_spi_reg_write(struct spioc *spioc, uint32_t pos, uint8_t *val, size_t size) ++{ ++ int ret; ++ ++ switch (spioc->reg_access_mode) { ++ case SYMBOL_I2C_DEV_MODE: ++ ret = i2c_device_func_write(spioc->dev_name, pos, val, size); ++ break; ++ case FILE_MODE: ++ ret = oc_spi_file_write(spioc->dev_name, pos, val, size); ++ break; ++ case SYMBOL_PCIE_DEV_MODE: ++ ret = pcie_device_func_write(spioc->dev_name, pos, val, size); ++ break; ++ case SYMBOL_IO_DEV_MODE: ++ ret = io_device_func_write(spioc->dev_name, pos, val, size); ++ break; ++ default: ++ SPI_OC_ERROR("err func_mode, write failed.\n"); ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int oc_spi_reg_read(struct spioc *spioc, uint32_t pos, uint8_t *val, size_t size) ++{ ++ int ret; ++ ++ switch (spioc->reg_access_mode) { ++ case SYMBOL_I2C_DEV_MODE: ++ ret = i2c_device_func_read(spioc->dev_name, pos, val, size); ++ break; ++ case FILE_MODE: ++ ret = oc_spi_file_read(spioc->dev_name, pos, val, size); ++ break; ++ case SYMBOL_PCIE_DEV_MODE: ++ ret = pcie_device_func_read(spioc->dev_name, pos, val, size); ++ break; ++ case SYMBOL_IO_DEV_MODE: ++ ret = io_device_func_read(spioc->dev_name, pos, val, size); ++ break; ++ default: ++ SPI_OC_ERROR("err func_mode, read failed.\n"); ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static void oc_spi_setreg_8(struct spioc *spioc, int reg, u32 value) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_1]; ++ u32 pos; ++ ++ pos = spioc->base_addr + (reg << spioc->reg_shift); ++ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ spioc->dev_name, spioc->reg_access_mode, pos, value); ++ ++ buf_tmp[0] = (value & 0Xff); ++ oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_1); ++ return; ++} ++ ++static void oc_spi_setreg_16(struct spioc *spioc, int reg, u32 value) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_2]; ++ u32 pos; ++ ++ pos = spioc->base_addr + (reg << spioc->reg_shift); ++ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ spioc->dev_name, spioc->reg_access_mode, pos, value); ++ ++ buf_tmp[0] = (value & 0Xff); ++ buf_tmp[1] = (value >> 8) & 0xff; ++ oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_2); ++ return; ++} ++ ++static void oc_spi_setreg_32(struct spioc *spioc, int reg, u32 value) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_4]; ++ u32 pos; ++ ++ pos = spioc->base_addr + (reg << spioc->reg_shift); ++ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ spioc->dev_name, spioc->reg_access_mode, pos, value); ++ ++ buf_tmp[0] = (value & 0xff); ++ buf_tmp[1] = (value >> 8) & 0xff; ++ buf_tmp[2] = (value >> 16) & 0xff; ++ buf_tmp[3] = (value >> 24) & 0xff; ++ ++ oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_4); ++ return; ++} ++ ++static void oc_spi_setreg_16be(struct spioc *spioc, int reg, u32 value) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_2]; ++ u32 pos; ++ ++ pos = spioc->base_addr + (reg << spioc->reg_shift); ++ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ spioc->dev_name, spioc->reg_access_mode, pos, value); ++ ++ buf_tmp[0] = (value >> 8) & 0xff; ++ buf_tmp[1] = (value & 0Xff); ++ oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_2); ++ return; ++} ++ ++static void oc_spi_setreg_32be(struct spioc *spioc, int reg, u32 value) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_4]; ++ u32 pos; ++ ++ pos = spioc->base_addr + (reg << spioc->reg_shift); ++ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ spioc->dev_name, spioc->reg_access_mode, pos, value); ++ ++ buf_tmp[0] = (value >> 24) & 0xff; ++ buf_tmp[1] = (value >> 16) & 0xff; ++ buf_tmp[2] = (value >> 8) & 0xff; ++ buf_tmp[3] = (value & 0xff); ++ oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_4); ++ return; ++} ++ ++static inline u32 oc_spi_getreg_8(struct spioc *spioc, int reg) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_1]; ++ u32 value, pos; ++ ++ pos = spioc->base_addr + (reg << spioc->reg_shift); ++ oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_1); ++ value = buf_tmp[0]; ++ ++ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ spioc->dev_name, spioc->reg_access_mode, pos, value); ++ ++ return value; ++} ++ ++static inline u32 oc_spi_getreg_16(struct spioc *spioc, int reg) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_2]; ++ u32 value, pos; ++ int i; ++ ++ pos = spioc->base_addr + (reg << spioc->reg_shift); ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_2); ++ ++ value = 0; ++ for (i = 0; i < REG_IO_WIDTH_2 ; i++) { ++ value |= buf_tmp[i] << (8 * i); ++ } ++ ++ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ spioc->dev_name, spioc->reg_access_mode, pos, value); ++ return value; ++} ++ ++static inline u32 oc_spi_getreg_32(struct spioc *spioc, int reg) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_4]; ++ u32 value, pos; ++ int i; ++ ++ pos = spioc->base_addr + (reg << spioc->reg_shift); ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_4); ++ ++ value = 0; ++ for (i = 0; i < REG_IO_WIDTH_4 ; i++) { ++ value |= buf_tmp[i] << (8 * i); ++ } ++ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ spioc->dev_name, spioc->reg_access_mode, pos, value); ++ return value; ++} ++ ++static inline u32 oc_spi_getreg_16be(struct spioc *spioc, int reg) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_2]; ++ u32 value, pos; ++ int i; ++ ++ pos = spioc->base_addr + (reg << spioc->reg_shift); ++ ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_2); ++ ++ value = 0; ++ for (i = 0; i < REG_IO_WIDTH_2 ; i++) { ++ value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_2 -i - 1)); ++ } ++ ++ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ spioc->dev_name, spioc->reg_access_mode, pos, value); ++ return value; ++} ++ ++static inline u32 oc_spi_getreg_32be(struct spioc *spioc, int reg) ++{ ++ u8 buf_tmp[REG_IO_WIDTH_4]; ++ u32 value, pos; ++ int i; ++ ++ pos = spioc->base_addr + (reg << spioc->reg_shift); ++ ++ mem_clear(buf_tmp, sizeof(buf_tmp)); ++ oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_4); ++ ++ value = 0; ++ for (i = 0; i < REG_IO_WIDTH_4 ; i++) { ++ value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_4 -i - 1)); ++ } ++ ++ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", ++ spioc->dev_name, spioc->reg_access_mode, pos, value); ++ return value; ++ ++} ++ ++static inline void oc_spi_setreg(struct spioc *spioc, int reg, u32 value) ++{ ++ spioc->setreg(spioc, reg, value); ++ return; ++} ++ ++static inline u32 oc_spi_getreg(struct spioc *spioc, int reg) ++{ ++ return spioc->getreg(spioc, reg); ++} ++ ++static int spioc_get_clkdiv(struct spioc *spioc, u32 speed) ++{ ++ u32 rate, div; ++ ++ rate = spioc->freq; ++ SPI_OC_VERBOSE("clk get rate:%u, speed:%u\n", rate, speed); ++ /* fs = fw/((DIV+2)*2) */ ++ ++ if (speed > (rate / 4)) { ++ div = 0; ++ SPI_OC_VERBOSE("spi device speed[%u] more than a quarter of clk rate[%u].\n", ++ speed, rate); ++ return div; ++ } ++ div = (rate/(2 * speed)) - 2; ++ if (div > SPIOC_MAX_DIV) { ++ SPI_OC_ERROR("Unsupport spi device speed, div:%u.\n", div); ++ return -1; ++ } ++ SPI_OC_VERBOSE("DIV is:0x%x\n", div); ++ return div; ++} ++ ++static inline int spioc_wait_trans(struct spioc *spioc, const unsigned long timeout) ++{ ++ unsigned long j; ++ unsigned int sch_time; ++ u8 reg; ++ ++ j = jiffies + timeout; ++ sch_time = SPIOC_WAIT_SCH; ++ while (1) { ++ reg = oc_spi_getreg(spioc, SPIOC_STS); ++ if (!(reg & SPIOC_BUSY_STS)) { ++ SPI_OC_VERBOSE("wait ok!\n"); ++ break; ++ } ++ ++ if (time_after(jiffies, j)) { ++ return -ETIMEDOUT; ++ } ++ ++ usleep_range(sch_time, sch_time + 1); ++ } ++ ++ return 0; ++} ++ ++static void spioc_chipselect(struct spi_device *spi, int is_active) ++{ ++ struct spioc *spioc; ++ u8 tx_conf; ++ int ret; ++ ++ spioc = spi_master_get_devdata(spi->master); ++ spioc->transfer_busy_flag = 0; ++ ret = spioc_wait_trans(spioc, msecs_to_jiffies(100)); ++ if (ret < 0) { ++ SPI_OC_ERROR("spi transfer is busy, ret=%d.\n", ret); ++ spioc->transfer_busy_flag = 1; ++ return; ++ } ++ spioc->chip_select = spi->chip_select; ++ SPI_OC_VERBOSE("spioc_chipselect:%u, value:%d.\n", spioc->chip_select, is_active); ++ tx_conf = 0; ++ tx_conf |= SPIOC_CSID(spioc->chip_select); ++ if (is_active) { ++ tx_conf |= SPIOC_CSLV; ++ } ++ ++ SPI_OC_VERBOSE("tx_config:[0x%x]\n", tx_conf); ++ oc_spi_setreg(spioc, SPIOC_TXCTL, tx_conf); ++ return; ++} ++ ++static void spioc_copy_tx(struct spioc *spioc) ++{ ++ const u8 *src; ++ int i; ++ ++ if (!spioc->txp) { ++ SPI_OC_ERROR("spioc->txp is NULL.\n"); ++ return; ++ } ++ ++ src = (u8 *)spioc->txp + spioc->cur_pos; ++ SPI_OC_VERBOSE("current tx len:0x%x, tx pos:[0x%x]\n", spioc->cur_len, spioc->cur_pos); ++ ++ for (i = 0; i < spioc->cur_len; i++) { ++ SPI_OC_VERBOSE("write %d, val:[0x%x]\n", i, src[i]); ++ oc_spi_setreg(spioc, SPIOC_TX(i), src[i]); ++ } ++} ++ ++static void spioc_copy_rx(struct spioc *spioc) ++{ ++ u8 *dest; ++ int i; ++ ++ if (!spioc->rxp) { ++ SPI_OC_ERROR("spioc->rxp is NULL.\n"); ++ return; ++ } ++ ++ dest = (u8 *)spioc->rxp + spioc->cur_pos; ++ SPI_OC_VERBOSE("current rx len:0x%x, rx pos:[0x%x]\n", spioc->cur_len, spioc->cur_pos); ++ ++ for (i = 0; i < spioc->cur_len; i++) { ++ dest[i] = oc_spi_getreg(spioc, SPIOC_RX(i)); ++ SPI_OC_VERBOSE("read %d, val:[0x%x]\n", i, dest[i]); ++ } ++} ++ ++static int spioc_setup_transfer(struct spi_device *spi, struct spi_transfer *transfer) ++{ ++ struct spioc *spioc; ++ u8 ctrl; ++ u32 hz; ++ int div; ++ ++ spioc = spi_master_get_devdata(spi->master); ++ ctrl = 0; ++ ++ if (spi->mode & SPI_LSB_FIRST) { ++ ctrl |= SPIOC_LSBF; ++ } ++ ++ if (!(spi->mode & SPI_CPOL)) { ++ ctrl |= SPIOC_IDLE_LOW; ++ } ++ ++ if (spioc->irq < 0) { ++ ++ ctrl |= SPIOC_INTREN; ++ } ++ ++ if (transfer != NULL) { ++ hz = transfer->speed_hz; ++ ++ if (hz == 0) { ++ hz = spi->max_speed_hz; ++ } ++ } else { ++ hz = spi->max_speed_hz; ++ } ++ ++ if (hz == 0) { ++ SPI_OC_ERROR("Unsupport zero speed.\n"); ++ return -EINVAL; ++ } ++ ++ div = spioc_get_clkdiv(spioc, hz); ++ if (div < 0) { ++ SPI_OC_ERROR("get div error, div:%d.\n", div); ++ return -EINVAL; ++ } ++ ctrl |= SPIOC_DIV(div); ++ ++ SPI_OC_VERBOSE("ctrl:[0x%x].\n", ctrl); ++ ++ oc_spi_setreg(spioc, SPIOC_CONF, ctrl); ++ return 0; ++} ++ ++static int spioc_spi_setup(struct spi_device *spi) ++{ ++ struct spioc *spioc; ++ ++ if (!(spi->mode & SPI_CPHA)) { ++ SPI_OC_ERROR("Unsupport spi device mde:0x%x, SPI_CPHA must be 1.\n", spi->mode); ++ return -EINVAL; ++ } ++ ++ spioc = spi_master_get_devdata(spi->master); ++ if (spi->chip_select >= spioc->num_chipselect) { ++ SPI_OC_ERROR("Spi device chipselect:%u, more than max chipselect:%u.\n", ++ spi->chip_select, spioc->num_chipselect); ++ return -EINVAL; ++ } ++ SPI_OC_VERBOSE("Support spi device mode:0x%x, chip_select:%u.\n", ++ spi->mode, spi->chip_select); ++ return 0; ++} ++ ++static int spioc_transfer_start(struct spioc *spioc) ++{ ++ u8 tx_conf; ++ int ret; ++ ++ tx_conf = oc_spi_getreg(spioc, SPIOC_TXCTL); ++ tx_conf |= SPIOC_TRSTART; ++ ++ SPI_OC_VERBOSE("tx_config:[0x%x]\n", tx_conf); ++ oc_spi_setreg(spioc, SPIOC_TXCTL, tx_conf); ++ ++ ret = spioc_wait_trans(spioc, msecs_to_jiffies(100)); ++ return ret; ++} ++ ++static int spioc_tx_start_one(struct spioc *spioc) ++{ ++ unsigned int txlen; ++ u8 txreg; ++ int ret; ++ ++ if (!spioc->reamin_len) { ++ SPI_OC_VERBOSE("spioc txlen:[0x0]\n"); ++ return 0; ++ } ++ ++ spioc->cur_len = spioc->reamin_len > SPIOC_MAX_LEN ? SPIOC_MAX_LEN : spioc->reamin_len; ++ ++ txlen = spioc->cur_len; ++ spioc->reamin_len -= txlen; ++ SPI_OC_VERBOSE("txlen:[0x%x], tx len remain:[0x%x]\n", txlen, spioc->reamin_len); ++ ++ spioc_copy_tx(spioc); ++ ++ /* when we only send, txlen == totlen */ ++ txreg = SPIOC_TXNUM(txlen) | SPIOC_TOTNUM(txlen); ++ SPI_OC_VERBOSE("txreg:[0x%x]\n", txreg); ++ oc_spi_setreg(spioc, SPIOC_TXTOT_NUM, txreg); ++ ++ ret = spioc_transfer_start(spioc); ++ if (ret) { ++ SPI_OC_ERROR("spioc tx rx poll wait for transfer timeout.\n"); ++ return ret; ++ } ++ ++ if (spioc->reamin_len) { ++ spioc->cur_pos += txlen; ++ SPI_OC_VERBOSE("cur_txpos:[0x%x]\n", spioc->cur_pos); ++ } ++ ++ return 0; ++} ++ ++static int spioc_rx_start_one(struct spioc *spioc) ++{ ++ unsigned int rxlen; ++ u8 txtnum; ++ int ret; ++ ++ if (!spioc->reamin_len) { ++ SPI_OC_VERBOSE("spioc reamin_len:[0x0]\n"); ++ return 0; ++ } ++ ++ spioc->cur_len = spioc->reamin_len > SPIOC_MAX_LEN ? SPIOC_MAX_LEN : spioc->reamin_len; ++ ++ rxlen = spioc->cur_len; ++ spioc->reamin_len -= rxlen; ++ SPI_OC_VERBOSE("rxlen:[0x%x], rx len remain:[0x%x]\n", rxlen, spioc->reamin_len); ++ ++ /* when we only receive, rxnum=totnum. txnum=0 */ ++ txtnum = SPIOC_TOTNUM(rxlen); ++ SPI_OC_VERBOSE("tx total reg:0x%x\n", txtnum); ++ oc_spi_setreg(spioc, SPIOC_TXTOT_NUM, txtnum); ++ ++ ret = spioc_transfer_start(spioc); ++ if (ret) { ++ SPI_OC_ERROR("spioc tx rx poll wait for transfer timeout.\n"); ++ return ret; ++ } ++ ++ spioc_copy_rx(spioc); ++ ++ if (spioc->reamin_len) { ++ spioc->cur_pos += rxlen; ++ SPI_OC_VERBOSE("cur_rxpos:[0x%x]\n", spioc->cur_pos); ++ } ++ ++ return 0; ++} ++ ++static int spioc_tx_rx_start_one(struct spioc *spioc) ++{ ++ unsigned int txlen, total_len; ++ u8 txreg; ++ int ret; ++ ++ if (!spioc->reamin_len) { ++ SPI_OC_VERBOSE("spioc reamin_len:[0x0]\n"); ++ return 0; ++ } ++ ++ spioc->cur_len = spioc->reamin_len > SPIOC_TXRX_MAX_LEN ? SPIOC_TXRX_MAX_LEN : spioc->reamin_len; ++ ++ txlen = spioc->cur_len; ++ spioc->reamin_len -= txlen; ++ SPI_OC_VERBOSE("tx len:[0x%x], tx len remain:[0x%x]\n", txlen, spioc->reamin_len); ++ ++ spioc_copy_tx(spioc); ++ ++ total_len = 2 * txlen; /* total_len=txlen + rxlen; rxlen=txlen */ ++ txreg = SPIOC_TXNUM(txlen) | SPIOC_TOTNUM(total_len); ++ SPI_OC_VERBOSE("txreg:[0x%x]\n", txreg); ++ oc_spi_setreg(spioc, SPIOC_TXTOT_NUM, txreg); ++ ++ ret = spioc_transfer_start(spioc); ++ if (ret) { ++ SPI_OC_ERROR("spioc tx rx poll wait for transfer timeout.\n"); ++ return ret; ++ } ++ ++ spioc_copy_rx(spioc); ++ if (spioc->reamin_len) { ++ spioc->cur_pos += txlen; ++ SPI_OC_VERBOSE("cur_txrx pos:[0x%x]\n", spioc->cur_pos); ++ } ++ return 0; ++} ++ ++static int spioc_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) ++{ ++ struct spioc *spioc; ++ int ret , len; ++ ++ if(!t->len || (!t->tx_buf && !t->rx_buf)) { ++ SPI_OC_ERROR("params error, tx_buf and rx_buf may both NULL, transfer len:0x%x.\n", ++ t->len); ++ return 0; ++ } ++ ++ spioc = spi_master_get_devdata(spi->master); ++ if (spioc->transfer_busy_flag) { ++ ret = -EBUSY; ++ goto err; ++ } ++ ++ spioc->txp = t->tx_buf; ++ spioc->rxp = t->rx_buf; ++ spioc->reamin_len = t->len; ++ spioc->cur_len = 0; ++ spioc->cur_pos = 0; ++ len = t->len; ++ ret = 0; ++ if (spioc->irq >= 0) { ++ /* use interrupt driven data transfer */ ++ if (t->tx_buf && t->rx_buf) { ++ spioc_tx_rx_start_one(spioc); ++ wait_for_completion(&spioc->done); ++ } else if (t->tx_buf) { ++ spioc_tx_start_one(spioc); ++ wait_for_completion(&spioc->done); ++ ++ } else { ++ spioc_rx_start_one(spioc); ++ wait_for_completion(&spioc->done); ++ } ++ } else { ++ if (t->tx_buf && t->rx_buf) { ++ SPI_OC_VERBOSE("start tx rx, len:0x%x\n", t->len); ++ while (spioc->reamin_len) { ++ ret = spioc_tx_rx_start_one(spioc); ++ if (ret) { ++ goto err; ++ } ++ } ++ } else if (t->tx_buf) { ++ SPI_OC_VERBOSE("start tx, txlen:0x%x\n", t->len); ++ while (spioc->reamin_len) { ++ ret = spioc_tx_start_one(spioc); ++ if (ret) { ++ goto err; ++ } ++ } ++ } else { ++ SPI_OC_VERBOSE("start rx, rxlen:0x%x\n", t->len); ++ while (spioc->reamin_len) { ++ ret = spioc_rx_start_one(spioc); ++ if (ret) { ++ goto err; ++ } ++ } ++ } ++ } ++ SPI_OC_VERBOSE("return num: 0x%x\n", len); ++ return len; ++err: ++ return ret; ++} ++ ++static irqreturn_t spioc_spi_irq(int irq, void *dev) ++{ ++ struct spioc *spioc; ++ ++ spioc = dev; ++ /* gooooohi, interrupt status bit judgment is not done */ ++ ++ if (spioc->txp && spioc->rxp) { ++ if (!spioc->reamin_len) { ++ complete(&spioc->done); ++ } else { ++ spioc_tx_rx_start_one(spioc); ++ } ++ } else if (spioc->txp) { ++ if (!spioc->reamin_len) { ++ complete(&spioc->done); ++ } else { ++ spioc_tx_start_one(spioc); ++ } ++ } else if (spioc->rxp){ ++ if (!spioc->reamin_len) { ++ complete(&spioc->done); ++ } else { ++ spioc_rx_start_one(spioc); ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int ocores_spi_config_init(struct spioc *spioc) ++{ ++ int ret = 0; ++ struct device *dev; ++ spi_ocores_device_t *spi_ocores_device; ++ ++ dev = spioc->dev; ++ if (dev->of_node) { ++ ret += of_property_read_string(dev->of_node, "dev_name", &spioc->dev_name); ++ ret += of_property_read_u32(dev->of_node, "dev_base", &spioc->base_addr); ++ ret += of_property_read_u32(dev->of_node, "reg_shift", &spioc->reg_shift); ++ ret += of_property_read_u32(dev->of_node, "reg_io_width", &spioc->reg_io_width); ++ ret += of_property_read_u32(dev->of_node, "clock-frequency", &spioc->freq); ++ ret += of_property_read_u32(dev->of_node, "reg_access_mode", &spioc->reg_access_mode); ++ ret += of_property_read_u32(dev->of_node, "num_chipselect", &spioc->num_chipselect); ++ ++ if (ret != 0) { ++ SPI_OC_ERROR("dts config error, ret:%d.\n", ret); ++ ret = -ENXIO; ++ return ret; ++ } ++ } else { ++ if (spioc->dev->platform_data == NULL) { ++ SPI_OC_ERROR("platform data config error.\n"); ++ ret = -ENXIO; ++ return ret; ++ } ++ spi_ocores_device = spioc->dev->platform_data; ++ spioc->bus_num = spi_ocores_device->bus_num; ++ spioc->dev_name = spi_ocores_device->dev_name; ++ spioc->big_endian = spi_ocores_device->big_endian; ++ spioc->base_addr = spi_ocores_device->dev_base; ++ spioc->reg_shift = spi_ocores_device->reg_shift; ++ spioc->reg_io_width = spi_ocores_device->reg_io_width; ++ spioc->freq = spi_ocores_device->clock_frequency; ++ spioc->reg_access_mode = spi_ocores_device->reg_access_mode; ++ spioc->num_chipselect = spi_ocores_device->num_chipselect; ++ } ++ ++ SPI_OC_VERBOSE("name:%s, base:0x%x, reg_shift:0x%x, io_width:0x%x, clock-frequency:0x%x.\n", ++ spioc->dev_name, spioc->base_addr, spioc->reg_shift, spioc->reg_io_width, spioc->freq); ++ SPI_OC_VERBOSE("reg access mode:%u, num_chipselect:%u.\n", ++ spioc->reg_access_mode, spioc->num_chipselect); ++ return ret; ++} ++ ++static int spioc_probe(struct platform_device *pdev) ++{ ++ struct spi_master *master; ++ struct spioc *spioc; ++ int ret; ++ bool be; ++ ++ ret = -1; ++ master = spi_alloc_master(&pdev->dev, sizeof(struct spioc)); ++ if (!master) { ++ dev_err(&pdev->dev, "Failed to alloc spi master.\n"); ++ goto out; ++ } ++ ++ spioc = spi_master_get_devdata(master); ++ platform_set_drvdata(pdev, spioc); ++ ++ spioc->dev = &pdev->dev; ++ ret = ocores_spi_config_init(spioc); ++ if (ret != 0) { ++ dev_err(spioc->dev, "Failed to get ocores spi dts config.\n"); ++ goto free; ++ } ++ ++ if (spioc->dev->of_node) { ++ if (of_property_read_u32(spioc->dev->of_node, "big_endian", &spioc->big_endian)) { ++ ++ be = 0; ++ } else { ++ be = spioc->big_endian; ++ } ++ } else { ++ be = spioc->big_endian; ++ } ++ ++ if (spioc->reg_io_width == 0) { ++ spioc->reg_io_width = 1; /* Set to default value */ ++ } ++ ++ if (!spioc->setreg || !spioc->getreg) { ++ switch (spioc->reg_io_width) { ++ case REG_IO_WIDTH_1: ++ spioc->setreg = oc_spi_setreg_8; ++ spioc->getreg = oc_spi_getreg_8; ++ break; ++ ++ case REG_IO_WIDTH_2: ++ spioc->setreg = be ? oc_spi_setreg_16be : oc_spi_setreg_16; ++ spioc->getreg = be ? oc_spi_getreg_16be : oc_spi_getreg_16; ++ break; ++ ++ case REG_IO_WIDTH_4: ++ spioc->setreg = be ? oc_spi_setreg_32be : oc_spi_setreg_32; ++ spioc->getreg = be ? oc_spi_getreg_32be : oc_spi_getreg_32; ++ break; ++ ++ default: ++ dev_err(spioc->dev, "Unsupported I/O width (%d)\n", spioc->reg_io_width); ++ ret = -EINVAL; ++ goto free; ++ } ++ } ++ ++ /* master state */ ++ master->num_chipselect = spioc->num_chipselect; ++ master->mode_bits = MODEBITS; ++ master->setup = spioc_spi_setup; ++ if (spioc->dev->of_node) { ++ master->dev.of_node = pdev->dev.of_node; ++ } else { ++ master->bus_num = spioc->bus_num; ++ } ++ ++ /* setup the state for the bitbang driver */ ++ spioc->bitbang.master = master; ++ spioc->bitbang.setup_transfer = spioc_setup_transfer; ++ spioc->bitbang.chipselect = spioc_chipselect; ++ spioc->bitbang.txrx_bufs = spioc_spi_txrx_bufs; ++ ++ /* gooooohi need revision */ ++ spioc->irq = platform_get_irq(pdev, 0); ++ if (spioc->irq >= 0) { ++ SPI_OC_VERBOSE("spi oc use irq, irq number:%d.\n", spioc->irq); ++ init_completion(&spioc->done); ++ ret = devm_request_irq(&pdev->dev, spioc->irq, spioc_spi_irq, 0, ++ pdev->name, spioc); ++ if (ret) { ++ dev_err(spioc->dev, "Failed to request irq:%d.\n", spioc->irq); ++ goto free; ++ } ++ } ++ ++ ret = spi_bitbang_start(&spioc->bitbang); ++ if (ret) { ++ dev_err(spioc->dev, "Failed to start spi bitbang, ret:%d.\n", ret); ++ goto free; ++ } ++ dev_info(spioc->dev, "registered spi-%d for %s with base address:0x%x success.\n", ++ master->bus_num, spioc->dev_name, spioc->base_addr); ++ ++ return ret; ++free: ++ spi_master_put(master); ++out: ++ return ret; ++} ++ ++static int spioc_remove(struct platform_device *pdev) ++{ ++ struct spioc *spioc; ++ struct spi_master *master; ++ ++ spioc = platform_get_drvdata(pdev); ++ master = spioc->bitbang.master; ++ spi_bitbang_stop(&spioc->bitbang); ++ platform_set_drvdata(pdev, NULL); ++ spi_master_put(master); ++ ++ return 0; ++} ++ ++static const struct of_device_id spioc_match[] = { ++ { .compatible = "wb-spi-oc", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, spioc_match); ++ ++static struct platform_driver spioc_driver = { ++ .probe = spioc_probe, ++ .remove = spioc_remove, ++ .driver = { ++ .name = "wb-spioc", ++ .owner = THIS_MODULE, ++ .of_match_table = spioc_match, ++ }, ++}; ++ ++module_platform_driver(spioc_driver); ++ ++MODULE_DESCRIPTION("spi open core adapter driver"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.h +new file mode 100644 +index 000000000..647ff0c5f +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.h +@@ -0,0 +1,21 @@ ++#ifndef __WB_SPI_OCORES_H__ ++#define __WB_SPI_OCORES_H__ ++#include ++ ++#define mem_clear(data, size) memset((data), 0, (size)) ++#define SPI_OCORES_DEV_NAME_MAX_LEN (64) ++ ++typedef struct spi_ocores_device_s { ++ uint32_t bus_num; ++ uint32_t big_endian; ++ char dev_name[SPI_OCORES_DEV_NAME_MAX_LEN]; ++ uint32_t reg_access_mode; ++ uint32_t dev_base; ++ uint32_t reg_shift; ++ uint32_t reg_io_width; ++ uint32_t clock_frequency; ++ uint32_t num_chipselect; ++ int device_flag; ++} spi_ocores_device_t; ++ ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_uio_irq.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_uio_irq.c +new file mode 100644 +index 000000000..da2b58244 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_uio_irq.c +@@ -0,0 +1,282 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++typedef struct dfd_irq_s { ++ int gpio; ++ int irq_type; ++ struct uio_info dfd_irq_info; ++ spinlock_t lock; ++ struct attribute_group attr_group; ++} dfd_irq_t; ++ ++#define DRV_NAME "uio-irq" ++#define DRV_VERSION "1.0" ++#define ENABLE_VAL (1) ++#define DISABLE_VAL (0) ++ ++#define DEBUG_ERR_LEVEL (0x1) ++#define DEBUG_WARN_LEVEL (0x2) ++#define DEBUG_INFO_LEVEL (0x4) ++#define DEBUG_VER_LEVEL (0x8) ++ ++static int debug = 0; ++module_param(debug, int, S_IRUGO | S_IWUSR); ++#define DEBUG_ERROR(fmt, args...) \ ++ do { \ ++ if (debug & DEBUG_ERR_LEVEL) { \ ++ printk(KERN_ERR "[ERR][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ ++ } else { \ ++ pr_debug(fmt, ## args); \ ++ } \ ++ } while(0) ++ ++#define DEBUG_WARN(fmt, args...) \ ++ do { \ ++ if (debug & DEBUG_WARN_LEVEL) { \ ++ printk(KERN_WARNING "[WARN][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ ++ } else { \ ++ pr_debug(fmt, ## args); \ ++ } \ ++ } while(0) ++ ++#define DEBUG_INFO(fmt, args...) \ ++ do { \ ++ if (debug & DEBUG_INFO_LEVEL) { \ ++ printk(KERN_INFO "[INFO][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ ++ } else { \ ++ pr_debug(fmt, ## args); \ ++ } \ ++ } while(0) ++ ++#define DEBUG_VERBOSE(fmt, args...) \ ++ do { \ ++ if (debug & DEBUG_VER_LEVEL) { \ ++ printk(KERN_DEBUG "[VER][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ ++ } else { \ ++ pr_debug(fmt, ## args); \ ++ } \ ++ } while(0) ++ ++static irqreturn_t dfd_genirq_handler(int irq, struct uio_info *dev_info) ++{ ++ disable_irq_nosync(irq); ++ DEBUG_VERBOSE("handler disable irq"); ++ return IRQ_HANDLED; ++} ++ ++static int dfd_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on) ++{ ++ struct irq_data *irqdata; ++ ++ irqdata = irq_get_irq_data(dev_info->irq); ++ ++ if (irqd_irq_disabled(irqdata) == !irq_on) { ++ DEBUG_VERBOSE("irq already disable"); ++ return 0; ++ } ++ if (irq_on) { ++ DEBUG_VERBOSE("irqcontrol enable irq"); ++ enable_irq(dev_info->irq); ++ } else { ++ DEBUG_VERBOSE("irqcontrol disable irq"); ++ disable_irq(dev_info->irq); ++ } ++ ++ return 0; ++} ++ ++static ssize_t set_irq_enable(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ dfd_irq_t *dfd_irq; ++ struct uio_info *dev_info; ++ unsigned long flags; ++ int ret, val; ++ ++ dfd_irq = dev_get_drvdata(dev); ++ dev_info = &dfd_irq->dfd_irq_info; ++ ++ spin_lock_irqsave(&dfd_irq->lock, flags); ++ ++ sscanf(buf, "%d", &val); ++ DEBUG_VERBOSE("set val:%d.\n", val); ++ ++ if ((val != ENABLE_VAL) && (val != DISABLE_VAL)) { ++ DEBUG_ERROR("unsupport val:%d ", val); ++ ret = -EINVAL; ++ goto fail; ++ } ++ ++ if (val) { ++ DEBUG_VERBOSE("sysfs enable irq"); ++ enable_irq(dev_info->irq); ++ } else { ++ DEBUG_VERBOSE("sysfs disable irq"); ++ disable_irq(dev_info->irq); ++ } ++ ++ spin_unlock_irqrestore(&dfd_irq->lock, flags); ++ return count; ++ ++fail: ++ spin_unlock_irqrestore(&dfd_irq->lock, flags); ++ return ret; ++} ++ ++static DEVICE_ATTR(irq_enable, S_IWUSR, NULL, set_irq_enable); ++ ++static struct attribute *irq_attrs[] = { ++ &dev_attr_irq_enable.attr, ++ NULL, ++}; ++ ++static struct attribute_group irq_attr_group = { ++ .attrs = irq_attrs, ++}; ++ ++static int dfd_irq_probe(struct platform_device *pdev) ++{ ++ u32 gpio, irq_type, pirq_line; ++ int ret, ret1, ret2; ++ struct uio_info *dfd_irq_info; ++ dfd_irq_t *dfd_irq; ++ ++ dfd_irq = kzalloc(sizeof(dfd_irq_t), GFP_KERNEL); ++ if (!dfd_irq) { ++ dev_err(&pdev->dev, "dfd_irq_t kzalloc failed.\n"); ++ return -ENOMEM; ++ } ++ ++ dfd_irq_info = &dfd_irq->dfd_irq_info; ++ dfd_irq_info->version = "1.0"; ++ dfd_irq_info->name = "uio-irq"; ++ ++ /* get pirq line for x86 */ ++ ret1 = of_property_read_u32(pdev->dev.of_node, "pirq-line", &pirq_line); ++ if (!ret1) { ++ DEBUG_VERBOSE("use pirq-line method, pirq-line:%u", pirq_line); ++ dfd_irq_info->irq = pirq_line; ++ } ++ ++ ret2 = of_property_read_u32(pdev->dev.of_node, "gpio", &gpio); ++ if (!ret2 && ret1) { ++ dfd_irq->gpio = gpio; ++ gpio_request(dfd_irq->gpio, "GPIOA"); ++ dfd_irq_info->irq = gpio_to_irq(dfd_irq->gpio); ++ DEBUG_VERBOSE("use gpio:%u, irq num:%ld", gpio, dfd_irq_info->irq); ++ } else if (ret2 && ret1){ ++ ret = -ENXIO; ++ dev_err(&pdev->dev, "no define irq num. ret2:%d, ret1:%d.\n", ret2, ret1); ++ goto free_mem; ++ } ++ ++ ret = of_property_read_u32(pdev->dev.of_node, "irq_type", &irq_type); ++ if (!ret && ret1) { ++ DEBUG_VERBOSE("use irq_type:%u", irq_type); ++ dfd_irq->irq_type = irq_type; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) ++ irq_set_irq_type(dfd_irq_info->irq, dfd_irq->irq_type); ++#else ++ set_irq_type(dfd_irq_info->irq, dfd_irq->irq_type); ++#endif ++ } else if (ret && ret1){ ++ ret = -ENXIO; ++ dev_err(&pdev->dev, "no define irq type. ret:%d, ret1:%d.\n", ret, ret1); ++ goto free_mem; ++ } ++ ++ dfd_irq_info->irq_flags = IRQF_SHARED; ++ dfd_irq_info->handler = dfd_genirq_handler; ++ dfd_irq_info->irqcontrol = dfd_genirq_irqcontrol; ++ ++ if(uio_register_device(&pdev->dev, dfd_irq_info)){ ++ ret = -ENODEV; ++ dev_err(&pdev->dev, "uio register failed.\n"); ++ goto free_mem; ++ } ++ ++ spin_lock_init(&dfd_irq->lock); ++ ++ dfd_irq->attr_group = irq_attr_group; ++ ret = sysfs_create_group(&pdev->dev.kobj, &dfd_irq->attr_group); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "sysfs_create_group failed. ret:%d.\n", ret); ++ goto free_mem; ++ } ++ DEBUG_VERBOSE("sysfs create group success\n"); ++ ++ platform_set_drvdata(pdev, dfd_irq); ++ ++ return 0; ++ ++free_mem: ++ kfree(dfd_irq); ++ ++ return ret; ++} ++ ++static int dfd_irq_remove(struct platform_device *pdev) ++{ ++ dfd_irq_t *dfd_irq; ++ struct uio_info *dfd_irq_info; ++ ++ dfd_irq = platform_get_drvdata(pdev); ++ dfd_irq_info = &dfd_irq->dfd_irq_info; ++ ++ uio_unregister_device(dfd_irq_info); ++ kfree(dfd_irq); ++ ++ sysfs_remove_group(&pdev->dev.kobj, &dfd_irq->attr_group); ++ ++ return 0; ++} ++ ++static struct of_device_id dfd_irq_match[] = { ++ { ++ .compatible = "uio-irq", ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, dfd_irq_match); ++ ++static struct platform_driver dfd_irq_driver = { ++ .probe = dfd_irq_probe, ++ .remove = dfd_irq_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = DRV_NAME, ++ .of_match_table = dfd_irq_match, ++ }, ++}; ++ ++static int __init dfd_irq_init(void) ++{ ++ int ret; ++ ++ ret = platform_driver_register(&dfd_irq_driver); ++ if (ret != 0 ) { ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void __exit dfd_irq_exit(void) ++{ ++ platform_driver_unregister(&dfd_irq_driver); ++} ++ ++module_init(dfd_irq_init); ++module_exit(dfd_irq_exit); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.c +new file mode 100644 +index 000000000..c97288944 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.c +@@ -0,0 +1,1187 @@ ++/* ++ * wb_wdt.c ++ * ko for watchdog function ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wb_wdt.h" ++ ++#define GPIO_FEED_WDT_MODE (1) ++#define LOGIC_FEED_WDT_MODE (2) ++ ++#define SYMBOL_I2C_DEV_MODE (1) ++#define SYMBOL_PCIE_DEV_MODE (2) ++#define SYMBOL_IO_DEV_MODE (3) ++#define FILE_MODE (4) ++ ++#define ONE_BYTE (1) ++ ++#define WDT_OFF (0) ++#define WDT_ON (1) ++ ++#define MS_TO_S (1000) ++#define MS_TO_NS (1000 * 1000) ++ ++#define MAX_REG_VAL (255) ++ ++extern int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++extern int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); ++ ++int g_wb_wdt_debug = 0; ++int g_wb_wdt_error = 0; ++ ++module_param(g_wb_wdt_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_wdt_error, int, S_IRUGO | S_IWUSR); ++ ++#define WDT_VERBOSE(fmt, args...) do { \ ++ if (g_wb_wdt_debug) { \ ++ printk(KERN_INFO "[WDT][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WDT_ERROR(fmt, args...) do { \ ++ if (g_wb_wdt_error) { \ ++ printk(KERN_ERR "[WDT][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++enum { ++ HW_ALGO_TOGGLE, ++ HW_ALGO_LEVEL, ++ HW_ALGO_EIGENVALUES, ++}; ++ ++enum { ++ WATCHDOG_DEVICE_TYPE = 0, ++ HRTIMER_TYPE, ++ THREAD_TYPE, ++}; ++ ++typedef struct wb_wdt_priv_s { ++ struct task_struct *thread; ++ struct hrtimer hrtimer; ++ ktime_t m_kt; ++ const char *config_dev_name; ++ uint8_t config_mode; ++ uint8_t hw_algo; ++ uint8_t enable_val; ++ uint8_t disable_val; ++ uint8_t enable_mask; ++ uint8_t priv_func_mode; ++ uint8_t feed_wdt_type; ++ uint32_t enable_reg; ++ uint32_t timeout_cfg_reg; ++ uint32_t timeleft_cfg_reg; ++ uint32_t hw_margin; ++ uint32_t feed_time; ++ uint8_t timer_accuracy_reg_flag; ++ uint32_t timer_accuracy_reg; ++ uint8_t timer_accuracy_reg_val; ++ uint32_t timer_accuracy; ++ uint8_t timer_update_reg_flag; ++ uint32_t timer_update_reg; ++ uint8_t timer_update_reg_val; ++ gpio_wdt_info_t gpio_wdt; ++ logic_wdt_info_t logic_wdt; ++ struct device *dev; ++ const struct attribute_group *sysfs_group; ++ uint8_t sysfs_index; ++ struct mutex update_lock; ++ struct watchdog_device wdd; ++}wb_wdt_priv_t; ++ ++static int wdt_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) ++{ ++ int ret; ++ struct file *filp; ++ loff_t tmp_pos; ++ ++ filp = filp_open(path, O_RDONLY, 0); ++ if (IS_ERR(filp)) { ++ WDT_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); ++ filp = NULL; ++ goto exit; ++ } ++ ++ tmp_pos = (loff_t)pos; ++ ret = kernel_read(filp, val, size, &tmp_pos); ++ if (ret < 0) { ++ WDT_ERROR("kernel_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); ++ goto exit; ++ } ++ ++ filp_close(filp, NULL); ++ ++ return ret; ++ ++exit: ++ if (filp != NULL) { ++ filp_close(filp, NULL); ++ } ++ ++ return -1; ++} ++ ++static int wdt_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) ++{ ++ int ret; ++ struct file *filp; ++ loff_t tmp_pos; ++ ++ filp = filp_open(path, O_RDWR, 777); ++ if (IS_ERR(filp)) { ++ WDT_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); ++ filp = NULL; ++ goto exit; ++ } ++ ++ tmp_pos = (loff_t)pos; ++ ret = kernel_write(filp, val, size, &tmp_pos); ++ if (ret < 0) { ++ WDT_ERROR("kernel_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); ++ goto exit; ++ } ++ ++ vfs_fsync(filp, 1); ++ filp_close(filp, NULL); ++ ++ return ret; ++ ++exit: ++ if (filp != NULL) { ++ filp_close(filp, NULL); ++ } ++ ++ return -1; ++} ++ ++static int wb_wdt_read(uint8_t mode, const char *path, ++ uint32_t offset, uint8_t *buf, size_t count) ++{ ++ int ret; ++ ++ switch (mode) { ++ case SYMBOL_I2C_DEV_MODE: ++ ret = i2c_device_func_read(path, offset, buf, count); ++ break; ++ case SYMBOL_PCIE_DEV_MODE: ++ ret = pcie_device_func_read(path, offset, buf, count); ++ break; ++ case SYMBOL_IO_DEV_MODE: ++ ret = io_device_func_read(path, offset, buf, count); ++ break; ++ case FILE_MODE: ++ ret = wdt_file_read(path, offset, buf, count); ++ break; ++ default: ++ WDT_ERROR("mode %u error, wdt func read failed.\n", mode); ++ return -EINVAL; ++ } ++ ++ WDT_VERBOSE("wdt func read mode:%u,dev_nam:%s, offset:0x%x, read_val:0x%x, size:%lu.\n", ++ mode, path, offset, *buf, count); ++ ++ return ret; ++} ++ ++static int wb_wdt_write(uint8_t mode, const char *path, ++ uint32_t offset, uint8_t *buf, size_t count) ++{ ++ int ret; ++ ++ switch (mode) { ++ case SYMBOL_I2C_DEV_MODE: ++ ret = i2c_device_func_write(path, offset, buf, count); ++ break; ++ case SYMBOL_PCIE_DEV_MODE: ++ ret = pcie_device_func_write(path, offset, buf, count); ++ break; ++ case SYMBOL_IO_DEV_MODE: ++ ret = io_device_func_write(path, offset, buf, count); ++ break; ++ case FILE_MODE: ++ ret = wdt_file_write(path, offset, buf, count); ++ break; ++ default: ++ WDT_ERROR("mode %u error, wdt func write failed.\n", mode); ++ return -EINVAL; ++ } ++ ++ WDT_VERBOSE("wdt func write mode:%u, dev_nam:%s, offset:0x%x, write_val:0x%x, size:%lu.\n", ++ mode, path, offset, *buf, count); ++ ++ return ret; ++} ++ ++static int wb_wdt_enable_ctrl(wb_wdt_priv_t *priv, uint8_t flag) ++{ ++ int ret; ++ uint8_t val; ++ uint8_t ctrl_val; ++ ++ switch (flag) { ++ case WDT_ON: ++ ctrl_val = priv->enable_val; ++ break; ++ case WDT_OFF: ++ ctrl_val = priv->disable_val; ++ break; ++ default: ++ WDT_ERROR("unsupport wdt enable ctrl:%u.\n", flag); ++ return -EINVAL; ++ } ++ ++ ret = wb_wdt_read(priv->priv_func_mode, priv->config_dev_name, ++ priv->enable_reg, &val, ONE_BYTE); ++ if (ret < 0) { ++ dev_err(priv->dev, "read wdt control reg error.\n"); ++ return ret; ++ } ++ ++ val &= ~priv->enable_mask; ++ ++ val |= ctrl_val & priv->enable_mask; ++ ++ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, ++ priv->enable_reg, &val, ONE_BYTE); ++ if (ret < 0) { ++ dev_err(priv->dev, "write wdt control reg error.\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void wdt_hwping(wb_wdt_priv_t *priv) ++{ ++ gpio_wdt_info_t *gpio_wdt; ++ logic_wdt_info_t *logic_wdt; ++ uint8_t tmp_val; ++ int ret; ++ ++ if (priv->config_mode == GPIO_FEED_WDT_MODE) { ++ gpio_wdt = &priv->gpio_wdt; ++ switch (priv->hw_algo) { ++ case HW_ALGO_TOGGLE: ++ gpio_wdt = &priv->gpio_wdt; ++ gpio_wdt->state = !gpio_wdt->state; ++ gpio_set_value_cansleep(gpio_wdt->gpio, gpio_wdt->state); ++ WDT_VERBOSE("gpio toggle wdt work. val:%u\n", gpio_wdt->state); ++ break; ++ case HW_ALGO_LEVEL: ++ gpio_wdt = &priv->gpio_wdt; ++ /* Pulse */ ++ gpio_set_value_cansleep(gpio_wdt->gpio, !gpio_wdt->active_low); ++ udelay(1); ++ gpio_set_value_cansleep(gpio_wdt->gpio, gpio_wdt->active_low); ++ WDT_VERBOSE("gpio level wdt work.\n"); ++ break; ++ } ++ } else { ++ logic_wdt = &priv->logic_wdt; ++ switch (priv->hw_algo) { ++ case HW_ALGO_TOGGLE: ++ logic_wdt->active_val = !logic_wdt->active_val; ++ ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, ++ logic_wdt->feed_reg, &logic_wdt->active_val, ONE_BYTE); ++ if (ret < 0) { ++ WDT_ERROR("logic toggle wdt write failed.ret = %d\n", ret); ++ } ++ WDT_VERBOSE("logic toggle wdt work.\n"); ++ break; ++ case HW_ALGO_LEVEL: ++ tmp_val = !logic_wdt->active_val; ++ ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, ++ logic_wdt->feed_reg, &tmp_val, ONE_BYTE); ++ if (ret < 0) { ++ WDT_ERROR("logic level wdt write first failed.ret = %d\n", ret); ++ } ++ udelay(1); ++ ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, ++ logic_wdt->feed_reg, &logic_wdt->active_val, ONE_BYTE); ++ if (ret < 0) { ++ WDT_ERROR("logic level wdt write second failed.ret = %d\n", ret); ++ } ++ WDT_VERBOSE("logic level wdt work.\n"); ++ break; ++ case HW_ALGO_EIGENVALUES: ++ ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, ++ logic_wdt->feed_reg, &logic_wdt->active_val, ONE_BYTE); ++ if (ret < 0) { ++ WDT_ERROR("logic eigenvalues wdt write failed, path: %s, mode: %d, reg: 0x%x, val: 0x%x, ret: %d\n", ++ logic_wdt->feed_dev_name, logic_wdt->logic_func_mode, logic_wdt->feed_reg, ++ logic_wdt->active_val, ret); ++ } ++ WDT_VERBOSE("logic eigenvalues wdt work, path: %s, mode: %d, reg: 0x%x, val: 0x%x\n", ++ logic_wdt->feed_dev_name, logic_wdt->logic_func_mode, logic_wdt->feed_reg, logic_wdt->active_val); ++ break; ++ } ++ } ++ return; ++} ++ ++static enum hrtimer_restart hrtimer_hwping(struct hrtimer *timer) ++{ ++ wb_wdt_priv_t *priv = container_of(timer, wb_wdt_priv_t, hrtimer); ++ ++ wdt_hwping(priv); ++ hrtimer_forward(timer, timer->base->get_time(), priv->m_kt); ++ return HRTIMER_RESTART; ++} ++ ++static int thread_timer_cfg(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) ++{ ++ struct device *dev; ++ uint32_t hw_margin; ++ uint32_t feed_time; ++ uint32_t accuracy; ++ uint8_t set_time_val; ++ int ret; ++ ++ dev = priv->dev; ++ ++ ret = 0; ++ if (dev->of_node) { ++ ret += of_property_read_u32(dev->of_node, "feed_time", &priv->feed_time); ++ if (ret != 0) { ++ dev_err(dev, "thread Failed to priv dts.\n"); ++ return -ENXIO; ++ } ++ } else { ++ priv->feed_time = wb_wdt_device->feed_time; ++ } ++ WDT_VERBOSE("thread priv->feed_time: %u.\n", priv->feed_time); ++ ++ hw_margin = priv->hw_margin; ++ feed_time = priv->feed_time; ++ accuracy = priv->timer_accuracy; ++ ++ if ((feed_time > (hw_margin / 2)) || (feed_time == 0)) { ++ dev_err(dev, "thread timer feed_time[%d] should be less than half hw_margin or zero.\n", feed_time); ++ return -EINVAL; ++ } ++ ++ if (priv->timer_accuracy_reg_flag != 0) { ++ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, ++ priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); ++ if (ret < 0) { ++ dev_err(priv->dev, "set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", ++ priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); ++ return ret; ++ } ++ } ++ ++ set_time_val = hw_margin / accuracy; ++ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, ++ priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); ++ if (ret < 0) { ++ dev_err(dev, "set wdt thread timer reg error.\n"); ++ return ret; ++ } ++ ++ if (priv->timer_update_reg_flag != 0) { ++ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, ++ priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); ++ if (ret < 0) { ++ dev_err(priv->dev, "set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", ++ priv->timer_update_reg, priv->timer_update_reg_val, ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int wdt_thread_timer(void *data) ++{ ++ wb_wdt_priv_t *priv = data; ++ ++ while (!kthread_should_stop()) { ++ schedule_timeout_uninterruptible(msecs_to_jiffies(priv->feed_time)); ++ wdt_hwping(priv); ++ } ++ return 0; ++} ++ ++static int thread_timer_create(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) ++{ ++ struct task_struct *p; ++ int ret; ++ ++ ret = thread_timer_cfg(priv, wb_wdt_device); ++ if (ret < 0) { ++ dev_err(priv->dev, "set wdt thread timer failed.\n"); ++ return ret; ++ } ++ ++ p = kthread_create(wdt_thread_timer, (void *)priv, "%s", "wb_wdt"); ++ if (!IS_ERR(p)) { ++ WDT_VERBOSE("timer thread create success.\n"); ++ priv->thread = p; ++ wake_up_process(p); ++ } else { ++ dev_err(priv->dev, "timer thread create failed.\n"); ++ return -ENXIO; ++ } ++ ++ ret = wb_wdt_enable_ctrl(priv, WDT_ON); ++ if (ret < 0) { ++ dev_err(priv->dev, "thread enable wdt failed.\n"); ++ return -ENXIO; ++ } ++ ++ return 0; ++} ++ ++static int hrtimer_cfg(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) ++{ ++ struct device *dev; ++ struct hrtimer *hrtimer; ++ uint8_t set_time_val; ++ uint8_t hrtimer_s; ++ uint32_t hrtimer_ns; ++ int ret; ++ uint32_t hw_margin; ++ uint32_t feed_time; ++ uint32_t accuracy; ++ uint32_t max_timeout; ++ ++ dev = priv->dev; ++ ++ ret = 0; ++ if (dev->of_node) { ++ ret += of_property_read_u32(dev->of_node, "feed_time", &priv->feed_time); ++ if (ret != 0) { ++ dev_err(dev, "hrtimer Failed to priv dts.\n"); ++ return -ENXIO; ++ } ++ } else { ++ priv->feed_time = wb_wdt_device->feed_time; ++ } ++ WDT_VERBOSE("hrtimer priv->feed_time: %u.\n", priv->feed_time); ++ ++ hrtimer = &priv->hrtimer; ++ hw_margin = priv->hw_margin; ++ feed_time = priv->feed_time; ++ accuracy = priv->timer_accuracy; ++ max_timeout = accuracy * 255; ++ ++ if (hw_margin < accuracy || hw_margin > max_timeout) { ++ dev_err(dev, "hrtimer_hw_margin should be between %u and %u.\n", ++ accuracy, max_timeout); ++ return -EINVAL; ++ } ++ if ((feed_time > (hw_margin / 2)) || (feed_time == 0)) { ++ dev_err(dev, "feed_time[%d] should be less than half hw_margin or zeor.\n", feed_time); ++ return -EINVAL; ++ } ++ ++ hrtimer_s = feed_time / MS_TO_S; ++ hrtimer_ns = (feed_time % MS_TO_S) * MS_TO_NS; ++ set_time_val = hw_margin / accuracy; ++ ++ if (priv->timer_accuracy_reg_flag != 0) { ++ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, ++ priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); ++ if (ret < 0) { ++ dev_err(priv->dev, "set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", ++ priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); ++ return ret; ++ } ++ } ++ ++ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, ++ priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); ++ if (ret < 0) { ++ dev_err(dev, "set wdt time reg error.\n"); ++ return ret; ++ } ++ ++ if (priv->timer_update_reg_flag != 0) { ++ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, ++ priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); ++ if (ret < 0) { ++ dev_err(priv->dev, "set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", ++ priv->timer_update_reg, priv->timer_update_reg_val, ret); ++ return ret; ++ } ++ } ++ ++ priv->m_kt = ktime_set(hrtimer_s, hrtimer_ns); ++ hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ hrtimer->function = hrtimer_hwping; ++ hrtimer_start(hrtimer, priv->m_kt, HRTIMER_MODE_REL); ++ ++ ret = wb_wdt_enable_ctrl(priv, WDT_ON); ++ if (ret < 0) { ++ dev_err(dev, "hrtimer enable wdt failed.\n"); ++ return -ENXIO; ++ } ++ ++ return 0; ++} ++ ++static int wb_wdt_ping(struct watchdog_device *wdd) ++{ ++ wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); ++ ++ wdt_hwping(priv); ++ return 0; ++} ++ ++static int wb_wdt_start(struct watchdog_device *wdd) ++{ ++ wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); ++ int ret; ++ ++ ret = wb_wdt_enable_ctrl(priv, WDT_ON); ++ if (ret < 0) { ++ WDT_ERROR("start wdt enable failed.\n"); ++ return -ENXIO; ++ } ++ set_bit(WDOG_HW_RUNNING, &wdd->status); ++ return 0; ++} ++ ++static int wb_wdt_stop(struct watchdog_device *wdd) ++{ ++ wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); ++ int ret; ++ ++ ret = wb_wdt_enable_ctrl(priv, WDT_OFF); ++ if (ret < 0) { ++ WDT_ERROR("stop wdt enable failed.\n"); ++ return -ENXIO; ++ } ++ clear_bit(WDOG_HW_RUNNING, &wdd->status); ++ return 0; ++} ++ ++static int wb_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) ++{ ++ wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); ++ uint32_t timeout_ms; ++ uint32_t accuracy; ++ uint8_t set_time_val; ++ int ret; ++ ++ accuracy = priv->timer_accuracy; ++ timeout_ms = t * 1000; ++ if (timeout_ms > accuracy * 255) { ++ WDT_ERROR("set wdt timeout too larger error.timeout_ms:%u\n", timeout_ms); ++ return -EINVAL; ++ } ++ ++ if (priv->timer_accuracy_reg_flag != 0) { ++ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, ++ priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); ++ if (ret < 0) { ++ WDT_ERROR("set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", ++ priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); ++ return ret; ++ } ++ } ++ ++ set_time_val = timeout_ms / accuracy; ++ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, ++ priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); ++ if (ret < 0) { ++ WDT_ERROR("set wdt timeout reg error, set_time_val:%u ret:%d\n", set_time_val, ret); ++ return ret; ++ } ++ ++ if (priv->timer_update_reg_flag != 0) { ++ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, ++ priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); ++ if (ret < 0) { ++ WDT_ERROR("set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", ++ priv->timer_update_reg, priv->timer_update_reg_val, ret); ++ return ret; ++ } ++ } ++ ++ wdd->timeout = t; ++ ++ return 0; ++} ++ ++static unsigned int wb_wdt_get_timeleft(struct watchdog_device *wdd) ++{ ++ wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); ++ unsigned int time_left; ++ uint32_t accuracy; ++ uint8_t get_time_val; ++ int ret; ++ ++ accuracy = priv->timer_accuracy; ++ ++ ret = wb_wdt_read(priv->priv_func_mode, priv->config_dev_name, ++ priv->timeleft_cfg_reg, &get_time_val, ONE_BYTE); ++ if (ret < 0) { ++ WDT_ERROR("get wdt timeout reg error.ret:%d\n", ret); ++ return ret; ++ } ++ time_left = get_time_val * accuracy / MS_TO_S; ++ ++ WDT_VERBOSE("get wdt timeleft %d get_time_val %d accuracy=%d\n", ++ time_left, get_time_val, accuracy); ++ return time_left; ++} ++ ++static const struct watchdog_info wb_wdt_ident = { ++ .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, ++ .firmware_version = 0, ++ .identity = "CPLD Watchdog", ++}; ++ ++static const struct watchdog_ops wb_wdt_ops = { ++ .owner = THIS_MODULE, ++ .start = wb_wdt_start, ++ .stop = wb_wdt_stop, ++ .ping = wb_wdt_ping, ++ .set_timeout = wb_wdt_set_timeout, ++ .get_timeleft = wb_wdt_get_timeleft, ++}; ++ ++static int watchdog_device_cfg(wb_wdt_priv_t *priv) ++{ ++ int ret; ++ uint8_t set_time_val; ++ ++ ret = wb_wdt_enable_ctrl(priv, WDT_OFF); ++ if (ret < 0) { ++ dev_err(priv->dev, "probe disable wdt failed.\n"); ++ return -ENXIO; ++ } ++ ++ if (priv->timer_accuracy_reg_flag != 0) { ++ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, ++ priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); ++ if (ret < 0) { ++ dev_err(priv->dev, "set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", ++ priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); ++ return ret; ++ } ++ } ++ ++ set_time_val = priv->hw_margin / priv->timer_accuracy; ++ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, ++ priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); ++ if (ret < 0) { ++ dev_err(priv->dev, "set wdt time reg error.\n"); ++ return ret; ++ } ++ ++ if (priv->timer_update_reg_flag != 0) { ++ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, ++ priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); ++ if (ret < 0) { ++ dev_err(priv->dev, "set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", ++ priv->timer_update_reg, priv->timer_update_reg_val, ret); ++ return ret; ++ } ++ } ++ ++ watchdog_set_drvdata(&priv->wdd, priv); ++ ++ priv->wdd.info = &wb_wdt_ident; ++ priv->wdd.ops = &wb_wdt_ops; ++ priv->wdd.bootstatus = 0; ++ priv->wdd.timeout = priv->hw_margin / MS_TO_S; ++ priv->wdd.min_timeout = priv->timer_accuracy / MS_TO_S; ++ priv->wdd.max_timeout = priv->timer_accuracy * MAX_REG_VAL / MS_TO_S; ++ priv->wdd.parent = priv->dev; ++ ++ watchdog_stop_on_reboot(&priv->wdd); ++ ++ ret = devm_watchdog_register_device(priv->dev, &priv->wdd); ++ if (ret != 0) { ++ dev_err(priv->dev, "cannot register watchdog device (err=%d)\n", ret); ++ return -ENXIO; ++ } ++ ++ return 0; ++} ++ ++static int logic_wdt_init(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) ++{ ++ struct device *dev; ++ logic_wdt_info_t *logic_wdt; ++ int ret; ++ ++ dev = priv->dev; ++ logic_wdt = &priv->logic_wdt; ++ ++ ret = 0; ++ if (dev->of_node) { ++ ret += of_property_read_string(dev->of_node, "feed_dev_name", &logic_wdt->feed_dev_name); ++ ret += of_property_read_u32(dev->of_node, "feed_reg", &logic_wdt->feed_reg); ++ ret += of_property_read_u8(dev->of_node, "active_val", &logic_wdt->active_val); ++ ret += of_property_read_u8(dev->of_node, "logic_func_mode", &logic_wdt->logic_func_mode); ++ if (ret != 0) { ++ dev_err(dev, "Failed to logic_wdt dts.\n"); ++ return -ENXIO; ++ } ++ } else { ++ logic_wdt->feed_dev_name = wb_wdt_device->wdt_config_mode.logic_wdt.feed_dev_name; ++ logic_wdt->feed_reg = wb_wdt_device->wdt_config_mode.logic_wdt.feed_reg; ++ logic_wdt->active_val = wb_wdt_device->wdt_config_mode.logic_wdt.active_val; ++ logic_wdt->logic_func_mode = wb_wdt_device->wdt_config_mode.logic_wdt.logic_func_mode; ++ } ++ ++ logic_wdt->state_val = logic_wdt->active_val; ++ ++ WDT_VERBOSE("feed_dev_name:%s, feed_reg:0x%x, active_val:%u, logic_func_mode:%u\n", ++ logic_wdt->feed_dev_name, logic_wdt->feed_reg, ++ logic_wdt->active_val, logic_wdt->logic_func_mode); ++ ++ return 0; ++} ++ ++static int gpio_wdt_init(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) ++{ ++ struct device *dev; ++ gpio_wdt_info_t *gpio_wdt; ++ enum of_gpio_flags flags; ++ uint32_t f = 0; ++ int ret; ++ ++ dev = priv->dev; ++ gpio_wdt = &priv->gpio_wdt; ++ ++ if (dev->of_node) { ++ gpio_wdt->gpio = of_get_gpio_flags(dev->of_node, 0, &flags); ++ } else { ++ gpio_wdt->gpio = wb_wdt_device->wdt_config_mode.gpio_wdt.gpio; ++ flags = wb_wdt_device->wdt_config_mode.gpio_wdt.flags; ++ } ++ if (!gpio_is_valid(gpio_wdt->gpio)) { ++ dev_err(dev, "gpio is invalid.\n"); ++ return gpio_wdt->gpio; ++ } ++ ++ gpio_wdt->active_low = flags & OF_GPIO_ACTIVE_LOW; ++ ++ if(priv->hw_algo == HW_ALGO_TOGGLE) { ++ f = GPIOF_IN; ++ } else { ++ f = gpio_wdt->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; ++ } ++ ++ ret = devm_gpio_request_one(dev, gpio_wdt->gpio, f, ++ dev_name(dev)); ++ if (ret) { ++ dev_err(dev, "devm_gpio_request_one failed.\n"); ++ return ret; ++ } ++ ++ gpio_wdt->state = gpio_wdt->active_low; ++ gpio_direction_output(gpio_wdt->gpio, gpio_wdt->state); ++ ++ WDT_VERBOSE("active_low:%d\n", gpio_wdt->active_low); ++ return 0; ++} ++ ++static ssize_t set_wdt_sysfs_value(struct device *dev, struct device_attribute *da, ++ const char *buf, size_t count) ++{ ++ wb_wdt_priv_t *priv = dev_get_drvdata(dev); ++ int ret, val; ++ ++ val = 0; ++ sscanf(buf, "%d", &val); ++ WDT_VERBOSE("set wdt, val:%d.\n", val); ++ ++ if (val < 0 || val > 255) { ++ WDT_ERROR("set wdt val %d failed.\n", val); ++ return -EINVAL; ++ } ++ ++ mutex_lock(&priv->update_lock); ++ ++ ret = wb_wdt_enable_ctrl(priv, val); ++ if (ret < 0) { ++ WDT_ERROR("set wdt sysfs value:%u failed.\n", val); ++ goto fail; ++ } ++ ++ WDT_VERBOSE("set wdt sysfs value:%u successed.\n", val); ++ mutex_unlock(&priv->update_lock); ++ return count; ++ ++fail: ++ mutex_unlock(&priv->update_lock); ++ return ret; ++} ++ ++static ssize_t show_wdt_sysfs_value(struct device *dev, ++ struct device_attribute *da, char *buf) ++{ ++ wb_wdt_priv_t *priv = dev_get_drvdata(dev); ++ uint8_t val, status; ++ int ret; ++ ++ mutex_lock(&priv->update_lock); ++ ++ ret = wb_wdt_read(priv->priv_func_mode, priv->config_dev_name, ++ priv->enable_reg, &val, ONE_BYTE); ++ if (ret < 0) { ++ dev_err(priv->dev, "read wdt enable reg val error.\n"); ++ goto fail; ++ } ++ ++ val &= priv->enable_mask; ++ if (val == priv->enable_val) { ++ status = WDT_ON; ++ } else if(val == priv->disable_val) { ++ status = WDT_OFF; ++ } else { ++ WDT_ERROR("enable reg read val not match set val, read val:%u, mask:%u, enable_val:%u, disable_val:%u", ++ val, priv->enable_mask, priv->enable_val, priv->disable_val); ++ ret = -EIO; ++ goto fail; ++ } ++ ++ WDT_VERBOSE("read_val:%u, mask:%u, enable_val:%u, disable_val:%u, status:%u", ++ val, priv->enable_mask, priv->enable_val, priv->disable_val, status); ++ ++ mutex_unlock(&priv->update_lock); ++ return sprintf(buf, "%u\n", status); ++ ++fail: ++ mutex_unlock(&priv->update_lock); ++ return ret; ++} ++ ++static SENSOR_DEVICE_ATTR(wdt_status, S_IRUGO | S_IWUSR, show_wdt_sysfs_value, set_wdt_sysfs_value, 0); ++ ++static struct attribute *wdt_sysfs_attrs[] = { ++ &sensor_dev_attr_wdt_status.dev_attr.attr, ++ NULL ++}; ++ ++static const struct attribute_group wdt_sysfs_group = { ++ .attrs = wdt_sysfs_attrs, ++}; ++ ++struct wdt_attr_match_group { ++ uint8_t index; ++ const struct attribute_group *attr_group_ptr; ++}; ++ ++static struct wdt_attr_match_group g_wdt_attr_match[] = { ++ {0, &wdt_sysfs_group}, ++}; ++ ++static const struct attribute_group *wdt_get_attr_group(uint32_t index) ++{ ++ int i; ++ struct wdt_attr_match_group *group; ++ ++ for (i = 0; i < ARRAY_SIZE(g_wdt_attr_match); i++) { ++ group = &g_wdt_attr_match[i]; ++ if (index == group->index) { ++ WDT_VERBOSE("get wdt attr, index:%u.\n", index); ++ return group->attr_group_ptr; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int wb_wdt_probe(struct platform_device *pdev) ++{ ++ wb_wdt_priv_t *priv; ++ int ret; ++ const char *algo; ++ wb_wdt_device_t *wb_wdt_device; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&pdev->dev, "devm_kzalloc failed.\n"); ++ return -ENOMEM; ++ } ++ ++ platform_set_drvdata(pdev, priv); ++ ++ if (pdev->dev.of_node) { ++ ret = 0; ++ ret += of_property_read_string(pdev->dev.of_node, "config_dev_name", &priv->config_dev_name); ++ ret += of_property_read_string(pdev->dev.of_node, "hw_algo", &algo); ++ ret += of_property_read_u8(pdev->dev.of_node, "config_mode", &priv->config_mode); ++ ret += of_property_read_u8(pdev->dev.of_node, "priv_func_mode", &priv->priv_func_mode); ++ ret += of_property_read_u8(pdev->dev.of_node, "enable_val", &priv->enable_val); ++ ret += of_property_read_u8(pdev->dev.of_node, "disable_val", &priv->disable_val); ++ ret += of_property_read_u8(pdev->dev.of_node, "enable_mask", &priv->enable_mask); ++ ret += of_property_read_u32(pdev->dev.of_node, "enable_reg", &priv->enable_reg); ++ ret += of_property_read_u32(pdev->dev.of_node, "timeout_cfg_reg", &priv->timeout_cfg_reg); ++ ret += of_property_read_u32(pdev->dev.of_node,"hw_margin_ms", &priv->hw_margin); ++ ret += of_property_read_u8(pdev->dev.of_node,"feed_wdt_type", &priv->feed_wdt_type); ++ ret += of_property_read_u32(pdev->dev.of_node,"timer_accuracy", &priv->timer_accuracy); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "Failed to priv dts.\n"); ++ return -ENXIO; ++ } ++ ++ priv->sysfs_index = SYSFS_NO_CFG; ++ of_property_read_u8(pdev->dev.of_node,"sysfs_index", &priv->sysfs_index); ++ ++ priv->timeleft_cfg_reg = priv->timeout_cfg_reg; ++ of_property_read_u32(pdev->dev.of_node,"timeleft_cfg_reg", &priv->timeleft_cfg_reg); ++ ++ /* timer accuracy register is optional */ ++ ret = of_property_read_u8(pdev->dev.of_node,"timer_accuracy_reg_flag", &priv->timer_accuracy_reg_flag); ++ if (ret < 0) { ++ /* case: don't has timer_accuracy_reg */ ++ dev_dbg(&pdev->dev, "Failed to get property in dts: timer_accuracy_reg_flag.\n"); ++ priv->timer_accuracy_reg_flag = 0; ++ } else { ++ ret = of_property_read_u32(pdev->dev.of_node, "timer_accuracy_reg", &priv->timer_accuracy_reg); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to get timer accuracy register address.\n"); ++ return -ENXIO; ++ } ++ ret = of_property_read_u8(pdev->dev.of_node, "timer_accuracy_reg_val", &priv->timer_accuracy_reg_val); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to get timer accuracy register value.\n"); ++ return -ENXIO; ++ } ++ } ++ ++ /* timer update register is optional */ ++ ret = of_property_read_u8(pdev->dev.of_node,"timer_update_reg_flag", &priv->timer_update_reg_flag); ++ if (ret < 0) { ++ /* case: don't has timer_update_reg */ ++ dev_dbg(&pdev->dev, "Failed to get property in dts: timer_update_reg_flag.\n"); ++ priv->timer_update_reg_flag = 0; /* no timer update register */ ++ } else { ++ ret = of_property_read_u32(pdev->dev.of_node, "timer_update_reg", &priv->timer_update_reg); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to get timer update register address.\n"); ++ return -ENXIO; ++ } ++ ret = of_property_read_u8(pdev->dev.of_node, "timer_update_reg_val", &priv->timer_update_reg_val); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to get timer update register value.\n"); ++ return -ENXIO; ++ } ++ } ++ } else { ++ if (pdev->dev.platform_data == NULL) { ++ dev_err(&pdev->dev, "Failed to get platform data config.\n"); ++ return -ENXIO; ++ } ++ wb_wdt_device = pdev->dev.platform_data; ++ priv->config_dev_name = wb_wdt_device->config_dev_name; ++ algo = wb_wdt_device->hw_algo; ++ priv->config_mode = wb_wdt_device->config_mode; ++ priv->priv_func_mode = wb_wdt_device->priv_func_mode; ++ priv->enable_val = wb_wdt_device->enable_val; ++ priv->disable_val = wb_wdt_device->disable_val; ++ priv->enable_mask = wb_wdt_device->enable_mask; ++ priv->enable_reg = wb_wdt_device->enable_reg; ++ priv->timeout_cfg_reg = wb_wdt_device->timeout_cfg_reg; ++ priv->hw_margin = wb_wdt_device->hw_margin; ++ priv->timer_accuracy = wb_wdt_device->timer_accuracy; ++ priv->feed_wdt_type = wb_wdt_device->feed_wdt_type; ++ priv->sysfs_index = wb_wdt_device->sysfs_index; ++ priv->timeleft_cfg_reg = wb_wdt_device->timeleft_cfg_reg; ++ priv->timer_accuracy_reg_flag = wb_wdt_device->timer_accuracy_reg_flag; ++ priv->timer_accuracy_reg = wb_wdt_device->timer_accuracy_reg; ++ priv->timer_accuracy_reg_val = wb_wdt_device->timer_accuracy_reg_val; ++ priv->timer_update_reg_flag = wb_wdt_device->timer_update_reg_flag; ++ priv->timer_update_reg = wb_wdt_device->timer_update_reg; ++ priv->timer_update_reg_val = wb_wdt_device->timer_update_reg_val; ++ } ++ ++ if (!strcmp(algo, "toggle")) { ++ priv->hw_algo = HW_ALGO_TOGGLE; ++ } else if (!strcmp(algo, "level")) { ++ priv->hw_algo = HW_ALGO_LEVEL; ++ } else if (!strcmp(algo, "eigenvalues")) { ++ priv->hw_algo = HW_ALGO_EIGENVALUES; ++ } else { ++ dev_err(&pdev->dev, "hw_algo config error.must be toggle or level.\n"); ++ return -EINVAL; ++ } ++ ++ WDT_VERBOSE("config_dev_name:%s, config_mode:%u, priv_func_mode:%u, enable_reg:0x%x, timeout_cfg_reg:0x%x\n", ++ priv->config_dev_name, priv->config_mode, priv->priv_func_mode, priv->enable_reg, priv->timeout_cfg_reg); ++ WDT_VERBOSE("timeout_cfg_reg:0x%x, enable_val:0x%x, disable_val:0x%x, enable_mask:0x%x, hw_margin:%u, feed_wdt_type:%u\n", ++ priv->timeleft_cfg_reg, priv->enable_val, priv->disable_val, priv->enable_mask, priv->hw_margin, priv->feed_wdt_type); ++ WDT_VERBOSE("timer_accuracy_reg_flag: %d, timer_accuracy_reg: 0x%x, timer_accuracy_reg_val: 0x%x, timer_accuracy: %d\n", ++ priv->timer_accuracy_reg_flag, priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, priv->timer_accuracy); ++ WDT_VERBOSE("timer_update_reg_flag: %d, timer_update_reg: 0x%x, timer_update_reg_val: 0x%x\n", priv->timer_update_reg_flag, ++ priv->timer_update_reg, priv->timer_update_reg_val); ++ ++ priv->dev = &pdev->dev; ++ if (priv->config_mode == GPIO_FEED_WDT_MODE) { ++ ret = gpio_wdt_init(priv, wb_wdt_device); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "init gpio mode wdt failed.\n"); ++ return -ENXIO; ++ } ++ } else if (priv->config_mode == LOGIC_FEED_WDT_MODE) { ++ ret = logic_wdt_init(priv, wb_wdt_device); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "init func mode wdt failed.\n"); ++ return -ENXIO; ++ } ++ } else { ++ dev_err(&pdev->dev, "unsupport %u config_mode, dts configure error.\n", ++ priv->config_mode); ++ return -ENXIO; ++ } ++ ++ switch (priv->feed_wdt_type) { ++ case WATCHDOG_DEVICE_TYPE: ++ ret = watchdog_device_cfg(priv); ++ break; ++ case HRTIMER_TYPE: ++ ret = hrtimer_cfg(priv, wb_wdt_device); ++ break; ++ case THREAD_TYPE: ++ ret = thread_timer_create(priv, wb_wdt_device); ++ break; ++ default: ++ dev_err(&pdev->dev, "timer type %u unsupport.\n", priv->feed_wdt_type); ++ return -EINVAL; ++ } ++ if (ret < 0) { ++ dev_err(&pdev->dev, "init timer feed_wdt_type %u failed.\n", priv->feed_wdt_type); ++ return -ENXIO; ++ } ++ ++ dev_info(&pdev->dev, "register %s mode, config_mode %u, func_mode %u, %u ms overtime wdt success\n", ++ algo, priv->config_mode, priv->priv_func_mode, priv->hw_margin); ++ ++ if (priv->sysfs_index != SYSFS_NO_CFG) { ++ ++ priv->sysfs_group = wdt_get_attr_group(priv->sysfs_index); ++ if (priv->sysfs_group) { ++ ret = sysfs_create_group(&pdev->dev.kobj, priv->sysfs_group); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "sysfs_create_group failed. ret:%d.\n", ret); ++ return -ENOMEM; ++ } ++ dev_info(&pdev->dev, "sysfs create group success\n"); ++ } else { ++ dev_err(&pdev->dev, "failed to find %u index wdt, return NULL.\n", priv->sysfs_index); ++ return -ENOMEM; ++ } ++ ++ mutex_init(&priv->update_lock); ++ ++ dev_info(&pdev->dev, "register %u index wdt sysfs success." ,priv->sysfs_index); ++ } ++ ++ return 0; ++} ++ ++static void unregister_action(struct platform_device *pdev) ++{ ++ wb_wdt_priv_t *priv = platform_get_drvdata(pdev); ++ gpio_wdt_info_t *gpio_wdt; ++ logic_wdt_info_t *logic_wdt; ++ int ret; ++ ++ ret = wb_wdt_enable_ctrl(priv, WDT_OFF); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "remove disable wdt failed.\n"); ++ } ++ ++ if (priv->sysfs_index != SYSFS_NO_CFG) { ++ sysfs_remove_group(&pdev->dev.kobj, priv->sysfs_group); ++ } ++ ++ if (priv->feed_wdt_type == HRTIMER_TYPE) { ++ hrtimer_cancel(&priv->hrtimer); ++ } else if (priv->feed_wdt_type == THREAD_TYPE) { ++ kthread_stop(priv->thread); ++ priv->thread = NULL; ++ } else { ++ WDT_VERBOSE("wdd type, do nothing.\n"); ++ } ++ ++ if (priv->config_mode == GPIO_FEED_WDT_MODE) { ++ gpio_wdt = &priv->gpio_wdt; ++ gpio_set_value_cansleep(gpio_wdt->gpio, !gpio_wdt->active_low); ++ ++ if (priv->hw_algo == HW_ALGO_TOGGLE) { ++ gpio_direction_input(gpio_wdt->gpio); ++ } ++ } else { ++ logic_wdt = &priv->logic_wdt; ++ logic_wdt->state_val = !logic_wdt->state_val; ++ ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, ++ logic_wdt->feed_reg, &logic_wdt->state_val, ONE_BYTE); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "set wdt control reg error.\n"); ++ } ++ } ++ ++ return; ++} ++ ++static int wb_wdt_remove(struct platform_device *pdev) ++{ ++ WDT_VERBOSE("enter remove wdt.\n"); ++ unregister_action(pdev); ++ dev_info(&pdev->dev, "remove wdt finish.\n"); ++ ++ return 0; ++} ++ ++static void wb_wdt_shutdown(struct platform_device *pdev) ++{ ++ WDT_VERBOSE("enter shutdown wdt.\n"); ++ unregister_action(pdev); ++ dev_info(&pdev->dev, "shutdown wdt finish.\n"); ++ ++ return; ++} ++ ++static const struct of_device_id wb_wdt_dt_ids[] = { ++ { .compatible = "wb_wdt", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, wb_wdt_dt_ids); ++ ++static struct platform_driver wb_wdt_driver = { ++ .driver = { ++ .name = "wb_wdt", ++ .of_match_table = wb_wdt_dt_ids, ++ }, ++ .probe = wb_wdt_probe, ++ .remove = wb_wdt_remove, ++ .shutdown = wb_wdt_shutdown, ++}; ++ ++#ifdef CONFIG_GPIO_WATCHDOG_ARCH_INITCALL ++static int __init wb_wdt_init(void) ++{ ++ return platform_driver_register(&wb_wdt_driver); ++} ++arch_initcall(wb_wdt_init); ++#else ++module_platform_driver(wb_wdt_driver); ++#endif ++ ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("watchdog driver"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.h +new file mode 100644 +index 000000000..d45904ba3 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.h +@@ -0,0 +1,53 @@ ++#ifndef __WB_WDT_H__ ++#define __WB_WDT_H__ ++ ++#include ++ ++#define SYSFS_NO_CFG (0xff) ++#define INVALID_REG_ADDR (0xffffffff) ++ ++typedef struct gpio_wdt_info_s { ++ int gpio; ++ enum of_gpio_flags flags; ++ bool active_low; ++ bool state; ++}gpio_wdt_info_t; ++ ++typedef struct logic_wdt_info_s { ++ const char *feed_dev_name; ++ uint8_t logic_func_mode; ++ uint32_t feed_reg; ++ uint8_t active_val; ++ uint8_t state_val; ++}logic_wdt_info_t; ++ ++typedef struct wb_wdt_device_s { ++ int device_flag; ++ const char *config_dev_name; ++ uint8_t config_mode; ++ const char *hw_algo; ++ uint8_t enable_val; ++ uint8_t disable_val; ++ uint8_t enable_mask; ++ uint8_t priv_func_mode; ++ uint8_t feed_wdt_type; ++ uint32_t enable_reg; ++ uint32_t timeout_cfg_reg; ++ uint32_t timeleft_cfg_reg; ++ uint32_t hw_margin; ++ uint32_t feed_time; ++ uint8_t timer_accuracy_reg_flag; ++ uint32_t timer_accuracy_reg; ++ uint8_t timer_accuracy_reg_val; ++ uint32_t timer_accuracy; ++ uint8_t timer_update_reg_flag; ++ uint32_t timer_update_reg; ++ uint8_t timer_update_reg_val; ++ union { ++ gpio_wdt_info_t gpio_wdt; ++ logic_wdt_info_t logic_wdt; ++ } wdt_config_mode; ++ uint8_t sysfs_index; ++} wb_wdt_device_t; ++ ++#endif +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_xdpe132g5c.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_xdpe132g5c.c +new file mode 100644 +index 000000000..edc12d34b +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_xdpe132g5c.c +@@ -0,0 +1,574 @@ ++/* ++ * xdpe132g5c_i2c_drv.c ++ * ++ * This module create sysfs to set AVS and create hwmon to get out power ++ * through xdpe132g5c I2C address. ++ * ++ * History ++ * [Version] [Date] [Description] ++ * * v1.0 2021-09-17 Initial version ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define WB_I2C_RETRY_SLEEP_TIME (10000) /* 10ms */ ++#define WB_I2C_RETRY_TIME (10) ++#define WB_XDPE_I2C_PAGE_ADDR (0xff) ++#define WB_XDPE_I2C_VOUT_MODE (0x40) ++#define WB_XDPE_I2C_VOUT_COMMAND (0x42) ++#define WB_XDPE_I2C_VOUT_PAGE (0x06) ++#define WB_XDPE_VOUT_MAX_THRESHOLD ((0xFFFF * 1000L * 1000L) / (256)) ++#define WB_XDPE_VOUT_MIN_THRESHOLD (0) ++ ++static int g_wb_xdpe_debug = 0; ++static int g_wb_xdpe_error = 0; ++ ++module_param(g_wb_xdpe_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_xdpe_error, int, S_IRUGO | S_IWUSR); ++ ++#define WB_XDPE_VERBOSE(fmt, args...) do { \ ++ if (g_wb_xdpe_debug) { \ ++ printk(KERN_INFO "[WB_XDPE][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_XDPE_ERROR(fmt, args...) do { \ ++ if (g_wb_xdpe_error) { \ ++ printk(KERN_ERR "[WB_XDPE][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++struct xdpe_data { ++ struct i2c_client *client; ++ struct device *hwmon_dev; ++ struct mutex update_lock; ++ long vout_max; ++ long vout_min; ++}; ++ ++typedef struct xdpe_vout_data_s { ++ u8 vout_mode; ++ int vout_precision; ++} xdpe_vout_data_t; ++ ++static xdpe_vout_data_t g_xdpe_vout_group[] = { ++ {.vout_mode = 0x18, .vout_precision = 256}, ++ {.vout_mode = 0x17, .vout_precision = 512}, ++ {.vout_mode = 0x16, .vout_precision = 1024}, ++ {.vout_mode = 0x15, .vout_precision = 2048}, ++ {.vout_mode = 0x14, .vout_precision = 4096}, ++}; ++ ++static s32 wb_i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command) ++{ ++ int i; ++ s32 ret; ++ ++ for (i = 0; i < WB_I2C_RETRY_TIME; i++) { ++ ret = i2c_smbus_read_byte_data(client, command); ++ if (ret >= 0) { ++ return ret; ++ } ++ usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); ++ } ++ return ret; ++} ++ ++static s32 wb_i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command, u8 value) ++{ ++ int i; ++ s32 ret; ++ ++ for (i = 0; i < WB_I2C_RETRY_TIME; i++) { ++ ret = i2c_smbus_write_byte_data(client, command, value); ++ if (ret >= 0) { ++ return ret; ++ } ++ usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); ++ } ++ return ret; ++} ++ ++static s32 wb_i2c_smbus_read_word_data(const struct i2c_client *client, u8 command) ++{ ++ int i; ++ s32 ret; ++ ++ for (i = 0; i < WB_I2C_RETRY_TIME; i++) { ++ ret = i2c_smbus_read_word_data(client, command); ++ if (ret >= 0) { ++ return ret; ++ } ++ usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); ++ } ++ return ret; ++} ++ ++static s32 wb_i2c_smbus_write_word_data(const struct i2c_client *client, u8 command, ++ u16 value) ++{ ++ int i; ++ s32 ret; ++ ++ for (i = 0; i < WB_I2C_RETRY_TIME; i++) { ++ ret = i2c_smbus_write_word_data(client, command, value); ++ if (ret >= 0) { ++ return ret; ++ } ++ usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); ++ } ++ return ret; ++} ++ ++static long calc_power_linear11_data(int data) ++{ ++ s16 exponent; ++ s32 mantissa; ++ long val; ++ ++ exponent = ((s16)data) >> 11; ++ mantissa = ((s16)((data & 0x7ff) << 5)) >> 5; ++ val = mantissa; ++ val = val * 1000L * 1000L; ++ ++ if (exponent >= 0) { ++ val <<= exponent; ++ } else { ++ val >>= -exponent; ++ } ++ return val; ++} ++ ++static int read_xdpe_power_value(const struct i2c_client *client, u8 page, u8 reg, long *value) ++{ ++ int ret, data; ++ ++ ret = wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, page); ++ if (ret < 0) { ++ WB_XDPE_ERROR("%d-%04x: set xdpe page%u failed, ret: %d\n", client->adapter->nr, ++ client->addr, page, ret); ++ return ret; ++ } ++ data = wb_i2c_smbus_read_word_data(client, reg); ++ if (data < 0) { ++ WB_XDPE_ERROR("%d-%04x: read xdpe page%u reg: 0x%x failed, ret: %d\n", ++ client->adapter->nr, client->addr, page, reg, data); ++ return data; ++ } ++ *value = calc_power_linear11_data(data); ++ WB_XDPE_VERBOSE("%d-%04x: page%u reg: 0x%x rd_data: 0x%x, decode linear11 value: %ld\n", ++ client->adapter->nr, client->addr, page, reg, data, *value); ++ return 0; ++} ++ ++static ssize_t xdpe_power_value_show(struct device *dev, struct device_attribute *da, ++ char *buf) ++{ ++ int ret, ori_page; ++ u16 sensor_h, sensor_l; ++ u8 page, reg; ++ struct sensor_device_attribute *attr; ++ struct i2c_client *client; ++ struct xdpe_data *data; ++ long value1, value2; ++ ++ data = dev_get_drvdata(dev); ++ client = data->client; ++ attr = to_sensor_dev_attr(da); ++ sensor_h = ((attr->index) >> 16) & 0xffff; ++ sensor_l = (attr->index) & 0xffff; ++ ++ mutex_lock(&data->update_lock); ++ ++ ori_page = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_PAGE_ADDR); ++ if (ori_page < 0) { ++ WB_XDPE_ERROR("%d-%04x: read xdpe origin page failed, ret: %d\n", client->adapter->nr, ++ client->addr, ori_page); ++ mutex_unlock(&data->update_lock); ++ return ori_page; ++ } ++ value1 = 0; ++ value2 = 0; ++ ++ if (sensor_h) { ++ page = (sensor_h >> 8) & 0xff; ++ reg = sensor_h & 0xff; ++ ret = read_xdpe_power_value(client, page, reg, &value1); ++ if (ret < 0) { ++ WB_XDPE_ERROR("%d-%04x: read xdpe sensor high sensor page%u reg: 0x%x failed, ret: %d\n", ++ client->adapter->nr, client->addr, page, reg, ret); ++ goto error; ++ } ++ WB_XDPE_VERBOSE("%d-%04x: read xdpe sensor high sensor page%u reg: 0x%x success, value: %ld\n", ++ client->adapter->nr, client->addr, page, reg, value1); ++ } ++ ++ page = (sensor_l >> 8) & 0xff; ++ reg = sensor_l & 0xff; ++ ret = read_xdpe_power_value(client, page, reg, &value2); ++ if (ret < 0) { ++ WB_XDPE_ERROR("%d-%04x: read xdpe sensor low sensor page%u reg: 0x%x failed, ret: %d\n", ++ client->adapter->nr, client->addr, page, reg, ret); ++ goto error; ++ } ++ WB_XDPE_VERBOSE("%d-%04x: read xdpe sensor low sensor page%u reg: 0x%x success, value: %ld\n", ++ client->adapter->nr, client->addr, page, reg, value2); ++ ++ wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); ++ mutex_unlock(&data->update_lock); ++ return snprintf(buf, PAGE_SIZE, "%ld\n", value1 + value2); ++error: ++ wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); ++ mutex_unlock(&data->update_lock); ++ return ret; ++} ++ ++static int xdpe_get_vout_precision(const struct i2c_client *client, int *vout_precision) ++{ ++ int i, vout_mode, a_size; ++ ++ vout_mode = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_VOUT_MODE); ++ if (vout_mode < 0) { ++ WB_XDPE_ERROR("%d-%04x: read xdpe vout mode reg: 0x%x failed, ret: %d\n", ++ client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_MODE, vout_mode); ++ return vout_mode; ++ } ++ ++ a_size = ARRAY_SIZE(g_xdpe_vout_group); ++ for (i = 0; i < a_size; i++) { ++ if (g_xdpe_vout_group[i].vout_mode == vout_mode) { ++ *vout_precision = g_xdpe_vout_group[i].vout_precision; ++ WB_XDPE_VERBOSE("%d-%04x: match, vout mode: 0x%x, precision: %d\n", ++ client->adapter->nr, client->addr, vout_mode, *vout_precision); ++ break; ++ } ++ } ++ if (i == a_size) { ++ WB_XDPE_ERROR("%d-%04x: invalid vout mode: 0x%x\n",client->adapter->nr, client->addr, ++ vout_mode); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static ssize_t xdpe_avs_vout_show(struct device *dev, struct device_attribute *da, char *buf) ++{ ++ int ret, ori_page, vout_cmd, vout_precision; ++ struct i2c_client *client; ++ struct xdpe_data *data; ++ long vout; ++ ++ client = to_i2c_client(dev); ++ data = i2c_get_clientdata(client); ++ ++ mutex_lock(&data->update_lock); ++ ++ ori_page = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_PAGE_ADDR); ++ if (ori_page < 0) { ++ WB_XDPE_ERROR("%d-%04x: read xdpe origin page failed, ret: %d\n", client->adapter->nr, ++ client->addr, ori_page); ++ mutex_unlock(&data->update_lock); ++ return ori_page; ++ } ++ ++ ret = wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, WB_XDPE_I2C_VOUT_PAGE); ++ if (ret < 0) { ++ WB_XDPE_ERROR("%d-%04x: set xdpe avs vout page%u failed, ret: %d\n", client->adapter->nr, ++ client->addr, WB_XDPE_I2C_VOUT_PAGE, ret); ++ goto error; ++ } ++ ++ ret = xdpe_get_vout_precision(client, &vout_precision); ++ if (ret < 0) { ++ WB_XDPE_ERROR("%d-%04x: get xdpe avs vout precision failed, ret: %d\n", ++ client->adapter->nr, client->addr, ret); ++ goto error; ++ } ++ ++ vout_cmd = wb_i2c_smbus_read_word_data(client, WB_XDPE_I2C_VOUT_COMMAND); ++ if (vout_cmd < 0) { ++ ret = vout_cmd; ++ WB_XDPE_ERROR("%d-%04x: read xdpe vout command reg: 0x%x failed, ret: %d\n", ++ client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_COMMAND, ret); ++ goto error; ++ } ++ ++ wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); ++ mutex_unlock(&data->update_lock); ++ ++ vout = vout_cmd * 1000L * 1000L / vout_precision; ++ WB_XDPE_VERBOSE("%d-%04x: vout: %ld, vout_cmd: 0x%x, precision: %d\n", client->adapter->nr, ++ client->addr, vout, vout_cmd, vout_precision); ++ return snprintf(buf, PAGE_SIZE, "%ld\n", vout); ++error: ++ wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); ++ mutex_unlock(&data->update_lock); ++ return ret; ++} ++ ++static ssize_t xdpe_avs_vout_store(struct device *dev, struct device_attribute *da, ++ const char *buf, size_t count) ++{ ++ int ret, ori_page, vout_cmd, vout_cmd_set, vout_precision; ++ struct i2c_client *client; ++ struct xdpe_data *data; ++ long vout, vout_max, vout_min; ++ ++ client = to_i2c_client(dev); ++ ret = kstrtol(buf, 10, &vout); ++ if (ret) { ++ WB_XDPE_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); ++ return -EINVAL; ++ } ++ ++ data = i2c_get_clientdata(client); ++ vout_max = data->vout_max; ++ vout_min = data->vout_min; ++ if ((vout > vout_max) || (vout < vout_min)) { ++ WB_XDPE_ERROR("%d-%04x: vout value: %ld, out of range [%ld, %ld] \n", client->adapter->nr, ++ client->addr, vout, vout_min, vout_max); ++ return -EINVAL; ++ } ++ ++ mutex_lock(&data->update_lock); ++ ++ ori_page = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_PAGE_ADDR); ++ if (ori_page < 0) { ++ WB_XDPE_ERROR("%d-%04x: read xdpe origin page failed, ret: %d\n", client->adapter->nr, ++ client->addr, ori_page); ++ mutex_unlock(&data->update_lock); ++ return ori_page; ++ } ++ ++ ret = wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, WB_XDPE_I2C_VOUT_PAGE); ++ if (ret < 0) { ++ WB_XDPE_ERROR("%d-%04x: set xdpe avs vout page%u failed, ret: %d\n", client->adapter->nr, ++ client->addr, WB_XDPE_I2C_VOUT_PAGE, ret); ++ goto error; ++ } ++ ++ ret = xdpe_get_vout_precision(client, &vout_precision); ++ if (ret < 0) { ++ WB_XDPE_ERROR("%d-%04x: get xdpe avs vout precision failed, ret: %d\n", ++ client->adapter->nr, client->addr, ret); ++ goto error; ++ } ++ ++ vout_cmd_set = (vout * vout_precision) / (1000L * 1000L); ++ if (vout_cmd_set > 0xffff) { ++ WB_XDPE_ERROR("%d-%04x: invalid value, vout %ld, vout_precision: %d, vout_cmd_set: 0x%x\n", ++ client->adapter->nr, client->addr, vout, vout_precision, vout_cmd_set); ++ ret = -EINVAL; ++ goto error; ++ } ++ ret = wb_i2c_smbus_write_word_data(client, WB_XDPE_I2C_VOUT_COMMAND, vout_cmd_set); ++ if (ret < 0) { ++ WB_XDPE_ERROR("%d-%04x: set xdpe vout cmd reg: 0x%x, value: 0x%x failed, ret: %d\n", ++ client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_COMMAND, vout_cmd_set, ret); ++ goto error; ++ } ++ ++ vout_cmd = wb_i2c_smbus_read_word_data(client, WB_XDPE_I2C_VOUT_COMMAND); ++ if (vout_cmd < 0) { ++ ret = vout_cmd; ++ WB_XDPE_ERROR("%d-%04x: read xdpe vout command reg: 0x%x failed, ret: %d\n", ++ client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_COMMAND, ret); ++ goto error; ++ } ++ if (vout_cmd != vout_cmd_set) { ++ ret = -EIO; ++ WB_XDPE_ERROR("%d-%04x: vout cmd value check error, vout cmd read: 0x%x, vout cmd set: 0x%x\n", ++ client->adapter->nr, client->addr, vout_cmd, vout_cmd_set); ++ goto error; ++ ++ } ++ ++ wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); ++ mutex_unlock(&data->update_lock); ++ WB_XDPE_VERBOSE("%d-%04x: set vout cmd success, vout %ld, vout_precision: %d, vout_cmd_set: 0x%x\n", ++ client->adapter->nr, client->addr, vout, vout_precision, vout_cmd_set); ++ return count; ++error: ++ wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); ++ mutex_unlock(&data->update_lock); ++ return ret; ++} ++ ++static ssize_t xdpe_avs_vout_max_show(struct device *dev, struct device_attribute *da, char *buf) ++{ ++ struct i2c_client *client; ++ struct xdpe_data *data; ++ long vout_max; ++ ++ client = to_i2c_client(dev); ++ data = i2c_get_clientdata(client); ++ vout_max = data->vout_max; ++ return snprintf(buf, PAGE_SIZE, "%ld\n", vout_max); ++} ++ ++static ssize_t xdpe_avs_vout_max_store(struct device *dev, struct device_attribute *da, ++ const char *buf, size_t count) ++{ ++ int ret; ++ struct i2c_client *client; ++ struct xdpe_data *data; ++ long vout_max; ++ ++ client = to_i2c_client(dev); ++ ret = kstrtol(buf, 10, &vout_max); ++ if (ret) { ++ WB_XDPE_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); ++ return -EINVAL; ++ } ++ WB_XDPE_VERBOSE("%d-%04x: vout max threshold: %ld", client->adapter->nr, client->addr, ++ vout_max); ++ data = i2c_get_clientdata(client); ++ data->vout_max = vout_max; ++ return count; ++} ++ ++static ssize_t xdpe_avs_vout_min_show(struct device *dev, struct device_attribute *da, char *buf) ++{ ++ struct i2c_client *client; ++ struct xdpe_data *data; ++ long vout_min; ++ ++ client = to_i2c_client(dev); ++ data = i2c_get_clientdata(client); ++ vout_min = data->vout_min; ++ return snprintf(buf, PAGE_SIZE, "%ld\n", vout_min); ++} ++ ++static ssize_t xdpe_avs_vout_min_store(struct device *dev, struct device_attribute *da, ++ const char *buf, size_t count) ++{ ++ int ret; ++ struct i2c_client *client; ++ struct xdpe_data *data; ++ long vout_min; ++ ++ client = to_i2c_client(dev); ++ ret = kstrtol(buf, 10, &vout_min); ++ if (ret) { ++ WB_XDPE_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); ++ return -EINVAL; ++ } ++ WB_XDPE_VERBOSE("%d-%04x: vout min threshold: %ld", client->adapter->nr, client->addr, ++ vout_min); ++ data = i2c_get_clientdata(client); ++ data->vout_min = vout_min; ++ return count; ++} ++ ++/* xdpe hwmon */ ++static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO ,xdpe_power_value_show, NULL, 0x072c); ++static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO ,xdpe_power_value_show, NULL, 0x0b2c); ++static SENSOR_DEVICE_ATTR(power3_input, S_IRUGO ,xdpe_power_value_show, NULL, 0x072c0b2c); ++ ++static struct attribute *xdpe_hwmon_attrs[] = { ++ &sensor_dev_attr_power1_input.dev_attr.attr, ++ &sensor_dev_attr_power2_input.dev_attr.attr, ++ &sensor_dev_attr_power3_input.dev_attr.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(xdpe_hwmon); ++ ++/* xdpe sysfs */ ++static SENSOR_DEVICE_ATTR(avs_vout, S_IRUGO | S_IWUSR, xdpe_avs_vout_show, xdpe_avs_vout_store, 0); ++static SENSOR_DEVICE_ATTR(avs_vout_max, S_IRUGO | S_IWUSR, xdpe_avs_vout_max_show, xdpe_avs_vout_max_store, 0); ++static SENSOR_DEVICE_ATTR(avs_vout_min, S_IRUGO | S_IWUSR, xdpe_avs_vout_min_show, xdpe_avs_vout_min_store, 0); ++ ++static struct attribute *xdpe132g5c_sysfs_attrs[] = { ++ &sensor_dev_attr_avs_vout.dev_attr.attr, ++ &sensor_dev_attr_avs_vout_max.dev_attr.attr, ++ &sensor_dev_attr_avs_vout_min.dev_attr.attr, ++ NULL, ++}; ++ ++static const struct attribute_group xdpe132g5c_sysfs_attrs_group = { ++ .attrs = xdpe132g5c_sysfs_attrs, ++}; ++ ++static int xdpe132g5c_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ struct xdpe_data *data; ++ int ret; ++ ++ WB_XDPE_VERBOSE("bus: %d, addr: 0x%02x do probe.\n", client->adapter->nr, client->addr); ++ data = devm_kzalloc(&client->dev, sizeof(struct xdpe_data), GFP_KERNEL); ++ if (!data) { ++ dev_err(&client->dev, "devm_kzalloc failed.\n"); ++ return -ENOMEM; ++ } ++ ++ data->client = client; ++ i2c_set_clientdata(client, data); ++ mutex_init(&data->update_lock); ++ ++ ret = sysfs_create_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); ++ if (ret != 0) { ++ dev_err(&client->dev, "Create xdpe132g5c sysfs failed, ret: %d\n", ret); ++ return ret; ++ } ++ data->hwmon_dev = hwmon_device_register_with_groups(&client->dev, client->name, data, ++ xdpe_hwmon_groups); ++ if (IS_ERR(data->hwmon_dev)) { ++ ret = PTR_ERR(data->hwmon_dev); ++ sysfs_remove_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); ++ dev_err(&client->dev, "Failed to register xdpe hwmon device, ret: %d\n", ret); ++ return ret; ++ } ++ data->vout_max = WB_XDPE_VOUT_MAX_THRESHOLD; ++ data->vout_min = WB_XDPE_VOUT_MIN_THRESHOLD; ++ dev_info(&client->dev, "xdpe132g5c probe success\n"); ++ return 0; ++} ++ ++static int xdpe132g5c_remove(struct i2c_client *client) ++{ ++ struct xdpe_data *data; ++ ++ WB_XDPE_VERBOSE("bus: %d, addr: 0x%02x do remove\n", client->adapter->nr, client->addr); ++ data = i2c_get_clientdata(client); ++ hwmon_device_unregister(data->hwmon_dev); ++ sysfs_remove_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); ++ return 0; ++} ++ ++static const struct i2c_device_id xdpe132g5c_id[] = { ++ {"wb_xdpe132g5c", 0}, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(i2c, xdpe132g5c_id); ++ ++static const struct of_device_id __maybe_unused xdpe132g5c_of_match[] = { ++ {.compatible = "infineon,wb_xdpe132g5c"}, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, xdpe132g5c_of_match); ++ ++static struct i2c_driver wb_xdpe132g5c_driver = { ++ .driver = { ++ .name = "wb_xdpe132g5c", ++ .of_match_table = of_match_ptr(xdpe132g5c_of_match), ++ }, ++ .probe = xdpe132g5c_probe, ++ .remove = xdpe132g5c_remove, ++ .id_table = xdpe132g5c_id, ++}; ++ ++module_i2c_driver(wb_xdpe132g5c_driver); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); ++MODULE_DESCRIPTION("I2C driver for Infineon XDPE132 family"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/auto_update.py b/platform/broadcom/sonic-platform-modules-micas/common/script/auto_update.py +new file mode 100755 +index 000000000..838e64f6b +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/auto_update.py +@@ -0,0 +1,196 @@ ++#!/usr/bin/env python3 ++ ++try: ++ import os ++ import json ++ import logging ++ import sys ++ from sonic_py_common import device_info ++ from sonic_platform.platform import Platform ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") from e ++ ++PLATFORM_COMPONENTS_FILE = "platform_components.json" ++CHASSIS_KEY = "chassis" ++COMPONENT_KEY = "component" ++FIRMWARE_KEY = "firmware" ++VERSION_KEY = "version" ++chassis_component_map = {} ++current_chassis_component_map = {} ++current_chassis = Platform().get_chassis() ++ ++ ++def parse_component_section(section, component): ++ if not isinstance(component, dict): ++ logging.error("dictionary is expected: key=%s", COMPONENT_KEY) ++ return False ++ ++ if not component: ++ return False ++ ++ missing_key = None ++ chassis_component_map[section] = {} ++ ++ for key1, value1 in component.items(): ++ if not isinstance(value1, dict): ++ logging.error("dictionary is expected: key=%s", key1) ++ return False ++ ++ if value1: ++ if len(value1) < 1 or len(value1) > 3: ++ logging.error("unexpected number of records: key=%s", key1) ++ return False ++ ++ if FIRMWARE_KEY not in value1: ++ missing_key = FIRMWARE_KEY ++ break ++ ++ for key2, value2 in value1.items(): ++ if not isinstance(value2, str): ++ logging.error("string is expected: key=%s", key2) ++ return False ++ ++ chassis_component_map[section][key1] = value1 ++ ++ if missing_key is not None: ++ logging.error("\"%s\" key hasn't been found", missing_key) ++ return False ++ ++ return True ++ ++ ++def parse_chassis_section(chassis): ++ if not isinstance(chassis, dict): ++ logging.error("dictionary is expected: key=%s", CHASSIS_KEY) ++ return False ++ ++ if not chassis: ++ logging.error("dictionary is empty: key=%s", CHASSIS_KEY) ++ return False ++ ++ if len(chassis) != 1: ++ logging.error("unexpected number of records: key=%s", CHASSIS_KEY) ++ return False ++ ++ for key, value in chassis.items(): ++ if not isinstance(value, dict): ++ logging.error("dictionary is expected: key=%s", key) ++ return False ++ ++ if not value: ++ logging.error("dictionary is empty: key=%s", key) ++ return False ++ ++ if COMPONENT_KEY not in value: ++ logging.error("\"%s\" key hasn't been found", COMPONENT_KEY) ++ return False ++ ++ if len(value) != 1: ++ logging.error("unexpected number of records: key=%s", key) ++ return False ++ ++ return parse_component_section(key, value[COMPONENT_KEY]) ++ ++ return False ++ ++ ++def get_platform_components_path(): ++ PLATFORM_COMPONENTS_PATH_TEMPLATE = "/usr/share/sonic/device/{}/{}" ++ PLATFORM_COMPONENTS_FILE_PATH = PLATFORM_COMPONENTS_PATH_TEMPLATE.format( ++ device_info.get_platform(), PLATFORM_COMPONENTS_FILE) ++ return PLATFORM_COMPONENTS_FILE_PATH ++ ++ ++def parse_platform_components(): ++ platform_components_path = get_platform_components_path() ++ with open(platform_components_path) as platform_components: ++ data = json.load(platform_components) ++ ++ if not isinstance(data, dict): ++ logging.error("dictionary is expected: key=root") ++ return False ++ ++ if not data: ++ logging.error("dictionary is empty: key=root") ++ return False ++ ++ if CHASSIS_KEY not in data: ++ logging.error("\"%s\" key hasn't been found", CHASSIS_KEY) ++ return False ++ ++ return parse_chassis_section(data[CHASSIS_KEY]) ++ ++ ++def get_current_chassis_component_map(): ++ chassis_name = current_chassis.get_name() ++ current_chassis_component_map[chassis_name] = {} ++ ++ component_list = current_chassis.get_all_components() ++ for component in component_list: ++ component_name = component.get_name() ++ current_chassis_component_map[chassis_name][component_name] = component ++ ++ return current_chassis_component_map ++ ++ ++def get_upgrade_dict(): ++ upgrade_dict = {} ++ firmware_version_current = "" ++ firmware_version_available = "" ++ ++ if not parse_platform_components(): ++ logging.error("Reading platform_components.json i, ion exception") ++ sys.exit(1) ++ ++ if not get_current_chassis_component_map(): ++ logging.error("Reading firmware i, ion from the driver is abnormal") ++ sys.exit(1) ++ ++ chassis_name = current_chassis.get_name() ++ diff_keys = set(chassis_component_map.keys()) ^ set(current_chassis_component_map.keys()) ++ if diff_keys: ++ logging.error("%s names mismatch: keys=%s", chassis_name, str(list(diff_keys))) ++ return None ++ ++ for chassis_name, component_map in current_chassis_component_map.items(): ++ for component_name, component in component_map.items(): ++ firmware_version_current = component.get_firmware_version() ++ if component_name in chassis_component_map[chassis_name]: ++ firmware_version_available = chassis_component_map[chassis_name][component_name][VERSION_KEY] ++ else: ++ logging.warning("can't find %s in %s", component_name, PLATFORM_COMPONENTS_FILE) ++ break ++ ++ if not os.path.exists(chassis_component_map[chassis_name][component_name][FIRMWARE_KEY]): ++ logging.error("%s does not exist", chassis_component_map[chassis_name][component_name][FIRMWARE_KEY]) ++ break ++ ++ if firmware_version_available != firmware_version_current: ++ upgrade_dict[component_name] = chassis_component_map[chassis_name][component_name][FIRMWARE_KEY] ++ ++ return upgrade_dict ++ ++ ++def auto_upgrade(): ++ upgrade_result_dict = {} ++ chassis_name = current_chassis.get_name() ++ ++ upgrade_dict = get_upgrade_dict() ++ if not upgrade_dict: ++ logging.info("No firmware found for automatic upgrade") ++ return None ++ ++ component_map = current_chassis_component_map[chassis_name] ++ for value, path in upgrade_dict.items(): ++ status = component_map[value].install_firmware(path) ++ if status: ++ upgrade_result_dict[value] = "success" ++ logging.info("%s Upgrade Success", value) ++ else: ++ upgrade_result_dict[value] = "failed" ++ logging.error("%s Upgrade Failed", value) ++ return upgrade_result_dict ++ ++ ++if __name__ == '__main__': ++ auto_upgrade() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/avscontrol.py b/platform/broadcom/sonic-platform-modules-micas/common/script/avscontrol.py +new file mode 100755 +index 000000000..a0a2ccaac +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/avscontrol.py +@@ -0,0 +1,203 @@ ++#!/usr/bin/env python3 ++import sys ++import os ++import time ++import syslog ++import glob ++import click ++from platform_config import MAC_DEFAULT_PARAM ++from platform_util import getSdkReg, write_sysfs, get_value, get_format_value ++ ++ ++AVSCTROL_DEBUG_FILE = "/etc/.avscontrol_debug_flag" ++ ++AVSCTROLERROR = 1 ++AVSCTROLDEBUG = 2 ++ ++debuglevel = 0 ++ ++CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} ++ ++ ++class AliasedGroup(click.Group): ++ def get_command(self, ctx, cmd_name): ++ rv = click.Group.get_command(self, ctx, cmd_name) ++ if rv is not None: ++ return rv ++ matches = [x for x in self.list_commands(ctx) ++ if x.startswith(cmd_name)] ++ if not matches: ++ return None ++ if len(matches) == 1: ++ return click.Group.get_command(self, ctx, matches[0]) ++ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) ++ return None ++ ++ ++def avscontrol_debug(s): ++ if AVSCTROLDEBUG & debuglevel: ++ syslog.openlog("AVSCONTROL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def avscontrol_error(s): ++ if AVSCTROLERROR & debuglevel: ++ syslog.openlog("AVSCONTROL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++def avserror(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("AVSCONTROL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++def avsinfo(s): ++ syslog.openlog("AVSCONTROL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_INFO, s) ++ ++ ++def debug_init(): ++ global debuglevel ++ if os.path.exists(AVSCTROL_DEBUG_FILE): ++ debuglevel = debuglevel | AVSCTROLDEBUG | AVSCTROLERROR ++ else: ++ debuglevel = debuglevel & ~(AVSCTROLDEBUG | AVSCTROLERROR) ++ ++ ++def set_avs_value_sysfs(conf, dcdc_value): ++ msg = "" ++ formula = conf.get("formula", None) ++ loc = conf.get("loc") ++ locations = glob.glob(loc) ++ if len(locations) == 0: ++ msg = "avs sysfs loc: %s not found" % loc ++ avscontrol_error(msg) ++ return False, msg ++ sysfs_loc = locations[0] ++ avscontrol_debug("set_avs_value_sysfs, loc: %s, origin dcdc value: %s, formula: %s" % ++ (sysfs_loc, dcdc_value, formula)) ++ if formula is not None: ++ dcdc_value = get_format_value(formula % (dcdc_value)) ++ wr_val = str(dcdc_value) ++ avscontrol_debug("set_avs_value_sysfs, write val: %s" % wr_val) ++ ret, log = write_sysfs(sysfs_loc, wr_val) ++ if ret is False: ++ msg = "set_avs_value_sysfs failed, msg: %s" % log ++ avscontrol_error(msg) ++ return ret, msg ++ ++ ++def set_avs_value(avs_conf, dcdc_value): ++ set_avs_way = avs_conf.get("set_avs", {}).get("gettype") ++ if set_avs_way != "sysfs": ++ msg = "unsupport set avs value type: %s" % set_avs_way ++ avscontrol_error(msg) ++ return False, msg ++ ret, msg = set_avs_value_sysfs(avs_conf["set_avs"], dcdc_value) ++ return ret, msg ++ ++ ++def get_dcdc_value(avs_conf, rov_value): ++ msg = "" ++ mac_avs_param = avs_conf.get("mac_avs_param", {}) ++ if rov_value not in mac_avs_param.keys(): ++ if avs_conf["type"] == 0: ++ msg = "VID:0x%x out of range, voltage regulate stop" % rov_value ++ avsinfo(msg) ++ return False, msg ++ dcdc_value = mac_avs_param[avs_conf["default"]] ++ avsinfo("VID:0x%x out of range, use default VID:0x%x" % (rov_value, dcdc_value)) ++ else: ++ dcdc_value = mac_avs_param[rov_value] ++ return True, dcdc_value ++ ++ ++def get_rov_value_cpld(avs_conf): ++ cpld_avs_config = avs_conf["cpld_avs"] ++ return get_value(cpld_avs_config) ++ ++ ++def get_rov_value_sdk(avs_conf): ++ name = avs_conf["sdkreg"] ++ ret, status = getSdkReg(name) ++ if ret is False: ++ return False, status ++ status = int(status, 16) ++ # shift operation ++ if avs_conf["sdktype"] != 0: ++ status = (status >> avs_conf["macregloc"]) & avs_conf["mask"] ++ macavs = status ++ return True, macavs ++ ++ ++def doAvsCtrol_single(avs_conf): ++ try: ++ avs_name = avs_conf.get("name") ++ rov_source = avs_conf["rov_source"] ++ if rov_source == 0: ++ ret, rov_value = get_rov_value_cpld(avs_conf) # get rov from cpld reg ++ else: ++ ret, rov_value = get_rov_value_sdk(avs_conf) # get rov from sdk reg ++ if ret is False: ++ msg = "%s get rov_value failed, msg: %s" % (avs_name, rov_value) ++ avscontrol_error(msg) ++ return False, msg ++ avscontrol_debug("%s rov_value: 0x%x" % (avs_name, rov_value)) ++ ret, dcdc_value = get_dcdc_value(avs_conf, rov_value) ++ if ret is False: ++ msg = "%s get output voltage value failed, msg: %s" % (avs_name, dcdc_value) ++ avscontrol_error(msg) ++ return False, msg ++ ret, msg = set_avs_value(avs_conf, dcdc_value) ++ return ret, msg ++ except Exception as e: ++ msg = "%s avscontrol raise exception, msg: %s" % (avs_name, str(e)) ++ avscontrol_error(msg) ++ return False, msg ++ ++ ++def doAvsCtrol(avs_conf): ++ retry_time = avs_conf.get("retry", 10) ++ for i in range(retry_time): ++ debug_init() ++ ret, log = doAvsCtrol_single(avs_conf) ++ if ret is True: ++ return True, log ++ time.sleep(1) ++ return False, log ++ ++ ++def run(): ++ # wait 30s for device steady ++ time.sleep(30) ++ errcnt = 0 ++ msg = "" ++ for item in MAC_DEFAULT_PARAM: ++ status, log = doAvsCtrol(item) ++ if status is False: ++ errcnt += 1 ++ msg += log ++ ++ if errcnt == 0: ++ avsinfo("%%AVSCONTROL success") ++ sys.exit(0) ++ avserror("%%DEV_MONITOR-AVS: MAC Voltage adjust failed.") ++ avserror("%%DEV_MONITOR-AVS: errmsg: %s" % msg) ++ sys.exit(1) ++ ++ ++@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) ++def main(): ++ '''device operator''' ++ ++ ++@main.command() ++def start(): ++ '''start AVS control''' ++ avsinfo("%%AVSCONTROL start") ++ run() ++ ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/dev_monitor.py b/platform/broadcom/sonic-platform-modules-micas/common/script/dev_monitor.py +new file mode 100755 +index 000000000..e13377b80 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/dev_monitor.py +@@ -0,0 +1,303 @@ ++#!/usr/bin/env python3 ++import sys ++import os ++import time ++import syslog ++import traceback ++import click ++from platform_config import DEV_MONITOR_PARAM ++from platform_util import io_rd, wbi2cget ++ ++ ++CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} ++ ++ ++class AliasedGroup(click.Group): ++ def get_command(self, ctx, cmd_name): ++ rv = click.Group.get_command(self, ctx, cmd_name) ++ if rv is not None: ++ return rv ++ matches = [x for x in self.list_commands(ctx) ++ if x.startswith(cmd_name)] ++ if not matches: ++ return None ++ if len(matches) == 1: ++ return click.Group.get_command(self, ctx, matches[0]) ++ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) ++ return None ++ ++ ++DEVMONITOR_DEBUG_FILE = "/etc/.devmonitor_debug_flag" ++ ++debuglevel = 0 ++ ++ ++def debug_init(): ++ global debuglevel ++ if os.path.exists(DEVMONITOR_DEBUG_FILE): ++ debuglevel = 1 ++ else: ++ debuglevel = 0 ++ ++ ++def devwarninglog(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("DEVMONITOR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_WARNING, s) ++ ++ ++def devcriticallog(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("DEVMONITOR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_CRIT, s) ++ ++ ++def deverror(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("DEVMONITOR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++def devinfo(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("DEVMONITOR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_INFO, s) ++ ++ ++def devdebuglog(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ if debuglevel == 1: ++ syslog.openlog("DEVMONITOR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++class DevMonitor(): ++ ++ def getpresentstatus(self, param): ++ try: ++ ret = {} ++ ret["status"] = '' ++ gettype = param.get('gettype') ++ presentbit = param.get('presentbit') ++ okval = param.get('okval') ++ if gettype == "io": ++ io_addr = param.get('io_addr') ++ val = io_rd(io_addr) ++ if val is None: ++ ret["status"] = "NOT OK" ++ return ret ++ retval = val ++ else: ++ bus = param.get('bus') ++ loc = param.get('loc') ++ offset = param.get('offset') ++ ind, val = wbi2cget(bus, loc, offset) ++ if ind is not True: ++ ret["status"] = "NOT OK" ++ return ret ++ retval = val ++ val_t = (int(retval, 16) & (1 << presentbit)) >> presentbit ++ if val_t != okval: ++ ret["status"] = "ABSENT" ++ else: ++ ret["status"] = "PRESENT" ++ except Exception as e: ++ ret["status"] = "NOT OK" ++ deverror("getpresentstatus error") ++ deverror(str(e)) ++ return ret ++ ++ def removeDev(self, bus, loc): ++ cmd = "echo 0x%02x > /sys/bus/i2c/devices/i2c-%d/delete_device" % (loc, bus) ++ devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) ++ if os.path.exists(devpath): ++ os.system(cmd) ++ ++ def addDev(self, name, bus, loc): ++ if name == "lm75": ++ time.sleep(0.1) ++ cmd = "echo %s 0x%02x > /sys/bus/i2c/devices/i2c-%d/new_device" % (name, loc, bus) ++ devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) ++ if os.path.exists(devpath) is False: ++ os.system(cmd) ++ ++ def checkattr(self, bus, loc, attr): ++ try: ++ attrpath = "/sys/bus/i2c/devices/%d-%04x/%s" % (bus, loc, attr) ++ if os.path.exists(attrpath): ++ return True ++ except Exception as e: ++ deverror("checkattr error") ++ deverror(str(e)) ++ return False ++ ++ def monitor(self, ret): ++ totalerr = 0 ++ for item in ret: ++ try: ++ name = item.get('name') ++ itemattr = '%sattr' % name ++ val_t = getattr(DevMonitor, itemattr, None) ++ if val_t == 'OK': ++ continue ++ present = item.get('present', None) ++ devices = item.get('device') ++ err_t = 0 ++ for item_dev in devices: ++ item_devattr = '%s' % (item_dev['id']) ++ val_t = getattr(DevMonitor, item_devattr, None) ++ if val_t == 'OK': ++ continue ++ devname = item_dev.get('name') ++ bus = item_dev.get('bus') ++ loc = item_dev.get('loc') ++ attr = item_dev.get('attr') ++ if self.checkattr(bus, loc, attr) is False: ++ err_t -= 1 ++ setattr(DevMonitor, item_devattr, 'NOT OK') ++ if present is not None: ++ presentstatus = self.getpresentstatus(present) ++ devdebuglog("%s present status:%s" % (name, presentstatus.get('status'))) ++ if presentstatus.get('status') == 'PRESENT': ++ self.removeDev(bus, loc) ++ time.sleep(0.1) ++ self.addDev(devname, bus, loc) ++ else: ++ self.removeDev(bus, loc) ++ time.sleep(0.1) ++ self.addDev(devname, bus, loc) ++ else: ++ setattr(DevMonitor, item_devattr, 'OK') ++ val_t = getattr(DevMonitor, item_devattr, None) ++ devdebuglog("%s status %s" % (item_devattr, val_t)) ++ if err_t == 0: ++ setattr(DevMonitor, itemattr, 'OK') ++ else: ++ totalerr -= 1 ++ setattr(DevMonitor, itemattr, 'NOT OK') ++ val_t = getattr(DevMonitor, itemattr, None) ++ devdebuglog("%s status %s" % (itemattr, val_t)) ++ except Exception as e: ++ totalerr -= 1 ++ deverror("monitor error") ++ deverror(str(e)) ++ return totalerr ++ ++ def psusmonitor(self): ++ psus_conf = DEV_MONITOR_PARAM.get('psus') ++ if psus_conf is None: ++ return 0 ++ psusattr = 'psusattr' ++ val_t = getattr(DevMonitor, psusattr, None) ++ if val_t == 'OK': ++ return 0 ++ ret = self.monitor(psus_conf) ++ if ret == 0: ++ setattr(DevMonitor, psusattr, 'OK') ++ else: ++ setattr(DevMonitor, psusattr, 'NOT OK') ++ val_t = getattr(DevMonitor, psusattr, None) ++ devdebuglog("psusattr:value:%s" % (val_t)) ++ return ret ++ ++ def fansmonitor(self): ++ fans_conf = DEV_MONITOR_PARAM.get('fans') ++ if fans_conf is None: ++ return 0 ++ fansattr = 'fansattr' ++ val_t = getattr(DevMonitor, fansattr, None) ++ if val_t == 'OK': ++ return 0 ++ ret = self.monitor(fans_conf) ++ if ret == 0: ++ setattr(DevMonitor, fansattr, 'OK') ++ else: ++ setattr(DevMonitor, fansattr, 'NOT OK') ++ val_t = getattr(DevMonitor, fansattr, None) ++ devdebuglog("fansattr:value:%s" % (val_t)) ++ return ret ++ ++ def slotsmonitor(self): ++ slots_conf = DEV_MONITOR_PARAM.get('slots') ++ if slots_conf is None: ++ return 0 ++ slotsattr = 'slotsattr' ++ val_t = getattr(DevMonitor, slotsattr, None) ++ if val_t == 'OK': ++ return 0 ++ ret = self.monitor(slots_conf) ++ if ret == 0: ++ setattr(DevMonitor, slotsattr, 'OK') ++ else: ++ setattr(DevMonitor, slotsattr, 'NOT OK') ++ val_t = getattr(DevMonitor, slotsattr, None) ++ devdebuglog("slotsattr:value:%s" % (val_t)) ++ return ret ++ ++ def othersmonitor(self): ++ others_conf = DEV_MONITOR_PARAM.get('others') ++ if others_conf is None: ++ return 0 ++ othersattr = 'othersattr' ++ val_t = getattr(DevMonitor, othersattr, None) ++ if val_t == 'OK': ++ return 0 ++ ret = self.monitor(others_conf) ++ if ret == 0: ++ setattr(DevMonitor, othersattr, 'OK') ++ else: ++ setattr(DevMonitor, othersattr, 'NOT OK') ++ val_t = getattr(DevMonitor, othersattr, None) ++ devdebuglog("othersattr:value:%s" % (val_t)) ++ return ret ++ ++ ++def doDevMonitor(devMonitor): ++ ret_t = 0 ++ ret_t += devMonitor.psusmonitor() ++ ret_t += devMonitor.fansmonitor() ++ ret_t += devMonitor.slotsmonitor() ++ ret_t += devMonitor.othersmonitor() ++ return ret_t ++ ++ ++def run(interval, devMonitor): ++ # devMonitor.devattrinit() ++ while True: ++ try: ++ debug_init() ++ ret = doDevMonitor(devMonitor) ++ except Exception as e: ++ traceback.print_exc() ++ deverror(str(e)) ++ ret = -1 ++ if ret == 0: ++ time.sleep(5) ++ devinfo("dev_monitor finished!") ++ sys.exit(0) ++ time.sleep(interval) ++ ++ ++@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) ++def main(): ++ '''device operator''' ++ ++ ++@main.command() ++def start(): ++ '''start device monitor''' ++ devinfo("dev_monitor start") ++ devMonitor = DevMonitor() ++ interval = DEV_MONITOR_PARAM.get('polling_time', 10) ++ run(interval, devMonitor) ++ ++ ++@main.command() ++def stop(): ++ '''stop device monitor ''' ++ devinfo("stop") ++ ++ ++# device_i2c operation ++if __name__ == '__main__': ++ main() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/drv_update.py b/platform/broadcom/sonic-platform-modules-micas/common/script/drv_update.py +new file mode 100755 +index 000000000..9de4911e8 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/drv_update.py +@@ -0,0 +1,152 @@ ++#!/usr/bin/env python ++# -*- coding: UTF-8 -*- ++import syslog ++import os ++import shutil ++from platform_config import DRVIER_UPDATE_CONF ++from platform_util import exec_os_cmd ++ ++ ++DRV_UPDATE_DEBUG_FILE = "/etc/.drv_update_debug_flag" ++ ++DRVUPDATEERROR = 1 ++DRVUPDATEDEBUG = 2 ++debuglevel = 0 ++ ++ ++def drv_update_debug(s): ++ if DRVUPDATEDEBUG & debuglevel: ++ syslog.openlog("DRV_UPDATE", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_INFO, s) ++ ++ ++def drv_update_error(s): ++ if DRVUPDATEERROR & debuglevel: ++ syslog.openlog("DRV_UPDATE", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++def drv_update_info(s): ++ syslog.openlog("DRV_UPDATE", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_NOTICE, s) ++ ++def debug_init(): ++ global debuglevel ++ try: ++ with open(DRV_UPDATE_DEBUG_FILE, "r") as fd: ++ value = fd.read() ++ debuglevel = int(value) ++ except Exception: ++ debuglevel = 0 ++ ++ ++def get_driver_md5sum(drv_path): ++ status, output = exec_os_cmd("md5sum %s" % drv_path) ++ if status or len(output) == 0: ++ return False, output ++ drv_md5 = output.strip().split(" ")[0] ++ return True, drv_md5 ++ ++ ++def do_driver_replace(src_file, target_file): ++ # Backup target file ++ src_file_dir = os.path.dirname(src_file) ++ target_file_name = os.path.basename(target_file) ++ drv_update_debug("src_file: %s, src_file_dir: %s" % (src_file, src_file_dir)) ++ drv_update_debug("target_file: %s, target_file_name: %s" % (target_file, target_file_name)) ++ try: ++ shutil.copyfile(target_file, "%s/%s.bak" % (src_file_dir, target_file_name)) ++ shutil.copyfile(src_file, target_file) ++ return True ++ except Exception as e: ++ drv_update_error("do_driver_replace error, msg: %s" % str(e)) ++ return False ++ ++ ++def doDrvUpdate(): ++ reboot_flag = DRVIER_UPDATE_CONF.get("reboot_flag", 0) ++ drv_list = DRVIER_UPDATE_CONF.get("drv_list", []) ++ err_cnt = 0 ++ update_initramfs_flag = 0 ++ # get kernel version ++ status, output = exec_os_cmd("uname -r") ++ if status or len(output) == 0: ++ drv_update_error("Failed to get kernel version, status: %s, log: %s" % (status, output)) ++ return ++ kversion = output.strip() ++ drv_update_debug("kernel version: %s" % kversion) ++ for item in drv_list: ++ try: ++ source_drv = item.get("source") ++ target_drv = item.get("target") ++ judge_flag = item.get("judge_flag") ++ if source_drv is None or target_drv is None or judge_flag is None: ++ drv_update_error("driver update config error, source_drv: %s, target_drv: %s, judge_file: %s" % (source_drv, target_drv, judge_flag)) ++ err_cnt += 1 ++ continue ++ drv_update_debug("source_drv: %s, target_drv: %s, judge_flag: %s" % (source_drv, target_drv, judge_flag)) ++ ++ # Check if the current driver is expected ++ if os.path.exists(judge_flag): ++ drv_update_debug("The current driver is expected, do nothing") ++ continue ++ ++ # get source driver file path ++ source_drv_path = "/lib/modules/%s/%s" % (kversion, source_drv) ++ drv_update_debug("source driver: %s, file path: %s" % (source_drv, source_drv_path)) ++ ++ # get target driver file path ++ target_drv_path = "/lib/modules/%s/%s" % (kversion, target_drv) ++ drv_update_debug("target driver: %s, file path: %s" % (target_drv, target_drv_path)) ++ ++ # get source driver md5sum ++ status, source_drv_md5 = get_driver_md5sum(source_drv_path) ++ if status is False: ++ msg = "get %s md5sum failed msg: %s" % (source_drv_path, source_drv_md5) ++ drv_update_error(msg) ++ err_cnt += 1 ++ continue ++ drv_update_debug("source driver file path: %s, md5sum: %s" % (source_drv_path, source_drv_md5)) ++ ++ # get target driver md5sum ++ status, target_drv_md5 = get_driver_md5sum(target_drv_path) ++ if status is False: ++ msg = "get %s md5sum failed msg: %s" % (target_drv_path, target_drv_md5) ++ drv_update_error(msg) ++ err_cnt += 1 ++ continue ++ drv_update_debug("target driver file path: %s, md5sum: %s" % (target_drv_path, target_drv_md5)) ++ ++ if source_drv_md5 != target_drv_md5: ++ drv_update_debug("source_drv_md5 not equal to target_drv_md5, try to use source driver replace target driver") ++ status = do_driver_replace(source_drv_path, target_drv_path) ++ if status is False: ++ err_cnt += 1 ++ continue ++ else: ++ drv_update_debug("source_drv_md5 equal to target_drv_md5, do nothing") ++ ++ drv_update_debug("Driver replacement completed, set update_initramfs_flag") ++ update_initramfs_flag = 1 ++ ++ except Exception as e: ++ err_cnt += 1 ++ drv_update_error(str(e)) ++ ++ if update_initramfs_flag == 1: ++ drv_update_debug("starting to update initramfs") ++ os.system("update-initramfs -u") ++ drv_update_debug("update initramfs finish") ++ ++ os.system("sync") ++ if update_initramfs_flag == 1 and err_cnt == 0 and reboot_flag == 1: ++ reboot_log = "%DRV_UPDATE-5-REBOOT: Update initramfs is completed, restarting the system to take effect." ++ reboot_log_cmd = "echo '%s' > /dev/ttyS0" % reboot_log ++ exec_os_cmd(reboot_log_cmd) ++ drv_update_info(reboot_log) ++ os.system("/sbin/reboot") ++ return ++ ++if __name__ == '__main__': ++ debug_init() ++ doDrvUpdate() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/generate_airflow.py b/platform/broadcom/sonic-platform-modules-micas/common/script/generate_airflow.py +new file mode 100755 +index 000000000..89d3e7233 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/generate_airflow.py +@@ -0,0 +1,254 @@ ++#!/usr/bin/env python ++# -*- coding: UTF-8 -*- ++''' ++generate board air flow according to fan and psu air flow ++write resulet to AIRFLOW_RESULT_FILE, file format: ++{ ++ "FAN1": { ++ "model":"M1HFAN I-F", ++ "airflow":"intake", ++ }, ++ "PSU1": { ++ "model":"CSU550AP-3-500", ++ "airflow":"intake", ++ }, ++ "board":"intake" ++} ++''' ++import os ++import syslog ++import json ++from platform_config import AIR_FLOW_CONF, AIRFLOW_RESULT_FILE ++from platform_util import dev_file_read, byteTostr ++from eepromutil.fru import ipmifru ++from eepromutil.cust_fru import CustFru ++from eepromutil.fantlv import fan_tlv ++ ++ ++AIRFLOW_DEBUG_FILE = "/etc/.airflow_debug_flag" ++ ++AIRFLOWERROR = 1 ++AIRFLOWDEBUG = 2 ++ ++debuglevel = 0 ++ ++ ++def airflow_info(s): ++ syslog.openlog("AIRFLOW", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_INFO, s) ++ ++ ++def airflow_error(s): ++ syslog.openlog("AIRFLOW", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++def airflow_debug(s): ++ if AIRFLOWDEBUG & debuglevel: ++ syslog.openlog("AIRFLOW", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def airflow_debug_error(s): ++ if AIRFLOWERROR & debuglevel: ++ syslog.openlog("AIRFLOW", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++def debug_init(): ++ global debuglevel ++ try: ++ with open(AIRFLOW_DEBUG_FILE, "r") as fd: ++ value = fd.read() ++ debuglevel = int(value) ++ except Exception: ++ debuglevel = 0 ++ ++ ++def get_model_fru(device, eeprom): ++ try: ++ fru = ipmifru() ++ fru.decodeBin(eeprom) ++ dev_name = device.get("name") ++ area = device.get("area") ++ field = device.get("field") ++ tmp_area = getattr(fru, area, None) ++ if tmp_area is None: ++ msg = "%s fru %s area config error" % (dev_name, area) ++ return False, msg ++ model = getattr(tmp_area, field, None) ++ if model is None: ++ msg = "%s get model error, area: %s, field: %s" % (dev_name, area, field) ++ return False, msg ++ airflow_debug("%s get model success, model: %s" % (dev_name, model)) ++ return True, model ++ except Exception as e: ++ return False, str(e) ++ ++def get_model_custfru(device, eeprom): ++ try: ++ custfru = CustFru() ++ custfru.decode(eeprom) ++ dev_name = device.get("name") ++ field = device.get("field") ++ model = getattr(custfru, field, None) ++ if model is None: ++ msg = "%s get model error, field: %s" % (dev_name, field) ++ return False, msg ++ airflow_debug("%s get model success, model: %s" % (dev_name, model)) ++ return True, model ++ except Exception as e: ++ return False, str(e) ++ ++ ++def get_model_fantlv(device, eeprom): ++ try: ++ dev_name = device.get("name") ++ tlv = fan_tlv() ++ rets = tlv.decode(eeprom) ++ if len(rets) == 0: ++ msg = "%s decode fantlv eeprom info error" % dev_name ++ return False, msg ++ ++ field = device.get("field") ++ for fantlv_item in rets: ++ if fantlv_item.get("name") == field: ++ return True, fantlv_item["value"] ++ msg = "%s get model error, field: %s not found" % (dev_name, field) ++ return False, msg ++ except Exception as e: ++ return False, str(e) ++ ++ ++def get_device_modele(device): ++ e2_type = device.get("e2_type") ++ dev_name = device.get("name") ++ support_e2_type = ("fru", "fantlv", "custfru") ++ if e2_type not in support_e2_type: ++ msg = "%s unsupport e2_type: %s" % (dev_name, e2_type) ++ return False, msg ++ ++ e2_path = device.get("e2_path") ++ e2_size = device.get("e2_size", 256) ++ ret, binval_bytes = dev_file_read(e2_path, 0, e2_size) ++ if ret is False: ++ msg = "%s eeprom read error, eeprom path: %s, msg: %s" % (dev_name, e2_path, binval_bytes) ++ return False, msg ++ ++ binval = byteTostr(binval_bytes) ++ if e2_type == "fru": ++ return get_model_fru(device, binval) ++ if e2_type == "custfru": ++ return get_model_custfru(device, binval) ++ return get_model_fantlv(device, binval) ++ ++ ++def get_board_air_flow(fan_intake_num, fan_exhaust_num, psu_intake_num, psu_exhaust_num): ++ airflow_debug("fan_intake_num: %d, fan_exhaust_num: %d, psu_intake_num: %d, psu_exhaust_num: %d" % ++ (fan_intake_num, fan_exhaust_num, psu_intake_num, psu_exhaust_num)) ++ ++ if fan_intake_num == 0 and fan_exhaust_num == 0 and psu_intake_num == 0 and psu_exhaust_num == 0: ++ airflow_error("get all fans and psus air flow failed") ++ return "N/A" ++ ++ if fan_intake_num > fan_exhaust_num: ++ airflow_debug("fan intake number more than fan exhaust number, set board air flow: intake") ++ return "intake" ++ ++ if fan_intake_num < fan_exhaust_num: ++ airflow_debug("fan intake number less than fan exhaust number, set board air flow: exhaust") ++ return "exhaust" ++ ++ airflow_debug("fan intake number equal to exhaust number, check psu air flow") ++ ++ if psu_intake_num > psu_exhaust_num: ++ airflow_debug("psu intake number more than psu exhaust number, set board air flow: intake") ++ return "intake" ++ ++ if psu_intake_num < psu_exhaust_num: ++ airflow_debug("psu intake number less than psu exhaust number, set board air flow: exhaust") ++ return "exhaust" ++ ++ airflow_debug("fan and psu intake and exhaust number equal, return intake") ++ return "intake" ++ ++ ++def generate_airflow(): ++ fan_intake_list = [] ++ fan_exhaust_list = [] ++ psu_intake_list = [] ++ psu_exhaust_list = [] ++ ret = {} ++ fans = AIR_FLOW_CONF.get("fans", []) ++ psus = AIR_FLOW_CONF.get("psus", []) ++ ++ for fan in fans: ++ dev_name = fan.get("name") ++ air_flow = "N/A" ++ status, model = get_device_modele(fan) ++ if status is False: ++ ret[dev_name] = {"model": "N/A", "airflow": "N/A"} ++ airflow_error(model) ++ continue ++ model = model.strip() ++ airflowconifg = AIR_FLOW_CONF[fan["decode"]] ++ for key, value in airflowconifg.items(): ++ if model in value: ++ air_flow = key ++ ret[dev_name] = {"model": model, "airflow": air_flow} ++ airflow_debug("%s model: %s, airflow: %s" % (dev_name, model, air_flow)) ++ if air_flow == "intake": ++ fan_intake_list.append(fan.get("name")) ++ elif air_flow == "exhaust": ++ fan_exhaust_list.append(fan.get("name")) ++ ++ airflow_debug("fan_intake_list: %s" % fan_intake_list) ++ airflow_debug("fan_exhaust_list: %s" % fan_exhaust_list) ++ ++ for psu in psus: ++ dev_name = psu.get("name") ++ air_flow = "N/A" ++ status, model = get_device_modele(psu) ++ if status is False: ++ ret[dev_name] = {"model": "N/A", "airflow": "N/A"} ++ airflow_error(model) ++ continue ++ model = model.strip() ++ airflowconifg = AIR_FLOW_CONF[psu["decode"]] ++ for key, value in airflowconifg.items(): ++ if model in value: ++ air_flow = key ++ ret[dev_name] = {"model": model, "airflow": air_flow} ++ airflow_debug("%s model: %s, airflow: %s" % (dev_name, model, air_flow)) ++ if air_flow == "intake": ++ psu_intake_list.append(psu.get("name")) ++ elif air_flow == "exhaust": ++ psu_exhaust_list.append(psu.get("name")) ++ ++ airflow_debug("psu_intake_list: %s" % psu_intake_list) ++ airflow_debug("psu_exhaust_list: %s" % psu_exhaust_list) ++ ++ fan_intake_num = len(fan_intake_list) ++ fan_exhaust_num = len(fan_exhaust_list) ++ psu_intake_num = len(psu_intake_list) ++ psu_exhaust_num = len(psu_exhaust_list) ++ ++ board_airflow = get_board_air_flow(fan_intake_num, fan_exhaust_num, psu_intake_num, psu_exhaust_num) ++ airflow_debug("board_airflow: %s" % board_airflow) ++ ret["board"] = board_airflow ++ ret_json = json.dumps(ret, ensure_ascii=False, indent=4) ++ ++ out_file_dir = os.path.dirname(AIRFLOW_RESULT_FILE) ++ if len(out_file_dir) != 0: ++ cmd = "mkdir -p %s" % out_file_dir ++ os.system(cmd) ++ os.system("sync") ++ with open(AIRFLOW_RESULT_FILE, "w") as fd: ++ fd.write(ret_json) ++ os.system("sync") ++ ++ ++if __name__ == '__main__': ++ debug_init() ++ airflow_debug("enter main") ++ generate_airflow() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/hal_fanctrl.py b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_fanctrl.py +new file mode 100755 +index 000000000..7722b111f +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_fanctrl.py +@@ -0,0 +1,1135 @@ ++#!/usr/bin/env python3 ++import os ++import subprocess ++import time ++import syslog ++import traceback ++from plat_hal.interface import interface ++from plat_hal.baseutil import baseutil ++from algorithm.pid import pid ++from algorithm.openloop import openloop ++from algorithm.hysteresis import hysteresis ++ ++ ++SWITCH_TEMP = "SWITCH_TEMP" ++INLET_TEMP = "INLET_TEMP" ++BOARD_TEMP = "BOARD_TEMP" ++OUTLET_TEMP = "OUTLET_TEMP" ++CPU_TEMP = "CPU_TEMP" ++ ++FANCTROL_DEBUG_FILE = "/etc/.fancontrol_debug_flag" ++# coordination with REBOOT_CAUSE_PARA ++OTP_SWITCH_REBOOT_JUDGE_FILE = "/etc/.otp_reboot_flag" ++OTP_OTHER_REBOOT_JUDGE_FILE = OTP_SWITCH_REBOOT_JUDGE_FILE ++ ++FANCTROLERROR = 1 ++FANCTROLDEBUG = 2 ++FANAIRFLOWDEBUG = 4 ++ ++debuglevel = 0 ++ ++F2B_AIR_FLOW = "intake" ++B2F_AIR_FLOW = "exhaust" ++ONIE_E2_NAME = "ONIE_E2" ++ ++TEMP_REBOOT_CRIT_SWITCH_FLAG = 1 ++TEMP_REBOOT_CRIT_OTHER_FLAG = 2 ++ ++ ++def fancontrol_debug(s): ++ if FANCTROLDEBUG & debuglevel: ++ syslog.openlog("FANCONTROL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def fancontrol_error(s): ++ if FANCTROLERROR & debuglevel: ++ syslog.openlog("FANCONTROL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++def fanairflow_debug(s): ++ if FANAIRFLOWDEBUG & debuglevel: ++ syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def fancontrol_warn(s): ++ syslog.openlog("FANCONTROL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_WARNING, s) ++ ++ ++def fancontrol_crit(s): ++ syslog.openlog("FANCONTROL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_CRIT, s) ++ ++ ++def fancontrol_alert(s): ++ syslog.openlog("FANCONTROL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_ALERT, s) ++ ++ ++def fancontrol_emerg(s): ++ syslog.openlog("FANCONTROL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_EMERG, s) ++ ++ ++def exec_os_cmd(cmd): ++ status, output = subprocess.getstatusoutput(cmd) ++ if status: ++ print(output) ++ return status, output ++ ++ ++def debug_init(): ++ global debuglevel ++ try: ++ with open(FANCTROL_DEBUG_FILE, "r") as fd: ++ value = fd.read() ++ debuglevel = int(value) ++ except Exception: ++ debuglevel = 0 ++ ++ ++error_temp = -9999 # get temp error ++invalid_temp = -10000 # get temp invalid ++PRE_FAN_NOK_UNKNOWN = "UNKNOWN" ++ ++ ++class DevFan(object): ++ ++ def __init__(self, name, hal_interface): ++ self.__name = name ++ self.origin_name = None ++ self.display_name = None ++ self.air_flow = None ++ self.air_flow_inconsistent = False ++ self.int_case = hal_interface ++ ++ @property ++ def name(self): ++ return self.__name ++ ++ def get_fan_rotor_number(self): ++ return self.int_case.get_fan_rotor_number(self.name) ++ ++ def get_fan_presence(self): ++ return self.int_case.get_fan_presence(self.name) ++ ++ def get_fan_rotor_status(self, rotor_name): ++ return self.int_case.get_fan_rotor_status(self.name, rotor_name) ++ ++ def get_fan_fru_info(self): ++ return self.int_case.get_fan_fru_info(self.name) ++ ++ @property ++ def na_ret(self): ++ return self.int_case.na_ret ++ ++ def update_fru_info(self): ++ try: ++ dic = self.get_fan_fru_info() ++ self.origin_name = dic["PN"] ++ self.air_flow = dic["AirFlow"] ++ self.display_name = dic["DisplayName"] ++ except Exception as e: ++ fanairflow_debug("update %s fru info error, msg: %s" % (self.name, str(e))) ++ self.origin_name = self.na_ret ++ self.air_flow = self.na_ret ++ self.display_name = self.na_ret ++ ++ ++class DevPsu(object): ++ ++ def __init__(self, name, hal_interface): ++ self.__name = name ++ self.origin_name = None ++ self.display_name = None ++ self.air_flow = None ++ self.air_flow_inconsistent = False ++ self.int_case = hal_interface ++ ++ @property ++ def name(self): ++ return self.__name ++ ++ def get_psu_fru_info(self): ++ return self.int_case.get_psu_fru_info(self.name) ++ ++ @property ++ def na_ret(self): ++ return self.int_case.na_ret ++ ++ def update_fru_info(self): ++ try: ++ dic = self.get_psu_fru_info() ++ self.origin_name = dic["PN"] ++ self.air_flow = dic["AirFlow"] ++ self.display_name = dic["DisplayName"] ++ except Exception as e: ++ fanairflow_debug("update %s fru info error, msg: %s" % (self.name, str(e))) ++ self.origin_name = self.na_ret ++ self.air_flow = self.na_ret ++ self.display_name = self.na_ret ++ ++ ++class fancontrol(object): ++ __int_case = None ++ ++ __pwm = 0x80 ++ ++ def __init__(self): ++ self.int_case = interface() ++ self.__config = baseutil.get_monitor_config() ++ self.__pid_config = self.__config["pid"] ++ self.__hyst_config = self.__config.get("hyst", {}) ++ self.__temps_threshold_config = self.__config["temps_threshold"] ++ for temp_threshold in self.__temps_threshold_config.values(): ++ temp_threshold['temp'] = 0 ++ temp_threshold['fail_num'] = 0 ++ temp_threshold['warning_num'] = 0 # temp warning times ++ temp_threshold['critical_num'] = 0 # temp critical times ++ temp_threshold['emergency_num'] = 0 # temp emergency times ++ temp_threshold.setdefault('ignore_threshold', 0) # default temp threshold on ++ temp_threshold.setdefault('invalid', invalid_temp) ++ temp_threshold.setdefault('error', error_temp) ++ ++ self.__otp_reboot_judge_file_config = self.__config.get("otp_reboot_judge_file", None) ++ if self.__otp_reboot_judge_file_config is None: ++ self.__otp_switch_reboot_judge_file = OTP_SWITCH_REBOOT_JUDGE_FILE ++ self.__otp_other_reboot_judge_file = OTP_OTHER_REBOOT_JUDGE_FILE ++ else: ++ self.__otp_switch_reboot_judge_file = self.__otp_reboot_judge_file_config.get( ++ "otp_switch_reboot_judge_file", OTP_SWITCH_REBOOT_JUDGE_FILE) ++ self.__otp_other_reboot_judge_file = self.__otp_reboot_judge_file_config.get( ++ "otp_other_reboot_judge_file", OTP_OTHER_REBOOT_JUDGE_FILE) ++ ++ self.__fan_rotor_error_num = {} ++ self.__fan_present_status = {} # {"FAN1":0, "FAN2":1...} 1:present, 0:absent ++ self.__fan_rotate_status = {} # {"FAN1":0, "FAN2":1...} 1:OK, 0:NOT OK ++ self.__fan_repair_flag = {} # {"FAN1":0, "FAN2":1...} 1:repair, 0:give up ++ fan_num = self.get_fan_total_number() ++ for i in range(fan_num): ++ fan_name = "FAN" + str(i + 1) ++ self.__fan_present_status[fan_name] = 1 # present ++ self.__fan_rotate_status[fan_name] = 1 # OK ++ self.__fan_repair_flag[fan_name] = 1 # repair ++ rotor_num = self.get_rotor_number(fan_name) ++ tmp_fan = {} ++ for j in range(rotor_num): ++ rotor_name = "Rotor" + str(j + 1) ++ tmp_fan[rotor_name] = 0 # not error ++ self.__fan_rotor_error_num[fan_name] = tmp_fan ++ ++ self.__fancontrol_para = self.__config["fancontrol_para"] ++ self.__interval = self.__fancontrol_para.get("interval", 5) ++ self.__fan_status_interval = self.__fancontrol_para.get("fan_status_interval", 0) ++ self.__max_pwm = self.__fancontrol_para.get("max_pwm", 0xff) ++ self.__min_pwm = self.__fancontrol_para.get("min_pwm", 0x80) ++ self.__abnormal_pwm = self.__fancontrol_para.get("abnormal_pwm", 0xbb) ++ self.__warning_pwm = self.__fancontrol_para.get("warning_pwm", 0xff) ++ self.__temp_invalid_pid_pwm = self.__fancontrol_para.get("temp_invalid_pid_pwm", 0x80) ++ self.__temp_error_pid_pwm = self.__fancontrol_para.get("temp_error_pid_pwm", 0x80) ++ self.__temp_fail_num = self.__fancontrol_para.get("temp_fail_num", 3) ++ self.__check_temp_fail = self.__fancontrol_para.get("check_temp_fail", []) ++ self.__temp_warning_num = self.__fancontrol_para.get("temp_warning_num", 3) ++ self.__temp_critical_num = self.__fancontrol_para.get("temp_critical_num", 3) ++ self.__temp_emergency_num = self.__fancontrol_para.get("temp_emergency_num", 3) ++ self.__temp_warning_countdown = self.__fancontrol_para.get("temp_warning_countdown", 60) ++ self.__temp_critical_countdown = self.__fancontrol_para.get("temp_critical_countdown", 60) ++ self.__temp_emergency_countdown = self.__fancontrol_para.get("temp_emergency_countdown", 60) ++ self.__rotor_error_count = self.__fancontrol_para.get("rotor_error_count", 6) ++ self.__inlet_mac_diff = self.__fancontrol_para.get("inlet_mac_diff", 50) ++ self.__check_crit_reboot_flag = self.__fancontrol_para.get("check_crit_reboot_flag", 1) ++ self.__check_emerg_reboot_flag = self.__fancontrol_para.get("check_emerg_reboot_flag", 1) ++ self.__check_crit_reboot_num = self.__fancontrol_para.get("check_crit_reboot_num", 3) ++ self.__check_crit_sleep_time = self.__fancontrol_para.get("check_crit_sleep_time", 20) ++ self.__check_emerg_reboot_num = self.__fancontrol_para.get("check_emerg_reboot_num", 3) ++ self.__check_emerg_sleep_time = self.__fancontrol_para.get("check_emerg_sleep_time", 20) ++ self.__check_temp_emergency = self.__fancontrol_para.get("check_temp_emergency", 0) ++ self.__check_temp_critical = self.__fancontrol_para.get("check_temp_critical", 1) ++ self.__check_temp_warning = self.__fancontrol_para.get("check_temp_warning", 1) ++ self.__check_temp_emergency_reboot = self.__fancontrol_para.get("check_temp_emergency_reboot", []) ++ self.__psu_absent_fullspeed_num = self.__fancontrol_para.get("psu_absent_fullspeed_num", 1) ++ self.__fan_absent_fullspeed_num = self.__fancontrol_para.get("fan_absent_fullspeed_num", 1) ++ self.__rotor_error_fullspeed_num = self.__fancontrol_para.get("rotor_error_fullspeed_num", 1) ++ self.__psu_fan_control = self.__fancontrol_para.get("psu_fan_control", 1) # default control psu fan ++ self.__fan_plug_in_pwm = self.__fancontrol_para.get("fan_plug_in_pwm", 0x80) ++ self.__fan_plug_in_default_countdown = self.__fancontrol_para.get("fan_plug_in_default_countdown", 0) ++ self.__deal_fan_error_policy = self.__fancontrol_para.get("deal_fan_error", 0) ++ self.__deal_fan_error_conf = self.__fancontrol_para.get("deal_fan_error_conf", {}) ++ self.__deal_fan_error_default_countdown = self.__deal_fan_error_conf.get("countdown", 0) ++ ++ self.__warning_countdown = 0 # temp warning flag for normal fancontrol ++ self.__critical_countdown = 0 # temp critical flag for normal fancontrol ++ self.__emergency_countdown = 0 # temp emergency flag for normal fancontrol ++ self.__fan_plug_in_countdown = 0 # fan plug in flag for normal fancontrol ++ self.__deal_fan_error_countdown = 0 ++ self.__fan_absent_num = 0 ++ self.__fan_nok_num = 0 ++ self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN ++ self.openloop = openloop() ++ self.pid = pid() ++ self.hyst = hysteresis() ++ self.__pwm = self.__min_pwm ++ ++ self.__board_air_flow = "" ++ self.__fan_air_flow_monitor = self.__fancontrol_para.get("fan_air_flow_monitor", 0) ++ self.__psu_air_flow_monitor = self.__fancontrol_para.get("psu_air_flow_monitor", 0) ++ self.__air_flow_correct_fan_pwm = self.__fancontrol_para.get("air_flow_correct_fan_pwm", 0xff) ++ self.__air_flow_correct_psu_pwm = self.__fancontrol_para.get("air_flow_correct_psu_pwm", 0xff) ++ self.__air_flow_error_fan_pwm = self.__fancontrol_para.get("air_flow_error_fan_pwm", 0) ++ self.__air_flow_error_psu_pwm = self.__fancontrol_para.get("air_flow_error_psu_pwm", 0) ++ self.fan_air_flow_inconsistent_flag = False ++ self.psu_air_flow_inconsistent_flag = False ++ self.air_flow_inconsistent_flag = False ++ self.fan_obj_list = [] ++ self.psu_obj_list = [] ++ ++ @property ++ def na_ret(self): ++ return self.int_case.na_ret ++ ++ def get_onie_e2_obj(self, name): ++ return self.int_case.get_onie_e2_obj(name) ++ ++ @property ++ def board_air_flow(self): ++ air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) ++ if self.__board_air_flow not in air_flow_tuple: ++ self.__board_air_flow = self.int_case.get_device_airflow(ONIE_E2_NAME) ++ fanairflow_debug("board_air_flow: %s" % self.__board_air_flow) ++ return self.__board_air_flow ++ ++ @property ++ def fan_air_flow_monitor(self): ++ return self.__fan_air_flow_monitor ++ ++ @property ++ def psu_air_flow_monitor(self): ++ return self.__psu_air_flow_monitor ++ ++ @property ++ def air_flow_correct_fan_pwm(self): ++ return self.__air_flow_correct_fan_pwm ++ ++ @property ++ def air_flow_correct_psu_pwm(self): ++ return self.__air_flow_correct_psu_pwm ++ ++ @property ++ def air_flow_error_fan_pwm(self): ++ return self.__air_flow_error_fan_pwm ++ ++ @property ++ def air_flow_error_psu_pwm(self): ++ return self.__air_flow_error_psu_pwm ++ ++ def get_para(self, t): ++ para = self.__pid_config.get(t) ++ return para ++ ++ def update_over_temp_threshold_num(self): ++ for temp_threshold in self.__temps_threshold_config.values(): ++ if temp_threshold['ignore_threshold']: ++ continue ++ emergency_threshold = temp_threshold.get('emergency', None) ++ critical_threshold = temp_threshold.get('critical', None) ++ warning_threshold = temp_threshold.get('warning', None) ++ fancontrol_debug("%s warning = %s, critical = %s, emergency = %s" % ++ (temp_threshold['name'], warning_threshold, critical_threshold, emergency_threshold)) ++ ++ if emergency_threshold is not None and temp_threshold['temp'] >= emergency_threshold: ++ temp_threshold['emergency_num'] += 1 ++ else: ++ temp_threshold['emergency_num'] = 0 ++ ++ if critical_threshold is not None and temp_threshold['temp'] >= critical_threshold: ++ temp_threshold['critical_num'] += 1 ++ else: ++ temp_threshold['critical_num'] = 0 ++ ++ if warning_threshold is not None and temp_threshold['temp'] >= warning_threshold: ++ temp_threshold['warning_num'] += 1 ++ else: ++ temp_threshold['warning_num'] = 0 ++ ++ fancontrol_debug("%s warning_num = %d, critical_num = %d, emergency_num = %d" % ++ (temp_threshold['name'], temp_threshold['warning_num'], temp_threshold['critical_num'], temp_threshold.get("emergency_num"))) ++ ++ def get_monitor_temp(self): ++ sensorlist = self.int_case.get_temp_info() ++ ++ for temp_threshold in self.__temps_threshold_config.values(): ++ sensor = sensorlist.get(temp_threshold['name']) ++ if sensor["Value"] is None or int(sensor["Value"]) == self.int_case.error_ret: ++ temp_threshold['fail_num'] += 1 ++ fancontrol_error("get %s failed, fail_num = %d" % (temp_threshold['name'], temp_threshold['fail_num'])) ++ else: ++ temp_threshold['fail_num'] = 0 ++ temp_threshold.setdefault('fix', 0) ++ temp_threshold['temp'] = sensor["Value"] + temp_threshold['fix'] ++ fancontrol_debug("%s = %d" % (temp_threshold['name'], temp_threshold['temp'])) ++ self.update_over_temp_threshold_num() ++ ++ def is_temp_warning(self): ++ warning_flag = False ++ for temp_threshold in self.__temps_threshold_config.values(): ++ if temp_threshold['ignore_threshold']: ++ continue ++ if temp_threshold['warning_num'] >= self.__temp_warning_num: ++ warning_flag = True ++ fancontrol_warn("%%FANCONTROL-4-TEMP_HIGH: %s temperature %sC is larger than warning threshold %sC." % ++ (temp_threshold['name'], temp_threshold['temp'], temp_threshold.get('warning'))) ++ return warning_flag ++ ++ def checkTempWarning(self): ++ try: ++ if self.is_temp_warning(): ++ self.__warning_countdown = self.__temp_warning_countdown ++ fancontrol_debug("temp is over warning") ++ return True ++ if self.__warning_countdown > 0: ++ self.__warning_countdown -= 1 ++ return False ++ except Exception as e: ++ fancontrol_error("%%policy: checkTempWarning failed") ++ fancontrol_error(str(e)) ++ return False ++ ++ def checkTempWarningCountdown(self): ++ if self.__warning_countdown > 0: ++ return True ++ return False ++ ++ def is_temp_critical(self): ++ critical_flag = False ++ for temp_threshold in self.__temps_threshold_config.values(): ++ temp_threshold['critical_flag'] = False ++ if temp_threshold['ignore_threshold']: ++ continue ++ if temp_threshold['critical_num'] >= self.__temp_critical_num: ++ critical_flag = True ++ temp_threshold['critical_flag'] = True ++ fancontrol_crit("%%FANCONTROL-2-TEMP_HIGH: %s temperature %sC is larger than critical threshold %sC." % ++ (temp_threshold['name'], temp_threshold['temp'], temp_threshold.get('critical'))) ++ return critical_flag ++ ++ def checkTempCritical(self): ++ try: ++ if self.is_temp_critical(): ++ self.__critical_countdown = self.__temp_critical_countdown ++ fancontrol_debug("temp is over critical") ++ return True ++ if self.__critical_countdown > 0: ++ self.__critical_countdown -= 1 ++ return False ++ except Exception as e: ++ fancontrol_error("%%policy: checkTempCrit failed") ++ fancontrol_error(str(e)) ++ return False ++ ++ def is_temp_emergency(self): ++ emergency_flag = False ++ for temp_threshold in self.__temps_threshold_config.values(): ++ temp_threshold['emergency_flag'] = False ++ if temp_threshold['ignore_threshold']: ++ continue ++ if temp_threshold['emergency_num'] >= self.__temp_emergency_num: ++ emergency_flag = True ++ temp_threshold['emergency_flag'] = True ++ fancontrol_alert("%%FANCONTROL-1-TEMP_HIGH: %s temperature %sC is larger than emergency threshold %sC." % ++ (temp_threshold['name'], temp_threshold['temp'], temp_threshold.get('emergency'))) ++ return emergency_flag ++ ++ def checkTempEmergency(self): ++ try: ++ if self.is_temp_emergency(): ++ self.__emergency_countdown = self.__temp_emergency_countdown ++ fancontrol_debug("temp is over emergency") ++ return True ++ if self.__emergency_countdown > 0: ++ self.__emergency_countdown -= 1 ++ return False ++ except Exception as e: ++ fancontrol_error("%%policy: checkTempEmergency failed") ++ fancontrol_error(str(e)) ++ return False ++ ++ def checkTempCriticalCountdown(self): ++ if self.__critical_countdown > 0: ++ return True ++ return False ++ ++ def checkTempEmergencyCountdown(self): ++ if self.__emergency_countdown > 0: ++ return True ++ return False ++ ++ def checkTempRebootCrit(self): ++ try: ++ if self.is_temp_critical(): ++ temp_dict = dict(self.__temps_threshold_config) ++ tmp = temp_dict.get(SWITCH_TEMP) ++ if tmp['critical_flag'] is True: ++ fancontrol_debug("switch temp is over reboot critical") ++ return TEMP_REBOOT_CRIT_SWITCH_FLAG ++ del temp_dict[SWITCH_TEMP] ++ for temp_items in temp_dict.values(): ++ if temp_items['ignore_threshold']: ++ continue ++ if temp_items['critical_flag'] is False: ++ return 0 ++ ++ fancontrol_debug("other temp is over reboot critical") ++ return TEMP_REBOOT_CRIT_OTHER_FLAG ++ except Exception as e: ++ fancontrol_error("%%policy: checkTempRebootCrit failed") ++ fancontrol_error(str(e)) ++ return 0 ++ ++ def checkCritReboot(self): ++ try: ++ reboot_flag = self.checkTempRebootCrit() ++ if reboot_flag > 0: ++ self.set_all_fan_speed_pwm(self.__max_pwm) ++ for i in range(self.__check_crit_reboot_num): ++ time.sleep(self.__check_crit_sleep_time) ++ self.get_monitor_temp() ++ reboot_flag = self.checkTempRebootCrit() ++ if reboot_flag > 0: ++ fancontrol_emerg("%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot critical value lasts for %d seconds." % ++ (self.__check_crit_sleep_time * (i + 1))) ++ continue ++ fancontrol_debug("The temperature of device is not over reboot critical value.") ++ break ++ if reboot_flag > 0: ++ fancontrol_emerg( ++ "%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot critical value, system is going to reboot now.") ++ for temp_threshold in self.__temps_threshold_config.values(): ++ fancontrol_emerg( ++ "%%FANCONTROL-TEMP_EMERG: %s temperature: %sC." % ++ (temp_threshold['name'], temp_threshold['temp'])) ++ if reboot_flag == TEMP_REBOOT_CRIT_SWITCH_FLAG: ++ create_judge_file = "touch %s" % self.__otp_switch_reboot_judge_file ++ else: ++ create_judge_file = "touch %s" % self.__otp_other_reboot_judge_file ++ exec_os_cmd(create_judge_file) ++ exec_os_cmd("sync") ++ time.sleep(3) ++ os.system("/sbin/reboot") ++ except Exception as e: ++ fancontrol_error("%%policy: checkCritReboot failed") ++ fancontrol_error(str(e)) ++ ++ def checkTempRebootEmerg(self): ++ try: ++ if self.is_temp_emergency(): ++ temp_emerg_reboot_flag = False ++ for temp_list in self.__check_temp_emergency_reboot: ++ for temp in temp_list: ++ tmp = self.__temps_threshold_config.get(temp) ++ if tmp['emergency_flag'] is False: ++ fancontrol_debug("temp_list %s, temp: %s not emergency" % (temp_list, temp)) ++ temp_emerg_reboot_flag = False ++ break ++ temp_emerg_reboot_flag = True ++ if temp_emerg_reboot_flag is True: ++ fancontrol_debug("temp_list %s, all temp is over emergency reboot" % temp_list) ++ return True ++ except Exception as e: ++ fancontrol_error("%%policy: checkTempRebootEmerg failed") ++ fancontrol_error(str(e)) ++ return False ++ ++ def checkEmergReboot(self): ++ try: ++ reboot_flag = False ++ if self.checkTempRebootEmerg() is True: ++ self.set_all_fan_speed_pwm(self.__max_pwm) ++ for i in range(self.__check_emerg_reboot_num): ++ time.sleep(self.__check_emerg_sleep_time) ++ self.get_monitor_temp() ++ if self.checkTempRebootEmerg() is True: ++ fancontrol_emerg("%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot emergency value lasts for %d seconds." % ++ (self.__check_emerg_sleep_time * (i + 1))) ++ reboot_flag = True ++ continue ++ fancontrol_debug("The temperature of device is not over reboot emergency value.") ++ reboot_flag = False ++ break ++ if reboot_flag is True: ++ fancontrol_emerg( ++ "%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot emergency value, system is going to reboot now.") ++ for temp_threshold in self.__temps_threshold_config.values(): ++ fancontrol_emerg( ++ "%%FANCONTROL-0-TEMP_EMERG: %s temperature: %sC." % ++ (temp_threshold['name'], temp_threshold['temp'])) ++ create_judge_file = "touch %s" % OTP_SWITCH_REBOOT_JUDGE_FILE ++ exec_os_cmd(create_judge_file) ++ exec_os_cmd("sync") ++ time.sleep(3) ++ os.system("/sbin/reboot") ++ except Exception as e: ++ fancontrol_error("%%policy: checkEmergReboot failed") ++ fancontrol_error(str(e)) ++ ++ def get_fan_total_number(self): ++ return self.int_case.get_fan_total_number() ++ ++ def get_rotor_number(self, fan_name): ++ return self.int_case.get_fan_rotor_number(fan_name) ++ ++ def get_fan_presence(self, fan_name): ++ return self.int_case.get_fan_presence(fan_name) ++ ++ def get_fan_rotor_status(self, fan_name, rotor_name): ++ return self.int_case.get_fan_rotor_status(fan_name, rotor_name) ++ ++ def get_psu_total_number(self): ++ return self.int_case.get_psu_total_number() ++ ++ def get_psu_presence(self, psu_name): ++ return self.int_case.get_psu_presence(psu_name) ++ ++ def get_psu_input_output_status(self, psu_name): ++ return self.int_case.get_psu_input_output_status(psu_name) ++ ++ def checkFanPresence(self): ++ absent_num = 0 ++ ++ fan_num = self.get_fan_total_number() ++ for i in range(fan_num): ++ fan_name = "FAN" + str(i + 1) ++ rotor_num = self.get_rotor_number(fan_name) ++ tmp_fan = self.__fan_rotor_error_num.get(fan_name) ++ status = self.get_fan_presence(fan_name) ++ if status is False: ++ absent_num = absent_num + 1 ++ self.__fan_present_status[fan_name] = 0 ++ fancontrol_debug("%s absent" % fan_name) ++ else: ++ if self.__fan_present_status[fan_name] == 0: # absent -> present ++ self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN ++ self.__fan_plug_in_countdown = self.__fan_plug_in_default_countdown ++ self.__fan_repair_flag[fan_name] = 1 ++ for j in range(rotor_num): ++ rotor_name = "Rotor" + str(j + 1) ++ tmp_fan[rotor_name] = 0 ++ self.__fan_present_status[fan_name] = 1 ++ fancontrol_debug("%s presence" % fan_name) ++ return absent_num ++ ++ def checkFanRotorStatus(self): ++ err_num = 0 ++ self.__fan_nok_num = 0 ++ fan_num = self.get_fan_total_number() ++ for i in range(fan_num): ++ fan_name = "FAN" + str(i + 1) ++ rotor_num = self.get_rotor_number(fan_name) ++ tmp_fan = self.__fan_rotor_error_num.get(fan_name) ++ fan_rotor_err_cnt = 0 ++ for j in range(rotor_num): ++ rotor_name = "Rotor" + str(j + 1) ++ status = self.get_fan_rotor_status(fan_name, rotor_name) ++ if status is True: ++ tmp_fan[rotor_name] = 0 ++ fancontrol_debug("%s %s ok" % (fan_name, rotor_name)) ++ else: ++ tmp_fan[rotor_name] += 1 ++ if tmp_fan[rotor_name] >= self.__rotor_error_count: ++ err_num = err_num + 1 ++ fan_rotor_err_cnt += 1 ++ fancontrol_debug("%s %s error" % (fan_name, rotor_name)) ++ fancontrol_debug("%s %s error %d times" % (fan_name, rotor_name, tmp_fan[rotor_name])) ++ if fan_rotor_err_cnt == 0: ++ self.__fan_rotate_status[fan_name] = 1 # FAN is ok ++ else: ++ self.__fan_rotate_status[fan_name] = 0 # FAN is not ok ++ self.__fan_nok_num += 1 ++ fancontrol_debug("fan not ok number:%d." % self.__fan_nok_num) ++ return err_num ++ ++ def checkPsuPresence(self): ++ absent_num = 0 ++ psu_num = self.get_psu_total_number() ++ for i in range(psu_num): ++ psu_name = "PSU" + str(i + 1) ++ status = self.get_psu_presence(psu_name) ++ if status is False: ++ absent_num = absent_num + 1 ++ fancontrol_debug("%s absent" % psu_name) ++ else: ++ fancontrol_debug("%s presence" % psu_name) ++ return absent_num ++ ++ def checkPsuStatus(self): ++ err_num = 0 ++ psu_num = self.get_psu_total_number() ++ for i in range(psu_num): ++ psu_name = "PSU" + str(i + 1) ++ status = self.get_psu_input_output_status(psu_name) ++ if status is False: ++ err_num = err_num + 1 ++ fancontrol_debug("%s error" % psu_name) ++ else: ++ fancontrol_debug("%s ok" % psu_name) ++ return err_num ++ ++ def checkDevError(self): ++ pwm = self.__min_pwm ++ switchtemp = self.__temps_threshold_config.get(SWITCH_TEMP)['temp'] ++ inlettemp = self.__temps_threshold_config.get(INLET_TEMP)['temp'] ++ temp_diff = abs(switchtemp - inlettemp) ++ fancontrol_debug("|switchtemp - inlettemp| = %d" % temp_diff) ++ if temp_diff >= self.__inlet_mac_diff: ++ fancontrol_debug("temp_diff is over than inlet_mac_diff(%d)" % self.__inlet_mac_diff) ++ if self.__pwm > self.__abnormal_pwm: ++ pwm = self.__max_pwm ++ else: ++ pwm = self.__abnormal_pwm ++ return pwm ++ ++ def checktempfail(self): ++ pwm = self.__min_pwm ++ for temp in self.__check_temp_fail: ++ temp_name = temp.get("temp_name") ++ temp_fail_num = self.__temps_threshold_config.get(temp_name)['fail_num'] ++ if temp_fail_num >= self.__temp_fail_num: ++ pwm = self.__abnormal_pwm ++ fancontrol_debug("%s temp_fail_num = %d" % (temp_name, temp_fail_num)) ++ fancontrol_debug("self.__temp_fail_num = %d" % self.__temp_fail_num) ++ return pwm ++ ++ def abnormal_check(self): ++ pwm_list = [] ++ pwm_min = self.__min_pwm ++ pwm_list.append(pwm_min) ++ ++ if self.__check_temp_emergency == 1: ++ status = self.checkTempEmergency() ++ if status is True: ++ over_emerg_pwm = self.__max_pwm ++ pwm_list.append(over_emerg_pwm) ++ fancontrol_debug("over_emerg_pwm = 0x%x" % over_emerg_pwm) ++ # do reset check ++ if self.__check_emerg_reboot_flag == 1: ++ self.checkEmergReboot() ++ else: ++ if self.checkTempEmergencyCountdown() is True: # temp lower than emergency in 5 min ++ over_emerg_countdown_pwm = self.__max_pwm ++ pwm_list.append(over_emerg_countdown_pwm) ++ fancontrol_debug("TempEmergencyCountdown: %d, over_emerg_countdown_pwm = 0x%x" % ++ (self.__emergency_countdown, over_emerg_countdown_pwm)) ++ ++ if self.__check_temp_critical == 1: ++ status = self.checkTempCritical() ++ if status is True: ++ over_crit_pwm = self.__max_pwm ++ pwm_list.append(over_crit_pwm) ++ fancontrol_debug("over_crit_pwm = 0x%x" % over_crit_pwm) ++ # do reset check ++ if self.__check_crit_reboot_flag == 1: ++ self.checkCritReboot() ++ else: ++ if self.checkTempCriticalCountdown() is True: # temp lower than critical in 5 min ++ over_crit_countdown_pwm = self.__max_pwm ++ pwm_list.append(over_crit_countdown_pwm) ++ fancontrol_debug("TempCriticalCountdown: %d, over_crit_countdown_pwm = 0x%x" % ++ (self.__critical_countdown, over_crit_countdown_pwm)) ++ ++ if self.__check_temp_warning == 1: ++ status = self.checkTempWarning() ++ if status is True: ++ over_warn_pwm = self.__warning_pwm ++ pwm_list.append(over_warn_pwm) ++ fancontrol_debug("over_warn_pwm = 0x%x" % over_warn_pwm) ++ else: ++ if self.checkTempWarningCountdown() is True: # temp lower than warning in 5 min ++ over_warn_countdown_pwm = self.__warning_pwm ++ pwm_list.append(over_warn_countdown_pwm) ++ fancontrol_debug("TempWarningCountdown: %d, over_warn_countdown_pwm = 0x%x" % ++ (self.__warning_countdown, over_warn_countdown_pwm)) ++ ++ self.__fan_absent_num = self.checkFanPresence() ++ if self.__fan_absent_num >= self.__fan_absent_fullspeed_num: ++ fan_absent_pwm = self.__max_pwm ++ pwm_list.append(fan_absent_pwm) ++ fancontrol_debug("fan_absent_pwm = 0x%x" % fan_absent_pwm) ++ ++ rotor_err_num = self.checkFanRotorStatus() ++ if rotor_err_num >= self.__rotor_error_fullspeed_num: ++ rotor_err_pwm = self.__max_pwm ++ pwm_list.append(rotor_err_pwm) ++ fancontrol_debug("rotor_err_pwm = 0x%x" % rotor_err_pwm) ++ ++ psu_absent_num = self.checkPsuPresence() ++ if psu_absent_num >= self.__psu_absent_fullspeed_num: ++ psu_absent_pwm = self.__max_pwm ++ pwm_list.append(psu_absent_pwm) ++ fancontrol_debug("psu_absent_pwm = 0x%x" % psu_absent_pwm) ++ ++ dev_err_pwm = self.checkDevError() ++ pwm_list.append(dev_err_pwm) ++ fancontrol_debug("dev_err_pwm = 0x%x" % dev_err_pwm) ++ ++ temp_fail_pwm = self.checktempfail() ++ pwm_list.append(temp_fail_pwm) ++ fancontrol_debug("temp_fail_pwm = 0x%x" % temp_fail_pwm) ++ ++ pwm = max(pwm_list) ++ return pwm ++ ++ def get_error_fan(self): ++ fan_num = self.get_fan_total_number() ++ for i in range(fan_num): ++ fan_name = "FAN" + str(i + 1) ++ if self.__fan_rotate_status[fan_name] == 0: ++ return fan_name ++ return None ++ ++ def fan_error_update_pwm(self, fan_pwm_dict): ++ try: ++ fancontrol_debug("enter deal fan error policy") ++ ori_fan_pwm_dict = fan_pwm_dict.copy() ++ ++ err_fan_name = self.get_error_fan() ++ if err_fan_name is None: ++ fancontrol_debug("fan name is None, do nothing.") ++ return ori_fan_pwm_dict ++ ++ if self.__fan_repair_flag[err_fan_name] == 0: ++ fancontrol_debug("%s already repaired, do nothing." % err_fan_name) ++ return ori_fan_pwm_dict ++ ++ if self.__pre_fan_nok != err_fan_name: ++ fancontrol_debug( ++ "not ok fan change from %s to %s, update countdown." % ++ (self.__pre_fan_nok, err_fan_name)) ++ self.__deal_fan_error_countdown = self.__deal_fan_error_default_countdown ++ if self.__pre_fan_nok != PRE_FAN_NOK_UNKNOWN: ++ fancontrol_debug( ++ "%s repaire success, %s NOT OK, try to repaire." % ++ (self.__pre_fan_nok, err_fan_name)) ++ self.__fan_repair_flag[self.__pre_fan_nok] = 0 ++ self.__pre_fan_nok = err_fan_name ++ ++ if self.__deal_fan_error_countdown > 0: ++ self.__deal_fan_error_countdown -= 1 ++ fancontrol_debug("%s repaire, countdown %d." % (err_fan_name, self.__deal_fan_error_countdown)) ++ ++ if self.__deal_fan_error_countdown == 0: ++ self.__fan_repair_flag[err_fan_name] = 0 ++ fancontrol_debug("%s set repaire fail flag, use origin pwm." % err_fan_name) ++ return ori_fan_pwm_dict ++ ++ fan_err_pwm_conf_list = self.__deal_fan_error_conf[err_fan_name] ++ for item in fan_err_pwm_conf_list: ++ fan_pwm_dict[item["name"]] = item["pwm"] ++ fancontrol_debug("fan pwm update, fan pwm dict:%s" % fan_pwm_dict) ++ ++ return fan_pwm_dict ++ except Exception as e: ++ fancontrol_error("%%policy: deal_fan_error raise Exception:%s" % str(e)) ++ self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN ++ return ori_fan_pwm_dict ++ ++ def get_fan_pwm_dict(self, default_pwm): ++ fan_pwm_dict = {} ++ fan_num = self.get_fan_total_number() ++ for i in range(fan_num): ++ fan_name = "FAN" + str(i + 1) ++ fan_pwm_dict[fan_name] = default_pwm ++ if self.__deal_fan_error_policy: ++ if self.__fan_absent_num == 0 and self.__fan_nok_num == 1: ++ fan_pwm_dict = self.fan_error_update_pwm(fan_pwm_dict) ++ else: ++ if self.__pre_fan_nok != PRE_FAN_NOK_UNKNOWN and self.__fan_rotate_status[self.__pre_fan_nok] == 1: ++ fancontrol_debug("%s repaire success." % (self.__pre_fan_nok)) ++ self.__fan_repair_flag[self.__pre_fan_nok] = 0 ++ self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN ++ return fan_pwm_dict ++ ++ def get_psu_pwm_dict(self, default_pwm): ++ psu_pwm_dict = {} ++ psu_num = self.get_psu_total_number() ++ for i in range(psu_num): ++ psu_name = "PSU" + str(i + 1) ++ psu_pwm_dict[psu_name] = default_pwm ++ return psu_pwm_dict ++ ++ def check_board_air_flow(self): ++ board_air_flow = self.board_air_flow ++ air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) ++ if board_air_flow not in air_flow_tuple: ++ fanairflow_debug("get board air flow error, value [%s]" % board_air_flow) ++ return False ++ fanairflow_debug("board air flow check ok: %s" % board_air_flow) ++ return True ++ ++ def check_fan_air_flow(self): ++ if self.fan_air_flow_monitor: ++ fanairflow_debug("open air flow monitor, check fan air flow") ++ ret = self.check_board_air_flow() ++ if ret is False: ++ fanairflow_debug("get board air flow error, set fan_air_flow_inconsistent_flag False") ++ self.fan_air_flow_inconsistent_flag = False ++ return ++ air_flow_inconsistent_flag_tmp = False ++ for fan_obj in self.fan_obj_list: ++ fan_obj.update_fru_info() ++ fanairflow_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % ++ (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow)) ++ if fan_obj.air_flow == self.na_ret: ++ fanairflow_debug("%s get air flow failed, set air_flow_inconsistent flag False" % fan_obj.name) ++ fan_obj.air_flow_inconsistent = False ++ continue ++ if fan_obj.air_flow != self.board_air_flow: ++ fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], fan air flow [%s], board air flow [%s]" % ++ (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) ++ air_flow_inconsistent_flag_tmp = True ++ fan_obj.air_flow_inconsistent = True ++ else: ++ fanairflow_debug("%s air flow check ok, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s]" % ++ (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) ++ fan_obj.air_flow_inconsistent = False ++ self.fan_air_flow_inconsistent_flag = air_flow_inconsistent_flag_tmp ++ else: ++ fanairflow_debug("air flow monitor not open, set fan_air_flow_inconsistent_flag False") ++ self.fan_air_flow_inconsistent_flag = False ++ return ++ ++ def check_psu_air_flow(self): ++ if self.psu_air_flow_monitor: ++ fanairflow_debug("open air flow monitor, check psu air flow") ++ ret = self.check_board_air_flow() ++ if ret is False: ++ fanairflow_debug("get board air flow error, set psu_air_flow_inconsistent_flag False") ++ self.psu_air_flow_inconsistent_flag = False ++ return ++ air_flow_inconsistent_flag_tmp = False ++ for psu_obj in self.psu_obj_list: ++ psu_obj.update_fru_info() ++ fanairflow_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % ++ (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow)) ++ if psu_obj.air_flow == self.na_ret: ++ fanairflow_debug("%s get air flow failed, set air_flow_inconsistent flag False" % psu_obj.name) ++ psu_obj.air_flow_inconsistent = False ++ continue ++ if psu_obj.air_flow != self.board_air_flow: ++ fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], psu air flow [%s], board air flow [%s]" % ++ (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) ++ air_flow_inconsistent_flag_tmp = True ++ psu_obj.air_flow_inconsistent = True ++ else: ++ fanairflow_debug("%s air flow check ok, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s]" % ++ (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) ++ psu_obj.air_flow_inconsistent = False ++ self.psu_air_flow_inconsistent_flag = air_flow_inconsistent_flag_tmp ++ else: ++ fanairflow_debug("air flow monitor not open, set psu_air_flow_inconsistent_flag False") ++ self.psu_air_flow_inconsistent_flag = False ++ return ++ ++ def do_fancontrol(self): ++ pwm_list = [] ++ pwm_min = self.__min_pwm ++ pwm_list.append(pwm_min) ++ ++ # first check air flow ++ self.check_fan_air_flow() ++ self.check_psu_air_flow() ++ if self.fan_air_flow_inconsistent_flag is True or self.psu_air_flow_inconsistent_flag is True: ++ self.air_flow_inconsistent_flag = True ++ else: ++ self.air_flow_inconsistent_flag = False ++ fanairflow_debug("check_air_flow, air_flow_inconsistent_flag: %s" % self.air_flow_inconsistent_flag) ++ # get_monitor_temp ++ self.get_monitor_temp() ++ fancontrol_debug("last_pwm = 0x%x" % self.__pwm) ++ # openloop ++ inlettemp = self.__temps_threshold_config.get(INLET_TEMP)['temp'] ++ linear_value = self.openloop.linear_cacl(inlettemp) ++ if linear_value is None: ++ linear_value = self.__min_pwm ++ pwm_list.append(linear_value) ++ fancontrol_debug("linear_value = 0x%x" % linear_value) ++ ++ curve_value = self.openloop.curve_cacl(inlettemp) ++ if curve_value is None: ++ curve_value = self.__min_pwm ++ pwm_list.append(curve_value) ++ fancontrol_debug("curve_value = 0x%x" % curve_value) ++ ++ # hyst ++ for hyst_index in self.__hyst_config.values(): ++ temp_name = hyst_index.get("name") ++ hyst_flag = hyst_index.get("flag", 0) ++ if hyst_flag == 0: ++ fancontrol_debug("%s hyst flag is 0, do nothing" % temp_name) ++ continue ++ tmp_temp = int(self.__temps_threshold_config.get(temp_name)['temp']) # make sure temp is int ++ hyst_value = self.hyst.cacl(temp_name, tmp_temp) ++ if hyst_value is None: ++ hyst_value = self.__min_pwm ++ pwm_list.append(hyst_value) ++ fancontrol_debug("%s hyst_value = 0x%x" % (temp_name, hyst_value)) ++ ++ # pid ++ for pid_index in self.__pid_config.values(): ++ temp_name = pid_index.get("name") ++ pid_flag = pid_index.get("flag", 0) ++ if pid_flag == 0: ++ fancontrol_debug("%s pid flag is 0, do nothing" % temp_name) ++ continue ++ tmp_temp = self.__temps_threshold_config.get(temp_name)['temp'] ++ if tmp_temp is not None: ++ tmp_temp = int(tmp_temp) # make sure temp is int ++ invalid_temp_val = self.__temps_threshold_config.get(temp_name)['invalid'] ++ error_temp_val = self.__temps_threshold_config.get(temp_name)['error'] ++ if tmp_temp == invalid_temp_val: # temp is invalid ++ temp = None ++ self.pid.cacl(self.__pwm, temp_name, temp) # temp invalid, PID need to record None ++ pid_value = self.__temp_invalid_pid_pwm ++ fancontrol_debug("%s is invalid, pid_value = 0x%x" % (temp_name, pid_value)) ++ fancontrol_debug("temp = %d, invalid_temp = %d" % (tmp_temp, invalid_temp_val)) ++ elif tmp_temp == error_temp_val: # temp is error ++ temp = None ++ self.pid.cacl(self.__pwm, temp_name, temp) # temp error, PID need to record None ++ pid_value = self.__temp_error_pid_pwm ++ fancontrol_debug("%s is error, pid_value = 0x%x" % (temp_name, pid_value)) ++ fancontrol_debug("temp = %d, error_temp = %d" % (tmp_temp, error_temp_val)) ++ else: ++ pid_value = self.pid.cacl(self.__pwm, temp_name, tmp_temp) ++ else: # temp get failed ++ pid_value = self.pid.cacl(self.__pwm, temp_name, tmp_temp) ++ if pid_value is None: ++ pid_value = self.__min_pwm ++ pwm_list.append(pid_value) ++ fancontrol_debug("%s pid_value = 0x%x" % (temp_name, pid_value)) ++ ++ # abnormal ++ abnormal_value = self.abnormal_check() ++ pwm_list.append(abnormal_value) ++ fancontrol_debug("abnormal_value = 0x%x" % abnormal_value) ++ ++ if self.__fan_plug_in_countdown > 0 and self.__fan_absent_num == 0: ++ fancontrol_debug("fan plug in countdown %d, set plug in pwm: 0x%x" % ++ (self.__fan_plug_in_countdown, self.__fan_plug_in_pwm)) ++ self.__pwm = self.__fan_plug_in_pwm ++ self.__fan_plug_in_countdown -= 1 ++ else: ++ self.__pwm = max(pwm_list) ++ fancontrol_debug("__pwm = 0x%x\n" % self.__pwm) ++ if self.air_flow_inconsistent_flag is True: ++ fanairflow_debug("air flow inconsistent, set all fan speed pwm") ++ self.set_all_fan_speed_pwm(self.__pwm) ++ else: ++ fanairflow_debug("air flow consistent, deal fan error policy") ++ fan_pwm_dict = self.get_fan_pwm_dict(self.__pwm) ++ psu_pwm_dict = self.get_psu_pwm_dict(self.__pwm) ++ self.set_fan_pwm_independent(fan_pwm_dict, psu_pwm_dict) ++ ++ def run(self): ++ start_time = time.time() ++ while True: ++ try: ++ debug_init() ++ if self.__fan_status_interval > 0 and self.__fan_status_interval < self.__interval: ++ delta_time = time.time() - start_time ++ if delta_time >= self.__interval or delta_time < 0: ++ self.do_fancontrol() ++ start_time = time.time() ++ else: ++ self.checkFanPresence() ++ time.sleep(self.__fan_status_interval) ++ else: ++ self.do_fancontrol() ++ time.sleep(self.__interval) ++ except Exception as e: ++ traceback.print_exc() ++ fancontrol_error(str(e)) ++ ++ def set_all_fan_speed_pwm(self, pwm): ++ fan_pwm_dict = {} ++ psu_pwm_dict = {} ++ fan_num = self.get_fan_total_number() ++ for i in range(fan_num): ++ fan_name = "FAN" + str(i + 1) ++ fan_pwm_dict[fan_name] = pwm ++ ++ psu_num = self.get_psu_total_number() ++ for i in range(psu_num): ++ psu_name = "PSU" + str(i + 1) ++ psu_pwm_dict[psu_name] = pwm ++ self.set_fan_pwm_independent(fan_pwm_dict, psu_pwm_dict) ++ ++ def set_fan_pwm_independent(self, fan_pwm_dict, psu_pwm_dict): ++ if self.air_flow_inconsistent_flag is True: ++ for psu_obj in self.psu_obj_list: ++ if psu_obj.air_flow_inconsistent is True: ++ psu_pwm_dict[psu_obj.name] = self.air_flow_error_psu_pwm ++ fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s], set psu pwm: 0x%x" % ++ (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow, self.air_flow_error_psu_pwm)) ++ else: ++ psu_pwm_dict[psu_obj.name] = self.air_flow_correct_psu_pwm ++ fanairflow_debug("%s air flow correct, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s], set psu pwm: 0x%x" % ++ (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow, self.air_flow_correct_psu_pwm)) ++ ++ for fan_obj in self.fan_obj_list: ++ if fan_obj.air_flow_inconsistent is True: ++ fan_pwm_dict[fan_obj.name] = self.air_flow_error_fan_pwm ++ fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s], set fan pwm: 0x%x" % ++ (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow, self.air_flow_error_fan_pwm)) ++ else: ++ fan_pwm_dict[fan_obj.name] = self.air_flow_correct_fan_pwm ++ fanairflow_debug("%s air flow correct, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s], set fan pwm: 0x%x" % ++ (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow, self.air_flow_correct_fan_pwm)) ++ fan_num = self.get_fan_total_number() ++ for i in range(fan_num): ++ fan_name = "FAN" + str(i + 1) ++ self.fan_set_speed_pwm_by_name(fan_name, fan_pwm_dict[fan_name]) ++ if self.__psu_fan_control == 1: ++ psu_num = self.get_psu_total_number() ++ for i in range(psu_num): ++ psu_name = "PSU" + str(i + 1) ++ self.psu_set_speed_pwm_by_name(psu_name, psu_pwm_dict[psu_name]) ++ ++ def fan_set_speed_pwm_by_name(self, fan_name, pwm): ++ duty = round(pwm * 100 / 255) ++ rotor_len = self.get_rotor_number(fan_name) ++ for i in range(rotor_len): ++ val = self.int_case.set_fan_speed_pwm(fan_name, i + 1, duty) ++ if val != 0: ++ fancontrol_error("%s rotor%d: %d" % (fan_name, i + 1, val)) ++ ++ def psu_set_speed_pwm_by_name(self, psu_name, pwm): ++ duty = round(pwm * 100 / 255) ++ status = self.int_case.set_psu_fan_speed_pwm(psu_name, int(duty)) ++ if status is not True: ++ fancontrol_error("set %s speed fail" % psu_name) ++ ++ def fan_obj_init(self): ++ fan_num = self.get_fan_total_number() ++ for i in range(fan_num): ++ fan_name = "FAN" + str(i + 1) ++ fan_obj = DevFan(fan_name, self.int_case) ++ self.fan_obj_list.append(fan_obj) ++ fanairflow_debug("fan object initialize success") ++ ++ def psu_obj_init(self): ++ psu_num = self.get_psu_total_number() ++ for i in range(psu_num): ++ psu_name = "PSU" + str(i + 1) ++ psu_obj = DevPsu(psu_name, self.int_case) ++ self.psu_obj_list.append(psu_obj) ++ fanairflow_debug("psu object initialize success") ++ ++ ++if __name__ == '__main__': ++ debug_init() ++ fancontrol_debug("enter main") ++ fan_control = fancontrol() ++ fan_control.fan_obj_init() ++ fan_control.psu_obj_init() ++ fan_control.run() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/hal_ledctrl.py b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_ledctrl.py +new file mode 100755 +index 000000000..c21fd3c1f +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_ledctrl.py +@@ -0,0 +1,830 @@ ++#!/usr/bin/env python3 ++import time ++import syslog ++import traceback ++from plat_hal.interface import interface ++from plat_hal.baseutil import baseutil ++try: ++ import abc ++except ImportError as error: ++ raise ImportError(str(error) + " - required module not found") from error ++ ++SWITCH_TEMP = "SWITCH_TEMP" ++F2B_AIR_FLOW = "intake" ++B2F_AIR_FLOW = "exhaust" ++ONIE_E2_NAME = "ONIE_E2" ++ ++# status ++STATUS_PRESENT = "PRESENT" ++STATUS_ABSENT = "ABSENT" ++STATUS_OK = "OK" ++STATUS_NOT_OK = "NOT OK" ++STATUS_FAILED = "FAILED" ++STATUS_UNKNOWN = "UNKNOWN" ++ ++LEDCTROL_DEBUG_FILE = "/etc/.ledcontrol_debug_flag" ++ ++LEDCTROLERROR = 1 ++LEDCTROLDEBUG = 2 ++ ++debuglevel = 0 ++# led status defined ++COLOR_GREEN = 1 ++COLOR_AMBER = 2 ++COLOR_RED = 3 ++LED_STATUS_DICT = {COLOR_GREEN: "green", COLOR_AMBER: "amber", COLOR_RED: "red"} ++ ++ ++def ledcontrol_debug(s): ++ if LEDCTROLDEBUG & debuglevel: ++ syslog.openlog("LEDCONTROL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def ledcontrol_error(s): ++ if LEDCTROLERROR & debuglevel: ++ syslog.openlog("LEDCONTROL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++def air_flow_warn(s): ++ syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_WARNING, s) ++ ++ ++def air_flow_error(s): ++ syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_ERR, s) ++ ++ ++def air_flow_emerg(s): ++ syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_EMERG, s) ++ ++ ++def debug_init(): ++ global debuglevel ++ try: ++ with open(LEDCTROL_DEBUG_FILE, "r") as fd: ++ value = fd.read() ++ debuglevel = int(value) ++ except Exception: ++ debuglevel = 0 ++ ++ ++class DevBase(object): ++ __metaclass__ = abc.ABCMeta ++ ++ def __init__(self, name, air_flow_monitor): ++ self.__name = name ++ self.__air_flow_monitor = air_flow_monitor ++ self.present = STATUS_UNKNOWN ++ self.status = STATUS_UNKNOWN ++ self.status_summary = STATUS_UNKNOWN ++ self.origin_name = STATUS_UNKNOWN ++ self.display_name = STATUS_UNKNOWN ++ self.air_flow = STATUS_UNKNOWN ++ self.led_status = COLOR_GREEN ++ ++ @property ++ def name(self): ++ return self.__name ++ ++ @property ++ def air_flow_monitor(self): ++ return self.__air_flow_monitor ++ ++ @abc.abstractmethod ++ def get_present(self): ++ """ ++ Gets the present status of PSU/FAN ++ ++ Returns: ++ A string, e.g. 'PRESENT, ABSENT, FAILED' ++ """ ++ raise NotImplementedError ++ ++ @abc.abstractmethod ++ def get_status(self): ++ """ ++ Gets the status of PSU/FAN ++ ++ Returns: ++ A string, e.g. 'OK, NOT OK, FAILED' ++ """ ++ raise NotImplementedError ++ ++ @abc.abstractmethod ++ def update_dev_info(self): ++ """ ++ update status and fru info of PSU/FAN ++ ++ include present, status, status_summary, part_model_name, product_name, air_flow ++ """ ++ raise NotImplementedError ++ ++ @abc.abstractmethod ++ def set_module_led(self, color): ++ """ ++ set PSU/FAN module LED status ++ ++ Args: ++ color: A string representing the color with which to set the ++ PSU/FAN module LED status ++ ++ Returns: ++ bool: True if status LED state is set successfully, False if not ++ """ ++ raise NotImplementedError ++ ++ ++class DevPsu(DevBase): ++ ++ def __init__(self, name, air_flow_monitor, hal_interface): ++ super(DevPsu, self).__init__(name, air_flow_monitor) ++ self.int_case = hal_interface ++ ++ def get_psu_presence(self): ++ return self.int_case.get_psu_presence(self.name) ++ ++ def get_psu_input_output_status(self): ++ return self.int_case.get_psu_input_output_status(self.name) ++ ++ def get_psu_fru_info(self): ++ return self.int_case.get_psu_fru_info(self.name) ++ ++ @property ++ def na_ret(self): ++ return self.int_case.na_ret ++ ++ def get_present(self): ++ try: ++ status = self.get_psu_presence() ++ if status is True: ++ return STATUS_PRESENT ++ if status is False: ++ return STATUS_ABSENT ++ except Exception as e: ++ ledcontrol_error("get %s present status error, msg: %s" % (self.name, str(e))) ++ return STATUS_FAILED ++ ++ def get_status(self): ++ try: ++ status = self.get_psu_input_output_status() ++ if status is True: ++ return STATUS_OK ++ if status is False: ++ return STATUS_NOT_OK ++ except Exception as e: ++ ledcontrol_error("get %s status error, msg: %s" % (self.name, str(e))) ++ return STATUS_FAILED ++ ++ def update_dev_info(self): ++ try: ++ # update status ++ self.present = self.get_present() ++ if self.present != STATUS_PRESENT: ++ self.status = STATUS_UNKNOWN ++ self.status_summary = self.present ++ else: ++ self.status = self.get_status() ++ self.status_summary = self.status ++ # update fru info if need air flow monitor ++ if self.air_flow_monitor: ++ dic = self.get_psu_fru_info() ++ self.origin_name = dic["PN"] ++ self.air_flow = dic["AirFlow"] ++ self.display_name = dic["DisplayName"] ++ except Exception as e: ++ ledcontrol_error("update %s info error, msg: %s" % (self.name, str(e))) ++ self.present = STATUS_FAILED ++ self.status = STATUS_FAILED ++ self.status_summary = STATUS_FAILED ++ self.origin_name = self.na_ret ++ self.air_flow = self.na_ret ++ self.display_name = self.na_ret ++ ++ def set_module_led(self, color): ++ """ ++ set PSU module LED is not support, always return True ++ """ ++ return True ++ ++ ++class DevFan(DevBase): ++ ++ def __init__(self, name, air_flow_monitor, hal_interface): ++ super(DevFan, self).__init__(name, air_flow_monitor) ++ self.int_case = hal_interface ++ ++ def get_fan_rotor_number(self): ++ return self.int_case.get_fan_rotor_number(self.name) ++ ++ def get_fan_presence(self): ++ return self.int_case.get_fan_presence(self.name) ++ ++ def get_fan_rotor_status(self, rotor_name): ++ return self.int_case.get_fan_rotor_status(self.name, rotor_name) ++ ++ def get_fan_fru_info(self): ++ return self.int_case.get_fan_fru_info(self.name) ++ ++ @property ++ def na_ret(self): ++ return self.int_case.na_ret ++ ++ def get_present(self): ++ try: ++ status = self.get_fan_presence() ++ if status is True: ++ return STATUS_PRESENT ++ if status is False: ++ return STATUS_ABSENT ++ except Exception as e: ++ ledcontrol_error("get %s present status error, msg: %s" % (self.name, str(e))) ++ return STATUS_FAILED ++ ++ def get_status(self): ++ try: ++ rotor_num = self.get_fan_rotor_number() ++ err_motor_num = 0 ++ for j in range(rotor_num): ++ rotor_name = "Rotor" + str(j + 1) ++ roll_status = self.get_fan_rotor_status(rotor_name) ++ if roll_status is not True: ++ err_motor_num += 1 ++ ledcontrol_debug("%s %s error, status %s" % (self.name, rotor_name, roll_status)) ++ else: ++ ledcontrol_debug("%s %s ok" % (self.name, rotor_name)) ++ if err_motor_num > 0: ++ return STATUS_NOT_OK ++ return STATUS_OK ++ except Exception as e: ++ ledcontrol_error("get %s status error, msg: %s" % (self.name, str(e))) ++ return STATUS_FAILED ++ ++ def update_dev_info(self): ++ try: ++ # update status ++ self.present = self.get_present() ++ if self.present != STATUS_PRESENT: ++ self.status = STATUS_UNKNOWN ++ self.status_summary = self.present ++ else: ++ self.status = self.get_status() ++ self.status_summary = self.status ++ # update fru info if need air flow monitor ++ if self.air_flow_monitor: ++ dic = self.get_fan_fru_info() ++ self.origin_name = dic["PN"] ++ self.air_flow = dic["AirFlow"] ++ self.display_name = dic["DisplayName"] ++ except Exception as e: ++ ledcontrol_error("update %s fru info error, msg: %s" % (self.name, str(e))) ++ self.present = STATUS_FAILED ++ self.status = STATUS_FAILED ++ self.status_summary = STATUS_FAILED ++ self.origin_name = self.na_ret ++ self.air_flow = self.na_ret ++ self.display_name = self.na_ret ++ ++ def set_module_led(self, color): ++ ret = self.int_case.set_fan_led(self.name, color) ++ if ret == 0: ++ return True ++ return False ++ ++ ++class ledcontrol(object): ++ ++ def __init__(self): ++ self.fan_obj_list = [] ++ self.psu_obj_list = [] ++ self.board_psu_led_status = COLOR_GREEN ++ self.board_fan_led_status = COLOR_GREEN ++ self.__board_air_flow = "" ++ self.int_case = interface() ++ self.__config = baseutil.get_monitor_config() ++ self.__temps_threshold_config = self.__config["temps_threshold"] ++ for temp_threshold in self.__temps_threshold_config.values(): ++ temp_threshold['temp'] = 0 ++ temp_threshold['fail_num'] = 0 ++ self.__ledcontrol_para = self.__config["ledcontrol_para"] ++ self.__interval = self.__ledcontrol_para.get("interval", 5) ++ self.__checkpsu = self.__ledcontrol_para.get("checkpsu", 0) ++ self.__checkfan = self.__ledcontrol_para.get("checkfan", 0) ++ self.__psu_amber_num = self.__ledcontrol_para.get("psu_amber_num") ++ self.__fan_amber_num = self.__ledcontrol_para.get("fan_amber_num") ++ self.__psu_air_flow_amber_num = self.__ledcontrol_para.get("psu_air_flow_amber_num", 0) ++ self.__fan_air_flow_amber_num = self.__ledcontrol_para.get("fan_air_flow_amber_num", 0) ++ self.__board_sys_led = self.__ledcontrol_para.get("board_sys_led", []) ++ self.__board_psu_led = self.__ledcontrol_para.get("board_psu_led", []) ++ self.__board_fan_led = self.__ledcontrol_para.get("board_fan_led", []) ++ self.__psu_air_flow_monitor = self.__ledcontrol_para.get("psu_air_flow_monitor", 0) ++ self.__fan_air_flow_monitor = self.__ledcontrol_para.get("fan_air_flow_monitor", 0) ++ self.__fan_mix_list = self.__ledcontrol_para.get("fan_mix_list", []) ++ ++ @property ++ def na_ret(self): ++ return self.int_case.na_ret ++ ++ @property ++ def checkpsu(self): ++ return self.__checkpsu ++ ++ @property ++ def checkfan(self): ++ return self.__checkfan ++ ++ @property ++ def psu_amber_num(self): ++ return self.__psu_amber_num ++ ++ @property ++ def fan_amber_num(self): ++ return self.__fan_amber_num ++ ++ @property ++ def psu_air_flow_amber_num(self): ++ return self.__psu_air_flow_amber_num ++ ++ @property ++ def fan_air_flow_amber_num(self): ++ return self.__fan_air_flow_amber_num ++ ++ @property ++ def psu_air_flow_monitor(self): ++ return self.__psu_air_flow_monitor ++ ++ @property ++ def fan_air_flow_monitor(self): ++ return self.__fan_air_flow_monitor ++ ++ @property ++ def board_sys_led(self): ++ return self.__board_sys_led ++ ++ @property ++ def board_psu_led(self): ++ return self.__board_psu_led ++ ++ @property ++ def board_fan_led(self): ++ return self.__board_fan_led ++ ++ @property ++ def fan_mix_list(self): ++ return self.__fan_mix_list ++ ++ @property ++ def interval(self): ++ return self.__interval ++ ++ def get_fan_total_number(self): ++ return self.int_case.get_fan_total_number() ++ ++ def get_psu_total_number(self): ++ return self.int_case.get_psu_total_number() ++ ++ def get_onie_e2_obj(self, name): ++ return self.int_case.get_onie_e2_obj(name) ++ ++ def set_led_color(self, led_name, color): ++ try: ++ ret = self.int_case.set_led_color(led_name, color) ++ except Exception as e: ++ ledcontrol_error("set %s led %s error, msg: %s" % (led_name, color, str(e))) ++ ret = False ++ return ret ++ ++ def set_sys_led(self, color): ++ for led in self.board_sys_led: ++ led_name = led.get("led_name") ++ ret = self.set_led_color(led_name, color) ++ if ret is True: ++ ledcontrol_debug("set %s success, color:%s," % (led_name, color)) ++ else: ++ ledcontrol_debug("set %s failed, color:%s," % (led_name, color)) ++ ++ def set_psu_led(self, color): ++ for led in self.board_psu_led: ++ led_name = led.get("led_name") ++ ret = self.set_led_color(led_name, color) ++ if ret is True: ++ ledcontrol_debug("set %s success, color:%s," % (led_name, color)) ++ else: ++ ledcontrol_debug("set %s failed, color:%s," % (led_name, color)) ++ ++ def set_fan_led(self, color): ++ for led in self.board_fan_led: ++ led_name = led.get("led_name") ++ ret = self.set_led_color(led_name, color) ++ if ret is True: ++ ledcontrol_debug("set %s success, color:%s," % (led_name, color)) ++ else: ++ ledcontrol_debug("set %s failed, color:%s," % (led_name, color)) ++ ++ def set_fan_module_led(self): ++ for fan_obj in self.fan_obj_list: ++ color = LED_STATUS_DICT.get(fan_obj.led_status) ++ ret = fan_obj.set_module_led(color) ++ if ret is True: ++ ledcontrol_debug("set %s module led success, color: %s," % (fan_obj.name, color)) ++ else: ++ ledcontrol_debug("set %s module led failed, color: %s," % (fan_obj.name, color)) ++ ++ @property ++ def board_air_flow(self): ++ air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) ++ if self.__board_air_flow not in air_flow_tuple: ++ self.__board_air_flow = self.int_case.get_device_airflow(ONIE_E2_NAME) ++ ledcontrol_debug("board_air_flow: %s" % self.__board_air_flow) ++ return self.__board_air_flow ++ ++ def update_psu_info(self): ++ for psu_obj in self.psu_obj_list: ++ psu_obj.update_dev_info() ++ ledcontrol_debug("%s present: [%s], status: [%s] status_summary [%s]" % ++ (psu_obj.name, psu_obj.present, psu_obj.status, psu_obj.status_summary)) ++ if psu_obj.air_flow_monitor: ++ ledcontrol_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % ++ (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow)) ++ ++ def update_fan_info(self): ++ for fan_obj in self.fan_obj_list: ++ fan_obj.update_dev_info() ++ ledcontrol_debug("%s present: [%s], status: [%s] status_summary [%s]" % ++ (fan_obj.name, fan_obj.present, fan_obj.status, fan_obj.status_summary)) ++ if fan_obj.air_flow_monitor: ++ ledcontrol_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % ++ (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow)) ++ ++ def get_monitor_temp(self): ++ sensorlist = self.int_case.get_temp_info() ++ ++ for temp_threshold in self.__temps_threshold_config.values(): ++ sensor = sensorlist.get(temp_threshold['name']) ++ if sensor["Value"] is None: ++ temp_threshold['fail_num'] += 1 ++ ledcontrol_error("get %s failed, fail_num = %d" % (temp_threshold['name'], temp_threshold['fail_num'])) ++ else: ++ temp_threshold['fail_num'] = 0 ++ temp_threshold.setdefault('fix', 0) ++ temp_threshold['temp'] = sensor["Value"] + temp_threshold['fix'] ++ ledcontrol_debug("%s = %d" % (temp_threshold['name'], temp_threshold['temp'])) ++ ledcontrol_debug("warning = %d, critical = %d" % (temp_threshold['warning'], temp_threshold['critical'])) ++ ++ def is_temp_warning(self): ++ warning_flag = False ++ for temp_threshold in self.__temps_threshold_config.values(): ++ if temp_threshold['temp'] >= temp_threshold['warning']: ++ warning_flag = True ++ ledcontrol_debug("%s is over warning" % temp_threshold['name']) ++ ledcontrol_debug( ++ "%s = %d, warning = %d" % ++ (temp_threshold['name'], ++ temp_threshold['temp'], ++ temp_threshold['warning'])) ++ return warning_flag ++ ++ def checkTempWarning(self): ++ try: ++ if self.is_temp_warning(): ++ ledcontrol_debug("temp is over warning") ++ return True ++ except Exception as e: ++ ledcontrol_error("%%policy: checkTempWarning failed") ++ ledcontrol_error(str(e)) ++ return False ++ ++ def is_temp_critical(self): ++ critical_flag = False ++ for temp_threshold in self.__temps_threshold_config.values(): ++ temp_threshold['critical_flag'] = False ++ if temp_threshold['temp'] >= temp_threshold['critical']: ++ critical_flag = True ++ temp_threshold['critical_flag'] = True ++ ledcontrol_debug("%s is over critical" % temp_threshold['name']) ++ ledcontrol_debug( ++ "%s = %d, critical = %d" % ++ (temp_threshold['name'], ++ temp_threshold['temp'], ++ temp_threshold['critical'])) ++ return critical_flag ++ ++ def checkTempCrit(self): ++ try: ++ if self.is_temp_critical(): ++ temp_dict = dict(self.__temps_threshold_config) ++ tmp = temp_dict.get(SWITCH_TEMP) ++ if tmp['critical_flag'] is True: ++ ledcontrol_debug("temp is over critical") ++ return True ++ ++ del temp_dict[SWITCH_TEMP] ++ for temp_items in temp_dict.values(): ++ if temp_items['critical_flag'] is False: ++ return False ++ ++ ledcontrol_debug("temp is over critical") ++ return True ++ except Exception as e: ++ ledcontrol_error("%%policy: checkTempCrit failed") ++ ledcontrol_error(str(e)) ++ return False ++ ++ def check_board_air_flow(self): ++ board_air_flow = self.board_air_flow ++ air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) ++ if board_air_flow not in air_flow_tuple: ++ air_flow_error("%%AIR_FLOW_MONITOR-3-BOARD: Get board air flow failed, value: %s." % board_air_flow) ++ return False ++ ledcontrol_debug("board air flow check ok: %s" % board_air_flow) ++ return True ++ ++ def get_monitor_fan_status(self): ++ fanerrnum = 0 ++ for fan_obj in self.fan_obj_list: ++ status = fan_obj.status_summary ++ ledcontrol_debug("%s status: %s" % (fan_obj.name, status)) ++ if status != STATUS_OK: ++ fan_obj.led_status = COLOR_RED ++ fanerrnum += 1 ++ else: ++ fan_obj.led_status = COLOR_GREEN ++ ledcontrol_debug("fan error number: %d" % fanerrnum) ++ ++ if fanerrnum == 0: ++ fan_led_status = COLOR_GREEN ++ elif fanerrnum <= self.fan_amber_num: ++ fan_led_status = COLOR_AMBER ++ else: ++ fan_led_status = COLOR_RED ++ ledcontrol_debug("monitor fan status, set fan led: %s" % LED_STATUS_DICT.get(fan_led_status)) ++ return fan_led_status ++ ++ def get_monitor_psu_status(self): ++ psuerrnum = 0 ++ for psu_obj in self.psu_obj_list: ++ status = psu_obj.status_summary ++ ledcontrol_debug("%s status: %s" % (psu_obj.name, status)) ++ if status != STATUS_OK: ++ psu_obj.led_status = COLOR_RED ++ psuerrnum += 1 ++ else: ++ psu_obj.led_status = COLOR_GREEN ++ ledcontrol_debug("psu error number: %d" % psuerrnum) ++ ++ if psuerrnum == 0: ++ psu_led_status = COLOR_GREEN ++ elif psuerrnum <= self.psu_amber_num: ++ psu_led_status = COLOR_AMBER ++ else: ++ psu_led_status = COLOR_RED ++ ledcontrol_debug("monitor psu status, set psu led: %s" % LED_STATUS_DICT.get(psu_led_status)) ++ return psu_led_status ++ ++ def get_monitor_fan_air_flow(self): ++ if self.fan_air_flow_monitor == 0: ++ ledcontrol_debug("fan air flow monitor not open, default green") ++ return COLOR_GREEN ++ ++ ret = self.check_board_air_flow() ++ if ret is False: ++ ledcontrol_debug("check board air flow error, skip fan air flow monitor.") ++ return COLOR_GREEN ++ ++ fan_led_status_list = [] ++ fan_air_flow_ok_obj_list = [] ++ fan_air_flow_ok_set = set() ++ fan_module_led_list = [] ++ fan_air_flow_err_num = 0 ++ for fan_obj in self.fan_obj_list: ++ if fan_obj.present != STATUS_PRESENT: ++ fan_module_led_list.append(COLOR_GREEN) ++ continue ++ if fan_obj.air_flow == self.na_ret: ++ air_flow_warn("%%AIR_FLOW_MONITOR-4-FAN: %s get air flow failed, fan model: %s, air flow: %s." % ++ (fan_obj.name, fan_obj.display_name, fan_obj.air_flow)) ++ led_status = COLOR_AMBER ++ fan_module_led_list.append(led_status) ++ elif fan_obj.air_flow != self.board_air_flow: ++ air_flow_emerg("%%AIR_FLOW_MONITOR-0-FAN: %s air flow error, fan model: %s, fan air flow: %s, board air flow: %s." % ++ (fan_obj.name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) ++ led_status = COLOR_RED ++ fan_air_flow_err_num += 1 ++ else: ++ fan_air_flow_ok_obj_list.append(fan_obj) ++ fan_air_flow_ok_set.add(fan_obj.origin_name) ++ ledcontrol_debug("%s air flow check ok, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s]" % ++ (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) ++ led_status = COLOR_GREEN ++ fan_module_led_list.append(led_status) ++ if led_status > fan_obj.led_status: ++ fan_obj.led_status = led_status ++ if len(fan_module_led_list) != 0: ++ fan_led_status = max(fan_module_led_list) ++ fan_led_status_list.append(fan_led_status) ++ # check fan mixing ++ if len(fan_air_flow_ok_set) > 1 and fan_air_flow_ok_set not in self.fan_mix_list: ++ for fan_obj in fan_air_flow_ok_obj_list: ++ air_flow_warn("%%AIR_FLOW_MONITOR-4-FAN: %s mixing, fan model: %s, air flow: %s." % ++ (fan_obj.name, fan_obj.origin_name, fan_obj.air_flow)) ++ fan_led_status = COLOR_AMBER ++ fan_led_status_list.append(fan_led_status) ++ # check fan air flow error number ++ if fan_air_flow_err_num == 0: ++ fan_led_status = COLOR_GREEN ++ elif fan_air_flow_err_num <= self.fan_air_flow_amber_num: ++ fan_led_status = COLOR_AMBER ++ else: ++ fan_led_status = COLOR_RED ++ fan_led_status_list.append(fan_led_status) ++ ++ fan_led_status = max(fan_led_status_list) ++ ledcontrol_debug("monitor fan air flow, set fan led: %s" % LED_STATUS_DICT.get(fan_led_status)) ++ return fan_led_status ++ ++ def get_monitor_psu_air_flow(self): ++ if self.psu_air_flow_monitor == 0: ++ ledcontrol_debug("psu air flow monitor not open, default green") ++ return COLOR_GREEN ++ ++ ret = self.check_board_air_flow() ++ if ret is False: ++ ledcontrol_debug("check board air flow error, skip psu air flow monitor.") ++ return COLOR_GREEN ++ ++ psu_led_status_list = [] ++ psu_module_led_list = [] ++ psu_air_flow_err_num = 0 ++ for psu_obj in self.psu_obj_list: ++ if psu_obj.present != STATUS_PRESENT: ++ psu_module_led_list.append(COLOR_GREEN) ++ continue ++ if psu_obj.air_flow == self.na_ret: ++ air_flow_warn("%%AIR_FLOW_MONITOR-4-PSU: %s get air flow failed, psu model: %s, air flow: %s." % ++ (psu_obj.name, psu_obj.display_name, psu_obj.air_flow)) ++ led_status = COLOR_AMBER ++ psu_module_led_list.append(led_status) ++ elif psu_obj.air_flow != self.board_air_flow: ++ air_flow_emerg("%%AIR_FLOW_MONITOR-0-PSU: %s air flow error, psu model: %s, psu air flow: %s, board air flow: %s." % ++ (psu_obj.name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) ++ led_status = COLOR_RED ++ psu_air_flow_err_num += 1 ++ else: ++ ledcontrol_debug("%s psu air flow check ok, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s]" % ++ (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) ++ led_status = COLOR_GREEN ++ psu_module_led_list.append(led_status) ++ if led_status > psu_obj.led_status: ++ psu_obj.led_status = led_status ++ ++ if len(psu_module_led_list) != 0: ++ psu_led_status = max(psu_module_led_list) ++ psu_led_status_list.append(psu_led_status) ++ ++ # check fan air flow error number ++ if psu_air_flow_err_num == 0: ++ psu_led_status = COLOR_GREEN ++ elif psu_air_flow_err_num <= self.psu_air_flow_amber_num: ++ psu_led_status = COLOR_AMBER ++ else: ++ psu_led_status = COLOR_RED ++ psu_led_status_list.append(psu_led_status) ++ ++ psu_led_status = max(psu_led_status_list) ++ ledcontrol_debug("monitor psu air flow, set psu led: %s" % LED_STATUS_DICT.get(psu_led_status)) ++ return psu_led_status ++ ++ def get_temp_sys_led_status(self): ++ if self.checkTempCrit() is True: ++ sys_led_status = COLOR_RED ++ elif self.checkTempWarning() is True: ++ sys_led_status = COLOR_AMBER ++ else: ++ sys_led_status = COLOR_GREEN ++ ledcontrol_debug("monitor temperature, set sys led: %s" % LED_STATUS_DICT.get(sys_led_status)) ++ return sys_led_status ++ ++ def get_sys_led_follow_fan_status(self): ++ ++ if self.checkfan: ++ sys_led_status = self.board_fan_led_status ++ ledcontrol_debug("sys led follow fan led, set sys led: %s" % LED_STATUS_DICT.get(sys_led_status)) ++ else: ++ sys_led_status = COLOR_GREEN ++ ledcontrol_debug("sys led don't follow fan led, set default green") ++ return sys_led_status ++ ++ def get_sys_led_follow_psu_status(self): ++ if self.checkpsu: ++ sys_led_status = self.board_psu_led_status ++ ledcontrol_debug("sys led follow psu led, set sys led: %s" % LED_STATUS_DICT.get(sys_led_status)) ++ else: ++ sys_led_status = COLOR_GREEN ++ ledcontrol_debug("sys led don't follow psu led, set default green") ++ return sys_led_status ++ ++ def dealSysLedStatus(self): ++ sys_led_status_list = [] ++ # get_monitor_temp ++ self.get_monitor_temp() ++ ++ # monitor temp get sys led status ++ sys_led_status = self.get_temp_sys_led_status() ++ sys_led_status_list.append(sys_led_status) ++ ++ # check sys led follow fan led status ++ sys_led_status = self.get_sys_led_follow_fan_status() ++ sys_led_status_list.append(sys_led_status) ++ ++ # check sys led follow psu led status ++ sys_led_status = self.get_sys_led_follow_psu_status() ++ sys_led_status_list.append(sys_led_status) ++ ++ sys_led_status = max(sys_led_status_list) ++ sys_led_color = LED_STATUS_DICT.get(sys_led_status) ++ ++ # set sys led ++ self.set_sys_led(sys_led_color) ++ ++ def dealFanLedStatus(self): ++ fan_led_status_list = [] ++ # update fan info ++ self.update_fan_info() ++ ++ # monitor fan status first ++ fan_led_status = self.get_monitor_fan_status() ++ fan_led_status_list.append(fan_led_status) ++ ++ # monitor fan air flow ++ fan_led_status = self.get_monitor_fan_air_flow() ++ fan_led_status_list.append(fan_led_status) ++ ++ self.board_fan_led_status = max(fan_led_status_list) ++ fan_led_color = LED_STATUS_DICT.get(self.board_fan_led_status) ++ ++ # set fan led ++ self.set_fan_led(fan_led_color) ++ # set fan module led ++ self.set_fan_module_led() ++ ++ def dealPsuLedStatus(self): ++ psu_led_status_list = [] ++ # update psu info ++ self.update_psu_info() ++ ++ # monitor psu status first ++ psu_led_status = self.get_monitor_psu_status() ++ psu_led_status_list.append(psu_led_status) ++ ++ # monitor psu air flow ++ psu_led_status = self.get_monitor_psu_air_flow() ++ psu_led_status_list.append(psu_led_status) ++ ++ self.board_psu_led_status = max(psu_led_status_list) ++ psu_led_color = LED_STATUS_DICT.get(self.board_psu_led_status) ++ ++ # set psu led ++ self.set_psu_led(psu_led_color) ++ ++ def do_ledcontrol(self): ++ self.dealPsuLedStatus() ++ self.dealFanLedStatus() ++ self.dealSysLedStatus() ++ ++ def fan_obj_init(self): ++ fan_num = self.get_fan_total_number() ++ for i in range(fan_num): ++ fan_name = "FAN" + str(i + 1) ++ fan_obj = DevFan(fan_name, self.fan_air_flow_monitor, self.int_case) ++ self.fan_obj_list.append(fan_obj) ++ ledcontrol_debug("fan object initialize success") ++ ++ def psu_obj_init(self): ++ psu_num = self.get_psu_total_number() ++ for i in range(psu_num): ++ psu_name = "PSU" + str(i + 1) ++ psu_obj = DevPsu(psu_name, self.psu_air_flow_monitor, self.int_case) ++ self.psu_obj_list.append(psu_obj) ++ ledcontrol_debug("psu object initialize success") ++ ++ def run(self): ++ while True: ++ try: ++ debug_init() ++ self.do_ledcontrol() ++ time.sleep(self.interval) ++ except Exception as e: ++ traceback.print_exc() ++ ledcontrol_error(str(e)) ++ ++ ++if __name__ == '__main__': ++ debug_init() ++ ledcontrol_debug("enter main") ++ led_control = ledcontrol() ++ led_control.fan_obj_init() ++ led_control.psu_obj_init() ++ led_control.run() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/hal_pltfm.py b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_pltfm.py +new file mode 100755 +index 000000000..11196f507 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_pltfm.py +@@ -0,0 +1,492 @@ ++#!/usr/bin/env python3 ++# -*- coding: UTF-8 -*- ++import inspect ++import sys ++import json ++import time ++from plat_hal.interface import interface ++ ++ ++class Command(): ++ def __init__(self, name, f): ++ self.name = name ++ self.f = f ++ self.paramcount = self.f.__code__.co_argcount ++ ++ def dofun(self, args): ++ fn = self.f.__call__ ++ fn(*args) ++ ++ ++class Group(): ++ def __init__(self, name, f): ++ self.groups = [] ++ self.commands = [] ++ self.name = name ++ self.f = f ++ ++ def add_groups(self, command): ++ self.groups.append(command) ++ ++ def add_commands(self, commnad): ++ x = Command(commnad.__name__, commnad) ++ self.commands.append(x) ++ ++ def find_valuebyname(self, name): ++ for item in self.groups: ++ if name == item.name: ++ return item ++ for item in self.commands: ++ if name == item.name: ++ return item ++ return None ++ ++ def deal(self, args): ++ if len(args) <= 0: ++ return self.print_help() ++ funclevel = args[0] ++ val = self.find_valuebyname(funclevel) ++ if val is None: ++ return self.print_help() ++ if isinstance(val, Command): ++ if len(args) < (val.paramcount + 1): ++ return self.print_help() ++ inputargs = args[1: (1 + val.paramcount)] ++ return val.dofun(inputargs) ++ if isinstance(val, Group): ++ args = args[1:] ++ return val.deal(args) ++ return self.print_help() ++ ++ def get_max(self, arr): ++ lentmp = 0 ++ for ar in arr: ++ lentmp = len(ar) if (len(ar) > lentmp) else lentmp ++ return lentmp ++ ++ def print_help(self): ++ ++ namesize = [] ++ for item in self.groups: ++ namesize.append(item.name) ++ for item in self.commands: ++ namesize.append(item.name) ++ maxvalue = self.get_max(namesize) ++ ++ if len(self.groups) > 0: ++ print("Groups:") ++ for item in self.groups: ++ print(" %-*s %s" % (maxvalue, item.name, item.f.__doc__ or '')) ++ if len(self.commands) > 0: ++ print("Commands:") ++ for item in self.commands: ++ print(" %-*s %s" % (maxvalue, item.name, item.f.__doc__ or '')) ++ ++ ++class clival(): ++ @staticmethod ++ def Fire(val=None): ++ group = Group("top", 'mainlevel') ++ clival.iterGroup(val, group) ++ # context = {} ++ # caller = inspect.stack()[1] ++ # caller_frame = caller[0] ++ # caller_globals = caller_frame.f_globals ++ # caller_locals = caller_frame.f_locals ++ # context.update(caller_globals) ++ # context.update(caller_locals) ++ args = sys.argv[1:] ++ group.deal(args) ++ ++ @staticmethod ++ def iterGroup(val, group): ++ for key, item in val.items(): ++ if item is None: # first level ++ if inspect.isfunction(key): ++ group.add_commands(key) ++ else: ++ group1 = Group(key.__name__, key) ++ clival.iterGroup(item, group1) ++ group.add_groups(group1) ++ ++ ++def psu(): ++ r'''test psu ''' ++ ++ ++def fan(): ++ r'''test fan ''' ++ ++ ++def sensor(): ++ r'''test sensor ''' ++ ++ ++def dcdc(): ++ r'''test dcdc ''' ++ ++ ++def led(): ++ r'''test led ''' ++ ++ ++def e2(): ++ r'''test onie eeprom ''' ++ ++ ++def temps(): ++ r'''test temps sensor''' ++ ++def cpu(): ++ r'''test cpu''' ++ ++ ++int_case = interface() ++ ++ ++def get_total_number(): ++ r'''psu get_total_number ''' ++ print("=================get_total_number======================") ++ print(int_case.get_psu_total_number()) ++ ++ ++def get_presence(): ++ r'''psu get_presence ''' ++ print("=================get_presence======================") ++ psus = int_case.get_psus() ++ for psu_item in psus: ++ print(psu_item.name, end=' ') ++ print(int_case.get_psu_presence(psu_item.name)) ++ ++ ++def get_fru_info(): ++ r'''psu get_fru_info ''' ++ print("=================get_fru_info======================") ++ psus = int_case.get_psus() ++ for psu_item in psus: ++ print(psu_item.name, end=' ') ++ print(json.dumps(int_case.get_psu_fru_info(psu_item.name), ensure_ascii=False, indent=4)) ++ ++ ++def get_status(): ++ r'''psu get_status ''' ++ print("=================get_status======================") ++ psus = int_case.get_psus() ++ for psu_item in psus: ++ print(psu_item.name, end=' ') ++ print(json.dumps(int_case.get_psu_status(psu_item.name), ensure_ascii=False, indent=4)) ++ ++ ++def set_psu_fan_speed_pwm(realspeed): ++ r'''set_psu_fan_speed_pwm''' ++ print("=================set_psu_fan_speed_pwm======================") ++ psus = int_case.get_psus() ++ for psu_item in psus: ++ print(psu_item.name, end=' ') ++ print(int_case.set_psu_fan_speed_pwm(psu_item.name, int(realspeed))) ++ ++ ++def get_psu_fan_speed_pwm(): ++ r'''get_psu_fan_speed_pwm''' ++ print("=================get_psu_fan_speed_pwm======================") ++ psus = int_case.get_psus() ++ for psu_item in psus: ++ print(psu_item.name, end=' ') ++ print(json.dumps(int_case.get_psu_fan_speed_pwm(psu_item.name))) ++ ++ ++def get_psu_power_status(): ++ r'''psu get_psu_power_status ''' ++ print("=================get_psu_power_status======================") ++ psus = int_case.get_psus() ++ for psu_item in psus: ++ print(psu_item.name, end=' ') ++ print(json.dumps(int_case.get_psu_power_status(psu_item.name), ensure_ascii=False, indent=4)) ++ ++ ++def get_info_all(): ++ r'''psu get_info_all ''' ++ print("=================get_info_all======================") ++ print(json.dumps(int_case.get_psu_info_all(), ensure_ascii=False, indent=4)) ++ ++ ++def fan_get_total_number(): ++ print("=================get_info_all======================") ++ print(json.dumps(int_case.get_fan_total_number(), ensure_ascii=False, indent=4)) ++ ++ ++def fan_get_rotor_number(): ++ r'''fan_get_rotor_number''' ++ print("=================fan_get_rotor_number======================") ++ fans = int_case.get_fans() ++ for fan_item in fans: ++ print(fan_item.name, end=' ') ++ print(int_case.get_fan_rotor_number(fan_item.name)) ++ ++ ++def fan_get_speed(): ++ r'''fan_get_speed''' ++ print("=================fan_get_speed======================") ++ fans = int_case.get_fans() ++ for fan_item in fans: ++ rotors = fan_item.rotor_list ++ for rotor in rotors: ++ index = rotors.index(rotor) ++ print("%s rotor%d" % (fan_item.name, index + 1), end=' ') ++ print(int_case.get_fan_speed(fan_item.name, index + 1)) ++ ++ ++def fan_get_speed_pwm(): ++ r'''fan_get_speed_pwm''' ++ print("=================fan_get_speed_pwm======================") ++ fans = int_case.get_fans() ++ for fan_item in fans: ++ rotors = fan_item.rotor_list ++ for rotor in rotors: ++ index = rotors.index(rotor) ++ print("%s rotor%d" % (fan_item.name, index + 1), end=' ') ++ print(int_case.get_fan_speed_pwm(fan_item.name, index + 1)) ++ ++ ++def fan_set_speed_pwm(pwm): ++ r'''fan_set_speed_pwm''' ++ print("=================fan_set_speed_pwm======================") ++ fans = int_case.get_fans() ++ for fan_item in fans: ++ rotors = fan_item.rotor_list ++ for rotor in rotors: ++ index = rotors.index(rotor) ++ print("%s %s" % (fan_item.name, rotor.name), end=' ') ++ val = int_case.set_fan_speed_pwm(fan_item.name, index + 1, pwm) ++ print(val) ++ ++ ++def fan_get_watchdog_status(): ++ r'''fan_get_watchdog_status''' ++ print("=================fan_get_watchdog_status======================") ++ print(int_case.get_fan_watchdog_status()) ++ ++ ++def fan_enable_watchdog(): ++ r'''fan_enable_watchdog''' ++ print("=================fan_enable_watchdog======================") ++ print('enable', int_case.enable_fan_watchdog()) ++ ++ ++def fan_disable_watchdog(): ++ r'''fan_disable_watchdog''' ++ print("=================fan_disable_watchdog======================") ++ print('disable', int_case.enable_fan_watchdog(enable=False)) ++ ++ ++def fan_get_speed1(): ++ r'''fan_get_speed''' ++ print("=================fan_get_speed======================") ++ fans = int_case.get_fans() ++ for fan_item in fans: ++ rotors = fan_item.rotor_list ++ for rotor in rotors: ++ print("%s %s" % (fan_item.name, rotor.name), end=' ') ++ print(int_case.get_fan_speed(fan_item.name, rotor.name)) ++ ++ ++def fan_feed_watchdog(): ++ r'''fan_feed_watchdog''' ++ print("=================fan_feed_watchdog======================") ++ fan_get_speed() ++ print(int_case.feed_fan_watchdog()) ++ time.sleep(2) ++ fan_get_speed() ++ ++ ++def fan_set_led(color): ++ r'''fan_set_led''' ++ print("=================fan_set_led======================") ++ fans = int_case.get_fans() ++ for fan_item in fans: ++ print("%s" % fan_item.name) ++ print(color, int_case.set_fan_led(fan_item.name, color)) ++ ++def fan_get_led(): ++ r'''fan_get_led''' ++ print("=================fan_get_led======================") ++ fans = int_case.get_fans() ++ for fan_item in fans: ++ print("%s" % fan_item.name) ++ print(int_case.get_fan_led(fan_item.name)) ++ ++ ++def fan_get_presence(): ++ r'''fan_get_presence''' ++ print("=================fan_get_presence======================") ++ fans = int_case.get_fans() ++ for fan_item in fans: ++ print("%s" % fan_item.name) ++ print(int_case.get_fan_presence(fan_item.name)) ++ ++ ++def fan_get_info(): ++ r'''fan_get_info''' ++ print("=================fan_get_info======================") ++ fans = int_case.get_fans() ++ for fan_item in fans: ++ print("%s" % fan_item.name) ++ print(json.dumps(int_case.get_fan_info(fan_item.name), ensure_ascii=False, indent=4)) ++ ++ ++def fan_get_status(): ++ r'''fan_get_status''' ++ print("=================fan_get_status======================") ++ fans = int_case.get_fans() ++ for fan_item in fans: ++ print("%s" % fan_item.name) ++ print(json.dumps(int_case.get_fan_status(fan_item.name), ensure_ascii=False, indent=4)) ++ ++ ++def fan_get_info_all(): ++ r'''fan_get_info_all''' ++ print("=================fan_get_info_all======================") ++ print(json.dumps(int_case.get_fan_info_all(), ensure_ascii=False, indent=4)) ++ ++ ++def get_sensor_info(): ++ r'''get_sensor_info''' ++ print("=================get_sensor_info======================") ++ print(json.dumps(int_case.get_sensor_info(), ensure_ascii=False, indent=4)) ++ ++ ++def get_dcdc_all_info(): ++ r'''get_dcdc_all_info''' ++ print("=================get_dcdc_all_info======================") ++ print(json.dumps(int_case.get_dcdc_all_info(), ensure_ascii=False, indent=4)) ++ ++ ++def set_all_led_color(color): ++ r'''set_all_led_color color''' ++ print("=================set_all_led_color======================") ++ leds = int_case.get_leds() ++ for led_item in leds: ++ print("%s" % led_item.name) ++ print(color, int_case.set_led_color(led_item.name, color)) ++ ++ ++def get_all_led_color(): ++ r'''get_all_led_color''' ++ print("=================get_all_led_color======================") ++ leds = int_case.get_leds() ++ for led_item in leds: ++ print("%s" % led_item.name) ++ print(int_case.get_led_color(led_item.name)) ++ ++ ++def set_single_led_color(led_name, color): ++ r'''set_single_led_color led_name color''' ++ print("=================set_single_led_color======================") ++ leds = int_case.get_leds() ++ for led_item in leds: ++ if led_name == led_item.name: ++ print("%s" % led_item.name) ++ print(color, int_case.set_led_color(led_item.name, color)) ++ ++ ++def get_single_led_color(led_name): ++ r'''get_single_led_color''' ++ print("=================get_single_led_color======================") ++ leds = int_case.get_leds() ++ for led_item in leds: ++ if led_name == led_item.name: ++ print("%s" % led_item.name) ++ print(int_case.get_led_color(led_item.name)) ++ ++ ++def get_onie_e2_path(): ++ r'''get_onie_e2_path''' ++ print("=================get_onie_e2_path======================") ++ path = int_case.get_onie_e2_path("ONIE_E2") ++ print("%s" % path) ++ ++ ++def get_device_airflow(): ++ r'''get_device_airflow''' ++ print("=================get_device_airflow======================") ++ airflow = int_case.get_device_airflow("ONIE_E2") ++ print("%s" % airflow) ++ ++ ++def get_temps_sensor(): ++ r'''get_temps_sensor''' ++ print("=================get_temps_sensor======================") ++ temp_list = int_case.get_temps() ++ for temp in temp_list: ++ print("id: %s, name: %s, API name: %s, value: %s" % (temp.temp_id, temp.name, temp.api_name, temp.Value)) ++ ++def get_cpu_reset_num(): ++ r'''get_cpu_reset_num''' ++ print("=================get_cpu_reset_num======================") ++ print(int_case.get_cpu_reset_num()) ++ ++def get_cpu_reboot_cause(): ++ r'''get_cpu_reboot_cause''' ++ print("=================get_cpu_reboot_cause======================") ++ print(int_case.get_cpu_reboot_cause()) ++ ++ ++def run_cli_man(): ++ clival.Fire( ++ { ++ psu: { ++ get_total_number: None, ++ get_presence: None, ++ get_fru_info: None, ++ set_psu_fan_speed_pwm: None, ++ get_psu_fan_speed_pwm: None, ++ get_status: None, ++ get_psu_power_status: None, ++ get_info_all: None ++ }, ++ fan: { ++ fan_get_total_number: None, ++ fan_get_rotor_number: None, ++ fan_get_speed: None, ++ fan_get_speed_pwm: None, ++ fan_set_speed_pwm: None, ++ fan_get_watchdog_status: None, ++ fan_enable_watchdog: None, ++ fan_disable_watchdog: None, ++ fan_feed_watchdog: None, ++ fan_set_led: None, ++ fan_get_led: None, ++ fan_get_presence: None, ++ fan_get_info: None, ++ fan_get_status: None, ++ fan_get_info_all: None ++ }, ++ sensor: { ++ get_sensor_info: None ++ }, ++ dcdc: { ++ get_dcdc_all_info: None ++ }, ++ led: { ++ set_all_led_color: None, ++ set_single_led_color: None, ++ get_all_led_color: None, ++ get_single_led_color: None, ++ }, ++ e2: { ++ get_onie_e2_path: None, ++ get_device_airflow: None, ++ }, ++ temps: { ++ get_temps_sensor: None, ++ }, ++ cpu: { ++ get_cpu_reset_num: None, ++ get_cpu_reboot_cause: None, ++ } ++ } ++ ) ++ ++ ++if __name__ == '__main__': ++ run_cli_man() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor.py b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor.py +new file mode 100755 +index 000000000..33d5bfba6 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor.py +@@ -0,0 +1,144 @@ ++#!/usr/bin/python3 ++# -*- coding: UTF-8 -*- ++ ++import os ++import time ++import syslog ++from plat_hal.interface import interface ++from plat_hal.baseutil import baseutil ++from platform_util import io_rd, wbi2cget ++ ++INTELLIGENT_MONITOR_DEBUG_FILE = "/etc/.intelligent_monitor_debug" ++ ++debuglevel = 0 ++ ++ ++def monitor_syslog_debug(s): ++ if debuglevel: ++ syslog.openlog("INTELLIGENT_MONITOR_DEBUG", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def monitor_syslog(s): ++ syslog.openlog("INTELLIGENT_MONITOR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_WARNING, s) ++ ++ ++def pmon_syslog_notice(s): ++ syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_NOTICE, s) ++ ++ ++class IntelligentMonitor(): ++ def __init__(self): ++ self.dcdc_dict = {} ++ self.int_case = interface() ++ self.__config = baseutil.get_monitor_config() ++ self.__intelligent_monitor_para = self.__config.get('intelligent_monitor_para', {}) ++ self.__interval = self.__intelligent_monitor_para.get('interval', 60) ++ self.__dcdc_whitelist = self.__config.get('dcdc_monitor_whitelist', {}) ++ self.__error_ret = self.int_case.error_ret ++ ++ @property ++ def error_ret(self): ++ return self.__error_ret ++ ++ @property ++ def interval(self): ++ return self.__interval ++ ++ def debug_init(self): ++ global debuglevel ++ if os.path.exists(INTELLIGENT_MONITOR_DEBUG_FILE): ++ debuglevel = 1 ++ else: ++ debuglevel = 0 ++ ++ def dcdc_whitelist_check(self, dcdc_name): ++ try: ++ check_item = self.__dcdc_whitelist.get(dcdc_name, {}) ++ if len(check_item) == 0: ++ return False ++ gettype = check_item.get("gettype", None) ++ checkbit = check_item.get("checkbit", None) ++ okval = check_item.get("okval", None) ++ if gettype is None or checkbit is None or okval is None: ++ monitor_syslog('%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s config error. gettype:%s, checkbit:%s, okval:%s' % ++ (dcdc_name, gettype, checkbit, okval)) ++ return False ++ if gettype == "io": ++ io_addr = check_item.get('io_addr', None) ++ val = io_rd(io_addr) ++ if val is not None: ++ retval = val ++ else: ++ monitor_syslog( ++ '%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s io_rd error. io_addr:%s' % ++ (dcdc_name, io_addr)) ++ return False ++ elif gettype == "i2c": ++ bus = check_item.get('bus', None) ++ addr = check_item.get('addr', None) ++ offset = check_item.get('offset', None) ++ ind, val = wbi2cget(bus, addr, offset) ++ if ind is True: ++ retval = val ++ else: ++ monitor_syslog('%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s i2cget error. bus:%s, addr:%s, offset:%s' % ++ (dcdc_name, bus, addr, offset)) ++ return False ++ else: ++ monitor_syslog('%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s gettype not support' % dcdc_name) ++ return False ++ ++ val_t = (int(retval, 16) & (1 << checkbit)) >> checkbit ++ if val_t != okval: ++ return False ++ return True ++ except Exception as e: ++ monitor_syslog('%%WHITELIST_CHECK: %s check error, msg: %s.' % (dcdc_name, str(e))) ++ return False ++ ++ def update_dcdc_status(self): ++ try: ++ self.dcdc_dict = self.int_case.get_dcdc_all_info() ++ for dcdc_name, item in self.dcdc_dict.items(): ++ ret = self.dcdc_whitelist_check(dcdc_name) ++ if ret is False: ++ if item['Value'] == self.error_ret: ++ monitor_syslog( ++ '%%INTELLIGENT_MONITOR-3-DCDC_SENSOR_FAILED: The value of %s read failed.' % ++ (dcdc_name)) ++ elif float(item['Value']) > float(item['Max']): ++ pmon_syslog_notice('%%PMON-5-VOLTAGE_HIGH: %s voltage %.3f%s is larger than max threshold %.3f%s.' % ++ (dcdc_name, float(item['Value']), item['Unit'], float(item['Max']), item['Unit'])) ++ elif float(item['Value']) < float(item['Min']): ++ pmon_syslog_notice('%%PMON-5-VOLTAGE_LOW: %s voltage %.3f%s is lower than min threshold %.3f%s.' % ++ (dcdc_name, float(item['Value']), item['Unit'], float(item['Min']), item['Unit'])) ++ else: ++ monitor_syslog_debug('%%INTELLIGENT_MONITOR-6-DCDC_SENSOR_OK: %s normal, value is %.3f%s.' % ++ (dcdc_name, item['Value'], item['Unit'])) ++ else: ++ monitor_syslog_debug( ++ '%%INTELLIGENT_MONITOR-6-DCDC_WHITELIST_CHECK: %s is in dcdc whitelist, not monitor voltage' % ++ dcdc_name) ++ continue ++ except Exception as e: ++ monitor_syslog('%%INTELLIGENT_MONITOR-3-EXCEPTION: update dcdc sensors status error, msg: %s.' % (str(e))) ++ ++ def doWork(self): ++ self.update_dcdc_status() ++ ++ def run(self): ++ while True: ++ try: ++ self.debug_init() ++ self.doWork() ++ time.sleep(self.interval) ++ except Exception as e: ++ monitor_syslog('%%INTELLIGENT_MONITOR-3-EXCEPTION: %s.' % (str(e))) ++ ++ ++if __name__ == '__main__': ++ intelligent_monitor = IntelligentMonitor() ++ intelligent_monitor.run() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor/monitor_fan.py b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor/monitor_fan.py +new file mode 100755 +index 000000000..c84319f3b +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor/monitor_fan.py +@@ -0,0 +1,284 @@ ++#!/usr/bin/python3 ++# -*- coding: UTF-8 -*- ++ ++import os ++import time ++import logging ++from logging.handlers import RotatingFileHandler ++ ++from plat_hal.interface import interface ++from plat_hal.baseutil import baseutil ++ ++ ++DEBUG_FILE = "/etc/.monitor_fan_debug_flag" ++ ++LOG_FILE = "/var/log/intelligent_monitor/monitor_fan_log" ++ ++E2_NAME = "ONIE_E2" ++ ++ ++def _init_logger(): ++ if not os.path.exists(LOG_FILE): ++ os.system("mkdir -p %s" % os.path.dirname(LOG_FILE)) ++ os.system("sync") ++ handler = RotatingFileHandler(filename=LOG_FILE, maxBytes=5 * 1024 * 1024, backupCount=1) ++ formatter = logging.Formatter("%(asctime)s %(levelname)s %(filename)s[%(funcName)s][%(lineno)s]: %(message)s") ++ handler.setFormatter(formatter) ++ logger = logging.getLogger(__name__) ++ logger.setLevel(logging.INFO) ++ logger.addHandler(handler) ++ return logger ++ ++ ++class Fan(object): ++ ++ def __init__(self, name, hal_interface): ++ self.name = name ++ self.fan_dict = {} ++ self.int_case = hal_interface ++ self.update_time = 0 ++ self.pre_present = False ++ self.pre_status = True ++ self.plugin_cnt = 0 ++ self.plugout_cnt = 0 ++ self.status_normal_cnt = 0 ++ self.status_error_cnt = 0 ++ ++ def fan_dict_update(self): ++ local_time = time.time() ++ if not self.fan_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds ++ self.update_time = local_time ++ self.fan_dict = self.int_case.get_fan_info(self.name) ++ ++ def get_model(self): ++ self.fan_dict_update() ++ return self.fan_dict["NAME"] ++ ++ def get_serial(self): ++ self.fan_dict_update() ++ return self.fan_dict["SN"] ++ ++ def get_presence(self): ++ return self.int_case.get_fan_presence(self.name) ++ ++ def get_rotor_speed(self, rotor_name): ++ """ ++ Retrieves the speed of fan as a percentage of full speed ++ ++ Returns: ++ An integer, the percentage of full fan speed, in the range 0 (off) ++ to 100 (full speed) ++ """ ++ fan_dir = {} ++ fan_dir = self.int_case.get_fan_info_rotor(self.name) ++ # get fan rotor pwm ++ value = fan_dir[rotor_name]["Speed"] ++ max_speed = fan_dir[rotor_name]["SpeedMax"] ++ ++ if isinstance(value, str) or value is None: ++ return 0 ++ pwm = value * 100 / max_speed ++ if pwm > 100: ++ pwm = 100 ++ elif pwm < 0: ++ pwm = 0 ++ return int(pwm) ++ ++ def get_rotor_speed_tolerance(self, rotor_name): ++ """ ++ Retrieves the speed tolerance of the fan ++ Returns: ++ An integer, the percentage of variance from target speed which is ++ considered tolerable ++ """ ++ # The default tolerance value is fixed as 30% ++ fan_dir = {} ++ fan_dir = self.int_case.get_fan_info_rotor(self.name) ++ # get fan rotor tolerance ++ tolerance = fan_dir[rotor_name]["Tolerance"] ++ ++ if isinstance(tolerance, str) or tolerance is None: ++ return 30 ++ return tolerance ++ ++ 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) ++ """ ++ pwm = self.int_case.get_fan_speed_pwm(self.name, 0) ++ return int(pwm) ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the FAN ++ Returns: ++ bool: True if FAN is operating properly, False if not ++ """ ++ if not self.get_presence(): ++ return False ++ ++ rotor_num = self.int_case.get_fan_rotor_number(self.name) ++ for i in range(rotor_num): ++ rotor_name = "Rotor" + str(i + 1) ++ speed = self.get_rotor_speed(rotor_name) ++ tolerance = self.get_rotor_speed_tolerance(rotor_name) ++ target = self.get_target_speed() ++ if (speed - target) > target * tolerance / 100: ++ return False ++ if (target - speed) > target * tolerance / 100: ++ return False ++ ++ return True ++ ++ def get_direction(self): ++ """ ++ Retrieves the fan airflow direction ++ Returns: ++ A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST ++ depending on fan direction ++ ++ Notes: ++ - Forward/Exhaust : Air flows from Port side to Fan side. ++ - Reverse/Intake : Air flows from Fan side to Port side. ++ """ ++ self.fan_dict_update() ++ return self.fan_dict["AirFlow"] ++ ++ ++class MonitorFan(object): ++ ++ def __init__(self): ++ self.int_case = interface() ++ self.logger = _init_logger() ++ self.fan_obj_list = [] ++ self.__config = baseutil.get_monitor_config() ++ self.__monitor_fan_config = self.__config.get("monitor_fan_para", {}) ++ self.__present_interval = self.__monitor_fan_config.get("present_interval", 0.5) ++ self.__status_interval = self.__monitor_fan_config.get("status_interval", 5) ++ self.__present_check_cnt = self.__monitor_fan_config.get("present_check_cnt", 3) ++ self.__status_check_cnt = self.__monitor_fan_config.get("status_check_cnt", 3) ++ ++ def debug_init(self): ++ if os.path.exists(DEBUG_FILE): ++ self.logger.setLevel(logging.DEBUG) ++ else: ++ self.logger.setLevel(logging.INFO) ++ ++ def get_fan_total_number(self): ++ return self.int_case.get_fan_total_number() ++ ++ def get_device_airflow(self): ++ return self.int_case.get_device_airflow(E2_NAME) ++ ++ def fan_obj_init(self): ++ fan_num = self.get_fan_total_number() ++ for i in range(fan_num): ++ fan_name = "FAN" + str(i + 1) ++ fan_obj = Fan(fan_name, self.int_case) ++ self.fan_obj_list.append(fan_obj) ++ self.logger.info("fan object initialize success") ++ ++ def fan_airflow_check(self, fan_obj): ++ fan_airflow = fan_obj.get_direction() ++ device_airflow = self.get_device_airflow() ++ if fan_airflow != device_airflow: ++ self.logger.error("%s airflow[%s] not match device airflow[%s]", fan_obj.name, fan_airflow, device_airflow) ++ else: ++ self.logger.debug("%s airflow[%s] match device airflow[%s]", fan_obj.name, fan_airflow, device_airflow) ++ ++ def fan_plug_in_out_check(self, fan_obj): ++ present = fan_obj.get_presence() ++ if present is True: ++ self.logger.debug("%s is present", fan_obj.name) ++ else: ++ self.logger.debug("%s is absent", fan_obj.name) ++ ++ if present != fan_obj.pre_present: ++ if present is True: ++ fan_obj.plugin_cnt += 1 ++ fan_obj.plugout_cnt = 0 ++ if fan_obj.plugin_cnt >= self.__present_check_cnt: ++ fan_obj.pre_present = True ++ self.logger.info("%s [serial:%s] is plugin", fan_obj.name, fan_obj.get_serial()) ++ self.fan_airflow_check(fan_obj) ++ else: ++ fan_obj.plugin_cnt = 0 ++ fan_obj.plugout_cnt += 1 ++ if fan_obj.plugout_cnt >= self.__present_check_cnt: ++ fan_obj.pre_present = False ++ self.logger.info("%s is plugout", fan_obj.name) ++ else: ++ fan_obj.plugin_cnt = 0 ++ fan_obj.plugout_cnt = 0 ++ self.logger.debug("%s present status is not change", fan_obj.name) ++ ++ def fan_status_check(self, fan_obj): ++ status = fan_obj.get_status() ++ if status is True: ++ self.logger.debug("%s is normal", fan_obj.name) ++ else: ++ self.logger.debug("%s is error", fan_obj.name) ++ ++ if status != fan_obj.pre_status: ++ if status is True: ++ fan_obj.status_normal_cnt += 1 ++ fan_obj.status_error_cnt = 0 ++ if fan_obj.status_normal_cnt >= self.__status_check_cnt: ++ fan_obj.pre_status = True ++ self.logger.info( ++ "%s [serial:%s] is form error change to normal", ++ fan_obj.name, ++ fan_obj.get_serial()) ++ else: ++ fan_obj.status_normal_cnt = 0 ++ fan_obj.status_error_cnt += 1 ++ if fan_obj.status_error_cnt >= self.__status_check_cnt: ++ fan_obj.pre_status = False ++ self.logger.info( ++ "%s [serial:%s] is form normal change to error", ++ fan_obj.name, ++ fan_obj.get_serial()) ++ else: ++ fan_obj.status_normal_cnt = 0 ++ fan_obj.status_error_cnt = 0 ++ self.logger.debug("%s status is not change", fan_obj.name) ++ ++ def checkFanPresence(self): ++ for fan_obj in self.fan_obj_list: ++ self.fan_plug_in_out_check(fan_obj) ++ ++ def checkFanStatus(self): ++ for fan_obj in self.fan_obj_list: ++ self.fan_status_check(fan_obj) ++ ++ def run(self): ++ start_time = time.time() ++ while True: ++ try: ++ self.debug_init() ++ delta_time = time.time() - start_time ++ if self.__present_interval <= self.__status_interval: ++ if delta_time >= self.__status_interval or delta_time < 0: ++ self.checkFanStatus() ++ start_time = time.time() ++ else: ++ self.checkFanPresence() ++ time.sleep(self.__present_interval) ++ else: ++ if delta_time >= self.__present_interval or delta_time < 0: ++ self.checkFanPresence() ++ start_time = time.time() ++ else: ++ self.checkFanStatus() ++ time.sleep(self.__status_interval) ++ except Exception as e: ++ self.logger.error('EXCEPTION: %s.', str(e)) ++ ++ ++if __name__ == '__main__': ++ monitor_fan = MonitorFan() ++ monitor_fan.fan_obj_init() ++ monitor_fan.run() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_common.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_common.py +new file mode 100755 +index 000000000..35c16728f +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_common.py +@@ -0,0 +1,186 @@ ++#!/usr/bin/python3 ++ ++__all__ = [ ++ "BLACKLIST_DRIVERS", ++ "DRIVERLISTS", ++ "DEVICE", ++ "STARTMODULE", ++ "MAC_LED_RESET", ++ "MAC_DEFAULT_PARAM", ++ "DEV_MONITOR_PARAM", ++ "SLOT_MONITOR_PARAM", ++ "MANUINFO_CONF", ++ "REBOOT_CTRL_PARAM", ++ "PMON_SYSLOG_STATUS", ++ "OPTOE", ++ "REBOOT_CAUSE_PARA", ++ "UPGRADE_SUMMARY", ++ "WARM_UPGRADE_PARAM", ++ "WARM_UPG_FLAG", ++ "WARM_UPGRADE_STARTED_FLAG", ++ "PLATFORM_E2_CONF", ++ "AIR_FLOW_CONF", ++ "AIRFLOW_RESULT_FILE", ++ "INIT_PARAM_PRE", ++ "INIT_COMMAND_PRE", ++ "INIT_PARAM", ++ "INIT_COMMAND", ++ "SET_MAC_CONF", ++ "DRVIER_UPDATE_CONF", ++ "MONITOR_TEMP_MIN", ++ "MONITOR_K", ++ "MONITOR_MAC_IN", ++ "MONITOR_DEFAULT_SPEED", ++ "MONITOR_MAX_SPEED", ++ "MONITOR_MIN_SPEED", ++ "MONITOR_MAC_ERROR_SPEED", ++ "MONITOR_FAN_TOTAL_NUM", ++ "MONITOR_MAC_UP_TEMP", ++ "MONITOR_MAC_LOWER_TEMP", ++ "MONITOR_MAC_MAX_TEMP", ++ "MONITOR_FALL_TEMP", ++ "MONITOR_MAC_WARNING_THRESHOLD", ++ "MONITOR_OUTTEMP_WARNING_THRESHOLD", ++ "MONITOR_BOARDTEMP_WARNING_THRESHOLD", ++ "MONITOR_CPUTEMP_WARNING_THRESHOLD", ++ "MONITOR_INTEMP_WARNING_THRESHOLD", ++ "MONITOR_MAC_CRITICAL_THRESHOLD", ++ "MONITOR_OUTTEMP_CRITICAL_THRESHOLD", ++ "MONITOR_BOARDTEMP_CRITICAL_THRESHOLD", ++ "MONITOR_CPUTEMP_CRITICAL_THRESHOLD", ++ "MONITOR_INTEMP_CRITICAL_THRESHOLD", ++ "MONITOR_CRITICAL_NUM", ++ "MONITOR_SHAKE_TIME", ++ "MONITOR_INTERVAL", ++ "MONITOR_LED_INTERVAL", ++ "MONITOR_PID_FLAG", ++ "MONITOR_MAC_SOURCE_SYSFS", ++ "MONITOR_MAC_SOURCE_PATH", ++ "MONITOR_PID_MODULE", ++ "PSU_FAN_FOLLOW", ++ "MONITOR_SYS_LED", ++ "MONITOR_SYS_FAN_LED", ++ "MONITOR_FANS_LED", ++ "MONITOR_SYS_PSU_LED", ++ "MONITOR_FAN_STATUS", ++ "MONITOR_PSU_STATUS", ++ "MONITOR_DEV_STATUS", ++ "MONITOR_DEV_STATUS_DECODE", ++ "DEV_LEDS", ++ "fanloc" ++] ++ ++# driver blacklist parameter ++BLACKLIST_DRIVERS = [] ++ ++# driver list parameter ++DRIVERLISTS = [] ++ ++# device list parameter ++DEVICE = [] ++ ++# start module parameters ++STARTMODULE = {} ++ ++# mac led reset parameter ++MAC_LED_RESET = {} ++ ++# avscontrol parameter ++MAC_DEFAULT_PARAM = [] ++ ++# dev_monitor parameter ++DEV_MONITOR_PARAM = {} ++ ++# slot_monitor parameter ++SLOT_MONITOR_PARAM = {} ++ ++# platform_manufacturer parameter ++MANUINFO_CONF = {} ++ ++# reboot_ctrl parameter ++REBOOT_CTRL_PARAM = {} ++ ++# pmon_syslog parameter ++PMON_SYSLOG_STATUS = {} ++ ++# sfp optoe device parameter ++OPTOE = [] ++ ++# reboot_cause parameter ++REBOOT_CAUSE_PARA = [] ++ ++# upgrade parameter ++UPGRADE_SUMMARY = {} ++ ++# warm_uprade parameter ++WARM_UPGRADE_PARAM = {} ++WARM_UPG_FLAG = "/etc/sonic/.warm_upg_flag" ++WARM_UPGRADE_STARTED_FLAG = "/etc/sonic/.doing_warm_upg" ++ ++# platform_e2 parameter ++PLATFORM_E2_CONF = {} ++ ++# generate_airflow parameter ++AIR_FLOW_CONF = {} ++AIRFLOW_RESULT_FILE = "/etc/sonic/.airflow" ++ ++# Initialization parameters ++INIT_PARAM_PRE = [] ++INIT_COMMAND_PRE = [] ++INIT_PARAM = [] ++INIT_COMMAND = [] ++ ++# Set eth mac address parameters ++SET_MAC_CONF = [] ++ ++# driver update config ++DRVIER_UPDATE_CONF = {} ++ ++################################ fancontrol parameter################################### ++MONITOR_TEMP_MIN = 38 ++MONITOR_K = 11 ++MONITOR_MAC_IN = 35 ++MONITOR_DEFAULT_SPEED = 0x60 ++MONITOR_MAX_SPEED = 0xFF ++MONITOR_MIN_SPEED = 0x60 ++MONITOR_MAC_ERROR_SPEED = 0XBB ++MONITOR_FAN_TOTAL_NUM = 4 ++MONITOR_MAC_UP_TEMP = 50 ++MONITOR_MAC_LOWER_TEMP = -50 ++MONITOR_MAC_MAX_TEMP = 100 # ++ ++MONITOR_FALL_TEMP = 4 ++MONITOR_MAC_WARNING_THRESHOLD = 100 ++MONITOR_OUTTEMP_WARNING_THRESHOLD = 85 ++MONITOR_BOARDTEMP_WARNING_THRESHOLD = 85 ++MONITOR_CPUTEMP_WARNING_THRESHOLD = 85 ++MONITOR_INTEMP_WARNING_THRESHOLD = 70 ++ ++MONITOR_MAC_CRITICAL_THRESHOLD = 105 ++MONITOR_OUTTEMP_CRITICAL_THRESHOLD = 90 ++MONITOR_BOARDTEMP_CRITICAL_THRESHOLD = 90 ++MONITOR_CPUTEMP_CRITICAL_THRESHOLD = 100 ++MONITOR_INTEMP_CRITICAL_THRESHOLD = 80 ++MONITOR_CRITICAL_NUM = 3 ++MONITOR_SHAKE_TIME = 20 ++MONITOR_INTERVAL = 60 ++MONITOR_LED_INTERVAL = 2 ++MONITOR_PID_FLAG = 0 ++ ++MONITOR_MAC_SOURCE_SYSFS = 0 ++MONITOR_MAC_SOURCE_PATH = None ++ ++MONITOR_PID_MODULE = {} ++ ++PSU_FAN_FOLLOW = {} ++ ++MONITOR_SYS_LED = [] ++MONITOR_SYS_FAN_LED = [] ++MONITOR_FANS_LED = [] ++MONITOR_SYS_PSU_LED = [] ++MONITOR_FAN_STATUS = [] ++MONITOR_PSU_STATUS = [] ++MONITOR_DEV_STATUS = {} ++MONITOR_DEV_STATUS_DECODE = {} ++DEV_LEDS = {} ++fanloc = [] +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_config.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_config.py +new file mode 100755 +index 000000000..d6b3151e4 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_config.py +@@ -0,0 +1,192 @@ ++#!/usr/bin/python3 ++ ++import sys ++import os ++from wbutil.baseutil import get_machine_info ++from wbutil.baseutil import get_platform_info ++from wbutil.baseutil import get_board_id ++ ++__all__ = [ ++ "MAILBOX_DIR", ++ "PLATFORM_GLOBALCONFIG", ++ "GLOBALCONFIG", ++ "STARTMODULE", ++ "MAC_LED_RESET", ++ "MAC_DEFAULT_PARAM", ++ "DEV_MONITOR_PARAM", ++ "SLOT_MONITOR_PARAM", ++ "MANUINFO_CONF", ++ "REBOOT_CTRL_PARAM", ++ "PMON_SYSLOG_STATUS", ++ "REBOOT_CAUSE_PARA", ++ "UPGRADE_SUMMARY", ++ "WARM_UPGRADE_PARAM", ++ "WARM_UPG_FLAG", ++ "WARM_UPGRADE_STARTED_FLAG", ++ "PLATFORM_E2_CONF", ++ "AIR_FLOW_CONF", ++ "AIRFLOW_RESULT_FILE", ++ "GLOBALINITPARAM", ++ "GLOBALINITCOMMAND", ++ "GLOBALINITPARAM_PRE", ++ "GLOBALINITCOMMAND_PRE", ++ "SET_MAC_CONF", ++ "DRVIER_UPDATE_CONF", ++ "MONITOR_CONST", ++ "PSU_FAN_FOLLOW", ++ "MONITOR_SYS_LED", ++ "MONITOR_FANS_LED", ++ "MONITOR_SYS_FAN_LED", ++ "MONITOR_SYS_PSU_LED", ++ "MONITOR_FAN_STATUS", ++ "MONITOR_PSU_STATUS", ++ "MONITOR_DEV_STATUS", ++ "MONITOR_DEV_STATUS_DECODE", ++ "DEV_LEDS", ++ "fanloc" ++] ++ ++ ++def getdeviceplatform(): ++ x = get_platform_info(get_machine_info()) ++ if x is not None: ++ filepath = "/usr/share/sonic/device/" + x ++ return filepath ++ return None ++ ++ ++platform = get_platform_info(get_machine_info()) ++board_id = get_board_id(get_machine_info()) ++platformpath = getdeviceplatform() ++MAILBOX_DIR = "/sys/bus/i2c/devices/" ++grtd_productfile = (platform + "_config").replace("-", "_") ++common_productfile = "platform_common" ++platform_configfile = (platform + "_" + board_id + "_config").replace("-", "_") # platfrom + board_id ++configfile_pre = "/usr/local/bin/" ++sys.path.append(platformpath) ++sys.path.append(configfile_pre) ++ ++############################################################################################ ++if os.path.exists(configfile_pre + platform_configfile + ".py"): ++ module_product = __import__(platform_configfile, globals(), locals(), [], 0) ++elif os.path.exists(configfile_pre + grtd_productfile + ".py"): ++ module_product = __import__(grtd_productfile, globals(), locals(), [], 0) ++elif os.path.exists(configfile_pre + common_productfile + ".py"): ++ module_product = __import__(common_productfile, globals(), locals(), [], 0) ++else: ++ print("config file not exist") ++ sys.exit(-1) ++############################################################################################ ++ ++PLATFORM_GLOBALCONFIG = { ++ "DRIVERLISTS": module_product.DRIVERLISTS, ++ "OPTOE": module_product.OPTOE, ++ "DEVS": module_product.DEVICE, ++ "BLACKLIST_DRIVERS": module_product.BLACKLIST_DRIVERS ++} ++GLOBALCONFIG = PLATFORM_GLOBALCONFIG ++ ++# start module parameters ++STARTMODULE = module_product.STARTMODULE ++ ++# mac led reset parameter ++MAC_LED_RESET = module_product.MAC_LED_RESET ++ ++# avscontrol parameter ++MAC_DEFAULT_PARAM = module_product.MAC_DEFAULT_PARAM ++ ++# dev_monitor parameter ++DEV_MONITOR_PARAM = module_product.DEV_MONITOR_PARAM ++ ++# slot_monitor parameter ++SLOT_MONITOR_PARAM = module_product.SLOT_MONITOR_PARAM ++ ++# platform_manufacturer parameter ++MANUINFO_CONF = module_product.MANUINFO_CONF ++ ++# reboot_ctrl parameter ++REBOOT_CTRL_PARAM = module_product.REBOOT_CTRL_PARAM ++ ++# pmon_syslog parameter ++PMON_SYSLOG_STATUS = module_product.PMON_SYSLOG_STATUS ++ ++# reboot_cause parameter ++REBOOT_CAUSE_PARA = module_product.REBOOT_CAUSE_PARA ++ ++# upgrade parameter ++UPGRADE_SUMMARY = module_product.UPGRADE_SUMMARY ++ ++# warm_uprade parameter ++WARM_UPGRADE_PARAM = module_product.WARM_UPGRADE_PARAM ++WARM_UPG_FLAG = module_product.WARM_UPG_FLAG ++WARM_UPGRADE_STARTED_FLAG = module_product.WARM_UPGRADE_STARTED_FLAG ++ ++# platform_e2 parameter ++PLATFORM_E2_CONF = module_product.PLATFORM_E2_CONF ++ ++# generate_airflow parameter ++AIR_FLOW_CONF = module_product.AIR_FLOW_CONF ++AIRFLOW_RESULT_FILE = module_product.AIRFLOW_RESULT_FILE ++ ++# Initialization parameters ++GLOBALINITPARAM = module_product.INIT_PARAM ++GLOBALINITCOMMAND = module_product.INIT_COMMAND ++GLOBALINITPARAM_PRE = module_product.INIT_PARAM_PRE ++GLOBALINITCOMMAND_PRE = module_product.INIT_COMMAND_PRE ++ ++# Set eth mac address parameters ++SET_MAC_CONF = module_product.SET_MAC_CONF ++ ++# driver update config ++DRVIER_UPDATE_CONF = module_product.DRVIER_UPDATE_CONF ++ ++################################ fancontrol parameter################################### ++ ++ ++class MONITOR_CONST: ++ TEMP_MIN = module_product.MONITOR_TEMP_MIN ++ K = module_product.MONITOR_K ++ MAC_IN = module_product.MONITOR_MAC_IN ++ DEFAULT_SPEED = module_product.MONITOR_DEFAULT_SPEED ++ MAX_SPEED = module_product.MONITOR_MAX_SPEED ++ MIN_SPEED = module_product.MONITOR_MIN_SPEED ++ MAC_ERROR_SPEED = module_product.MONITOR_MAC_ERROR_SPEED ++ FAN_TOTAL_NUM = module_product.MONITOR_FAN_TOTAL_NUM ++ MAC_UP_TEMP = module_product.MONITOR_MAC_UP_TEMP ++ MAC_LOWER_TEMP = module_product.MONITOR_MAC_LOWER_TEMP ++ MAC_MAX_TEMP = module_product.MONITOR_MAC_MAX_TEMP ++ ++ MAC_WARNING_THRESHOLD = module_product.MONITOR_MAC_WARNING_THRESHOLD ++ OUTTEMP_WARNING_THRESHOLD = module_product.MONITOR_OUTTEMP_WARNING_THRESHOLD ++ BOARDTEMP_WARNING_THRESHOLD = module_product.MONITOR_BOARDTEMP_WARNING_THRESHOLD ++ CPUTEMP_WARNING_THRESHOLD = module_product.MONITOR_CPUTEMP_WARNING_THRESHOLD ++ INTEMP_WARNING_THRESHOLD = module_product.MONITOR_INTEMP_WARNING_THRESHOLD ++ ++ MAC_CRITICAL_THRESHOLD = module_product.MONITOR_MAC_CRITICAL_THRESHOLD ++ OUTTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_OUTTEMP_CRITICAL_THRESHOLD ++ BOARDTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_BOARDTEMP_CRITICAL_THRESHOLD ++ CPUTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_CPUTEMP_CRITICAL_THRESHOLD ++ INTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_INTEMP_CRITICAL_THRESHOLD ++ CRITICAL_NUM = module_product.MONITOR_CRITICAL_NUM ++ SHAKE_TIME = module_product.MONITOR_SHAKE_TIME ++ MONITOR_INTERVAL = module_product.MONITOR_INTERVAL ++ MONITOR_LED_INTERVAL = module_product.MONITOR_LED_INTERVAL ++ MONITOR_FALL_TEMP = module_product.MONITOR_FALL_TEMP ++ MONITOR_PID_FLAG = module_product.MONITOR_PID_FLAG ++ MONITOR_PID_MODULE = module_product.MONITOR_PID_MODULE ++ ++ MONITOR_MAC_SOURCE_SYSFS = module_product.MONITOR_MAC_SOURCE_SYSFS ++ MONITOR_MAC_SOURCE_PATH = module_product.MONITOR_MAC_SOURCE_PATH ++ ++ ++PSU_FAN_FOLLOW = module_product.PSU_FAN_FOLLOW ++MONITOR_SYS_LED = module_product.MONITOR_SYS_LED ++MONITOR_FANS_LED = module_product.MONITOR_FANS_LED ++MONITOR_SYS_FAN_LED = module_product.MONITOR_SYS_FAN_LED ++MONITOR_SYS_PSU_LED = module_product.MONITOR_SYS_PSU_LED ++MONITOR_FAN_STATUS = module_product.MONITOR_FAN_STATUS ++MONITOR_PSU_STATUS = module_product.MONITOR_PSU_STATUS ++MONITOR_DEV_STATUS = module_product.MONITOR_DEV_STATUS ++MONITOR_DEV_STATUS_DECODE = module_product.MONITOR_DEV_STATUS_DECODE ++DEV_LEDS = module_product.DEV_LEDS ++fanloc = module_product.fanloc +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_driver.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_driver.py +new file mode 100755 +index 000000000..6d2c6de65 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_driver.py +@@ -0,0 +1,258 @@ ++#!/usr/bin/env python3 ++import os ++import subprocess ++import time ++import click ++from platform_config import GLOBALCONFIG, WARM_UPGRADE_STARTED_FLAG, WARM_UPG_FLAG ++ ++ ++CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} ++ ++ ++class AliasedGroup(click.Group): ++ def get_command(self, ctx, cmd_name): ++ rv = click.Group.get_command(self, ctx, cmd_name) ++ if rv is not None: ++ return rv ++ matches = [x for x in self.list_commands(ctx) ++ if x.startswith(cmd_name)] ++ if not matches: ++ return None ++ if len(matches) == 1: ++ return click.Group.get_command(self, ctx, matches[0]) ++ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) ++ return None ++ ++ ++def log_os_system(cmd): ++ status, output = subprocess.getstatusoutput(cmd) ++ if status: ++ print(output) ++ return status, output ++ ++ ++def platform_process_file_check(): ++ # WARM_UPGRADE_STARTED_FLAG is used as warm_upgrade.py process start flag ++ if os.path.exists(WARM_UPGRADE_STARTED_FLAG): ++ os.remove(WARM_UPGRADE_STARTED_FLAG) ++ ++ # WARM_UPG_FLAG is used as port related service judgment flag ++ if os.path.exists(WARM_UPG_FLAG): ++ os.remove(WARM_UPG_FLAG) ++ ++ ++def startCommon_operation(): ++ platform_process_file_check() ++ ++ ++def check_driver(): ++ status, output = log_os_system("lsmod | grep wb | wc -l") ++ if status: ++ return False ++ if output.isdigit() and int(output) > 0: ++ return True ++ return False ++ ++ ++def removeDev(bus, loc): ++ cmd = "echo 0x%02x > /sys/bus/i2c/devices/i2c-%d/delete_device" % (loc, bus) ++ devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) ++ if os.path.exists(devpath): ++ log_os_system(cmd) ++ ++ ++def addDev(name, bus, loc): ++ if name == "lm75": ++ time.sleep(0.1) ++ pdevpath = "/sys/bus/i2c/devices/i2c-%d/" % (bus) ++ for i in range(1, 100): ++ if os.path.exists(pdevpath) is True: ++ break ++ time.sleep(0.1) ++ if i % 10 == 0: ++ click.echo("%%WB_PLATFORM_DRIVER-INIT: %s not found, wait 0.1 second ! i %d " % (pdevpath, i)) ++ ++ cmd = "echo %s 0x%02x > /sys/bus/i2c/devices/i2c-%d/new_device" % (name, loc, bus) ++ devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) ++ if os.path.exists(devpath) is False: ++ os.system(cmd) ++ ++ ++def removeOPTOE(startbus, endbus): ++ for bus in range(endbus, startbus - 1, -1): ++ removeDev(bus, 0x50) ++ ++ ++def addOPTOE(name, startbus, endbus): ++ for bus in range(startbus, endbus + 1): ++ addDev(name, bus, 0x50) ++ ++ ++def removeoptoes(): ++ optoes = GLOBALCONFIG["OPTOE"] ++ for index in range(len(optoes) - 1, -1, -1): ++ removeOPTOE(optoes[index]["startbus"], optoes[index]["endbus"]) ++ ++ ++def addoptoes(): ++ optoes = GLOBALCONFIG["OPTOE"] ++ for optoe in optoes: ++ addOPTOE(optoe["name"], optoe["startbus"], optoe["endbus"]) ++ ++ ++def removedevs(): ++ devs = GLOBALCONFIG["DEVS"] ++ for index in range(len(devs) - 1, -1, -1): ++ removeDev(devs[index]["bus"], devs[index]["loc"]) ++ ++ ++def adddevs(): ++ devs = GLOBALCONFIG["DEVS"] ++ for dev in devs: ++ addDev(dev["name"], dev["bus"], dev["loc"]) ++ ++ ++def checksignaldriver(name): ++ modisexistcmd = "lsmod | grep -w %s | wc -l" % name ++ status, output = log_os_system(modisexistcmd) ++ if status: ++ return False ++ if output.isdigit() and int(output) > 0: ++ return True ++ return False ++ ++ ++def adddriver(name, delay): ++ cmd = "modprobe %s" % name ++ if delay != 0: ++ time.sleep(delay) ++ if checksignaldriver(name) is not True: ++ log_os_system(cmd) ++ ++ ++def removedriver(name, delay, removeable=1): ++ realname = name.lstrip().split(" ")[0] ++ cmd = "rmmod -f %s" % realname ++ if checksignaldriver(realname) and removeable: ++ log_os_system(cmd) ++ if delay > 0: ++ time.sleep(delay) ++ ++ ++def removedrivers(): ++ if GLOBALCONFIG is None: ++ click.echo("%%WB_PLATFORM_DRIVER-INIT: load global config failed.") ++ return ++ drivers = GLOBALCONFIG.get("DRIVERLISTS", None) ++ if drivers is None: ++ click.echo("%%WB_PLATFORM_DRIVER-INIT: load driver list failed.") ++ return ++ for index in range(len(drivers) - 1, -1, -1): ++ delay = 0 ++ name = "" ++ removeable = drivers[index].get("removable", 1) ++ if isinstance(drivers[index], dict) and "delay" in drivers[index]: ++ name = drivers[index].get("name") ++ delay = drivers[index]["delay"] ++ else: ++ name = drivers[index] ++ removedriver(name, delay, removeable) ++ ++ ++def adddrivers(): ++ if GLOBALCONFIG is None: ++ click.echo("%%WB_PLATFORM_DRIVER-INIT: load global config failed.") ++ return ++ drivers = GLOBALCONFIG.get("DRIVERLISTS", None) ++ if drivers is None: ++ click.echo("%%WB_PLATFORM_DRIVER-INIT: load driver list failed.") ++ return ++ for driver in drivers: ++ delay = 0 ++ name = "" ++ if isinstance(driver, dict) and "delay" in driver: ++ name = driver.get("name") ++ delay = driver["delay"] ++ else: ++ name = driver ++ adddriver(name, delay) ++ ++ ++def blacklist_driver_remove(): ++ if GLOBALCONFIG is None: ++ click.echo("%%WB_PLATFORM_DRIVER-INIT: load global config failed.") ++ return ++ blacklist_drivers = GLOBALCONFIG.get("BLACKLIST_DRIVERS", []) ++ for driver in blacklist_drivers: ++ delay = 0 ++ name = "" ++ if isinstance(driver, dict) and "delay" in driver: ++ name = driver.get("name") ++ delay = driver["delay"] ++ else: ++ name = driver ++ removedriver(name, delay) ++ ++ ++def unload_driver(): ++ removeoptoes() ++ removedevs() ++ removedrivers() ++ ++ ++def reload_driver(): ++ removedevs() ++ removedrivers() ++ time.sleep(1) ++ adddrivers() ++ adddevs() ++ ++ ++def i2c_check(bus, retrytime=6): ++ try: ++ i2cpath = "/sys/bus/i2c/devices/" + bus ++ while retrytime and not os.path.exists(i2cpath): ++ click.echo("%%WB_PLATFORM_DRIVER-HA: i2c bus abnormal, last bus %s is not exist." % i2cpath) ++ reload_driver() ++ retrytime -= 1 ++ time.sleep(1) ++ except Exception as e: ++ click.echo("%%WB_PLATFORM_DRIVER-HA: %s" % str(e)) ++ ++ ++def load_driver(): ++ startCommon_operation() ++ adddrivers() ++ adddevs() ++ addoptoes() ++ ++ ++@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) ++def main(): ++ '''device operator''' ++ ++ ++@main.command() ++def start(): ++ '''load drivers and device ''' ++ blacklist_driver_remove() ++ if check_driver(): ++ unload_driver() ++ load_driver() ++ ++ ++@main.command() ++def stop(): ++ '''stop drivers device ''' ++ unload_driver() ++ ++ ++@main.command() ++def restart(): ++ '''restart drivers and device''' ++ unload_driver() ++ load_driver() ++ ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_e2.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_e2.py +new file mode 100755 +index 000000000..152dd16a2 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_e2.py +@@ -0,0 +1,439 @@ ++#!/usr/bin/env python3 ++# -*- coding: UTF-8 -*- ++import click ++ ++from eepromutil.fru import ipmifru ++from eepromutil.cust_fru import CustFru ++from eepromutil.fantlv import fan_tlv ++import eepromutil.onietlv as ot ++from platform_config import PLATFORM_E2_CONF ++from platform_util import byteTostr, dev_file_read ++ ++CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} ++ ++ ++class AliasedGroup(click.Group): ++ def get_command(self, ctx, cmd_name): ++ rv = click.Group.get_command(self, ctx, cmd_name) ++ if rv is not None: ++ return rv ++ matches = [x for x in self.list_commands(ctx) ++ if x.startswith(cmd_name)] ++ if not matches: ++ return None ++ if len(matches) == 1: ++ return click.Group.get_command(self, ctx, matches[0]) ++ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) ++ return None ++ ++ ++class ExtraFunc(object): ++ @staticmethod ++ def decode_mac(encodedata): ++ if encodedata is None: ++ return None ++ ret = ":".join("%02x" % ord(data) for data in encodedata) ++ return ret.upper() ++ ++ @staticmethod ++ def decode_mac_number(encodedata): ++ if encodedata is None: ++ return None ++ return (ord(encodedata[0]) << 8) | (ord(encodedata[1]) & 0x00ff) ++ ++ @staticmethod ++ @staticmethod ++ def fru_decode_mac_number(params): ++ ipmi_fru = params.get("fru") ++ area = params.get("area") ++ field = params.get("field") ++ area_info = getattr(ipmi_fru, area, None) ++ if area_info is not None: ++ raw_mac_number = getattr(area_info, field, None) ++ mac_number = decode_mac_number(raw_mac_number) ++ ipmi_fru.setValue(area, field, mac_number) ++ ++ @staticmethod ++ def fru_decode_mac(params): ++ ipmi_fru = params.get("fru") ++ area = params.get("area") ++ field = params.get("field") ++ area_info = getattr(ipmi_fru, area, None) ++ if area_info is not None: ++ raw_mac = getattr(area_info, field, None) ++ decoded_mac = decode_mac(raw_mac) ++ ipmi_fru.setValue(area, field, decoded_mac) ++ ++ @staticmethod ++ def fru_decode_hw(params): ++ ipmi_fru = params.get("fru") ++ area = params.get("area") ++ field = params.get("field") ++ area_info = getattr(ipmi_fru, area, None) ++ if area_info is not None: ++ raw_hw = getattr(area_info, field, None) ++ decode_hw = str(int(raw_hw, 16)) ++ ipmi_fru.setValue(area, field, decode_hw) ++ ++ ++def set_onie_value(params): ++ onie = params.get("onie") ++ field = params.get("field") ++ config_value = params.get("config_value") ++ for index, onie_item in enumerate(onie): ++ if onie_item.get("name") == field: ++ if "value" in onie_item.keys(): ++ onie[index]["value"] = config_value ++ ++ ++def onie_eeprom_decode(onie, e2_decode): ++ for e2_decode_item in e2_decode: ++ field = e2_decode_item.get("field") ++ decode_type = e2_decode_item.get("decode_type") ++ if decode_type == 'func': ++ params = { ++ "onie": onie, ++ "field": field ++ } ++ func_name = e2_decode_item.get("func_name") ++ if func_name is not None: ++ run_func(func_name, params) ++ elif decode_type == 'config': ++ config_value = e2_decode_item.get("config_value") ++ if config_value is not None: ++ params = { ++ "onie": onie, ++ "field": field, ++ "config_value": config_value ++ } ++ set_onie_value(params) ++ else: ++ print("unsupport decode type") ++ continue ++ ++ ++def onie_eeprom_show(eeprom, e2_decode=None): ++ try: ++ onietlv = ot.onie_tlv() ++ rets = onietlv.decode(eeprom) ++ if e2_decode is not None: ++ onie_eeprom_decode(rets, e2_decode) ++ print("%-20s %-5s %-5s %-20s" % ("TLV name", "Code", "lens", "Value")) ++ for item in rets: ++ if item["code"] == 0xfd: ++ print("%-20s 0x%-02X %-5s" % (item["name"], item["code"], item["lens"])) ++ else: ++ print("%-20s 0x%-02X %-5s %-20s" % (item["name"], item["code"], item["lens"], item["value"])) ++ except Exception as e: ++ print(str(e)) ++ ++ ++def set_fantlv_value(params): ++ fantlv_dict = params.get("fantlv") ++ field = params.get("field") ++ config_value = params.get("config_value") ++ for index, fantlv_item in enumerate(fantlv_dict): ++ if fantlv_item.get("name") == field: ++ if "value" in fantlv_item.keys(): ++ fantlv_dict[index]["value"] = config_value ++ ++ ++def fantlv_eeprom_decode(fantlv_dict, e2_decode): ++ for e2_decode_item in e2_decode: ++ field = e2_decode_item.get("field") ++ decode_type = e2_decode_item.get("decode_type") ++ if decode_type == 'func': ++ params = { ++ "fantlv": fantlv_dict, ++ "field": field ++ } ++ func_name = e2_decode_item.get("func_name") ++ if func_name is not None: ++ run_func(func_name, params) ++ elif decode_type == 'config': ++ config_value = e2_decode_item.get("config_value") ++ if config_value is not None: ++ params = { ++ "fantlv": fantlv_dict, ++ "field": field, ++ "config_value": config_value ++ } ++ set_fantlv_value(params) ++ else: ++ print("unsupport decode type") ++ continue ++ ++ ++def fantlv_eeprom_show(eeprom, e2_decode=None): ++ try: ++ tlv = fan_tlv() ++ rets = tlv.decode(eeprom) ++ if len(rets) == 0: ++ print("fan tlv eeprom info error.!") ++ return ++ if e2_decode is not None: ++ fantlv_eeprom_decode(rets, e2_decode) ++ print("%-15s %-5s %-5s %-20s" % ("TLV name", "Code", "lens", "Value")) ++ for item in rets: ++ print("%-15s 0x%-02X %-5s %-20s" % (item["name"], item["code"], item["lens"], item["value"])) ++ except Exception as e: ++ print(str(e)) ++ return ++ ++ ++def run_func(funcname, params): ++ try: ++ func = getattr(ExtraFunc, funcname) ++ func(params) ++ except Exception as e: ++ print(str(e)) ++ ++def set_fru_value(params): ++ ipmi_fru = params.get("fru") ++ area = params.get("area") ++ field = params.get("field") ++ config_value = params.get("config_value") ++ ipmi_fru.setValue(area, field, config_value) ++ ++ ++def fru_eeprom_decode(ipmi_fru, e2_decode): ++ for e2_decode_item in e2_decode: ++ area = e2_decode_item.get("area") ++ field = e2_decode_item.get("field") ++ decode_type = e2_decode_item.get("decode_type") ++ if decode_type == 'func': ++ params = { ++ "fru": ipmi_fru, ++ "area": area, ++ "field": field ++ } ++ func_name = e2_decode_item.get("func_name") ++ if func_name is not None: ++ run_func(func_name, params) ++ elif decode_type == 'config': ++ config_value = e2_decode_item.get("config_value") ++ if config_value is not None: ++ params = { ++ "fru": ipmi_fru, ++ "area": area, ++ "field": field, ++ "config_value": config_value ++ } ++ set_fru_value(params) ++ else: ++ print("unsupport decode type") ++ continue ++ ++ ++def fru_eeprom_show(eeprom, e2_decode=None): ++ try: ++ ipmi_fru = ipmifru() ++ ipmi_fru.decodeBin(eeprom) ++ if e2_decode is not None: ++ fru_eeprom_decode(ipmi_fru, e2_decode) ++ print("=================board=================") ++ print(ipmi_fru.boardInfoArea) ++ print("=================product=================") ++ print(ipmi_fru.productInfoArea) ++ except Exception as e: ++ print(str(e)) ++ ++ ++def custfru_eeprom_show(eeprom, e2_decode=None): ++ try: ++ custfru = CustFru() ++ custfru.decode(eeprom) ++ print(custfru) ++ except Exception as e: ++ print(str(e)) ++ ++ ++def eeprom_parase(eeprom_conf): ++ name = eeprom_conf.get("name") ++ e2_type = eeprom_conf.get("e2_type") ++ e2_path = eeprom_conf.get("e2_path") ++ e2_size = eeprom_conf.get("e2_size", 256) ++ e2_decode = eeprom_conf.get("e2_decode") ++ print("===================%s===================" % name) ++ ret, binval_bytes = dev_file_read(e2_path, 0, e2_size) ++ if ret is False: ++ print("eeprom read error, eeprom path: %s, msg: %s" % (e2_path, binval_bytes)) ++ return ++ binval = byteTostr(binval_bytes) ++ if e2_type == "onie_tlv": ++ onie_eeprom_show(binval, e2_decode) ++ elif e2_type == "fru": ++ fru_eeprom_show(binval, e2_decode) ++ elif e2_type == "fantlv": ++ fantlv_eeprom_show(binval, e2_decode) ++ elif e2_type == "custfru": ++ custfru_eeprom_show(binval, e2_decode) ++ else: ++ print("Unknow eeprom type: %s" % e2_type) ++ return ++ ++ ++def get_fans_eeprom_info(param): ++ fan_eeprom_conf = PLATFORM_E2_CONF.get("fan", []) ++ fan_num = len(fan_eeprom_conf) ++ if fan_num == 0: ++ print("fan number is 0, can't get fan eeprom info") ++ return ++ if param == 'all': ++ for conf in fan_eeprom_conf: ++ eeprom_parase(conf) ++ return ++ if not param.isdigit(): ++ print("param error, %s is not digital or 'all'" % param) ++ return ++ fan_index = int(param, 10) - 1 ++ if fan_index < 0 or fan_index >= fan_num: ++ print("param error, total fan number: %d, fan index: %d" % (fan_num, fan_index + 1)) ++ return ++ eeprom_parase(fan_eeprom_conf[fan_index]) ++ return ++ ++ ++def get_psus_eeprom_info(param): ++ psu_eeprom_conf = PLATFORM_E2_CONF.get("psu", []) ++ psu_num = len(psu_eeprom_conf) ++ if psu_num == 0: ++ print("psu number is 0, can't get psu eeprom info") ++ return ++ if param == 'all': ++ for conf in psu_eeprom_conf: ++ eeprom_parase(conf) ++ return ++ if not param.isdigit(): ++ print("param error, %s is not digital or 'all'" % param) ++ return ++ psu_index = int(param, 10) - 1 ++ if psu_index < 0 or psu_index >= psu_num: ++ print("param error, total psu number: %d, psu index: %d" % (psu_num, psu_index + 1)) ++ return ++ eeprom_parase(psu_eeprom_conf[psu_index]) ++ return ++ ++ ++def get_slots_eeprom_info(param): ++ slot_eeprom_conf = PLATFORM_E2_CONF.get("slot", []) ++ slot_num = len(slot_eeprom_conf) ++ if slot_num == 0: ++ print("slot number is 0, can't get slot eeprom info") ++ return ++ if param == 'all': ++ for conf in slot_eeprom_conf: ++ eeprom_parase(conf) ++ return ++ if not param.isdigit(): ++ print("param error, %s is not digital or 'all'" % param) ++ return ++ slot_index = int(param, 10) - 1 ++ if slot_index < 0 or slot_index >= slot_num: ++ print("param error, total slot number: %d, slot index: %d" % (slot_num, slot_index + 1)) ++ return ++ eeprom_parase(slot_eeprom_conf[slot_index]) ++ return ++ ++ ++def get_syseeprom_info(param): ++ syseeprom_conf = PLATFORM_E2_CONF.get("syseeprom", []) ++ syseeprom_num = len(syseeprom_conf) ++ if syseeprom_num == 0: ++ print("syseeprom number is 0, can't get syseeprom info") ++ return ++ if param == 'all': ++ for conf in syseeprom_conf: ++ eeprom_parase(conf) ++ return ++ if not param.isdigit(): ++ print("param error, %s is not digital or 'all'" % param) ++ return ++ syseeprom_index = int(param, 10) - 1 ++ if syseeprom_index < 0 or syseeprom_index >= syseeprom_num: ++ print("param error, total syseeprom number: %d, syseeprom index: %d" % (syseeprom_num, syseeprom_index + 1)) ++ return ++ eeprom_parase(syseeprom_conf[syseeprom_index]) ++ return ++ ++ ++def decode_eeprom_info(e2_type, e2_path, e2_size): ++ if not e2_size.isdigit(): ++ print("param error, e2_size %s is not digital" % e2_size) ++ return ++ e2_size = int(e2_size, 10) ++ eeprom_conf = {} ++ eeprom_conf["name"] = e2_type ++ eeprom_conf["e2_type"] = e2_type ++ eeprom_conf["e2_path"] = e2_path ++ eeprom_conf["e2_size"] = e2_size ++ eeprom_parase(eeprom_conf) ++ return ++ ++ ++@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) ++def main(): ++ '''platform eeprom display script''' ++ ++ ++# fan eeprom info display ++@main.command() ++@click.argument('fan_index', required=True) ++def fan(fan_index): ++ '''fan_index(1, 2, 3...)/all''' ++ get_fans_eeprom_info(fan_index) ++ ++ ++# psu eeprom info display ++@main.command() ++@click.argument('psu_index', required=True) ++def psu(psu_index): ++ '''psu_index(1, 2, 3...)/all''' ++ get_psus_eeprom_info(psu_index) ++ ++ ++# slot eeprom info display ++@main.command() ++@click.argument('slot_index', required=True) ++def slot(slot_index): ++ '''slot_index(1, 2, 3...)/all''' ++ get_slots_eeprom_info(slot_index) ++ ++ ++# syseeprom info display ++@main.command() ++@click.argument('syseeprom_index', required=True) ++def syseeprom(syseeprom_index): ++ '''syseeprom_index(1, 2, 3...)/all''' ++ get_syseeprom_info(syseeprom_index) ++ ++ ++# fru eeprom info decode ++@main.command() ++@click.argument('e2_path', required=True) ++@click.argument('e2_size', required=False, default="256") ++def fru(e2_path, e2_size): ++ '''e2_path''' ++ decode_eeprom_info("fru", e2_path, e2_size) ++ ++ ++# fantlv eeprom info decode ++@main.command() ++@click.argument('e2_path', required=True) ++@click.argument('e2_size', required=False, default="256") ++def fantlv(e2_path, e2_size): ++ '''e2_path''' ++ decode_eeprom_info("fantlv", e2_path, e2_size) ++ ++ ++# onie_tlv eeprom info decode ++@main.command() ++@click.argument('e2_path', required=True) ++@click.argument('e2_size', required=False, default="256") ++def onie_tlv(e2_path, e2_size): ++ '''e2_path''' ++ decode_eeprom_info("onie_tlv", e2_path, e2_size) ++ ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_intf.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_intf.py +new file mode 100755 +index 000000000..43f36f040 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_intf.py +@@ -0,0 +1,384 @@ ++#!/usr/bin/env python3 ++import os ++import syslog ++import importlib.machinery ++from platform_util import getplatform_name, dev_file_read, dev_file_write, write_sysfs, read_sysfs ++ ++__all__ = [ ++ "platform_reg_read", ++ "platform_reg_write", ++ "platform_set_optoe_type", ++ "platform_get_optoe_type", ++ "platform_sfp_read", ++ "platform_sfp_write", ++] ++ ++CPLD = 0 ++FPGA = 1 ++CPLD_PATH = "/dev/cpld%d" ++FPGA_PATH = "/dev/fpga%d" ++ ++ ++OPTOE_PATH = "/sys/bus/i2c/devices/%d-0050/" ++OPTOE_DEV_CLASS = "dev_class" ++OPTOE_EEPROM = "eeprom" ++ ++ ++PLATFORM_INTF_DEBUG_FILE = "/etc/.platform_intf_debug_flag" ++ ++ ++CONFIG_FILE_LIST = [ ++ "/usr/local/bin/", ++ "/usr/local/lib/python3/dist-packages/config/", ++ "/usr/local/lib/python3.7/dist-packages/config/", ++ "/usr/local/lib/python3.9/dist-packages/config/"] ++ ++ ++def platform_intf_debug(s): ++ if os.path.exists(PLATFORM_INTF_DEBUG_FILE): ++ syslog.openlog("PLATFORM_INTF_DEBUG", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def platform_intf_error(s): ++ if os.path.exists(PLATFORM_INTF_DEBUG_FILE): ++ syslog.openlog("PLATFORM_INTF_ERROR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++class IntfPlatform: ++ CONFIG_NAME = 'PLATFORM_INTF_OPTOE' ++ __port_optoe_dict = {} ++ ++ def __init__(self): ++ real_path = None ++ platform_name = (getplatform_name()).replace("-", "_") ++ for configfile_path in CONFIG_FILE_LIST: ++ configfile = configfile_path + platform_name + "_port_config.py" ++ if os.path.exists(configfile): ++ real_path = configfile ++ break ++ if real_path is None: ++ raise Exception("get port config error") ++ config = importlib.machinery.SourceFileLoader(self.CONFIG_NAME, real_path).load_module() ++ self.__port_optoe_dict = config.PLATFORM_INTF_OPTOE ++ ++ def get_dev_path(self, dev_type, dev_id): ++ if dev_type == CPLD: ++ path = CPLD_PATH % dev_id ++ elif dev_type == FPGA: ++ path = FPGA_PATH % dev_id ++ else: ++ msg = "dev_type error!" ++ return False, msg ++ platform_intf_debug("path:%s" % path) ++ return True, path ++ ++ def get_port_path(self, port): ++ port_num = self.__port_optoe_dict.get("port_num", 0) ++ if port_num <= 0: ++ msg = "PLATFORM_INTF_OPTOE port_num config error, port_num: %d!" % port_num ++ return False, msg ++ ++ if port <= 0 or port > port_num: ++ msg = "port out of range !" ++ return False, msg ++ ++ port_bus_map = self.__port_optoe_dict.get("port_bus_map") ++ optoe_start_bus = self.__port_optoe_dict.get("optoe_start_bus", 0) ++ if port_bus_map is None: # get port bus by optoe_start_bus ++ if optoe_start_bus <= 0: ++ msg = "PLATFORM_INTF_OPTOE optoe_start_bus config error, optoe_start_bus: %d" % optoe_start_bus ++ return False, msg ++ port_bus = port + optoe_start_bus - 1 ++ else: # get port bus by port_bus_map ++ port_bus = port_bus_map.get(port) ++ if port_bus is None: ++ msg = "port %d don't has i2c bus" % port ++ return False, msg ++ if not isinstance(port_bus, int) or port_bus < 0: ++ msg = "port %d i2c bus config error, port_bus: %s " % port_bus ++ return False, msg ++ ++ path = OPTOE_PATH % (port_bus) ++ platform_intf_debug("path:%s" % path) ++ return True, path ++ ++ ########################################### ++ # reg_read - read logic device register ++ # @dev_type: 0: CPLD, 1: FPGA ++ # @dev_id: device ID, start from 0 ++ # @offset: register offset ++ # @size: read length ++ # return: ++ # @ret: True if read success, False if not ++ # @info: The read value list if read success, otherwise the detail error message ++ ########################################### ++ def reg_read(self, dev_type, dev_id, offset, size): ++ ret, path = self.get_dev_path(dev_type, dev_id) ++ if ret is False: ++ return False, path ++ ret, info = dev_file_read(path, offset, size) ++ return ret, info ++ ++ ########################################### ++ # platform_reg_write - write logic device register ++ # @dev_type: 0: CPLD, 1: FPGA ++ # @dev_id: device ID, start from 0 ++ # @offset: register offset ++ # @val_list: The write value list ++ # return: ++ # @ret: True if write success, False if not ++ # @info: The write value length if write success, otherwise the detail error message ++ ########################################### ++ def reg_write(self, dev_type, dev_id, offset, val_list): ++ ret, path = self.get_dev_path(dev_type, dev_id) ++ if ret is False: ++ return False, path ++ ret, info = dev_file_write(path, offset, val_list) ++ return ret, info ++ ++ ########################################### ++ # set_optoe_type - set port optoe type ++ # @port: port index start from 1 ++ # @optoe_type: optoe type, including the following values ++ # 1: OPTOE1 ++ # 2: OPTOE2 ++ # 3: OPTOE3 ++ # return: ++ # @ret: True if set optoe type success, False if not ++ # @info: None if set optoe type success, otherwise the detail error message ++ ########################################### ++ def set_optoe_type(self, port, optoe_type): ++ ret, path = self.get_port_path(port) ++ if ret is False: ++ return False, path ++ optoe_type_path = path + OPTOE_DEV_CLASS ++ ret, info = write_sysfs(optoe_type_path, "%d" % optoe_type) ++ if ret is False: ++ return False, info ++ return True, None ++ ++ ########################################### ++ # get_optoe_type - get port optoe type ++ # @port: port index start from 1 ++ # return: ++ # @ret: True if set optoe type success, False if not ++ # @info: Optoe type value if get optoe type success, otherwise the detail error message ++ # optoe type including the following values ++ # 1: OPTOE1 ++ # 2: OPTOE2 ++ # 3: OPTOE3 ++ ########################################### ++ def get_optoe_type(self, port): ++ ret, path = self.get_port_path(port) ++ if ret is False: ++ return False, path ++ optoe_type_path = path + OPTOE_DEV_CLASS ++ ret, info = read_sysfs(optoe_type_path) ++ if ret is False: ++ return False, info ++ return True, int(info) ++ ++ ########################################### ++ # sfp_read -read sfp eeprom ++ # @port_id: port index start from 1 ++ # @offset: sfp eeprom offset ++ # @size: read sfp eeprom length ++ # return: ++ # @ret: True if read success, False if not ++ # @info: The read value list if read success, otherwise the detail error message ++ ########################################### ++ def sfp_read(self, port_id, offset, size): ++ ret, path = self.get_port_path(port_id) ++ if ret is False: ++ return False, path ++ optoe_eeprom_path = path + OPTOE_EEPROM ++ ret, info = dev_file_read(optoe_eeprom_path, offset, size) ++ return ret, info ++ ++ ########################################### ++ # sfp_write -write sfp eeprom ++ # @port_id: port index start from 1 ++ # @offset: sfp eeprom offset ++ # @val_list: The write value list ++ # return: ++ # @ret: True if read success, False if not ++ # @info: The write value length if write success, otherwise the detail error message ++ ########################################### ++ def sfp_write(self, port_id, offset, val_list): ++ ret, path = self.get_port_path(port_id) ++ if ret is False: ++ return False, path ++ optoe_eeprom_path = path + OPTOE_EEPROM ++ ret, info = dev_file_write(optoe_eeprom_path, offset, val_list) ++ return ret, info ++ ++ ++platform = IntfPlatform() ++ ++ ++########################################### ++# platform_reg_read - read logic device register ++# @dev_type: 0: CPLD, 1: FPGA ++# @dev_id: device ID, start from 0 ++# @offset: register offset ++# @size: read length ++# return: ++# @ret: True if read success, False if not ++# @info: The read value list if read success, otherwise the detail error message ++########################################### ++def platform_reg_read(dev_type, dev_id, offset, size): ++ ret = False ++ info = None ++ ++ # params check ++ if (isinstance(dev_type, int) is False or isinstance(dev_id, int) is False or ++ isinstance(offset, int) is False or isinstance(size, int) is False): ++ info = "params type check fail in platform_reg_read" ++ return ret, info ++ if dev_id < 0 or offset < 0 or size <= 0: ++ info = "params value check fail in platform_reg_read" ++ return ret, info ++ support_dev_type = (CPLD, FPGA) ++ if dev_type not in support_dev_type: ++ info = "dev_type match erro, fail in platform_reg_read" ++ return ret, info ++ ++ # call the solve func ++ return platform.reg_read(dev_type, dev_id, offset, size) ++ ++ ++########################################### ++# platform_reg_write - write logic device register ++# @dev_type: 0: CPLD, 1: FPGA ++# @dev_id: device ID, start from 0 ++# @offset: register offset ++# @val_list: The write value list ++# return: ++# @ret: True if write success, False if not ++# @info: The write value length if write success, otherwise the detail error message ++########################################### ++def platform_reg_write(dev_type, dev_id, offset, val_list): ++ ret = False ++ info = None ++ ++ # params check ++ if (isinstance(dev_type, int) is False or isinstance(dev_id, int) is False or ++ isinstance(offset, int) is False or isinstance(val_list, list) is False): ++ info = "params type check fail in platform_reg_write" ++ return ret, info ++ if dev_id < 0 or offset < 0 or len(val_list) <= 0: ++ info = "params value check fail in platform_reg_write" ++ return ret, info ++ support_dev_type = (CPLD, FPGA) ++ if dev_type not in support_dev_type: ++ info = "dev_type match erro, fail in platform_reg_write" ++ return ret, info ++ ++ # call the solve func ++ return platform.reg_write(dev_type, dev_id, offset, val_list) ++ ++ ++########################################### ++# platform_set_optoe_type - set port optoe type ++# @port: port index start from 1 ++# @optoe_type: optoe type, including the following values ++# 1: OPTOE1 ++# 2: OPTOE2 ++# 3: OPTOE3 ++# return: ++# @ret: True if set optoe type success, False if not ++# @info: None if set optoe type success, otherwise the detail error message ++########################################### ++def platform_set_optoe_type(port, optoe_type): ++ ret = False ++ info = None ++ ++ # params check ++ if isinstance(port, int) is False or isinstance(optoe_type, int) is False: ++ info = "params type check fail in platform_set_optoe_type" ++ return ret, info ++ if port < 0 or optoe_type < 1 or optoe_type > 3: ++ info = "params value check fail in platform_set_optoe_type" ++ return ret, info ++ ++ # call the solve func ++ return platform.set_optoe_type(port, optoe_type) ++ ++ ++########################################### ++# platform_get_optoe_type - get port optoe type ++# @port: port index start from 1 ++# return: ++# @ret: True if set optoe type success, False if not ++# @info: Optoe type value if get optoe type success, otherwise the detail error message ++# optoe type including the following values ++# 1: OPTOE1 ++# 2: OPTOE2 ++# 3: OPTOE3 ++########################################### ++def platform_get_optoe_type(port): ++ ret = False ++ info = None ++ ++ # params check ++ if isinstance(port, int) is False: ++ info = "params type check fail in platform_get_optoe_type" ++ return ret, info ++ if port < 0: ++ info = "params value check fail in platform_get_optoe_type" ++ return ret, info ++ ++ # call the solve func ++ return platform.get_optoe_type(port) ++ ++ ++########################################### ++# platform_sfp_read -read sfp eeprom ++# @port_id: port index start from 1 ++# @offset: sfp eeprom offset ++# @size: read sfp eeprom length ++# return: ++# @ret: True if read success, False if not ++# @info: The read value list if read success, otherwise the detail error message ++########################################### ++def platform_sfp_read(port_id, offset, size): ++ ret = False ++ info = None ++ ++ # params check ++ if isinstance(port_id, int) is False or isinstance(offset, int) is False or isinstance(size, int) is False: ++ info = "params type check fail in platform_sfp_read" ++ return ret, info ++ if port_id < 0 or offset < 0 or size <= 0: ++ info = "params value check fail in platform_sfp_read" ++ return ret, info ++ ++ # call the solve func ++ return platform.sfp_read(port_id, offset, size) ++ ++ ++########################################### ++# platform_sfp_write -write sfp eeprom ++# @port_id: port index start from 1 ++# @offset: sfp eeprom offset ++# @val_list: The write value list ++# return: ++# @ret: True if read success, False if not ++# @info: The write value length if write success, otherwise the detail error message ++########################################### ++def platform_sfp_write(port_id, offset, val_list): ++ ret = False ++ info = None ++ ++ # params check ++ if isinstance(port_id, int) is False or isinstance(offset, int) is False or isinstance(val_list, list) is False: ++ info = "params type check fail in platform_sfp_write" ++ return ret, info ++ if port_id < 0 or offset < 0 or len(val_list) <= 0: ++ info = "params value check fail in platform_sfp_write" ++ return ret, info ++ ++ # call the solve func ++ return platform.sfp_write(port_id, offset, val_list) +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_ipmi.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_ipmi.py +new file mode 100755 +index 000000000..c9b72c99c +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_ipmi.py +@@ -0,0 +1,92 @@ ++#!/usr/bin/env python3 ++# -*- coding: utf-8 -*- ++import sys ++import os ++import syslog ++import click ++from platform_util import exec_os_cmd ++ ++ ++IPMITOOL_CMD = "ipmitool raw 0x32 0x04" # All products are the same command ++ ++PLATFORM_IPMI_DEBUG_FILE = "/etc/.platform_ipmi_debug_flag" ++UPGRADEDEBUG = 1 ++debuglevel = 0 ++ ++ ++def debug_init(): ++ global debuglevel ++ if os.path.exists(PLATFORM_IPMI_DEBUG_FILE): ++ debuglevel = debuglevel | UPGRADEDEBUG ++ else: ++ debuglevel = debuglevel & ~(UPGRADEDEBUG) ++ ++ ++def ipmidebuglog(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ if UPGRADEDEBUG & debuglevel: ++ syslog.openlog("PLATFORM_IPMI", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def ipmierror(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("PLATFORM_IPMI", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++@click.command() ++@click.argument('cmd', required=True) ++def platform_ipmi_main(cmd): ++ '''Send command to BMC through ipmi''' ++ try: ++ # Convert string command to ASCII ++ user_cmd = "" ++ for ch in cmd: ++ user_cmd += " " + str(ord(ch)) ++ ++ final_cmd = IPMITOOL_CMD + user_cmd ++ ipmidebuglog("final cmd:%s" % final_cmd) ++ ++ # exec ipmitool cmd ++ status, output = exec_os_cmd(final_cmd) ++ if status: ++ ipmierror("exec ipmitool_cmd:%s user_cmd:%s failed" % (IPMITOOL_CMD, cmd)) ++ ipmierror("failed log: %s" % output) ++ return False, "exec final_cmd failed" ++ ++ # the data read by ipmitool is hex value, needs transformation ++ data_list = output.replace("\n", "").strip(' ').split(' ') ++ ipmidebuglog("data_list: %s" % data_list) ++ result = "" ++ for data in data_list: ++ result += chr(int(data, 16)) ++ ++ # 'result' string include ret and log, separated by , ++ result_list = result.split(',', 2) ++ if len(result_list) != 2: ++ log = "split failed. len(result) != 2. result:%s" % result ++ ipmierror(log) ++ return False, log ++ if int(result_list[0]) != 0: ++ ipmierror("finally analy ipmitool_cmd:%s user_cmd:%s exec failed" % (IPMITOOL_CMD, cmd)) ++ ipmierror("failed return log: %s" % result_list[1]) ++ print(result_list[1]) ++ return False, result_list[1] ++ ++ ipmidebuglog("finally exec ipmitool_cmd:%s user_cmd:%s success" % (IPMITOOL_CMD, cmd)) ++ print(result_list[1]) ++ return True, result_list[1] ++ ++ except Exception as e: ++ log = "An exception occurred, exception log:%s" % str(e) ++ ipmierror(log) ++ return False, log ++ ++ ++if __name__ == '__main__': ++ debug_init() ++ ret, msg = platform_ipmi_main() ++ if ret is False: ++ sys.exit(1) ++ sys.exit(0) +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_manufacturer.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_manufacturer.py +new file mode 100755 +index 000000000..b2643da9b +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_manufacturer.py +@@ -0,0 +1,562 @@ ++#!/usr/bin/env python3 ++ ++import re ++import mmap ++import fcntl ++import subprocess ++import shlex ++import signal ++import os ++import time ++import sys ++from platform_config import MANUINFO_CONF ++from monitor import status ++ ++ ++INDENT = 4 ++ ++ ++def printerr(vchar): ++ sys.stderr.write(vchar + '\n') ++ ++ ++g_extra_cache = {} ++g_meminfo_cache = {} ++g_exphy_cache = {} ++ ++ ++def exec_os_cmd(cmd, timeout = None): ++ status, output = subprocess.getstatusoutput(cmd) ++ return status, output ++ ++ ++def exphyfwsplit(): ++ # improve performance ++ global g_exphy_cache ++ if g_exphy_cache: ++ return ++ cmd = "bcmcmd -t 1 \"phy control xe,ce fw_get\" |grep fw_version" ++ ret, output = exec_os_cmd(cmd) ++ if ret or len(output) == 0: ++ raise Exception("run cmd: {} error, status: {}, msg: {}".format(cmd, ret, output)) ++ exphyfwstr = output.strip() ++ portlist = exphyfwstr.split("\n") ++ for port in portlist: ++ phy_addr_str = get_regular_val(port, r"phy_addr\s*=\s*\w+", 0) ++ if phy_addr_str.startswith("ERR"): ++ continue ++ phy_addr_key = phy_addr_str.replace(" ", "") ++ if phy_addr_key in g_exphy_cache: ++ continue ++ ++ g_exphy_cache[phy_addr_key] = {} ++ ++ fw_version_str = get_regular_val(port, r"fw_version\s*=\s*\w+", 0) ++ if fw_version_str.startswith("ERR"): ++ del g_exphy_cache[phy_addr_key] ++ continue ++ ++ fw_version = fw_version_str.split("=")[1].strip() ++ g_exphy_cache[phy_addr_key]["fw_version"] = fw_version ++ ++ if "success" in port: ++ ret = "OK" ++ else: ++ ret = "Unexpected" ++ g_exphy_cache[phy_addr_key]["status"] = ret ++ return ++ ++ ++def lshwmemorysplit(): ++ # improve performance ++ global g_meminfo_cache ++ if g_meminfo_cache: ++ return ++ cmd = "lshw -c memory" ++ ret, output = exec_os_cmd(cmd) ++ if ret or len(output) == 0: ++ raise Exception("run cmd: {} error, status: {}, msg: {}".format(cmd, ret, output)) ++ memstr = output.strip() ++ memlist = memstr.split("*-") ++ for item in memlist: ++ if item.strip().startswith("memory") and "System Memory" not in item: ++ continue ++ line_index = 0 ++ for line in item.splitlines(): ++ line_index += 1 ++ if line_index == 1: ++ memdict_key = line ++ g_meminfo_cache[memdict_key] = {} ++ else: ++ if ":" not in line: ++ continue ++ key = line.split(":", 1)[0].strip() ++ value = line.split(":", 1)[1].strip() ++ g_meminfo_cache[memdict_key][key] = value ++ if "empty" in item: ++ break ++ return ++ ++ ++def run_extra_func(funcname): ++ # improve performance ++ if funcname in g_extra_cache: ++ return g_extra_cache.get(funcname) ++ func = getattr(status, funcname) ++ ret = [] ++ func(ret) ++ if ret: ++ g_extra_cache[funcname] = ret ++ return ret ++ ++ ++def get_extra_value(funcname, itemid, key): ++ for item in run_extra_func(funcname): ++ if item.get("id") == itemid: ++ return item.get(key, "NA") ++ return "NA" ++ ++ ++def io_wr(reg_addr, reg_data): ++ try: ++ regdata = 0 ++ regaddr = 0 ++ if isinstance(reg_addr, int): ++ regaddr = reg_addr ++ else: ++ regaddr = int(reg_addr, 16) ++ if isinstance(reg_data, int): ++ regdata = reg_data ++ else: ++ regdata = int(reg_data, 16) ++ devfile = "/dev/port" ++ fd = os.open(devfile, os.O_RDWR | os.O_CREAT) ++ os.lseek(fd, regaddr, os.SEEK_SET) ++ os.write(fd, regdata.to_bytes(1, 'little')) ++ return True ++ except ValueError as e: ++ print(e) ++ return False ++ except Exception as e: ++ print(e) ++ return False ++ finally: ++ os.close(fd) ++ ++ ++def checksignaldriver(name): ++ modisexistcmd = "lsmod | grep -w %s | wc -l" % name ++ ret, output = exec_os_cmd(modisexistcmd) ++ if ret: ++ return False ++ if output.isdigit() and int(output) > 0: ++ return True ++ return False ++ ++ ++def adddriver(name): ++ cmd = "modprobe %s" % name ++ if checksignaldriver(name) is not True: ++ ret, log = exec_os_cmd(cmd) ++ if ret != 0 or len(log) > 0: ++ return False ++ return True ++ return True ++ ++ ++def removedriver(name): ++ cmd = "rmmod %s" % name ++ if checksignaldriver(name): ++ exec_os_cmd(cmd) ++ ++def deal_itmes(item_list): ++ for item in item_list: ++ dealtype = item.get("dealtype") ++ if dealtype == "shell": ++ cmd = item.get("cmd") ++ timeout = item.get("timeout", 10) ++ exec_os_cmd(cmd, timeout) ++ elif dealtype == "io_wr": ++ io_addr = item.get("io_addr") ++ wr_value = item.get("value") ++ io_wr(io_addr, wr_value) ++ ++ ++def get_func_value(funcname, params): ++ func = getattr(ExtraFunc, funcname) ++ ret = func(params) ++ return ret ++ ++ ++def read_pci_reg(pcibus, slot, fn, resource, offset): ++ '''read pci register''' ++ if offset % 4 != 0: ++ return "ERR offset: %d not 4 bytes align" ++ filename = "/sys/bus/pci/devices/0000:%02x:%02x.%x/resource%d" % (int(pcibus), int(slot), int(fn), int(resource)) ++ size = os.path.getsize(filename) ++ with open(filename, "r+") as file: ++ data = mmap.mmap(file.fileno(), size) ++ result = data[offset: offset + 4] ++ s = result[::-1] ++ val = 0 ++ for value in s: ++ val = val << 8 | value ++ data.close() ++ return "%08x" % val ++ ++ ++def devfileread(path, offset, length, bit_width): ++ ret = "" ++ val_str = '' ++ val_list = [] ++ fd = -1 ++ if not os.path.exists(path): ++ return "%s not found !" % path ++ if length % bit_width != 0: ++ return "only support read by bit_width" ++ if length < bit_width: ++ return "len needs to greater than or equal to bit_width" ++ ++ try: ++ fd = os.open(path, os.O_RDONLY) ++ os.lseek(fd, offset, os.SEEK_SET) ++ ret = os.read(fd, length) ++ for item in ret: ++ val_list.append(item) ++ ++ for i in range(0, length, bit_width): ++ for j in range(0, bit_width): ++ val_str += "%02x" % val_list[i + bit_width - j - 1] ++ except Exception as e: ++ return str(e) ++ finally: ++ if fd > 0: ++ os.close(fd) ++ return val_str ++ ++ ++def read_reg(loc, offset, size): ++ with open(loc, 'rb') as file: ++ file.seek(offset) ++ return ' '.join(["%02x" % item for item in file.read(size)]) ++ ++ ++def std_match(stdout, pattern): ++ if pattern is None: ++ return stdout.strip() ++ for line in stdout.splitlines(): ++ if re.match(pattern, line): ++ return line.strip() ++ raise EOFError("pattern: {} does not match anything in stdout {}".format( ++ pattern, stdout)) ++ ++ ++def i2c_rd(bus, loc, offset): ++ ''' ++ read i2c with i2cget command ++ ''' ++ cmd = "i2cget -f -y {} {} {}".format(bus, loc, offset) ++ retrytime = 6 ++ for i in range(retrytime): ++ ret, stdout = subprocess.getstatusoutput(cmd) ++ if ret == 0: ++ return stdout ++ time.sleep(0.1) ++ raise RuntimeError("run cmd: {} error, status {}".format(cmd, ret)) ++ ++ ++def i2c_rd_bytes(bus, loc, offset, size): ++ blist = [] ++ for i in range(size): ++ ret = i2c_rd(bus, loc, offset + i) ++ blist.append(ret) ++ ++ return blist ++ ++ ++def get_pair_val(source, separator): ++ try: ++ value = source.split(separator, 1)[1] ++ except (ValueError, IndexError): ++ return "ERR separator: {} does not match in source: {}".format(separator, source) ++ return value.strip() ++ ++ ++def get_regular_val(source, pattern, group): ++ try: ++ value = re.findall(pattern, source)[group] ++ except Exception: ++ return "ERR pattern: {} does not match in source: {} with group: {}".format(pattern, source, group) ++ return value.strip() ++ ++ ++def find_match(file2read, pattern): ++ with open(file2read, 'r') as file: ++ for line in file: ++ if not re.match(pattern, line): ++ continue ++ return line.strip() ++ return "ERR pattern %s not match in %s" % (pattern, file2read) ++ ++ ++def readaline(file2read): ++ with open(file2read, 'r') as file: ++ return file.readline() ++ ++ ++def sort_key(e): ++ return e.arrt_index ++ ++ ++class ExtraFunc(object): ++ @staticmethod ++ def get_bcm5387_version(params): ++ version = "" ++ try: ++ before_deal_list = params.get("before", []) ++ deal_itmes(before_deal_list) ++ ++ ret, version = exec_os_cmd(params["get_version"]) ++ if ret != 0: ++ version = "ERR " + version ++ ++ after_deal_list = params.get("after", []) ++ deal_itmes(after_deal_list) ++ ++ except Exception as e: ++ version = "ERR %s" % (str(e)) ++ finally: ++ finally_deal_list = params.get("finally", []) ++ deal_itmes(finally_deal_list) ++ return version ++ ++ @staticmethod ++ def get_memory_value(params): ++ root_key = params.get("root_key") ++ sub_key = params.get("sub_key") ++ lshwmemorysplit() ++ return g_meminfo_cache.get(root_key, {}).get(sub_key, "NA") ++ ++ @staticmethod ++ def get_memory_bank_value(params): ++ lshwmemorysplit() ++ bank = params.get("bankid") ++ if g_meminfo_cache.get(bank, {}): ++ return True ++ return False ++ ++ @staticmethod ++ def get_exphy_fw(phyid): ++ exphyfwsplit() ++ if phyid not in g_exphy_cache: ++ return "ERR %s not found." % phyid ++ fw_version = g_exphy_cache.get(phyid).get("fw_version") ++ ret = g_exphy_cache.get(phyid).get("status") ++ msg = "%s %s" % (fw_version, ret) ++ return msg ++ ++class CallbackSet: ++ def cpld_format(self, blist): ++ if isinstance(blist, str): ++ blist = blist.split() ++ elif not isinstance(blist, list) or len(blist) != 4: ++ raise ValueError("cpld format: wrong parameter: {}".format(blist)) ++ ++ return "{}{}{}{}".format(*blist).replace("0x", "") ++ ++ ++class VersionHunter: ++ call = CallbackSet() ++ ++ def __init__(self, entires): ++ self.head = None ++ self.next = None ++ self.key = None ++ self.cmd = None ++ self.file = None ++ self.reg = None ++ self.i2c = None ++ self.extra = None ++ self.pattern = None ++ self.separator = None ++ self.parent = None ++ self.ignore = False ++ self.children = [] ++ self.level = 0 ++ self.callback = None ++ self.delspace = None ++ self.arrt_index = None ++ self.config = None ++ self.precheck = None ++ self.func = None ++ self.regular = None ++ self.group = 0 ++ self.pci = None ++ self.devfile = None ++ self.decode = None ++ self.timeout = 10 ++ self.__dict__.update(entires) ++ ++ def check_para(self): ++ if self.pattern is None: ++ return False ++ if self.cmd is None or self.file is None: ++ return False ++ return True ++ ++ def get_version(self): ++ ret = "NA" ++ try: ++ if self.cmd is not None: ++ ret, output = exec_os_cmd(self.cmd, self.timeout) ++ if ret or len(output) == 0: ++ raise RuntimeError("run cmd: {} error, status: {}, msg: {}".format(self.cmd, ret, output)) ++ ret = std_match(output, self.pattern) ++ elif self.file is not None: ++ ret = self.read_file() ++ elif self.reg is not None: ++ ret = read_reg(self.reg.get("loc"), self.reg.get("offset"), ++ self.reg.get("size")) ++ elif self.extra: ++ ret = get_extra_value(self.extra.get("funcname"), ++ self.extra.get("id"), ++ self.extra.get("key")) ++ elif self.i2c: ++ ret = i2c_rd_bytes(self.i2c.get("bus"), self.i2c.get("loc"), ++ self.i2c.get("offset"), ++ self.i2c.get("size")) ++ elif self.config: ++ ret = self.config ++ elif self.func: ++ ret = get_func_value(self.func.get("funcname"), ++ self.func.get("params")) ++ elif self.pci: ++ ret = read_pci_reg(self.pci.get("bus"), self.pci.get("slot"), ++ self.pci.get("fn"), self.pci.get("bar"), self.pci.get("offset")) ++ elif self.devfile: ++ ret = devfileread(self.devfile.get("loc"), self.devfile.get("offset"), ++ self.devfile.get("len"), self.devfile.get("bit_width")) ++ ++ except Exception as e: ++ # printerr(e.message) ++ return "ERR %s" % str(e) ++ return self.exe_callback(ret) ++ ++ def exe_callback(self, data): ++ try: ++ if self.callback: ++ method = getattr(self.call, self.callback) ++ return method(data) ++ except Exception: ++ return "ERR run callback method: {} error, data: {}".format(self.callback, data) ++ return data ++ ++ def read_file(self): ++ if self.pattern is not None: ++ return find_match(self.file, self.pattern) ++ return readaline(self.file) ++ ++ def hunt(self): ++ if self.ignore: ++ return ++ indent = self.level * INDENT * " " ++ ++ if self.precheck: ++ try: ++ ret = get_func_value(self.precheck.get("funcname"), self.precheck.get("params")) ++ if ret is not True: ++ return ++ except Exception as e: ++ err_msg = "ERR %s" % str(e) ++ format_str = "{}{:<{}}{}".format(indent, self.key + ':', ++ (30 - len(indent)), err_msg) ++ print(format_str) ++ return ++ # has children ++ if self.children: ++ self.children.sort(key=sort_key) ++ format_str = "{}{}:".format(indent, self.key) ++ print(format_str) ++ for child in self.children: ++ if not isinstance(child, VersionHunter): ++ continue ++ child.level = self.level + 1 ++ child.hunt() ++ else: ++ version = self.get_version() or "" ++ if not version.startswith("ERR"): ++ version = version.replace("\x00", "").strip() ++ if self.separator is not None: ++ version = get_pair_val(version, self.separator) ++ if self.delspace is not None: ++ version = version.replace(" ", "") ++ if self.regular is not None: ++ version = get_regular_val(version, self.regular, self.group) ++ if self.decode is not None: ++ tmp_version = self.decode.get(version) ++ if tmp_version is None: ++ version = "ERR decode %s failed" % version ++ else: ++ version = tmp_version ++ format_str = "{}{:<{}}{}".format(indent, self.key + ':', ++ (30 - len(indent)), version) ++ print(format_str) ++ ++ if self.next: ++ print("") ++ self.next.hunt() ++ ++ ++pidfile = 0 ++ ++ ++def ApplicationInstance(): ++ global pidfile ++ pidfile = open(os.path.realpath(__file__), "r") ++ try: ++ fcntl.flock(pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB) ++ return True ++ except Exception: ++ return False ++ ++ ++def run(): ++ if os.geteuid() != 0: ++ print("Root privileges are required for this operation") ++ sys.exit(1) ++ ++ start_time = time.time() ++ while True: ++ ret = ApplicationInstance() ++ if ret is True: ++ break ++ if time.time() - start_time > 10: ++ printerr("manufacturer is running.") ++ sys.exit(1) ++ time.sleep(0.5) ++ ++ objmap = {} ++ ++ try: ++ target = {} ++ target.update(MANUINFO_CONF) ++ for objname, value in target.items(): ++ objmap[objname] = VersionHunter(value) ++ except Exception as e: ++ printerr(str(e)) ++ sys.exit(1) ++ ++ head = None ++ for objname, obj in objmap.items(): ++ if head is None and obj.head: ++ head = obj ++ if obj.parent: ++ objmap.get(obj.parent).children.append(obj) ++ if obj.next: ++ obj.next = objmap.get(obj.next) ++ ++ head.hunt() ++ ++ ++if __name__ == "__main__": ++ run() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_process.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_process.py +new file mode 100755 +index 000000000..f19231bba +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_process.py +@@ -0,0 +1,413 @@ ++#!/usr/bin/env python3 ++import os ++import subprocess ++import glob ++import time ++import click ++import shutil ++from platform_config import STARTMODULE, MAC_LED_RESET, AIRFLOW_RESULT_FILE ++from platform_config import GLOBALINITPARAM, GLOBALINITCOMMAND, GLOBALINITPARAM_PRE, GLOBALINITCOMMAND_PRE ++from platform_util import wbpciwr ++ ++ ++CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} ++ ++ ++class AliasedGroup(click.Group): ++ def get_command(self, ctx, cmd_name): ++ rv = click.Group.get_command(self, ctx, cmd_name) ++ if rv is not None: ++ return rv ++ matches = [x for x in self.list_commands(ctx) ++ if x.startswith(cmd_name)] ++ if not matches: ++ return None ++ if len(matches) == 1: ++ return click.Group.get_command(self, ctx, matches[0]) ++ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) ++ return None ++ ++ ++def log_os_system(cmd): ++ status, output = subprocess.getstatusoutput(cmd) ++ if status: ++ print(output) ++ return status, output ++ ++ ++def write_sysfs_value(reg_name, value): ++ mb_reg_file = "/sys/bus/i2c/devices/" + reg_name ++ locations = glob.glob(mb_reg_file) ++ if len(locations) == 0: ++ print("%s not found" % mb_reg_file) ++ return False ++ sysfs_loc = locations[0] ++ try: ++ with open(sysfs_loc, 'w') as fd: ++ fd.write(value) ++ except Exception: ++ return False ++ return True ++ ++ ++def getPid(name): ++ ret = [] ++ for dirname in os.listdir('/proc'): ++ if dirname == 'curproc': ++ continue ++ try: ++ with open('/proc/{}/cmdline'.format(dirname), mode='r') as fd: ++ content = fd.read() ++ except Exception: ++ continue ++ if name in content: ++ ret.append(dirname) ++ return ret ++ ++ ++def startAvscontrol(): ++ if STARTMODULE.get('avscontrol', 0) == 1: ++ cmd = "nohup avscontrol.py start >/dev/null 2>&1 &" ++ rets = getPid("avscontrol.py") ++ if len(rets) == 0: ++ os.system(cmd) ++ ++ ++def startFanctrol(): ++ if STARTMODULE.get('fancontrol', 0) == 1: ++ cmd = "nohup fancontrol.py start >/dev/null 2>&1 &" ++ rets = getPid("fancontrol.py") ++ if len(rets) == 0: ++ os.system(cmd) ++ ++ ++def starthal_fanctrl(): ++ if STARTMODULE.get('hal_fanctrl', 0) == 1: ++ cmd = "nohup hal_fanctrl.py start >/dev/null 2>&1 &" ++ rets = getPid("hal_fanctrl.py") ++ if len(rets) == 0: ++ os.system(cmd) ++ ++ ++def starthal_ledctrl(): ++ if STARTMODULE.get('hal_ledctrl', 0) == 1: ++ cmd = "nohup hal_ledctrl.py start >/dev/null 2>&1 &" ++ rets = getPid("hal_ledctrl.py") ++ if len(rets) == 0: ++ os.system(cmd) ++ ++ ++def startDevmonitor(): ++ if STARTMODULE.get('dev_monitor', 0) == 1: ++ cmd = "nohup dev_monitor.py start >/dev/null 2>&1 &" ++ rets = getPid("dev_monitor.py") ++ if len(rets) == 0: ++ os.system(cmd) ++ ++ ++def startSlotmonitor(): ++ if STARTMODULE.get('slot_monitor', 0) == 1: ++ cmd = "nohup slot_monitor.py start >/dev/null 2>&1 &" ++ rets = getPid("slot_monitor.py") ++ if len(rets) == 0: ++ os.system(cmd) ++ ++ ++def startIntelligentmonitor(): ++ if STARTMODULE.get('intelligent_monitor', 0) == 1: ++ cmd = "nohup intelligent_monitor.py >/dev/null 2>&1 &" ++ rets = getPid("intelligent_monitor.py") ++ if len(rets) == 0: ++ os.system(cmd) ++ ++ ++def startSignalmonitor(): ++ if STARTMODULE.get('signal_monitor', 0) == 1: ++ cmd = "nohup signal_monitor.py start >/dev/null 2>&1 &" ++ rets = getPid("signal_monitor.py") ++ if len(rets) == 0: ++ os.system(cmd) ++ ++ ++def startSff_temp_polling(): ++ if STARTMODULE.get('sff_temp_polling', 0) == 1: ++ cmd = "nohup sfp_highest_temperatue.py >/dev/null 2>&1 &" ++ rets = getPid("sfp_highest_temperatue.py") ++ if len(rets) == 0: ++ os.system(cmd) ++ ++ ++def startRebootCause(): ++ if STARTMODULE.get('reboot_cause', 0) == 1: ++ cmd = "nohup reboot_cause.py >/dev/null 2>&1 &" ++ rets = getPid("reboot_cause.py") ++ if len(rets) == 0: ++ os.system(cmd) ++ ++ ++def startPMON_sys(): ++ if STARTMODULE.get('pmon_syslog', 0) == 1: ++ cmd = "nohup pmon_syslog.py >/dev/null 2>&1 &" ++ rets = getPid("pmon_syslog.py") ++ if len(rets) == 0: ++ os.system(cmd) ++ ++ ++def startSff_polling(): ++ if STARTMODULE.get('sff_polling', 0) == 1: ++ cmd = "nohup sff_polling.py start > /dev/null 2>&1 &" ++ rets = getPid("sff_polling.py") ++ if len(rets) == 0: ++ os.system(cmd) ++ ++ ++def generate_air_flow(): ++ cmd = "nohup generate_airflow.py > /dev/null 2>&1 &" ++ rets = getPid("generate_airflow.py") ++ if len(rets) == 0: ++ os.system(cmd) ++ time.sleep(1) ++ ++ ++def startGenerate_air_flow(): ++ if STARTMODULE.get('generate_airflow', 0) == 1: ++ for i in range(10): ++ generate_air_flow() ++ if os.path.exists(AIRFLOW_RESULT_FILE): ++ click.echo("%%WB_PLATFORM_PROCESS: generate air flow success") ++ return ++ time.sleep(1) ++ click.echo("%%WB_PLATFORM_PROCESS: generate air flow,failed, %s not exits" % AIRFLOW_RESULT_FILE) ++ return ++ ++ ++def start_tty_console(): ++ if STARTMODULE.get('tty_console', 0) == 1: ++ cmd = "nohup tty_console.py > /dev/null 2>&1 &" ++ rets = getPid("tty_console.py") ++ if len(rets) == 0: ++ os.system(cmd) ++ ++def startDrvUpdate(): ++ if STARTMODULE.get('drv_update', 0) == 1: ++ cmd = "nohup drv_update.py >/dev/null 2>&1 &" ++ rets = getPid("drv_update.py") ++ if len(rets) == 0: ++ os.system(cmd) ++ ++ ++def stopAvscontrol(): ++ if STARTMODULE.get('avscontrol', 0) == 1: ++ rets = getPid("avscontrol.py") ++ for ret in rets: ++ cmd = "kill " + ret ++ os.system(cmd) ++ ++ ++def stopFanctrol(): ++ if STARTMODULE.get('fancontrol', 0) == 1: ++ rets = getPid("fancontrol.py") # ++ for ret in rets: ++ cmd = "kill " + ret ++ os.system(cmd) ++ ++ ++def stophal_fanctrl(): ++ if STARTMODULE.get('hal_fanctrl', 0) == 1: ++ rets = getPid("hal_fanctrl.py") ++ for ret in rets: ++ cmd = "kill " + ret ++ os.system(cmd) ++ ++ ++def stophal_ledctrl(): ++ if STARTMODULE.get('hal_ledctrl', 0) == 1: ++ rets = getPid("hal_ledctrl.py") ++ for ret in rets: ++ cmd = "kill " + ret ++ os.system(cmd) ++ ++ ++def stopDevmonitor(): ++ if STARTMODULE.get('dev_monitor', 0) == 1: ++ rets = getPid("dev_monitor.py") # ++ for ret in rets: ++ cmd = "kill " + ret ++ os.system(cmd) ++ ++ ++def stopSlotmonitor(): ++ if STARTMODULE.get('slot_monitor', 0) == 1: ++ rets = getPid("slot_monitor.py") # ++ for ret in rets: ++ cmd = "kill " + ret ++ os.system(cmd) ++ ++ ++def stopIntelligentmonitor(): ++ if STARTMODULE.get('intelligent_monitor', 0) == 1: ++ rets = getPid("intelligent_monitor.py") ++ for ret in rets: ++ cmd = "kill " + ret ++ os.system(cmd) ++ ++ ++def stopSignalmonitor(): ++ if STARTMODULE.get('signal_monitor', 0) == 1: ++ rets = getPid("signal_monitor.py") # ++ for ret in rets: ++ cmd = "kill " + ret ++ os.system(cmd) ++ ++ ++def stopSff_temp_polling(): ++ if STARTMODULE.get('sff_temp_polling', 0) == 1: ++ rets = getPid("sfp_highest_temperatue.py") ++ for ret in rets: ++ cmd = "kill " + ret ++ os.system(cmd) ++ ++ ++def stopPMON_sys(): ++ if STARTMODULE.get('pmon_syslog', 0) == 1: ++ rets = getPid("pmon_syslog.py") ++ for ret in rets: ++ cmd = "kill " + ret ++ os.system(cmd) ++ ++ ++def stopRebootCause(): ++ if STARTMODULE.get('reboot_cause', 0) == 1: ++ rets = getPid("reboot_cause.py") ++ for ret in rets: ++ cmd = "kill " + ret ++ os.system(cmd) ++ ++ ++def stopSff_polling(): ++ if STARTMODULE.get('sff_polling', 0) == 1: ++ rets = getPid("sff_polling.py") ++ for ret in rets: ++ cmd = "kill " + ret ++ os.system(cmd) ++ ++ ++def stopGenerate_air_flow(): ++ if STARTMODULE.get('generate_airflow', 0) == 1: ++ rets = getPid("generate_airflow.py") ++ for ret in rets: ++ cmd = "kill " + ret ++ os.system(cmd) ++ ++ ++def stop_tty_console(): ++ if STARTMODULE.get('tty_console', 0) == 1: ++ rets = getPid("tty_console.py") ++ for ret in rets: ++ cmd = "kill " + ret ++ os.system(cmd) ++ ++ ++def otherinit(): ++ for index in GLOBALINITPARAM: ++ write_sysfs_value(index["loc"], index["value"]) ++ ++ for index in GLOBALINITCOMMAND: ++ log_os_system(index) ++ ++ ++def otherinit_pre(): ++ for index in GLOBALINITPARAM_PRE: ++ write_sysfs_value(index["loc"], index["value"]) ++ ++ for index in GLOBALINITCOMMAND_PRE: ++ log_os_system(index) ++ ++ ++def unload_apps(): ++ stopSff_polling() ++ stopPMON_sys() ++ stopSignalmonitor() ++ stopIntelligentmonitor() ++ stopSlotmonitor() ++ stopDevmonitor() ++ stopAvscontrol() ++ stophal_ledctrl() ++ stophal_fanctrl() ++ stopFanctrol() ++ stopSff_temp_polling() ++ stopRebootCause() ++ stop_tty_console() ++ stopGenerate_air_flow() ++ ++ ++def MacLedSet(data): ++ '''write pci register''' ++ pcibus = MAC_LED_RESET.get("pcibus") ++ slot = MAC_LED_RESET.get("slot") ++ fn = MAC_LED_RESET.get("fn") ++ resource = MAC_LED_RESET.get("bar") ++ offset = MAC_LED_RESET.get("offset") ++ val = MAC_LED_RESET.get(data, None) ++ if val is None: ++ click.echo("%%WB_PLATFORM_PROCESS-INIT: MacLedSet wrong input") ++ return ++ wbpciwr(pcibus, slot, fn, resource, offset, val) ++ ++ ++def copy_machineconf(): ++ try: ++ shutil.copyfile("/host/machine.conf", "/etc/sonic/machine.conf") ++ return True ++ except Exception: ++ return False ++ ++def load_apps(): ++ copy_machineconf() ++ otherinit_pre() ++ startDrvUpdate() ++ startGenerate_air_flow() ++ start_tty_console() ++ startRebootCause() ++ startSff_temp_polling() ++ startFanctrol() ++ starthal_fanctrl() ++ starthal_ledctrl() ++ startAvscontrol() ++ startDevmonitor() ++ startSlotmonitor() ++ startIntelligentmonitor() ++ startSignalmonitor() ++ startPMON_sys() ++ startSff_polling() ++ otherinit() ++ if STARTMODULE.get("macledreset", 0) == 1: ++ MacLedSet("reset") ++ ++ ++@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) ++def main(): ++ '''device operator''' ++ ++ ++@main.command() ++def start(): ++ '''load process ''' ++ load_apps() ++ ++ ++@main.command() ++def stop(): ++ '''stop process ''' ++ unload_apps() ++ ++ ++@main.command() ++def restart(): ++ '''restart process''' ++ unload_apps() ++ load_apps() ++ ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_sensors.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_sensors.py +new file mode 100755 +index 000000000..d5b72f48f +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_sensors.py +@@ -0,0 +1,272 @@ ++#!/usr/bin/python3 ++ ++import os ++import sys ++import importlib.machinery ++ ++ ++def get_machine_info(): ++ if not os.path.isfile('/host/machine.conf'): ++ return None ++ machine_vars = {} ++ with open('/host/machine.conf') as machine_file: ++ for line in machine_file: ++ tokens = line.split('=') ++ if len(tokens) < 2: ++ continue ++ machine_vars[tokens[0]] = tokens[1].strip() ++ return machine_vars ++ ++ ++def get_platform_info(machine_info): ++ if machine_info is not None: ++ if 'onie_platform' in machine_info: ++ return machine_info['onie_platform'] ++ if 'aboot_platform' in machine_info: ++ return machine_info['aboot_platform'] ++ return None ++ ++ ++PLATFORM_ROOT_PATH = '/usr/share/sonic/device' ++PLATFORM_SPECIFIC_MODULE_NAME = 'monitor' ++PLATFORM_SPECIFIC_CLASS_NAME = 'status' ++platform_status_class = None ++platform = None ++ ++ ++def get_platform_name(): ++ global platform ++ platform = get_platform_info(get_machine_info()) ++ return platform ++ ++ ++val = get_platform_name() ++sys.path.append("/".join([PLATFORM_ROOT_PATH, platform])) ++ ++# Loads platform specific sfputil module from source ++ ++ ++def load_platform_monitor(): ++ global platform_status_class ++ platform_name = get_platform_info(get_machine_info()) ++ platform_path = "/".join([PLATFORM_ROOT_PATH, platform_name]) ++ try: ++ module_file = "/".join([platform_path, PLATFORM_SPECIFIC_MODULE_NAME + ".py"]) ++ module = importlib.machinery.SourceFileLoader(PLATFORM_SPECIFIC_MODULE_NAME, module_file).load_module() ++ except IOError: ++ return -1 ++ try: ++ platform_status_class = getattr(module, PLATFORM_SPECIFIC_CLASS_NAME) ++ except AttributeError: ++ return -2 ++ return 0 ++ ++ ++def printerr(msg): ++ print("\033[0;31m%s\033[0m" % msg) ++ ++ ++def print_console(msg): ++ print(msg) ++ ++ ++val_t = load_platform_monitor() ++if val_t != 0: ++ raise Exception("load monitor.py error") ++ ++ ++def print_platform(): ++ platform_info = get_platform_name() ++ print_console(platform_info) ++ print_console("") ++ ++ ++def print_cputemp_sensors(): ++ val_ret = get_call_value_by_function("getcputemp") ++ print_info_str = "" ++ toptile = "Onboard coretemp Sensors:" ++ formatstr = " {name:<20} : {temp} C (high = {max} C , crit = {crit} C )" ++ ++ if len(val_ret) != 0: ++ print_info_str += toptile + '\n' ++ for item in val_ret: ++ print_info_str += formatstr.format(**item) + '\n' ++ print_console(print_info_str) ++ ++ ++def print_boardtemp(): ++ val_ret = get_call_value_by_function("getTemp") ++ print_info_str = "" ++ toptile = "Onboard Temperature Sensors:" ++ errformat = " {id:<20} : {errmsg}" ++ formatstr = " {id:<20} : {temp1_input} C (high = {temp1_max} C, hyst = {temp1_max_hyst} C)" ++ ++ if len(val_ret) != 0: ++ print_info_str += toptile + '\n' ++ for item in val_ret: ++ realformat = formatstr if item.get('errcode', 0) == 0 else errformat ++ print_info_str += realformat.format(**item) + '\n' ++ print_console(print_info_str) ++ ++ ++def print_mactemp_sensors(): ++ val_ret = get_call_value_by_function("getmactemp") ++ print_info_str = "" ++ toptile = "Onboard MAC Temperature Sensors:" ++ errformat = " {id:<20} : {errmsg}" ++ formatstr = " {id:<20} : {temp_input} C" ++ ++ if len(val_ret) != 0: ++ print_info_str += toptile + '\n' ++ for item in val_ret: ++ realformat = formatstr if item.get('errcode', 0) == 0 else errformat ++ print_info_str += realformat.format(**item) + '\n' ++ print_console(print_info_str) ++ ++ ++def print_macpower_sensors(): ++ val_ret = get_call_value_by_function("getmacpower") ++ print_info_str = "" ++ toptile = "Onboard MAC Power Sensors:" ++ errformat = " {id:<20} : {errmsg}" ++ formatstr = " {id:<20} : {power_input} W" ++ ++ if len(val_ret) != 0: ++ print_info_str += toptile + '\n' ++ for item in val_ret: ++ realformat = formatstr if item.get('errcode', 0) == 0 else errformat ++ print_info_str += realformat.format(**item) + '\n' ++ print_console(print_info_str) ++ ++ ++def print_fan_sensor(): ++ val_ret = get_call_value_by_function("checkFan") ++ print_info_str = "" ++ toptile = "Onboard fan Sensors:" ++ errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" ++ fan_signle_rotor_format = " {id} : \n" \ ++ " fan_type : {fan_type}\n" \ ++ " sn : {sn}\n" \ ++ " hw_version: {hw_version}\n" \ ++ " Speed : {Speed} RPM\n" \ ++ " status : {errmsg} \n" ++ fan_double_rotor_format = " {id} : \n" \ ++ " fan_type : {fan_type}\n" \ ++ " sn : {sn}\n" \ ++ " hw_version: {hw_version}\n" \ ++ " Speed :\n" \ ++ " speed_front : {rotor1_speed:<5} RPM\n" \ ++ " speed_rear : {rotor2_speed:<5} RPM\n" \ ++ " status : {errmsg} \n" ++ ++ if len(val_ret) != 0: ++ print_info_str += toptile + '\n' ++ for item in val_ret: ++ if item.get('Speed', None) is None: ++ realformat = fan_double_rotor_format if item.get('errcode', 0) == 0 else errformat ++ else: ++ realformat = fan_signle_rotor_format if item.get('errcode', 0) == 0 else errformat ++ print_info_str += realformat.format(**item) ++ print_console(print_info_str) ++ ++ ++def print_psu_sensor(): ++ val_ret = get_call_value_by_function("getPsu") ++ print_info_str = "" ++ toptile = "Onboard Power Supply Unit Sensors:" ++ errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" ++ psuformat = " {id} : \n" \ ++ " type : {type1}\n" \ ++ " sn : {sn}\n" \ ++ " in_current : {in_current} A\n" \ ++ " in_voltage : {in_voltage} V\n" \ ++ " out_current: {out_current} A\n" \ ++ " out_voltage: {out_voltage} V\n" \ ++ " temp : {temp} C \n" \ ++ " fan_speed : {fan_speed} RPM\n" \ ++ " in_power : {in_power} W\n" \ ++ " out_power : {out_power} W\n" ++ ++ if len(val_ret) != 0: ++ print_info_str += toptile + '\r\n' ++ for item in val_ret: ++ realformat = psuformat if item.get('errcode', 0) == 0 else errformat ++ print_info_str += realformat.format(**item) ++ print_console(print_info_str) ++ ++def print_cust_psu_sensor(): ++ val_ret = get_call_value_by_function("getCustPsu") ++ print_info_str = "" ++ toptile = "Onboard Power Supply Unit Sensors:" ++ errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" ++ psuformat = " {id} : \n" \ ++ " Model : {type1}\n" \ ++ " Serial : {sn}\n" \ ++ " HW Rev : {hw_version}\n" \ ++ " Status : {errmsg}\n" ++ ++ if len(val_ret) != 0: ++ print_info_str += toptile + '\r\n' ++ for item in val_ret: ++ realformat = psuformat if item.get('errcode', 0) == 0 else errformat ++ print_info_str += realformat.format(**item) ++ print_console(print_info_str) ++ ++ ++def print_slot_sensor(): ++ val_ret = get_call_value_by_function("checkSlot") ++ print_info_str = "" ++ toptile = "Onboard slot Sensors:" ++ errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" ++ psuformat = " {id} : \n" \ ++ " slot_type : {slot_type}\n" \ ++ " sn : {sn}\n" \ ++ " hw_version : {hw_version} \n" \ ++ " status : {errmsg}\n" ++ ++ if len(val_ret) != 0: ++ print_info_str += toptile + '\r\n' ++ for item in val_ret: ++ realformat = psuformat if item.get('errcode', 0) == 0 else errformat ++ print_info_str += realformat.format(**item) ++ print_console(print_info_str) ++ ++ ++def print_boarddcdc(): ++ val_ret = get_call_value_by_function("getDcdc") ++ print_info_str = "" ++ toptile = "Onboard DCDC Sensors:" ++ errformat = " {id:<26} : {errmsg}" ++ formatstr = " {id:<26} : {dcdc_input:<6} {dcdc_unit:<1} (Min = {dcdc_min:<6} {dcdc_unit:<1}, Max = {dcdc_max:<6} {dcdc_unit:<1})" ++ ++ if len(val_ret) != 0: ++ print_info_str += toptile + '\n' ++ for item in val_ret: ++ realformat = formatstr if item.get('errcode', 0) == 0 else errformat ++ print_info_str += realformat.format(**item) + '\n' ++ print_console(print_info_str) ++ ++ ++def get_call_value_by_function(function_name): ++ valtemp = [] ++ if hasattr(platform_status_class, function_name): ++ test2_func = getattr(platform_status_class, function_name) ++ test2_func(valtemp) ++ return valtemp ++ ++ ++def getsensors(): ++ print_platform() ++ print_cputemp_sensors() ++ print_boardtemp() ++ print_mactemp_sensors() ++ print_macpower_sensors() ++ print_fan_sensor() ++ print_psu_sensor() ++ print_cust_psu_sensor() ++ print_slot_sensor() ++ print_boarddcdc() ++ ++ ++if __name__ == "__main__": ++ getsensors() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_test.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_test.py +new file mode 100755 +index 000000000..da7119a9c +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_test.py +@@ -0,0 +1,142 @@ ++#!/usr/bin/env python3 ++# -*- coding: UTF-8 -*- ++ ++try: ++ import click ++ from platform_intf import platform_reg_read, platform_reg_write, platform_get_optoe_type ++ from platform_intf import platform_set_optoe_type, platform_sfp_read, platform_sfp_write ++except ImportError as error: ++ raise ImportError('%s - required module not found' % str(error)) from error ++ ++ ++CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} ++ ++ ++class AliasedGroup(click.Group): ++ def get_command(self, ctx, cmd_name): ++ rv = click.Group.get_command(self, ctx, cmd_name) ++ if rv is not None: ++ return rv ++ matches = [x for x in self.list_commands(ctx) ++ if x.startswith(cmd_name)] ++ if not matches: ++ return None ++ if len(matches) == 1: ++ return click.Group.get_command(self, ctx, matches[0]) ++ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) ++ return None ++ ++ ++def print_reg(info, offset): ++ try: ++ size = len(info) ++ j = offset % 16 ++ tmp = j ++ offset -= j ++ print_buf = "\n " ++ ++ for i in range(16): ++ print_buf = print_buf + "%2x " % i ++ print(print_buf) ++ ++ print_buf = None ++ for i in range(size + j): ++ if i % 16 == 0: ++ print_buf = "" ++ print_buf = "0x%08x " % offset ++ offset = offset + 16 ++ if tmp: ++ print_buf = print_buf + " " ++ tmp = tmp - 1 ++ else: ++ print_buf = print_buf + "%02x " % info[i - j] ++ if (i + 1) % 16 == 0 or i == size + j - 1: ++ print(print_buf) ++ except Exception as e: ++ msg = str(e) ++ print("i = %d, j = %d," % (i, j)) ++ print(msg) ++ ++ ++@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) ++def main(): ++ '''platform_test main''' ++ ++ ++@main.command() ++@click.argument('dev_type', required=True) ++@click.argument('dev_id', required=True) ++@click.argument('offset', required=True) ++@click.argument('size', required=True) ++def reg_rd(dev_type, dev_id, offset, size): ++ '''read cpld/fpga reg''' ++ ret, info = platform_reg_read(int(dev_type), int(dev_id), int(offset), int(size)) ++ print(ret) ++ if ret is True: ++ print_reg(info, int(offset)) ++ else: ++ print(info) ++ ++ ++@main.command() ++@click.argument('dev_type', required=True) ++@click.argument('dev_id', required=True) ++@click.argument('offset', required=True) ++@click.argument('value', required=True) ++def reg_wr(dev_type, dev_id, offset, value): ++ '''write cpld/fpga reg''' ++ value_list = [] ++ value_list.append(int(value)) ++ ret, info = platform_reg_write(int(dev_type), int(dev_id), int(offset), value_list) ++ print(ret) ++ print(info) ++ ++ ++@main.command() ++@click.argument('port', required=True) ++def get_optoe_type(port): ++ '''get optoe type''' ++ ret, info = platform_get_optoe_type(int(port)) ++ print(ret) ++ print(info) ++ ++ ++@main.command() ++@click.argument('port', required=True) ++@click.argument('optoe_type', required=True) ++def set_optoe_type(port, optoe_type): ++ '''set optoe type''' ++ ret, info = platform_set_optoe_type(int(port), int(optoe_type)) ++ print(ret) ++ print(info) ++ ++ ++@main.command() ++@click.argument('port_id', required=True) ++@click.argument('offset', required=True) ++@click.argument('size', required=True) ++def sfp_rd(port_id, offset, size): ++ '''read sfp''' ++ ret, info = platform_sfp_read(int(port_id), int(offset), int(size)) ++ print(ret) ++ if ret is True: ++ print_reg(info, int(offset)) ++ else: ++ print(info) ++ ++ ++@main.command() ++@click.argument('port_id', required=True) ++@click.argument('offset', required=True) ++@click.argument('value', required=True) ++def sfp_wr(port_id, offset, value): ++ '''write sfp''' ++ value_list = [] ++ value_list.append(int(value)) ++ ret, info = platform_sfp_write(int(port_id), int(offset), value_list) ++ print(ret) ++ print(info) ++ ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_util.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_util.py +new file mode 100755 +index 000000000..71a97e5a2 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_util.py +@@ -0,0 +1,838 @@ ++#!/usr/bin/python3 ++ ++import sys ++import os ++import re ++import subprocess ++import shlex ++import time ++import mmap ++import glob ++import logging.handlers ++import shutil ++import gzip ++import ast ++ ++ ++CONFIG_DB_PATH = "/etc/sonic/config_db.json" ++MAILBOX_DIR = "/sys/bus/i2c/devices/" ++ ++ ++__all__ = [ ++ "strtoint", ++ "byteTostr", ++ "getplatform_name", ++ "wbi2cget", ++ "wbi2cset", ++ "wbpcird", ++ "wbpciwr", ++ "wbi2cgetWord", ++ "wbi2csetWord", ++ "wbi2cset_pec", ++ "wbi2cset_wordpec", ++ "wbsysset", ++ "dev_file_read", ++ "dev_file_write", ++ "wb_os_system", ++ "io_rd", ++ "io_wr", ++ "exec_os_cmd", ++ "exec_os_cmd_log", ++ "write_sysfs", ++ "read_sysfs", ++ "get_sysfs_value", ++ "write_sysfs_value", ++ "get_value", ++ "set_value", ++ "getSdkReg", ++ "getMacTemp", ++ "getMacTemp_sysfs", ++ "get_format_value" ++] ++ ++class CodeVisitor(ast.NodeVisitor): ++ ++ def __init__(self): ++ self.value = None ++ ++ def get_value(self): ++ return self.value ++ ++ def get_op_value(self, node): ++ if isinstance(node, ast.Call): # node is func call ++ value = self.visit_Call(node) ++ elif isinstance(node, ast.BinOp): # node is BinOp ++ value = self.visit_BinOp(node) ++ elif isinstance(node, ast.UnaryOp): # node is UnaryOp ++ value = self.visit_UnaryOp(node) ++ elif isinstance(node, ast.Num): # node is Num Constant ++ value = node.n ++ elif isinstance(node, ast.Str): # node is Str Constant ++ value = node.s ++ else: ++ raise NotImplementedError("Unsupport operand type: %s" % type(node)) ++ return value ++ ++ def visit_UnaryOp(self, node): ++ ''' ++ node.op: operand type, only support ast.UAdd/ast.USub ++ node.operand: only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.UnaryOp ++ ''' ++ ++ operand_value = self.get_op_value(node.operand) ++ if isinstance(node.op, ast.UAdd): ++ self.value = operand_value ++ elif isinstance(node.op, ast.USub): ++ self.value = 0 - operand_value ++ else: ++ raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) ++ return self.value ++ ++ def visit_BinOp(self, node): ++ ''' ++ node.left: left operand, only support ast.Call/ast.Constant(ast.Num)/ast.BinOp ++ node.op: operand type, only support ast.Add/ast.Sub/ast.Mult/ast.Div ++ node.right: right operan, only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp ++ ''' ++ left_value = self.get_op_value(node.left) ++ right_value = self.get_op_value(node.right) ++ ++ if isinstance(node.op, ast.Add): ++ self.value = left_value + right_value ++ elif isinstance(node.op, ast.Sub): ++ self.value = left_value - right_value ++ elif isinstance(node.op, ast.Mult): ++ self.value = left_value * right_value ++ elif isinstance(node.op, ast.Div): ++ self.value = left_value / right_value ++ else: ++ raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) ++ return self.value ++ ++ def visit_Call(self, node): ++ ''' ++ node.func.id: func name, only support 'float', 'int', 'str' ++ node.args: func args list,only support ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.Call ++ str/float only support one parameter, eg: float(XXX), str(xxx) ++ int support one or two parameters, eg: int(xxx) or int(xxx, 16) ++ xxx can be ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp ++ ''' ++ calc_tuple = ("float", "int", "str") ++ ++ if node.func.id not in calc_tuple: ++ raise NotImplementedError("Unsupport function call type: %s" % node.func.id) ++ ++ args_val_list = [] ++ for item in node.args: ++ ret = self.get_op_value(item) ++ args_val_list.append(ret) ++ ++ if node.func.id == "str": ++ if len(args_val_list) != 1: ++ raise TypeError("str() takes 1 positional argument but %s were given" % len(args_val_list)) ++ value = str(args_val_list[0]) ++ self.value = value ++ return value ++ ++ if node.func.id == "float": ++ if len(args_val_list) != 1: ++ raise TypeError("float() takes 1 positional argument but %s were given" % len(args_val_list)) ++ value = float(args_val_list[0]) ++ self.value = value ++ return value ++ # int ++ if len(args_val_list) == 1: ++ value = int(args_val_list[0]) ++ self.value = value ++ return value ++ if len(args_val_list) == 2: ++ value = int(args_val_list[0], args_val_list[1]) ++ self.value = value ++ return value ++ raise TypeError("int() takes 1 or 2 arguments (%s given)" % len(args_val_list)) ++ ++def inttostr(vl, length): ++ if not isinstance(vl, int): ++ raise Exception(" type error") ++ index = 0 ++ ret_t = "" ++ while index < length: ++ ret = 0xff & (vl >> index * 8) ++ ret_t += chr(ret) ++ index += 1 ++ return ret_t ++ ++ ++def strtoint(str_tmp): ++ value = 0 ++ rest_v = str_tmp.replace("0X", "").replace("0x", "") ++ str_len = len(rest_v) ++ for index, val in enumerate(rest_v): ++ value |= int(val, 16) << ((str_len - index - 1) * 4) ++ return value ++ ++ ++def inttobytes(val, length): ++ if not isinstance(val, int): ++ raise Exception("type error") ++ data_array = bytearray() ++ index = 0 ++ while index < length: ++ ret = 0xff & (val >> index * 8) ++ data_array.append(ret) ++ index += 1 ++ return data_array ++ ++ ++def byteTostr(val): ++ strtmp = '' ++ for value in val: ++ strtmp += chr(value) ++ return strtmp ++ ++ ++def typeTostr(val): ++ strtmp = '' ++ if isinstance(val, bytes): ++ strtmp = byteTostr(val) ++ return strtmp ++ ++ ++def getonieplatform(path): ++ if not os.path.isfile(path): ++ return "" ++ machine_vars = {} ++ with open(path) as machine_file: ++ for line in machine_file: ++ tokens = line.split('=') ++ if len(tokens) < 2: ++ continue ++ machine_vars[tokens[0]] = tokens[1].strip() ++ return machine_vars.get("onie_platform") ++ ++ ++def getplatform_config_db(): ++ if not os.path.isfile(CONFIG_DB_PATH): ++ return "" ++ val = os.popen("sonic-cfggen -j %s -v DEVICE_METADATA.localhost.platform" % CONFIG_DB_PATH).read().strip() ++ if len(val) <= 0: ++ return "" ++ return val ++ ++ ++def getplatform_name(): ++ if os.path.isfile('/host/machine.conf'): ++ return getonieplatform('/host/machine.conf') ++ if os.path.isfile('/etc/sonic/machine.conf'): ++ return getonieplatform('/etc/sonic/machine.conf') ++ return getplatform_config_db() ++ ++ ++def wbi2cget(bus, devno, address, word=None): ++ if word is None: ++ command_line = "i2cget -f -y %d 0x%02x 0x%02x " % (bus, devno, address) ++ else: ++ command_line = "i2cget -f -y %d 0x%02x 0x%02x %s" % (bus, devno, address, word) ++ retrytime = 6 ++ ret_t = "" ++ for i in range(retrytime): ++ ret, ret_t = wb_os_system(command_line) ++ if ret == 0: ++ return True, ret_t ++ time.sleep(0.1) ++ return False, ret_t ++ ++ ++def wbi2cset(bus, devno, address, byte): ++ command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x" % ( ++ bus, devno, address, byte) ++ retrytime = 6 ++ ret_t = "" ++ for i in range(retrytime): ++ ret, ret_t = wb_os_system(command_line) ++ if ret == 0: ++ return True, ret_t ++ return False, ret_t ++ ++ ++def wbpcird(pcibus, slot, fn, resource, offset): ++ '''read pci register''' ++ if offset % 4 != 0: ++ return "ERR offset: %d not 4 bytes align" ++ filename = "/sys/bus/pci/devices/0000:%02x:%02x.%x/resource%d" % (int(pcibus), int(slot), int(fn), int(resource)) ++ with open(filename, "r+") as file: ++ size = os.path.getsize(filename) ++ data = mmap.mmap(file.fileno(), size) ++ result = data[offset: offset + 4] ++ s = result[::-1] ++ val = 0 ++ for value in s: ++ val = val << 8 | value ++ data.close() ++ return "0x%08x" % val ++ ++ ++def wbpciwr(pcibus, slot, fn, resource, offset, data): ++ '''write pci register''' ++ ret = inttobytes(data, 4) ++ filename = "/sys/bus/pci/devices/0000:%02x:%02x.%x/resource%d" % (int(pcibus), int(slot), int(fn), int(resource)) ++ with open(filename, "r+") as file: ++ size = os.path.getsize(filename) ++ data = mmap.mmap(file.fileno(), size) ++ data[offset: offset + 4] = ret ++ result = data[offset: offset + 4] ++ s = result[::-1] ++ val = 0 ++ for value in s: ++ val = val << 8 | value ++ data.close() ++ ++ ++def wbi2cgetWord(bus, devno, address): ++ command_line = "i2cget -f -y %d 0x%02x 0x%02x w" % (bus, devno, address) ++ retrytime = 3 ++ ret_t = "" ++ for i in range(retrytime): ++ ret, ret_t = wb_os_system(command_line) ++ if ret == 0: ++ return True, ret_t ++ return False, ret_t ++ ++ ++def wbi2csetWord(bus, devno, address, byte): ++ command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%x w" % ( ++ bus, devno, address, byte) ++ retrytime = 6 ++ ret_t = "" ++ for i in range(retrytime): ++ ret, ret_t = wb_os_system(command_line) ++ if ret == 0: ++ return True, ret_t ++ return False, ret_t ++ ++ ++def wbi2cset_pec(bus, devno, address, byte): ++ command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x bp" % ( ++ bus, devno, address, byte) ++ retrytime = 6 ++ ret_t = "" ++ for i in range(retrytime): ++ ret, ret_t = wb_os_system(command_line) ++ if ret == 0: ++ return True, ret_t ++ return False, ret_t ++ ++ ++def wbi2cset_wordpec(bus, devno, address, byte): ++ command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x wp" % ( ++ bus, devno, address, byte) ++ retrytime = 6 ++ ret_t = "" ++ for i in range(retrytime): ++ ret, ret_t = wb_os_system(command_line) ++ if ret == 0: ++ return True, ret_t ++ return False, ret_t ++ ++ ++def wbsysset(location, value): ++ command_line = "echo 0x%02x > %s" % (value, location) ++ retrytime = 6 ++ ret_t = "" ++ for i in range(retrytime): ++ ret, ret_t = wb_os_system(command_line) ++ if ret == 0: ++ return True, ret_t ++ return False, ret_t ++ ++ ++def dev_file_read(path, offset, read_len): ++ val_list = [] ++ msg = "" ++ ret = "" ++ fd = -1 ++ ++ if not os.path.exists(path): ++ msg = path + " not found !" ++ return False, msg ++ ++ try: ++ fd = os.open(path, os.O_RDONLY) ++ os.lseek(fd, offset, os.SEEK_SET) ++ ret = os.read(fd, read_len) ++ for item in ret: ++ val_list.append(item) ++ except Exception as e: ++ msg = str(e) ++ return False, msg ++ finally: ++ if fd > 0: ++ os.close(fd) ++ return True, val_list ++ ++ ++def dev_file_write(path, offset, buf_list): ++ msg = "" ++ fd = -1 ++ ++ if not isinstance(buf_list, list) or len(buf_list) == 0: ++ msg = "buf:%s is not list type or is NONE !" % buf_list ++ return False, msg ++ ++ if not os.path.exists(path): ++ msg = path + " not found !" ++ return False, msg ++ ++ try: ++ fd = os.open(path, os.O_WRONLY) ++ os.lseek(fd, offset, os.SEEK_SET) ++ ret = os.write(fd, bytes(buf_list)) ++ except Exception as e: ++ msg = str(e) ++ return False, msg ++ finally: ++ if fd > 0: ++ os.close(fd) ++ ++ return True, ret ++ ++ ++def wb_os_system(cmd): ++ status, output = subprocess.getstatusoutput(cmd) ++ return status, output ++ ++ ++def io_rd(reg_addr, read_len=1): ++ try: ++ regaddr = 0 ++ if isinstance(reg_addr, int): ++ regaddr = reg_addr ++ else: ++ regaddr = int(reg_addr, 16) ++ devfile = "/dev/port" ++ fd = os.open(devfile, os.O_RDWR | os.O_CREAT) ++ os.lseek(fd, regaddr, os.SEEK_SET) ++ val = os.read(fd, read_len) ++ return "".join(["%02x" % item for item in val]) ++ except ValueError: ++ return None ++ except Exception as e: ++ print(e) ++ return None ++ finally: ++ os.close(fd) ++ ++ ++def io_wr(reg_addr, reg_data): ++ try: ++ regdata = 0 ++ regaddr = 0 ++ if isinstance(reg_addr, int): ++ regaddr = reg_addr ++ else: ++ regaddr = int(reg_addr, 16) ++ if isinstance(reg_data, int): ++ regdata = reg_data ++ else: ++ regdata = int(reg_data, 16) ++ devfile = "/dev/port" ++ fd = os.open(devfile, os.O_RDWR | os.O_CREAT) ++ os.lseek(fd, regaddr, os.SEEK_SET) ++ os.write(fd, regdata.to_bytes(1, 'little')) ++ return True ++ except ValueError as e: ++ print(e) ++ return False ++ except Exception as e: ++ print(e) ++ return False ++ finally: ++ os.close(fd) ++ ++ ++def exec_os_cmd(cmd): ++ status, output = subprocess.getstatusoutput(cmd) ++ return status, output ++ ++ ++def exec_os_cmd_log(cmd): ++ proc = subprocess.Popen(shlex.split(cmd), stdin=subprocess.PIPE, shell=False, stderr=sys.stderr, close_fds=True, ++ stdout=sys.stdout, universal_newlines=True, bufsize=1) ++ proc.wait() ++ stdout = proc.communicate()[0] ++ stdout = typeTostr(stdout) ++ return proc.returncode, stdout ++ ++ ++def write_sysfs(location, value): ++ try: ++ if not os.path.isfile(location): ++ return False, ("location[%s] not found !" % location) ++ with open(location, 'w') as fd1: ++ fd1.write(value) ++ except Exception as e: ++ return False, (str(e) + " location[%s]" % location) ++ return True, ("set location[%s] %s success !" % (location, value)) ++ ++ ++def read_sysfs(location): ++ try: ++ locations = glob.glob(location) ++ with open(locations[0], 'rb') as fd1: ++ retval = fd1.read() ++ retval = typeTostr(retval) ++ retval = retval.rstrip('\r\n') ++ retval = retval.lstrip(" ") ++ except Exception as e: ++ return False, (str(e) + "location[%s]" % location) ++ return True, retval ++ ++ ++def get_pmc_register(reg_name): ++ retval = 'ERR' ++ mb_reg_file = MAILBOX_DIR + reg_name ++ filepath = glob.glob(mb_reg_file) ++ if len(filepath) == 0: ++ return "%s %s notfound" % (retval, mb_reg_file) ++ mb_reg_file = filepath[0] ++ if not os.path.isfile(mb_reg_file): ++ return "%s %s notfound" % (retval, mb_reg_file) ++ try: ++ with open(mb_reg_file, 'r') as fd: ++ retval = fd.read() ++ except Exception as error: ++ retval = retval + str(error) ++ retval = retval.rstrip('\r\n') ++ retval = retval.lstrip(" ") ++ return retval ++ ++ ++def get_sysfs_value(location): ++ pos_t = str(location) ++ name = get_pmc_register(pos_t) ++ return name ++ ++ ++def write_sysfs_value(reg_name, value): ++ fileLoc = MAILBOX_DIR + reg_name ++ try: ++ if not os.path.isfile(fileLoc): ++ print(fileLoc, 'not found !') ++ return False ++ with open(fileLoc, 'w') as fd: ++ fd.write(value) ++ except Exception: ++ print("Unable to open " + fileLoc + "file !") ++ return False ++ return True ++ ++ ++def get_value_once(config): ++ try: ++ way = config.get("gettype") ++ int_decode = config.get("int_decode", 16) ++ if way == 'sysfs': ++ loc = config.get("loc") ++ ret, val = read_sysfs(loc) ++ if ret is True: ++ return True, int(val, int_decode) ++ return False, ("sysfs read %s failed. log:%s" % (loc, val)) ++ if way == "i2c": ++ bus = config.get("bus") ++ addr = config.get("loc") ++ offset = config.get("offset", 0) ++ ret, val = wbi2cget(bus, addr, offset) ++ if ret is True: ++ return True, int(val, int_decode) ++ return False, ("i2c read failed. bus:%d , addr:0x%x, offset:0x%x" % (bus, addr, offset)) ++ if way == "io": ++ io_addr = config.get('io_addr') ++ val = io_rd(io_addr) ++ if len(val) != 0: ++ return True, int(val, int_decode) ++ return False, ("io_addr read 0x%x failed" % io_addr) ++ if way == "i2cword": ++ bus = config.get("bus") ++ addr = config.get("loc") ++ offset = config.get("offset") ++ ret, val = wbi2cgetWord(bus, addr, offset) ++ if ret is True: ++ return True, int(val, int_decode) ++ return False, ("i2cword read failed. bus:%d, addr:0x%x, offset:0x%x" % (bus, addr, offset)) ++ if way == "devfile": ++ path = config.get("path") ++ offset = config.get("offset") ++ read_len = config.get("read_len") ++ ret, val_list = dev_file_read(path, offset, read_len) ++ if ret is True: ++ return True, val_list ++ return False, ("devfile read failed. path:%s, offset:0x%x, read_len:%d" % (path, offset, read_len)) ++ if way == 'cmd': ++ cmd = config.get("cmd") ++ ret, val = exec_os_cmd(cmd) ++ if ret: ++ return False, ("cmd read exec %s failed, log: %s" % (cmd, val)) ++ return True, int(val, int_decode) ++ if way == 'file_exist': ++ judge_file = config.get('judge_file', None) ++ if os.path.exists(judge_file): ++ return True, True ++ return True, False ++ return False, "not support read type" ++ except Exception as e: ++ return False, ("get_value_once exception:%s happen" % str(e)) ++ ++ ++def set_value_once(config): ++ try: ++ delay_time = config.get("delay", None) ++ if delay_time is not None: ++ time.sleep(delay_time) ++ ++ way = config.get("gettype") ++ if way == 'sysfs': ++ loc = config.get("loc") ++ value = config.get("value") ++ mask = config.get("mask", 0xff) ++ mask_tuple = (0xff, 0) ++ if mask not in mask_tuple: ++ ret, read_value = read_sysfs(loc) ++ if ret is True: ++ read_value = int(read_value, base=16) ++ value = (read_value & mask) | value ++ else: ++ return False, ("sysfs read %s failed. log:%s" % (loc, read_value)) ++ ret, log = write_sysfs(loc, "0x%02x" % value) ++ if ret is not True: ++ return False, ("sysfs %s write 0x%x failed" % (loc, value)) ++ return True, ("sysfs write 0x%x success" % value) ++ if way == "i2c": ++ bus = config.get("bus") ++ addr = config.get("loc") ++ offset = config.get("offset") ++ value = config.get("value") ++ mask = config.get("mask", 0xff) ++ mask_tuple = (0xff, 0) ++ if mask not in mask_tuple: ++ ret, read_value = wbi2cget(bus, addr, offset) ++ if ret is True: ++ read_value = int(read_value, base=16) ++ value = (read_value & mask) | value ++ else: ++ return False, ("i2c read failed. bus:%d , addr:0x%x, offset:0x%x" % (bus, addr, offset)) ++ ret, log = wbi2cset(bus, addr, offset, value) ++ if ret is not True: ++ return False, ("i2c write bus:%d, addr:0x%x, offset:0x%x, value:0x%x failed" % ++ (bus, addr, offset, value)) ++ return True, ("i2c write bus:%d, addr:0x%x, offset:0x%x, value:0x%x success" % ++ (bus, addr, offset, value)) ++ if way == "io": ++ io_addr = config.get('io_addr') ++ value = config.get('value') ++ mask = config.get("mask", 0xff) ++ mask_tuple = (0xff, 0) ++ if mask not in mask_tuple: ++ read_value = io_rd(io_addr) ++ if read_value is None: ++ return False, ("io_addr 0x%x read failed" % (io_addr)) ++ read_value = int(read_value, base=16) ++ value = (read_value & mask) | value ++ ret = io_wr(io_addr, value) ++ if ret is not True: ++ return False, ("io_addr 0x%x write 0x%x failed" % (io_addr, value)) ++ return True, ("io_addr 0x%x write 0x%x success" % (io_addr, value)) ++ if way == 'i2cword': ++ bus = config.get("bus") ++ addr = config.get("loc") ++ offset = config.get("offset") ++ value = config.get("value") ++ mask = config.get("mask", 0xff) ++ mask_tuple = (0xff, 0) ++ if mask not in mask_tuple: ++ ret, read_value = wbi2cgetWord(bus, addr, offset) ++ if ret is True: ++ read_value = int(read_value, base=16) ++ value = (read_value & mask) | value ++ else: ++ return False, ("i2c read word failed. bus:%d , addr:0x%x, offset:0x%x" % (bus, addr, offset)) ++ ret, log = wbi2csetWord(bus, addr, offset, value) ++ if ret is not True: ++ return False, ("i2cword write bus:%d, addr:0x%x, offset:0x%x, value:0x%x failed" % ++ (bus, addr, offset, value)) ++ return True, ("i2cword write bus:%d, addr:0x%x, offset:0x%x, value:0x%x success" % ++ (bus, addr, offset, value)) ++ if way == "devfile": ++ path = config.get("path") ++ offset = config.get("offset") ++ buf_list = config.get("value") ++ ret, log = dev_file_write(path, offset, buf_list) ++ if ret is True: ++ return True, ("devfile write path:%s, offset:0x%x, buf_list:%s success." % (path, offset, buf_list)) ++ return False, ("devfile read path:%s, offset:0x%x, buf_list:%s failed.log:%s" % ++ (path, offset, buf_list, log)) ++ if way == 'cmd': ++ cmd = config.get("cmd") ++ ret, log = exec_os_cmd(cmd) ++ if ret: ++ return False, ("cmd write exec %s failed, log: %s" % (cmd, log)) ++ return True, ("cmd write exec %s success" % cmd) ++ if way == 'bit_wr': ++ mask = config.get("mask") ++ bit_val = config.get("value") ++ val_config = config.get("val_config") ++ ret, rd_value = get_value_once(val_config) ++ if ret is False: ++ return False, ("bit_wr read failed, log: %s" % rd_value) ++ wr_val = (rd_value & mask) | bit_val ++ val_config["value"] = wr_val ++ ret, log = set_value_once(val_config) ++ if ret is False: ++ return False, ("bit_wr failed, log: %s" % log) ++ return True, ("bit_wr success, log: %s" % log) ++ if way == 'creat_file': ++ file_name = config.get("file") ++ ret, log = exec_os_cmd("touch %s" % file_name) ++ if ret: ++ return False, ("creat file %s failed, log: %s" % (file_name, log)) ++ exec_os_cmd("sync") ++ return True, ("creat file %s success" % file_name) ++ if way == 'remove_file': ++ file_name = config.get("file") ++ ret, log = exec_os_cmd("rm -rf %s" % file_name) ++ if ret: ++ return False, ("remove file %s failed, log: %s" % (file_name, log)) ++ exec_os_cmd("sync") ++ return True, ("remove file %s success" % file_name) ++ return False, "not support write type" ++ except Exception as e: ++ return False, ("set_value_once exception:%s happen" % str(e)) ++ ++ ++def get_value(config): ++ retrytime = 6 ++ for i in range(retrytime): ++ ret, val = get_value_once(config) ++ if ret is True: ++ return True, val ++ time.sleep(0.1) ++ return False, val ++ ++ ++def set_value(config): ++ retrytime = 6 ++ ignore_result_flag = config.get("ignore_result", 0) ++ for i in range(retrytime): ++ ret, log = set_value_once(config) ++ if ret is True: ++ return True, log ++ if ignore_result_flag == 1: ++ return True, log ++ time.sleep(0.1) ++ return False, log ++ ++ ++class CompressedRotatingFileHandler(logging.handlers.RotatingFileHandler): ++ def doRollover(self): ++ """ ++ Do a rollover, as described in __init__(). ++ """ ++ if self.stream: ++ self.stream.close() ++ self.stream = None ++ if self.backupCount > 0: ++ for i in range(self.backupCount - 1, 0, -1): ++ sfn = "%s.%d.gz" % (self.baseFilename, i) ++ dfn = "%s.%d.gz" % (self.baseFilename, i + 1) ++ if os.path.exists(sfn): ++ if os.path.exists(dfn): ++ os.remove(dfn) ++ os.rename(sfn, dfn) ++ dfn = self.baseFilename + ".1.gz" ++ if os.path.exists(dfn): ++ os.remove(dfn) ++ # These two lines below are the only new lines. I commented out the os.rename(self.baseFilename, dfn) and ++ # replaced it with these two lines. ++ with open(self.baseFilename, 'rb') as f_in, gzip.open(dfn, 'wb') as f_out: ++ shutil.copyfileobj(f_in, f_out) ++ self.mode = 'w' ++ self.stream = self._open() ++ ++ ++def getSdkReg(reg): ++ try: ++ cmd = "bcmcmd -t 1 'getr %s ' < /dev/null" % reg ++ ret, result = wb_os_system(cmd) ++ result_t = result.strip().replace("\r", "").replace("\n", "") ++ if ret != 0 or "Error:" in result_t: ++ return False, result ++ patt = r"%s.(.*):(.*)>drivshell" % reg ++ rt = re.findall(patt, result_t, re.S) ++ test = re.findall("=(.*)", rt[0][0])[0] ++ except Exception: ++ return False, 'getsdk register error' ++ return True, test ++ ++ ++def getMacTemp(): ++ result = {} ++ wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") ++ ret, log = wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") ++ if ret: ++ return False, result ++ logs = log.splitlines() ++ for line in logs: ++ if "average" in line: ++ b = re.findall(r'\d+.\d+', line) ++ result["average"] = b[0] ++ elif "maximum" in line: ++ b = re.findall(r'\d+.\d+', line) ++ result["maximum"] = b[0] ++ return True, result ++ ++ ++def getMacTemp_sysfs(mactempconf): ++ temp = -1000000 ++ try: ++ temp_list = [] ++ mac_temp_loc = mactempconf.get("loc", []) ++ mac_temp_flag = mactempconf.get("flag", None) ++ if mac_temp_flag is not None: ++ gettype = mac_temp_flag.get('gettype') ++ okbit = mac_temp_flag.get('okbit') ++ okval = mac_temp_flag.get('okval') ++ if gettype == "io": ++ io_addr = mac_temp_flag.get('io_addr') ++ val = io_rd(io_addr) ++ if val is None: ++ raise Exception("get mac_flag by io failed.") ++ else: ++ bus = mac_temp_flag.get('bus') ++ loc = mac_temp_flag.get('loc') ++ offset = mac_temp_flag.get('offset') ++ ind, val = wbi2cget(bus, loc, offset) ++ if ind is not True: ++ raise Exception("get mac_flag by i2c failed.") ++ val_t = (int(val, 16) & (1 << okbit)) >> okbit ++ if val_t != okval: ++ raise Exception("mac_flag invalid, val_t:%d." % val_t) ++ for loc in mac_temp_loc: ++ temp_s = get_sysfs_value(loc) ++ if isinstance(temp_s, str) and temp_s.startswith("ERR"): ++ raise Exception("get mac temp error. loc:%s" % loc) ++ temp_t = int(temp_s) ++ if temp_t == -1000000: ++ raise Exception("mac temp invalid.loc:%s" % loc) ++ temp_list.append(temp_t) ++ temp_list.sort(reverse=True) ++ temp = temp_list[0] ++ except Exception: ++ return False, temp ++ return True, temp ++ ++def get_format_value(format_str): ++ ast_obj = ast.parse(format_str, mode='eval') ++ visitor = CodeVisitor() ++ visitor.visit(ast_obj) ++ ret = visitor.get_value() ++ return ret ++ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/pmon_syslog.py b/platform/broadcom/sonic-platform-modules-micas/common/script/pmon_syslog.py +new file mode 100755 +index 000000000..8bdceef8c +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/pmon_syslog.py +@@ -0,0 +1,519 @@ ++#!/usr/bin/python3 ++# * onboard interval check ++# * FAN trays ++# * PSU ++# * SFF ++import time ++import syslog ++import traceback ++import glob ++from platform_config import PMON_SYSLOG_STATUS ++ ++PMON_DEBUG_FILE = "/etc/.pmon_syslog_debug_flag" ++debuglevel = 0 ++PMONERROR = 1 ++PMONDEBUG = 2 ++ ++ ++def pmon_debug(s): ++ if PMONDEBUG & debuglevel: ++ syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def pmon_error(s): ++ if PMONERROR & debuglevel: ++ syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++def dev_syslog(s): ++ syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_NOTICE, s) ++ ++ ++# status ++STATUS_PRESENT = 'PRESENT' ++STATUS_ABSENT = 'ABSENT' ++STATUS_OK = 'OK' ++STATUS_NOT_OK = 'NOT OK' ++STATUS_FAILED = 'FAILED' ++ ++ ++class checkBase(object): ++ def __init__(self, path, dev_name, display_name, obj_type, config): ++ self._peroid_syslog = None ++ self._peroid_failed_syslog = None # exception ++ self._preDevStatus = None ++ self._path = path ++ self._name = dev_name ++ self._display_name = display_name ++ self._type = obj_type ++ self._config = config ++ ++ def getCurstatus(self): ++ # get ok/not ok/absent status ++ status, log = self.getPresent() ++ if status == STATUS_PRESENT: ++ # check status ++ property_status, log = self.getStatus() ++ if property_status is not None: ++ status = property_status ++ return status, log ++ ++ def getPresent(self): ++ presentFilepath = self.getPath() ++ try: ++ # get ok/not ok/absent status ++ presentConfig = self._config["present"] ++ mask = presentConfig.get("mask", 0xff) ++ absent_val = presentConfig.get("ABSENT", None) ++ absent_val = absent_val & mask ++ with open(presentFilepath, "r") as fd: ++ retval = fd.read() ++ if int(retval) == absent_val: ++ return STATUS_ABSENT, None ++ return STATUS_PRESENT, None ++ except Exception as e: ++ return STATUS_FAILED, (str(e) + " location[%s]" % presentFilepath) ++ ++ def getStatus(self): ++ if "status" in self._config: ++ statusConfig = self._config["status"] ++ for itemConfig in statusConfig: ++ mask = itemConfig.get("mask", 0xff) ++ ok_val = itemConfig.get("okval", None) ++ ok_val = ok_val & mask ++ Filepath = itemConfig["path"] % self._name ++ try: ++ with open(Filepath, "r") as fd1: ++ retval = fd1.read() ++ if int(retval) != ok_val: ++ return STATUS_NOT_OK, None ++ except Exception as e: ++ return STATUS_FAILED, (str(e) + " location[%s]" % Filepath) ++ return STATUS_OK, None ++ return None, None ++ ++ def getPath(self): ++ return self._path ++ ++ def getName(self): ++ return self._name ++ ++ def getType(self): ++ return self._type ++ ++ def getDisplayName(self): ++ return self._display_name ++ ++ def getnochangedMsgFlag(self): ++ return self._config["nochangedmsgflag"] ++ ++ def getnochangedMsgTime(self): ++ return self._config["nochangedmsgtime"] ++ ++ def getnoprintFirstTimeFlag(self): ++ return self._config["noprintfirsttimeflag"] ++ ++ def checkStatus(self): ++ # syslog msg ++ dev_type = self.getType() ++ display_name = self.getDisplayName() ++ nochangedMsgTime = self.getnochangedMsgTime() ++ getnochangedMsgFlag = self.getnochangedMsgFlag() ++ noprintFirstTimeFlag = self.getnoprintFirstTimeFlag() ++ MSG_IN = '%%PMON-5-' + dev_type + '_PLUG_IN: %s is PRESENT.' ++ MSG_OUT = '%%PMON-5-' + dev_type + '_PLUG_OUT: %s is ABSENT.' ++ MSG_OK = '%%PMON-5-' + dev_type + '_OK: %s is OK.' ++ MSG_NOT_OK = '%%PMON-5-' + dev_type + '_FAILED: %s is NOT OK.' ++ MSG_ABSENT = '%%PMON-5-' + dev_type + '_ABSENT: %s is ABSENT.' ++ MSG_UNKNOWN = '%%PMON-5-' + dev_type + '_UNKNOWN: %s is UNKNOWN.%s' ++ MSG_RECOVER = '%%PMON-5-' + dev_type + '_OK: %s is OK. Recover from ' + dev_type + ' FAILED.' ++ ++ curStatus, log = self.getCurstatus() ++ pmon_debug("%s: current status %s" % (display_name, curStatus)) ++ pmon_debug("%s: pre status %s" % (display_name, self._preDevStatus)) ++ pmon_debug("%s: peroid_syslog %s" % (display_name, self._peroid_syslog)) ++ ++ if curStatus == STATUS_FAILED: ++ # get status failed ++ if self._peroid_failed_syslog is not None: ++ if getnochangedMsgFlag and time.time() - self._peroid_failed_syslog >= nochangedMsgTime: ++ # absent as before for some time, notice ++ dev_syslog(MSG_UNKNOWN % (display_name, log)) ++ self._peroid_failed_syslog = time.time() ++ else: # first time failed ++ dev_syslog(MSG_UNKNOWN % (display_name, log)) ++ self._peroid_failed_syslog = time.time() ++ return ++ self._peroid_failed_syslog = time.time() ++ ++ if self._preDevStatus is None: ++ # 1st time ++ if noprintFirstTimeFlag == 1: ++ self._peroid_syslog = time.time() ++ else: ++ if curStatus == STATUS_PRESENT: ++ # present ++ dev_syslog(MSG_IN % display_name) ++ elif curStatus == STATUS_OK: ++ # ok ++ dev_syslog(MSG_OK % display_name) ++ elif curStatus == STATUS_NOT_OK: ++ # not ok ++ dev_syslog(MSG_NOT_OK % display_name) ++ self._peroid_syslog = time.time() ++ else: ++ # absent ++ dev_syslog(MSG_ABSENT % display_name) ++ self._peroid_syslog = time.time() ++ else: ++ # from 2nd time... ++ if self._preDevStatus == curStatus: ++ # status not changed ++ if self._preDevStatus == STATUS_ABSENT: ++ if self._peroid_syslog is not None: ++ if getnochangedMsgFlag and time.time() - self._peroid_syslog >= nochangedMsgTime: ++ # absent as before for some time, notice ++ dev_syslog(MSG_ABSENT % display_name) ++ self._peroid_syslog = time.time() ++ elif self._preDevStatus == STATUS_NOT_OK: ++ if self._peroid_syslog is not None: ++ if getnochangedMsgFlag and time.time() - self._peroid_syslog >= nochangedMsgTime: ++ # not ok as before for some time, notice ++ dev_syslog(MSG_NOT_OK % display_name) ++ self._peroid_syslog = time.time() ++ else: ++ # status changed ++ if self._preDevStatus == STATUS_ABSENT: ++ if curStatus == STATUS_NOT_OK: ++ # absent -> not ok ++ dev_syslog(MSG_IN % display_name) ++ dev_syslog(MSG_NOT_OK % display_name) ++ self._peroid_syslog = time.time() ++ elif curStatus == STATUS_OK: ++ # absent -> ok ++ dev_syslog(MSG_IN % display_name) ++ dev_syslog(MSG_OK % display_name) ++ else: ++ # absent -> prsent ++ dev_syslog(MSG_IN % display_name) ++ ++ elif self._preDevStatus == STATUS_OK: ++ if curStatus == STATUS_NOT_OK: ++ # ok -> not ok ++ dev_syslog(MSG_NOT_OK % display_name) ++ self._peroid_syslog = time.time() ++ elif curStatus == STATUS_ABSENT: ++ # ok -> absent ++ dev_syslog(MSG_OUT % display_name) ++ self._peroid_syslog = time.time() ++ elif self._preDevStatus == STATUS_PRESENT: ++ # present -> absent ++ dev_syslog(MSG_OUT % display_name) ++ self._peroid_syslog = time.time() ++ else: # not ok ++ if curStatus == STATUS_OK: ++ # not ok -> ok ++ dev_syslog(MSG_RECOVER % display_name) ++ dev_syslog(MSG_OK % display_name) ++ else: ++ # not ok -> absent ++ dev_syslog(MSG_OUT % display_name) ++ self._peroid_syslog = time.time() ++ self._preDevStatus = curStatus ++ ++ ++class checkSfp(checkBase): ++ def __init__(self, path, dev_name, display_name, config): ++ super(checkSfp, self).__init__(path, dev_name, display_name, 'XCVR', config) ++ ++ def getPath(self): ++ super(checkSfp, self).getPath() ++ return self._path ++ ++ def getName(self): ++ super(checkSfp, self).getName() ++ return self._name ++ ++ def getType(self): ++ super(checkSfp, self).getType() ++ return self._type ++ ++ ++class checkSlot(checkBase): ++ def __init__(self, path, dev_name, display_name, config): ++ super(checkSlot, self).__init__(path, dev_name, display_name, 'SLOT', config) ++ ++ def getPath(self): ++ super(checkSlot, self).getPath() ++ return self._path ++ ++ def getName(self): ++ super(checkSlot, self).getName() ++ return self._name ++ ++ def getType(self): ++ super(checkSlot, self).getType() ++ return self._type ++ ++ ++class checkPSU(checkBase): ++ def __init__(self, path, dev_name, display_name, config): ++ super(checkPSU, self).__init__(path, dev_name, display_name, 'PSU', config) ++ ++ def getPath(self): ++ super(checkPSU, self).getPath() ++ return self._path ++ ++ def getName(self): ++ super(checkPSU, self).getName() ++ return self._name ++ ++ def getType(self): ++ super(checkPSU, self).getType() ++ return self._type ++ ++ ++class checkFAN(checkBase): ++ def __init__(self, path, dev_name, display_name, config): ++ super(checkFAN, self).__init__(path, dev_name, display_name, 'FAN', config) ++ ++ def getPath(self): ++ super(checkFAN, self).getPath() ++ return self._path ++ ++ def getName(self): ++ super(checkFAN, self).getName() ++ return self._name ++ ++ def getType(self): ++ super(checkFAN, self).getType() ++ return self._type ++ ++ ++class platformSyslog(): ++ def __init__(self): ++ self.__sfp_checklist = [] ++ self.__fan_checklist = [] ++ self.__psu_checklist = [] ++ self.__slot_checklist = [] ++ self.__temp_checklist = [] ++ self.temps_peroid_syslog = {} ++ self.normal_status = 0 ++ self.warning_status = 1 ++ self.critical_status = 2 ++ self.poweron_flag = 0 ++ ++ self.pmon_syslog_config = PMON_SYSLOG_STATUS.copy() ++ self.__pollingtime = self.pmon_syslog_config.get('polling_time', 3) ++ ++ tmpconfig = self.pmon_syslog_config.get('sffs', None) ++ if tmpconfig is not None: ++ preset_item = tmpconfig.get("present", {}) ++ path = preset_item.get("path", []) ++ for location in path: ++ if '*' not in location: ++ pmon_error("sff location config error: %s" % location) ++ continue ++ dev_name_index = 0 ++ loc_split_list = location.split('/') ++ for i, item in enumerate(loc_split_list): ++ if '*' in item: ++ dev_name_index = i ++ break ++ locations = glob.glob(location) ++ for dev_path in locations: ++ dev_name_list = dev_path.split('/') ++ # explame:get eth1 from /sys_switch/transceiver/eth1/present ++ dev_name = dev_name_list[dev_name_index] ++ dev_name_alias = tmpconfig.get("alias", {}) ++ display_name = dev_name_alias.get(dev_name, dev_name) ++ dev = checkSfp(dev_path, dev_name, display_name, tmpconfig) ++ self.__sfp_checklist.append(dev) ++ ++ tmpconfig = self.pmon_syslog_config.get('fans', None) ++ if tmpconfig is not None: ++ preset_item = tmpconfig.get("present", {}) ++ path = preset_item.get("path", []) ++ for location in path: ++ if '*' not in location: ++ pmon_error("fan location config error: %s" % location) ++ continue ++ dev_name_index = 0 ++ loc_split_list = location.split('/') ++ for i, item in enumerate(loc_split_list): ++ if '*' in item: ++ dev_name_index = i ++ break ++ locations = glob.glob(location) ++ for dev_path in locations: ++ dev_name_list = dev_path.split('/') ++ dev_name = dev_name_list[dev_name_index] ++ dev_name_alias = tmpconfig.get("alias", {}) ++ display_name = dev_name_alias.get(dev_name, dev_name) ++ dev = checkFAN(dev_path, dev_name, display_name, tmpconfig) ++ self.__fan_checklist.append(dev) ++ ++ tmpconfig = self.pmon_syslog_config.get('psus', None) ++ if tmpconfig is not None: ++ preset_item = tmpconfig.get("present", {}) ++ path = preset_item.get("path", []) ++ for location in path: ++ if '*' not in location: ++ pmon_error("psu location config error: %s" % location) ++ continue ++ dev_name_index = 0 ++ loc_split_list = location.split('/') ++ for i, item in enumerate(loc_split_list): ++ if '*' in item: ++ dev_name_index = i ++ break ++ locations = glob.glob(location) ++ for dev_path in locations: ++ dev_name_list = dev_path.split('/') ++ dev_name = dev_name_list[dev_name_index] ++ dev_name_alias = tmpconfig.get("alias", {}) ++ display_name = dev_name_alias.get(dev_name, dev_name) ++ dev = checkPSU(dev_path, dev_name, display_name, tmpconfig) ++ self.__psu_checklist.append(dev) ++ ++ tmpconfig = self.pmon_syslog_config.get('slots', None) ++ if tmpconfig is not None: ++ preset_item = tmpconfig.get("present", {}) ++ path = preset_item.get("path", []) ++ for location in path: ++ if '*' not in location: ++ pmon_error("slot location config error: %s" % location) ++ continue ++ dev_name_index = 0 ++ loc_split_list = location.split('/') ++ for i, item in enumerate(loc_split_list): ++ if '*' in item: ++ dev_name_index = i ++ break ++ locations = glob.glob(location) ++ for dev_path in locations: ++ dev_name_list = dev_path.split('/') ++ dev_name = dev_name_list[dev_name_index] ++ dev_name_alias = tmpconfig.get("alias", {}) ++ display_name = dev_name_alias.get(dev_name, dev_name) ++ dev = checkSlot(dev_path, dev_name, display_name, tmpconfig) ++ self.__slot_checklist.append(dev) ++ ++ tmpconfig = self.pmon_syslog_config.get('temps', None) ++ if tmpconfig is not None: ++ self.__temp_checklist = tmpconfig.get('temps_list', []) ++ self.__temps_pollingseconds = tmpconfig.get('over_temps_polling_seconds', None) ++ ++ def checkTempStaus(self, temp_item): ++ temp_name = temp_item.get('name', None) ++ input_path = temp_item.get('input_path', None) ++ warning_temp = temp_item.get('warning', None) ++ critical_temp = temp_item.get('critical', None) ++ input_accuracy = temp_item.get('input_accuracy', None) ++ if temp_name is None or input_path is None or warning_temp is None or critical_temp is None: ++ dev_syslog('%%PMON-5-TEMP_NOTICE: get temperature config parament failed.') ++ return ++ try: ++ locations = glob.glob(input_path) ++ with open(locations[0], "r") as fd: ++ input_temp = fd.read() ++ input_temp = float(input_temp) / float(input_accuracy) ++ ++ if 'time' not in temp_item: ++ temp_item['time'] = time.time() ++ temp_item['status'] = self.normal_status ++ if float(input_temp) >= float(warning_temp): ++ if float(input_temp) >= float(critical_temp): ++ if time.time() - \ ++ temp_item['time'] >= self.__temps_pollingseconds or temp_item['status'] != self.critical_status: ++ dev_syslog('%%PMON-5-TEMP_HIGH: %s temperature %sC is larger than max critical threshold %sC.' ++ % (temp_name, input_temp, critical_temp)) ++ temp_item['status'] = self.critical_status ++ temp_item['time'] = time.time() ++ else: ++ if time.time() - \ ++ temp_item['time'] >= self.__temps_pollingseconds or temp_item['status'] != self.warning_status: ++ dev_syslog('%%PMON-5-TEMP_HIGH: %s temperature %sC is larger than max warning threshold %sC.' ++ % (temp_name, input_temp, warning_temp)) ++ temp_item['status'] = self.warning_status ++ temp_item['time'] = time.time() ++ else: ++ pmon_debug( ++ "%s temperature %sC is in range [%s, %s]" % ++ (temp_name, input_temp, warning_temp, critical_temp)) ++ temp_item['status'] = self.normal_status ++ temp_item['time'] = time.time() ++ except Exception as e: ++ dev_syslog('%%PMON-5-TEMP_NOTICE: Cannot get %s temperature. Exception log: %s' % (temp_name, str(e))) ++ return ++ ++ def sysfs_precondition_check(self, check_module, check_project): ++ try: ++ tmpconfig = self.pmon_syslog_config.get(check_module, None) ++ if tmpconfig is not None: ++ check_list = tmpconfig.get(check_project, []) ++ for check_item in check_list: ++ location = check_item.get("path", None) ++ ok_val = check_item.get("ok_val", None) ++ mask = check_item.get("mask", 0xff) ++ ok_val = ok_val & mask ++ locations = glob.glob(location) ++ for power_path in locations: ++ with open(power_path, "r") as fd: ++ retval = fd.read() ++ if int(retval) != ok_val: ++ return ++ self.poweron_flag = 1 ++ except Exception as e: ++ dev_syslog('%%PMON-5-TEMP_NOTICE: Cannot check power status. Exception log: %s' % str(e)) ++ return ++ ++ def updateSysDeviceStatus(self): ++ if self.poweron_flag == 1: ++ for dev in self.__sfp_checklist: ++ dev.checkStatus() ++ else: ++ self.sysfs_precondition_check('sffs', 'power') ++ ++ for dev in self.__fan_checklist: ++ dev.checkStatus() ++ for dev in self.__psu_checklist: ++ dev.checkStatus() ++ for dev in self.__slot_checklist: ++ dev.checkStatus() ++ for temp_item in self.__temp_checklist: ++ self.checkTempStaus(temp_item) ++ ++ def getPollingtime(self): ++ return self.__pollingtime ++ ++ def debug_init(self): ++ global debuglevel ++ try: ++ with open(PMON_DEBUG_FILE, "r") as fd: ++ value = fd.read() ++ debuglevel = int(value) ++ except Exception: ++ debuglevel = 0 ++ ++ def doWork(self): ++ try: ++ self.debug_init() ++ self.updateSysDeviceStatus() ++ except Exception as e: ++ MSG_EXCEPTION = '%%PMON-5-NOTICE: Exception happened! info:%s' % str(e) ++ pmon_error(MSG_EXCEPTION % traceback.format_exc()) ++ ++ ++def run(): ++ platform = platformSyslog() ++ while True: ++ platform.doWork() ++ time.sleep(platform.getPollingtime()) ++ ++ ++if __name__ == '__main__': ++ run() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_cause.py b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_cause.py +new file mode 100755 +index 000000000..2f125c508 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_cause.py +@@ -0,0 +1,183 @@ ++#!/usr/bin/python3 ++# -*- coding: UTF-8 -*- ++import sys ++import os ++import time ++import syslog ++from platform_util import get_value, set_value, exec_os_cmd, wb_os_system ++from platform_config import REBOOT_CAUSE_PARA ++ ++REBOOT_CAUSE_DEBUG_FILE = "/etc/.reboot_cause_debug" ++REBOOT_CAUSE_STARTED_FLAG = "/tmp/.reboot_cause_started_flag" ++ ++debuglevel = 0 ++ ++ ++def record_syslog_debug(s): ++ if debuglevel: ++ syslog.openlog("REBOOT_CAUSE_DEBUG", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def record_syslog(s): ++ syslog.openlog("REBOOT_CAUSE", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_WARNING, s) ++ ++ ++class RebootCause(): ++ def __init__(self): ++ self.reboot_cause_para = REBOOT_CAUSE_PARA.copy() ++ self.reboot_cause_list = self.reboot_cause_para.get('reboot_cause_list', None) ++ self.other_reboot_cause_record = self.reboot_cause_para.get('other_reboot_cause_record', None) ++ ++ def debug_init(self): ++ global debuglevel ++ if os.path.exists(REBOOT_CAUSE_DEBUG_FILE): ++ debuglevel = 1 ++ else: ++ debuglevel = 0 ++ ++ def monitor_point_check(self, item): ++ try: ++ gettype = item.get('gettype', None) ++ okval = item.get('okval', None) ++ compare_mode = item.get('compare_mode', "equal") ++ ret, value = get_value(item) ++ if ret is True: ++ if compare_mode == "equal": ++ if value == okval: ++ return True ++ elif compare_mode == "great": ++ if value > okval: ++ return True ++ elif compare_mode == "ignore": ++ return True ++ else: ++ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: compare_mode %s not match error.' % (compare_mode)) ++ else: ++ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: base point check type:%s not support.' % gettype) ++ except Exception as e: ++ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: base point check error. msg: %s.' % (str(e))) ++ return False ++ ++ def reboot_cause_record(self, item_list): ++ RET = {"RETURN_KEY1": 0} ++ try: ++ for item in item_list: ++ record_type = item.get('record_type', None) ++ if record_type == 'file': ++ file_mode = item.get('mode', None) ++ file_log = item.get('log', None) ++ file_path = item.get('path', None) ++ file_max_size = item.get('file_max_size', 0) ++ ++ if file_path is None: ++ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: record type is file, but path is none.') ++ continue ++ ++ if file_max_size > 0: ++ file_size = 0 ++ if os.path.exists(file_path): ++ file_size = os.path.getsize(file_path) // file_max_size ++ if file_size >= 1: ++ reocrd_cmd = "mv %s %s_bak" % (file_path, file_path) ++ status, output = exec_os_cmd(reocrd_cmd) ++ if status: ++ record_syslog( ++ '%%REBOOT_CAUSE-3-EXCEPTION: exec cmd %s failed, %s' % ++ (reocrd_cmd, output)) ++ ++ if file_mode == 'cover': ++ operate_cmd = ">" ++ elif file_mode == 'add': ++ operate_cmd = ">>" ++ else: ++ RET["RETURN_KEY1"] = -1 ++ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: file record mode:%s not support.' % file_mode) ++ continue ++ ++ create_dir = "mkdir -p %s" % os.path.dirname(file_path) ++ status, ret_t = wb_os_system(create_dir) ++ if status != 0: ++ RET["RETURN_KEY1"] = -1 ++ record_syslog( ++ '%%REBOOT_CAUSE-3-EXCEPTION: create %s failed, msg: %s' % ++ (os.path.dirname(file_path), ret_t)) ++ continue ++ ++ status, date = wb_os_system("date") ++ if status != 0 or len(date) == 0: ++ RET["RETURN_KEY1"] = -1 ++ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: get date failed.') ++ continue ++ ++ reocrd_cmd = "echo %s %s %s %s" % (file_log, date, operate_cmd, file_path) ++ status, ret_t = wb_os_system(reocrd_cmd) ++ if status != 0: ++ RET["RETURN_KEY1"] = -1 ++ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: get date failed, msg: %s' % ret_t) ++ continue ++ wb_os_system('sync') ++ else: ++ RET["RETURN_KEY1"] = -1 ++ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: record_type:%s not support.' % record_type) ++ continue ++ except Exception as e: ++ RET["RETURN_KEY1"] = -1 ++ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: reboot cause record error. msg: %s.' % (str(e))) ++ if RET["RETURN_KEY1"] == 0: ++ return True ++ return False ++ ++ def reboot_cause_check(self): ++ try: ++ reboot_cause_flag = False ++ if self.reboot_cause_list is None: ++ record_syslog_debug('%%REBOOT_CAUSE-6-DEBUG: reboot cause check config not found') ++ return ++ for item in self.reboot_cause_list: ++ name = item.get('name', None) ++ monitor_point = item.get('monitor_point', None) ++ record = item.get('record', None) ++ finish_operation_list = item.get('finish_operation', []) ++ if name is None or monitor_point is None or record is None: ++ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: reboot cause check get config failed.name:%s, monitor_point:%s, record:%s' % ++ (name, monitor_point, record)) ++ return ++ ret = self.monitor_point_check(monitor_point) ++ if ret is True: ++ record_syslog_debug('%%REBOOT_CAUSE-6-DEBUG: %s reboot cause is happen' % name) ++ self.reboot_cause_record(record) ++ reboot_cause_flag = True ++ for finish_operation_item in finish_operation_list: ++ ret, log = set_value(finish_operation_item) ++ if ret is False: ++ log = "%%REBOOT_CAUSE-3-EXCEPTION: " + log ++ record_syslog(log) ++ ++ if reboot_cause_flag is False and self.other_reboot_cause_record is not None: ++ record_syslog_debug('%%REBOOT_CAUSE-6-DEBUG: other reboot cause is happen') ++ self.reboot_cause_record(self.other_reboot_cause_record) ++ except Exception as e: ++ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: reboot cause check error. msg: %s.' % (str(e))) ++ return ++ ++ def run(self): ++ try: ++ self.debug_init() ++ if os.path.exists(REBOOT_CAUSE_STARTED_FLAG): ++ record_syslog_debug( ++ '%%REBOOT_CAUSE-6-DEBUG: Reboot cause has been started and will not be started again') ++ sys.exit(0) ++ self.reboot_cause_check() ++ wb_os_system("touch %s" % REBOOT_CAUSE_STARTED_FLAG) ++ wb_os_system("sync") ++ time.sleep(5) ++ sys.exit(0) ++ except Exception as e: ++ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: %s.' % (str(e))) ++ ++ ++if __name__ == '__main__': ++ reboot_cause = RebootCause() ++ reboot_cause.run() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_ctrl.py b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_ctrl.py +new file mode 100755 +index 000000000..17d3f5902 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_ctrl.py +@@ -0,0 +1,150 @@ ++#!/usr/bin/env python3 ++# -*- coding: UTF-8 -*- ++import time ++import syslog ++import click ++from platform_util import write_sysfs, wbi2cset, io_wr, wbi2csetWord ++from platform_config import REBOOT_CTRL_PARAM ++ ++ ++REBOOTCTLDEBUG = 0 ++ ++CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} ++ ++ ++class AliasedGroup(click.Group): ++ def get_command(self, ctx, cmd_name): ++ rv = click.Group.get_command(self, ctx, cmd_name) ++ if rv is not None: ++ return rv ++ matches = [x for x in self.list_commands(ctx) ++ if x.startswith(cmd_name)] ++ if not matches: ++ return None ++ if len(matches) == 1: ++ return click.Group.get_command(self, ctx, matches[0]) ++ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) ++ return None ++ ++ ++def rebootctrlwarning(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("REBOOTCTRL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_WARNING, s) ++ ++ ++def rebootctrlcritical(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("REBOOTCTRL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_CRIT, s) ++ ++ ++def rebootctrlerror(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("REBOOTCTRL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++def rebootctrldebug(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ if REBOOTCTLDEBUG == 1: ++ syslog.openlog("REBOOTCTRL", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++class RebootCtrl(): ++ def __init__(self): ++ self.config = REBOOT_CTRL_PARAM.copy() ++ ++ def set_value(self, config, val): ++ way = config.get("gettype") ++ if way == 'sysfs': ++ loc = config.get("loc") ++ value = config.get(val) ++ rebootctrldebug("sysfs type.loc:0x%x, value:0x%x" % (loc, value)) ++ return write_sysfs(loc, "0x%02x" % value) ++ if way == "i2c": ++ bus = config.get("bus") ++ addr = config.get("loc") ++ offset = config.get("offset") ++ value = config.get(val) ++ rebootctrldebug("i2c type.bus:0x%x, addr:0x%x, offset:0x%x, value:0x%x" % (bus, addr, offset, value)) ++ return wbi2cset(bus, addr, offset, value) ++ if way == "io": ++ io_addr = config.get('io_addr') ++ value = config.get(val) ++ rebootctrldebug("io type.io_addr:0x%x, value:0x%x" % (io_addr, value)) ++ ret = io_wr(io_addr, value) ++ if ret is not True: ++ return False, ("write 0x%x failed" % io_addr) ++ return True, ("write 0x%x success" % io_addr) ++ if way == 'i2cword': ++ bus = config.get("bus") ++ addr = config.get("loc") ++ offset = config.get("offset") ++ value = config.get(val) ++ rebootctrldebug("i2cword type.bus:0x%x, addr:0x%x, offset:0x%x, value:0x%x" % (bus, addr, offset, value)) ++ return wbi2csetWord(bus, addr, offset, value) ++ return False, "unsupport way: %s" % way ++ ++ def reset_operate(self, config): ++ ret, log = self.set_value(config, "rst_val") ++ rst_delay = config.get("rst_delay", 0) ++ time.sleep(rst_delay) ++ return ret, log ++ ++ def unlock_reset_operate(self, config): ++ ret, log = self.set_value(config, "unlock_rst_val") ++ unlock_rst_delay = config.get("unlock_rst_delay", 0) ++ time.sleep(unlock_rst_delay) ++ return ret, log ++ ++ def do_rebootctrl(self, option): ++ if self.config is None: ++ rebootctrlerror("Reset failed, REBOOT_CTRL_PARAM cfg get failed.") ++ return ++ try: ++ name_conf = self.config.get(option, None) ++ if name_conf is None: ++ print("Reset %s not support" % option) ++ return ++ try: ++ click.confirm("Are you sure you want to reset " + option + "?", ++ default=False, abort=True, show_default=True) ++ except Exception as e: ++ print("Aborted, msg: %s" % str(e)) ++ return ++ print("Reset %s start" % option) ++ ret, log = self.reset_operate(name_conf) ++ if ret is False: ++ rebootctrlerror(log) ++ print("Reset %s failed" % option) ++ return ++ if "unlock_rst_val" in name_conf: ++ ret, log = self.unlock_reset_operate(name_conf) ++ if ret is False: ++ rebootctrlerror(log) ++ print("%s unlock reset failed" % option) ++ return ++ print("Reset %s success" % option) ++ except Exception: ++ rebootctrlerror("do_rebootctrl Exception error") ++ return ++ ++ ++@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) ++def main(): ++ '''reboot_ctrl reset [option]''' ++ ++ ++@main.command() ++@click.argument('option', required=True) ++def reset(option): ++ '''reset device''' ++ rebootctrldebug("reboot ctrl option %s" % option) ++ rebootctrl = RebootCtrl() ++ rebootctrl.do_rebootctrl(option) ++ ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/sensors b/platform/broadcom/sonic-platform-modules-micas/common/script/sensors +new file mode 100755 +index 000000000..a2c72b123 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/sensors +@@ -0,0 +1,8 @@ ++#!/bin/bash ++#docker exec -i pmon sensors "$@" ++ ++ ++#To probe sensors not part of lm-sensors ++if [ -r /usr/local/bin/platform_sensors.py ]; then ++ python /usr/local/bin/platform_sensors.py ++fi +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/set_eth_mac.py b/platform/broadcom/sonic-platform-modules-micas/common/script/set_eth_mac.py +new file mode 100755 +index 000000000..3e445a3ac +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/set_eth_mac.py +@@ -0,0 +1,274 @@ ++#!/usr/bin/env python ++# -*- coding: UTF-8 -*- ++import syslog ++import os ++import re ++import eepromutil.onietlv as ot ++from eepromutil.fru import ipmifru ++from platform_config import STARTMODULE, SET_MAC_CONF ++from platform_util import byteTostr, dev_file_read, exec_os_cmd ++ ++ ++STANDARD_MAC_LEN = 12 ++SETMAC_DEBUG_FILE = "/etc/.setmac_debug_flag" ++ ++SETMACERROR = 1 ++SETMACDEBUG = 2 ++debuglevel = 0 ++ ++cfg_prefix = "iface" ++mac_prefix = "hwaddress ether" ++ ++def setmac_debug(s): ++ if SETMACDEBUG & debuglevel: ++ syslog.openlog("SETMAC", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_INFO, s) ++ ++ ++def setmac_error(s): ++ if SETMACERROR & debuglevel: ++ syslog.openlog("SETMAC", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++def setmac_info(s): ++ syslog.openlog("SETMAC", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_INFO, s) ++ ++ ++def debug_init(): ++ global debuglevel ++ try: ++ with open(SETMAC_DEBUG_FILE, "r") as fd: ++ value = fd.read() ++ debuglevel = int(value) ++ except Exception: ++ debuglevel = 0 ++ ++ ++def decode_mac(encodedata): ++ if encodedata == None: ++ return None ++ ret = ":".join("%02x" % ord(data) for data in encodedata) ++ return ret.upper() ++ ++ ++def validate_mac(value): ++ if value is None: ++ setmac_error("mac is none") ++ return False ++ if value.find('-') != -1: ++ pattern = re.compile(r"^\s*([0-9a-fA-F]{2,2}-){5,5}[0-9a-fA-F]{2,2}\s*$") ++ temp_value = value.replace("-", "") ++ elif value.find(':') != -1: ++ pattern = re.compile(r"^\s*([0-9a-fA-F]{2,2}:){5,5}[0-9a-fA-F]{2,2}\s*$") ++ temp_value = value.replace(":", "") ++ else: ++ pattern = re.compile(r"^\s*([0-9a-fA-F]{2,2}){5,5}[0-9a-fA-F]{2,2}\s*$") ++ temp_value = value ++ if not pattern.match(value): ++ setmac_error("mac format error") ++ return False ++ if len(temp_value) != STANDARD_MAC_LEN: ++ setmac_error("mac len error len:%d" % len(temp_value)) ++ return False ++ if temp_value == "000000000000": ++ setmac_error("illegal zero mac") ++ return False ++ if int(temp_value, 16) >> 40 & 1 == 1: ++ setmac_error("illegal mac") ++ return False ++ setmac_debug("mac validate success") ++ return True ++ ++ ++def get_onie_eeprom(eeprom): ++ try: ++ onietlv = ot.onie_tlv() ++ rets = onietlv.decode(eeprom) ++ setmac_debug("%-20s %-5s %-5s %-20s" % ("TLV name", "Code", "lens", "Value")) ++ for item in rets: ++ if item["code"] == 0xfd: ++ setmac_debug("%-20s 0x%-02X %-5s" % (item["name"], item["code"], item["lens"])) ++ else: ++ setmac_debug("%-20s 0x%-02X %-5s %-20s" % (item["name"], item["code"], item["lens"], item["value"])) ++ except Exception as e: ++ setmac_error(str(e)) ++ return False, str(e) ++ return True, rets ++ ++ ++def get_fru_eeprom_info(eeprom): ++ try: ++ fru = ipmifru() ++ fru.decodeBin(eeprom) ++ except Exception as e: ++ setmac_error(str(e)) ++ return False, str(e) ++ return True, fru ++ ++ ++def get_mac_from_eeprom(eeprom_conf): ++ name = eeprom_conf.get("name") ++ e2_type = eeprom_conf.get("e2_type") ++ e2_path = eeprom_conf.get("e2_path") ++ e2_size = eeprom_conf.get("e2_size", 256) ++ mac_location = eeprom_conf.get("mac_location", {}) ++ e2_mac = None ++ ++ support_e2_type = ("fru", "onie_tlv") ++ if e2_type not in support_e2_type: ++ msg = "Unsupport e2 type: %s" % e2_type ++ return False, msg ++ ++ setmac_debug("===================%s===================" % name) ++ ret, binval_bytes = dev_file_read(e2_path, 0, e2_size) ++ if ret is False: ++ msg = "eeprom read error, eeprom path: %s, msg: %s" % (e2_path, binval_bytes) ++ return False, msg ++ binval = byteTostr(binval_bytes) ++ ++ # onie_tlv ++ if e2_type == "onie_tlv": ++ status, eeprom_info = get_onie_eeprom(binval) ++ if status is False: ++ msg = "get_onie_eeprom failed, msg: %s" % (eeprom_info) ++ return False, msg ++ ++ field = mac_location.get("field", "") ++ for eeprom_info_item in eeprom_info: ++ if eeprom_info_item.get("name") == field: ++ e2_mac = eeprom_info_item.get("value") ++ break ++ if e2_mac is None: ++ msg = "get_onie_eeprom mac address failed, e2_mac is None" ++ return False, msg ++ return True, e2_mac ++ ++ # fru ++ status, eeprom_info = get_fru_eeprom_info(binval) ++ if status is False: ++ msg = "get_fru_eeprom_info failed, msg: %s" % (eeprom_info) ++ return False, msg ++ ++ area = mac_location.get("area", "") ++ field = mac_location.get("field", "") ++ fru_area = getattr(eeprom_info, area, None) ++ fru_field = getattr(fru_area, field, None) ++ e2_mac = decode_mac(fru_field) ++ if e2_mac is None: ++ msg = "decode_mac failed, area: %s, field: %s, value: %s" % (area, field, fru_field) ++ return False, msg ++ return True, e2_mac ++ ++ ++def read_mac_from_config_file(ifcfg): ++ ifcfg_file_path = ifcfg.get("ifcfg_file_path") ++ if not os.path.exists(ifcfg_file_path): ++ msg = "%s not exist" % ifcfg_file_path ++ return False, msg ++ try: ++ fd = open(ifcfg_file_path, 'r') ++ for line in reversed(fd.readlines()): ++ if line.strip().startswith(mac_prefix): ++ mac = line.strip().replace(mac_prefix, "").strip() ++ return True, mac ++ except Exception as e: ++ setmac_error(str(e)) ++ return False, str(e) ++ return False, "mac address not found in %s" % ifcfg_file_path ++ ++ ++def set_e2_mac_to_config_file(eth_name, mac, ifcfg): ++ try: ++ ifcfg_file_path = ifcfg.get("ifcfg_file_path") ++ cfg_file_dir = os.path.dirname(ifcfg_file_path) ++ if not os.path.exists(cfg_file_dir): ++ cmd = "mkdir -p %s" % cfg_file_dir ++ setmac_info("Create interfaces config directory: %s" % cfg_file_dir) ++ os.system(cmd) ++ os.system("sync") ++ wr_val = cfg_prefix + " %s\n" % eth_name ++ wr_val += " %s %s\n" % (mac_prefix, mac) ++ with open(ifcfg_file_path, "w") as fd: ++ fd.write(wr_val) ++ os.system("sync") ++ setmac_info("Create interfaces config: %s with mac address: %s" % (ifcfg_file_path, mac)) ++ return True ++ except Exception as e: ++ setmac_error(str(e)) ++ return False ++ ++def get_eth_current_mac(eth_name): ++ get_mac_cmd = "ifconfig %s |grep ether |awk '{print $2}'" % eth_name ++ status, output = exec_os_cmd(get_mac_cmd) ++ if status or len(output) == 0: ++ msg = "get mac exec cmd : %s fail, msg: %s" % (get_mac_cmd, output) ++ setmac_error(msg) ++ return False, msg ++ mac = output.replace("\n", "").upper() ++ return True, mac ++ ++def set_eth_mac(eth_name, mac): ++ set_mac_cmd = "ifconfig %s hw ether %s" % (eth_name, mac) ++ status, output = exec_os_cmd(set_mac_cmd) ++ if status: ++ setmac_error("run cmd: %s fail, msg: %s" % (set_mac_cmd, output)) ++ return False ++ setmac_info("ifconfig %s with mac address: %s success" % (eth_name, mac)) ++ return True ++ ++ ++def doSetmac(): ++ if STARTMODULE.get('set_eth_mac', 0) == 0: ++ setmac_debug("set_eth_mac config not set") ++ return ++ ++ try: ++ if SET_MAC_CONF is None: ++ setmac_debug("set_mac_conf in none") ++ return ++ ++ if len(SET_MAC_CONF) == 0: ++ setmac_debug("set_mac_conf list is none") ++ return ++ ++ for setmac_item in SET_MAC_CONF: ++ eth_name = setmac_item.get("eth_name") ++ e2_name = setmac_item.get("e2_name", "") ++ ifcfg = setmac_item.get("ifcfg") ++ if eth_name is None or ifcfg is None: ++ setmac_error("set_mac_conf error, eth_name or ifcfg is None") ++ continue ++ ++ # decode mac by eeprom ++ status, e2_mac = get_mac_from_eeprom(setmac_item) ++ if status is False: ++ setmac_error("get mac from %s eeprom fail, msg: %s" % (e2_name, e2_mac)) ++ continue ++ status = validate_mac(e2_mac) ++ if status is False: ++ setmac_error("e2_mac: %s invalid" % e2_mac) ++ continue ++ setmac_debug("get mac from %s eeprom info success, mac: %s" % (e2_name, e2_mac)) ++ ++ # read config file mac address ++ status, cfg_mac = read_mac_from_config_file(ifcfg) ++ setmac_debug("read_mac_from_config_file, status: %s, cfg_mac: %s" % (status, cfg_mac)) ++ if status is False or cfg_mac != e2_mac: ++ set_e2_mac_to_config_file(eth_name, e2_mac, ifcfg) ++ # check current eth mac ++ status, current_mac = get_eth_current_mac(eth_name) ++ if status is False: ++ setmac_error("get %s current mac fail" % eth_name) ++ continue ++ setmac_debug("current_mac:%s len:%d" % (current_mac, len(current_mac))) ++ if current_mac != e2_mac: ++ set_eth_mac(eth_name, e2_mac) ++ except Exception as e: ++ setmac_error(str(e)) ++ return ++ ++ ++if __name__ == '__main__': ++ debug_init() ++ doSetmac() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/sfp_highest_temperatue.py b/platform/broadcom/sonic-platform-modules-micas/common/script/sfp_highest_temperatue.py +new file mode 100755 +index 000000000..4dd98f3a3 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/sfp_highest_temperatue.py +@@ -0,0 +1,148 @@ ++#!/usr/bin/python3 ++import os ++import importlib.machinery ++import time ++import syslog ++import subprocess ++import fcntl ++ ++sfp_temperature_file = "/tmp/highest_sff_temp" ++ ++SFP_TEMP_DEBUG_FILE = "/etc/.sfp_temp_debug_flag" ++SFP_TEMP_RECORD_DEBUG = 1 ++SFP_TEMP_RECORD_ERROR = 2 ++debuglevel = 0 ++ ++ ++def sfp_temp_debug(s): ++ if SFP_TEMP_RECORD_DEBUG & debuglevel: ++ syslog.openlog("SFP_TEMP_DEBUG", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def sfp_temp_error(s): ++ if SFP_TEMP_RECORD_ERROR & debuglevel: ++ syslog.openlog("SFP_TEMP_ERROR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++pidfile = None ++ ++ ++def file_rw_lock(): ++ global pidfile ++ pidfile = open(sfp_temperature_file, "r") ++ try: ++ fcntl.flock(pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB) ++ sfp_temp_debug("file lock success") ++ return True ++ except Exception: ++ if pidfile is not None: ++ pidfile.close() ++ pidfile = None ++ return False ++ ++ ++def file_rw_unlock(): ++ try: ++ global pidfile ++ ++ if pidfile is not None: ++ fcntl.flock(pidfile, fcntl.LOCK_UN) ++ pidfile.close() ++ pidfile = None ++ sfp_temp_debug("file unlock success") ++ else: ++ sfp_temp_debug("pidfile is invalid, do nothing") ++ return True ++ except Exception as e: ++ sfp_temp_error("file unlock err, msg:%s" % (str(e))) ++ return False ++ ++ ++def get_sfp_highest_temperature(): ++ highest_temperature = 0 ++ platform_sfputil = None ++ ++ sfputil_dir = "/usr/share/sonic/device/" ++ try: ++ if not os.path.exists(sfputil_dir): ++ sfputil_dir = "/usr/share/sonic/platform/" ++ sfputil_path = sfputil_dir + "/plugins/sfputil.py" ++ else: ++ cmd = "cat /host/machine.conf | grep onie_build_platform" ++ ret, output = subprocess.getstatusoutput(cmd) ++ if ret != 0: ++ sfp_temp_error("cmd: %s execution fail, output: %s" % (cmd, output)) ++ ++ onie_platform = output.split("=")[1] ++ sfputil_path = sfputil_dir + onie_platform + "/plugins/sfputil.py" ++ ++ module = importlib.machinery.SourceFileLoader("sfputil", sfputil_path).load_module() ++ platform_sfputil_class = getattr(module, "SfpUtil") ++ platform_sfputil = platform_sfputil_class() ++ ++ temperature = platform_sfputil.get_highest_temperature() ++ highest_temperature = int(temperature) * 1000 ++ except Exception as e: ++ sfp_temp_error("get sfp temperature error, msg:%s" % str(e)) ++ highest_temperature = -9999000 ++ ++ return highest_temperature ++ ++ ++def write_sfp_highest_temperature(temperature): ++ ++ loop = 1000 ++ ret = False ++ try: ++ if os.path.exists(sfp_temperature_file) is False: ++ with open(sfp_temperature_file, 'w') as sfp_f: ++ pass ++ for i in range(0, loop): ++ ret = file_rw_lock() ++ if ret is True: ++ break ++ time.sleep(0.001) ++ ++ if ret is False: ++ sfp_temp_error("take file lock timeout") ++ return ++ ++ with open(sfp_temperature_file, 'w') as sfp_f: ++ sfp_f.write("%s\n" % str(temperature)) ++ ++ file_rw_unlock() ++ return ++ except Exception as e: ++ sfp_temp_error("write sfp temperature error, msg:%s" % str(e)) ++ file_rw_unlock() ++ return ++ ++ ++def debug_init(): ++ global debuglevel ++ ++ try: ++ with open(SFP_TEMP_DEBUG_FILE, "r") as fd: ++ value = fd.read() ++ debuglevel = int(value) ++ except Exception: ++ debuglevel = 0 ++ ++ ++def main(): ++ while True: ++ debug_init() ++ temperature = 0 ++ try: ++ temperature = get_sfp_highest_temperature() ++ write_sfp_highest_temperature(temperature) ++ except Exception as e: ++ sfp_temp_error("get/write sfp temperature error, msg:%s" % str(e)) ++ write_sfp_highest_temperature(-9999000) ++ time.sleep(5) ++ ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/slot_monitor.py b/platform/broadcom/sonic-platform-modules-micas/common/script/slot_monitor.py +new file mode 100755 +index 000000000..0385f50b6 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/slot_monitor.py +@@ -0,0 +1,253 @@ ++#!/usr/bin/env python3 ++# -*- coding: UTF-8 -*- ++import time ++import syslog ++import traceback ++import operator ++import click ++import os ++from platform_config import SLOT_MONITOR_PARAM ++from platform_util import io_rd, io_wr, wbi2cget, wbi2cset ++ ++ ++SLOTMONITORDEBUG = 0 ++SLOTMONITOR_DEBUG_FILE = "/etc/.slotmonitor_debug_flag" ++ ++ ++CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} ++ ++ ++class AliasedGroup(click.Group): ++ def get_command(self, ctx, cmd_name): ++ rv = click.Group.get_command(self, ctx, cmd_name) ++ if rv is not None: ++ return rv ++ matches = [x for x in self.list_commands(ctx) ++ if x.startswith(cmd_name)] ++ if not matches: ++ return None ++ if len(matches) == 1: ++ return click.Group.get_command(self, ctx, matches[0]) ++ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) ++ return None ++ ++ ++def debug_init(): ++ global SLOTMONITORDEBUG ++ if os.path.exists(SLOTMONITOR_DEBUG_FILE): ++ SLOTMONITORDEBUG = 1 ++ else: ++ SLOTMONITORDEBUG = 0 ++ ++ ++def slotwarninglog(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("SLOTMONITOR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_WARNING, s) ++ ++ ++def slotcriticallog(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("SLOTMONITOR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_CRIT, s) ++ ++ ++def sloterror(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("SLOTMONITOR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++def slotinfo(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("SLOTMONITOR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_INFO, s) ++ ++ ++def slotdebuglog(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ if SLOTMONITORDEBUG == 1: ++ syslog.openlog("SLOTMONITOR", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++class SlotMonitor(): ++ def __init__(self): ++ self.preSlotStatus = [] ++ ++ def checkslot(self, ret): ++ slots_conf = SLOT_MONITOR_PARAM.get('slots', None) ++ ++ if slots_conf is None: ++ return False ++ for item_slot in slots_conf: ++ totalerr = 0 ++ try: ++ ret_t = {} ++ ret_t["id"] = item_slot.get('name') ++ ret_t["status"] = "" ++ presentattr = item_slot.get('present') ++ gettype = presentattr.get('gettype') ++ presentbit = presentattr.get('presentbit') ++ if gettype == "io": ++ io_addr = presentattr.get('io_addr') ++ val = io_rd(io_addr) ++ if val is not None: ++ retval = val ++ else: ++ totalerr -= 1 ++ sloterror(" %s %s" % (item_slot.get('name'), "lpc read failed")) ++ else: ++ bus = presentattr.get('bus') ++ loc = presentattr.get('loc') ++ offset = presentattr.get('offset') ++ ind, val = wbi2cget(bus, loc, offset) ++ if ind is True: ++ retval = val ++ else: ++ totalerr -= 1 ++ sloterror(" %s %s" % (item_slot.get('name'), "i2c read failed")) ++ if totalerr < 0: ++ ret_t["status"] = "NOT OK" ++ ret.append(ret_t) ++ continue ++ val_t = (int(retval, 16) & (1 << presentbit)) >> presentbit ++ if val_t != presentattr.get('okval'): ++ ret_t["status"] = "ABSENT" ++ else: ++ ret_t["status"] = "PRESENT" ++ except Exception as e: ++ ret_t["status"] = "NOT OK" ++ totalerr -= 1 ++ sloterror("checkslot error") ++ sloterror(str(e)) ++ slotdebuglog("%s status: %s" % (ret_t["id"], ret_t["status"])) ++ ret.append(ret_t) ++ return True ++ ++ def dealslotplugin(self, name): ++ slotdebuglog("enter dealslotplugin %s" % name) ++ # wait for slot stable ++ time.sleep(5) ++ slots_conf = SLOT_MONITOR_PARAM.get('slots', None) ++ if slots_conf is None: ++ return False ++ for item_slot in slots_conf: ++ try: ++ slotdebuglog("name %s, item_slot.get('name') %s" % (name, item_slot.get('name'))) ++ if name == item_slot.get('name'): ++ actattr = item_slot.get('act') ++ for item_act in actattr: ++ gettype = item_act.get('gettype') ++ if gettype == "io": ++ io_addr = item_act.get('io_addr') ++ value = item_act.get('value') ++ mask = item_act.get('mask') ++ val = io_rd(io_addr) ++ if val is None: ++ sloterror(" %s %s" % (name, "lpc read failed")) ++ continue ++ set_val = (int(val, 16) & mask) | value ++ ret = io_wr(io_addr, set_val) ++ if ret is not True: ++ sloterror(" %s %s" % (name, "lpc write failed")) ++ continue ++ slotdebuglog("io set io_addr:0x%x value:0x%x success" % (io_addr, set_val)) ++ elif gettype == "i2c": ++ bus = item_act.get('bus') ++ loc = item_act.get('loc') ++ offset = item_act.get('offset') ++ value = item_act.get('value') ++ ret, log = wbi2cset(bus, loc, offset, value) ++ if ret is not True: ++ sloterror(" %s %s %s" % (name, "i2c write failed", log)) ++ continue ++ slotdebuglog( ++ "i2c set bus:%d loc:0x%x offset:0x%x value:0x%x success" % ++ (bus, loc, offset, value)) ++ else: ++ sloterror("gettype error") ++ break ++ except Exception as e: ++ sloterror("dealslotplugin failed") ++ sloterror(str(e)) ++ return False ++ return True ++ ++ def updateSlotStatus(self): ++ ''' ++ Only two status: PRESENT and ABSENT ++ ''' ++ curSlotStatus = [] ++ self.checkslot(curSlotStatus) ++ slotdebuglog('curSlotStatus: {}\n preSlotStatus: {}'.format(curSlotStatus, self.preSlotStatus)) ++ if operator.eq(self.preSlotStatus, curSlotStatus) is False: ++ if len(self.preSlotStatus) == 0: ++ # first time ++ for i, item in enumerate(curSlotStatus): ++ if item['status'] == 'PRESENT': ++ slotdebuglog('SLOT_PLUG_IN: %s' % (item['id'])) ++ elif item['status'] == 'ABSENT': ++ slotdebuglog('SLOT_ABSENT: %s' % (item['id'])) ++ else: ++ slotdebuglog('SLOT_FAILED: %s status %s not support yet' % (item['id'], item['status'])) ++ self.preSlotStatus.append(item) ++ else: ++ for i, item in enumerate(curSlotStatus): ++ if item['status'] == self.preSlotStatus[i]['status']: ++ continue ++ if item['status'] == 'PRESENT' and self.preSlotStatus[i]['status'] == 'ABSENT': ++ self.dealslotplugin(item['id']) ++ slotinfo('SLOT_PLUG_IN: %s' % (item['id'])) ++ elif item['status'] == 'ABSENT' and self.preSlotStatus[i]['status'] == 'PRESENT': ++ slotwarninglog('SLOT_PLUG_OUT: %s' % (item['id'])) ++ else: ++ slotwarninglog('SLOT_PLUG_OUT: %s status change from %s to %s not support' % ++ (item['id'], self.preSlotStatus[i]['status'], item['status'])) ++ self.preSlotStatus.remove(self.preSlotStatus[i]) ++ self.preSlotStatus.insert(i, item) ++ ++ def slotmonitor(self): ++ self.updateSlotStatus() ++ return 0 ++ ++ ++def doSlotMonitor(slotMonitor): ++ slotMonitor.slotmonitor() ++ ++ ++def run(interval, slotMonitor): ++ # slotMonitor.devattrinit() ++ while True: ++ try: ++ debug_init() ++ doSlotMonitor(slotMonitor) ++ except Exception as e: ++ traceback.print_exc() ++ sloterror(str(e)) ++ time.sleep(interval) ++ ++ ++@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) ++def main(): ++ '''slot monitor operator''' ++ ++ ++@main.command() ++def start(): ++ '''start slot monitor''' ++ slotinfo("slot_monitor start") ++ slotMonitor = SlotMonitor() ++ interval = SLOT_MONITOR_PARAM.get('polling_time', 1) ++ run(interval, slotMonitor) ++ ++ ++@main.command() ++def stop(): ++ '''stop slot monitor ''' ++ slotinfo("stop") ++ ++ ++# device_i2c operation ++if __name__ == '__main__': ++ main() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/ssdmon b/platform/broadcom/sonic-platform-modules-micas/common/script/ssdmon +new file mode 100755 +index 000000000..4290b0a68 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/ssdmon +@@ -0,0 +1,82 @@ ++#!/usr/bin/env python3 ++# ++# ssdmon ++# ++# Command-line utility to check SSD health and parameters ++# ++ ++try: ++ import argparse ++ import os ++ import sys ++ ++ from sonic_py_common import device_info, logger ++except ImportError as e: ++ raise ImportError("%s - required module not found" % str(e)) ++ ++DEFAULT_DEVICE = "/dev/sda" ++SYSLOG_IDENTIFIER = "ssdmon" ++ ++# Global logger instance ++log = logger.Logger(SYSLOG_IDENTIFIER) ++ ++def import_ssd_api(diskdev): ++ """ ++ Loads platform specific or generic ssd_mon module from source ++ Raises an ImportError exception if none of above available ++ ++ Returns: ++ Instance of the class with SSD API implementation (vendor or generic) ++ """ ++ ++ # try to load platform specific module ++ try: ++ platform_path, _ = device_info.get_paths_to_platform_and_hwsku_dirs() ++ platform_plugins_path = os.path.join(platform_path, "plugins") ++ sys.path.append(os.path.abspath(platform_plugins_path)) ++ from ssd_util import SsdUtil ++ except ImportError as e: ++ log.log_warning("Platform specific SsdMon module not found.") ++ ++ return SsdUtil(diskdev) ++ ++def is_number(s): ++ try: ++ float(s) ++ return True ++ except ValueError: ++ return False ++ ++# ==================== Entry point ==================== ++def ssdmon(): ++ if os.geteuid() != 0: ++ print("Root privileges are required for this operation") ++ sys.exit(1) ++ ++ parser = argparse.ArgumentParser() ++ parser.add_argument("-d", "--device", help="Device name to show health info", default=DEFAULT_DEVICE) ++ parser.add_argument("-t", "--temperature", action="store_true", default=False, help="Show only temperature") ++ parser.add_argument("-j", "--health", action="store_true", default=False, help="Show only health") ++ ++ args = parser.parse_args() ++ ++ ssd = import_ssd_api(args.device) ++ ++ if args.temperature: ++ print(ssd.get_temperature()) ++ return ++ ++ if args.health: ++ print(ssd.get_health()) ++ return ++ ++ print("Device Model : {}".format(ssd.get_model())) ++ print("Firmware : {}".format(ssd.get_firmware())) ++ print("Serial : {}".format(ssd.get_serial())) ++ print("Health : {}{}".format(ssd.get_health(), "%" if is_number(ssd.get_health()) else "")) ++ print("Remain Life : {}{}".format(ssd.get_remaining_life(), "%" if is_number(ssd.get_remaining_life()) else "")) ++ print("Temperature : {}{}".format(ssd.get_temperature(), "C" if is_number(ssd.get_temperature()) else "")) ++ print("SATA Rate : {}".format(ssd.get_sata_rate())) ++ ++if __name__ == '__main__': ++ ssdmon() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/tty_console.py b/platform/broadcom/sonic-platform-modules-micas/common/script/tty_console.py +new file mode 100755 +index 000000000..4fae02f51 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/tty_console.py +@@ -0,0 +1,91 @@ ++#!/usr/bin/python3 ++# -*- coding: UTF-8 -*- ++ ++import logging.handlers ++import subprocess ++import shlex ++import time ++import sys ++import os ++from platform_util import CompressedRotatingFileHandler, exec_os_cmd ++ ++console_file = "/dev/ttyS1" ++console_logfile = "/var/log/bmc-console.log" ++MAX_LOG_BYTES = 20 * 1024 * 1024 ++BACKUP_COUNT = 9 ++ ++READ_SIZE = 1024 ++ ++logger = logging.getLogger("cpu_monitor_bmc") ++logger.setLevel(logging.DEBUG) ++fh = CompressedRotatingFileHandler( ++ console_logfile, ++ mode='a', ++ maxBytes=MAX_LOG_BYTES, ++ backupCount=BACKUP_COUNT, ++ encoding=None, ++ delay=0) ++fh.setLevel(logging.DEBUG) ++ ++formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") ++fh.setFormatter(formatter) ++logger.addHandler(fh) ++ ++ ++def tty_system_cmd(cmd, print_log=True): ++ if print_log: ++ logger.debug("command: %s", cmd) ++ status, output = exec_os_cmd(cmd) ++ logger.debug("command status %s", status) ++ logger.debug("command output:\n%s", output) ++ else: ++ status, output = exec_os_cmd(cmd) ++ return status, output ++ ++ ++if __name__ == '__main__': ++ try_times = 0 ++ while try_times < 3: ++ try_times = try_times + 1 ++ ret, log = tty_system_cmd("stty -F /dev/ttyS1 | grep 115200", True) ++ if len(log) != 0 and "115200" in log: ++ break ++ tty_system_cmd("stty -F /dev/ttyS1 115200", True) ++ if try_times > 1: ++ logger.error("The %d time try to set SONiC /dev/ttyS1 115200", try_times) ++ ++ if not os.path.exists(console_file): ++ logger.error("device %s not exist", console_file) ++ sys.exit(1) ++ ++ nopen = 3 ++ while nopen > 0: ++ try: ++ console_fd = os.open(console_file, os.O_RDONLY) ++ break ++ except Exception as e: ++ logger.error(e) ++ logger.error("open %s failed", console_file) ++ nopen = nopen - 1 ++ time.sleep(1) ++ if nopen == 0: ++ sys.exit(1) ++ ++ try: ++ tmp_read = "" ++ while True: ++ dev_read = os.read(console_fd, READ_SIZE) ++ dev_read = str(dev_read, encoding='utf-8') ++ if len(dev_read) == 1 and dev_read == "\n": ++ continue ++ if dev_read[len(dev_read) - 1] == '\n': ++ tmp_read = tmp_read + dev_read[0:(len(dev_read) - 1)] ++ logger.info(tmp_read) ++ tmp_read = "" ++ else: ++ tmp_read = tmp_read + dev_read ++ ++ except Exception as e: ++ if console_fd is not None: ++ os.close(console_fd) ++ logger.error(e) +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/upgrade.py b/platform/broadcom/sonic-platform-modules-micas/common/script/upgrade.py +new file mode 100755 +index 000000000..1b2523198 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/upgrade.py +@@ -0,0 +1,991 @@ ++#!/usr/bin/env python3 ++# -*- coding: UTF-8 -*- ++import sys ++import os ++import time ++import syslog ++import signal ++import click ++from platform_util import get_value, set_value, exec_os_cmd, exec_os_cmd_log ++from platform_config import UPGRADE_SUMMARY, WARM_UPGRADE_STARTED_FLAG ++from warm_upgrade import WarmBasePlatform ++ ++ ++############################# Error code defined ############################# ++ERR_FW_CHECK_CPLD_UPGRADE = -601 # "Failed to check the device CPLD information" ++ERR_FW_CHECK_FPGA_UPGRADE = -602 # "Failed to check the device FPGA information" ++ERR_FW_MATCH_CPLD_UPGRADE = -603 # "Not found upgrade CPLD file." ++ERR_FW_MATCH_FPGA_UPGRADE = -604 # "Not found upgrade FPGA file." ++ERR_FW_SAMEVER_CPLD_UPGRADE = -605 # "The CPLD version in device is same" ++ERR_FW_SAMEVER_FPGA_UPGRADE = -606 # "The FPGA version in device is same" ++ERR_FW_DO_CPLD_UPGRADE = -607 # "Doing upgrade CPLD is failed." ++ERR_FW_DO_FPGA_UPGRADE = -608 # "Doing upgrade FPGA is failed." ++ERR_FW_UPGRADE = -609 # "Failed to upgrade firmware" ++FIRMWARE_PROGRAM_EXEC_ERR = -610 # "Firmware program run error!" ++ERR_FW_FILE_FOUND = -701 # "Failed to find upgrade file" ++ERR_FW_HEAD_PARSE = -702 # "Failed to parse upgrade firmware head info" ++ERR_FW_CONFIG_FOUND = -703 # "Failed to find config item" ++ERR_FW_NOSUPPORT_HOT = -704 # "No support hot upgrade" ++ERR_FW_CHECK_SIZE = -705 # "Failed to check file size" ++ERR_FW_DEVICE_ACCESS = -706 # "Failed to access device" ++ERR_FW_NO_FILE_SUCCESS = -707 # "No files were successfully upgraded" ++ERR_FW_CARD_ABSENT = -708 # "The subcard not present" ++ERR_FW_HEAD_CHECK = -709 # "Failed to check head info" ++ERR_FW_FOOL_PROOF = -710 # "Failed to fool proof verification" ++ERR_FW_RAISE_EXCEPTION = -711 # Code raise exception ++ERR_FW_INVALID_PARAM = -712 # Invalid parameter ++ERR_FW_UNZIP_FAILED = -713 # Unzip firmware failed ++ ++FIRMWARE_SUCCESS = 0 ++CHECK_OK = 0 ++ ++ ++UPGRADE_DEBUG_FILE = "/etc/.upgrade_debug_flag" ++UPGRADE_FILE_DIR = "/tmp/firmware/" ++ ++UPGRADEDEBUG = 1 ++ ++debuglevel = 0 ++ ++COLD_UPGRADE = 1 ++WARM_UPGRADE = 2 ++TEST_UPGRADE = 3 ++BMC_UPGRADE = 4 ++ ++CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} ++ ++ ++class AliasedGroup(click.Group): ++ ++ def get_command(self, ctx, cmd_name): ++ rv = click.Group.get_command(self, ctx, cmd_name) ++ if rv is not None: ++ return rv ++ matches = [x for x in self.list_commands(ctx) ++ if x.startswith(cmd_name)] ++ if not matches: ++ return None ++ if len(matches) == 1: ++ return click.Group.get_command(self, ctx, matches[0]) ++ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) ++ return None ++ ++ ++def debug_init(): ++ global debuglevel ++ if os.path.exists(UPGRADE_DEBUG_FILE): ++ debuglevel = debuglevel | UPGRADEDEBUG ++ else: ++ debuglevel = debuglevel & ~(UPGRADEDEBUG) ++ ++ ++def upgradewarninglog(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("UPGRADE", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_WARNING, s) ++ ++ ++def upgradecriticallog(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("UPGRADE", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_CRIT, s) ++ ++ ++def upgradeerror(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("UPGRADE", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++def upgradedebuglog(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ if UPGRADEDEBUG & debuglevel: ++ syslog.openlog("UPGRADE", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def signal_init(): ++ signal.signal(signal.SIGINT, signal.SIG_IGN) # ignore ctrl+c signal ++ signal.signal(signal.SIGTERM, signal.SIG_IGN) # ignore kill signal ++ signal.signal(signal.SIGTSTP, signal.SIG_IGN) # ignore ctrl+z signal ++ ++ ++class BasePlatform(): ++ ++ def __init__(self): ++ self.upgrade_param = UPGRADE_SUMMARY.copy() ++ self.devtype = self.upgrade_param.get('devtype', None) ++ self.max_slot_num = self.upgrade_param.get("max_slot_num", 0) ++ self.head_info_config = {} ++ self.slot_config = {} ++ self.cold_chain_config = {} ++ self.subtype = None ++ self.chain = None ++ self.filetype = None ++ self.DEVTYPE = None ++ self.SUBTYPE = '0' ++ self.TYPE = None ++ self.CHAIN = None ++ self.CHIPNAME = None ++ self.VERSION = None ++ self.FILETYPE = None ++ self.CRC = None ++ self.SUBTYPE_LIST = None ++ ++ def save_and_set_value(self, cfg_list): ++ for config in cfg_list: ++ ret, val = get_value(config) ++ if ret: ++ config["save_value"] = val ++ else: ++ upgradeerror(val) ++ return False, "get save value fail" ++ ++ set_val = config.get("set_value", None) ++ if set_val is None: ++ log = "save_and_set_value lack of set_val config" ++ upgradeerror(log) ++ return log ++ ++ gettype = config.get("gettype", None) ++ set_cmd = config.get("set_cmd", None) ++ if gettype == "cmd": ++ if set_cmd is None: ++ log = "save_and_set_value lack of set_cmd config" ++ upgradeerror(log) ++ return False, log ++ config["cmd"] = set_cmd % set_val ++ upgradedebuglog("save_and_set_value modify set cmd to %s" % config["cmd"]) ++ else: ++ config["value"] = set_val ++ upgradedebuglog("save_and_set_value modify set val to %s" % config["value"]) ++ ++ ret, log = set_value(config) ++ if ret is False: ++ upgradeerror(log) ++ return False, log ++ return True, "save and set value success" ++ ++ def recover_save_value(self, cfg_list): ++ total_err = 0 ++ for config in cfg_list: ++ upgradedebuglog("config: %s, recover save value" % config) ++ val = config.get("save_value", None) ++ if val is None: ++ upgradeerror("recover_save_value lack of save_value config") ++ total_err -= 1 ++ continue ++ gettype = config.get("gettype", None) ++ set_cmd = config.get("set_cmd", None) ++ if gettype == "cmd": ++ config["cmd"] = set_cmd % val ++ upgradedebuglog("recover_save_value modify set cmd to %s" % config["cmd"]) ++ else: ++ config["value"] = val ++ upgradedebuglog("recover_save_value modify set val to %s" % config["value"]) ++ ++ ret, log = set_value(config) ++ if ret is False: ++ upgradeerror("recover save value write failed, log: %s" % log) ++ total_err -= 1 ++ else: ++ upgradedebuglog("recover save value success") ++ if total_err < 0: ++ return False, "recover save value failed" ++ return True, "recover save value success" ++ ++ def check_slot_present(self, slot_present_config): ++ presentbit = slot_present_config.get('presentbit') ++ ret, value = get_value(slot_present_config) ++ if ret is False: ++ return "NOT OK" ++ if isinstance(value, str): ++ val_t = int(value, 16) ++ else: ++ val_t = value ++ val_t = (val_t & (1 << presentbit)) >> presentbit ++ if val_t != slot_present_config.get('okval'): ++ status = "ABSENT" ++ else: ++ status = "PRESENT" ++ return status ++ ++ def linecard_present_check(self, slot_present_config): ++ present_status = self.check_slot_present(slot_present_config) ++ if present_status == "NOT OK": ++ return ERR_FW_DEVICE_ACCESS, "get slot present status failed." ++ if present_status == "ABSENT": ++ return ERR_FW_CARD_ABSENT, "slot absent" ++ return CHECK_OK, "slot present" ++ ++ def subprocess_warm_upgrade(self, config, file, main_type, sub_type, slot): ++ dev_name = config.get("name", None) ++ status, output = self.subprocess_firmware_upgrade(config, file, main_type, sub_type, slot) ++ if status is False: ++ upgradeerror("%s warm upgrade failed" % dev_name) ++ return False, output ++ command = "warm_upgrade.py %s 0x%x 0x%x %s %s %s" % (file, main_type, sub_type, slot, self.filetype, self.chain) ++ upgradedebuglog("warm upgrade cmd: %s" % command) ++ if os.path.exists(UPGRADE_DEBUG_FILE): ++ status, output = exec_os_cmd_log(command) ++ else: ++ status, output = exec_os_cmd(command) ++ if status: ++ upgradeerror("%s warm upgrade failed" % dev_name) ++ return False, output ++ upgradedebuglog("%s warm upgrade success" % dev_name) ++ return True, "upgrade success" ++ ++ def do_fw_upg_init_cmd(self, dev_name, init_cmd_list): ++ # pre operation ++ try: ++ for init_cmd_config in init_cmd_list: ++ ret, log = set_value(init_cmd_config) ++ if ret is False: ++ upgradeerror("%s do init cmd: %s failed, msg: %s" % (dev_name, init_cmd_config, log)) ++ return False, log ++ msg = "%s firmware init cmd all set success" % dev_name ++ upgradedebuglog(msg) ++ return True, msg ++ except Exception as e: ++ return False, str(e) ++ ++ def do_fw_upg_finish_cmd(self, dev_name, finish_cmd_list): ++ # end operation ++ ret = 0 ++ for finish_cmd_config in finish_cmd_list: ++ ret_t, log = set_value(finish_cmd_config) ++ if ret_t is False: ++ upgradeerror("%s do finish cmd: %s failed, msg: %s" % (dev_name, finish_cmd_config, log)) ++ ret = -1 ++ if ret != 0: ++ msg = "%s firmware finish cmd exec failed" % dev_name ++ upgradeerror(msg) ++ return False, msg ++ msg = "%s firmware finish cmd all set success" % dev_name ++ upgradedebuglog(msg) ++ return True, msg ++ ++ def subprocess_firmware_upgrade(self, config, file, main_type, sub_type, slot): ++ dev_name = config.get("name", None) ++ init_cmd_list = config.get("init_cmd", []) ++ finish_cmd_list = config.get("finish_cmd", []) ++ try: ++ ret, log = self.do_fw_upg_init_cmd(dev_name, init_cmd_list) ++ if ret is False: ++ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) ++ return False, log ++ time.sleep(0.5) # delay 0.5s after execute init_cmd ++ command = "firmware_upgrade %s 0x%x 0x%x %s" % (file, main_type, sub_type, slot) ++ upgradedebuglog("firmware upgrade cmd: %s" % command) ++ if os.path.exists(UPGRADE_DEBUG_FILE): ++ status, output = exec_os_cmd_log(command) ++ else: ++ status, output = exec_os_cmd(command) ++ if status: ++ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) ++ upgradeerror("%s firmware upgrade failed, msg: %s" % (dev_name, output)) ++ return False, output ++ upgradedebuglog("%s firmware upgrade success" % dev_name) ++ ret, log = self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) ++ if ret is False: ++ return False, log ++ return True, "upgrade success" ++ except Exception as e: ++ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) ++ return False, str(e) ++ ++ def subprocess_test_upgrade(self, config, file, main_type, sub_type, slot): ++ dev_name = config.get("name", None) ++ init_cmd_list = config.get("init_cmd", []) ++ finish_cmd_list = config.get("finish_cmd", []) ++ try: ++ ret, log = self.do_fw_upg_init_cmd(dev_name, init_cmd_list) ++ if ret is False: ++ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) ++ return False, log ++ time.sleep(0.5) # delay 0.5s after execute init_cmd ++ command = "firmware_upgrade test %s 0x%x 0x%x %s" % (file, main_type, sub_type, slot) ++ upgradedebuglog("firmware upgrade cmd: %s" % command) ++ if os.path.exists(UPGRADE_DEBUG_FILE): ++ status, output = exec_os_cmd_log(command) ++ else: ++ status, output = exec_os_cmd(command) ++ if status: ++ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) ++ upgradeerror("%s test upgrade failed, msg: %s" % (dev_name, output)) ++ return False, output ++ upgradedebuglog("%s test upgrade success" % dev_name) ++ ret, log = self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) ++ if ret is False: ++ return False, log ++ return True, "upgrade success" ++ except Exception as e: ++ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) ++ return False, str(e) ++ ++ def subprocess_bmc_upgrade(self, config, file, chip_select, erase_type): ++ dev_name = config.get("name", None) ++ init_cmd_list = config.get("init_cmd", []) ++ finish_cmd_list = config.get("finish_cmd", []) ++ save_set_reg_list = config.get("save_set_reg", []) ++ try: ++ # save and set reg ++ ret, log = self.save_and_set_value(save_set_reg_list) ++ if ret is False: ++ upgradeerror(log) ++ self.recover_save_value(save_set_reg_list) ++ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) ++ return False, log ++ upgradedebuglog("%s save and set cmd all set success" % dev_name) ++ time.sleep(0.5) # delay 0.5s after execute save and set reg ++ ++ # pre operation ++ ret, log = self.do_fw_upg_init_cmd(dev_name, init_cmd_list) ++ if ret is False: ++ self.recover_save_value(save_set_reg_list) ++ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) ++ return False, log ++ ++ upgradedebuglog("%s bmc init cmd all set success" % dev_name) ++ time.sleep(0.5) # delay 0.5s after execute init_cmd ++ ++ command = "fw_upgrade upgrade %s %s %s" % (file, chip_select, erase_type) ++ upgradedebuglog("fw_upgrade upgrade cmd: %s" % command) ++ status, output = exec_os_cmd_log(command) ++ if status: ++ upgradeerror("%s bmc upgrade failed" % dev_name) ++ self.recover_save_value(save_set_reg_list) ++ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) ++ return False, output ++ upgradedebuglog("%s bmc upgrade success" % dev_name) ++ ++ ret1, log1 = self.recover_save_value(save_set_reg_list) ++ if ret1 is False: ++ upgradeerror("bmc upgrade recover save value failed, msg: %s" % log1) ++ ret2, log2 = self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) ++ if ret2 is False: ++ upgradeerror("bmc upgrade do finish command failed, msg: %s" % log2) ++ if ret1 is False or ret2 is False: ++ return False, "bmc upgrade do recover save value or finish command failed" ++ return True, "upgrade success" ++ ++ except Exception as e: ++ self.recover_save_value(save_set_reg_list) ++ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) ++ return False, str(e) ++ ++ def file_head_param_check(self, head_info_config): ++ try: ++ self.DEVTYPE = head_info_config.get('DEVTYPE', None) ++ self.SUBTYPE = head_info_config.get('SUBTYPE', '0') ++ self.TYPE = head_info_config.get('TYPE', None) ++ self.CHAIN = head_info_config.get('CHAIN', None) ++ self.CHIPNAME = head_info_config.get('CHIPNAME', None) ++ self.VERSION = head_info_config.get('VERSION', None) ++ self.FILETYPE = head_info_config.get('FILETYPE', None) ++ self.CRC = head_info_config.get('CRC', None) ++ ++ if self.devtype != int(self.DEVTYPE, 16): ++ return ERR_FW_HEAD_CHECK, ("no support %s devtype" % self.DEVTYPE) ++ ++ if self.SUBTYPE is not None: ++ self.SUBTYPE_LIST = self.SUBTYPE.split(',') ++ self.SUBTYPE_LIST = [int(tmp_subtype, base=16) for tmp_subtype in self.SUBTYPE_LIST] ++ if len(self.SUBTYPE) != 0 and self.subtype not in self.SUBTYPE_LIST: ++ return ERR_FW_HEAD_CHECK, ("no support %s SUBTYPE" % self.SUBTYPE) ++ ++ if len(self.CHAIN) == 0 or len(self.FILETYPE) == 0: ++ return ERR_FW_HEAD_CHECK, ("CHAIN:%s, FILETYPE:%s get failed" % (self.CHAIN, self.FILETYPE)) ++ self.chain = int(self.CHAIN) ++ self.filetype = self.FILETYPE ++ upgradedebuglog("file head param: devtype:0x%x, subtype:0x%x, chain:%s, filetype:%s" ++ % (self.devtype, self.subtype, self.chain, self.filetype)) ++ return CHECK_OK, "SUCCESS" ++ except Exception as e: ++ return ERR_FW_RAISE_EXCEPTION, str(e) ++ ++ def parse_file_head(self, file): ++ try: ++ self.head_info_config = {} ++ with open(file, 'r', errors='ignore') as fd: ++ rdbuf = fd.read() ++ upgradedebuglog("start parse upgrade file head") ++ file_head_start = rdbuf.index('FILEHEADER(\n') # ponit to F ++ file_head_start += rdbuf[file_head_start:].index('\n') # ponit to \n ++ file_head_end = rdbuf.index(')\n') ++ header_buf = rdbuf[file_head_start + 1: file_head_end - 1] ++ upgradedebuglog("upgrade file head find FILEHEADER") ++ for line in header_buf.split('\n'): ++ head_list = line.split('=', 1) ++ head_key = head_list[0] ++ head_val = head_list[1] ++ self.head_info_config[head_key] = head_val ++ upgradedebuglog("file: %s head_info_config: %s" % (file, self.head_info_config)) ++ return CHECK_OK, "SUCCESS" ++ except Exception as e: ++ msg = "parse %s head failed, msg: %s" % (file, str(e)) ++ upgradeerror(msg) ++ return ERR_FW_RAISE_EXCEPTION, msg ++ ++ def get_file_size_k(self, file): ++ fsize = os.path.getsize(file) ++ fsize = fsize / float(1024) ++ return round(fsize, 2) ++ ++ def get_device_model(self, conf): ++ ret, val = get_value(conf) ++ if ret is False: ++ msg = "get device model failed, msg: %s" % val ++ return False, msg ++ decode_val = conf.get("decode") ++ if decode_val is None: ++ return True, val ++ for k, v in decode_val.items(): ++ if val == v: ++ return True, k ++ msg = "device model decode error, val: %s" % val ++ return False, msg ++ ++ def upgrade_fool_proofing(self, conf): ++ try: ++ status, dev_model = self.get_device_model(conf) ++ if status is False: ++ msg = "upgrade fool proofing get device model failed, msg: %s" % dev_model ++ upgradeerror(msg) ++ return False, msg ++ upgradedebuglog("get device model success, device model: %s" % dev_model) ++ if dev_model != self.VERSION: ++ msg = "upgrade fool proofing failed, device model: %s, upgrade file version: %s" % ( ++ dev_model, self.VERSION) ++ upgradedebuglog(msg) ++ return False, msg ++ msg = "upgrade fool proofing pass, device model: %s, upgrade file version: %s" % (dev_model, self.VERSION) ++ upgradedebuglog(msg) ++ return True, msg ++ except Exception as e: ++ upgradeerror(str(e)) ++ return False, str(e) ++ ++ def upgrading(self, config, file, devtype, subtype, slot, option_flag, erase_type=None): ++ dev_name = config.get("name", None) ++ if option_flag == COLD_UPGRADE: ++ status, output = self.subprocess_firmware_upgrade(config, file, devtype, subtype, slot) ++ elif option_flag == WARM_UPGRADE: ++ status, output = self.subprocess_warm_upgrade(config, file, devtype, subtype, slot) ++ elif option_flag == TEST_UPGRADE: ++ status, output = self.subprocess_test_upgrade(config, file, devtype, subtype, slot) ++ elif option_flag == BMC_UPGRADE: ++ status, output = self.subprocess_bmc_upgrade(config, file, slot, erase_type) ++ else: ++ log = "%s set error option flag" % dev_name ++ upgradeerror(log) ++ return False, log ++ ++ if status is False: ++ upgradeerror("%s upgrade failed" % dev_name) ++ return False, output ++ upgradedebuglog("%s upgrade success" % dev_name) ++ return True, "upgrade success" ++ ++ def initial_check(self, file, slot, upg_type): ++ try: ++ upgradedebuglog("BasePlatform initial_check, file: %s, slot: %s, upg_type: %s" % ++ (file, slot, upg_type)) ++ ++ upgradedebuglog("do file exist check...") ++ if not os.path.isfile(file): ++ msg = "%s not found" % file ++ upgradedebuglog(msg) ++ return ERR_FW_FILE_FOUND, msg ++ upgradedebuglog("file exist check ok") ++ ++ slot_name = "slot%d" % slot ++ slot_config = self.upgrade_param.get(slot_name, {}) ++ slot_present_config = slot_config.get("present", {}) ++ if len(slot_present_config) != 0: ++ upgradedebuglog("do %s present check..." % slot_name) ++ ret, log = self.linecard_present_check(slot_present_config) ++ if ret != CHECK_OK: ++ msg = "check %s present error, msg: %s" % (slot_name, log) ++ upgradedebuglog(msg) ++ return ret, msg ++ upgradedebuglog("%s present check ok" % slot_name) ++ ++ upgradedebuglog("do file head parse...") ++ self.subtype = slot_config.get("subtype", 0) ++ ret, log = self.parse_file_head(file) ++ if ret != CHECK_OK: ++ return ret, log ++ upgradedebuglog("file head parse success") ++ ++ upgradedebuglog("do file head check...") ++ ret, log = self.file_head_param_check(self.head_info_config) ++ if ret != CHECK_OK: ++ msg = "file: %s, head check failed, msg: %s" % (file, log) ++ upgradedebuglog(msg) ++ return ret, msg ++ upgradedebuglog("file head check ok") ++ ++ upgradedebuglog("get upgrade chain config...") ++ filetype_config = slot_config.get(self.filetype, {}) ++ if len(filetype_config) == 0: ++ msg = "file: %s filetype: %s no support" % (file, self.filetype) ++ upgradedebuglog(msg) ++ return ERR_FW_CONFIG_FOUND, msg ++ chain_num = "chain%s" % self.chain ++ chain_config = filetype_config.get(chain_num, {}) ++ if len(chain_config) == 0: ++ msg = "file: %s get %s config failed" % (file, chain_num) ++ upgradedebuglog(msg) ++ return ERR_FW_CONFIG_FOUND, msg ++ self.cold_chain_config = chain_config ++ upgradedebuglog("get %s filetype: %s %s config success" % (slot_name, self.filetype, chain_num)) ++ ++ fool_proofing = chain_config.get("fool_proofing") ++ if fool_proofing is not None: ++ upgradedebuglog("do fool proofing check...") ++ status, log = self.upgrade_fool_proofing(fool_proofing) ++ if status is False: ++ msg = "upgrade fool proofing check failed, msg: %s" % log ++ upgradedebuglog(msg) ++ return ERR_FW_FOOL_PROOF, msg ++ upgradedebuglog("do fool proofing check ok") ++ ++ if upg_type == WARM_UPGRADE: ++ upgradedebuglog("do support warm upgrade check...") ++ if chain_config.get("is_support_warm_upg", 0) != 1: ++ msg = "file: %s %s chain config not support warm upgrade" % (file, slot_name) ++ upgradedebuglog(msg) ++ return ERR_FW_NOSUPPORT_HOT, msg ++ upgradedebuglog("file: %s %s chain config support warm upgrade" % (file, slot_name)) ++ ++ filesizecheck = chain_config.get("filesizecheck", 0) ++ if filesizecheck != 0: ++ upgradedebuglog("do file size check...") ++ file_size = self.get_file_size_k(file) ++ if file_size > filesizecheck: ++ msg = "file: %s size: %s exceed %s" % (file, file_size, filesizecheck) ++ upgradedebuglog(msg) ++ return ERR_FW_CHECK_SIZE, msg ++ msg = "file: %s size: %s check ok" % (file, file_size) ++ upgradedebuglog(msg) ++ ++ msg = "file: %s slot: %s upgrade type: %s check ok" % (file, slot, upg_type) ++ upgradedebuglog(msg) ++ return CHECK_OK, msg ++ except Exception as e: ++ return ERR_FW_RAISE_EXCEPTION, str(e) ++ ++ def do_upgrade(self, file, slot, upg_type): ++ try: ++ ret, log = self.initial_check(file, slot, upg_type) ++ if ret != CHECK_OK: ++ return ret, log ++ ++ # start upgrading ++ upgradedebuglog("start upgrading") ++ ret, log = self.upgrading(self.cold_chain_config, file, self.devtype, self.subtype, slot, upg_type) ++ if ret is False: ++ upgradeerror("upgrade failed") ++ return ERR_FW_UPGRADE, log ++ upgradedebuglog("upgrade success") ++ return FIRMWARE_SUCCESS, "SUCCESS" ++ except Exception as e: ++ return ERR_FW_RAISE_EXCEPTION, str(e) ++ ++ def do_pre_check(self, conf): ++ ret, val = get_value(conf) ++ if ret is False: ++ msg = "pre check get value failed, msg: %s" % val ++ return False, msg ++ ok_val = conf.get("ok_val") ++ if val == ok_val: ++ msg = "pre check success, ok_val: %s, get value: %s" % (ok_val, val) ++ return True, msg ++ msg = "pre check failed, ok_val: %s, get value: %s" % (ok_val, val) ++ return False, msg ++ ++ def do_test(self, device, slot): ++ try: ++ # slot present check ++ slot_name = "slot%d" % slot ++ slot_config = self.upgrade_param.get(slot_name, {}) ++ slot_present_config = slot_config.get("present", {}) ++ if len(slot_present_config) != 0: ++ ret, log = self.linecard_present_check(slot_present_config) ++ if ret != CHECK_OK: ++ msg = "check %s present error, msg: %s" % (slot_name, log) ++ upgradedebuglog(msg) ++ return ret, msg ++ upgradedebuglog("%s present" % slot_name) ++ ++ # get list of devices to be tested ++ test_config = slot_config.get("TEST", {}) ++ if len(test_config) == 0: ++ return ERR_FW_CONFIG_FOUND, "test config no found" ++ device_list = test_config.get(device, []) ++ if len(device_list) == 0: ++ return ERR_FW_CONFIG_FOUND, ("logic device %s test config list not found" % device) ++ ++ # test_file existence check ++ for test_config in device_list: ++ chain_num = test_config.get("chain", None) ++ test_file = test_config.get("file", None) ++ display_name = test_config.get("display_name", None) ++ if chain_num is None or test_file is None or display_name is None: ++ log = "test_config:%s lack of config" % test_config ++ upgradeerror(log) ++ return ERR_FW_CONFIG_FOUND, log ++ if not os.path.isfile(test_file): ++ return ERR_FW_FILE_FOUND, ("%s not found" % test_file) ++ ++ # start testing ++ RET = 0 ++ pre_check_failed = 0 ++ pre_check_failed_summary = "" ++ failed_summary = "chain test failed.\ntest fail chain:" ++ success_summary = "test success chain:" ++ for test_config in device_list: ++ chain_num = test_config.get("chain", None) ++ test_file = test_config.get("file", None) ++ display_name = test_config.get("display_name", None) ++ pre_check_conf = test_config.get("pre_check", None) ++ if pre_check_conf is not None: ++ status, msg = self.do_pre_check(pre_check_conf) ++ if status is False: ++ pre_check_failed += 1 ++ log = "\nchain:%d, name:%s, pre check failed, msg: %s" % (chain_num, display_name, msg) ++ upgradedebuglog(log) ++ pre_check_failed_summary += log ++ continue ++ upgradedebuglog("chain:%d, name:%s, pre check ok, msg: %s" % (chain_num, display_name, msg)) ++ ret, log = self.do_upgrade(test_file, slot, TEST_UPGRADE) ++ if ret != FIRMWARE_SUCCESS: ++ RET = -1 ++ upgradeerror("chain:%d, name:%s test failed" % (chain_num, display_name)) ++ failed_summary += "\n chain:%d, name:%s;" % (chain_num, display_name) ++ else: ++ upgradedebuglog("chain:%d, name:%s test success" % (chain_num, display_name)) ++ success_summary += "\n chain:%d, name:%s;" % (chain_num, display_name) ++ if RET != 0: ++ return ERR_FW_UPGRADE, failed_summary ++ if pre_check_failed == len(device_list): ++ return ERR_FW_NO_FILE_SUCCESS, failed_summary + pre_check_failed_summary ++ return FIRMWARE_SUCCESS, success_summary ++ except Exception as e: ++ return ERR_FW_RAISE_EXCEPTION, str(e) ++ ++ def do_test_main(self, device, slot): ++ print("+================================+") ++ print("|Doing upgrade test, please wait.|") ++ ret, log = self.do_test(device, slot) ++ if ret == FIRMWARE_SUCCESS: ++ print("| test succeeded! |") ++ print("+================================+") ++ print(log) ++ sys.exit(0) ++ else: ++ print("| test failed! |") ++ print("+================================+") ++ print("FAILED REASON:") ++ print(log) ++ sys.exit(1) ++ ++ def do_bmc_upgrade_main(self, file, chip_select, erase_type): ++ bmc_upgrade_config = self.upgrade_param.get("BMC", {}) ++ ret, log = self.upgrading(bmc_upgrade_config, file, self.devtype, ++ self.subtype, chip_select, BMC_UPGRADE, erase_type) ++ if ret is True: ++ print("===========upgrade succeeded!============") ++ sys.exit(0) ++ else: ++ print("============upgrade failed!==============") ++ print("FAILED REASON:") ++ print("%s" % log) ++ sys.exit(1) ++ ++ ++class FileUpg(object): ++ def __init__(self, config, file, devtype, subtype, slot, filetype, chain, upg_type): ++ self.config = config ++ self.file = file ++ self.devtype = devtype ++ self.subtype = subtype ++ self.slot = slot ++ self.filetype = filetype ++ self.chain = chain ++ self.upg_type = upg_type ++ ++ def __repr__(self): ++ return "file:%s slot:%d" % (self.file, self.slot) ++ ++ ++class FwUpg(object): ++ def __init__(self): ++ self.upg_platform = BasePlatform() ++ self.warm_upg_platform = WarmBasePlatform() ++ self.max_slot_num = self.upg_platform.max_slot_num ++ self.file_list = [] ++ ++ def do_file_refresh(self, fw_upg_instance): ++ fw_upg_config = fw_upg_instance.config ++ fw_upg_file = fw_upg_instance.file ++ fw_upg_devtype = fw_upg_instance.devtype ++ fw_upg_subype = fw_upg_instance.subtype ++ fw_upg_slot = fw_upg_instance.slot ++ fw_upg_filetype = fw_upg_instance.filetype ++ fw_upg_chain = fw_upg_instance.chain ++ dev_name = fw_upg_config.get("name", None) ++ upgradedebuglog("%s start warm upgrade, file: %s, devtype:0x%x, subype: 0x%x, slot: %d, filetype: %s, chain: %d" % ++ (dev_name, fw_upg_file, fw_upg_devtype, fw_upg_subype, fw_upg_slot, fw_upg_filetype, fw_upg_chain)) ++ status, output = self.warm_upg_platform.do_warmupgrade(fw_upg_file, fw_upg_devtype, fw_upg_subype, fw_upg_slot, ++ fw_upg_filetype, fw_upg_chain) ++ if status is False: ++ upgradeerror("%s warm upgrade failed, msg: %s" % (dev_name, output)) ++ return False, output ++ upgradedebuglog("%s warm upgrade success" % dev_name) ++ return True, "upgrade success" ++ ++ def do_refresh(self): ++ try: ++ exec_os_cmd("touch %s" % WARM_UPGRADE_STARTED_FLAG) ++ exec_os_cmd("sync") ++ ++ # stop upper layer services access ++ ret, log = self.warm_upg_platform.stop_services_access() ++ if ret is False: ++ upgradeerror("stop upper layer services access failed") ++ upgradeerror(log) ++ return ERR_FW_UPGRADE, log ++ upgradedebuglog("stop upper layer services access success") ++ ++ for file_instance in self.file_list: ++ file_info = repr(file_instance) ++ ret, log = self.do_file_refresh(file_instance) ++ if ret is False: ++ msg = "%s refresh failed, ret:%s, \n log:%s." % (file_info, ret, log) ++ upgradeerror(msg) ++ return ERR_FW_UPGRADE, msg ++ upgradedebuglog("%s refresh success." % file_info) ++ msg = "all files refresh success." ++ return FIRMWARE_SUCCESS, msg ++ except Exception as e: ++ msg = "do warm upg exception happend. log:%s" % str(e) ++ upgradeerror(msg) ++ return ERR_FW_UPGRADE, msg ++ finally: ++ self.warm_upg_platform.start_services_access() ++ if os.path.isfile(WARM_UPGRADE_STARTED_FLAG): ++ exec_os_cmd("rm -rf %s" % WARM_UPGRADE_STARTED_FLAG) ++ exec_os_cmd("sync") ++ ++ def do_file_cold_upg(self, fw_upg_instance): ++ try: ++ upgradedebuglog("start cold upgrade") ++ fw_upg_config = fw_upg_instance.config ++ fw_upg_file = fw_upg_instance.file ++ fw_upg_devtype = fw_upg_instance.devtype ++ fw_upg_subype = fw_upg_instance.subtype ++ fw_upg_slot = fw_upg_instance.slot ++ ret, log = self.upg_platform.upgrading( ++ fw_upg_config, fw_upg_file, fw_upg_devtype, fw_upg_subype, fw_upg_slot, COLD_UPGRADE) ++ if ret is False: ++ upgradeerror("cold upgrade %s slot%d failed, log:%s" % (fw_upg_file, fw_upg_slot, log)) ++ return ERR_FW_UPGRADE, log ++ log = "cold upgrade %s slot%d success" % (fw_upg_file, fw_upg_slot) ++ upgradedebuglog(log) ++ return FIRMWARE_SUCCESS, log ++ except Exception as e: ++ msg = "do cold upg exception happend. log:%s" % str(e) ++ upgradeerror(msg) ++ return ERR_FW_UPGRADE, msg ++ ++ def do_file_init_check(self, file_path, slot, upg_type): ++ upgradedebuglog("do_file_init_check, file_path: %s, slot: %s, upg_type: %s" % (file_path, slot, upg_type)) ++ ++ if slot is None: # traverse all slots ++ for i in range(0, self.max_slot_num + 1): ++ ret, log = self.upg_platform.initial_check(file_path, i, upg_type) ++ if ret != CHECK_OK: ++ upgradedebuglog( ++ "file: %s, slot%d initial check not ok, ret: %d, msg: %s" % ++ (file_path, i, ret, log)) ++ accept_error = (ERR_FW_CARD_ABSENT, ERR_FW_HEAD_CHECK, ERR_FW_FOOL_PROOF) ++ if ret in accept_error: ++ msg = "file: %s, slot%d initial check ret: %d, acceptable error." % (file_path, i, ret) ++ upgradedebuglog(msg) ++ continue ++ return ret, log ++ file_instance = FileUpg(self.upg_platform.cold_chain_config, file_path, self.upg_platform.devtype, ++ self.upg_platform.subtype, i, self.upg_platform.filetype, self.upg_platform.chain, upg_type) ++ self.file_list.append(file_instance) ++ else: ++ slot = int(slot, 10) ++ ret, log = self.upg_platform.initial_check(file_path, slot, upg_type) ++ if ret != CHECK_OK: ++ msg = "file: %s, slot%d initial check not ok, ret: %d, msg: %s" % (file_path, slot, ret, log) ++ return ret, msg ++ file_instance = FileUpg(self.upg_platform.cold_chain_config, file_path, self.upg_platform.devtype, ++ self.upg_platform.subtype, slot, self.upg_platform.filetype, self.upg_platform.chain, upg_type) ++ self.file_list.append(file_instance) ++ msg = "file: %s all slots init check ok" % file_path ++ return CHECK_OK, msg ++ ++ def do_dir_init_check(self, path, slot, upg_type): ++ for root, dirs, names in os.walk(path): ++ # root: directory absolute path ++ # dirs: folder path collection under directory ++ # names: file path collection under directory ++ for filename in names: ++ # file_path is file absolute path ++ file_path = os.path.join(root, filename) ++ ret, log = self.do_file_init_check(file_path, slot, upg_type) ++ if ret != CHECK_OK: ++ return ret, log ++ msg = "all files in dir have been check ok" ++ upgradedebuglog(msg) ++ return CHECK_OK, msg ++ ++ def do_fw_upg(self, path, slot, upg_type): ++ match_zip_file_flag = False ++ try: ++ upgradedebuglog("do_fw_upg, path: %s, slot: %s, upg_type: %s" % (path, slot, upg_type)) ++ if slot is not None and not slot.isdigit(): ++ msg = "invalid slot param: %s" % slot ++ upgradeerror(msg) ++ return ERR_FW_INVALID_PARAM, msg ++ ++ upgradedebuglog("start init check") ++ if os.path.isfile(path) and path.endswith(".zip"): ++ upgradedebuglog("firmware upgrade via compressed package: %s" % path) ++ # remove origin firmware upgrade file ++ exec_os_cmd("rm -rf %s" % UPGRADE_FILE_DIR) ++ cmd = "unzip -o %s -d /tmp/" % path ++ if os.path.exists(UPGRADE_DEBUG_FILE): ++ status, output = exec_os_cmd_log(cmd) ++ else: ++ status, output = exec_os_cmd(cmd) ++ if status: ++ msg = "unzip %s failed, log: %s" % (path, output) ++ upgradeerror(msg) ++ return ERR_FW_UNZIP_FAILED, msg ++ match_zip_file_flag = True ++ path = UPGRADE_FILE_DIR ++ ++ if os.path.isdir(path): ++ ret, msg = self.do_dir_init_check(path, slot, upg_type) ++ elif os.path.isfile(path): ++ ret, msg = self.do_file_init_check(path, slot, upg_type) ++ else: ++ ret = ERR_FW_FILE_FOUND ++ msg = "path: %s not found" % path ++ upgradeerror(msg) ++ ++ if ret != CHECK_OK: ++ return ret, msg ++ ++ # self.file_list is a collection of all check ok files ++ if len(self.file_list) == 0: ++ msg = "all file upgrade check not be satisfied." ++ upgradeerror(msg) ++ return ERR_FW_NO_FILE_SUCCESS, msg ++ ++ SUCCUSS_FILE_SUMMARY = "SUCCESS FILE: \n" ++ # file cold upgrade ++ upgradedebuglog("start all files cold upgrade") ++ for file_instance in self.file_list: ++ file_info = repr(file_instance) ++ ret, log = self.do_file_cold_upg(file_instance) ++ if ret != FIRMWARE_SUCCESS: ++ msg = "%s cold upgrade failed, ret:%d, \n log:\n%s." % (file_info, ret, log) ++ upgradeerror(msg) ++ return ret, msg ++ SUCCUSS_FILE_SUMMARY += "%s \n" % file_info ++ upgradedebuglog("%s cold upgrade success." % file_info) ++ ++ # file refresh upgrade ++ if upg_type == WARM_UPGRADE: ++ upgradedebuglog("start all files refresh upgrade") ++ ret, log = self.do_refresh() ++ if ret != FIRMWARE_SUCCESS: ++ return ret, log ++ ++ msg = "all file upgrade success" ++ upgradedebuglog(msg) ++ return FIRMWARE_SUCCESS, SUCCUSS_FILE_SUMMARY ++ except Exception as e: ++ msg = "do dir upgrade exception happend. log: %s" % str(e) ++ upgradeerror(msg) ++ return ERR_FW_UPGRADE, msg ++ finally: ++ if match_zip_file_flag is True: ++ exec_os_cmd("rm -rf %s" % UPGRADE_FILE_DIR) ++ ++ def fw_upg(self, path, slot, upg_type): ++ print("+================================+") ++ print("| Doing upgrade, please wait... |") ++ ret, log = self.do_fw_upg(path, slot, upg_type) ++ if ret == FIRMWARE_SUCCESS: ++ print("| upgrade succeeded! |") ++ print("+================================+") ++ print(log) ++ sys.exit(0) ++ else: ++ print("| upgrade failed! |") ++ print("+================================+") ++ print("FAILED REASON:") ++ print("%s" % log) ++ sys.exit(1) ++ ++ ++@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) ++def main(): ++ '''upgrade script''' ++ ++ ++# cold upgrade ++@main.command() ++@click.argument('file_name', required=True) ++@click.argument('slot_num', required=False, default=None) ++def cold(file_name, slot_num): ++ '''cold upgrade''' ++ fwupg = FwUpg() ++ fwupg.fw_upg(file_name, slot_num, COLD_UPGRADE) ++ ++ ++# warm upgrade ++@main.command() ++@click.argument('file_name', required=True) ++@click.argument('slot_num', required=False, default=None) ++def warm(file_name, slot_num): ++ '''warm upgrade''' ++ fwupg = FwUpg() ++ fwupg.fw_upg(file_name, slot_num, WARM_UPGRADE) ++ ++ ++# test upgrade ++@main.command() ++@click.argument('device', required=True) ++@click.argument('slot_num', required=True) ++def test(device, slot_num): ++ '''upgrade test''' ++ platform = BasePlatform() ++ platform.do_test_main(device, int(slot_num)) ++ ++ ++# BMC upgrade ++@main.command() ++@click.argument('file_name', required=True) ++@click.argument('chip_select', required=False, default="2") ++@click.argument('erase_type', required=False, default="full") ++def bmc(file_name, chip_select, erase_type): ++ '''BMC upgrade''' ++ platform = BasePlatform() ++ platform.do_bmc_upgrade_main(file_name, chip_select, erase_type) ++ ++ ++if __name__ == '__main__': ++ signal_init() ++ debug_init() ++ main() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/warm_upgrade.py b/platform/broadcom/sonic-platform-modules-micas/common/script/warm_upgrade.py +new file mode 100755 +index 000000000..69a310faa +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/script/warm_upgrade.py +@@ -0,0 +1,514 @@ ++#!/usr/bin/env python3 ++# -*- coding: UTF-8 -*- ++import sys ++import os ++import time ++import syslog ++import signal ++import click ++from platform_util import get_value, set_value, exec_os_cmd, exec_os_cmd_log ++from platform_config import WARM_UPGRADE_PARAM ++ ++ ++WARM_UPGRADE_DEBUG_FILE = "/etc/.warm_upgrade_debug_flag" ++ ++WARMUPGRADEDEBUG = 1 ++ ++debuglevel = 0 ++ ++CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} ++ ++ ++class AliasedGroup(click.Group): ++ ++ def get_command(self, ctx, cmd_name): ++ rv = click.Group.get_command(self, ctx, cmd_name) ++ if rv is not None: ++ return rv ++ matches = [x for x in self.list_commands(ctx) ++ if x.startswith(cmd_name)] ++ if not matches: ++ return None ++ if len(matches) == 1: ++ return click.Group.get_command(self, ctx, matches[0]) ++ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) ++ return None ++ ++ ++def debug_init(): ++ global debuglevel ++ if os.path.exists(WARM_UPGRADE_DEBUG_FILE): ++ debuglevel = debuglevel | WARMUPGRADEDEBUG ++ else: ++ debuglevel = debuglevel & ~(WARMUPGRADEDEBUG) ++ ++ ++def warmupgradewarninglog(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("WARMUPGRADE", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_WARNING, s) ++ ++ ++def warmupgradecriticallog(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("WARMUPGRADE", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_CRIT, s) ++ ++ ++def warmupgradeerror(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ syslog.openlog("WARMUPGRADE", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_ERR, s) ++ ++ ++def warmupgradedebuglog(s): ++ # s = s.decode('utf-8').encode('gb2312') ++ if WARMUPGRADEDEBUG & debuglevel: ++ syslog.openlog("WARMUPGRADE", syslog.LOG_PID) ++ syslog.syslog(syslog.LOG_DEBUG, s) ++ ++ ++def subprocess_warm_upgrade(file, main_type, sub_type, slot): ++ command = "firmware_upgrade %s 0x%x 0x%x %s" % (file, main_type, sub_type, slot) ++ warmupgradedebuglog("warm upgrade firmware cmd:%s" % command) ++ if os.path.exists(WARM_UPGRADE_DEBUG_FILE): ++ return exec_os_cmd_log(command) ++ return exec_os_cmd(command) ++ ++ ++def signal_init(): ++ signal.signal(signal.SIGINT, signal.SIG_IGN) # ignore ctrl+c signal ++ signal.signal(signal.SIGTERM, signal.SIG_IGN) # ignore kill signal ++ signal.signal(signal.SIGTSTP, signal.SIG_IGN) # ignore ctrl+z signal ++ ++ ++class RefreshUpgradeBase(object): ++ ++ def __init__(self, config, slot_num, devtype, subtype): ++ self._config = config ++ self._slot_num = slot_num ++ self._devtype = devtype ++ self._subtype = subtype ++ self.device_name = self._config.get("name", None) ++ self.refresh_file = self._config.get("refresh_file", None) ++ self.init_cmd_list = self._config.get("init_cmd", []) ++ self.save_set_reg_list = self._config.get("save_set_reg", []) ++ self.rw_recover_reg_list = self._config.get("rw_recover_reg", []) ++ self.after_upgrade_delay = self._config.get("after_upgrade_delay", None) ++ self.after_upgrade_delay_timeout = self._config.get("after_upgrade_delay_timeout", None) ++ self.refresh_finish_flag_check_config = self._config.get("refresh_finish_flag_check", None) ++ self.access_check_reg_config = self._config.get("access_check_reg", {}) ++ self.time_delay = 0 ++ self.finish_cmd_list = self._config.get("finish_cmd", []) ++ ++ def get_config(self): ++ pass ++ ++ def get_slot_num(self): ++ pass ++ ++ def save_value(self, cfg_list): ++ for config in cfg_list: ++ ret, val = get_value(config) ++ if ret: ++ config["value"] = val ++ else: ++ warmupgradeerror(val) ++ return False, val ++ return True, "save value success" ++ ++ def save_and_set_value(self, cfg_list): ++ for config in cfg_list: ++ ret, val = get_value(config) ++ if ret: ++ config["save_value"] = val ++ else: ++ warmupgradeerror(val) ++ return False, "get save value fail" ++ set_val = config.get("set_value", None) ++ if set_val is not None: ++ config["value"] = set_val ++ else: ++ warmupgradeerror("save_and_set_value lack of set_val config") ++ return False, "set value is not config" ++ ret, log = set_value(config) ++ if ret is False: ++ warmupgradeerror(log) ++ return False, log ++ return True, "save value success" ++ ++ def recover_value(self, cfg_list): ++ fail_flag = 0 ++ for config in cfg_list: ++ ret, log = set_value(config) ++ if ret is False: ++ fail_flag = -1 ++ warmupgradeerror("recover_value set_value failed, log: %s" % log) ++ if fail_flag != 0: ++ warmupgradeerror("recover_value write failed") ++ return False, "recover write failed" ++ return True, "recover write success" ++ ++ def recover_save_value(self, cfg_list): ++ total_err = 0 ++ for config in cfg_list: ++ val = config.get("save_value", None) ++ if val is None: ++ warmupgradeerror("recover_save_value lack of save_value config") ++ total_err -= 1 ++ continue ++ config["value"] = val ++ ret, log = set_value(config) ++ if ret is False: ++ total_err -= 1 ++ warmupgradeerror("recover save value write failed, log: %s" % log) ++ else: ++ warmupgradedebuglog("recover save value success") ++ if total_err < 0: ++ return False, "recover save value failed" ++ return True, "recover save value success" ++ ++ def do_fw_upg_init_cmd(self, init_cmd_list): ++ # pre operation ++ try: ++ for init_cmd_config in init_cmd_list: ++ ret, log = set_value(init_cmd_config) ++ if ret is False: ++ warmupgradeerror("%s do init cmd: %s failed, msg: %s" % (self.device_name, init_cmd_config, log)) ++ return False, log ++ msg = "%s warm upgrade init cmd all set success" % self.device_name ++ warmupgradedebuglog(msg) ++ return True, msg ++ except Exception as e: ++ return False, str(e) ++ ++ def do_fw_upg_finish_cmd(self, finish_cmd_list): ++ # end operation ++ total_err = 0 ++ for finish_cmd_config in finish_cmd_list: ++ ret_t, log = set_value(finish_cmd_config) ++ if ret_t is False: ++ warmupgradeerror("%s do finish cmd: %s failed, msg: %s" % (self.device_name, finish_cmd_config, log)) ++ total_err -= 1 ++ if total_err < 0: ++ msg = "%s warm upgrade finish cmd exec failed" % self.device_name ++ warmupgradeerror(msg) ++ return False, msg ++ msg = "%s warm upgrade finish cmd all set success" % self.device_name ++ warmupgradedebuglog(msg) ++ return True, msg ++ ++ def access_test(self, config): ++ # polling execute command ++ polling_cmd_list = config.get("polling_cmd", []) ++ for polling_cmd_config in polling_cmd_list: ++ ret, log = set_value(polling_cmd_config) ++ if ret is False: ++ warmupgradeerror(log) ++ return False ++ polling_delay = config.get("polling_delay", None) ++ if polling_delay is not None: ++ time.sleep(polling_delay) ++ ++ # record check val ++ check_val = config.get("value", None) ++ # write value ++ ret, log = set_value(config) ++ if ret is False: ++ warmupgradeerror(log) ++ return False ++ # read value ++ ret, val = get_value(config) ++ if ret is False: ++ warmupgradeerror(val) ++ return False ++ ++ # compare write and read val ++ warmupgradedebuglog("check_val:%s" % check_val) ++ warmupgradedebuglog("get_value:%s" % val) ++ if val != check_val: ++ warmupgradeerror("check_val:%s != get_value:%s" % (check_val, val)) ++ return False ++ return True ++ ++ def check_value(self, config): ++ # record check val ++ check_val = config.get("value", None) ++ ret, val = get_value(config) ++ if ret is False: ++ warmupgradeerror(val) ++ return False ++ # compare write and read val ++ warmupgradedebuglog("check_val:%s" % check_val) ++ warmupgradedebuglog("get_value:%s" % val) ++ if val != check_val: ++ warmupgradeerror("check_val:%s != get_value:%s" % (check_val, val)) ++ return False ++ return True ++ ++ def refresh_file_upgrade(self): ++ try: ++ warmupgradedebuglog("start %s warm upgrading" % self.device_name) ++ ++ # save and set reg ++ ret, log = self.save_and_set_value(self.save_set_reg_list) ++ if ret is False: ++ warmupgradeerror(log) ++ self.recover_save_value(self.save_set_reg_list) ++ self.do_fw_upg_finish_cmd(self.finish_cmd_list) ++ return False, log ++ warmupgradedebuglog("%s save and set reg cmd all set success" % self.device_name) ++ time.sleep(0.5) # delay 0.5s after execute save and set reg ++ ++ # pre operation ++ ret, log = self.do_fw_upg_init_cmd(self.init_cmd_list) ++ if ret is False: ++ warmupgradeerror(log) ++ self.recover_save_value(self.save_set_reg_list) ++ self.do_fw_upg_finish_cmd(self.finish_cmd_list) ++ return False, log ++ time.sleep(0.5) # delay 0.5s after execute init_cmd ++ ++ # save reg ++ ret, log = self.save_value(self.rw_recover_reg_list) ++ if ret is False: ++ warmupgradeerror("%s save reg failed" % self.device_name) ++ self.recover_save_value(self.save_set_reg_list) ++ self.do_fw_upg_finish_cmd(self.finish_cmd_list) ++ return False, log ++ warmupgradedebuglog("%s all reg save success" % self.device_name) ++ ++ # upgrade refresh file ++ if self.refresh_file is not None: ++ status, output = subprocess_warm_upgrade( ++ self.refresh_file, self._devtype, self._subtype, self._slot_num) ++ if status: ++ log = "%s refresh file upg failed, msg: %s" % (self.device_name, output) ++ warmupgradeerror(log) ++ self.recover_save_value(self.save_set_reg_list) ++ self.do_fw_upg_finish_cmd(self.finish_cmd_list) ++ return False, log ++ warmupgradedebuglog("%s refresh file upg success" % self.device_name) ++ ++ # delay the preset time after the upgrade is complete ++ if self.after_upgrade_delay is not None: ++ time.sleep(self.after_upgrade_delay) ++ ++ # check something in the timeout period ++ if self.after_upgrade_delay_timeout is not None: ++ while self.time_delay < self.after_upgrade_delay_timeout: ++ ++ # check refresh finish flag ++ if self.refresh_finish_flag_check_config is not None: ++ ret = self.check_value(self.refresh_finish_flag_check_config) ++ if ret is False: ++ time.sleep(1) ++ self.time_delay = self.time_delay + 1 ++ warmupgradedebuglog("doing refresh_finish_flag_check, time_delay:%s" % self.time_delay) ++ continue ++ warmupgradedebuglog("%s upgrade_finish_flag_check success. self.time_delay:%d" ++ % (self.device_name, self.time_delay)) ++ ++ # doing logic device rw access test ++ ret = self.access_test(self.access_check_reg_config) ++ if ret: ++ warmupgradedebuglog( ++ "%s rw test success. self.time_delay:%d" % ++ (self.device_name, self.time_delay)) ++ break ++ time.sleep(1) ++ self.time_delay = self.time_delay + 1 ++ warmupgradedebuglog("doing access_test, self.time_delay:%s" % self.time_delay) ++ ++ if self.time_delay >= self.after_upgrade_delay_timeout: ++ log = "wait %s access test timeout" % self.device_name ++ warmupgradeerror(log) ++ self.recover_save_value(self.save_set_reg_list) ++ self.do_fw_upg_finish_cmd(self.finish_cmd_list) ++ return False, log ++ warmupgradedebuglog("%s access test success" % self.device_name) ++ ++ # recover reg ++ ret, log = self.recover_value(self.rw_recover_reg_list) ++ if ret is False: ++ warmupgradeerror("recover %s reg failed" % self.device_name) ++ self.recover_save_value(self.save_set_reg_list) ++ self.do_fw_upg_finish_cmd(self.finish_cmd_list) ++ return False, log ++ warmupgradedebuglog("recover %s reg success" % self.device_name) ++ # finally ++ ret1, log1 = self.recover_save_value(self.save_set_reg_list) ++ if ret1 is False: ++ warmupgradeerror("bmc upgrade recover save value failed, msg: %s" % log1) ++ ret2, log2 = self.do_fw_upg_finish_cmd(self.finish_cmd_list) ++ if ret2 is False: ++ warmupgradeerror("bmc upgrade do finish command failed, msg: %s" % log2) ++ if ret1 is False or ret2 is False: ++ return False, "upgrading %s recover save value or finish command failed" % self.device_name ++ return True, "upgrading %s success" % self.device_name ++ ++ except Exception as e: ++ log = "refresh file upgrade Exception happend, error log : %s" % str(e) ++ self.recover_save_value(self.save_set_reg_list) ++ self.do_fw_upg_finish_cmd(self.finish_cmd_list) ++ return False, log ++ ++ ++class RefreshUpgrade(RefreshUpgradeBase): ++ ++ def __init__(self, config, slot_num, devtype, subtype): ++ super(RefreshUpgrade, self).__init__(config, slot_num, devtype, subtype) ++ ++ def get_config(self): ++ super(RefreshUpgrade, self).get_config() ++ return self._config ++ ++ def get_slot_num(self): ++ super(RefreshUpgrade, self).get_slot_num() ++ return self._slot_num ++ ++ ++class WarmBasePlatform(): ++ ++ def __init__(self): ++ signal_init() ++ debug_init() ++ self.warm_upgrade_param = WARM_UPGRADE_PARAM.copy() ++ self.stop_services_cmd_list = self.warm_upgrade_param.get("stop_services_cmd", []) ++ self.start_services_cmd_list = self.warm_upgrade_param.get("start_services_cmd", []) ++ self.__warm_upgrade_config_list = [] ++ ++ def execute_command_list(self, cmd_list): ++ for cmd_item in cmd_list: ++ warmupgradedebuglog("execute cmd: %s" % cmd_item) ++ status, output = exec_os_cmd(cmd_item) ++ if status: ++ log = "execute %s failed, msg: %s" % (cmd_item, output) ++ warmupgradeerror(log) ++ return False, log ++ return True, "execute success" ++ ++ def stop_services_access(self): ++ return self.execute_command_list(self.stop_services_cmd_list) ++ ++ def start_services_access(self): ++ return self.execute_command_list(self.start_services_cmd_list) ++ ++ def check_slot_present(self, slot_present_config): ++ totalerr = 0 ++ presentbit = slot_present_config.get('presentbit') ++ ret, value = get_value(slot_present_config) ++ if ret is False: ++ return "NOT OK" ++ if isinstance(value, str): ++ val_t = int(value, 16) ++ else: ++ val_t = value ++ val_t = (val_t & (1 << presentbit)) >> presentbit ++ if val_t != slot_present_config.get('okval'): ++ status = "ABSENT" ++ else: ++ status = "PRESENT" ++ return status ++ ++ def linecard_present_check(self, slot_name, slot_present_config): ++ present_status = self.check_slot_present(slot_present_config) ++ present_status_tuple = ("ABSENT", "NOT OK") ++ if present_status in present_status_tuple: ++ return False, ("%s not present, warm upgrade exit" % slot_name) ++ warmupgradedebuglog("%s present" % slot_name) ++ return True, ("%s present" % slot_name) ++ ++ def start_warmupgrade(self): ++ try: ++ # start refresh file upgrade process ++ for dev in self.__warm_upgrade_config_list: ++ ret, log = dev.refresh_file_upgrade() ++ if ret is False: ++ return ret, log ++ return True, "all success" ++ except Exception as e: ++ log = "Exception happend, error log : %s" % str(e) ++ return False, log ++ ++ def do_warmupgrade(self, file, main_type, sub_type, slot, file_type, chain): ++ try: ++ # upgrade file existence check ++ if not os.path.isfile(file): ++ return False, "%s not found" % file ++ ++ # get slot config ++ slot_name = "slot%d" % slot ++ slot_config = self.warm_upgrade_param.get(slot_name, {}) ++ if len(slot_config) == 0: ++ return False, ("%s config not found" % slot_name) ++ ++ # linecard present check ++ slot_present_config = slot_config.get("present", {}) ++ if len(slot_present_config) != 0: ++ ret, log = self.linecard_present_check(slot_name, slot_present_config) ++ if ret is False: ++ return False, log ++ ++ # match file_type and chain_num get chain_config ++ file_type_config = slot_config.get(file_type, {}) ++ chain_name = "chain%d" % chain ++ chain_list = file_type_config.get(chain_name, []) ++ self.__warm_upgrade_config_list = [] ++ for refresh_config in chain_list: ++ # refresh_file existence check ++ refresh_file_judge_flag = refresh_config.get("refresh_file_judge_flag", 0) ++ if refresh_file_judge_flag == 1: ++ refresh_file = refresh_config.get("refresh_file", None) ++ if not os.path.isfile(refresh_file): ++ log = "%s not found" % refresh_file ++ return False, log ++ # each refresh_config add as an instance of RefreshUpgrade Class ++ refresh_instance = RefreshUpgrade(refresh_config, slot, main_type, sub_type) ++ self.__warm_upgrade_config_list.append(refresh_instance) ++ ++ ret, log = self.start_warmupgrade() ++ if ret is False: ++ warmupgradeerror("doing warm upgrade failed") ++ warmupgradeerror(log) ++ return ret, log ++ ++ except Exception as e: ++ log = "Exception happend, error log : %s" % str(e) ++ return False, log ++ return True, "all success" ++ ++ def do_warm_upgrade(self, file, main_type, sub_type, slot, file_type, chain): ++ print("+================================+") ++ print("|Begin warm upgrade, please wait..|") ++ ret, log = self.do_warmupgrade(file, main_type, sub_type, slot, file_type, chain) ++ if ret: ++ print("| warm upgrade succeeded! |") ++ print("+================================+") ++ sys.exit(0) ++ else: ++ print("| warm upgrade failed! |") ++ print("+================================+") ++ print("FAILED REASON:") ++ print("%s" % log) ++ sys.exit(1) ++ ++ ++@click.group(invoke_without_command=True, context_settings=CONTEXT_SETTINGS) ++@click.argument('file', required=True) ++@click.argument('main_type', required=True) ++@click.argument('sub_type', required=True) ++@click.argument('slot', required=True) ++@click.argument('file_type', required=True) ++@click.argument('chain', required=True) ++def main(file, main_type, sub_type, slot, file_type, chain): ++ '''warm upgrade''' ++ signal_init() ++ debug_init() ++ platform = WarmBasePlatform() ++ platform.do_warm_upgrade(file, int(main_type, 16), int(sub_type, 16), int(slot), file_type, int(chain)) ++ ++ ++# warm upgrade ++if __name__ == '__main__': ++ main() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/service/platform_driver.service b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_driver.service +new file mode 100644 +index 000000000..08a49d695 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_driver.service +@@ -0,0 +1,15 @@ ++[Unit] ++Description= Global Initialize platform drivers. ++After=local-fs.target ++Before=pmon.service platform_process.service ++#DefaultDependencies=no ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/local/bin/platform_driver.py start ++ExecStop=/usr/local/bin/platform_driver.py stop ++RemainAfterExit=yes ++ ++[Install] ++WantedBy=multi-user.target ++ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/service/platform_process.service b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_process.service +new file mode 100644 +index 000000000..13dd77855 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_process.service +@@ -0,0 +1,16 @@ ++[Unit] ++Description= Global Load process. ++After=platform_driver.service ++Before=determine-reboot-cause.service pmon.service ++Requires=platform_driver.service ++#DefaultDependencies=no ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/local/bin/platform_process.py start ++ExecStop=/usr/local/bin/platform_process.py stop ++RemainAfterExit=yes ++ ++[Install] ++WantedBy=multi-user.target ++ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/__init__.py +new file mode 100644 +index 000000000..b70995a58 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/__init__.py +@@ -0,0 +1,2 @@ ++__all__ = ["platform", "chassis", "sfp", "eeprom", "component", "thermal", "psu", "fan", "fan_drawer", "watchdog"] ++from . import platform +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/chassis.py +new file mode 100644 +index 000000000..b0ddc8691 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/chassis.py +@@ -0,0 +1,530 @@ ++#!/usr/bin/env python3 ++ ++############################################################################# ++# ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the platform information ++# ++############################################################################# ++ ++try: ++ import time ++ import sys ++ from sonic_platform_base.chassis_base import ChassisBase ++ from sonic_platform.sfp import Sfp ++ from sonic_platform.psu import Psu ++ # from sonic_platform.fan import Fan ++ from sonic_platform.fan_drawer import FanDrawer ++ from sonic_platform.thermal import Thermal ++ # from sonic_platform.watchdog import Watchdog ++ from sonic_platform.component import Component ++ from sonic_platform.eeprom import Eeprom ++ from sonic_platform.dcdc import Dcdc ++ from plat_hal.baseutil import baseutil ++ ++ from plat_hal.interface import interface ++ ++except ImportError as error: ++ raise ImportError(str(error) + "- required module not found")from error ++ ++ ++class Chassis(ChassisBase): ++ """ ++ Platform-specific Chassis class ++ """ ++ # List of Dcdc objects representing all dcdc ++ # available on the chassis ++ _dcdc_list = None ++ ++ STATUS_INSERTED = "1" ++ STATUS_REMOVED = "0" ++ STATUS_NORMAL = "0" ++ STATUS_ABNORMAL = "1" ++ sfp_present_dict = {} ++ fan_present_dict = {} ++ voltage_status_dict = {} ++ ++ def __init__(self): ++ ChassisBase.__init__(self) ++ self._dcdc_list = [] ++ self.int_case = interface() ++ # Initialize SFP list ++ ++ # sfp.py will read eeprom contents and retrive the eeprom data. ++ # It will also provide support sfp controls like reset and setting ++ # low power mode. ++ # We pass the eeprom path and sfp control path from chassis.py ++ # So that sfp.py implementation can be generic to all platforms ++ try: ++ self._sfp_list = [] ++ self.port_num = baseutil.get_config().get("sfps", None).get("port_num", 0) ++ self.port_start_index = baseutil.get_config().get("sfps", None).get("port_index_start", 0) ++ # fix problem with first index is 1, we add a fake sfp node ++ if self.port_start_index == 1: ++ self._sfp_list.append(Sfp(1)) ++ ++ # sfp id always start at 1 ++ for index in range(1, self.port_num + 1): ++ self._sfp_list.append(Sfp(index)) ++ ++ for i in range(self.port_start_index, self.port_start_index + self.port_num): ++ self.sfp_present_dict[i] = self.STATUS_REMOVED ++ ++ except Exception as err: ++ print("SFP init error: %s" % str(err)) ++ ++ try: ++ self._eeprom = Eeprom(self.int_case) ++ except Exception as err: ++ print("EEPROM INIT ERROR %s" % str(err)) ++ ++ # Initialize watchdog ++ # self._watchdog = Watchdog() ++ fantray_num = self.int_case.get_fan_total_number() ++ for index in range(fantray_num): ++ fandrawer = FanDrawer(self.int_case, index + 1) ++ self._fan_drawer_list.append(fandrawer) ++ self._fan_list.extend(fandrawer._fan_list) ++ ++ psu_num = self.int_case.get_psu_total_number() ++ for index in range(psu_num): ++ psuobj = Psu(self.int_case, index + 1) ++ self._psu_list.append(psuobj) ++ ++ thermal_num = self.int_case.get_temp_id_number() ++ for index in range(thermal_num): ++ thermalobj = Thermal(self.int_case, index + 1) ++ self._thermal_list.append(thermalobj) ++ ++ component_num = self.int_case.get_cpld_total_number() ++ for index in range(component_num): ++ componentobj = Component(self.int_case, index + 1) ++ self._component_list.append(componentobj) ++ ++ dcdc_num = self.int_case.get_dcdc_total_number() ++ for index in range(dcdc_num): ++ dcdcobj = Dcdc(self.int_case, index + 1) ++ self._dcdc_list.append(dcdcobj) ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the chassis ++ Returns: ++ string: The name of the chassis ++ """ ++ name = '' ++ sys_eeprom = self.get_eeprom() ++ if sys_eeprom is None: ++ return '' ++ ++ e = sys_eeprom.read_eeprom() ++ name = sys_eeprom.modelstr(e) ++ if name is None: ++ return '' ++ return name ++ ++ 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 ++ """ ++ model = '' ++ sys_eeprom = self.get_eeprom() ++ if sys_eeprom is None: ++ return '' ++ ++ e = sys_eeprom.read_eeprom() ++ model = sys_eeprom.modelnumber(e) ++ if model is None: ++ return '' ++ return model ++ ++ def get_serial_number(self): ++ """ ++ Retrieves the hardware serial number for the chassis ++ ++ Returns: ++ A string containing the hardware serial number for this chassis. ++ """ ++ serial_number = '' ++ sys_eeprom = self.get_eeprom() ++ if sys_eeprom is None: ++ return '' ++ ++ e = sys_eeprom.read_eeprom() ++ serial_number = sys_eeprom.serial_number_str(e) ++ if serial_number is None: ++ return '' ++ ++ return serial_number ++ ++ def get_revision(self): ++ """ ++ Retrieves the hardware revision of the device ++ ++ Returns: ++ string: Revision value of device ++ """ ++ device_version = '' ++ sys_eeprom = self.get_eeprom() ++ if sys_eeprom is None: ++ return '' ++ ++ e = sys_eeprom.read_eeprom() ++ device_version = sys_eeprom.deviceversion(e) ++ if device_version is None: ++ return '' ++ ++ return device_version ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the chassis (Service tag) ++ Returns: ++ string: Serial number of chassis ++ """ ++ return self.get_serial_number() ++ ++ 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_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 initizalize_system_led(self): ++ return True ++ ++ def set_status_led(self, color): ++ return False ++ ++ 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. ++ """ ++ ret, color = self.int_case.get_led_color_by_type('SYS_LED') ++ if ret is True: ++ return color ++ return 'N/A' ++ ++ 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' ++ """ ++ base_mac = '' ++ sys_eeprom = self.get_eeprom() ++ if sys_eeprom is None: ++ return '' ++ ++ e = sys_eeprom.read_eeprom() ++ base_mac = sys_eeprom.base_mac_addr(e) ++ if base_mac is None: ++ return '' ++ ++ return base_mac.upper() ++ ++ 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. ++ Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', ++ '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', ++ '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} ++ """ ++ sys_eeprom = self.get_eeprom() ++ if sys_eeprom is None: ++ return {} ++ return sys_eeprom.system_eeprom_info() ++ ++ def get_thermal_manager(self): ++ """ ++ Retrieves thermal manager class on this chassis ++ :return: A class derived from ThermalManagerBase representing the ++ specified thermal manager. ThermalManagerBase is returned as default ++ """ ++ return False ++ ++ 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. ++ """ ++ reboot_cause_msg = self.int_case.get_cpu_reboot_cause() ++ if "Power Loss" in reboot_cause_msg: ++ reboot_cause_type = self.REBOOT_CAUSE_POWER_LOSS ++ elif "Watchdog" in reboot_cause_msg: ++ reboot_cause_type = self.REBOOT_CAUSE_WATCHDOG ++ elif "BMC reboot" in reboot_cause_msg or "BMC powerdown" in reboot_cause_msg: ++ reboot_cause_type = self.REBOOT_CAUSE_HARDWARE_OTHER ++ elif "Thermal Overload: ASIC" in reboot_cause_msg: ++ reboot_cause_type = self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC ++ elif "Thermal Overload: Other" in reboot_cause_msg: ++ reboot_cause_type = self.REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER ++ elif "Other" in reboot_cause_msg: ++ reboot_cause_type = self.REBOOT_CAUSE_NON_HARDWARE ++ else: ++ reboot_cause_type = self.REBOOT_CAUSE_NON_HARDWARE ++ return (reboot_cause_type, reboot_cause_msg) ++ ++ def get_module(self, index): ++ """ ++ Retrieves module represented by (0-based) index ++ ++ Args: ++ index: An integer, the index (0-based) of the module to ++ retrieve ++ ++ Returns: ++ An object dervied from ModuleBase representing the specified ++ module ++ """ ++ module = None ++ ++ try: ++ if self.get_num_modules(): ++ module = self._module_list[index] ++ except IndexError: ++ sys.stderr.write("Module index {} out of range (0-{})\n".format( ++ index, len(self._module_list) - 1)) ++ ++ return module ++ ++ def get_fan_drawer(self, index): ++ """ ++ Retrieves fan drawers represented by (0-based) index ++ ++ Args: ++ index: An integer, the index (0-based) of the fan drawer to ++ retrieve ++ ++ Returns: ++ An object dervied from FanDrawerBase representing the specified fan ++ drawer ++ """ ++ fan_drawer = None ++ ++ try: ++ if self.get_num_fan_drawers(): ++ fan_drawer = self._fan_drawer_list[index] ++ except IndexError: ++ sys.stderr.write("Fan drawer index {} out of range (0-{})\n".format( ++ index, len(self._fan_drawer_list) - 1)) ++ ++ return fan_drawer ++ ++ 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): ++ - bool: True if call successful, False if not; ++ - dict: 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. ++ The known devices's device_id and device_event was defined as table below. ++ ----------------------------------------------------------------- ++ device | device_id | device_event | annotate ++ ----------------------------------------------------------------- ++ 'fan' '' '0' Fan removed ++ '1' Fan inserted ++ ++ 'sfp' '' '0' Sfp removed ++ '1' Sfp inserted ++ '2' I2C bus stuck ++ '3' Bad eeprom ++ '4' Unsupported cable ++ '5' High Temperature ++ '6' Bad cable ++ ++ 'voltage' '' '0' Vout normal ++ '1' Vout abnormal ++ -------------------------------------------------------------------- ++ Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0', '12':'1'}, ++ 'voltage':{'U20':'0', 'U21':'1'}} ++ Indicates that: ++ fan 0 has been removed, fan 2 has been inserted. ++ sfp 11 has been removed, sfp 12 has been inserted. ++ monitored voltage U20 became normal, voltage U21 became abnormal. ++ Note: For sfp, when event 3-6 happened, the module will not be avalaible, ++ XCVRD shall stop to read eeprom before SFP recovered from error status. ++ """ ++ ++ change_event_dict = {"fan": {}, "sfp": {}, "voltage": {}} ++ ++ start_time = time.time() ++ forever = False ++ ++ if timeout == 0: ++ forever = True ++ elif timeout > 0: ++ timeout = timeout / float(1000) # Convert to secs ++ else: ++ print("get_change_event:Invalid timeout value: %s" % timeout) ++ return False, change_event_dict ++ ++ end_time = start_time + timeout ++ if start_time > end_time: ++ print("get_change_event:time wrap / invalid timeout value: %s" % timeout) ++ return False, change_event_dict # Time wrap or possibly incorrect timeout ++ try: ++ while timeout >= 0: ++ # check for sfp ++ sfp_change_dict = self.get_transceiver_change_event() ++ # check for fan ++ fan_change_dict = self.get_fan_change_event() ++ # check for voltage ++ voltage_change_dict = self.get_voltage_change_event() ++ ++ if sfp_change_dict or fan_change_dict or voltage_change_dict: ++ change_event_dict["sfp"] = sfp_change_dict ++ change_event_dict["fan"] = fan_change_dict ++ change_event_dict["voltage"] = voltage_change_dict ++ return True, change_event_dict ++ 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, change_event_dict ++ except Exception as e: ++ print(e) ++ print("get_change_event: Should not reach here.") ++ return False, change_event_dict ++ ++ def get_transceiver_change_event(self): ++ current_sfp_present_dict = {} ++ ret_dict = {} ++ ++ # Check for OIR events and return ret_dict ++ for i in range(self.port_start_index, self.port_start_index + self.port_num): ++ sfp = self._sfp_list[i] ++ if sfp.get_presence(): ++ current_sfp_present_dict[i] = self.STATUS_INSERTED ++ ++ else: ++ current_sfp_present_dict[i] = self.STATUS_REMOVED ++ ++ # Update reg value ++ if current_sfp_present_dict == self.sfp_present_dict: ++ return ret_dict ++ ++ for index, status in current_sfp_present_dict.items(): ++ if self.sfp_present_dict[index] != status: ++ ret_dict[index] = status ++ ++ self.sfp_present_dict = current_sfp_present_dict ++ ++ return ret_dict ++ ++ def get_fan_change_event(self): ++ current_fan_present_dict = {} ++ ret_dict = {} ++ ++ # Check for OIR events and return ret_dict ++ for index, fan in enumerate(self._fan_list): ++ if fan.get_presence() is True: ++ current_fan_present_dict[index] = self.STATUS_INSERTED ++ else: ++ current_fan_present_dict[index] = self.STATUS_REMOVED ++ ++ if len(self.fan_present_dict) == 0: # first time ++ self.fan_present_dict = current_fan_present_dict ++ return {} ++ ++ if current_fan_present_dict == self.fan_present_dict: ++ return {} ++ ++ # updated fan_present_dict ++ for index, status in current_fan_present_dict.items(): ++ if self.fan_present_dict[index] != status: ++ ret_dict[str(index)] = status ++ self.fan_present_dict = current_fan_present_dict ++ return ret_dict ++ ++ def get_voltage_change_event(self): ++ current_voltage_status_dict = {} ++ ret_dict = {} ++ ++ # Check for OIR events and return ret_dict ++ for index, dcdc in enumerate(self._dcdc_list): ++ name = dcdc.get_name() ++ value = dcdc.get_value() ++ high = dcdc.get_high_threshold() ++ low = dcdc.get_low_threshold() ++ if (value is None) or (value > high) or (value < low): ++ current_voltage_status_dict[name] = self.STATUS_ABNORMAL ++ else: ++ current_voltage_status_dict[name] = self.STATUS_NORMAL ++ ++ if len(self.voltage_status_dict) == 0: # first time ++ self.voltage_status_dict = current_voltage_status_dict ++ return {} ++ ++ if current_voltage_status_dict == self.voltage_status_dict: ++ return {} ++ ++ # updated voltage_status_dict ++ for name, status in current_voltage_status_dict.items(): ++ if self.voltage_status_dict[name] != status: ++ ret_dict[name] = status ++ self.voltage_status_dict = current_voltage_status_dict ++ return ret_dict ++ ++ +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/component.py +new file mode 100644 +index 000000000..fa674a98a +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/component.py +@@ -0,0 +1,226 @@ ++#!/usr/bin/env python3 ++ ++######################################################################## ++# ++# 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 time ++ import subprocess ++ import os ++ from sonic_platform_base.component_base import ComponentBase ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") from e ++ ++ ++FIRMWARE_UPDATE_DIR = "/tmp/.firmwareupdate/" ++ ++class Component(ComponentBase): ++ """Platform-specific Component class""" ++ ++ def __init__(self, interface_obj, index): ++ self.cpld_dict = {} ++ self.int_case = interface_obj ++ self.index = index ++ self.update_time = 0 ++ self.cpld_id = "CPLD" + str(index) ++ ++ def cpld_dict_update(self): ++ local_time = time.time() ++ if not self.cpld_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds ++ self.update_time = local_time ++ self.cpld_dict = self.int_case.get_cpld_version_by_id(self.cpld_id) ++ ++ def get_slot(self): ++ self.cpld_dict_update() ++ return self.cpld_dict["Slot"] ++ ++ def get_warm_upgrade_flag(self): ++ self.cpld_dict_update() ++ return self.cpld_dict["Warm"] ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the component ++ ++ Returns: ++ A string containing the name of the component ++ """ ++ self.cpld_dict_update() ++ return self.cpld_dict["Name"] ++ ++ def get_description(self): ++ """ ++ Retrieves the description of the component ++ ++ Returns: ++ A string containing the description of the component ++ """ ++ self.cpld_dict_update() ++ return self.cpld_dict["Desc"] ++ ++ def get_firmware_version(self): ++ """ ++ Retrieves the firmware version of the component ++ ++ Note: the firmware version will be read from HW ++ ++ Returns: ++ A string containing the firmware version of the component ++ """ ++ self.cpld_dict_update() ++ return self.cpld_dict["Version"] ++ ++ 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 ++ """ ++ raise NotImplementedError ++ ++ def get_firmware_update_notification(self, image_path): ++ """ ++ Retrieves a notification on what should be done in order to complete ++ the component firmware update ++ ++ Args: ++ image_path: A string, path to firmware image ++ ++ Returns: ++ A string containing the component firmware update notification if required. ++ By default 'None' value will be used, which indicates that no actions are required ++ """ ++ return None ++ ++ def install_firmware(self, image_path): ++ """ ++ Installs firmware to the component ++ ++ This API performs firmware installation only: this may/may not be the same as firmware update. ++ 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 must be done manually by user ++ ++ Note: in case immediate actions are required to complete the component firmware update ++ (e.g., reboot, power cycle, etc.) - will be done automatically by API and no return value provided ++ ++ Args: ++ image_path: A string, path to firmware image ++ ++ Returns: ++ A boolean, True if install was successful, False if not ++ """ ++ if not os.path.isfile(image_path): ++ print("ERROR: %s not found" % image_path) ++ return False ++ cmdstr = "upgrade.py cold %s %d" % (image_path, self.get_slot()) ++ status, output = subprocess.getstatusoutput(cmdstr) ++ if status == 0: ++ print("INFO: %s firmware install succeeded" % self.get_name()) ++ return True ++ print("%s install failed. status:%d, output:\n%s" % (self.get_name(), status, output)) ++ return False ++ ++ 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 ++ """ ++ if not os.path.isfile(image_path): ++ raise RuntimeError("ERROR: %s not found" % image_path) ++ ++ if self.get_warm_upgrade_flag() == 1: # use warm upgrade ++ cmdstr = "upgrade.py warm %s %d" % (image_path, self.get_slot()) ++ else: ++ cmdstr = "upgrade.py cold %s %d" % (image_path, self.get_slot()) ++ status, output = subprocess.getstatusoutput(cmdstr) ++ if status == 0: ++ if self.get_warm_upgrade_flag() != 1: # not support warm upgrade, need to cold reboot ++ print("INFO: %s firmware install succeeded" % self.get_name()) ++ print("INFO: please cold reboot to make the %s firmware up-to-date" % self.get_name()) ++ else: ++ print("INFO: %s firmware update succeeded" % self.get_name()) ++ print("INFO: %s firmware version up-to-date" % self.get_name()) ++ return None ++ raise RuntimeError(output) ++ ++ def auto_update_firmware(self, image_path, boot_type): ++ """ ++ Updates firmware of the component ++ ++ This API performs firmware update automatically based on boot_type: it assumes firmware installation ++ and/or creating a loading task during the reboot, if needed, 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 during the reboot. ++ The loading task will be created by API. ++ ++ Args: ++ image_path: A string, path to firmware image ++ boot_type: A string, reboot type following the upgrade ++ - none/fast/warm/cold ++ ++ Returns: ++ Output: A return code ++ return_code: An integer number, status of component firmware auto-update ++ - return code of a positive number indicates successful auto-update ++ - status_installed = 1 ++ - status_updated = 2 ++ - status_scheduled = 3 ++ - return_code of a negative number indicates failed auto-update ++ - status_err_boot_type = -1 ++ - status_err_image = -2 ++ - status_err_unknown = -3 ++ ++ Raises: ++ RuntimeError: auto-update failure cause ++ """ ++ if not os.path.isfile(image_path): ++ print("ERROR: %s not found" % image_path) ++ return -2 ++ ++ if not os.path.isdir(FIRMWARE_UPDATE_DIR): ++ os.mkdir(FIRMWARE_UPDATE_DIR) ++ ++ warm_upgrade_flag = self.get_warm_upgrade_flag() ++ file_name = os.path.basename(image_path) ++ file_path = os.path.join(FIRMWARE_UPDATE_DIR, file_name) ++ if os.path.exists(file_path): # firmware already update ++ if warm_upgrade_flag == 1: ++ print("INFO: %s firmware update succeeded, firmware version up-to-date" % self.get_name()) ++ return 2 ++ print("INFO: %s firmware install succeeded, please cold reboot to make it up-to-date" % self.get_name()) ++ return 1 ++ ++ if warm_upgrade_flag == 1: # use warm upgrade ++ cmdstr = "upgrade.py warm %s %d" % (image_path, self.get_slot()) ++ else: ++ cmdstr = "upgrade.py cold %s %d" % (image_path, self.get_slot()) ++ status, output = subprocess.getstatusoutput(cmdstr) ++ if status == 0: ++ os.mknod(file_path) ++ if warm_upgrade_flag == 1: ++ print("INFO: %s firmware update succeeded, firmware version up-to-date" % self.get_name()) ++ return 2 ++ print("INFO: %s firmware install succeeded, please cold reboot to make it up-to-date" % self.get_name()) ++ return 1 ++ print("%s update failed, status:%d, output:\n%s" % (self.get_name(), status, output)) ++ return -3 +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/dcdc.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/dcdc.py +new file mode 100644 +index 000000000..494d4aa61 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/dcdc.py +@@ -0,0 +1,85 @@ ++#!/usr/bin/env python3 ++ ++######################################################################## ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the Thermals' information which are available in the platform ++# ++######################################################################## ++import time ++ ++ ++class Dcdc(object): ++ ++ def __init__(self, interface_obj, index): ++ self.dcdc_dict = {} ++ self.int_case = interface_obj ++ self.index = index ++ self.update_time = 0 ++ self.dcdc_id = "DCDC" + str(index) ++ ++ def dcdc_dict_update(self): ++ local_time = time.time() ++ if not self.dcdc_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds ++ self.update_time = local_time ++ self.dcdc_dict = self.int_case.get_dcdc_by_id(self.dcdc_id) ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the sensor ++ ++ Returns: ++ string: The name of the sensor ++ """ ++ self.dcdc_dict_update() ++ return self.dcdc_dict["Name"] ++ ++ def get_value(self): ++ """ ++ Retrieves current value reading from sensor ++ """ ++ self.dcdc_dict_update() ++ value = self.dcdc_dict["Value"] ++ if value is None: ++ value = 0 ++ return round(float(value), 3) ++ ++ def get_high_threshold(self): ++ """ ++ Retrieves the high threshold temperature of sensor ++ """ ++ self.dcdc_dict_update() ++ value = self.dcdc_dict["High"] ++ if value is None: ++ value = 0 ++ return round(float(value), 3) ++ ++ def get_low_threshold(self): ++ """ ++ Retrieves the low threshold temperature of sensor ++ """ ++ self.dcdc_dict_update() ++ value = self.dcdc_dict["Low"] ++ if value is None: ++ value = 0 ++ return round(float(value), 3) ++ ++ def get_high_critical_threshold(self): ++ """ ++ Retrieves the high critical threshold temperature of sensor ++ """ ++ self.dcdc_dict_update() ++ value = self.dcdc_dict["Max"] ++ if value is None: ++ value = 0 ++ return round(float(value), 3) ++ ++ def get_low_critical_threshold(self): ++ """ ++ Retrieves the low critical threshold temperature of sensor ++ """ ++ self.dcdc_dict_update() ++ value = self.dcdc_dict["Min"] ++ if value is None: ++ value = 0 ++ return round(float(value), 3) +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/eeprom.py +new file mode 100644 +index 000000000..05fcc3c25 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/eeprom.py +@@ -0,0 +1,92 @@ ++#!/usr/bin/env python3 ++######################################################################## ++# ++# 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. ++# - PSU EEPROM : Contains Serial number, Part number, Service Tag, ++# PSU type, Revision. ++# - Fan EEPROM : Contains Serial number, Part number, Service Tag, ++# Fan type, Number of Fans in Fantray, Revision. ++######################################################################## ++ ++try: ++ from sonic_eeprom import eeprom_tlvinfo ++except ImportError as error: ++ raise ImportError(str(error) + "- required module not found") from error ++ ++ ++class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): ++ ++ def __init__(self, interface_obj): ++ self.int_case = interface_obj ++ self.name = "ONIE_E2" ++ ++ eeprom_path = self.int_case.get_onie_e2_path(self.name) ++ if eeprom_path is None: ++ raise ValueError("get eeprom path failed") ++ ++ super().__init__(eeprom_path, 0, "", True) ++ ++ def modelnumber(self, e): ++ ''' ++ Returns the value field of the model(part) number TLV as a string ++ ''' ++ (is_valid, t) = self.get_tlv_field(e, self._TLV_CODE_PART_NUMBER) ++ if not is_valid: ++ return super().part_number_str(e) ++ ++ return t[2].decode("ascii") ++ ++ def deviceversion(self, e): ++ ''' ++ Returns the value field of the Device Version as a string ++ ''' ++ (is_valid, t) = self.get_tlv_field(e, self._TLV_CODE_DEVICE_VERSION) ++ if not is_valid: ++ return "N/A" ++ ++ return str(ord(t[2])) ++ ++ def 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. ++ Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', ++ '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', ++ '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} ++ ''' ++ sys_eeprom_dict = {} ++ e = self.read_eeprom() ++ if self._TLV_HDR_ENABLED: ++ if not self.is_valid_tlvinfo_header(e): ++ return {} ++ total_len = (e[9] << 8) | e[10] ++ tlv_index = self._TLV_INFO_HDR_LEN ++ tlv_end = self._TLV_INFO_HDR_LEN + total_len ++ else: ++ tlv_index = self.eeprom_start ++ tlv_end = self._TLV_INFO_MAX_LEN ++ ++ while (tlv_index + 2) < len(e) and tlv_index < tlv_end: ++ if not self.is_valid_tlv(e[tlv_index:]): ++ break ++ ++ tlv = e[tlv_index:tlv_index + 2 + e[tlv_index + 1]] ++ code = "0x%02X" % tlv[0] ++ name, value = self.decoder(None, tlv) ++ sys_eeprom_dict[code] = value ++ ++ if e[tlv_index] == self._TLV_CODE_QUANTA_CRC or \ ++ e[tlv_index] == self._TLV_CODE_CRC_32: ++ break ++ tlv_index += e[tlv_index + 1] + 2 ++ ++ return sys_eeprom_dict +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan.py +new file mode 100644 +index 000000000..be1c8ce8f +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan.py +@@ -0,0 +1,314 @@ ++#!/usr/bin/env python3 ++######################################################################## ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the Fans' information which are available in the platform. ++# ++######################################################################## ++ ++try: ++ import time ++ from sonic_platform_base.fan_base import FanBase ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") from e ++ ++ ++class Fan(FanBase): ++ """Platform-specific Fan class""" ++ ++ def __init__(self, interface_obj, fantray_index, fan_index, psu_fan=False, psu_index=0): ++ self.fan_dict = {} ++ self.int_case = interface_obj ++ self.fantray_index = fantray_index ++ self.fan_index = fan_index ++ self.psu_index = psu_index ++ self.is_psu_fan = psu_fan ++ self.update_time = 0 ++ if not self.is_psu_fan: ++ self.name = "FAN" + str(fantray_index) ++ else: ++ self.name = "PSU" + str(psu_index) ++ ++ def fan_dict_update(self): ++ local_time = time.time() ++ if not self.fan_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds ++ self.update_time = local_time ++ if not self.is_psu_fan: ++ self.fan_dict = self.int_case.get_fan_info(self.name) ++ else: ++ self.fan_dict = self.int_case.get_psu_fru_info(self.name) ++ ++ def get_name(self): ++ """ ++ Retrieves the fan name ++ Returns: ++ string: The name of the device ++ """ ++ if not self.is_psu_fan: ++ return "Fantray{}_{}".format(self.fantray_index, self.fan_index) ++ return "PSU{}_FAN{}".format(self.psu_index, self.fan_index) ++ ++ def get_model(self): ++ """ ++ Retrieves the part number of the FAN ++ Returns: ++ string: Part number of FAN ++ """ ++ if not self.is_psu_fan: ++ self.fan_dict_update() ++ return self.fan_dict["DisplayName"] ++ return 'N/A' ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the FAN ++ Returns: ++ string: Serial number of FAN ++ """ ++ if not self.is_psu_fan: ++ self.fan_dict_update() ++ return self.fan_dict["SN"] ++ return 'N/A' ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the FAN ++ Returns: ++ bool: True if fan is present, False if not ++ """ ++ if not self.is_psu_fan: ++ return self.int_case.get_fan_presence(self.name) ++ return self.int_case.get_psu_presence(self.name) ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the FAN ++ Returns: ++ bool: True if FAN is operating properly, False if not ++ """ ++ if not self.get_presence(): ++ return False ++ ++ if not self.is_psu_fan: ++ fan_dir = {} ++ fan_dir = self.int_case.get_fan_info_rotor(self.name) ++ # get fan rotor pwm ++ rotor_name = "Rotor" + str(self.fan_index) ++ value = fan_dir[rotor_name]["Speed"] ++ min_speed = fan_dir[rotor_name]["SpeedMin"] ++ max_speed = fan_dir[rotor_name]["SpeedMax"] ++ tolerance = fan_dir[rotor_name]["Tolerance"] ++ else: ++ psu_status_dict = self.int_case.get_psu_status(self.name) ++ value = psu_status_dict["FanSpeed"]["Value"] ++ min_speed = psu_status_dict["FanSpeed"]["Min"] ++ max_speed = psu_status_dict["FanSpeed"]["Max"] ++ tolerance = psu_status_dict["FanSpeed"]["Tolerance"] ++ ++ if isinstance(tolerance, str) or tolerance is None: ++ tolerance = 30 ++ ++ if isinstance(value, str) or value is None: ++ if self.is_psu_fan: ++ psu_status_dict = self.int_case.get_psu_status(self.name) ++ if psu_status_dict["OutputStatus"] is True: ++ return True ++ return False ++ ++ if value < min_speed: ++ return False ++ ++ speed = int(value * 100 / max_speed) ++ if speed > 100: ++ speed = 100 ++ elif speed < 0: ++ speed = 0 ++ target = self.get_target_speed() ++ ++ if (speed - target) > target * tolerance / 100: ++ return False ++ if (target - speed) > target * tolerance / 100: ++ return False ++ ++ return True ++ ++ 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 True ++ ++ def get_direction(self): ++ """ ++ Retrieves the fan airflow direction ++ Returns: ++ A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST ++ depending on fan direction ++ ++ Notes: ++ - Forward/Exhaust : Air flows from Port side to Fan side. ++ - Reverse/Intake : Air flows from Fan side to Port side. ++ """ ++ self.fan_dict_update() ++ air_flow = self.fan_dict["AirFlow"] ++ if air_flow is not None: ++ return air_flow ++ return self.FAN_DIRECTION_NOT_APPLICABLE ++ ++ def get_speed(self): ++ """ ++ Retrieves the speed of fan as a percentage of full speed ++ ++ Returns: ++ An integer, the percentage of full fan speed, in the range 0 (off) ++ to 100 (full speed) ++ """ ++ if not self.get_presence(): ++ return 0 ++ ++ if not self.is_psu_fan: ++ fan_dir = {} ++ fan_dir = self.int_case.get_fan_info_rotor(self.name) ++ # get fan rotor pwm ++ rotor_name = "Rotor" + str(self.fan_index) ++ value = fan_dir[rotor_name]["Speed"] ++ max_speed = fan_dir[rotor_name]["SpeedMax"] ++ else: ++ psu_status_dict = self.int_case.get_psu_status(self.name) ++ value = psu_status_dict["FanSpeed"]["Value"] ++ max_speed = psu_status_dict["FanSpeed"]["Max"] ++ ++ if isinstance(value, str) or value is None: ++ return None ++ pwm = value * 100 / max_speed ++ if pwm > 100: ++ pwm = 100 ++ elif pwm < 0: ++ pwm = 0 ++ return int(pwm) ++ ++ 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 ++ """ ++ # The default tolerance value is fixed as 30% ++ if not self.is_psu_fan: ++ fan_dir = {} ++ fan_dir = self.int_case.get_fan_info_rotor(self.name) ++ # get fan rotor tolerance ++ rotor_name = "Rotor" + str(self.fan_index) ++ tolerance = fan_dir[rotor_name]["Tolerance"] ++ else: ++ psu_status_dict = self.int_case.get_psu_status(self.name) ++ tolerance = psu_status_dict["FanSpeed"]["Tolerance"] ++ ++ if isinstance(tolerance, str) or tolerance is None: ++ return 30 ++ return tolerance ++ ++ def fan_set_speed_pwm(self, pwm): ++ status = self.int_case.set_fan_speed_pwm(self.name, self.fan_index, pwm) ++ if status == -1: ++ return False ++ return True ++ ++ 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 not self.is_psu_fan: ++ return self.fan_set_speed_pwm(speed) ++ return self.int_case.set_psu_fan_speed_pwm(self.name, int(speed)) ++ ++ 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. ++ """ ++ # not supported ++ 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 self.is_psu_fan: ++ # No LED available for PSU Fan ++ return 'N/A' ++ ++ if not self.get_presence(): ++ return 'N/A' ++ ++ ret, color = self.int_case.get_fan_led(self.name) ++ if ret is True: ++ return color ++ 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) ++ """ ++ if not self.is_psu_fan: ++ # get fan rotor pwm ++ pwm = int(self.int_case.get_fan_speed_pwm(self.name, self.fan_index)) ++ else: ++ psu_status_dict = self.int_case.get_psu_status(self.name) ++ if psu_status_dict["InputStatus"] is False: ++ pwm = 0 ++ else: ++ pwm = self.get_speed() # target equal to real pwm, to avoid alarm ++ if pwm is None: ++ return None ++ return int(pwm) ++ ++ def get_vendor(self): ++ """ ++ Retrieves the vendor name of the fan ++ ++ Returns: ++ string: Vendor name of fan ++ """ ++ if not self.is_psu_fan: ++ return "WB" ++ return 'N/A' ++ ++ def get_revision(self): ++ """ ++ Retrieves the hardware revision of the device ++ ++ Returns: ++ string: Revision value of device ++ """ ++ if not self.is_psu_fan: ++ self.fan_dict_update() ++ return self.fan_dict["HW"] ++ return 'N/A' +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan_drawer.py +new file mode 100644 +index 000000000..f0b039648 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan_drawer.py +@@ -0,0 +1,167 @@ ++#!/usr/bin/env python3 ++# ++# fan_drawer_base.py ++# ++# Abstract base class for implementing a platform-specific class with which ++# to interact with a fan drawer module in SONiC ++# ++ ++try: ++ import time ++ from sonic_platform_base.fan_drawer_base import FanDrawerBase ++ from sonic_platform.fan import Fan ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") from e ++ ++ ++class FanDrawer(FanDrawerBase): ++ """ ++ Abstract base class for interfacing with a fan drawer ++ """ ++ # Device type definition. Note, this is a constant. ++ DEVICE_TYPE = "fan_drawer" ++ ++ def __init__(self, interface_obj, fantray_index): ++ FanDrawerBase.__init__(self) ++ self.fantray_dict = {} ++ self.fantray_update_time = 0 ++ self.fantray_index = fantray_index ++ self.int_case = interface_obj ++ self.fantrayname = "FAN" + str(fantray_index) ++ self.num_fans_per_fantray = self.int_case.get_fan_rotor_number(self.fantrayname) ++ for i in range(self.num_fans_per_fantray): ++ self._fan_list.append(Fan(interface_obj, fantray_index, i + 1)) ++ ++ def fantray_dict_update(self): ++ local_time = time.time() ++ # update data every 1 seconds ++ if not self.fantray_dict or (local_time - self.fantray_update_time) >= 1: ++ self.fantray_update_time = local_time ++ self.fantray_dict = self.int_case.get_fan_info(self.fantrayname) ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the device ++ Returns: ++ string: The name of the device ++ """ ++ return "Fantray{}".format(self.fantray_index) ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the FAN ++ Returns: ++ bool: True if fan is present, False if not ++ """ ++ return self.int_case.get_fan_presence(self.fantrayname) ++ ++ def get_model(self): ++ """ ++ Retrieves the part number of the FAN ++ Returns: ++ string: Part number of FAN ++ """ ++ self.fantray_dict_update() ++ return self.fantray_dict["NAME"] ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the FAN ++ Returns: ++ string: Serial number of FAN ++ """ ++ self.fantray_dict_update() ++ return self.fantray_dict["SN"] ++ ++ def get_revision(self): ++ """ ++ Retrieves the hardware revision of the device ++ ++ Returns: ++ string: Revision value of device ++ """ ++ self.fantray_dict_update() ++ return self.fantray_dict["HW"] ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the FAN ++ Returns: ++ bool: True if FAN is operating properly, False if not ++ """ ++ for i in range(self.num_fans_per_fantray): ++ if self._fan_list[i].get_status() is False: ++ return False ++ return True ++ ++ 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 True ++ ++ def get_num_fans(self): ++ """ ++ Retrieves the number of fans available on this fan drawer ++ Returns: ++ An integer, the number of fan modules available on this fan drawer ++ """ ++ return len(self._fan_list) ++ ++ def get_all_fans(self): ++ """ ++ Retrieves all fan modules available on this fan drawer ++ Returns: ++ A list of objects derived from FanBase representing all fan ++ modules available on this fan drawer ++ """ ++ return self._fan_list ++ ++ 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 ++ """ ++ # not supported ++ 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' ++ ++ ret, color = self.int_case.get_fan_led(self.fantrayname) ++ if ret is True: ++ return color ++ return 'N/A' ++ ++ def get_maximum_consumed_power(self): ++ """ ++ Retrives the maximum power drawn by Fan Drawer ++ ++ Returns: ++ A float, with value of the maximum consumable power of the ++ component. ++ """ ++ self.fantray_dict_update() ++ return self.fantray_dict["PowerMax"] +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/pcie.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/pcie.py +new file mode 100644 +index 000000000..8ea66f339 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/pcie.py +@@ -0,0 +1,21 @@ ++#!/usr/bin/env python3 ++# -*- coding: utf-8 -*- ++ ++######################################################################## ++# ++# Module contains a platform specific implementation of SONiC Platform ++# Base PCIe class ++# ++######################################################################## ++ ++try: ++ from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") from e ++ ++ ++class Pcie(PcieUtil): ++ """Platform-specific Pcie class""" ++ ++ def __init__(self, platform_path): ++ PcieUtil.__init__(self, platform_path) +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/platform.py +new file mode 100644 +index 000000000..4d6fe03d9 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/platform.py +@@ -0,0 +1,24 @@ ++#!/usr/bin/env python3 ++ ++############################################################################# ++# ++# 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): ++ """ ++ Platform-specific class ++ """ ++ ++ def __init__(self): ++ PlatformBase.__init__(self) ++ self._chassis = Chassis() +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/psu.py +new file mode 100644 +index 000000000..2a634ca6b +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/psu.py +@@ -0,0 +1,359 @@ ++#!/usr/bin/env python3 ++######################################################################## ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the PSUs' information which are available in the platform ++# ++######################################################################## ++ ++ ++try: ++ import time ++ from sonic_platform_base.psu_base import PsuBase ++ from sonic_platform.fan import Fan ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") from e ++ ++ ++class Psu(PsuBase): ++ """Platform-specific PSU class""" ++ ++ def __init__(self, interface_obj, index): ++ self.psu_dict = {} ++ self.psu_status_dict = {} ++ self.psu_power_dict = {} ++ self._fan_list = [] ++ self._thermal_list = [] ++ self.int_case = interface_obj ++ self.index = index ++ self.name = "PSU" + str(index) ++ ++ self.psu_dict_update_time = 0 ++ self.psu_status_dict_update_time = 0 ++ self.psu_power_dict_update_time = 0 ++ ++ self._fan_list.append(Fan(self.int_case, 1, 1, psu_fan=True, psu_index=index)) ++ ++ def psu_dict_update(self): ++ local_time = time.time() ++ if not self.psu_dict or (local_time - self.psu_dict_update_time) >= 1: # update data every 1 seconds ++ self.psu_dict_update_time = local_time ++ self.psu_dict = self.int_case.get_psu_fru_info(self.name) ++ ++ def psu_status_dict_update(self): ++ local_time = time.time() ++ if not self.psu_status_dict or ( ++ local_time - self.psu_status_dict_update_time) >= 1: # update data every 1 seconds ++ self.psu_status_dict_update_time = local_time ++ self.psu_status_dict = self.int_case.get_psu_status(self.name) ++ ++ def psu_power_dict_update(self): ++ local_time = time.time() ++ if not self.psu_power_dict or ( ++ local_time - self.psu_power_dict_update_time) >= 1: # update data every 1 seconds ++ self.psu_power_dict_update_time = local_time ++ self.psu_power_dict = self.int_case.get_psu_power_status(self.name) ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the device ++ ++ Returns: ++ string: The name of the device ++ """ ++ return "Psu{}".format(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 ++ """ ++ return self.int_case.get_psu_presence(self.name) ++ ++ def get_model(self): ++ """ ++ Retrieves the part number of the PSU ++ ++ Returns: ++ string: Part number of PSU ++ """ ++ self.psu_dict_update() ++ return self.psu_dict["DisplayName"] ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the PSU ++ ++ Returns: ++ string: Serial number of PSU ++ """ ++ self.psu_dict_update() ++ return self.psu_dict["SN"] ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the PSU ++ ++ Returns: ++ bool: True if PSU is operating properly, False if not ++ """ ++ return self.int_case.get_psu_input_output_status(self.name) ++ ++ 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 True ++ ++ def get_voltage(self): ++ """ ++ Retrieves current PSU voltage output ++ ++ Returns: ++ A float number, the output voltage in volts, ++ e.g. 12.1 ++ """ ++ self.psu_status_dict_update() ++ if self.psu_status_dict["OutputStatus"] is False: ++ value = 0 ++ else: ++ self.psu_power_dict_update() ++ value = self.psu_power_dict["Outputs"]["Voltage"]["Value"] ++ if value is None: ++ return None ++ return round(float(value), 1) ++ ++ def get_current(self): ++ """ ++ Retrieves present electric current supplied by PSU ++ ++ Returns: ++ A float number, electric current in amperes, ++ e.g. 15.4 ++ """ ++ self.psu_status_dict_update() ++ if self.psu_status_dict["OutputStatus"] is False: ++ value = 0 ++ else: ++ self.psu_power_dict_update() ++ value = self.psu_power_dict["Outputs"]["Current"]["Value"] ++ if value is None: ++ return None ++ return round(float(value), 1) ++ ++ def get_power(self): ++ """ ++ Retrieves current energy supplied by PSU ++ ++ Returns: ++ A float number, the power in watts, ++ e.g. 302.6 ++ """ ++ self.psu_status_dict_update() ++ if self.psu_status_dict["OutputStatus"] is False: ++ value = 0 ++ else: ++ self.psu_power_dict_update() ++ value = self.psu_power_dict["Outputs"]["Power"]["Value"] ++ if value is None: ++ return None ++ return round(float(value), 1) ++ ++ 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 self.int_case.get_psu_input_output_status(self.name) ++ ++ 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" ++ if self.int_case.get_psu_input_output_status(self.name): ++ return self.STATUS_LED_COLOR_GREEN ++ return self.STATUS_LED_COLOR_RED ++ ++ 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 ++ """ ++ # not supported ++ return False ++ ++ def get_temperature(self): ++ """ ++ Retrieves current temperature reading from PSU ++ ++ Returns: ++ A float number of current temperature in Celsius up to nearest thousandth ++ of one degree Celsius, e.g. 30.125 ++ """ ++ self.psu_status_dict_update() ++ value = self.psu_status_dict["Temperature"]["Value"] ++ if value is None: ++ return None ++ return round(float(value), 1) ++ ++ def get_temperature_high_threshold(self): ++ """ ++ Retrieves the high threshold temperature of PSU ++ ++ Returns: ++ A float number, the high threshold temperature of PSU in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ self.psu_status_dict_update() ++ value = self.psu_status_dict["Temperature"]["Max"] ++ if value is None: ++ return None ++ return round(float(value), 1) ++ ++ 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 ++ """ ++ self.psu_power_dict_update() ++ value = self.psu_power_dict["Outputs"]["Voltage"]["HighAlarm"] ++ if value is None: ++ return None ++ return round(float(value), 1) ++ ++ 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 ++ """ ++ self.psu_power_dict_update() ++ value = self.psu_power_dict["Outputs"]["Voltage"]["LowAlarm"] ++ if value is None: ++ return None ++ return round(float(value), 1) ++ ++ def get_input_voltage(self): ++ """ ++ Get the input voltage of the PSU ++ ++ Returns: ++ A float number, the input voltage in volts, ++ """ ++ self.psu_status_dict_update() ++ if self.psu_status_dict["InputStatus"] is False: ++ value = 0 ++ else: ++ self.psu_power_dict_update() ++ value = self.psu_power_dict["Inputs"]["Voltage"]["Value"] ++ if value is None: ++ return None ++ return round(float(value), 1) ++ ++ def get_input_current(self): ++ """ ++ Get the input electric current of the PSU ++ ++ Returns: ++ A float number, the input current in amperes, e.g 220.3 ++ """ ++ self.psu_status_dict_update() ++ if self.psu_status_dict["InputStatus"] is False: ++ value = 0 ++ else: ++ self.psu_power_dict_update() ++ value = self.psu_power_dict["Inputs"]["Current"]["Value"] ++ if value is None: ++ return None ++ return round(float(value), 1) ++ ++ def get_input_power(self): ++ """ ++ Get the input current energy of the PSU ++ ++ Returns: ++ A float number, the input power in watts, e.g. 302.6 ++ """ ++ self.psu_status_dict_update() ++ if self.psu_status_dict["InputStatus"] is False: ++ value = 0 ++ else: ++ self.psu_power_dict_update() ++ value = self.psu_power_dict["Inputs"]["Power"]["Value"] ++ if value is None: ++ return None ++ return round(float(value), 1) ++ ++ def get_revision(self): ++ """ ++ Retrieves the hardware revision of the device ++ ++ Returns: ++ string: Revision value of device ++ """ ++ self.psu_dict_update() ++ return self.psu_dict["HW"] ++ ++ def get_vendor(self): ++ """ ++ Retrieves the vendor name of the psu ++ ++ Returns: ++ string: Vendor name of psu ++ """ ++ self.psu_dict_update() ++ return self.psu_dict["VENDOR"] ++ ++ def get_maximum_supplied_power(self): ++ """ ++ Retrieves the maximum supplied power by PSU ++ ++ Returns: ++ A float number, the maximum power output in Watts. ++ e.g. 1200.1 ++ """ ++ return False ++ ++ def get_thermal(self, index): ++ """ ++ Retrieves thermal unit represented by (0-based) index ++ ++ Args: ++ index: An integer, the index (0-based) of the thermal to ++ retrieve ++ ++ Returns: ++ An object dervied from ThermalBase representing the specified thermal ++ """ ++ return False +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/sfp.py +new file mode 100644 +index 000000000..3fc22b4b6 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/sfp.py +@@ -0,0 +1,634 @@ ++#!/usr/bin/python ++# -*- coding: UTF-8 -*- ++ ++############################################################################# ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the platform information ++# ++# ++# *_device.py config version instruction: ++# ver 1.0 - platform api: ++# "presence_cpld": { ++# "dev_id": { ++# [dev_id]: { ++# "offset": { ++# [offset]: [port_id] ++# } ++# } ++# } ++# } ++# "reset_cpld": { ++# "dev_id": { ++# [dev_id]: { ++# "offset": { ++# [offset]: [port_id] ++# } ++# } ++# } ++# } ++# ver 2.0 - wb_plat: ++# "presence_path": "/xx/wb_plat/xx[port_id]/present" ++# "eeprom_path": "/sys/bus/i2c/devices/i2c-[bus]/[bus]-0050/eeprom" ++# "reset_path": "/xx/wb_plat/xx[port_id]/reset" ++############################################################################# ++import sys ++import time ++import syslog ++import traceback ++from abc import abstractmethod ++ ++configfile_pre = "/usr/local/bin/" ++sys.path.append(configfile_pre) ++ ++try: ++ from platform_intf import * ++ from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase ++ from plat_hal.baseutil import baseutil ++ ++except ImportError as error: ++ raise ImportError(str(error) + "- required module not found") from error ++ ++LOG_DEBUG_LEVEL = 1 ++LOG_WARNING_LEVEL = 2 ++LOG_ERROR_LEVEL = 3 ++ ++ ++class Sfp(SfpOptoeBase): ++ ++ OPTOE_DRV_TYPE1 = 1 ++ OPTOE_DRV_TYPE2 = 2 ++ OPTOE_DRV_TYPE3 = 3 ++ ++ # index must start at 1 ++ def __init__(self, index): ++ SfpOptoeBase.__init__(self) ++ self.sfp_type = None ++ sfp_config = baseutil.get_config().get("sfps", None) ++ self.log_level_config = sfp_config.get("log_level", LOG_WARNING_LEVEL) ++ # Init instance of SfpCust ++ ver = sfp_config.get("ver", None) ++ if ver is None: ++ self._sfplog(LOG_ERROR_LEVEL, "Get Ver Config Error!") ++ vers = int(float(ver)) ++ if vers == 1: ++ self._sfp_api = SfpV1(index) ++ elif vers == 2: ++ self._sfp_api = SfpV2(index) ++ else: ++ self._sfplog(LOG_ERROR_LEVEL, "Get SfpVer Error!") ++ ++ def get_eeprom_path(self): ++ return self._sfp_api._get_eeprom_path() ++ ++ def read_eeprom(self, offset, num_bytes): ++ return self._sfp_api.read_eeprom(offset, num_bytes) ++ ++ def get_presence(self): ++ return self._sfp_api.get_presence() ++ ++ def get_transceiver_info(self): ++ # temporary solution for a sonic202111 bug ++ transceiver_info = super().get_transceiver_info() ++ try: ++ if transceiver_info == None: ++ return None ++ if transceiver_info['cable_type'] == None: ++ transceiver_info['cable_type'] = 'N/A' ++ if transceiver_info["vendor_rev"] is not None: ++ transceiver_info["hardware_rev"] = transceiver_info["vendor_rev"] ++ except BaseException: ++ print(traceback.format_exc()) ++ return None ++ return transceiver_info ++ ++ def get_reset_status(self): ++ if self.get_presence() is False: ++ return False ++ ++ if self.sfp_type is None: ++ self.refresh_xcvr_api() ++ ++ if self.sfp_type == 'SFP': ++ self._sfplog(LOG_ERROR_LEVEL, 'SFP does not support reset') ++ return False ++ ++ ret = self._sfp_api.get_reset_status() ++ return ret ++ ++ def reset(self): ++ if self.get_presence() is False: ++ return False ++ ++ if self.sfp_type is None: ++ self.refresh_xcvr_api() ++ ++ if self.sfp_type == 'SFP': ++ self._sfplog(LOG_ERROR_LEVEL, 'SFP does not support reset') ++ return False ++ ++ self._sfplog(LOG_DEBUG_LEVEL, 'resetting...') ++ ret = self._sfp_api.set_reset(True) ++ if ret: ++ time.sleep(0.5) ++ ret = self._sfp_api.set_reset(False) ++ ++ return ret ++ ++ def get_lpmode(self): ++ if self.get_presence() is False: ++ return False ++ ++ if self.sfp_type is None: ++ self.refresh_xcvr_api() ++ ++ if self.sfp_type == 'QSFP' or self.sfp_type == 'QSFP-DD': ++ return SfpOptoeBase.get_lpmode(self) ++ ++ self._sfplog(LOG_WARNING_LEVEL, 'SFP does not support lpmode') ++ return False ++ ++ def set_lpmode(self, lpmode): ++ if self.get_presence() is False: ++ return False ++ ++ if self.sfp_type is None or self._xcvr_api is None: ++ self.refresh_xcvr_api() ++ ++ if self.sfp_type == 'QSFP-DD' or self.sfp_type == 'QSFP': ++ return SfpOptoeBase.set_lpmode(self, lpmode) ++ ++ self._sfplog(LOG_WARNING_LEVEL, 'SFP does not support lpmode') ++ return False ++ ++ def get_tx_disable(self): ++ if self.get_presence() is False: ++ return False ++ ++ if self.sfp_type is None: ++ self.refresh_xcvr_api() ++ ++ if self.sfp_type == 'SFP': ++ return self._sfp_api.get_tx_disable() ++ ++ return SfpOptoeBase.get_tx_disable(self) ++ ++ def get_tx_disable_channel(self): ++ if self.get_presence() is False: ++ return False ++ ++ if self.sfp_type is None: ++ self.refresh_xcvr_api() ++ ++ if self.sfp_type == 'SFP': ++ return self._sfp_api.get_tx_disable_channel() ++ ++ return SfpOptoeBase.get_tx_disable_channel(self) ++ ++ def tx_disable(self, tx_disable): ++ if self.get_presence() is False: ++ return False ++ ++ if self.sfp_type is None: ++ self.refresh_xcvr_api() ++ ++ if self.sfp_type == 'SFP': ++ return self._sfp_api.set_tx_disable(tx_disable) ++ ++ return SfpOptoeBase.tx_disable(self, tx_disable) ++ ++ def tx_disable_channel(self, channel, disable): ++ if self.get_presence() is False: ++ return False ++ ++ if self.sfp_type is None: ++ self.refresh_xcvr_api() ++ ++ if self.sfp_type == 'SFP': ++ self._sfplog(LOG_WARNING_LEVEL, 'SFP does not support tx disable channel') ++ return False ++ ++ return SfpOptoeBase.tx_disable_channel(self, channel, disable) ++ ++ def set_optoe_write_max(self, write_max): ++ """ ++ This func is declared and implemented by SONiC but we're not supported ++ so override it as NotImplemented ++ """ ++ self._sfplog(LOG_DEBUG_LEVEL, "set_optoe_write_max NotImplemented") ++ ++ def refresh_xcvr_api(self): ++ """ ++ Updates the XcvrApi associated with this SFP ++ """ ++ self._xcvr_api = self._xcvr_api_factory.create_xcvr_api() ++ class_name = self._xcvr_api.__class__.__name__ ++ optoe_type = None ++ # set sfp_type ++ if 'CmisApi' in class_name: ++ self.sfp_type = 'QSFP-DD' ++ optoe_type = self.OPTOE_DRV_TYPE3 ++ elif 'Sff8472Api' in class_name: ++ self.sfp_type = 'SFP' ++ optoe_type = self.OPTOE_DRV_TYPE2 ++ elif ('Sff8636Api' in class_name or 'Sff8436Api' in class_name): ++ self.sfp_type = 'QSFP' ++ optoe_type = self.OPTOE_DRV_TYPE1 ++ # set optoe driver ++ if optoe_type is not None: ++ self._sfp_api.set_optoe_type(optoe_type) ++ ++ def _sfplog(self, log_level, msg): ++ if log_level >= self.log_level_config: ++ try: ++ syslog.openlog("Sfp") ++ if log_level == LOG_DEBUG_LEVEL: ++ syslog.syslog(syslog.LOG_DEBUG, msg) ++ elif log_level == LOG_WARNING_LEVEL: ++ syslog.syslog(syslog.LOG_DEBUG, msg) ++ elif log_level == LOG_ERROR_LEVEL: ++ syslog.syslog(syslog.LOG_ERR, msg) ++ syslog.closelog() ++ ++ except BaseException: ++ print(traceback.format_exc()) ++ ++ ++class SfpCust(): ++ def __init__(self, index): ++ self.eeprom_path = None ++ self._init_config(index) ++ ++ def _init_config(self, index): ++ sfp_config = baseutil.get_config().get("sfps", None) ++ self.log_level_config = sfp_config.get("log_level", LOG_WARNING_LEVEL) ++ self._port_id = index ++ self.eeprom_retry_times = sfp_config.get("eeprom_retry_times", 0) ++ self.eeprom_retry_break_sec = sfp_config.get("eeprom_retry_break_sec", 0) ++ ++ def _get_eeprom_path(self): ++ return self.eeprom_path or None ++ ++ @abstractmethod ++ def get_presence(self): ++ pass ++ ++ def read_eeprom(self, offset, num_bytes): ++ try: ++ for i in range(self.eeprom_retry_times): ++ with open(self._get_eeprom_path(), mode='rb', buffering=0) as f: ++ f.seek(offset) ++ result = f.read(num_bytes) ++ # temporary solution for a sonic202111 bug ++ if len(result) < num_bytes: ++ result = result[::-1].zfill(num_bytes)[::-1] ++ if result is not None: ++ return bytearray(result) ++ time.sleep(self.eeprom_retry_break_sec) ++ continue ++ ++ except BaseException: ++ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) ++ return None ++ ++ def write_eeprom(self, offset, num_bytes, write_buffer): ++ try: ++ for i in range(self.eeprom_retry_times): ++ ret = SfpOptoeBase.write_eeprom(self, offset, num_bytes, write_buffer) ++ if ret is False: ++ time.sleep(self.eeprom_retry_break_sec) ++ continue ++ break ++ ++ return ret ++ except BaseException: ++ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) ++ return False ++ ++ @abstractmethod ++ def set_optoe_type(self, optoe_type): ++ pass ++ ++ @abstractmethod ++ def set_reset(self, reset): ++ pass ++ ++ def _convert_str_range_to_int_arr(self, range_str): ++ if not range_str: ++ return [] ++ ++ int_range_strs = range_str.split(',') ++ range_res = [] ++ for int_range_str in int_range_strs: ++ if '-' in int_range_str: ++ range_s = int(int_range_str.split('-')[0]) ++ range_e = int(int_range_str.split('-')[1]) + 1 ++ else: ++ range_s = int(int_range_str) ++ range_e = int(int_range_str) + 1 ++ ++ range_res = range_res + list(range(range_s, range_e)) ++ ++ return range_res ++ ++ def _sfplog(self, log_level, msg): ++ if log_level >= self.log_level_config: ++ try: ++ syslog.openlog("SfpCust") ++ if log_level == LOG_DEBUG_LEVEL: ++ syslog.syslog(syslog.LOG_DEBUG, msg) ++ elif log_level == LOG_WARNING_LEVEL: ++ syslog.syslog(syslog.LOG_DEBUG, msg) ++ elif log_level == LOG_ERROR_LEVEL: ++ syslog.syslog(syslog.LOG_ERR, msg) ++ syslog.closelog() ++ ++ except BaseException: ++ print(traceback.format_exc()) ++ ++ ++class SfpV1(SfpCust): ++ def _init_config(self, index): ++ super()._init_config(index) ++ # init presence path ++ sfp_config = baseutil.get_config().get("sfps", None) ++ ++ eeprom_path_config = sfp_config.get("eeprom_path", None) ++ eeprom_path_key = sfp_config.get("eeprom_path_key")[self._port_id - 1] ++ self.eeprom_path = None if eeprom_path_config is None else eeprom_path_config % ( ++ eeprom_path_key, eeprom_path_key) ++ self._sfplog(LOG_DEBUG_LEVEL, "Done init eeprom path: %s" % self.eeprom_path) ++ ++ self.presence_cpld = sfp_config.get("presence_cpld", None) ++ self.presence_val_is_present = sfp_config.get("presence_val_is_present", 0) ++ self._sfplog(LOG_DEBUG_LEVEL, "Done init presence path") ++ ++ # init reset path ++ self.reset_cpld = sfp_config.get("reset_cpld", None) ++ self.reset_val_is_reset = sfp_config.get("reset_val_is_reset", 0) ++ self._sfplog(LOG_DEBUG_LEVEL, "Done init cpld path") ++ ++ # init tx_disable path ++ self.txdis_cpld = sfp_config.get("txdis_cpld", None) ++ self.txdisable_val_is_on = sfp_config.get("txdisable_val_is_on", 0) ++ self._sfplog(LOG_DEBUG_LEVEL, "Done init cpld tx_disable path") ++ ++ def get_presence(self): ++ if self.presence_cpld is None: ++ self._sfplog(LOG_ERROR_LEVEL, "presence_cpld is None!") ++ return False ++ try: ++ dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.presence_cpld) ++ if dev_id == -1: ++ return False ++ ret, info = platform_reg_read(0, dev_id, offset, 1) ++ if (ret is False ++ or info is None): ++ return False ++ return info[0] & (1 << offset_bit) == self.presence_val_is_present ++ except BaseException: ++ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) ++ return False ++ ++ def get_reset_status(self): ++ if self.reset_cpld is None: ++ self._sfplog(LOG_ERROR_LEVEL, "reset_cpld is None!") ++ return False ++ try: ++ dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.reset_cpld) ++ if dev_id == -1: ++ return False ++ ret, info = platform_reg_read(0, dev_id, offset, 1) ++ if (ret is False ++ or info is None): ++ self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") ++ return False ++ ++ return (info[0] & (1 << offset_bit) == self.reset_val_is_reset) ++ except BaseException: ++ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) ++ return False ++ ++ def get_tx_disable(self): ++ if self.reset_cpld is None: ++ self._sfplog(LOG_ERROR_LEVEL, "txdis_cpld is None!") ++ return None ++ ++ try: ++ tx_disable_list = [] ++ dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.txdis_cpld) ++ if dev_id == -1: ++ return False ++ ret, info = platform_reg_read(0, dev_id, offset, 1) ++ if (ret is False ++ or info is None): ++ self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") ++ return None ++ if self.txdisable_val_is_on == 1: ++ tx_disable_list.append(info[0] & (1 << offset_bit) != 0) ++ else: ++ tx_disable_list.append(info[0] & (1 << offset_bit) == 0) ++ except BaseException: ++ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) ++ return None ++ ++ return tx_disable_list ++ ++ def get_tx_disable_channel(self): ++ tx_disable_list = [] ++ tx_disable_list = self.get_tx_disable() ++ if tx_disable_list is None: ++ return 0 ++ ++ tx_disabled = 0 ++ for i in range(len(tx_disable_list)): ++ if tx_disable_list[i]: ++ tx_disabled |= 1 << i ++ ++ return tx_disabled ++ ++ def read_eeprom(self, offset, num_bytes): ++ try: ++ for i in range(self.eeprom_retry_times): ++ ret, info = platform_sfp_read(self._port_id, offset, num_bytes) ++ if (ret is False ++ or info is None): ++ time.sleep(self.eeprom_retry_break_sec) ++ continue ++ eeprom_raw = [] ++ for i in range(0, num_bytes): ++ eeprom_raw.append(0) ++ for n in range(0, len(info)): ++ eeprom_raw[n] = info[n] ++ # temporary solution for a sonic202111 bug ++ if len(eeprom_raw) < num_bytes: ++ eeprom_raw = eeprom_raw[::-1].zfill(num_bytes)[::-1] ++ return bytearray(eeprom_raw) ++ except BaseException: ++ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) ++ return None ++ ++ def set_optoe_type(self, optoe_type): ++ ret, info = platform_get_optoe_type(self._port_id) ++ if ret is True and info != optoe_type: ++ try: ++ ret, _ = platform_set_optoe_type(self._port_id, optoe_type) ++ except Exception as err: ++ self._sfplog(LOG_ERROR_LEVEL, "Set optoe err %s" % err) ++ ++ def set_reset(self, reset): ++ if self.reset_cpld is None: ++ self._sfplog(LOG_ERROR_LEVEL, "reset_cpld is None!") ++ return False ++ try: ++ val = [] ++ dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.reset_cpld) ++ if dev_id == -1: ++ return False ++ ret, info = platform_reg_read(0, dev_id, offset, 1) ++ if (ret is False ++ or info is None): ++ self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") ++ return False ++ ++ if self.reset_val_is_reset == 0: ++ if reset: ++ val.append(info[0] & (~(1 << offset_bit))) ++ else: ++ val.append(info[0] | (1 << offset_bit)) ++ else: ++ if reset: ++ val.append(info[0] | (1 << offset_bit)) ++ else: ++ val.append(info[0] & (~(1 << offset_bit))) ++ ++ ret, info = platform_reg_write(0, dev_id, offset, val) ++ if ret is False: ++ self._sfplog(LOG_ERROR_LEVEL, "platform_reg_write error!") ++ return False ++ ++ except BaseException: ++ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) ++ return False ++ ++ return True ++ ++ def set_tx_disable(self, tx_disable): ++ if self.txdis_cpld is None: ++ self._sfplog(LOG_ERROR_LEVEL, "txdis_cpld is None!") ++ return False ++ try: ++ val = [] ++ dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.txdis_cpld) ++ if dev_id == -1: ++ return False ++ ret, info = platform_reg_read(0, dev_id, offset, 1) ++ if (ret is False ++ or info is None): ++ self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") ++ return False ++ ++ if self.txdisable_val_is_on == 0: ++ if tx_disable: ++ val.append(info[0] & (~(1 << offset_bit))) ++ else: ++ val.append(info[0] | (1 << offset_bit)) ++ else: ++ if tx_disable: ++ val.append(info[0] | (1 << offset_bit)) ++ else: ++ val.append(info[0] & (~(1 << offset_bit))) ++ ++ ret, info = platform_reg_write(0, dev_id, offset, val) ++ if ret is False: ++ self._sfplog(LOG_ERROR_LEVEL, "platform_reg_write error!") ++ return False ++ ++ except BaseException: ++ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) ++ return False ++ ++ return True ++ ++ def _get_sfp_cpld_info(self, cpld_config): ++ dev_id = -1 ++ offset = -1 ++ offset_bit = -1 ++ for dev_id_temp in cpld_config["dev_id"]: ++ for offset_temp in cpld_config["dev_id"][dev_id_temp]["offset"]: ++ port_range_str = cpld_config["dev_id"][dev_id_temp]["offset"][offset_temp] ++ port_range_int = self._convert_str_range_to_int_arr(port_range_str) ++ if self._port_id in port_range_int: ++ dev_id = dev_id_temp ++ offset = offset_temp ++ offset_bit = port_range_int.index(self._port_id) ++ break ++ ++ return dev_id, offset, offset_bit ++ ++ ++class SfpV2(SfpCust): ++ def _init_config(self, index): ++ super()._init_config(index) ++ # init eeprom path ++ sfp_config = baseutil.get_config().get("sfps", None) ++ eeprom_path_config = sfp_config.get("eeprom_path", None) ++ eeprom_path_key = sfp_config.get("eeprom_path_key")[self._port_id - 1] ++ self.eeprom_path = None if eeprom_path_config is None else eeprom_path_config % ( ++ eeprom_path_key, eeprom_path_key) ++ self._sfplog(LOG_DEBUG_LEVEL, "Done init eeprom path: %s" % self.eeprom_path) ++ ++ # init presence path ++ self.presence_path = None if sfp_config.get("presence_path", ++ None) is None else sfp_config.get("presence_path") % self._port_id ++ self.presence_val_is_present = sfp_config.get("presence_val_is_present", 0) ++ self._sfplog(LOG_DEBUG_LEVEL, "Done init presence path: %s" % self.presence_path) ++ ++ # init optoe driver path ++ optoe_driver_path = sfp_config.get("optoe_driver_path", None) ++ optoe_driver_key = sfp_config.get("optoe_driver_key")[self._port_id - 1] ++ self.dev_class_path = None if optoe_driver_path is None else optoe_driver_path % ( ++ optoe_driver_key, optoe_driver_key) ++ self._sfplog(LOG_DEBUG_LEVEL, "Done init optoe driver path: %s" % self.dev_class_path) ++ ++ # init reset path ++ self.reset_path = None if sfp_config.get( ++ "reset_path", ++ None) is None else sfp_config.get( ++ "reset_path", ++ None) % self._port_id ++ self.reset_val_is_reset = sfp_config.get("reset_val_is_reset", 0) ++ self._sfplog(LOG_DEBUG_LEVEL, "Done init reset path: %s" % self.reset_path) ++ ++ def get_presence(self): ++ if self.presence_path is None: ++ self._sfplog(LOG_ERROR_LEVEL, "presence_path is None!") ++ return False ++ try: ++ with open(self.presence_path, "rb") as data: ++ sysfs_data = data.read(1) ++ if sysfs_data != "": ++ result = int(sysfs_data, 16) ++ return result == self.presence_val_is_present ++ except BaseException: ++ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) ++ return False ++ ++ def set_reset(self, reset): ++ return True ++ ++ def set_optoe_type(self, optoe_type): ++ if self.dev_class_path is None: ++ self._sfplog(LOG_ERROR_LEVEL, "dev_class_path is None!") ++ return False ++ try: ++ with open(self.dev_class_path, "r+") as dc_file: ++ dc_file_val = dc_file.read(1) ++ if int(dc_file_val) != optoe_type: ++ dc_str = "%s" % str(optoe_type) ++ dc_file.write(dc_str) ++ # dc_file.close() ++ except BaseException: ++ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) ++ return False ++ return True +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/thermal.py +new file mode 100644 +index 000000000..4632de3bc +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/thermal.py +@@ -0,0 +1,234 @@ ++#!/usr/bin/env python3 ++ ++######################################################################## ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the Thermals' information which are available in the platform ++# ++######################################################################## ++ ++ ++try: ++ import time ++ from sonic_platform_base.thermal_base import ThermalBase ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") from e ++ ++ ++class Thermal(ThermalBase): ++ ++ def __init__(self, interface_obj, index): ++ self.temp_dict = {} ++ self.temperature_list = [] ++ self.int_case = interface_obj ++ self.index = index ++ self.update_time = 0 ++ self.temp_id = "TEMP" + str(index) ++ ++ def temp_dict_update(self): ++ local_time = time.time() ++ if not self.temp_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds ++ self.update_time = local_time ++ self.temp_dict = self.int_case.get_monitor_temp_by_id(self.temp_id) ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the thermal ++ ++ Returns: ++ string: The name of the thermal ++ """ ++ self.temp_dict_update() ++ return self.temp_dict["Api_name"] ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the thermal ++ ++ Returns: ++ bool: True if thermal is present, False if not ++ """ ++ return True ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the Thermal ++ ++ Returns: ++ string: Model/part number of Thermal ++ """ ++ return "N/A" ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the Thermal ++ ++ Returns: ++ string: Serial number of Thermal ++ """ ++ return "N/A" ++ ++ def get_revision(self): ++ """ ++ Retrieves the hardware revision of the device ++ ++ Returns: ++ string: Revision value of device ++ """ ++ return "N/A" ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the thermal ++ ++ Returns: ++ A boolean value, True if thermal is operating properly, ++ False if not ++ """ ++ self.temp_dict_update() ++ if (self.temp_dict["Value"] >= self.temp_dict["High"]) or (self.temp_dict["Value"] <= self.temp_dict["Low"]): ++ return False ++ ++ return True ++ ++ 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 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 ++ """ ++ self.temp_dict_update() ++ value = self.temp_dict["Value"] ++ if value is None or value == self.int_case.error_ret: ++ return "N/A" ++ if len(self.temperature_list) >= 1000: ++ del self.temperature_list[0] ++ self.temperature_list.append(float(value)) ++ return round(float(value), 1) ++ ++ 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 ++ """ ++ self.temp_dict_update() ++ value = self.temp_dict["High"] ++ if value is None or value == self.int_case.error_ret: ++ return "N/A" ++ return round(float(value), 1) ++ ++ 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 ++ """ ++ self.temp_dict_update() ++ value = self.temp_dict["Low"] ++ if value is None or value == self.int_case.error_ret: ++ return "N/A" ++ return round(float(value), 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 ++ """ ++ # not supported ++ return False ++ ++ 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 ++ """ ++ # not supported ++ 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 ++ """ ++ self.temp_dict_update() ++ value = self.temp_dict["Max"] ++ if value is None or value == self.int_case.error_ret: ++ return "N/A" ++ return round(float(value), 1) ++ ++ def get_low_critical_threshold(self): ++ """ ++ Retrieves the low critical threshold temperature of thermal ++ ++ Returns: ++ A float number, the low critical threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ self.temp_dict_update() ++ value = self.temp_dict["Min"] ++ if value is None or value == self.int_case.error_ret: ++ return "N/A" ++ return round(float(value), 1) ++ ++ def get_minimum_recorded(self): ++ """ ++ Retrieves the minimum recorded temperature of thermal ++ ++ Returns: ++ A float number, the minimum recorded temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ if len(self.temperature_list) == 0: ++ return "N/A" ++ return round(float(min(self.temperature_list)), 1) ++ ++ def get_maximum_recorded(self): ++ """ ++ Retrieves the maximum recorded temperature of thermal ++ ++ Returns: ++ A float number, the maximum recorded temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ if len(self.temperature_list) == 0: ++ return "N/A" ++ return round(float(max(self.temperature_list)), 1) +diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/watchdog.py +new file mode 100644 +index 000000000..948337f47 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/watchdog.py +@@ -0,0 +1,236 @@ ++#!/usr/bin/env python3 ++ ++######################################################################## ++# ++# ++# Abstract base class for implementing a platform-specific class with ++# which to interact with a hardware watchdog module in SONiC ++# ++######################################################################## ++ ++import fcntl ++import os ++import array ++ ++try: ++ from sonic_platform_base.watchdog_base import WatchdogBase ++except ImportError as error: ++ raise ImportError(str(error) + "- required module not found") from error ++ ++ ++# ioctl constants ++IO_WRITE = 0x40000000 ++IO_READ = 0x80000000 ++IO_READ_WRITE = 0xC0000000 ++IO_SIZE_INT = 0x00040000 ++IO_SIZE_40 = 0x00280000 ++IO_TYPE_WATCHDOG = ord('W') << 8 ++ ++WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG ++WDR_40 = IO_READ | IO_SIZE_40 | IO_TYPE_WATCHDOG ++WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG ++ ++# Watchdog ioctl command ++WDIOC_GETSUPPORT = 0 | WDR_40 ++WDIOC_GETSTATUS = 1 | WDR_INT ++WDIOC_GETBOOTSTATUS = 2 | WDR_INT ++WDIOC_GETTEMP = 3 | WDR_INT ++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 ++ ++WDT_COMMON_ERROR = -1 ++WDT_IDENTITY = "CPLD Watchdog" ++WDT_SYSFS_PATH = "/sys/class/watchdog/" ++ ++DEFAULT_TIMEOUT = 180 ++ ++ ++class Watchdog(WatchdogBase): ++ """ ++ Abstract base class for interfacing with a hardware watchdog module ++ """ ++ ++ def __init__(self): ++ self.watchdog, self.wdt_main_dev_name = self._get_wdt() ++ self.status_path = "/sys/class/watchdog/%s/status" % self.wdt_main_dev_name ++ self.state_path = "/sys/class/watchdog/%s/state" % self.wdt_main_dev_name ++ self.timeout_path = "/sys/class/watchdog/%s/timeout" % self.wdt_main_dev_name ++ # Set default value ++ self._disable() ++ self.armed = False ++ self.timeout = self._gettimeout() ++ ++ def _is_wd_main(self, dev): ++ """ ++ Checks watchdog identity ++ """ ++ identity = self._read_file( ++ "{}/{}/identity".format(WDT_SYSFS_PATH, dev)) ++ return identity == WDT_IDENTITY ++ ++ def _get_wdt(self): ++ """ ++ Retrieves watchdog device ++ """ ++ wdt_main_dev_list = [dev for dev in os.listdir( ++ "/dev/") if dev.startswith("watchdog") and self._is_wd_main(dev)] ++ if not wdt_main_dev_list: ++ return None ++ wdt_main_dev_name = wdt_main_dev_list[0] ++ watchdog_device_path = "/dev/{}".format(wdt_main_dev_name) ++ watchdog = os.open(watchdog_device_path, os.O_RDWR) ++ return watchdog, wdt_main_dev_name ++ ++ def _read_file(self, file_path): ++ """ ++ Read text file ++ """ ++ try: ++ with open(file_path, "r") as fd: ++ txt = fd.read() ++ except IOError: ++ return WDT_COMMON_ERROR ++ return txt.strip() ++ ++ def _enable(self): ++ """ ++ Turn on the watchdog timer ++ """ ++ req = array.array('h', [WDIOS_ENABLECARD]) ++ fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) ++ ++ def _disable(self): ++ """ ++ Turn off the watchdog timer ++ """ ++ req = array.array('h', [WDIOS_DISABLECARD]) ++ 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 ++ """ ++ req = array.array('I', [0]) ++ fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True) ++ ++ return int(req[0]) ++ ++ 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): ++ """ ++ Arm the hardware watchdog with a timeout of seconds. ++ If the watchdog is currently armed, calling this function will ++ simply reset the timer to the provided value. If the underlying ++ hardware does not support the value provided in , this ++ method should arm the watchdog with the *next greater* available ++ value. ++ ++ Returns: ++ An integer specifying the *actual* number of seconds the watchdog ++ was armed with. On failure returns -1. ++ """ ++ ret = WDT_COMMON_ERROR ++ if seconds < 0: ++ return ret ++ ++ try: ++ if self.timeout != seconds: ++ self.timeout = self._settimeout(seconds) ++ if self.armed: ++ self._keepalive() ++ else: ++ self._settimeout(seconds) ++ self._enable() ++ self.armed = True ++ ret = self.timeout ++ except IOError: ++ pass ++ ++ return ret ++ ++ def disarm(self): ++ """ ++ Disarm the hardware watchdog ++ ++ Returns: ++ A boolean, True if watchdog is disarmed successfully, False if not ++ """ ++ disarmed = False ++ if self.is_armed(): ++ try: ++ self._disable() ++ self.armed = False ++ disarmed = True ++ except IOError: ++ pass ++ ++ return disarmed ++ ++ def is_armed(self): ++ """ ++ Retrieves the armed state of the hardware watchdog. ++ ++ Returns: ++ A boolean, True if watchdog is armed, False if not ++ """ ++ return self.armed ++ ++ def get_remaining_time(self): ++ """ ++ If the watchdog is armed, retrieve the number of seconds remaining on ++ the watchdog timer ++ ++ Returns: ++ An integer specifying the number of seconds remaining on thei ++ watchdog timer. If the watchdog is not armed, returns -1. ++ """ ++ timeleft = WDT_COMMON_ERROR ++ ++ if self.armed: ++ try: ++ timeleft = self._gettimeleft() ++ except IOError: ++ pass ++ ++ return timeleft ++ ++ def __del__(self): ++ """ ++ Close watchdog ++ """ ++ os.close(self.watchdog) +diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/changelog b/platform/broadcom/sonic-platform-modules-micas/debian/changelog +new file mode 100644 +index 000000000..d908208c5 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/debian/changelog +@@ -0,0 +1,5 @@ ++sonic-micas-platform-modules (1.0) unstable; urgency=low ++ ++ * Initial release ++ ++ -- support Fri, 21 APR 2017 11:11:11 -0800 +diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/compat b/platform/broadcom/sonic-platform-modules-micas/debian/compat +new file mode 100644 +index 000000000..f599e28b8 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/debian/compat +@@ -0,0 +1 @@ ++10 +diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/control b/platform/broadcom/sonic-platform-modules-micas/debian/control +new file mode 100644 +index 000000000..55b583777 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/debian/control +@@ -0,0 +1,9 @@ ++Source: sonic-micas-platform-modules ++Section: main ++Priority: extra ++Maintainer: support ++Standards-Version: 3.9.3 ++ ++Package: platform-modules-micas-m2-w6510-48v8c ++Architecture: amd64 ++Description: kernel modules for platform devices such as fan, led, sfp +diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/copyright b/platform/broadcom/sonic-platform-modules-micas/debian/copyright +new file mode 100644 +index 000000000..676cdeec7 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/debian/copyright +@@ -0,0 +1,15 @@ ++Copyright (C) 2016 Microsoft, Inc ++ ++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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.install b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.install +new file mode 100644 +index 000000000..6f3e9b257 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.install +@@ -0,0 +1 @@ ++m2-w6510-48v8c/modules/sonic_platform-1.0-py3-none-any.whl /usr/share/sonic/device/x86_64-micas_m2-w6510-48v8c-r0 +diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.postinst b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.postinst +new file mode 100644 +index 000000000..a8132f4f6 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.postinst +@@ -0,0 +1,10 @@ ++#!/bin/sh ++# postinst ++ ++kernel_version=$(uname -r) ++ ++if [ -e /boot/System.map-${kernel_version} ]; then ++ depmod -a -F /boot/System.map-${kernel_version} ${kernel_version} || true ++fi ++ ++#DEBHELPER# +diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/rule.mk b/platform/broadcom/sonic-platform-modules-micas/debian/rule.mk +new file mode 100644 +index 000000000..f27bca1d6 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/debian/rule.mk +@@ -0,0 +1,5 @@ ++currentdir = $(shell pwd) ++ ++MODULE_DIRS := m2-w6510-48v8c ++ ++export MODULE_DIRS +diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/rules b/platform/broadcom/sonic-platform-modules-micas/debian/rules +new file mode 100755 +index 000000000..e801ef47f +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/debian/rules +@@ -0,0 +1,92 @@ ++#!/usr/bin/make -f ++CC=gcc ++INSTALL_MOD_DIR:=extra ++KVERSION ?= $(shell uname -r) ++KERNEL_SRC := /lib/modules/$(KVERSION) ++MOD_SRC_DIR:= $(shell pwd) ++KBUILD_OUTPUT=$(KERNEL_SRC)/build ++ ++LIB_DIR = usr/lib/python3/dist-packages ++CUSTOM_RULES_DIR := $(shell pwd)/debian ++ ++export INSTALL_MOD_DIR top_srcdir KVERSION KERNEL_SRC CC KBUILD_OUTPUT CUSTOM_RULES_DIR ++ ++include $(CUSTOM_RULES_DIR)/rule.mk ++ ++#all product need common ++COMPILE_DIRS = $(MODULE_DIRS) ++ ++clean_dirs = $(MODULE_DIRS) ++clean_dirs += common ++ ++complie_clean_dirs := $(addprefix _clean_,$(clean_dirs) ) ++ ++%: ++ dh $@ ++build: COMPILE_WHL ++ @echo "build success" ++ ++$(complie_clean_dirs): ++ $(MAKE) -C $(patsubst _clean_%,%,$@) clean ++ ++common_build : ++ $(MAKE) -C $(MOD_SRC_DIR)/common ++ ++$(COMPILE_DIRS): common_build ++ $(MAKE) -C $(MOD_SRC_DIR)/$@ ++ dh_testdir ++ dh_installdirs ++ cp -r $(MOD_SRC_DIR)/common/build/* debian/platform-modules-micas-$@/; \ ++ cp -r $(MOD_SRC_DIR)/$@/build/* debian/platform-modules-micas-$@/; \ ++ ++COMPILE_WHL: $(COMPILE_DIRS) ++ @(for mod in $(MODULE_DIRS); do \ ++ cd $(MOD_SRC_DIR)/$${mod}; \ ++ cp -r $(MOD_SRC_DIR)/common/lib/plat_hal $(MOD_SRC_DIR)/$${mod}/; \ ++ cp -r $(MOD_SRC_DIR)/common/lib/wbutil $(MOD_SRC_DIR)/$${mod}/; \ ++ cp -r $(MOD_SRC_DIR)/common/lib/eepromutil $(MOD_SRC_DIR)/$${mod}/; \ ++ cp -r $(MOD_SRC_DIR)/common/sonic_platform $(MOD_SRC_DIR)/$${mod}/; \ ++ cp $(MOD_SRC_DIR)/common/script/hal_pltfm.py $(MOD_SRC_DIR)/$${mod}/hal_pltfm.py; \ ++ cp $(MOD_SRC_DIR)/common/script/platform_util.py $(MOD_SRC_DIR)/$${mod}/platform_util.py; \ ++ cp $(MOD_SRC_DIR)/common/script/platform_intf.py $(MOD_SRC_DIR)/$${mod}/platform_intf.py; \ ++ python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ ++ rm -rf $(MOD_SRC_DIR)/$${mod}/plat_hal; \ ++ rm -rf $(MOD_SRC_DIR)/$${mod}/wbutil; \ ++ rm -rf $(MOD_SRC_DIR)/$${mod}/eepromutil; \ ++ rm -rf $(MOD_SRC_DIR)/$${mod}/sonic_platform; \ ++ rm -rf $(MOD_SRC_DIR)/$${mod}/hal_pltfm.py; \ ++ rm -rf $(MOD_SRC_DIR)/$${mod}/platform_intf.py; \ ++ rm -rf $(MOD_SRC_DIR)/$${mod}/platform_util.py; \ ++ cd $(MOD_SRC_DIR); \ ++ done) ++ ++binary: binary-indep ++ @echo "=======================================================" ++ ++binary-indep: ++ # Resuming debhelper scripts ++ dh_testroot ++ dh_install ++ dh_installchangelogs ++ dh_installdocs ++ dh_systemd_enable ++ dh_installinit ++ dh_systemd_start ++ dh_link ++ dh_fixperms ++ dh_compress ++ dh_strip ++ dh_installdeb ++ dh_gencontrol ++ dh_md5sums ++ dh_builddeb ++override_dh_usrlocal: ++ ++override_dh_pysupport: ++ ++clean: $(complie_clean_dirs) ++ dh_testdir ++ dh_testroot ++ dh_clean ++ ++.PHONY: build $(COMPILE_DIRS) binary binary-arch binary-indep clean +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/cpld_test_header.vme b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/cpld_test_header.vme +new file mode 100644 +index 0000000000000000000000000000000000000000..083fd78f3ea1919d9d3737fe0d8d0c7b8b2ce881 +GIT binary patch +literal 406 +zcmaiu!AgWc7{^Cl9GwWZEU4QY>mrW2O9%#{v#rqDVj^@}T%AMUt^?Upr*1u1&(K43 +z?FnqO2k^UmA0NNppMS~gYSXfp);#POTEzEsNrQ-{S16)+_OzzH_2yb`frh&jGzynN +zocKiSc%1|*>JQ(XrjPMM;vcLbWx(?lMPV9>2xnduTlc0w*NEL#8!^N-$!~cVJr}!X +zU*U-Hx_RHReT%cEsj*`cOSm-1L@17ejCweGWq851n7EkCz1hsO3AQcUK?q#pT+$Q+ +zaP`9Ix{m7r0$EYyqaQexPBa5Reu@nVOwPd9@%QJs+)cP9_xx1wT$jWNHKXIBQctQq +VsrNb@^ic_@K=0eZ|8`^i#~;mYW4-_Y + +literal 0 +HcmV?d00001 + +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/fpga_test_header.bin b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/fpga_test_header.bin +new file mode 100644 +index 000000000..bdf9ae213 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/fpga_test_header.bin +@@ -0,0 +1,10 @@ ++fpga_test_header.bin ++FILEHEADER( ++DEVTYPE=0x404a ++TYPE=fpga ++CHAIN=3 ++CHIPNAME=fpga ++VERSION=v0 ++FILETYPE=SPI-LOGIC-DEV ++CRC=0x00000000 ++) +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/Makefile b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/Makefile +new file mode 100644 +index 000000000..1b84abef4 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/Makefile +@@ -0,0 +1,28 @@ ++PWD = $(shell pwd) ++DIR_KERNEL_SRC = $(PWD)/modules/driver ++EXTRA_CFLAGS:= -I$(M)/include ++EXTRA_CFLAGS+= -Wall ++SUB_BUILD_DIR = $(PWD)/build ++INSTALL_DIR = $(SUB_BUILD_DIR)/$(KERNEL_SRC)/$(INSTALL_MOD_DIR) ++INSTALL_SCRIPT_DIR = $(SUB_BUILD_DIR)/usr/local/bin ++INSTALL_LIB_DIR = $(SUB_BUILD_DIR)/usr/lib/python3/dist-packages ++INSTALL_SYSFS_CFG_DIR = $(SUB_BUILD_DIR)/etc/plat_sysfs_cfg ++INSTALL_UPGRADE_TEST_DIR = $(SUB_BUILD_DIR)/etc/.upgrade_test ++ ++all: ++ $(MAKE) -C $(KBUILD_OUTPUT) M=$(DIR_KERNEL_SRC) modules ++ @if [ ! -d ${INSTALL_DIR} ]; then mkdir -p ${INSTALL_DIR} ;fi ++ cp -r $(DIR_KERNEL_SRC)/*.ko $(INSTALL_DIR) ++ @if [ ! -d ${INSTALL_SCRIPT_DIR} ]; then mkdir -p ${INSTALL_SCRIPT_DIR} ;fi ++ cp -r $(PWD)/config/* $(INSTALL_SCRIPT_DIR) ++ @if [ ! -d ${INSTALL_LIB_DIR} ]; then mkdir -p ${INSTALL_LIB_DIR} ;fi ++ @if [ -d $(PWD)/hal-config/ ]; then cp -r $(PWD)/hal-config/* ${INSTALL_LIB_DIR} ;fi ++ @if [ ! -d ${INSTALL_SYSFS_CFG_DIR} ]; then mkdir -p ${INSTALL_SYSFS_CFG_DIR} ;fi ++ @if [ -d $(PWD)/plat_sysfs_cfg/ ]; then cp -r $(PWD)/plat_sysfs_cfg/* ${INSTALL_SYSFS_CFG_DIR} ;fi ++ @if [ ! -d ${INSTALL_UPGRADE_TEST_DIR} ]; then mkdir -p ${INSTALL_UPGRADE_TEST_DIR} ;fi ++ @if [ -d $(PWD)/.upgrade_test/ ]; then cp -r $(PWD)/.upgrade_test/* ${INSTALL_UPGRADE_TEST_DIR} ;fi ++clean: ++ rm -f ${DIR_KERNEL_SRC}/*.o ${DIR_KERNEL_SRC}/*.ko ${DIR_KERNEL_SRC}/*.mod.c ${DIR_KERNEL_SRC}/.*.cmd ++ rm -f ${DIR_KERNEL_SRC}/Module.markers ${DIR_KERNEL_SRC}/Module.symvers ${DIR_KERNEL_SRC}/modules.order ++ rm -rf ${DIR_KERNEL_SRC}/.tmp_versions ++ rm -rf $(SUB_BUILD_DIR) +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_config.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_config.py +new file mode 100755 +index 000000000..587e303a6 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_config.py +@@ -0,0 +1,1106 @@ ++#!/usr/bin/python ++# -*- coding: UTF-8 -*- ++from platform_common import * ++ ++STARTMODULE = { ++ "hal_fanctrl": 1, ++ "hal_ledctrl": 1, ++ "avscontrol": 1, ++ "dev_monitor": 1, ++ "pmon_syslog": 1, ++ "tty_console": 1, ++ "macledreset": 1, ++ "sff_temp_polling": 1, ++ "generate_airflow": 1, ++ "reboot_cause": 1, ++} ++ ++MAC_LED_RESET = {"pcibus": 8, "slot": 0, "fn": 0, "bar": 0, "offset": 64, "reset": 0x98} ++ ++MANUINFO_CONF = { ++ "bios": { ++ "key": "BIOS", ++ "head": True, ++ "next": "onie" ++ }, ++ "bios_vendor": { ++ "parent": "bios", ++ "key": "Vendor", ++ "cmd": "dmidecode -t 0 |grep Vendor", ++ "pattern": r".*Vendor", ++ "separator": ":", ++ "arrt_index": 1, ++ }, ++ "bios_version": { ++ "parent": "bios", ++ "key": "Version", ++ "cmd": "dmidecode -t 0 |grep Version", ++ "pattern": r".*Version", ++ "separator": ":", ++ "arrt_index": 2, ++ }, ++ "bios_date": { ++ "parent": "bios", ++ "key": "Release Date", ++ "cmd": "dmidecode -t 0 |grep Release", ++ "pattern": r".*Release Date", ++ "separator": ":", ++ "arrt_index": 3, ++ }, ++ "onie": { ++ "key": "ONIE", ++ "next": "cpu" ++ }, ++ "onie_date": { ++ "parent": "onie", ++ "key": "Build Date", ++ "file": "/host/machine.conf", ++ "pattern": r"^onie_build_date", ++ "separator": "=", ++ "arrt_index": 1, ++ }, ++ "onie_version": { ++ "parent": "onie", ++ "key": "Version", ++ "file": "/host/machine.conf", ++ "pattern": r"^onie_version", ++ "separator": "=", ++ "arrt_index": 2, ++ }, ++ ++ "cpu": { ++ "key": "CPU", ++ "next": "ssd" ++ }, ++ "cpu_vendor": { ++ "parent": "cpu", ++ "key": "Vendor", ++ "cmd": "dmidecode --type processor |grep Manufacturer", ++ "pattern": r".*Manufacturer", ++ "separator": ":", ++ "arrt_index": 1, ++ }, ++ "cpu_model": { ++ "parent": "cpu", ++ "key": "Device Model", ++ "cmd": "dmidecode --type processor | grep Version", ++ "pattern": r".*Version", ++ "separator": ":", ++ "arrt_index": 2, ++ }, ++ "cpu_core": { ++ "parent": "cpu", ++ "key": "Core Count", ++ "cmd": "dmidecode --type processor | grep \"Core Count\"", ++ "pattern": r".*Core Count", ++ "separator": ":", ++ "arrt_index": 3, ++ }, ++ "cpu_thread": { ++ "parent": "cpu", ++ "key": "Thread Count", ++ "cmd": "dmidecode --type processor | grep \"Thread Count\"", ++ "pattern": r".*Thread Count", ++ "separator": ":", ++ "arrt_index": 4, ++ }, ++ "ssd": { ++ "key": "SSD", ++ "next": "cpld" ++ }, ++ "ssd_model": { ++ "parent": "ssd", ++ "key": "Device Model", ++ "cmd": "smartctl -i /dev/sda |grep \"Device Model\"", ++ "pattern": r".*Device Model", ++ "separator": ":", ++ "arrt_index": 1, ++ }, ++ "ssd_fw": { ++ "parent": "ssd", ++ "key": "Firmware Version", ++ "cmd": "smartctl -i /dev/sda |grep \"Firmware Version\"", ++ "pattern": r".*Firmware Version", ++ "separator": ":", ++ "arrt_index": 2, ++ }, ++ "ssd_user_cap": { ++ "parent": "ssd", ++ "key": "User Capacity", ++ "cmd": "smartctl -i /dev/sda |grep \"User Capacity\"", ++ "pattern": r".*User Capacity", ++ "separator": ":", ++ "arrt_index": 3, ++ }, ++ ++ "cpld": { ++ "key": "CPLD", ++ "next": "psu" ++ }, ++ ++ "cpld1": { ++ "key": "CPLD1", ++ "parent": "cpld", ++ "arrt_index": 1, ++ }, ++ "cpld1_model": { ++ "key": "Device Model", ++ "parent": "cpld1", ++ "config": "LCMXO3LF-2100C-5BG256C", ++ "arrt_index": 1, ++ }, ++ "cpld1_vender": { ++ "key": "Vendor", ++ "parent": "cpld1", ++ "config": "LATTICE", ++ "arrt_index": 2, ++ }, ++ "cpld1_desc": { ++ "key": "Description", ++ "parent": "cpld1", ++ "config": "CPU_CPLD", ++ "arrt_index": 3, ++ }, ++ "cpld1_version": { ++ "key": "Firmware Version", ++ "parent": "cpld1", ++ "reg": { ++ "loc": "/dev/port", ++ "offset": 0x700, ++ "size": 4 ++ }, ++ "callback": "cpld_format", ++ "arrt_index": 4, ++ }, ++ ++ "cpld2": { ++ "key": "CPLD2", ++ "parent": "cpld", ++ "arrt_index": 2, ++ }, ++ "cpld2_model": { ++ "key": "Device Model", ++ "parent": "cpld2", ++ "config": "LCMXO3LF-2100C-5BG256C", ++ "arrt_index": 1, ++ }, ++ "cpld2_vender": { ++ "key": "Vendor", ++ "parent": "cpld2", ++ "config": "LATTICE", ++ "arrt_index": 2, ++ }, ++ "cpld2_desc": { ++ "key": "Description", ++ "parent": "cpld2", ++ "config": "CONNECT_CPLD", ++ "arrt_index": 3, ++ }, ++ "cpld2_version": { ++ "key": "Firmware Version", ++ "parent": "cpld2", ++ "reg": { ++ "loc": "/dev/port", ++ "offset": 0x900, ++ "size": 4 ++ }, ++ "callback": "cpld_format", ++ "arrt_index": 4, ++ }, ++ ++ "cpld3": { ++ "key": "CPLD3", ++ "parent": "cpld", ++ "arrt_index": 3, ++ }, ++ "cpld3_model": { ++ "key": "Device Model", ++ "parent": "cpld3", ++ "config": "LCMXO3LF-2100C-5BG256C", ++ "arrt_index": 1, ++ }, ++ "cpld3_vender": { ++ "key": "Vendor", ++ "parent": "cpld3", ++ "config": "LATTICE", ++ "arrt_index": 2, ++ }, ++ "cpld3_desc": { ++ "key": "Description", ++ "parent": "cpld3", ++ "config": "CONNECT_CPLD-FAN", ++ "arrt_index": 3, ++ }, ++ "cpld3_version": { ++ "key": "Firmware Version", ++ "parent": "cpld3", ++ "i2c": { ++ "bus": "2", ++ "loc": "0x0d", ++ "offset": 0, ++ "size": 4 ++ }, ++ "callback": "cpld_format", ++ "arrt_index": 4, ++ }, ++ ++ "cpld4": { ++ "key": "CPLD4", ++ "parent": "cpld", ++ "arrt_index": 4, ++ }, ++ "cpld4_model": { ++ "key": "Device Model", ++ "parent": "cpld4", ++ "config": "LCMXO3LF-2100C-5BG256C", ++ "arrt_index": 1, ++ }, ++ "cpld4_vender": { ++ "key": "Vendor", ++ "parent": "cpld4", ++ "config": "LATTICE", ++ "arrt_index": 2, ++ }, ++ "cpld4_desc": { ++ "key": "Description", ++ "parent": "cpld4", ++ "config": "MAC_CPLD1", ++ "arrt_index": 3, ++ }, ++ "cpld4_version": { ++ "key": "Firmware Version", ++ "parent": "cpld4", ++ "i2c": { ++ "bus": "8", ++ "loc": "0x30", ++ "offset": 0, ++ "size": 4 ++ }, ++ "callback": "cpld_format", ++ "arrt_index": 4, ++ }, ++ ++ "cpld5": { ++ "key": "CPLD5", ++ "parent": "cpld", ++ "arrt_index": 5, ++ }, ++ "cpld5_model": { ++ "key": "Device Model", ++ "parent": "cpld5", ++ "config": "LCMXO3LF-2100C-5BG256C", ++ "arrt_index": 1, ++ }, ++ "cpld5_vender": { ++ "key": "Vendor", ++ "parent": "cpld5", ++ "config": "LATTICE", ++ "arrt_index": 2, ++ }, ++ "cpld5_desc": { ++ "key": "Description", ++ "parent": "cpld5", ++ "config": "MAC_CPLD2", ++ "arrt_index": 3, ++ }, ++ "cpld5_version": { ++ "key": "Firmware Version", ++ "parent": "cpld5", ++ "i2c": { ++ "bus": "8", ++ "loc": "0x31", ++ "offset": 0, ++ "size": 4 ++ }, ++ "callback": "cpld_format", ++ "arrt_index": 4, ++ }, ++ ++ "psu": { ++ "key": "PSU", ++ "next": "fan" ++ }, ++ ++ "psu1": { ++ "parent": "psu", ++ "key": "PSU1", ++ "arrt_index": 1, ++ }, ++ "psu1_hw_version": { ++ "key": "Hardware Version", ++ "parent": "psu1", ++ "extra": { ++ "funcname": "getPsu", ++ "id": "psu1", ++ "key": "hw_version" ++ }, ++ "arrt_index": 1, ++ }, ++ "psu1_fw_version": { ++ "key": "Firmware Version", ++ "parent": "psu1", ++ "config": "NA", ++ "arrt_index": 2, ++ }, ++ ++ "psu2": { ++ "parent": "psu", ++ "key": "PSU2", ++ "arrt_index": 2, ++ }, ++ "psu2_hw_version": { ++ "key": "Hardware Version", ++ "parent": "psu2", ++ "extra": { ++ "funcname": "getPsu", ++ "id": "psu2", ++ "key": "hw_version" ++ }, ++ "arrt_index": 1, ++ }, ++ "psu2_fw_version": { ++ "key": "Firmware Version", ++ "parent": "psu2", ++ "config": "NA", ++ "arrt_index": 2, ++ }, ++ ++ "fan": { ++ "key": "FAN", ++ "next": "i210" ++ }, ++ ++ "fan1": { ++ "key": "FAN1", ++ "parent": "fan", ++ "arrt_index": 1, ++ }, ++ "fan1_hw_version": { ++ "key": "Hardware Version", ++ "parent": "fan1", ++ "extra": { ++ "funcname": "checkFan", ++ "id": "fan1", ++ "key": "hw_version" ++ }, ++ "arrt_index": 1, ++ }, ++ "fan1_fw_version": { ++ "key": "Firmware Version", ++ "parent": "fan1", ++ "config": "NA", ++ "arrt_index": 2, ++ }, ++ ++ "fan2": { ++ "key": "FAN2", ++ "parent": "fan", ++ "arrt_index": 2, ++ }, ++ "fan2_hw_version": { ++ "key": "Hardware Version", ++ "parent": "fan2", ++ "extra": { ++ "funcname": "checkFan", ++ "id": "fan2", ++ "key": "hw_version" ++ }, ++ "arrt_index": 1, ++ }, ++ "fan2_fw_version": { ++ "key": "Firmware Version", ++ "parent": "fan2", ++ "config": "NA", ++ "arrt_index": 2, ++ }, ++ ++ "fan3": { ++ "key": "FAN3", ++ "parent": "fan", ++ "arrt_index": 3, ++ }, ++ "fan3_hw_version": { ++ "key": "Hardware Version", ++ "parent": "fan3", ++ "extra": { ++ "funcname": "checkFan", ++ "id": "fan3", ++ "key": "hw_version" ++ }, ++ "arrt_index": 1, ++ }, ++ "fan3_fw_version": { ++ "key": "Firmware Version", ++ "parent": "fan3", ++ "config": "NA", ++ "arrt_index": 2, ++ }, ++ ++ "fan4": { ++ "key": "FAN4", ++ "parent": "fan", ++ "arrt_index": 4, ++ }, ++ "fan4_hw_version": { ++ "key": "Hardware Version", ++ "parent": "fan4", ++ "extra": { ++ "funcname": "checkFan", ++ "id": "fan4", ++ "key": "hw_version" ++ }, ++ "arrt_index": 1, ++ }, ++ "fan4_fw_version": { ++ "key": "Firmware Version", ++ "parent": "fan4", ++ "config": "NA", ++ "arrt_index": 2, ++ }, ++ ++ "i210": { ++ "key": "NIC", ++ "next": "fpga" ++ }, ++ "i210_model": { ++ "parent": "i210", ++ "config": "NA", ++ "key": "Device Model", ++ "arrt_index": 1, ++ }, ++ "i210_vendor": { ++ "parent": "i210", ++ "config": "INTEL", ++ "key": "Vendor", ++ "arrt_index": 2, ++ }, ++ "i210_version": { ++ "parent": "i210", ++ "cmd": "ethtool -i eth0", ++ "pattern": r"firmware-version", ++ "separator": ":", ++ "key": "Firmware Version", ++ "arrt_index": 3, ++ }, ++ ++ "fpga": { ++ "key": "FPGA", ++ "next": "asic" ++ }, ++ "fpga_model": { ++ "parent": "fpga", ++ "config": "XC7A15T-2FGG484C", ++ "key": "Device Model", ++ "arrt_index": 1, ++ }, ++ "fpga_vendor": { ++ "parent": "fpga", ++ "config": "XILINX", ++ "key": "Vendor", ++ "arrt_index": 2, ++ }, ++ "fpga_desc": { ++ "parent": "fpga", ++ "config": "NA", ++ "key": "Description", ++ "arrt_index": 3, ++ }, ++ "fpga_hw_version": { ++ "parent": "fpga", ++ "config": "NA", ++ "key": "Hardware Version", ++ "arrt_index": 4, ++ }, ++ "fpga_fw_version": { ++ "parent": "fpga", ++ "pci": { ++ "bus": 8, ++ "slot": 0, ++ "fn": 0, ++ "bar": 0, ++ "offset": 0 ++ }, ++ "key": "Firmware Version", ++ "arrt_index": 5, ++ }, ++ "fpga_date": { ++ "parent": "fpga", ++ "pci": { ++ "bus": 8, ++ "slot": 0, ++ "fn": 0, ++ "bar": 0, ++ "offset": 4 ++ }, ++ "key": "Build Date", ++ "arrt_index": 6, ++ }, ++ "asic": { ++ "key": "ASIC", ++ }, ++ "sdk_model": { ++ "parent": "asic", ++ "cmd": "bcmcmd -t 1 att", ++ "pattern": r"^Attach", ++ "regular": r"(?<=\()[^)]*(?=\))", ++ "key": "Device Model", ++ "arrt_index": 1, ++ }, ++ "sdk_version": { ++ "parent": "asic", ++ "cmd": "bcmcmd -t 1 version | grep Release", ++ "pattern": r".*Release", ++ "separator": ":", ++ "key": "SDK Version", ++ "arrt_index": 2, ++ }, ++ "pci_version": { ++ "parent": "asic", ++ "cmd": "bcmcmd -t 1 \"pciephy fw version\" |grep \"PCIe FW version\"", ++ "pattern": r".*PCIe FW version", ++ "separator": ":", ++ "key": "PCIe Firmware Version", ++ "arrt_index": 3, ++ }, ++} ++ ++PMON_SYSLOG_STATUS = { ++ "polling_time": 3, ++ "sffs": { ++ "present": {"path": ["/sys/wb_plat/sff/*/present"], "ABSENT": 0}, ++ "nochangedmsgflag": 0, ++ "nochangedmsgtime": 60, ++ "noprintfirsttimeflag": 1, ++ "alias": { ++ "sff1": "Ethernet1", ++ "sff2": "Ethernet2", ++ "sff3": "Ethernet3", ++ "sff4": "Ethernet4", ++ "sff5": "Ethernet5", ++ "sff6": "Ethernet6", ++ "sff7": "Ethernet7", ++ "sff8": "Ethernet8", ++ "sff9": "Ethernet9", ++ "sff10": "Ethernet10", ++ "sff11": "Ethernet11", ++ "sff12": "Ethernet12", ++ "sff13": "Ethernet13", ++ "sff14": "Ethernet14", ++ "sff15": "Ethernet15", ++ "sff16": "Ethernet16", ++ "sff17": "Ethernet17", ++ "sff18": "Ethernet18", ++ "sff19": "Ethernet19", ++ "sff20": "Ethernet20", ++ "sff21": "Ethernet21", ++ "sff22": "Ethernet22", ++ "sff23": "Ethernet23", ++ "sff24": "Ethernet24", ++ "sff25": "Ethernet25", ++ "sff26": "Ethernet26", ++ "sff27": "Ethernet27", ++ "sff28": "Ethernet28", ++ "sff29": "Ethernet29", ++ "sff30": "Ethernet30", ++ "sff31": "Ethernet31", ++ "sff32": "Ethernet32", ++ "sff33": "Ethernet33", ++ "sff34": "Ethernet34", ++ "sff35": "Ethernet35", ++ "sff36": "Ethernet36", ++ "sff37": "Ethernet37", ++ "sff38": "Ethernet38", ++ "sff39": "Ethernet39", ++ "sff40": "Ethernet40", ++ "sff41": "Ethernet41", ++ "sff42": "Ethernet42", ++ "sff43": "Ethernet43", ++ "sff44": "Ethernet44", ++ "sff45": "Ethernet45", ++ "sff46": "Ethernet46", ++ "sff47": "Ethernet47", ++ "sff48": "Ethernet48", ++ "sff49": "Ethernet49", ++ "sff50": "Ethernet50", ++ "sff51": "Ethernet51", ++ "sff52": "Ethernet52", ++ "sff53": "Ethernet53", ++ "sff54": "Ethernet54", ++ "sff55": "Ethernet55", ++ "sff56": "Ethernet56", ++ } ++ }, ++ "fans": { ++ "present": {"path": ["/sys/wb_plat/fan/*/present"], "ABSENT": 0}, ++ "status": [ ++ {"path": "/sys/wb_plat/fan/%s/motor0/status", 'okval': 1}, ++ {"path": "/sys/wb_plat/fan/%s/motor1/status", 'okval': 1}, ++ ], ++ "nochangedmsgflag": 1, ++ "nochangedmsgtime": 60, ++ "noprintfirsttimeflag": 0, ++ "alias": { ++ "fan1": "FAN1", ++ "fan2": "FAN2", ++ "fan3": "FAN3", ++ "fan4": "FAN4" ++ } ++ }, ++ "psus": { ++ "present": {"path": ["/sys/wb_plat/psu/*/present"], "ABSENT": 0}, ++ "status": [ ++ {"path": "/sys/wb_plat/psu/%s/output", "okval": 1}, ++ {"path": "/sys/wb_plat/psu/%s/alert", "okval": 0}, ++ ], ++ "nochangedmsgflag": 1, ++ "nochangedmsgtime": 60, ++ "noprintfirsttimeflag": 0, ++ "alias": { ++ "psu1": "PSU1", ++ "psu2": "PSU2" ++ } ++ } ++} ++ ++##################### MAC Voltage adjust#################################### ++MAC_DEFAULT_PARAM = [ ++ { ++ "name": "mac_core", # AVS name ++ "type": 1, # 1: used default value, if rov value not in range. 0: do nothing, if rov value not in range ++ "default": 0x74, # default value, if rov value not in range ++ "sdkreg": "TOP_AVS_SEL_REG", # SDK register name ++ "sdktype": 0, # 0: No shift operation required, 1: shift operation required ++ "macregloc": 24, # Shift right 24 bits ++ "mask": 0xff, # Use with macregloc ++ "rov_source": 1, # 0:get rov value from cpld, 1: get rov value from SDK ++ "cpld_avs": {"bus": 6, "loc": 0x0d, "offset": 0xc3, "gettype": "i2c"}, ++ "set_avs": { ++ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/avs0_vout", ++ "gettype": "sysfs", "formula": "int((%f)*1000000)" ++ }, ++ "mac_avs_param": { ++ 0x08: 0.888, ++ 0x72: 0.900, ++ 0x73: 0.894, ++ 0x74: 0.888, ++ 0x75: 0.882, ++ 0x76: 0.875, ++ 0x77: 0.869, ++ 0x78: 0.863, ++ 0x79: 0.857, ++ 0x7a: 0.850, ++ 0x7b: 0.844, ++ 0x7c: 0.838, ++ 0x7d: 0.832, ++ 0x7e: 0.825, ++ 0x7f: 0.819, ++ 0x80: 0.813, ++ 0x81: 0.807, ++ 0x82: 0.800, ++ 0x83: 0.794, ++ 0x84: 0.788, ++ 0x85: 0.782, ++ 0x86: 0.775, ++ 0x87: 0.769, ++ 0x88: 0.763, ++ 0x89: 0.757, ++ 0x8A: 0.750 ++ } ++ } ++] ++ ++BLACKLIST_DRIVERS = [ ++ {"name": "i2c_i801", "delay": 0}, ++] ++ ++DRIVERLISTS = [ ++ {"name": "wb_i2c_i801", "delay": 0}, ++ {"name": "wb_gpio_d1500", "delay": 0}, ++ {"name": "i2c_dev", "delay": 0}, ++ {"name": "wb_i2c_algo_bit", "delay": 0}, ++ {"name": "wb_i2c_gpio", "delay": 0}, ++ {"name": "i2c_mux", "delay": 0}, ++ {"name": "wb_gpio_device", "delay": 0}, ++ {"name": "wb_i2c_gpio_device gpio_sda=17 gpio_scl=1 gpio_udelay=2", "delay": 0}, ++ {"name": "platform_common dfd_my_type=0x404a", "delay": 0}, ++ {"name": "wb_lpc_drv", "delay": 0}, ++ {"name": "wb_lpc_drv_device", "delay": 0}, ++ {"name": "wb_io_dev", "delay": 0}, ++ {"name": "wb_io_dev_device", "delay": 0}, ++ {"name": "wb_fpga_pcie", "delay": 0}, ++ {"name": "wb_pcie_dev", "delay": 0}, ++ {"name": "wb_pcie_dev_device", "delay": 0}, ++ {"name": "wb_i2c_dev", "delay": 0}, ++ {"name": "wb_i2c_ocores", "delay": 0}, ++ {"name": "wb_i2c_ocores_device", "delay": 0}, ++ {"name": "wb_i2c_mux_pca9641", "delay": 0}, ++ {"name": "wb_i2c_mux_pca954x", "delay": 0}, ++ {"name": "wb_i2c_mux_pca954x_device", "delay": 0}, ++ {"name": "wb_i2c_dev_device", "delay": 0}, ++ {"name": "wb_lm75", "delay": 0}, ++ {"name": "wb_optoe", "delay": 0}, ++ {"name": "wb_at24", "delay": 0}, ++ {"name": "wb_mac_bsc", "delay": 0}, ++ {"name": "wb_pmbus_core", "delay": 0}, ++ {"name": "wb_isl68137", "delay": 0}, ++ {"name": "wb_csu550", "delay": 0}, ++ {"name": "wb_ina3221", "delay": 0}, ++ {"name": "wb_tps53622", "delay": 0}, ++ {"name": "plat_dfd", "delay": 0}, ++ {"name": "plat_switch", "delay": 0}, ++ {"name": "plat_fan", "delay": 0}, ++ {"name": "plat_psu", "delay": 0}, ++ {"name": "plat_sff", "delay": 0}, ++] ++ ++DEVICE = [ ++ {"name": "wb_24c02", "bus": 0, "loc": 0x56}, ++ {"name": "wb_mac_bsc_td3", "bus": 3, "loc": 0x44}, ++ # fan ++ {"name": "wb_24c02", "bus": 16, "loc": 0x50}, ++ {"name": "wb_24c02", "bus": 17, "loc": 0x50}, ++ {"name": "wb_24c02", "bus": 18, "loc": 0x50}, ++ {"name": "wb_24c02", "bus": 19, "loc": 0x50}, ++ # psu ++ {"name": "wb_24c02", "bus": 24, "loc": 0x50}, ++ {"name": "wb_dps550", "bus": 24, "loc": 0x58}, ++ {"name": "wb_24c02", "bus": 25, "loc": 0x50}, ++ {"name": "wb_dps550", "bus": 25, "loc": 0x58}, ++ # temp ++ {"name": "wb_lm75", "bus": 3, "loc": 0x48}, ++ {"name": "wb_lm75", "bus": 3, "loc": 0x49}, ++ {"name": "wb_lm75", "bus": 3, "loc": 0x4a}, ++ {"name": "wb_lm75", "bus": 3, "loc": 0x4b}, ++ {"name": "wb_lm75", "bus": 3, "loc": 0x4c}, ++ # dcdc ++ {"name": "wb_ina3221", "bus": 7, "loc": 0x40}, ++ {"name": "wb_ina3221", "bus": 7, "loc": 0x41}, ++ {"name": "wb_ina3221", "bus": 7, "loc": 0x42}, ++ {"name": "wb_ina3221", "bus": 7, "loc": 0x43}, ++ {"name": "wb_tps53622", "bus": 7, "loc": 0x60}, ++ {"name": "wb_tps53622", "bus": 7, "loc": 0x6c}, ++ {"name": "wb_isl68127", "bus": 7, "loc": 0x64}, ++] ++ ++OPTOE = [ ++ {"name": "wb_optoe2", "startbus": 32, "endbus": 79}, ++ {"name": "wb_optoe1", "startbus": 80, "endbus": 87}, ++] ++ ++DEV_MONITOR_PARAM = { ++ "polling_time": 10, ++ "psus": [ ++ { ++ "name": "psu1", ++ "present": {"gettype": "i2c", "bus": 6, "loc": 0x0d, "offset": 0x51, "presentbit": 0, "okval": 0}, ++ "device": [ ++ {"id": "psu1pmbus", "name": "wb_dps550", "bus": 24, "loc": 0x58, "attr": "hwmon"}, ++ {"id": "psu1frue2", "name": "wb_24c02", "bus": 24, "loc": 0x50, "attr": "eeprom"}, ++ ], ++ }, ++ { ++ "name": "psu2", ++ "present": {"gettype": "i2c", "bus": 6, "loc": 0x0d, "offset": 0x51, "presentbit": 4, "okval": 0}, ++ "device": [ ++ {"id": "psu2pmbus", "name": "wb_dps550", "bus": 25, "loc": 0x58, "attr": "hwmon"}, ++ {"id": "psu2frue2", "name": "wb_24c02", "bus": 25, "loc": 0x50, "attr": "eeprom"}, ++ ], ++ }, ++ ], ++ "fans": [ ++ { ++ "name": "fan1", ++ "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 0, "okval": 0}, ++ "device": [ ++ {"id": "fan1frue2", "name": "24c02", "bus": 16, "loc": 0x50, "attr": "eeprom"}, ++ ], ++ }, ++ { ++ "name": "fan2", ++ "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 1, "okval": 0}, ++ "device": [ ++ {"id": "fan2frue2", "name": "24c02", "bus": 17, "loc": 0x50, "attr": "eeprom"}, ++ ], ++ }, ++ { ++ "name": "fan3", ++ "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 2, "okval": 0}, ++ "device": [ ++ {"id": "fan3frue2", "name": "24c02", "bus": 18, "loc": 0x50, "attr": "eeprom"}, ++ ], ++ }, ++ { ++ "name": "fan4", ++ "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 3, "okval": 0}, ++ "device": [ ++ {"id": "fan4frue2", "name": "24c02", "bus": 19, "loc": 0x50, "attr": "eeprom"}, ++ ], ++ }, ++ ], ++ "others": [ ++ { ++ "name": "eeprom", ++ "device": [ ++ {"id": "eeprom_1", "name": "wb_24c02", "bus": 0, "loc": 0x56, "attr": "eeprom"}, ++ ], ++ }, ++ { ++ "name": "lm75", ++ "device": [ ++ {"id": "lm75_1", "name": "wb_lm75", "bus": 3, "loc": 0x48, "attr": "hwmon"}, ++ {"id": "lm75_2", "name": "wb_lm75", "bus": 3, "loc": 0x49, "attr": "hwmon"}, ++ {"id": "lm75_3", "name": "wb_lm75", "bus": 3, "loc": 0x4a, "attr": "hwmon"}, ++ {"id": "lm75_4", "name": "wb_lm75", "bus": 3, "loc": 0x4b, "attr": "hwmon"}, ++ {"id": "lm75_5", "name": "wb_lm75", "bus": 3, "loc": 0x4c, "attr": "hwmon"}, ++ ], ++ }, ++ { ++ "name": "mac_bsc", ++ "device": [ ++ {"id": "mac_bsc_1", "name": "wb_mac_bsc_td3", "bus": 3, "loc": 0x44, "attr": "hwmon"}, ++ ], ++ }, ++ { ++ "name": "ina3221", ++ "device": [ ++ {"id": "ina3221_1", "name": "wb_ina3221", "bus": 7, "loc": 0x40, "attr": "hwmon"}, ++ {"id": "ina3221_2", "name": "wb_ina3221", "bus": 7, "loc": 0x41, "attr": "hwmon"}, ++ {"id": "ina3221_3", "name": "wb_ina3221", "bus": 7, "loc": 0x42, "attr": "hwmon"}, ++ {"id": "ina3221_4", "name": "wb_ina3221", "bus": 7, "loc": 0x43, "attr": "hwmon"}, ++ ], ++ }, ++ { ++ "name": "tps53622", ++ "device": [ ++ {"id": "tps53622_1", "name": "wb_tps53622", "bus": 7, "loc": 0x60, "attr": "hwmon"}, ++ {"id": "tps53622_2", "name": "wb_tps53622", "bus": 7, "loc": 0x6c, "attr": "hwmon"}, ++ ], ++ }, ++ { ++ "name": "isl68127", ++ "device": [ ++ {"id": "isl68127_1", "name": "wb_isl68127", "bus": 7, "loc": 0x64, "attr": "hwmon"}, ++ ], ++ } ++ ], ++} ++ ++INIT_PARAM_PRE = [ ++ {"loc": "7-0064/hwmon/hwmon*/avs0_vout_max", "value": "900000"}, ++ {"loc": "7-0064/hwmon/hwmon*/avs0_vout_min", "value": "750000"}, ++] ++INIT_COMMAND_PRE = [ ++ "i2cset -y -f 6 0x0d 0x91 0x48", ++ "i2cset -y -f 6 0x0d 0x92 0x01", # MAC_PWR_EN ++ "i2cset -y -f 6 0x0d 0x94 0x01", # SFF_PWR_EN ++ "i2cset -y -f 6 0x0d 0xbf 0x01", # enbale tty_console monitor ++] ++ ++INIT_PARAM = [] ++ ++INIT_COMMAND = [ ++ "i2cset -y -f 8 0x30 0x60 0x00", # enable txdis[1~8] ++ "i2cset -y -f 8 0x30 0x61 0x00", # enable txdis[9~16] ++ "i2cset -y -f 8 0x30 0x62 0x00", # enable txdis[17~24] ++ "i2cset -y -f 8 0x31 0x60 0x00", # enable txdis[24~32] ++ "i2cset -y -f 8 0x31 0x61 0x00", # enable txdis[33~40] ++ "i2cset -y -f 8 0x31 0x62 0x00", # enable txdis[41~48] ++] ++ ++REBOOT_CAUSE_PARA = { ++ "reboot_cause_list": [ ++ { ++ "name": "otp_switch_reboot", ++ "monitor_point": {"gettype": "file_exist", "judge_file": "/etc/.otp_switch_reboot_flag", "okval": True}, ++ "record": [ ++ {"record_type": "file", "mode": "cover", "log": "Thermal Overload: ASIC, ", ++ "path": "/etc/sonic/.reboot/.previous-reboot-cause.txt"}, ++ {"record_type": "file", "mode": "add", "log": "Thermal Overload: ASIC, ", ++ "path": "/etc/sonic/.reboot/.history-reboot-cause.txt", "file_max_size": 1 * 1024 * 1024} ++ ], ++ "finish_operation": [ ++ {"gettype": "cmd", "cmd": "rm -rf /etc/.otp_switch_reboot_flag"}, ++ ] ++ }, ++ { ++ "name": "otp_other_reboot", ++ "monitor_point": {"gettype": "file_exist", "judge_file": "/etc/.otp_other_reboot_flag", "okval": True}, ++ "record": [ ++ {"record_type": "file", "mode": "cover", "log": "Thermal Overload: Other, ", ++ "path": "/etc/sonic/.reboot/.previous-reboot-cause.txt"}, ++ {"record_type": "file", "mode": "add", "log": "Thermal Overload: Other, ", ++ "path": "/etc/sonic/.reboot/.history-reboot-cause.txt", "file_max_size": 1 * 1024 * 1024} ++ ], ++ "finish_operation": [ ++ {"gettype": "cmd", "cmd": "rm -rf /etc/.otp_other_reboot_flag"}, ++ ] ++ }, ++ ], ++ "other_reboot_cause_record": [ ++ {"record_type": "file", "mode": "cover", "log": "Other, ", "path": "/etc/sonic/.reboot/.previous-reboot-cause.txt"}, ++ {"record_type": "file", "mode": "add", "log": "Other, ", "path": "/etc/sonic/.reboot/.history-reboot-cause.txt"} ++ ], ++} ++ ++UPGRADE_SUMMARY = { ++ "devtype": 0x404a, ++ ++ "slot0": { ++ "subtype": 0, ++ "VME": { ++ "chain1": { ++ "name": "VME_CPLD", ++ "is_support_warm_upg": 0, ++ }, ++ }, ++ ++ "SPI-LOGIC-DEV": { ++ "chain3": { ++ "name": "FPGA", ++ "is_support_warm_upg": 0, ++ }, ++ }, ++ ++ "MTD": { ++ "chain2": { ++ "name": "BIOS", ++ "is_support_warm_upg": 0, ++ "filesizecheck": 10240, # bios check file size, Unit: K ++ "init_cmd": [ ++ {"io_addr": 0x722, "value": 0x02, "gettype": "io"}, ++ {"cmd": "modprobe mtd", "gettype": "cmd"}, ++ {"cmd": "modprobe spi_nor", "gettype": "cmd"}, ++ {"cmd": "modprobe ofpart", "gettype": "cmd"}, ++ {"cmd": "modprobe intel_spi writeable=1", "gettype": "cmd"}, ++ {"cmd": "modprobe intel_spi_platform writeable=1", "gettype": "cmd"}, ++ ], ++ "finish_cmd": [ ++ {"cmd": "rmmod intel_spi_platform", "gettype": "cmd"}, ++ {"cmd": "rmmod intel_spi", "gettype": "cmd"}, ++ {"cmd": "rmmod ofpart", "gettype": "cmd"}, ++ {"cmd": "rmmod spi_nor", "gettype": "cmd"}, ++ {"cmd": "rmmod mtd", "gettype": "cmd"}, ++ ], ++ }, ++ }, ++ ++ "TEST": { ++ "cpld": [ ++ {"chain": 1, "file": "/etc/.upgrade_test/cpld_test_header.vme", "display_name": "CPLD"}, ++ ], ++ "fpga": [ ++ { ++ "chain": 3, ++ "file": "/etc/.upgrade_test/fpga_test_header.bin", ++ "display_name": "FPGA", ++ }, ++ ], ++ }, ++ }, ++ ++ "BMC": { ++ "name": "BMC", ++ "init_cmd": [ ++ ], ++ "finish_cmd": [], ++ }, ++} ++ ++ ++PLATFORM_E2_CONF = { ++ "fan": [ ++ { ++ "name": "fan1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/16-0050/eeprom", ++ "e2_decode": [ ++ { ++ "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" ++ }, ++ { ++ "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" ++ }, ++ ], ++ }, ++ { ++ "name": "fan2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/17-0050/eeprom", ++ "e2_decode": [ ++ { ++ "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" ++ }, ++ { ++ "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" ++ }, ++ ], ++ }, ++ { ++ "name": "fan3", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/18-0050/eeprom", ++ "e2_decode": [ ++ { ++ "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" ++ }, ++ { ++ "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" ++ }, ++ ], ++ }, ++ { ++ "name": "fan4", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/19-0050/eeprom", ++ "e2_decode": [ ++ { ++ "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" ++ }, ++ { ++ "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" ++ }, ++ ], ++ }, ++ ], ++ "psu": [ ++ {"name": "psu1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/24-0050/eeprom"}, ++ {"name": "psu2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/25-0050/eeprom"}, ++ ], ++ "syseeprom": [ ++ {"name": "syseeprom", "e2_type": "onie_tlv", "e2_path": "/sys/bus/i2c/devices/0-0056/eeprom"}, ++ ], ++} ++ ++AIR_FLOW_CONF = { ++ "psu_fan_airflow": { ++ "intake": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3', 'U1D-D10800-DRB'], ++ "exhaust": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'] ++ }, ++ ++ "fanairflow": { ++ "intake": ['M1HFAN III-F'], ++ "exhaust": ['M1HFAN III-R'] ++ }, ++ ++ "fans": [ ++ { ++ "name": "FAN1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/16-0050/eeprom", ++ "area": "productInfoArea", "field": "productName", "decode": "fanairflow" ++ }, ++ { ++ "name": "FAN2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/17-0050/eeprom", ++ "area": "productInfoArea", "field": "productName", "decode": "fanairflow" ++ }, ++ { ++ "name": "FAN3", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/18-0050/eeprom", ++ "area": "productInfoArea", "field": "productName", "decode": "fanairflow" ++ }, ++ { ++ "name": "FAN4", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/19-0050/eeprom", ++ "area": "productInfoArea", "field": "productName", "decode": "fanairflow" ++ } ++ ], ++ ++ "psus": [ ++ { ++ "name": "PSU1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/24-0050/eeprom", ++ "area": "productInfoArea", "field": "productPartModelName", "decode": "psu_fan_airflow" ++ }, ++ { ++ "name": "PSU2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/25-0050/eeprom", ++ "area": "productInfoArea", "field": "productPartModelName", "decode": "psu_fan_airflow" ++ } ++ ] ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_port_config.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_port_config.py +new file mode 100755 +index 000000000..26f92a77a +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_port_config.py +@@ -0,0 +1,7 @@ ++#!/usr/bin/python3 ++# -*- coding: UTF-8 -*- ++ ++PLATFORM_INTF_OPTOE = { ++ "port_num": 56, ++ "optoe_start_bus": 32, ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_device.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_device.py +new file mode 100755 +index 000000000..c1eb46247 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_device.py +@@ -0,0 +1,1371 @@ ++#!/usr/bin/python3 ++ ++psu_fan_airflow = { ++ "intake": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3', 'U1D-D10800-DRB'], ++ "exhaust": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'] ++} ++ ++fanairflow = { ++ "intake": ['M1HFAN III-F'], ++ "exhaust": ['M1HFAN III-R'], ++} ++ ++psu_display_name = { ++ "PA550II-F": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3'], ++ "PA550II-R": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'], ++ "PD800I-F": ['U1D-D10800-DRB'] ++} ++ ++psutypedecode = { ++ 0x00: 'N/A', ++ 0x01: 'AC', ++ 0x02: 'DC', ++} ++ ++ ++class Unit: ++ Temperature = "C" ++ Voltage = "V" ++ Current = "A" ++ Power = "W" ++ Speed = "RPM" ++ ++ ++PSU_NOT_PRESENT_PWM = 100 ++ ++ ++class threshold: ++ PSU_TEMP_MIN = -20 * 1000 ++ PSU_TEMP_MAX = 60 * 1000 ++ ++ PSU_FAN_SPEED_MIN = 2000 ++ PSU_FAN_SPEED_MAX = 18000 ++ ++ PSU_OUTPUT_VOLTAGE_MIN = 11 * 1000 ++ PSU_OUTPUT_VOLTAGE_MAX = 14 * 1000 ++ ++ PSU_AC_INPUT_VOLTAGE_MIN = 200 * 1000 ++ PSU_AC_INPUT_VOLTAGE_MAX = 240 * 1000 ++ ++ PSU_DC_INPUT_VOLTAGE_MIN = 190 * 1000 ++ PSU_DC_INPUT_VOLTAGE_MAX = 290 * 1000 ++ ++ ERR_VALUE = -9999999 ++ ++ PSU_OUTPUT_POWER_MIN = 10 * 1000 * 1000 ++ PSU_OUTPUT_POWER_MAX = 560 * 1000 * 1000 ++ ++ PSU_INPUT_POWER_MIN = 10 * 1000 * 1000 ++ PSU_INPUT_POWER_MAX = 625 * 1000 * 1000 ++ ++ PSU_OUTPUT_CURRENT_MIN = 1 * 1000 ++ PSU_OUTPUT_CURRENT_MAX = 45 * 1000 ++ ++ PSU_INPUT_CURRENT_MIN = 0 * 1000 ++ PSU_INPUT_CURRENT_MAX = 7 * 1000 ++ ++ FRONT_FAN_SPEED_MAX = 24000 ++ REAR_FAN_SPEED_MAX = 22500 ++ FAN_SPEED_MIN = 5000 ++ ++ ++ ASPOWER_DC_PSU_TEMP_MIN = -10 * 1000 ++ ASPOWER_DC_PSU_TEMP_MAX = 55 * 1000 ++ ++ ASPOWER_DC_PSU_FAN_SPEED_MIN = 800 ++ ASPOWER_DC_PSU_FAN_SPEED_MAX = 24000 ++ ++ ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN = 11.4 * 1000 ++ ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX = 12.6 * 1000 ++ ++ ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN = 36 * 1000 ++ ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX = 72 * 1000 ++ ++ ASPOWER_DC_ERR_VALUE = -9999999 ++ ++ ASPOWER_DC_PSU_OUTPUT_POWER_MIN = 5 * 1000 * 1000 ++ ASPOWER_DC_PSU_OUTPUT_POWER_MAX = 800 * 1000 * 1000 ++ ++ ASPOWER_DC_PSU_INPUT_POWER_MIN = 5 * 1000 * 1000 ++ ASPOWER_DC_PSU_INPUT_POWER_MAX = 880 * 1000 * 1000 ++ ++ ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN = 0.5 * 1000 ++ ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX = 66 * 1000 ++ ++ ASPOWER_DC_PSU_INPUT_CURRENT_MIN = 1 * 1000 ++ ASPOWER_DC_PSU_INPUT_CURRENT_MAX = 28 * 1000 ++ ++ ++class Description: ++ CPLD = "Used for managing IO modules, SFP+ modules and system LEDs" ++ BIOS = "Performs initialization of hardware components during booting" ++ FPGA = "Platform management controller for on-board temperature monitoring, in-chassis power" ++ ++ ++devices = { ++ "onie_e2": [ ++ { ++ "name": "ONIE_E2", ++ "e2loc": {"loc": "/sys/bus/i2c/devices/0-0056/eeprom", "way": "sysfs"}, ++ "airflow": "intake" ++ }, ++ ], ++ "psus": [ ++ { ++ "e2loc": {"loc": "/sys/bus/i2c/devices/24-0050/eeprom", "way": "sysfs"}, ++ "pmbusloc": {"bus": 24, "addr": 0x58, "way": "i2c"}, ++ "present": {"loc": "/sys/wb_plat/psu/psu1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, ++ "name": "PSU1", ++ "get_threshold_by_model": 1, ++ "psu_display_name": psu_display_name, ++ "airflow": psu_fan_airflow, ++ "TempStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, ++ "other": threshold.PSU_TEMP_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, ++ "other": threshold.PSU_TEMP_MAX, ++ }, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ }, ++ "FanStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, ++ "FanSpeed": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, ++ "other": threshold.PSU_FAN_SPEED_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, ++ "other": threshold.PSU_FAN_SPEED_MAX, ++ }, ++ "Unit": Unit.Speed ++ }, ++ "psu_fan_tolerance": 40, ++ "InputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, ++ "InputsType": {"bus": 24, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, ++ "InputsVoltage": { ++ 'AC': { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, ++ "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, ++ "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ ++ }, ++ 'DC': { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, ++ "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, ++ "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, ++ }, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ }, ++ 'other': { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, ++ "other": threshold.ERR_VALUE, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, ++ "other": threshold.ERR_VALUE, ++ }, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ "InputsCurrent": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, ++ "other": threshold.PSU_INPUT_CURRENT_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, ++ "other": threshold.PSU_INPUT_CURRENT_MAX, ++ }, ++ "Unit": Unit.Current, ++ "format": "float(float(%s)/1000)" ++ }, ++ "InputsPower": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, ++ "other": threshold.PSU_INPUT_POWER_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, ++ "other": threshold.PSU_INPUT_POWER_MAX, ++ }, ++ "Unit": Unit.Power, ++ "format": "float(float(%s)/1000000)" ++ }, ++ "OutputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, ++ "OutputsVoltage": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, ++ "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, ++ "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, ++ }, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ }, ++ "OutputsCurrent": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, ++ "other": threshold.PSU_OUTPUT_CURRENT_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, ++ "other": threshold.PSU_OUTPUT_CURRENT_MAX, ++ }, ++ "Unit": Unit.Current, ++ "format": "float(float(%s)/1000)" ++ }, ++ "OutputsPower": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, ++ "other": threshold.PSU_OUTPUT_POWER_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, ++ "other": threshold.PSU_OUTPUT_POWER_MAX, ++ }, ++ "Unit": Unit.Power, ++ "format": "float(float(%s)/1000000)" ++ }, ++ }, ++ { ++ "e2loc": {"loc": "/sys/bus/i2c/devices/25-0050/eeprom", "way": "sysfs"}, ++ "pmbusloc": {"bus": 25, "addr": 0x58, "way": "i2c"}, ++ "present": {"loc": "/sys/wb_plat/psu/psu2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, ++ "name": "PSU2", ++ "get_threshold_by_model": 1, ++ "psu_display_name": psu_display_name, ++ "airflow": psu_fan_airflow, ++ "TempStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, ++ "other": threshold.PSU_TEMP_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, ++ "other": threshold.PSU_TEMP_MAX, ++ }, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ }, ++ "FanStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, ++ "FanSpeed": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, ++ "other": threshold.PSU_FAN_SPEED_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, ++ "other": threshold.PSU_FAN_SPEED_MAX, ++ }, ++ "Unit": Unit.Speed ++ }, ++ "psu_fan_tolerance": 40, ++ "InputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, ++ "InputsType": {"bus": 25, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, ++ "InputsVoltage": { ++ 'AC': { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, ++ "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, ++ "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ ++ }, ++ 'DC': { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, ++ "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, ++ "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, ++ }, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ }, ++ 'other': { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, ++ "other": threshold.ERR_VALUE, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, ++ "other": threshold.ERR_VALUE, ++ }, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ "InputsCurrent": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, ++ "other": threshold.PSU_INPUT_CURRENT_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, ++ "other": threshold.PSU_INPUT_CURRENT_MAX, ++ }, ++ "Unit": Unit.Current, ++ "format": "float(float(%s)/1000)" ++ }, ++ "InputsPower": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, ++ "other": threshold.PSU_INPUT_POWER_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, ++ "other": threshold.PSU_INPUT_POWER_MAX, ++ }, ++ "Unit": Unit.Power, ++ "format": "float(float(%s)/1000000)" ++ }, ++ "OutputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, ++ "OutputsVoltage": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, ++ "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, ++ "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, ++ }, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ }, ++ "OutputsCurrent": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, ++ "other": threshold.PSU_OUTPUT_CURRENT_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, ++ "other": threshold.PSU_OUTPUT_CURRENT_MAX, ++ }, ++ "Unit": Unit.Current, ++ "format": "float(float(%s)/1000)" ++ }, ++ "OutputsPower": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, ++ "other": threshold.PSU_OUTPUT_POWER_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, ++ "other": threshold.PSU_OUTPUT_POWER_MAX, ++ }, ++ "Unit": Unit.Power, ++ "format": "float(float(%s)/1000000)" ++ }, ++ } ++ ], ++ "temps": [ ++ { ++ "name": "SWITCH_TEMP", ++ "temp_id": "TEMP1", ++ "api_name": "ASIC_TEMP", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/3-0044/hwmon/hwmon*/temp99_input", "way": "sysfs"}, ++ "Min": -30000, ++ "Low": 0, ++ "High": 105000, ++ "Max": 110000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ { ++ "name": "CPU_TEMP", ++ "temp_id": "TEMP2", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/platform/devices/coretemp.0/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": -15000, ++ "Low": 0, ++ "High": 100000, ++ "Max": 102000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ { ++ "name": "INLET_TEMP", ++ "temp_id": "TEMP3", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/3-0048/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": -30000, ++ "Low": 0, ++ "High": 55000, ++ "Max": 60000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ }, ++ "fix_value": { ++ "fix_type": "config", ++ "addend": -3, ++ } ++ }, ++ { ++ "name": "OUTLET_TEMP", ++ "temp_id": "TEMP4", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/3-004c/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": -30000, ++ "Low": 0, ++ "High": 75000, ++ "Max": 80000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ { ++ "name": "BOARD_TEMP", ++ "temp_id": "TEMP5", ++ "api_name": "MAC_OUT_TEMP", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/3-004a/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": -30000, ++ "Low": 0, ++ "High": 75000, ++ "Max": 80000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ { ++ "name": "MAC_IN_TEMP", ++ "temp_id": "TEMP6", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/3-0049/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": -30000, ++ "Low": 0, ++ "High": 75000, ++ "Max": 80000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ { ++ "name": "PSU1_TEMP", ++ "temp_id": "TEMP7", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": -20000, ++ "Low": 0, ++ "High": 55000, ++ "Max": 60000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ { ++ "name": "PSU2_TEMP", ++ "temp_id": "TEMP8", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": -20000, ++ "Low": 0, ++ "High": 55000, ++ "Max": 60000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ { ++ "name": "SFF_TEMP", ++ "Temperature": { ++ "value": {"loc": "/tmp/highest_sff_temp", "way": "sysfs", "flock_path": "/tmp/highest_sff_temp"}, ++ "Min": -30000, ++ "Low": 0, ++ "High": 90000, ++ "Max": 100000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ }, ++ "invalid": -10000, ++ "error": -9999, ++ } ++ ], ++ "leds": [ ++ { ++ "name": "FRONT_SYS_LED", ++ "led_type": "SYS_LED", ++ "led": {"bus": 6, "addr": 0x0d, "offset": 0x72, "way": "i2c"}, ++ "led_attrs": { ++ "off": 0x00, "red_flash": 0x01, "red": 0x02, ++ "green_flash": 0x03, "green": 0x04, "amber_flash": 0x05, ++ "amber": 0x06, "mask": 0x07 ++ }, ++ }, ++ { ++ "name": "FRONT_PSU_LED", ++ "led_type": "PSU_LED", ++ "led": {"bus": 6, "addr": 0x0d, "offset": 0x73, "way": "i2c"}, ++ "led_attrs": { ++ "off": 0x10, "red_flash": 0x11, "red": 0x12, ++ "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, ++ "amber": 0x16, "mask": 0x17 ++ }, ++ }, ++ { ++ "name": "FRONT_FAN_LED", ++ "led_type": "FAN_LED", ++ "led": {"bus": 6, "addr": 0x0d, "offset": 0x74, "way": "i2c"}, ++ "led_attrs": { ++ "off": 0x10, "red_flash": 0x11, "red": 0x12, ++ "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, ++ "amber": 0x16, "mask": 0x17 ++ }, ++ }, ++ ], ++ "fans": [ ++ { ++ "name": "FAN1", ++ "airflow": fanairflow, ++ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-16/16-0050/eeprom', 'way': 'sysfs'}, ++ "present": {"loc": "/sys/wb_plat/fan/fan1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3b, "way": "i2c"}, ++ "led_attrs": { ++ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, ++ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, ++ "amber": 0x03, "mask": 0x0f ++ }, ++ "PowerMax": 38.4, ++ "Rotor": { ++ "Rotor1_config": { ++ "name": "Rotor1", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan1/motor1/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.FRONT_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ "Rotor2_config": { ++ "name": "Rotor2", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan1/motor0/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.REAR_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ }, ++ }, ++ { ++ "name": "FAN2", ++ "airflow": fanairflow, ++ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-17/17-0050/eeprom', 'way': 'sysfs'}, ++ "present": {"loc": "/sys/wb_plat/fan/fan2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3c, "way": "i2c"}, ++ "led_attrs": { ++ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, ++ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, ++ "amber": 0x03, "mask": 0x0f ++ }, ++ "PowerMax": 38.4, ++ "Rotor": { ++ "Rotor1_config": { ++ "name": "Rotor1", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan2/motor1/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.FRONT_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ "Rotor2_config": { ++ "name": "Rotor2", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan2/motor0/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.REAR_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ }, ++ }, ++ { ++ "name": "FAN3", ++ "airflow": fanairflow, ++ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-18/18-0050/eeprom', 'way': 'sysfs'}, ++ "present": {"loc": "/sys/wb_plat/fan/fan3/present", "way": "sysfs", "mask": 0x01, "okval": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3d, "way": "i2c"}, ++ "led_attrs": { ++ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, ++ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, ++ "amber": 0x03, "mask": 0x0f ++ }, ++ "PowerMax": 38.4, ++ "Rotor": { ++ "Rotor1_config": { ++ "name": "Rotor1", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan3/motor1/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.FRONT_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ "Rotor2_config": { ++ "name": "Rotor2", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan3/motor0/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.REAR_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ }, ++ }, ++ ++ { ++ "name": "FAN4", ++ "airflow": fanairflow, ++ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-19/19-0050/eeprom', 'way': 'sysfs'}, ++ "present": {"loc": "/sys/wb_plat/fan/fan4/present", "way": "sysfs", "mask": 0x01, "okval": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3e, "way": "i2c"}, ++ "led_attrs": { ++ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, ++ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, ++ "amber": 0x03, "mask": 0x0f ++ }, ++ "PowerMax": 38.4, ++ "Rotor": { ++ "Rotor1_config": { ++ "name": "Rotor1", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan4/motor1/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.FRONT_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ "Rotor2_config": { ++ "name": "Rotor2", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan4/motor0/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.REAR_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ }, ++ }, ++ ++ ], ++ "cplds": [ ++ { ++ "name": "CPU_CPLD", ++ "cpld_id": "CPLD1", ++ "VersionFile": {"loc": "/dev/cpld0", "offset": 0, "len": 4, "way": "devfile_ascii"}, ++ "desc": "Used for system power", ++ "slot": 0, ++ "warm": 0, ++ }, ++ { ++ "name": "CONNECT_CPLD", ++ "cpld_id": "CPLD2", ++ "VersionFile": {"loc": "/dev/cpld1", "offset": 0, "len": 4, "way": "devfile_ascii"}, ++ "desc": "Used for base functions", ++ "slot": 0, ++ "warm": 0, ++ }, ++ { ++ "name": "CONNECT_CPLD-FAN", ++ "cpld_id": "CPLD3", ++ "VersionFile": {"loc": "/dev/cpld2", "offset": 0, "len": 4, "way": "devfile_ascii"}, ++ "desc": "Used for fan modules", ++ "slot": 0, ++ "warm": 0, ++ }, ++ { ++ "name": "MAC_CPLD1", ++ "cpld_id": "CPLD4", ++ "VersionFile": {"loc": "/dev/cpld3", "offset": 0, "len": 4, "way": "devfile_ascii"}, ++ "desc": "Used for sff modules", ++ "slot": 0, ++ "warm": 0, ++ }, ++ { ++ "name": "MAC_CPLD2", ++ "cpld_id": "CPLD5", ++ "VersionFile": {"loc": "/dev/cpld4", "offset": 0, "len": 4, "way": "devfile_ascii"}, ++ "desc": "Used for sff modules", ++ "slot": 0, ++ "warm": 0, ++ }, ++ { ++ "name": "FPGA", ++ "cpld_id": "CPLD6", ++ "VersionFile": {"loc": "/dev/fpga0", "offset": 0, "len": 4, "way": "devfile_ascii"}, ++ "desc": "Used for base functions", ++ "slot": 0, ++ "format": "little_endian", ++ "warm": 0, ++ }, ++ { ++ "name": "BIOS", ++ "cpld_id": "CPLD7", ++ "VersionFile": {"cmd": "dmidecode -s bios-version", "way": "cmd"}, ++ "desc": "Performs initialization of hardware components during booting", ++ "slot": 0, ++ "type": "str", ++ "warm": 0, ++ }, ++ ], ++ "dcdc": [ ++ { ++ "name": "Switch_ZSFP1_3v3_C", ++ "dcdc_id": "DCDC1", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 22000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_QSFP1_3v3_C", ++ "dcdc_id": "DCDC2", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 22000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_5v0_C", ++ "dcdc_id": "DCDC3", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 1000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_ZSFP1_3v3_V", ++ "dcdc_id": "DCDC4", ++ "Min": 2640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 3960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_QSFP1_3v3_V", ++ "dcdc_id": "DCDC5", ++ "Min": 2640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 3960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_5v0_V", ++ "dcdc_id": "DCDC6", ++ "Min": 4000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 6000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_1v2_C", ++ "dcdc_id": "DCDC7", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 2000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_3v3_C", ++ "dcdc_id": "DCDC8", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 1000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_Cpld_3v3_C", ++ "dcdc_id": "DCDC9", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 2000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_1v2_V", ++ "dcdc_id": "DCDC10", ++ "Min": 960, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 1440, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_3v3_V", ++ "dcdc_id": "DCDC11", ++ "Min": 2640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 3960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_Cpld_3v3_V", ++ "dcdc_id": "DCDC12", ++ "Min": 2640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 3960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Con_1v2_C", ++ "dcdc_id": "DCDC13", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 1300, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Con_3v3_C", ++ "dcdc_id": "DCDC14", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 2800, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Con_SSD_3v3_C", ++ "dcdc_id": "DCDC15", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 4500, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Con_1v2_V", ++ "dcdc_id": "DCDC16", ++ "Min": 960, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 1440, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Con_3v3_V", ++ "dcdc_id": "DCDC17", ++ "Min": 2640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 3960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Con_SSD_3v3_V", ++ "dcdc_id": "DCDC18", ++ "Min": 2640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 3960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_3v3_C", ++ "dcdc_id": "DCDC19", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 4686, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_5v_C", ++ "dcdc_id": "DCDC20", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 2200, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_1v7_C", ++ "dcdc_id": "DCDC21", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 2200, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_3v3_V", ++ "dcdc_id": "DCDC22", ++ "Min": 2640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 3960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_5v_V", ++ "dcdc_id": "DCDC23", ++ "Min": 4000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 6000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_1v7_V", ++ "dcdc_id": "DCDC24", ++ "Min": 1360, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 2040, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_CORE_C", ++ "dcdc_id": "DCDC25", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 47300, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_1v05_C", ++ "dcdc_id": "DCDC26", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 15400, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_CORE_V", ++ "dcdc_id": "DCDC27", ++ "Min": 1456, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 2184, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_1v05_V", ++ "dcdc_id": "DCDC28", ++ "Min": 840, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 1260, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_CORE_C", ++ "dcdc_id": "DCDC29", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 220000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_ANALOG_C", ++ "dcdc_id": "DCDC30", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 18000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_CORE_V", ++ "dcdc_id": "DCDC31", ++ "Min": 600, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 1200, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_ANALOG_V", ++ "dcdc_id": "DCDC32", ++ "Min": 640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_1v2_C", ++ "dcdc_id": "DCDC33", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 9900, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_2v23_C", ++ "dcdc_id": "DCDC34", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 2200, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_1v2_V", ++ "dcdc_id": "DCDC35", ++ "Min": 960, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 1440, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_2v23_V", ++ "dcdc_id": "DCDC36", ++ "Min": 1784, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 2676, ++ "format": "float(float(%s)/1000)", ++ }, ++ ], ++ "cpu": [ ++ { ++ "name": "cpu", ++ "reboot_cause_path": "/etc/sonic/.reboot/.previous-reboot-cause.txt" ++ } ++ ], ++ "sfps": { ++ "ver": '1.0', ++ "port_index_start": 1, ++ "port_num": 56, ++ "log_level": 2, ++ "eeprom_retry_times": 5, ++ "eeprom_retry_break_sec": 0.2, ++ "presence_cpld": { ++ "dev_id": { ++ 3: { ++ "offset": { ++ 0x30: "1-8", ++ 0x31: "9-16", ++ 0x32: "17-24", ++ }, ++ }, ++ 4: { ++ "offset": { ++ 0x30: "25-32", ++ 0x31: "33-40", ++ 0x32: "41-48", ++ 0x33: "49-56", ++ }, ++ }, ++ }, ++ }, ++ "presence_val_is_present": 0, ++ "eeprom_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/eeprom", ++ "eeprom_path_key": list(range(32, 88)), ++ "optoe_driver_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/dev_class", ++ "optoe_driver_key": list(range(32, 88)), ++ "txdis_cpld": { ++ "dev_id": { ++ 3: { ++ "offset": { ++ 0x60: "1-8", ++ 0x61: "9-16", ++ 0x62: "17-24", ++ }, ++ }, ++ 4: { ++ "offset": { ++ 0x60: "25-32", ++ 0x61: "33-40", ++ 0x62: "41-48", ++ }, ++ }, ++ }, ++ }, ++ "txdisable_val_is_on": 1, ++ "reset_cpld": { ++ "dev_id": { ++ 4: { ++ "offset": { ++ 0xb9: "49-56", ++ }, ++ }, ++ }, ++ }, ++ "reset_val_is_reset": 0, ++ } ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_exhaust_device.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_exhaust_device.py +new file mode 100755 +index 000000000..c2b857975 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_exhaust_device.py +@@ -0,0 +1,1371 @@ ++#!/usr/bin/python3 ++ ++psu_fan_airflow = { ++ "intake": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3', 'U1D-D10800-DRB'], ++ "exhaust": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'] ++} ++ ++fanairflow = { ++ "intake": ['M1HFAN III-F'], ++ "exhaust": ['M1HFAN III-R'], ++} ++ ++psu_display_name = { ++ "PA550II-F": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3'], ++ "PA550II-R": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'], ++ "PD800I-F": ['U1D-D10800-DRB'] ++} ++ ++psutypedecode = { ++ 0x00: 'N/A', ++ 0x01: 'AC', ++ 0x02: 'DC', ++} ++ ++ ++class Unit: ++ Temperature = "C" ++ Voltage = "V" ++ Current = "A" ++ Power = "W" ++ Speed = "RPM" ++ ++ ++PSU_NOT_PRESENT_PWM = 100 ++ ++ ++class threshold: ++ PSU_TEMP_MIN = -20 * 1000 ++ PSU_TEMP_MAX = 60 * 1000 ++ ++ PSU_FAN_SPEED_MIN = 2000 ++ PSU_FAN_SPEED_MAX = 18000 ++ ++ PSU_OUTPUT_VOLTAGE_MIN = 11 * 1000 ++ PSU_OUTPUT_VOLTAGE_MAX = 14 * 1000 ++ ++ PSU_AC_INPUT_VOLTAGE_MIN = 200 * 1000 ++ PSU_AC_INPUT_VOLTAGE_MAX = 240 * 1000 ++ ++ PSU_DC_INPUT_VOLTAGE_MIN = 190 * 1000 ++ PSU_DC_INPUT_VOLTAGE_MAX = 290 * 1000 ++ ++ ERR_VALUE = -9999999 ++ ++ PSU_OUTPUT_POWER_MIN = 10 * 1000 * 1000 ++ PSU_OUTPUT_POWER_MAX = 560 * 1000 * 1000 ++ ++ PSU_INPUT_POWER_MIN = 10 * 1000 * 1000 ++ PSU_INPUT_POWER_MAX = 625 * 1000 * 1000 ++ ++ PSU_OUTPUT_CURRENT_MIN = 1 * 1000 ++ PSU_OUTPUT_CURRENT_MAX = 45 * 1000 ++ ++ PSU_INPUT_CURRENT_MIN = 0 * 1000 ++ PSU_INPUT_CURRENT_MAX = 7 * 1000 ++ ++ FRONT_FAN_SPEED_MAX = 24000 ++ REAR_FAN_SPEED_MAX = 22500 ++ FAN_SPEED_MIN = 5000 ++ ++ ++ ASPOWER_DC_PSU_TEMP_MIN = -10 * 1000 ++ ASPOWER_DC_PSU_TEMP_MAX = 55 * 1000 ++ ++ ASPOWER_DC_PSU_FAN_SPEED_MIN = 800 ++ ASPOWER_DC_PSU_FAN_SPEED_MAX = 24000 ++ ++ ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN = 11.4 * 1000 ++ ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX = 12.6 * 1000 ++ ++ ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN = 36 * 1000 ++ ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX = 72 * 1000 ++ ++ ASPOWER_DC_ERR_VALUE = -9999999 ++ ++ ASPOWER_DC_PSU_OUTPUT_POWER_MIN = 5 * 1000 * 1000 ++ ASPOWER_DC_PSU_OUTPUT_POWER_MAX = 800 * 1000 * 1000 ++ ++ ASPOWER_DC_PSU_INPUT_POWER_MIN = 5 * 1000 * 1000 ++ ASPOWER_DC_PSU_INPUT_POWER_MAX = 880 * 1000 * 1000 ++ ++ ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN = 0.5 * 1000 ++ ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX = 66 * 1000 ++ ++ ASPOWER_DC_PSU_INPUT_CURRENT_MIN = 1 * 1000 ++ ASPOWER_DC_PSU_INPUT_CURRENT_MAX = 28 * 1000 ++ ++ ++class Description: ++ CPLD = "Used for managing IO modules, SFP+ modules and system LEDs" ++ BIOS = "Performs initialization of hardware components during booting" ++ FPGA = "Platform management controller for on-board temperature monitoring, in-chassis power" ++ ++ ++devices = { ++ "onie_e2": [ ++ { ++ "name": "ONIE_E2", ++ "e2loc": {"loc": "/sys/bus/i2c/devices/0-0056/eeprom", "way": "sysfs"}, ++ "airflow": "exhaust" ++ }, ++ ], ++ "psus": [ ++ { ++ "e2loc": {"loc": "/sys/bus/i2c/devices/24-0050/eeprom", "way": "sysfs"}, ++ "pmbusloc": {"bus": 24, "addr": 0x58, "way": "i2c"}, ++ "present": {"loc": "/sys/wb_plat/psu/psu1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, ++ "name": "PSU1", ++ "get_threshold_by_model": 1, ++ "psu_display_name": psu_display_name, ++ "airflow": psu_fan_airflow, ++ "TempStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, ++ "other": threshold.PSU_TEMP_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, ++ "other": threshold.PSU_TEMP_MAX, ++ }, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ }, ++ "FanStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, ++ "FanSpeed": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, ++ "other": threshold.PSU_FAN_SPEED_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, ++ "other": threshold.PSU_FAN_SPEED_MAX, ++ }, ++ "Unit": Unit.Speed ++ }, ++ "psu_fan_tolerance": 40, ++ "InputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, ++ "InputsType": {"bus": 24, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, ++ "InputsVoltage": { ++ 'AC': { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, ++ "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, ++ "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ ++ }, ++ 'DC': { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, ++ "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, ++ "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, ++ }, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ }, ++ 'other': { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, ++ "other": threshold.ERR_VALUE, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, ++ "other": threshold.ERR_VALUE, ++ }, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ "InputsCurrent": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, ++ "other": threshold.PSU_INPUT_CURRENT_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, ++ "other": threshold.PSU_INPUT_CURRENT_MAX, ++ }, ++ "Unit": Unit.Current, ++ "format": "float(float(%s)/1000)" ++ }, ++ "InputsPower": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, ++ "other": threshold.PSU_INPUT_POWER_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, ++ "other": threshold.PSU_INPUT_POWER_MAX, ++ }, ++ "Unit": Unit.Power, ++ "format": "float(float(%s)/1000000)" ++ }, ++ "OutputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, ++ "OutputsVoltage": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, ++ "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, ++ "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, ++ }, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ }, ++ "OutputsCurrent": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, ++ "other": threshold.PSU_OUTPUT_CURRENT_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, ++ "other": threshold.PSU_OUTPUT_CURRENT_MAX, ++ }, ++ "Unit": Unit.Current, ++ "format": "float(float(%s)/1000)" ++ }, ++ "OutputsPower": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, ++ "other": threshold.PSU_OUTPUT_POWER_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, ++ "other": threshold.PSU_OUTPUT_POWER_MAX, ++ }, ++ "Unit": Unit.Power, ++ "format": "float(float(%s)/1000000)" ++ }, ++ }, ++ { ++ "e2loc": {"loc": "/sys/bus/i2c/devices/25-0050/eeprom", "way": "sysfs"}, ++ "pmbusloc": {"bus": 25, "addr": 0x58, "way": "i2c"}, ++ "present": {"loc": "/sys/wb_plat/psu/psu2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, ++ "name": "PSU2", ++ "get_threshold_by_model": 1, ++ "psu_display_name": psu_display_name, ++ "airflow": psu_fan_airflow, ++ "TempStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, ++ "other": threshold.PSU_TEMP_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, ++ "other": threshold.PSU_TEMP_MAX, ++ }, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ }, ++ "FanStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, ++ "FanSpeed": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, ++ "other": threshold.PSU_FAN_SPEED_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, ++ "other": threshold.PSU_FAN_SPEED_MAX, ++ }, ++ "Unit": Unit.Speed ++ }, ++ "psu_fan_tolerance": 40, ++ "InputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, ++ "InputsType": {"bus": 25, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, ++ "InputsVoltage": { ++ 'AC': { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, ++ "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, ++ "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ ++ }, ++ 'DC': { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, ++ "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, ++ "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, ++ }, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ }, ++ 'other': { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, ++ "other": threshold.ERR_VALUE, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, ++ "other": threshold.ERR_VALUE, ++ }, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ "InputsCurrent": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, ++ "other": threshold.PSU_INPUT_CURRENT_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, ++ "other": threshold.PSU_INPUT_CURRENT_MAX, ++ }, ++ "Unit": Unit.Current, ++ "format": "float(float(%s)/1000)" ++ }, ++ "InputsPower": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, ++ "other": threshold.PSU_INPUT_POWER_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, ++ "other": threshold.PSU_INPUT_POWER_MAX, ++ }, ++ "Unit": Unit.Power, ++ "format": "float(float(%s)/1000000)" ++ }, ++ "OutputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, ++ "OutputsVoltage": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, ++ "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, ++ "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, ++ }, ++ "Unit": Unit.Voltage, ++ "format": "float(float(%s)/1000)" ++ }, ++ "OutputsCurrent": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, ++ "other": threshold.PSU_OUTPUT_CURRENT_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, ++ "other": threshold.PSU_OUTPUT_CURRENT_MAX, ++ }, ++ "Unit": Unit.Current, ++ "format": "float(float(%s)/1000)" ++ }, ++ "OutputsPower": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, ++ "Min": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, ++ "other": threshold.PSU_OUTPUT_POWER_MIN, ++ }, ++ "Max": { ++ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, ++ "other": threshold.PSU_OUTPUT_POWER_MAX, ++ }, ++ "Unit": Unit.Power, ++ "format": "float(float(%s)/1000000)" ++ }, ++ } ++ ], ++ "temps": [ ++ { ++ "name": "SWITCH_TEMP", ++ "temp_id": "TEMP1", ++ "api_name": "ASIC_TEMP", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/3-0044/hwmon/hwmon*/temp99_input", "way": "sysfs"}, ++ "Min": -30000, ++ "Low": 0, ++ "High": 105000, ++ "Max": 110000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ { ++ "name": "CPU_TEMP", ++ "temp_id": "TEMP2", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/platform/devices/coretemp.0/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": -15000, ++ "Low": 0, ++ "High": 100000, ++ "Max": 102000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ { ++ "name": "INLET_TEMP", ++ "temp_id": "TEMP3", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/3-004c/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": -30000, ++ "Low": 0, ++ "High": 55000, ++ "Max": 60000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ }, ++ "fix_value": { ++ "fix_type": "config", ++ "addend": -3, ++ } ++ }, ++ { ++ "name": "OUTLET_TEMP", ++ "temp_id": "TEMP4", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/3-0048/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": -30000, ++ "Low": 0, ++ "High": 75000, ++ "Max": 80000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ { ++ "name": "BOARD_TEMP", ++ "temp_id": "TEMP5", ++ "api_name": "MAC_OUT_TEMP", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/3-0049/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": -30000, ++ "Low": 0, ++ "High": 75000, ++ "Max": 80000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ { ++ "name": "MAC_IN_TEMP", ++ "temp_id": "TEMP6", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/3-004a/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": -30000, ++ "Low": 0, ++ "High": 75000, ++ "Max": 80000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ { ++ "name": "PSU1_TEMP", ++ "temp_id": "TEMP7", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": -20000, ++ "Low": 0, ++ "High": 55000, ++ "Max": 60000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ { ++ "name": "PSU2_TEMP", ++ "temp_id": "TEMP8", ++ "Temperature": { ++ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, ++ "Min": -20000, ++ "Low": 0, ++ "High": 55000, ++ "Max": 60000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ } ++ }, ++ { ++ "name": "SFF_TEMP", ++ "Temperature": { ++ "value": {"loc": "/tmp/highest_sff_temp", "way": "sysfs", "flock_path": "/tmp/highest_sff_temp"}, ++ "Min": -30000, ++ "Low": 0, ++ "High": 90000, ++ "Max": 100000, ++ "Unit": Unit.Temperature, ++ "format": "float(float(%s)/1000)" ++ }, ++ "invalid": -10000, ++ "error": -9999, ++ } ++ ], ++ "leds": [ ++ { ++ "name": "FRONT_SYS_LED", ++ "led_type": "SYS_LED", ++ "led": {"bus": 6, "addr": 0x0d, "offset": 0x72, "way": "i2c"}, ++ "led_attrs": { ++ "off": 0x00, "red_flash": 0x01, "red": 0x02, ++ "green_flash": 0x03, "green": 0x04, "amber_flash": 0x05, ++ "amber": 0x06, "mask": 0x07 ++ }, ++ }, ++ { ++ "name": "FRONT_PSU_LED", ++ "led_type": "PSU_LED", ++ "led": {"bus": 6, "addr": 0x0d, "offset": 0x73, "way": "i2c"}, ++ "led_attrs": { ++ "off": 0x10, "red_flash": 0x11, "red": 0x12, ++ "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, ++ "amber": 0x16, "mask": 0x17 ++ }, ++ }, ++ { ++ "name": "FRONT_FAN_LED", ++ "led_type": "FAN_LED", ++ "led": {"bus": 6, "addr": 0x0d, "offset": 0x74, "way": "i2c"}, ++ "led_attrs": { ++ "off": 0x10, "red_flash": 0x11, "red": 0x12, ++ "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, ++ "amber": 0x16, "mask": 0x17 ++ }, ++ }, ++ ], ++ "fans": [ ++ { ++ "name": "FAN1", ++ "airflow": fanairflow, ++ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-16/16-0050/eeprom', 'way': 'sysfs'}, ++ "present": {"loc": "/sys/wb_plat/fan/fan1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3b, "way": "i2c"}, ++ "led_attrs": { ++ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, ++ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, ++ "amber": 0x03, "mask": 0x0f ++ }, ++ "PowerMax": 38.4, ++ "Rotor": { ++ "Rotor1_config": { ++ "name": "Rotor1", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan1/motor1/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.FRONT_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ "Rotor2_config": { ++ "name": "Rotor2", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan1/motor0/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.REAR_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ }, ++ }, ++ { ++ "name": "FAN2", ++ "airflow": fanairflow, ++ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-17/17-0050/eeprom', 'way': 'sysfs'}, ++ "present": {"loc": "/sys/wb_plat/fan/fan2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3c, "way": "i2c"}, ++ "led_attrs": { ++ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, ++ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, ++ "amber": 0x03, "mask": 0x0f ++ }, ++ "PowerMax": 38.4, ++ "Rotor": { ++ "Rotor1_config": { ++ "name": "Rotor1", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan2/motor1/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.FRONT_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ "Rotor2_config": { ++ "name": "Rotor2", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan2/motor0/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.REAR_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ }, ++ }, ++ { ++ "name": "FAN3", ++ "airflow": fanairflow, ++ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-18/18-0050/eeprom', 'way': 'sysfs'}, ++ "present": {"loc": "/sys/wb_plat/fan/fan3/present", "way": "sysfs", "mask": 0x01, "okval": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3d, "way": "i2c"}, ++ "led_attrs": { ++ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, ++ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, ++ "amber": 0x03, "mask": 0x0f ++ }, ++ "PowerMax": 38.4, ++ "Rotor": { ++ "Rotor1_config": { ++ "name": "Rotor1", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan3/motor1/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.FRONT_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ "Rotor2_config": { ++ "name": "Rotor2", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan3/motor0/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.REAR_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ }, ++ }, ++ ++ { ++ "name": "FAN4", ++ "airflow": fanairflow, ++ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-19/19-0050/eeprom', 'way': 'sysfs'}, ++ "present": {"loc": "/sys/wb_plat/fan/fan4/present", "way": "sysfs", "mask": 0x01, "okval": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3e, "way": "i2c"}, ++ "led_attrs": { ++ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, ++ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, ++ "amber": 0x03, "mask": 0x0f ++ }, ++ "PowerMax": 38.4, ++ "Rotor": { ++ "Rotor1_config": { ++ "name": "Rotor1", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan4/motor1/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.FRONT_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ "Rotor2_config": { ++ "name": "Rotor2", ++ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, ++ "Running": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, ++ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, ++ "SpeedMin": threshold.FAN_SPEED_MIN, ++ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, ++ "Speed": { ++ "value": {"loc": "/sys/wb_plat/fan/fan4/motor0/speed", "way": "sysfs"}, ++ "Min": threshold.FAN_SPEED_MIN, ++ "Max": threshold.REAR_FAN_SPEED_MAX, ++ "Unit": Unit.Speed, ++ }, ++ }, ++ }, ++ }, ++ ++ ], ++ "cplds": [ ++ { ++ "name": "CPU_CPLD", ++ "cpld_id": "CPLD1", ++ "VersionFile": {"loc": "/dev/cpld0", "offset": 0, "len": 4, "way": "devfile_ascii"}, ++ "desc": "Used for system power", ++ "slot": 0, ++ "warm": 0, ++ }, ++ { ++ "name": "CONNECT_CPLD", ++ "cpld_id": "CPLD2", ++ "VersionFile": {"loc": "/dev/cpld1", "offset": 0, "len": 4, "way": "devfile_ascii"}, ++ "desc": "Used for base functions", ++ "slot": 0, ++ "warm": 0, ++ }, ++ { ++ "name": "CONNECT_CPLD-FAN", ++ "cpld_id": "CPLD3", ++ "VersionFile": {"loc": "/dev/cpld2", "offset": 0, "len": 4, "way": "devfile_ascii"}, ++ "desc": "Used for fan modules", ++ "slot": 0, ++ "warm": 0, ++ }, ++ { ++ "name": "MAC_CPLD1", ++ "cpld_id": "CPLD4", ++ "VersionFile": {"loc": "/dev/cpld3", "offset": 0, "len": 4, "way": "devfile_ascii"}, ++ "desc": "Used for sff modules", ++ "slot": 0, ++ "warm": 0, ++ }, ++ { ++ "name": "MAC_CPLD2", ++ "cpld_id": "CPLD5", ++ "VersionFile": {"loc": "/dev/cpld4", "offset": 0, "len": 4, "way": "devfile_ascii"}, ++ "desc": "Used for sff modules", ++ "slot": 0, ++ "warm": 0, ++ }, ++ { ++ "name": "FPGA", ++ "cpld_id": "CPLD6", ++ "VersionFile": {"loc": "/dev/fpga0", "offset": 0, "len": 4, "way": "devfile_ascii"}, ++ "desc": "Used for base functions", ++ "slot": 0, ++ "format": "little_endian", ++ "warm": 0, ++ }, ++ { ++ "name": "BIOS", ++ "cpld_id": "CPLD7", ++ "VersionFile": {"cmd": "dmidecode -s bios-version", "way": "cmd"}, ++ "desc": "Performs initialization of hardware components during booting", ++ "slot": 0, ++ "type": "str", ++ "warm": 0, ++ }, ++ ], ++ "dcdc": [ ++ { ++ "name": "Switch_ZSFP1_3v3_C", ++ "dcdc_id": "DCDC1", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 22000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_QSFP1_3v3_C", ++ "dcdc_id": "DCDC2", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 22000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_5v0_C", ++ "dcdc_id": "DCDC3", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 1000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_ZSFP1_3v3_V", ++ "dcdc_id": "DCDC4", ++ "Min": 2640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 3960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_QSFP1_3v3_V", ++ "dcdc_id": "DCDC5", ++ "Min": 2640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 3960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_5v0_V", ++ "dcdc_id": "DCDC6", ++ "Min": 4000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 6000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_1v2_C", ++ "dcdc_id": "DCDC7", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 2000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_3v3_C", ++ "dcdc_id": "DCDC8", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 1000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_Cpld_3v3_C", ++ "dcdc_id": "DCDC9", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 2000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_1v2_V", ++ "dcdc_id": "DCDC10", ++ "Min": 960, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 1440, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_3v3_V", ++ "dcdc_id": "DCDC11", ++ "Min": 2640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 3960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_Cpld_3v3_V", ++ "dcdc_id": "DCDC12", ++ "Min": 2640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 3960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Con_1v2_C", ++ "dcdc_id": "DCDC13", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 1300, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Con_3v3_C", ++ "dcdc_id": "DCDC14", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 2800, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Con_SSD_3v3_C", ++ "dcdc_id": "DCDC15", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 4500, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Con_1v2_V", ++ "dcdc_id": "DCDC16", ++ "Min": 960, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 1440, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Con_3v3_V", ++ "dcdc_id": "DCDC17", ++ "Min": 2640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 3960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Con_SSD_3v3_V", ++ "dcdc_id": "DCDC18", ++ "Min": 2640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 3960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_3v3_C", ++ "dcdc_id": "DCDC19", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 4686, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_5v_C", ++ "dcdc_id": "DCDC20", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 2200, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_1v7_C", ++ "dcdc_id": "DCDC21", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 2200, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_3v3_V", ++ "dcdc_id": "DCDC22", ++ "Min": 2640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 3960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_5v_V", ++ "dcdc_id": "DCDC23", ++ "Min": 4000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 6000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_1v7_V", ++ "dcdc_id": "DCDC24", ++ "Min": 1360, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 2040, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_CORE_C", ++ "dcdc_id": "DCDC25", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 47300, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_1v05_C", ++ "dcdc_id": "DCDC26", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 15400, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_CORE_V", ++ "dcdc_id": "DCDC27", ++ "Min": 1456, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 2184, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_1v05_V", ++ "dcdc_id": "DCDC28", ++ "Min": 840, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 1260, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_CORE_C", ++ "dcdc_id": "DCDC29", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 220000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_ANALOG_C", ++ "dcdc_id": "DCDC30", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 18000, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_CORE_V", ++ "dcdc_id": "DCDC31", ++ "Min": 600, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 1200, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Switch_ANALOG_V", ++ "dcdc_id": "DCDC32", ++ "Min": 640, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 960, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_1v2_C", ++ "dcdc_id": "DCDC33", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr1_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 9900, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_2v23_C", ++ "dcdc_id": "DCDC34", ++ "Min": -1000, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "A", ++ "Max": 2200, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_1v2_V", ++ "dcdc_id": "DCDC35", ++ "Min": 960, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in2_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 1440, ++ "format": "float(float(%s)/1000)", ++ }, ++ ++ { ++ "name": "Cpu_2v23_V", ++ "dcdc_id": "DCDC36", ++ "Min": 1784, ++ "value": { ++ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in3_input", ++ "way": "sysfs", ++ }, ++ "read_times": 5, ++ "Unit": "V", ++ "Max": 2676, ++ "format": "float(float(%s)/1000)", ++ }, ++ ], ++ "cpu": [ ++ { ++ "name": "cpu", ++ "reboot_cause_path": "/etc/sonic/.reboot/.previous-reboot-cause.txt" ++ } ++ ], ++ "sfps": { ++ "ver": '1.0', ++ "port_index_start": 1, ++ "port_num": 56, ++ "log_level": 2, ++ "eeprom_retry_times": 5, ++ "eeprom_retry_break_sec": 0.2, ++ "presence_cpld": { ++ "dev_id": { ++ 3: { ++ "offset": { ++ 0x30: "1-8", ++ 0x31: "9-16", ++ 0x32: "17-24", ++ }, ++ }, ++ 4: { ++ "offset": { ++ 0x30: "25-32", ++ 0x31: "33-40", ++ 0x32: "41-48", ++ 0x33: "49-56", ++ }, ++ }, ++ }, ++ }, ++ "presence_val_is_present": 0, ++ "eeprom_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/eeprom", ++ "eeprom_path_key": list(range(32, 88)), ++ "optoe_driver_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/dev_class", ++ "optoe_driver_key": list(range(32, 88)), ++ "txdis_cpld": { ++ "dev_id": { ++ 3: { ++ "offset": { ++ 0x60: "1-8", ++ 0x61: "9-16", ++ 0x62: "17-24", ++ }, ++ }, ++ 4: { ++ "offset": { ++ 0x60: "25-32", ++ 0x61: "33-40", ++ 0x62: "41-48", ++ }, ++ }, ++ }, ++ }, ++ "txdisable_val_is_on": 0, ++ "reset_cpld": { ++ "dev_id": { ++ 4: { ++ "offset": { ++ 0xb9: "49-56", ++ }, ++ }, ++ }, ++ }, ++ "reset_val_is_reset": 0, ++ } ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_monitor.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_monitor.py +new file mode 100755 +index 000000000..aab279a21 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_monitor.py +@@ -0,0 +1,206 @@ ++# coding:utf-8 ++ ++ ++monitor = { ++ "openloop": { ++ "linear": { ++ "name": "linear", ++ "flag": 0, ++ "pwm_min": 0x80, ++ "pwm_max": 0xff, ++ "K": 11, ++ "tin_min": 38, ++ }, ++ "curve": { ++ "name": "curve", ++ "flag": 0, ++ "pwm_min": 0x5a, ++ "pwm_max": 0xff, ++ "a": 0.086, ++ "b": 0.318, ++ "c": 28, ++ "tin_min": 25, ++ }, ++ }, ++ ++ "pid": { ++ "CPU_TEMP": { ++ "name": "CPU_TEMP", ++ "flag": 1, ++ "type": "duty", ++ "pwm_min": 0x80, ++ "pwm_max": 0xff, ++ "Kp": 3, ++ "Ki": 0.5, ++ "Kd": 0.5, ++ "target": 89, ++ "value": [None, None, None], ++ }, ++ "SWITCH_TEMP": { ++ "name": "SWITCH_TEMP", ++ "flag": 1, ++ "type": "duty", ++ "pwm_min": 0x80, ++ "pwm_max": 0xff, ++ "Kp": 3, ++ "Ki": 0.4, ++ "Kd": 0.4, ++ "target": 82, ++ "value": [None, None, None], ++ }, ++ "OUTLET_TEMP": { ++ "name": "OUTLET_TEMP", ++ "flag": 0, ++ "type": "duty", ++ "pwm_min": 0x80, ++ "pwm_max": 0xff, ++ "Kp": 2, ++ "Ki": 0.4, ++ "Kd": 0.3, ++ "target": 65, ++ "value": [None, None, None], ++ }, ++ "BOARD_TEMP": { ++ "name": "BOARD_TEMP", ++ "flag": 0, ++ "type": "duty", ++ "pwm_min": 0x80, ++ "pwm_max": 0xff, ++ "Kp": 2, ++ "Ki": 0.4, ++ "Kd": 0.3, ++ "target": 65, ++ "value": [None, None, None], ++ }, ++ "SFF_TEMP": { ++ "name": "SFF_TEMP", ++ "flag": 1, ++ "type": "duty", ++ "pwm_min": 0x80, ++ "pwm_max": 0xff, ++ "Kp": 0.1, ++ "Ki": 0.4, ++ "Kd": 0, ++ "target": 60, ++ "value": [None, None, None], ++ }, ++ }, ++ ++ "hyst": { ++ "INLET_TEMP": { ++ "name": "INLET_TEMP", ++ "flag": 1, ++ "type": "duty", ++ "hyst_min": 50, # duty ++ "hyst_max": 100, # duty ++ "last_hyst_value": 50, # duty ++ "temp_min": 23, ++ "temp_max": 40, ++ "value": [None, None], ++ "rising": { ++ 23: 50, ++ 24: 50, ++ 25: 50, ++ 26: 53, ++ 27: 56, ++ 28: 59, ++ 29: 62, ++ 30: 65, ++ 31: 68, ++ 32: 71, ++ 33: 74, ++ 34: 77, ++ 35: 80, ++ 36: 84, ++ 37: 88, ++ 38: 92, ++ 39: 96, ++ 40: 100, ++ }, ++ "descending": { ++ 23: 50, ++ 24: 53, ++ 25: 56, ++ 26: 59, ++ 27: 62, ++ 28: 65, ++ 29: 68, ++ 30: 71, ++ 31: 74, ++ 32: 77, ++ 33: 80, ++ 34: 84, ++ 35: 88, ++ 36: 92, ++ 37: 96, ++ 38: 100, ++ 39: 100, ++ 40: 100, ++ }, ++ } ++ }, ++ ++ "temps_threshold": { ++ "SWITCH_TEMP": {"name": "SWITCH_TEMP", "warning": 100, "critical": 105}, ++ "INLET_TEMP": {"name": "INLET_TEMP", "warning": 40, "critical": 50}, ++ "BOARD_TEMP": {"name": "BOARD_TEMP", "warning": 70, "critical": 80}, ++ "OUTLET_TEMP": {"name": "OUTLET_TEMP", "warning": 70, "critical": 80}, ++ "CPU_TEMP": {"name": "CPU_TEMP", "warning": 100, "critical": 102}, ++ "SFF_TEMP": {"name": "SFF_TEMP", "warning": 999, "critical": 1000, "ignore_threshold": 1, "invalid": -10000, "error": -9999}, ++ }, ++ ++ "fancontrol_para": { ++ "interval": 5, ++ "fan_air_flow_monitor": 1, ++ "psu_air_flow_monitor": 1, ++ "max_pwm": 0xff, ++ "min_pwm": 0x80, ++ "abnormal_pwm": 0xff, ++ "warning_pwm": 0xff, ++ "temp_invalid_pid_pwm": 0x80, ++ "temp_error_pid_pwm": 0x80, ++ "temp_fail_num": 3, ++ "check_temp_fail": [ ++ {"temp_name": "INLET_TEMP"}, ++ {"temp_name": "SWITCH_TEMP"}, ++ {"temp_name": "CPU_TEMP"}, ++ ], ++ "temp_warning_num": 3, # temp over warning 3 times continuously ++ "temp_critical_num": 3, # temp over critical 3 times continuously ++ "temp_warning_countdown": 60, # 5 min warning speed after not warning ++ "temp_critical_countdown": 60, # 5 min full speed after not critical ++ "rotor_error_count": 6, # fan rotor error 6 times continuously ++ "inlet_mac_diff": 999, ++ "check_crit_reboot_flag": 1, ++ "check_crit_reboot_num": 3, ++ "check_crit_sleep_time": 20, ++ "psu_absent_fullspeed_num": 0xFF, ++ "fan_absent_fullspeed_num": 1, ++ "rotor_error_fullspeed_num": 1, ++ }, ++ ++ "ledcontrol_para": { ++ "interval": 5, ++ "checkpsu": 0, # 0: sys led don't follow psu led ++ "checkfan": 0, # 0: sys led don't follow fan led ++ "psu_amber_num": 1, ++ "fan_amber_num": 1, ++ "board_sys_led": [ ++ {"led_name": "FRONT_SYS_LED"}, ++ ], ++ "board_psu_led": [ ++ {"led_name": "FRONT_PSU_LED"}, ++ ], ++ "board_fan_led": [ ++ {"led_name": "FRONT_FAN_LED"}, ++ ], ++ "psu_air_flow_monitor": 1, ++ "fan_air_flow_monitor": 1, ++ "psu_air_flow_amber_num": 1, ++ "fan_air_flow_amber_num": 1, ++ }, ++ "otp_reboot_judge_file": { ++ "otp_switch_reboot_judge_file": "/etc/.otp_switch_reboot_flag", ++ "otp_other_reboot_judge_file": "/etc/.otp_other_reboot_flag", ++ }, ++} +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/Makefile b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/Makefile +new file mode 100755 +index 000000000..2e9c25ae6 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/Makefile +@@ -0,0 +1,12 @@ ++MAKEFILE_FILE_PATH = $(abspath $(lastword $(MAKEFILE_LIST))) ++MODULES_DIR = $(abspath $(MAKEFILE_FILE_PATH)/../../../../common/modules) ++ ++EXTRA_CFLAGS+= -I$(MODULES_DIR) ++EXTRA_CFLAGS+= -I$(MODULES_DIR)/linux-5.10 ++ ++obj-m := wb_pcie_dev_device.o ++obj-m += wb_i2c_mux_pca954x_device.o ++obj-m += wb_i2c_ocores_device.o ++obj-m += wb_lpc_drv_device.o ++obj-m += wb_i2c_dev_device.o ++obj-m += wb_io_dev_device.o +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_dev_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_dev_device.c +new file mode 100644 +index 000000000..865e7afea +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_dev_device.c +@@ -0,0 +1,140 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++static int g_wb_i2c_dev_device_debug = 0; ++static int g_wb_i2c_dev_device_error = 0; ++ ++module_param(g_wb_i2c_dev_device_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_i2c_dev_device_error, int, S_IRUGO | S_IWUSR); ++ ++#define WB_I2C_DEV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ ++ if (g_wb_i2c_dev_device_debug) { \ ++ printk(KERN_INFO "[WB_I2C_DEV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_I2C_DEV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_wb_i2c_dev_device_error) { \ ++ printk(KERN_ERR "[WB_I2C_DEV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static i2c_dev_device_t i2c_dev_device_data0 = { ++ .i2c_bus = 2, ++ .i2c_addr = 0x0d, ++ .i2c_name = "cpld2", ++ .data_bus_width = 1, ++ .addr_bus_width = 1, ++ .per_rd_len = 256, ++ .per_wr_len = 256, ++ .i2c_len = 256, ++}; ++ ++static i2c_dev_device_t i2c_dev_device_data1 = { ++ .i2c_bus = 8, ++ .i2c_addr = 0x30, ++ .i2c_name = "cpld3", ++ .data_bus_width = 1, ++ .addr_bus_width = 1, ++ .per_rd_len = 256, ++ .per_wr_len = 256, ++ .i2c_len = 256, ++}; ++ ++static i2c_dev_device_t i2c_dev_device_data2 = { ++ .i2c_bus = 8, ++ .i2c_addr = 0x31, ++ .i2c_name = "cpld4", ++ .data_bus_width = 1, ++ .addr_bus_width = 1, ++ .per_rd_len = 256, ++ .per_wr_len = 256, ++ .i2c_len = 256, ++}; ++ ++static i2c_dev_device_t i2c_dev_device_data3 = { ++ .i2c_bus = 6, ++ .i2c_addr = 0x0d, ++ .i2c_name = "cpld5", ++ .data_bus_width = 1, ++ .addr_bus_width = 1, ++ .per_rd_len = 256, ++ .per_wr_len = 256, ++ .i2c_len = 256, ++}; ++ ++struct i2c_board_info i2c_dev_device_info[] = { ++ { ++ .type = "wb-i2c-dev", ++ .platform_data = &i2c_dev_device_data0, ++ }, ++ { ++ .type = "wb-i2c-dev", ++ .platform_data = &i2c_dev_device_data1, ++ }, ++ { ++ .type = "wb-i2c-dev", ++ .platform_data = &i2c_dev_device_data2, ++ }, ++ { ++ .type = "wb-i2c-dev", ++ .platform_data = &i2c_dev_device_data3, ++ }, ++}; ++ ++static int __init wb_i2c_dev_device_init(void) ++{ ++ int i; ++ struct i2c_adapter *adap; ++ struct i2c_client *client; ++ i2c_dev_device_t *i2c_dev_device_data; ++ ++ WB_I2C_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); ++ for (i = 0; i < ARRAY_SIZE(i2c_dev_device_info); i++) { ++ i2c_dev_device_data = i2c_dev_device_info[i].platform_data; ++ i2c_dev_device_info[i].addr = i2c_dev_device_data->i2c_addr; ++ adap = i2c_get_adapter(i2c_dev_device_data->i2c_bus); ++ if (adap == NULL) { ++ i2c_dev_device_data->client = NULL; ++ printk(KERN_ERR "get i2c bus %d adapter fail.\n", i2c_dev_device_data->i2c_bus); ++ continue; ++ } ++ client = i2c_new_client_device(adap, &i2c_dev_device_info[i]); ++ if (!client) { ++ i2c_dev_device_data->client = NULL; ++ printk(KERN_ERR "Failed to register i2c dev device %d at bus %d!\n", ++ i2c_dev_device_data->i2c_addr, i2c_dev_device_data->i2c_bus); ++ } else { ++ i2c_dev_device_data->client = client; ++ } ++ i2c_put_adapter(adap); ++ } ++ return 0; ++} ++ ++static void __exit wb_i2c_dev_device_exit(void) ++{ ++ int i; ++ i2c_dev_device_t *i2c_dev_device_data; ++ ++ WB_I2C_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); ++ for (i = ARRAY_SIZE(i2c_dev_device_info) - 1; i >= 0; i--) { ++ i2c_dev_device_data = i2c_dev_device_info[i].platform_data; ++ if (i2c_dev_device_data->client) { ++ i2c_unregister_device(i2c_dev_device_data->client); ++ i2c_dev_device_data->client = NULL; ++ } ++ } ++} ++ ++module_init(wb_i2c_dev_device_init); ++module_exit(wb_i2c_dev_device_exit); ++MODULE_DESCRIPTION("I2C DEV Devices"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_mux_pca954x_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_mux_pca954x_device.c +new file mode 100644 +index 000000000..f12a71013 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_mux_pca954x_device.c +@@ -0,0 +1,296 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++static int g_wb_i2c_mux_pca954x_device_debug = 0; ++static int g_wb_i2c_mux_pca954x_device_error = 0; ++ ++module_param(g_wb_i2c_mux_pca954x_device_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_i2c_mux_pca954x_device_error, int, S_IRUGO | S_IWUSR); ++ ++#define WB_I2C_MUX_PCA954X_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ ++ if (g_wb_i2c_mux_pca954x_device_debug) { \ ++ printk(KERN_INFO "[WB_I2C_MUX_PCA954X_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_I2C_MUX_PCA954X_DEVICE_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_wb_i2c_mux_pca954x_device_error) { \ ++ printk(KERN_ERR "[WB_I2C_MUX_PCA954X_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data0 = { ++ .i2c_bus = 2, ++ .i2c_addr = 0x77, ++ .probe_disable = 1, ++ .select_chan_check = 0, ++ .close_chan_force_reset = 0, ++ .pca9548_base_nr = 16, ++ .pca9548_reset_type = PCA9548_RESET_FILE, ++ .rst_delay_b = 0, ++ .rst_delay = 1000, ++ .rst_delay_a = 1000, ++ .attr = { ++ .file_attr.dev_name = "/dev/cpld5", ++ .file_attr.offset = 0x60, ++ .file_attr.mask = 0x02, ++ .file_attr.reset_on = 0x00, ++ .file_attr.reset_off = 0x02, ++ }, ++}; ++ ++static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data1 = { ++ .i2c_bus = 4, ++ .i2c_addr = 0x77, ++ .probe_disable = 1, ++ .select_chan_check = 0, ++ .close_chan_force_reset = 0, ++ .pca9548_base_nr = 24, ++ .pca9548_reset_type = PCA9548_RESET_FILE, ++ .rst_delay_b = 0, ++ .rst_delay = 1000, ++ .rst_delay_a = 1000, ++ .attr = { ++ .file_attr.dev_name = "/dev/cpld5", ++ .file_attr.offset = 0x60, ++ .file_attr.mask = 0x01, ++ .file_attr.reset_on = 0x00, ++ .file_attr.reset_off = 0x01, ++ }, ++}; ++ ++static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data2 = { ++ .i2c_bus = 12, ++ .i2c_addr = 0x70, ++ .probe_disable = 1, ++ .select_chan_check = 0, ++ .close_chan_force_reset = 0, ++ .pca9548_base_nr = 32, ++ .pca9548_reset_type = PCA9548_RESET_FILE, ++ .rst_delay_b = 0, ++ .rst_delay = 1000, ++ .rst_delay_a = 1000, ++ .attr = { ++ .file_attr.dev_name = "/dev/fpga0", ++ .file_attr.offset = 0x20, ++ .file_attr.mask = 0x01, ++ .file_attr.reset_on = 0x00, ++ .file_attr.reset_off = 0x01, ++ }, ++}; ++ ++static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data3 = { ++ .i2c_bus = 12, ++ .i2c_addr = 0x71, ++ .probe_disable = 1, ++ .select_chan_check = 0, ++ .close_chan_force_reset = 0, ++ .pca9548_base_nr = 40, ++ .pca9548_reset_type = PCA9548_RESET_FILE, ++ .rst_delay_b = 0, ++ .rst_delay = 1000, ++ .rst_delay_a = 1000, ++ .attr = { ++ .file_attr.dev_name = "/dev/fpga0", ++ .file_attr.offset = 0x20, ++ .file_attr.mask = 0x01, ++ .file_attr.reset_on = 0x00, ++ .file_attr.reset_off = 0x01, ++ }, ++}; ++ ++static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data4 = { ++ .i2c_bus = 12, ++ .i2c_addr = 0x72, ++ .probe_disable = 1, ++ .select_chan_check = 0, ++ .close_chan_force_reset = 0, ++ .pca9548_base_nr = 48, ++ .pca9548_reset_type = PCA9548_RESET_FILE, ++ .rst_delay_b = 0, ++ .rst_delay = 1000, ++ .rst_delay_a = 1000, ++ .attr = { ++ .file_attr.dev_name = "/dev/fpga0", ++ .file_attr.offset = 0x20, ++ .file_attr.mask = 0x01, ++ .file_attr.reset_on = 0x00, ++ .file_attr.reset_off = 0x01, ++ }, ++}; ++ ++static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data5 = { ++ .i2c_bus = 12, ++ .i2c_addr = 0x73, ++ .probe_disable = 1, ++ .select_chan_check = 0, ++ .close_chan_force_reset = 0, ++ .pca9548_base_nr = 56, ++ .pca9548_reset_type = PCA9548_RESET_FILE, ++ .rst_delay_b = 0, ++ .rst_delay = 1000, ++ .rst_delay_a = 1000, ++ .attr = { ++ .file_attr.dev_name = "/dev/fpga0", ++ .file_attr.offset = 0x20, ++ .file_attr.mask = 0x01, ++ .file_attr.reset_on = 0x00, ++ .file_attr.reset_off = 0x01, ++ }, ++}; ++ ++static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data6 = { ++ .i2c_bus = 13, ++ .i2c_addr = 0x70, ++ .probe_disable = 1, ++ .select_chan_check = 0, ++ .close_chan_force_reset = 0, ++ .pca9548_base_nr = 64, ++ .pca9548_reset_type = PCA9548_RESET_FILE, ++ .rst_delay_b = 0, ++ .rst_delay = 1000, ++ .rst_delay_a = 1000, ++ .attr = { ++ .file_attr.dev_name = "/dev/fpga0", ++ .file_attr.offset = 0x20, ++ .file_attr.mask = 0x01, ++ .file_attr.reset_on = 0x00, ++ .file_attr.reset_off = 0x01, ++ }, ++}; ++ ++static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data7 = { ++ .i2c_bus = 13, ++ .i2c_addr = 0x71, ++ .probe_disable = 1, ++ .select_chan_check = 0, ++ .close_chan_force_reset = 0, ++ .pca9548_base_nr = 72, ++ .pca9548_reset_type = PCA9548_RESET_FILE, ++ .rst_delay_b = 0, ++ .rst_delay = 1000, ++ .rst_delay_a = 1000, ++ .attr = { ++ .file_attr.dev_name = "/dev/fpga0", ++ .file_attr.offset = 0x20, ++ .file_attr.mask = 0x01, ++ .file_attr.reset_on = 0x00, ++ .file_attr.reset_off = 0x01, ++ }, ++}; ++ ++static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data8 = { ++ .i2c_bus = 13, ++ .i2c_addr = 0x72, ++ .probe_disable = 1, ++ .select_chan_check = 0, ++ .close_chan_force_reset = 0, ++ .pca9548_base_nr = 80, ++ .pca9548_reset_type = PCA9548_RESET_FILE, ++ .rst_delay_b = 0, ++ .rst_delay = 1000, ++ .rst_delay_a = 1000, ++ .attr = { ++ .file_attr.dev_name = "/dev/fpga0", ++ .file_attr.offset = 0x20, ++ .file_attr.mask = 0x01, ++ .file_attr.reset_on = 0x00, ++ .file_attr.reset_off = 0x01, ++ }, ++}; ++ ++struct i2c_board_info i2c_mux_pca954x_device_info[] = { ++ { ++ .type = "wb_pca9548", ++ .platform_data = &i2c_mux_pca954x_device_data0, ++ }, ++ { ++ .type = "wb_pca9548", ++ .platform_data = &i2c_mux_pca954x_device_data1, ++ }, ++ { ++ .type = "wb_pca9548", ++ .platform_data = &i2c_mux_pca954x_device_data2, ++ }, ++ { ++ .type = "wb_pca9548", ++ .platform_data = &i2c_mux_pca954x_device_data3, ++ }, ++ { ++ .type = "wb_pca9548", ++ .platform_data = &i2c_mux_pca954x_device_data4, ++ }, ++ { ++ .type = "wb_pca9548", ++ .platform_data = &i2c_mux_pca954x_device_data5, ++ }, ++ { ++ .type = "wb_pca9548", ++ .platform_data = &i2c_mux_pca954x_device_data6, ++ }, ++ { ++ .type = "wb_pca9548", ++ .platform_data = &i2c_mux_pca954x_device_data7, ++ }, ++ { ++ .type = "wb_pca9548", ++ .platform_data = &i2c_mux_pca954x_device_data8, ++ }, ++}; ++ ++static int __init wb_i2c_mux_pca954x_device_init(void) ++{ ++ int i; ++ struct i2c_adapter *adap; ++ struct i2c_client *client; ++ i2c_mux_pca954x_device_t *i2c_mux_pca954x_device_data; ++ ++ WB_I2C_MUX_PCA954X_DEVICE_DEBUG_VERBOSE("enter!\n"); ++ for (i = 0; i < ARRAY_SIZE(i2c_mux_pca954x_device_info); i++) { ++ i2c_mux_pca954x_device_data = i2c_mux_pca954x_device_info[i].platform_data; ++ i2c_mux_pca954x_device_info[i].addr = i2c_mux_pca954x_device_data->i2c_addr; ++ adap = i2c_get_adapter(i2c_mux_pca954x_device_data->i2c_bus); ++ if (adap == NULL) { ++ i2c_mux_pca954x_device_data->client = NULL; ++ printk(KERN_ERR "get i2c bus %d adapter fail.\n", i2c_mux_pca954x_device_data->i2c_bus); ++ continue; ++ } ++ client = i2c_new_client_device(adap, &i2c_mux_pca954x_device_info[i]); ++ if (!client) { ++ i2c_mux_pca954x_device_data->client = NULL; ++ printk(KERN_ERR "Failed to register pca954x device %d at bus %d!\n", ++ i2c_mux_pca954x_device_data->i2c_addr, i2c_mux_pca954x_device_data->i2c_bus); ++ } else { ++ i2c_mux_pca954x_device_data->client = client; ++ } ++ i2c_put_adapter(adap); ++ } ++ return 0; ++} ++ ++static void __exit wb_i2c_mux_pca954x_device_exit(void) ++{ ++ int i; ++ i2c_mux_pca954x_device_t *i2c_mux_pca954x_device_data; ++ ++ WB_I2C_MUX_PCA954X_DEVICE_DEBUG_VERBOSE("enter!\n"); ++ for (i = ARRAY_SIZE(i2c_mux_pca954x_device_info) - 1; i >= 0; i--) { ++ i2c_mux_pca954x_device_data = i2c_mux_pca954x_device_info[i].platform_data; ++ if (i2c_mux_pca954x_device_data->client) { ++ i2c_unregister_device(i2c_mux_pca954x_device_data->client); ++ i2c_mux_pca954x_device_data->client = NULL; ++ } ++ } ++} ++ ++module_init(wb_i2c_mux_pca954x_device_init); ++module_exit(wb_i2c_mux_pca954x_device_exit); ++MODULE_DESCRIPTION("I2C MUX PCA954X Devices"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_ocores_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_ocores_device.c +new file mode 100644 +index 000000000..ff7ba9d26 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_ocores_device.c +@@ -0,0 +1,423 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++static int g_wb_i2c_ocores_device_debug = 0; ++static int g_wb_i2c_ocores_device_error = 0; ++ ++module_param(g_wb_i2c_ocores_device_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_i2c_ocores_device_error, int, S_IRUGO | S_IWUSR); ++ ++#define WB_I2C_OCORE_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ ++ if (g_wb_i2c_ocores_device_debug) { \ ++ printk(KERN_INFO "[WB_I2C_OCORE_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_I2C_OCORE_DEVICE_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_wb_i2c_ocores_device_error) { \ ++ printk(KERN_ERR "[WB_I2C_OCORE_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static i2c_ocores_device_t i2c_ocores_device_data0 = { ++ .adap_nr = 2, ++ .big_endian = 0, ++ .dev_name = "/dev/fpga0", ++ .reg_access_mode = 3, ++ .dev_base = 0x0800, ++ .reg_shift = 2, ++ .reg_io_width = 4, ++ .ip_clock_khz = 125000, ++ .bus_clock_khz = 100, ++ .irq_offset = 0, ++ .pci_domain = 0, ++ .pci_bus = 8, ++ .pci_slot = 0, ++ .pci_fn = 0, ++}; ++ ++static i2c_ocores_device_t i2c_ocores_device_data1 = { ++ .adap_nr = 3, ++ .big_endian = 0, ++ .dev_name = "/dev/fpga0", ++ .reg_access_mode = 3, ++ .dev_base = 0x0820, ++ .reg_shift = 2, ++ .reg_io_width = 4, ++ .ip_clock_khz = 125000, ++ .bus_clock_khz = 100, ++ .irq_offset = 1, ++ .pci_domain = 0, ++ .pci_bus = 8, ++ .pci_slot = 0, ++ .pci_fn = 0, ++}; ++ ++static i2c_ocores_device_t i2c_ocores_device_data2 = { ++ .adap_nr = 4, ++ .big_endian = 0, ++ .dev_name = "/dev/fpga0", ++ .reg_access_mode = 3, ++ .dev_base = 0x0840, ++ .reg_shift = 2, ++ .reg_io_width = 4, ++ .ip_clock_khz = 125000, ++ .bus_clock_khz = 100, ++ .irq_offset = 2, ++ .pci_domain = 0, ++ .pci_bus = 8, ++ .pci_slot = 0, ++ .pci_fn = 0, ++}; ++ ++static i2c_ocores_device_t i2c_ocores_device_data3 = { ++ .adap_nr = 5, ++ .big_endian = 0, ++ .dev_name = "/dev/fpga0", ++ .reg_access_mode = 3, ++ .dev_base = 0x0860, ++ .reg_shift = 2, ++ .reg_io_width = 4, ++ .ip_clock_khz = 125000, ++ .bus_clock_khz = 100, ++ .irq_offset = 3, ++ .pci_domain = 0, ++ .pci_bus = 8, ++ .pci_slot = 0, ++ .pci_fn = 0, ++}; ++ ++static i2c_ocores_device_t i2c_ocores_device_data4 = { ++ .adap_nr = 6, ++ .big_endian = 0, ++ .dev_name = "/dev/fpga0", ++ .reg_access_mode = 3, ++ .dev_base = 0x0880, ++ .reg_shift = 2, ++ .reg_io_width = 4, ++ .ip_clock_khz = 125000, ++ .bus_clock_khz = 100, ++ .irq_offset = 4, ++ .pci_domain = 0, ++ .pci_bus = 8, ++ .pci_slot = 0, ++ .pci_fn = 0, ++}; ++ ++static i2c_ocores_device_t i2c_ocores_device_data5 = { ++ .adap_nr = 7, ++ .big_endian = 0, ++ .dev_name = "/dev/fpga0", ++ .reg_access_mode = 3, ++ .dev_base = 0x08a0, ++ .reg_shift = 2, ++ .reg_io_width = 4, ++ .ip_clock_khz = 125000, ++ .bus_clock_khz = 100, ++ .irq_offset = 5, ++ .pci_domain = 0, ++ .pci_bus = 8, ++ .pci_slot = 0, ++ .pci_fn = 0, ++}; ++ ++static i2c_ocores_device_t i2c_ocores_device_data6 = { ++ .adap_nr = 8, ++ .big_endian = 0, ++ .dev_name = "/dev/fpga0", ++ .reg_access_mode = 3, ++ .dev_base = 0x08c0, ++ .reg_shift = 2, ++ .reg_io_width = 4, ++ .ip_clock_khz = 125000, ++ .bus_clock_khz = 100, ++ .irq_offset = 6, ++ .pci_domain = 0, ++ .pci_bus = 8, ++ .pci_slot = 0, ++ .pci_fn = 0, ++}; ++ ++static i2c_ocores_device_t i2c_ocores_device_data7 = { ++ .adap_nr = 9, ++ .big_endian = 0, ++ .dev_name = "/dev/fpga0", ++ .reg_access_mode = 3, ++ .dev_base = 0x08e0, ++ .reg_shift = 2, ++ .reg_io_width = 4, ++ .ip_clock_khz = 125000, ++ .bus_clock_khz = 100, ++ .irq_offset = 7, ++ .pci_domain = 0, ++ .pci_bus = 8, ++ .pci_slot = 0, ++ .pci_fn = 0, ++}; ++ ++static i2c_ocores_device_t i2c_ocores_device_data8 = { ++ .adap_nr = 10, ++ .big_endian = 0, ++ .dev_name = "/dev/fpga0", ++ .reg_access_mode = 3, ++ .dev_base = 0x0900, ++ .reg_shift = 2, ++ .reg_io_width = 4, ++ .ip_clock_khz = 125000, ++ .bus_clock_khz = 100, ++ .irq_offset = 8, ++ .pci_domain = 0, ++ .pci_bus = 8, ++ .pci_slot = 0, ++ .pci_fn = 0, ++}; ++ ++static i2c_ocores_device_t i2c_ocores_device_data9 = { ++ .adap_nr = 11, ++ .big_endian = 0, ++ .dev_name = "/dev/fpga0", ++ .reg_access_mode = 3, ++ .dev_base = 0x0920, ++ .reg_shift = 2, ++ .reg_io_width = 4, ++ .ip_clock_khz = 125000, ++ .bus_clock_khz = 100, ++ .irq_offset = 9, ++ .pci_domain = 0, ++ .pci_bus = 8, ++ .pci_slot = 0, ++ .pci_fn = 0, ++}; ++ ++static i2c_ocores_device_t i2c_ocores_device_data10 = { ++ .adap_nr = 12, ++ .big_endian = 0, ++ .dev_name = "/dev/fpga0", ++ .reg_access_mode = 3, ++ .dev_base = 0x0940, ++ .reg_shift = 2, ++ .reg_io_width = 4, ++ .ip_clock_khz = 125000, ++ .bus_clock_khz = 100, ++ .irq_offset = 10, ++ .pci_domain = 0, ++ .pci_bus = 8, ++ .pci_slot = 0, ++ .pci_fn = 0, ++}; ++ ++static i2c_ocores_device_t i2c_ocores_device_data11 = { ++ .adap_nr = 13, ++ .big_endian = 0, ++ .dev_name = "/dev/fpga0", ++ .reg_access_mode = 3, ++ .dev_base = 0x0960, ++ .reg_shift = 2, ++ .reg_io_width = 4, ++ .ip_clock_khz = 125000, ++ .bus_clock_khz = 100, ++ .irq_offset = 11, ++ .pci_domain = 0, ++ .pci_bus = 8, ++ .pci_slot = 0, ++ .pci_fn = 0, ++}; ++ ++static i2c_ocores_device_t i2c_ocores_device_data12 = { ++ .adap_nr = 14, ++ .big_endian = 0, ++ .dev_name = "/dev/fpga0", ++ .reg_access_mode = 3, ++ .dev_base = 0x0980, ++ .reg_shift = 2, ++ .reg_io_width = 4, ++ .ip_clock_khz = 125000, ++ .bus_clock_khz = 100, ++ .irq_offset = 12, ++ .pci_domain = 0, ++ .pci_bus = 8, ++ .pci_slot = 0, ++ .pci_fn = 0, ++}; ++ ++static i2c_ocores_device_t i2c_ocores_device_data13 = { ++ .adap_nr = 15, ++ .big_endian = 0, ++ .dev_name = "/dev/fpga0", ++ .reg_access_mode = 3, ++ .dev_base = 0x09a0, ++ .reg_shift = 2, ++ .reg_io_width = 4, ++ .ip_clock_khz = 125000, ++ .bus_clock_khz = 100, ++ .irq_offset = 13, ++ .pci_domain = 0, ++ .pci_bus = 8, ++ .pci_slot = 0, ++ .pci_fn = 0, ++}; ++ ++static void wb_i2c_ocores_device_release(struct device *dev) ++{ ++ return; ++} ++ ++static struct platform_device i2c_ocores_device[] = { ++ { ++ .name = "wb-ocores-i2c", ++ .id = 1, ++ .dev = { ++ .platform_data = &i2c_ocores_device_data0, ++ .release = wb_i2c_ocores_device_release, ++ }, ++ }, ++ { ++ .name = "wb-ocores-i2c", ++ .id = 2, ++ .dev = { ++ .platform_data = &i2c_ocores_device_data1, ++ .release = wb_i2c_ocores_device_release, ++ }, ++ }, ++ { ++ .name = "wb-ocores-i2c", ++ .id = 3, ++ .dev = { ++ .platform_data = &i2c_ocores_device_data2, ++ .release = wb_i2c_ocores_device_release, ++ }, ++ }, ++ { ++ .name = "wb-ocores-i2c", ++ .id = 4, ++ .dev = { ++ .platform_data = &i2c_ocores_device_data3, ++ .release = wb_i2c_ocores_device_release, ++ }, ++ }, ++ { ++ .name = "wb-ocores-i2c", ++ .id = 5, ++ .dev = { ++ .platform_data = &i2c_ocores_device_data4, ++ .release = wb_i2c_ocores_device_release, ++ }, ++ }, ++ { ++ .name = "wb-ocores-i2c", ++ .id = 6, ++ .dev = { ++ .platform_data = &i2c_ocores_device_data5, ++ .release = wb_i2c_ocores_device_release, ++ }, ++ }, ++ { ++ .name = "wb-ocores-i2c", ++ .id = 7, ++ .dev = { ++ .platform_data = &i2c_ocores_device_data6, ++ .release = wb_i2c_ocores_device_release, ++ }, ++ }, ++ { ++ .name = "wb-ocores-i2c", ++ .id = 8, ++ .dev = { ++ .platform_data = &i2c_ocores_device_data7, ++ .release = wb_i2c_ocores_device_release, ++ }, ++ }, ++ { ++ .name = "wb-ocores-i2c", ++ .id = 9, ++ .dev = { ++ .platform_data = &i2c_ocores_device_data8, ++ .release = wb_i2c_ocores_device_release, ++ }, ++ }, ++ { ++ .name = "wb-ocores-i2c", ++ .id = 10, ++ .dev = { ++ .platform_data = &i2c_ocores_device_data9, ++ .release = wb_i2c_ocores_device_release, ++ }, ++ }, ++ { ++ .name = "wb-ocores-i2c", ++ .id = 11, ++ .dev = { ++ .platform_data = &i2c_ocores_device_data10, ++ .release = wb_i2c_ocores_device_release, ++ }, ++ }, ++ { ++ .name = "wb-ocores-i2c", ++ .id = 12, ++ .dev = { ++ .platform_data = &i2c_ocores_device_data11, ++ .release = wb_i2c_ocores_device_release, ++ }, ++ }, ++ { ++ .name = "wb-ocores-i2c", ++ .id = 13, ++ .dev = { ++ .platform_data = &i2c_ocores_device_data12, ++ .release = wb_i2c_ocores_device_release, ++ }, ++ }, ++ { ++ .name = "wb-ocores-i2c", ++ .id = 14, ++ .dev = { ++ .platform_data = &i2c_ocores_device_data13, ++ .release = wb_i2c_ocores_device_release, ++ }, ++ }, ++}; ++ ++static int __init wb_i2c_ocores_device_init(void) ++{ ++ int i; ++ int ret = 0; ++ i2c_ocores_device_t *i2c_ocores_device_data; ++ ++ WB_I2C_OCORE_DEVICE_DEBUG_VERBOSE("enter!\n"); ++ for (i = 0; i < ARRAY_SIZE(i2c_ocores_device); i++) { ++ i2c_ocores_device_data = i2c_ocores_device[i].dev.platform_data; ++ ret = platform_device_register(&i2c_ocores_device[i]); ++ if (ret < 0) { ++ i2c_ocores_device_data->device_flag = -1; /* device register failed, set flag -1 */ ++ printk(KERN_ERR "wb-ocores-i2c.%d register failed!\n", i + 1); ++ } else { ++ i2c_ocores_device_data->device_flag = 0; /* device register suucess, set flag 0 */ ++ } ++ } ++ return 0; ++} ++ ++static void __exit wb_i2c_ocores_device_exit(void) ++{ ++ int i; ++ i2c_ocores_device_t *i2c_ocores_device_data; ++ ++ WB_I2C_OCORE_DEVICE_DEBUG_VERBOSE("enter!\n"); ++ for (i = ARRAY_SIZE(i2c_ocores_device) - 1; i >= 0; i--) { ++ i2c_ocores_device_data = i2c_ocores_device[i].dev.platform_data; ++ if (i2c_ocores_device_data->device_flag == 0) { /* device register success, need unregister */ ++ platform_device_unregister(&i2c_ocores_device[i]); ++ } ++ } ++} ++ ++module_init(wb_i2c_ocores_device_init); ++module_exit(wb_i2c_ocores_device_exit); ++MODULE_DESCRIPTION("I2C OCORES Devices"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_io_dev_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_io_dev_device.c +new file mode 100644 +index 000000000..cc84938ff +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_io_dev_device.c +@@ -0,0 +1,103 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++static int g_wb_io_dev_device_debug = 0; ++static int g_wb_io_dev_device_error = 0; ++ ++module_param(g_wb_io_dev_device_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_io_dev_device_error, int, S_IRUGO | S_IWUSR); ++ ++#define WB_IO_DEV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ ++ if (g_wb_io_dev_device_debug) { \ ++ printk(KERN_INFO "[WB_IO_DEV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_IO_DEV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_wb_io_dev_device_error) { \ ++ printk(KERN_ERR "[WB_IO_DEV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static io_dev_device_t io_dev_device_data0 = { ++ .io_dev_name = "cpld0", ++ .io_base = 0x700, ++ .io_len = 0x100, ++ .indirect_addr = 0, ++}; ++ ++static io_dev_device_t io_dev_device_data1 = { ++ .io_dev_name = "cpld1", ++ .io_base = 0x900, ++ .io_len = 0x100, ++ .indirect_addr = 0, ++}; ++ ++static void wb_io_dev_device_release(struct device *dev) ++{ ++ return; ++} ++ ++static struct platform_device io_dev_device[] = { ++ { ++ .name = "wb-io-dev", ++ .id = 1, ++ .dev = { ++ .platform_data = &io_dev_device_data0, ++ .release = wb_io_dev_device_release, ++ }, ++ }, ++ { ++ .name = "wb-io-dev", ++ .id = 2, ++ .dev = { ++ .platform_data = &io_dev_device_data1, ++ .release = wb_io_dev_device_release, ++ }, ++ }, ++}; ++ ++static int __init wb_io_dev_device_init(void) ++{ ++ int i; ++ int ret = 0; ++ io_dev_device_t *io_dev_device_data; ++ ++ WB_IO_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); ++ for (i = 0; i < ARRAY_SIZE(io_dev_device); i++) { ++ io_dev_device_data = io_dev_device[i].dev.platform_data; ++ ret = platform_device_register(&io_dev_device[i]); ++ if (ret < 0) { ++ io_dev_device_data->device_flag = -1; /* device register failed, set flag -1 */ ++ printk(KERN_ERR "wb-io-dev.%d register failed!\n", i + 1); ++ } else { ++ io_dev_device_data->device_flag = 0; /* device register suucess, set flag 0 */ ++ } ++ } ++ return 0; ++} ++ ++static void __exit wb_io_dev_device_exit(void) ++{ ++ int i; ++ io_dev_device_t *io_dev_device_data; ++ ++ WB_IO_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); ++ for (i = ARRAY_SIZE(io_dev_device) - 1; i >= 0; i--) { ++ io_dev_device_data = io_dev_device[i].dev.platform_data; ++ if (io_dev_device_data->device_flag == 0) { /* device register success, need unregister */ ++ platform_device_unregister(&io_dev_device[i]); ++ } ++ } ++} ++ ++module_init(wb_io_dev_device_init); ++module_exit(wb_io_dev_device_exit); ++MODULE_DESCRIPTION("IO DEV Devices"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_lpc_drv_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_lpc_drv_device.c +new file mode 100644 +index 000000000..9b6b61a51 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_lpc_drv_device.c +@@ -0,0 +1,130 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++static int g_wb_lpc_drv_device_debug = 0; ++static int g_wb_lpc_drv_device_error = 0; ++ ++module_param(g_wb_lpc_drv_device_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_lpc_drv_device_error, int, S_IRUGO | S_IWUSR); ++ ++#define WB_LPC_DRV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ ++ if (g_wb_lpc_drv_device_debug) { \ ++ printk(KERN_INFO "[WB_LPC_DRV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_LPC_DRV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_wb_lpc_drv_device_error) { \ ++ printk(KERN_ERR "[WB_LPC_DRV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static lpc_drv_device_t lpc_drv_device_data_0 = { ++ .lpc_io_name = "wb_lpc", ++ .pci_domain = 0x0000, ++ .pci_bus = 0x00, ++ .pci_slot = 0x1f, ++ .pci_fn = 0, ++ .lpc_io_base = 0x700, ++ .lpc_io_size = 0x100, ++ .lpc_gen_dec = 0x84, ++}; ++ ++static lpc_drv_device_t lpc_drv_device_data_1 = { ++ .lpc_io_name = "wb_lpc", ++ .pci_domain = 0x0000, ++ .pci_bus = 0x00, ++ .pci_slot = 0x1f, ++ .pci_fn = 0, ++ .lpc_io_base = 0x900, ++ .lpc_io_size = 0x100, ++ .lpc_gen_dec = 0x88, ++}; ++ ++static lpc_drv_device_t lpc_drv_device_data_2 = { ++ .lpc_io_name = "wb_lpc", ++ .pci_domain = 0x0000, ++ .pci_bus = 0x00, ++ .pci_slot = 0x1f, ++ .pci_fn = 0, ++ .lpc_io_base = 0xb00, ++ .lpc_io_size = 0x100, ++ .lpc_gen_dec = 0x90, ++}; ++ ++static void wb_lpc_drv_device_release(struct device *dev) ++{ ++ return; ++} ++ ++static struct platform_device lpc_drv_device[] = { ++ { ++ .name = "wb-lpc", ++ .id = 1, ++ .dev = { ++ .platform_data = &lpc_drv_device_data_0, ++ .release = wb_lpc_drv_device_release, ++ }, ++ }, ++ { ++ .name = "wb-lpc", ++ .id = 2, ++ .dev = { ++ .platform_data = &lpc_drv_device_data_1, ++ .release = wb_lpc_drv_device_release, ++ }, ++ }, ++ { ++ .name = "wb-lpc", ++ .id = 3, ++ .dev = { ++ .platform_data = &lpc_drv_device_data_2, ++ .release = wb_lpc_drv_device_release, ++ }, ++ }, ++}; ++ ++static int __init wb_lpc_drv_device_init(void) ++{ ++ int i; ++ int ret = 0; ++ lpc_drv_device_t *lpc_drv_device_data; ++ ++ WB_LPC_DRV_DEVICE_DEBUG_VERBOSE("enter!\n"); ++ for (i = 0; i < ARRAY_SIZE(lpc_drv_device); i++) { ++ lpc_drv_device_data = lpc_drv_device[i].dev.platform_data; ++ ret = platform_device_register(&lpc_drv_device[i]); ++ if (ret < 0) { ++ lpc_drv_device_data->device_flag = -1; /* device register failed, set flag -1 */ ++ printk(KERN_ERR "wb-lpc.%d register failed!\n", i + 1); ++ } else { ++ lpc_drv_device_data->device_flag = 0; /* device register suucess, set flag 0 */ ++ } ++ } ++ return 0; ++} ++ ++static void __exit wb_lpc_drv_device_exit(void) ++{ ++ int i; ++ lpc_drv_device_t *lpc_drv_device_data; ++ ++ WB_LPC_DRV_DEVICE_DEBUG_VERBOSE("enter!\n"); ++ for (i = ARRAY_SIZE(lpc_drv_device) - 1; i >= 0; i--) { ++ lpc_drv_device_data = lpc_drv_device[i].dev.platform_data; ++ if (lpc_drv_device_data->device_flag == 0) { /* device register success, need unregister */ ++ platform_device_unregister(&lpc_drv_device[i]); ++ } ++ } ++} ++ ++module_init(wb_lpc_drv_device_init); ++module_exit(wb_lpc_drv_device_exit); ++MODULE_DESCRIPTION("LPC DRV Devices"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_pcie_dev_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_pcie_dev_device.c +new file mode 100644 +index 000000000..f79b29770 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_pcie_dev_device.c +@@ -0,0 +1,93 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++static int g_wb_pcie_dev_device_debug = 0; ++static int g_wb_pcie_dev_device_error = 0; ++ ++module_param(g_wb_pcie_dev_device_debug, int, S_IRUGO | S_IWUSR); ++module_param(g_wb_pcie_dev_device_error, int, S_IRUGO | S_IWUSR); ++ ++#define WB_PCIE_DEV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ ++ if (g_wb_pcie_dev_device_debug) { \ ++ printk(KERN_INFO "[WB_PCIE_DEV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++#define WB_PCIE_DEV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ ++ if (g_wb_pcie_dev_device_error) { \ ++ printk(KERN_ERR "[WB_PCIE_DEV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ ++ } \ ++} while (0) ++ ++static pci_dev_device_t pcie_dev_device_data0 = { ++ .pci_dev_name = "fpga0", ++ .pci_domain = 0x0000, ++ .pci_bus = 0x08, ++ .pci_slot = 0x00, ++ .pci_fn = 0, ++ .pci_bar = 0, ++ .bus_width = 4, ++ .upg_ctrl_base = 0xa00, ++ .upg_flash_base = 0x1a0000, ++}; ++ ++static void wb_pcie_dev_device_release(struct device *dev) ++{ ++ return; ++} ++ ++static struct platform_device pcie_dev_device[] = { ++ { ++ .name = "wb-pci-dev", ++ .id = 1, ++ .dev = { ++ .platform_data = &pcie_dev_device_data0, ++ .release = wb_pcie_dev_device_release, ++ }, ++ }, ++}; ++ ++static int __init wb_pcie_dev_device_init(void) ++{ ++ int i; ++ int ret = 0; ++ pci_dev_device_t *pcie_dev_device_data; ++ ++ WB_PCIE_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); ++ for (i = 0; i < ARRAY_SIZE(pcie_dev_device); i++) { ++ pcie_dev_device_data = pcie_dev_device[i].dev.platform_data; ++ ret = platform_device_register(&pcie_dev_device[i]); ++ if (ret < 0) { ++ pcie_dev_device_data->device_flag = -1; /* device register failed, set flag -1 */ ++ printk(KERN_ERR "wb-pci-dev.%d register failed!\n", i + 1); ++ } else { ++ pcie_dev_device_data->device_flag = 0; /* device register suucess, set flag 0 */ ++ } ++ } ++ return 0; ++} ++ ++static void __exit wb_pcie_dev_device_exit(void) ++{ ++ int i; ++ pci_dev_device_t *pcie_dev_device_data; ++ ++ WB_PCIE_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); ++ for (i = ARRAY_SIZE(pcie_dev_device) - 1; i >= 0; i--) { ++ pcie_dev_device_data = pcie_dev_device[i].dev.platform_data; ++ if (pcie_dev_device_data->device_flag == 0) { /* device register success, need unregister */ ++ platform_device_unregister(&pcie_dev_device[i]); ++ } ++ } ++} ++ ++module_init(wb_pcie_dev_device_init); ++module_exit(wb_pcie_dev_device_exit); ++MODULE_DESCRIPTION("PCIE DEV Devices"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("support"); +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_CPLD.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_CPLD.cfg +new file mode 100644 +index 000000000..98d1da175 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_CPLD.cfg +@@ -0,0 +1,41 @@ ++# configuration item: I2C address of CPLD ++# format: cpld_i2c_dev.bus_[cpld_slot]_[cpld_id] cpld_i2c_dev.addr_[cpld_slot]_[cpld_id] ++# cpld_slot: Main card: 0, linear card: start from 1 ++# cpld_id: start from 0 ++# bus: I2C bus number of CPLD ++# addr: I2C address of CPLD ++cpld_i2c_dev.bus_0_2=2 ++cpld_i2c_dev.addr_0_2=0x0d ++cpld_i2c_dev.bus_0_3=8 ++cpld_i2c_dev.addr_0_3=0x30 ++cpld_i2c_dev.bus_0_4=8 ++cpld_i2c_dev.addr_0_4=0x31 ++cpld_i2c_dev.bus_0_5=6 ++cpld_i2c_dev.addr_0_5=0x0d ++ ++ ++# configuration item: LPC address of CPLD ++# format: cpld_lpc_addr_[cpld_slot]_[cpld_id] ++# cpld_slot: Main card: 0, linear card: start from 1 ++# cpld_id: start from 0 ++cpld_lpc_dev_0_0=0x700 ++cpld_lpc_dev_0_1=0x900 ++ ++ ++# configuration item: CPLD access method, lpc or i2c ++# format: mode_cpld_[cpld_slot][cpld_slot]=lpc/i2c ++# cpld_slot: Main card: 0, linear card: start from 1 ++# cpld_id: start from 0 ++mode_cpld_0_0=lpc ++mode_cpld_0_1=lpc ++mode_cpld_0_2=i2c ++mode_cpld_0_3=i2c ++mode_cpld_0_4=i2c ++mode_cpld_0_5=i2c ++ ++ ++# configuration item: the number of CPLD ++# format: dev_num_[main_dev]_[minor_dev] ++# main_dev: CPLD main_dev is 4 ++# minor_dev: CPLD minor_dev not exist ++dev_num_4_0=6 +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_FAN.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_FAN.cfg +new file mode 100644 +index 000000000..2350b74eb +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_FAN.cfg +@@ -0,0 +1,304 @@ ++# configuration item: the number of fans ++# format: dev_num_[main_dev]_[minor_dev] ++# main_dev: fan main_dev is 1 ++# minor_dev: fan minor_dev not exist(0) ++dev_num_1_0=4 ++ ++ ++# configuration item: the number of rotors ++# format: dev_num_[main_dev]_[minor_dev] ++# main_dev: rotor main_dev is 1 ++# minor_dev: rotor minor_dev is 5 ++dev_num_1_5=2 ++ ++ ++# configuration item: fan presence status ++# format: dev_present_status_[main_dev_id][fan_index] ++# main_dev_id: fan main_dev_id is 1 ++# fan_index: start from 1 ++dev_present_status.mode_1_1=config ++dev_present_status.src_1_1=cpld ++dev_present_status.frmt_1_1=bit ++dev_present_status.pola_1_1=negative ++dev_present_status.addr_1_1=0x00020030 ++dev_present_status.len_1_1=1 ++dev_present_status.bit_offset_1_1=0 ++ ++dev_present_status.mode_1_2=config ++dev_present_status.src_1_2=cpld ++dev_present_status.frmt_1_2=bit ++dev_present_status.pola_1_2=negative ++dev_present_status.addr_1_2=0x00020030 ++dev_present_status.len_1_2=1 ++dev_present_status.bit_offset_1_2=1 ++ ++dev_present_status.mode_1_3=config ++dev_present_status.src_1_3=cpld ++dev_present_status.frmt_1_3=bit ++dev_present_status.pola_1_3=negative ++dev_present_status.addr_1_3=0x00020030 ++dev_present_status.len_1_3=1 ++dev_present_status.bit_offset_1_3=2 ++ ++dev_present_status.mode_1_4=config ++dev_present_status.src_1_4=cpld ++dev_present_status.frmt_1_4=bit ++dev_present_status.pola_1_4=negative ++dev_present_status.addr_1_4=0x00020030 ++dev_present_status.len_1_4=1 ++dev_present_status.bit_offset_1_4=3 ++ ++ ++# configuration item: fan rotor status ++# format: fan_roll_status_[fan_id]_[motor_id] ++# fan_id: start from 1 ++# motor_id: start from 0 ++fan_roll_status.mode_1_0=config ++fan_roll_status.int_cons_1_0= ++fan_roll_status.src_1_0=cpld ++fan_roll_status.frmt_1_0=bit ++fan_roll_status.pola_1_0=positive ++fan_roll_status.fpath_1_0= ++fan_roll_status.addr_1_0=0x00020031 ++fan_roll_status.len_1_0=1 ++fan_roll_status.bit_offset_1_0=0 ++ ++fan_roll_status.mode_1_1=config ++fan_roll_status.int_cons_1_1= ++fan_roll_status.src_1_1=cpld ++fan_roll_status.frmt_1_1=bit ++fan_roll_status.pola_1_1=positive ++fan_roll_status.fpath_1_1= ++fan_roll_status.addr_1_1=0x00020034 ++fan_roll_status.len_1_1=1 ++fan_roll_status.bit_offset_1_1=0 ++ ++fan_roll_status.mode_2_0=config ++fan_roll_status.int_cons_2_0= ++fan_roll_status.src_2_0=cpld ++fan_roll_status.frmt_2_0=bit ++fan_roll_status.pola_2_0=positive ++fan_roll_status.fpath_2_0= ++fan_roll_status.addr_2_0=0x00020031 ++fan_roll_status.len_2_0=1 ++fan_roll_status.bit_offset_2_0=1 ++ ++fan_roll_status.mode_2_1=config ++fan_roll_status.int_cons_2_1= ++fan_roll_status.src_2_1=cpld ++fan_roll_status.frmt_2_1=bit ++fan_roll_status.pola_2_1=positive ++fan_roll_status.fpath_2_1= ++fan_roll_status.addr_2_1=0x00020034 ++fan_roll_status.len_2_1=1 ++fan_roll_status.bit_offset_2_1=1 ++ ++fan_roll_status.mode_3_0=config ++fan_roll_status.int_cons_3_0= ++fan_roll_status.src_3_0=cpld ++fan_roll_status.frmt_3_0=bit ++fan_roll_status.pola_3_0=positive ++fan_roll_status.fpath_3_0= ++fan_roll_status.addr_3_0=0x00020031 ++fan_roll_status.len_3_0=1 ++fan_roll_status.bit_offset_3_0=2 ++ ++fan_roll_status.mode_3_1=config ++fan_roll_status.int_cons_3_1= ++fan_roll_status.src_3_1=cpld ++fan_roll_status.frmt_3_1=bit ++fan_roll_status.pola_3_1=positive ++fan_roll_status.fpath_3_1= ++fan_roll_status.addr_3_1=0x00020034 ++fan_roll_status.len_3_1=1 ++fan_roll_status.bit_offset_3_1=2 ++ ++fan_roll_status.mode_4_0=config ++fan_roll_status.int_cons_4_0= ++fan_roll_status.src_4_0=cpld ++fan_roll_status.frmt_4_0=bit ++fan_roll_status.pola_4_0=positive ++fan_roll_status.fpath_4_0= ++fan_roll_status.addr_4_0=0x00020031 ++fan_roll_status.len_4_0=1 ++fan_roll_status.bit_offset_4_0=3 ++ ++fan_roll_status.mode_4_1=config ++fan_roll_status.int_cons_4_1= ++fan_roll_status.src_4_1=cpld ++fan_roll_status.frmt_4_1=bit ++fan_roll_status.pola_4_1=positive ++fan_roll_status.fpath_4_1= ++fan_roll_status.addr_4_1=0x00020034 ++fan_roll_status.len_4_1=1 ++fan_roll_status.bit_offset_4_1=3 ++ ++ ++# configuration item: fan speed ++# format: fan_speed_[fan_id]_[motor_id] ++# fan_id: start from 1 ++# motor_id: start from 0 ++fan_speed.mode_1_0=config ++fan_speed.int_cons_1_0= ++fan_speed.src_1_0=cpld ++fan_speed.frmt_1_0=num_bytes ++fan_speed.pola_1_0=negative ++fan_speed.fpath_1_0= ++fan_speed.addr_1_0=0x0002001b ++fan_speed.len_1_0=2 ++fan_speed.bit_offset_1_0= ++ ++fan_speed.mode_1_1=config ++fan_speed.int_cons_1_1= ++fan_speed.src_1_1=cpld ++fan_speed.frmt_1_1=num_bytes ++fan_speed.pola_1_1=negative ++fan_speed.fpath_1_1= ++fan_speed.addr_1_1=0x00020025 ++fan_speed.len_1_1=2 ++fan_speed.bit_offset_1_1= ++ ++fan_speed.mode_2_0=config ++fan_speed.int_cons_2_0= ++fan_speed.src_2_0=cpld ++fan_speed.frmt_2_0=num_bytes ++fan_speed.pola_2_0=negative ++fan_speed.fpath_2_0= ++fan_speed.addr_2_0=0x0002001d ++fan_speed.len_2_0=2 ++fan_speed.bit_offset_2_0= ++ ++fan_speed.mode_2_1=config ++fan_speed.int_cons_2_1= ++fan_speed.src_2_1=cpld ++fan_speed.frmt_2_1=num_bytes ++fan_speed.pola_2_1=negative ++fan_speed.fpath_2_1= ++fan_speed.addr_2_1=0x00020027 ++fan_speed.len_2_1=2 ++fan_speed.bit_offset_2_1= ++ ++fan_speed.mode_3_0=config ++fan_speed.int_cons_3_0= ++fan_speed.src_3_0=cpld ++fan_speed.frmt_3_0=num_bytes ++fan_speed.pola_3_0=negative ++fan_speed.fpath_3_0= ++fan_speed.addr_3_0=0x0002001f ++fan_speed.len_3_0=2 ++fan_speed.bit_offset_3_0= ++ ++fan_speed.mode_3_1=config ++fan_speed.int_cons_3_1= ++fan_speed.src_3_1=cpld ++fan_speed.frmt_3_1=num_bytes ++fan_speed.pola_3_1=negative ++fan_speed.fpath_3_1= ++fan_speed.addr_3_1=0x00020029 ++fan_speed.len_3_1=2 ++fan_speed.bit_offset_3_1= ++ ++fan_speed.mode_4_0=config ++fan_speed.int_cons_4_0= ++fan_speed.src_4_0=cpld ++fan_speed.frmt_4_0=num_bytes ++fan_speed.pola_4_0=negative ++fan_speed.fpath_4_0= ++fan_speed.addr_4_0=0x00020021 ++fan_speed.len_4_0=2 ++fan_speed.bit_offset_4_0= ++ ++fan_speed.mode_4_1=config ++fan_speed.int_cons_4_1= ++fan_speed.src_4_1=cpld ++fan_speed.frmt_4_1=num_bytes ++fan_speed.pola_4_1=negative ++fan_speed.fpath_4_1= ++fan_speed.addr_4_1=0x0002002b ++fan_speed.len_4_1=2 ++fan_speed.bit_offset_4_1= ++ ++ ++# configuration item: fan pwm ++# format: fan_ratio_[fan_id]_[motor_id] ++# fan_id: start from 1 ++# motor_id: start from 0 ++fan_ratio.mode_1_0=config ++fan_ratio.int_cons_1_0= ++fan_ratio.src_1_0=cpld ++fan_ratio.frmt_1_0=byte ++fan_ratio.pola_1_0= ++fan_ratio.fpath_1_0= ++fan_ratio.addr_1_0=0x00020014 ++fan_ratio.len_1_0=1 ++fan_ratio.bit_offset_1_0= ++ ++fan_ratio.mode_1_1=config ++fan_ratio.int_cons_1_1= ++fan_ratio.src_1_1=cpld ++fan_ratio.frmt_1_1=byte ++fan_ratio.pola_1_1= ++fan_ratio.fpath_1_1= ++fan_ratio.addr_1_1=0x00020014 ++fan_ratio.len_1_1=1 ++fan_ratio.bit_offset_1_1= ++ ++fan_ratio.mode_2_0=config ++fan_ratio.int_cons_2_0= ++fan_ratio.src_2_0=cpld ++fan_ratio.frmt_2_0=byte ++fan_ratio.pola_2_0= ++fan_ratio.fpath_2_0= ++fan_ratio.addr_2_0=0x00020015 ++fan_ratio.len_2_0=1 ++fan_ratio.bit_offset_2_0= ++ ++fan_ratio.mode_2_1=config ++fan_ratio.int_cons_2_1= ++fan_ratio.src_2_1=cpld ++fan_ratio.frmt_2_1=byte ++fan_ratio.pola_2_1= ++fan_ratio.fpath_2_1= ++fan_ratio.addr_2_1=0x00020015 ++fan_ratio.len_2_1=1 ++fan_ratio.bit_offset_2_1= ++ ++fan_ratio.mode_3_0=config ++fan_ratio.int_cons_3_0= ++fan_ratio.src_3_0=cpld ++fan_ratio.frmt_3_0=byte ++fan_ratio.pola_3_0= ++fan_ratio.fpath_3_0= ++fan_ratio.addr_3_0=0x00020016 ++fan_ratio.len_3_0=1 ++fan_ratio.bit_offset_3_0= ++ ++fan_ratio.mode_3_1=config ++fan_ratio.int_cons_3_1= ++fan_ratio.src_3_1=cpld ++fan_ratio.frmt_3_1=byte ++fan_ratio.pola_3_1= ++fan_ratio.fpath_3_1= ++fan_ratio.addr_3_1=0x00020016 ++fan_ratio.len_3_1=1 ++fan_ratio.bit_offset_3_1= ++ ++fan_ratio.mode_4_0=config ++fan_ratio.int_cons_4_0= ++fan_ratio.src_4_0=cpld ++fan_ratio.frmt_4_0=byte ++fan_ratio.pola_4_0= ++fan_ratio.fpath_4_0= ++fan_ratio.addr_4_0=0x00020017 ++fan_ratio.len_4_0=1 ++fan_ratio.bit_offset_4_0= ++ ++fan_ratio.mode_4_1=config ++fan_ratio.int_cons_4_1= ++fan_ratio.src_4_1=cpld ++fan_ratio.frmt_4_1=byte ++fan_ratio.pola_4_1= ++fan_ratio.fpath_4_1= ++fan_ratio.addr_4_1=0x00020017 ++fan_ratio.len_4_1=1 ++fan_ratio.bit_offset_4_1= +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_PSU.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_PSU.cfg +new file mode 100644 +index 000000000..082ef20fe +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_PSU.cfg +@@ -0,0 +1,64 @@ ++# configuration item: the number of psus ++# format: dev_num_[main_dev]_[minor_dev] ++# main_dev: psu main_dev is 2 ++# minor_dev: psu minor_dev not exist(0) ++dev_num_2_0=2 ++ ++ ++# configuration item: psu status ++# format: psu_status_[psu_index]_[status_id] ++# psu_index: start from 1 ++# status_id: 0: presence 1: output 2: alert ++# psu1 presence status ++psu_status.mode_1_0=config ++psu_status.src_1_0=cpld ++psu_status.frmt_1_0=bit ++psu_status.pola_1_0=negative ++psu_status.addr_1_0=0x00050051 ++psu_status.len_1_0=1 ++psu_status.bit_offset_1_0=0 ++ ++# psu1 output status ++psu_status.mode_1_1=config ++psu_status.src_1_1=cpld ++psu_status.frmt_1_1=bit ++psu_status.pola_1_1=positive ++psu_status.addr_1_1=0x00050051 ++psu_status.len_1_1=1 ++psu_status.bit_offset_1_1=1 ++ ++# psu1 alert status ++psu_status.mode_1_2=config ++psu_status.src_1_2=cpld ++psu_status.frmt_1_2=bit ++psu_status.pola_1_2=negative ++psu_status.addr_1_2=0x00050051 ++psu_status.len_1_2=1 ++psu_status.bit_offset_1_2=2 ++ ++# psu2 presence status ++psu_status.mode_2_0=config ++psu_status.src_2_0=cpld ++psu_status.frmt_2_0=bit ++psu_status.pola_2_0=negative ++psu_status.addr_2_0=0x00050051 ++psu_status.len_2_0=1 ++psu_status.bit_offset_2_0=4 ++ ++# psu2 output status ++psu_status.mode_2_1=config ++psu_status.src_2_1=cpld ++psu_status.frmt_2_1=bit ++psu_status.pola_2_1=positive ++psu_status.addr_2_1=0x00050051 ++psu_status.len_2_1=1 ++psu_status.bit_offset_2_1=5 ++ ++# psu2 alert status ++psu_status.mode_2_2=config ++psu_status.src_2_2=cpld ++psu_status.frmt_2_2=bit ++psu_status.pola_2_2=negative ++psu_status.addr_2_2=0x00050051 ++psu_status.len_2_2=1 ++psu_status.bit_offset_2_2=6 +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_SFF.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_SFF.cfg +new file mode 100644 +index 000000000..7f57dfd93 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_SFF.cfg +@@ -0,0 +1,521 @@ ++# configuration item: the number of sffs ++# format: dev_num_[main_dev]_[minor_dev] ++# main_dev: sff main_dev is 3 ++# minor_dev: sff minor_dev not exist(0) ++dev_num_3_0=56 ++ ++# configuration item: The directory name of sff sysfs ++# format: sff_dir_name_[sff_index] ++# sff_index: start from 1 ++sff_dir_name_1 =sff1 ++sff_dir_name_2 =sff2 ++sff_dir_name_3 =sff3 ++sff_dir_name_4 =sff4 ++sff_dir_name_5 =sff5 ++sff_dir_name_6 =sff6 ++sff_dir_name_7 =sff7 ++sff_dir_name_8 =sff8 ++sff_dir_name_9 =sff9 ++sff_dir_name_10 =sff10 ++sff_dir_name_11 =sff11 ++sff_dir_name_12 =sff12 ++sff_dir_name_13 =sff13 ++sff_dir_name_14 =sff14 ++sff_dir_name_15 =sff15 ++sff_dir_name_16 =sff16 ++sff_dir_name_17 =sff17 ++sff_dir_name_18 =sff18 ++sff_dir_name_19 =sff19 ++sff_dir_name_20 =sff20 ++sff_dir_name_21 =sff21 ++sff_dir_name_22 =sff22 ++sff_dir_name_23 =sff23 ++sff_dir_name_24 =sff24 ++sff_dir_name_25 =sff25 ++sff_dir_name_26 =sff26 ++sff_dir_name_27 =sff27 ++sff_dir_name_28 =sff28 ++sff_dir_name_29 =sff29 ++sff_dir_name_30 =sff30 ++sff_dir_name_31 =sff31 ++sff_dir_name_32 =sff32 ++sff_dir_name_33 =sff33 ++sff_dir_name_34 =sff34 ++sff_dir_name_35 =sff35 ++sff_dir_name_36 =sff36 ++sff_dir_name_37 =sff37 ++sff_dir_name_38 =sff38 ++sff_dir_name_39 =sff39 ++sff_dir_name_40 =sff40 ++sff_dir_name_41 =sff41 ++sff_dir_name_42 =sff42 ++sff_dir_name_43 =sff43 ++sff_dir_name_44 =sff44 ++sff_dir_name_45 =sff45 ++sff_dir_name_46 =sff46 ++sff_dir_name_47 =sff47 ++sff_dir_name_48 =sff48 ++sff_dir_name_49 =sff49 ++sff_dir_name_50 =sff50 ++sff_dir_name_51 =sff51 ++sff_dir_name_52 =sff52 ++sff_dir_name_53 =sff53 ++sff_dir_name_54 =sff54 ++sff_dir_name_55 =sff55 ++sff_dir_name_56 =sff56 ++ ++ ++# configuration item: sff cpld register status ++# format: sff_cpld_reg_[sff_index]_[cpld_reg] ++# sff_index: start from 1 ++# cpld_reg: 1: power_on, 2: tx_fault, 3: tx_dis, 4:pre_n, 5:rx_los ++# 6: reset, 7: lpmode, 8: module_present, 9: interrupt ++ ++# sff cpld presence status ++sff_cpld_reg.mode_1_8=config ++sff_cpld_reg.src_1_8=cpld ++sff_cpld_reg.frmt_1_8=bit ++sff_cpld_reg.pola_1_8=negative ++sff_cpld_reg.addr_1_8=0x00030030 ++sff_cpld_reg.len_1_8=1 ++sff_cpld_reg.bit_offset_1_8=0 ++ ++sff_cpld_reg.mode_2_8=config ++sff_cpld_reg.src_2_8=cpld ++sff_cpld_reg.frmt_2_8=bit ++sff_cpld_reg.pola_2_8=negative ++sff_cpld_reg.addr_2_8=0x00030030 ++sff_cpld_reg.len_2_8=1 ++sff_cpld_reg.bit_offset_2_8=1 ++ ++sff_cpld_reg.mode_3_8=config ++sff_cpld_reg.src_3_8=cpld ++sff_cpld_reg.frmt_3_8=bit ++sff_cpld_reg.pola_3_8=negative ++sff_cpld_reg.addr_3_8=0x00030030 ++sff_cpld_reg.len_3_8=1 ++sff_cpld_reg.bit_offset_3_8=2 ++ ++sff_cpld_reg.mode_4_8=config ++sff_cpld_reg.src_4_8=cpld ++sff_cpld_reg.frmt_4_8=bit ++sff_cpld_reg.pola_4_8=negative ++sff_cpld_reg.addr_4_8=0x00030030 ++sff_cpld_reg.len_4_8=1 ++sff_cpld_reg.bit_offset_4_8=3 ++ ++sff_cpld_reg.mode_5_8=config ++sff_cpld_reg.src_5_8=cpld ++sff_cpld_reg.frmt_5_8=bit ++sff_cpld_reg.pola_5_8=negative ++sff_cpld_reg.addr_5_8=0x00030030 ++sff_cpld_reg.len_5_8=1 ++sff_cpld_reg.bit_offset_5_8=4 ++ ++sff_cpld_reg.mode_6_8=config ++sff_cpld_reg.src_6_8=cpld ++sff_cpld_reg.frmt_6_8=bit ++sff_cpld_reg.pola_6_8=negative ++sff_cpld_reg.addr_6_8=0x00030030 ++sff_cpld_reg.len_6_8=1 ++sff_cpld_reg.bit_offset_6_8=5 ++ ++sff_cpld_reg.mode_7_8=config ++sff_cpld_reg.src_7_8=cpld ++sff_cpld_reg.frmt_7_8=bit ++sff_cpld_reg.pola_7_8=negative ++sff_cpld_reg.addr_7_8=0x00030030 ++sff_cpld_reg.len_7_8=1 ++sff_cpld_reg.bit_offset_7_8=6 ++ ++sff_cpld_reg.mode_8_8=config ++sff_cpld_reg.src_8_8=cpld ++sff_cpld_reg.frmt_8_8=bit ++sff_cpld_reg.pola_8_8=negative ++sff_cpld_reg.addr_8_8=0x00030030 ++sff_cpld_reg.len_8_8=1 ++sff_cpld_reg.bit_offset_8_8=7 ++ ++sff_cpld_reg.mode_9_8=config ++sff_cpld_reg.src_9_8=cpld ++sff_cpld_reg.frmt_9_8=bit ++sff_cpld_reg.pola_9_8=negative ++sff_cpld_reg.addr_9_8=0x00030031 ++sff_cpld_reg.len_9_8=1 ++sff_cpld_reg.bit_offset_9_8=0 ++ ++sff_cpld_reg.mode_10_8=config ++sff_cpld_reg.src_10_8=cpld ++sff_cpld_reg.frmt_10_8=bit ++sff_cpld_reg.pola_10_8=negative ++sff_cpld_reg.addr_10_8=0x00030031 ++sff_cpld_reg.len_10_8=1 ++sff_cpld_reg.bit_offset_10_8=1 ++ ++sff_cpld_reg.mode_11_8=config ++sff_cpld_reg.src_11_8=cpld ++sff_cpld_reg.frmt_11_8=bit ++sff_cpld_reg.pola_11_8=negative ++sff_cpld_reg.addr_11_8=0x00030031 ++sff_cpld_reg.len_11_8=1 ++sff_cpld_reg.bit_offset_11_8=2 ++ ++sff_cpld_reg.mode_12_8=config ++sff_cpld_reg.src_12_8=cpld ++sff_cpld_reg.frmt_12_8=bit ++sff_cpld_reg.pola_12_8=negative ++sff_cpld_reg.addr_12_8=0x00030031 ++sff_cpld_reg.len_12_8=1 ++sff_cpld_reg.bit_offset_12_8=3 ++ ++sff_cpld_reg.mode_13_8=config ++sff_cpld_reg.src_13_8=cpld ++sff_cpld_reg.frmt_13_8=bit ++sff_cpld_reg.pola_13_8=negative ++sff_cpld_reg.addr_13_8=0x00030031 ++sff_cpld_reg.len_13_8=1 ++sff_cpld_reg.bit_offset_13_8=4 ++ ++sff_cpld_reg.mode_14_8=config ++sff_cpld_reg.src_14_8=cpld ++sff_cpld_reg.frmt_14_8=bit ++sff_cpld_reg.pola_14_8=negative ++sff_cpld_reg.addr_14_8=0x00030031 ++sff_cpld_reg.len_14_8=1 ++sff_cpld_reg.bit_offset_14_8=5 ++ ++sff_cpld_reg.mode_15_8=config ++sff_cpld_reg.src_15_8=cpld ++sff_cpld_reg.frmt_15_8=bit ++sff_cpld_reg.pola_15_8=negative ++sff_cpld_reg.addr_15_8=0x00030031 ++sff_cpld_reg.len_15_8=1 ++sff_cpld_reg.bit_offset_15_8=6 ++ ++sff_cpld_reg.mode_16_8=config ++sff_cpld_reg.src_16_8=cpld ++sff_cpld_reg.frmt_16_8=bit ++sff_cpld_reg.pola_16_8=negative ++sff_cpld_reg.addr_16_8=0x00030031 ++sff_cpld_reg.len_16_8=1 ++sff_cpld_reg.bit_offset_16_8=7 ++ ++sff_cpld_reg.mode_17_8=config ++sff_cpld_reg.src_17_8=cpld ++sff_cpld_reg.frmt_17_8=bit ++sff_cpld_reg.pola_17_8=negative ++sff_cpld_reg.addr_17_8=0x00030032 ++sff_cpld_reg.len_17_8=1 ++sff_cpld_reg.bit_offset_17_8=0 ++ ++sff_cpld_reg.mode_18_8=config ++sff_cpld_reg.src_18_8=cpld ++sff_cpld_reg.frmt_18_8=bit ++sff_cpld_reg.pola_18_8=negative ++sff_cpld_reg.addr_18_8=0x00030032 ++sff_cpld_reg.len_18_8=1 ++sff_cpld_reg.bit_offset_18_8=1 ++ ++sff_cpld_reg.mode_19_8=config ++sff_cpld_reg.src_19_8=cpld ++sff_cpld_reg.frmt_19_8=bit ++sff_cpld_reg.pola_19_8=negative ++sff_cpld_reg.addr_19_8=0x00030032 ++sff_cpld_reg.len_19_8=1 ++sff_cpld_reg.bit_offset_19_8=2 ++ ++sff_cpld_reg.mode_20_8=config ++sff_cpld_reg.src_20_8=cpld ++sff_cpld_reg.frmt_20_8=bit ++sff_cpld_reg.pola_20_8=negative ++sff_cpld_reg.addr_20_8=0x00030032 ++sff_cpld_reg.len_20_8=1 ++sff_cpld_reg.bit_offset_20_8=3 ++ ++sff_cpld_reg.mode_21_8=config ++sff_cpld_reg.src_21_8=cpld ++sff_cpld_reg.frmt_21_8=bit ++sff_cpld_reg.pola_21_8=negative ++sff_cpld_reg.addr_21_8=0x00030032 ++sff_cpld_reg.len_21_8=1 ++sff_cpld_reg.bit_offset_21_8=4 ++ ++sff_cpld_reg.mode_22_8=config ++sff_cpld_reg.src_22_8=cpld ++sff_cpld_reg.frmt_22_8=bit ++sff_cpld_reg.pola_22_8=negative ++sff_cpld_reg.addr_22_8=0x00030032 ++sff_cpld_reg.len_22_8=1 ++sff_cpld_reg.bit_offset_22_8=5 ++ ++sff_cpld_reg.mode_23_8=config ++sff_cpld_reg.src_23_8=cpld ++sff_cpld_reg.frmt_23_8=bit ++sff_cpld_reg.pola_23_8=negative ++sff_cpld_reg.addr_23_8=0x00030032 ++sff_cpld_reg.len_23_8=1 ++sff_cpld_reg.bit_offset_23_8=6 ++ ++sff_cpld_reg.mode_24_8=config ++sff_cpld_reg.src_24_8=cpld ++sff_cpld_reg.frmt_24_8=bit ++sff_cpld_reg.pola_24_8=negative ++sff_cpld_reg.addr_24_8=0x00030032 ++sff_cpld_reg.len_24_8=1 ++sff_cpld_reg.bit_offset_24_8=7 ++ ++sff_cpld_reg.mode_25_8=config ++sff_cpld_reg.src_25_8=cpld ++sff_cpld_reg.frmt_25_8=bit ++sff_cpld_reg.pola_25_8=negative ++sff_cpld_reg.addr_25_8=0x00040030 ++sff_cpld_reg.len_25_8=1 ++sff_cpld_reg.bit_offset_25_8=0 ++ ++sff_cpld_reg.mode_26_8=config ++sff_cpld_reg.src_26_8=cpld ++sff_cpld_reg.frmt_26_8=bit ++sff_cpld_reg.pola_26_8=negative ++sff_cpld_reg.addr_26_8=0x00040030 ++sff_cpld_reg.len_26_8=1 ++sff_cpld_reg.bit_offset_26_8=1 ++ ++sff_cpld_reg.mode_27_8=config ++sff_cpld_reg.src_27_8=cpld ++sff_cpld_reg.frmt_27_8=bit ++sff_cpld_reg.pola_27_8=negative ++sff_cpld_reg.addr_27_8=0x00040030 ++sff_cpld_reg.len_27_8=1 ++sff_cpld_reg.bit_offset_27_8=2 ++ ++sff_cpld_reg.mode_28_8=config ++sff_cpld_reg.src_28_8=cpld ++sff_cpld_reg.frmt_28_8=bit ++sff_cpld_reg.pola_28_8=negative ++sff_cpld_reg.addr_28_8=0x00040030 ++sff_cpld_reg.len_28_8=1 ++sff_cpld_reg.bit_offset_28_8=3 ++ ++sff_cpld_reg.mode_29_8=config ++sff_cpld_reg.src_29_8=cpld ++sff_cpld_reg.frmt_29_8=bit ++sff_cpld_reg.pola_29_8=negative ++sff_cpld_reg.addr_29_8=0x00040030 ++sff_cpld_reg.len_29_8=1 ++sff_cpld_reg.bit_offset_29_8=4 ++ ++sff_cpld_reg.mode_30_8=config ++sff_cpld_reg.src_30_8=cpld ++sff_cpld_reg.frmt_30_8=bit ++sff_cpld_reg.pola_30_8=negative ++sff_cpld_reg.addr_30_8=0x00040030 ++sff_cpld_reg.len_30_8=1 ++sff_cpld_reg.bit_offset_30_8=5 ++ ++sff_cpld_reg.mode_31_8=config ++sff_cpld_reg.src_31_8=cpld ++sff_cpld_reg.frmt_31_8=bit ++sff_cpld_reg.pola_31_8=negative ++sff_cpld_reg.addr_31_8=0x00040030 ++sff_cpld_reg.len_31_8=1 ++sff_cpld_reg.bit_offset_31_8=6 ++ ++sff_cpld_reg.mode_32_8=config ++sff_cpld_reg.src_32_8=cpld ++sff_cpld_reg.frmt_32_8=bit ++sff_cpld_reg.pola_32_8=negative ++sff_cpld_reg.addr_32_8=0x00040030 ++sff_cpld_reg.len_32_8=1 ++sff_cpld_reg.bit_offset_32_8=7 ++ ++sff_cpld_reg.mode_33_8=config ++sff_cpld_reg.src_33_8=cpld ++sff_cpld_reg.frmt_33_8=bit ++sff_cpld_reg.pola_33_8=negative ++sff_cpld_reg.addr_33_8=0x00040031 ++sff_cpld_reg.len_33_8=1 ++sff_cpld_reg.bit_offset_33_8=0 ++ ++sff_cpld_reg.mode_34_8=config ++sff_cpld_reg.src_34_8=cpld ++sff_cpld_reg.frmt_34_8=bit ++sff_cpld_reg.pola_34_8=negative ++sff_cpld_reg.addr_34_8=0x00040031 ++sff_cpld_reg.len_34_8=1 ++sff_cpld_reg.bit_offset_34_8=1 ++ ++sff_cpld_reg.mode_35_8=config ++sff_cpld_reg.src_35_8=cpld ++sff_cpld_reg.frmt_35_8=bit ++sff_cpld_reg.pola_35_8=negative ++sff_cpld_reg.addr_35_8=0x00040031 ++sff_cpld_reg.len_35_8=1 ++sff_cpld_reg.bit_offset_35_8=2 ++ ++sff_cpld_reg.mode_36_8=config ++sff_cpld_reg.src_36_8=cpld ++sff_cpld_reg.frmt_36_8=bit ++sff_cpld_reg.pola_36_8=negative ++sff_cpld_reg.addr_36_8=0x00040031 ++sff_cpld_reg.len_36_8=1 ++sff_cpld_reg.bit_offset_36_8=3 ++ ++sff_cpld_reg.mode_37_8=config ++sff_cpld_reg.src_37_8=cpld ++sff_cpld_reg.frmt_37_8=bit ++sff_cpld_reg.pola_37_8=negative ++sff_cpld_reg.addr_37_8=0x00040031 ++sff_cpld_reg.len_37_8=1 ++sff_cpld_reg.bit_offset_37_8=4 ++ ++sff_cpld_reg.mode_38_8=config ++sff_cpld_reg.src_38_8=cpld ++sff_cpld_reg.frmt_38_8=bit ++sff_cpld_reg.pola_38_8=negative ++sff_cpld_reg.addr_38_8=0x00040031 ++sff_cpld_reg.len_38_8=1 ++sff_cpld_reg.bit_offset_38_8=5 ++ ++sff_cpld_reg.mode_39_8=config ++sff_cpld_reg.src_39_8=cpld ++sff_cpld_reg.frmt_39_8=bit ++sff_cpld_reg.pola_39_8=negative ++sff_cpld_reg.addr_39_8=0x00040031 ++sff_cpld_reg.len_39_8=1 ++sff_cpld_reg.bit_offset_39_8=6 ++ ++sff_cpld_reg.mode_40_8=config ++sff_cpld_reg.src_40_8=cpld ++sff_cpld_reg.frmt_40_8=bit ++sff_cpld_reg.pola_40_8=negative ++sff_cpld_reg.addr_40_8=0x00040031 ++sff_cpld_reg.len_40_8=1 ++sff_cpld_reg.bit_offset_40_8=7 ++ ++sff_cpld_reg.mode_41_8=config ++sff_cpld_reg.src_41_8=cpld ++sff_cpld_reg.frmt_41_8=bit ++sff_cpld_reg.pola_41_8=negative ++sff_cpld_reg.addr_41_8=0x00040032 ++sff_cpld_reg.len_41_8=1 ++sff_cpld_reg.bit_offset_41_8=0 ++ ++sff_cpld_reg.mode_42_8=config ++sff_cpld_reg.src_42_8=cpld ++sff_cpld_reg.frmt_42_8=bit ++sff_cpld_reg.pola_42_8=negative ++sff_cpld_reg.addr_42_8=0x00040032 ++sff_cpld_reg.len_42_8=1 ++sff_cpld_reg.bit_offset_42_8=1 ++ ++sff_cpld_reg.mode_43_8=config ++sff_cpld_reg.src_43_8=cpld ++sff_cpld_reg.frmt_43_8=bit ++sff_cpld_reg.pola_43_8=negative ++sff_cpld_reg.addr_43_8=0x00040032 ++sff_cpld_reg.len_43_8=1 ++sff_cpld_reg.bit_offset_43_8=2 ++ ++sff_cpld_reg.mode_44_8=config ++sff_cpld_reg.src_44_8=cpld ++sff_cpld_reg.frmt_44_8=bit ++sff_cpld_reg.pola_44_8=negative ++sff_cpld_reg.addr_44_8=0x00040032 ++sff_cpld_reg.len_44_8=1 ++sff_cpld_reg.bit_offset_44_8=3 ++ ++sff_cpld_reg.mode_45_8=config ++sff_cpld_reg.src_45_8=cpld ++sff_cpld_reg.frmt_45_8=bit ++sff_cpld_reg.pola_45_8=negative ++sff_cpld_reg.addr_45_8=0x00040032 ++sff_cpld_reg.len_45_8=1 ++sff_cpld_reg.bit_offset_45_8=4 ++ ++sff_cpld_reg.mode_46_8=config ++sff_cpld_reg.src_46_8=cpld ++sff_cpld_reg.frmt_46_8=bit ++sff_cpld_reg.pola_46_8=negative ++sff_cpld_reg.addr_46_8=0x00040032 ++sff_cpld_reg.len_46_8=1 ++sff_cpld_reg.bit_offset_46_8=5 ++ ++sff_cpld_reg.mode_47_8=config ++sff_cpld_reg.src_47_8=cpld ++sff_cpld_reg.frmt_47_8=bit ++sff_cpld_reg.pola_47_8=negative ++sff_cpld_reg.addr_47_8=0x00040032 ++sff_cpld_reg.len_47_8=1 ++sff_cpld_reg.bit_offset_47_8=6 ++ ++sff_cpld_reg.mode_48_8=config ++sff_cpld_reg.src_48_8=cpld ++sff_cpld_reg.frmt_48_8=bit ++sff_cpld_reg.pola_48_8=negative ++sff_cpld_reg.addr_48_8=0x00040032 ++sff_cpld_reg.len_48_8=1 ++sff_cpld_reg.bit_offset_48_8=7 ++ ++sff_cpld_reg.mode_49_8=config ++sff_cpld_reg.src_49_8=cpld ++sff_cpld_reg.frmt_49_8=bit ++sff_cpld_reg.pola_49_8=negative ++sff_cpld_reg.addr_49_8=0x00040033 ++sff_cpld_reg.len_49_8=1 ++sff_cpld_reg.bit_offset_49_8=0 ++ ++sff_cpld_reg.mode_50_8=config ++sff_cpld_reg.src_50_8=cpld ++sff_cpld_reg.frmt_50_8=bit ++sff_cpld_reg.pola_50_8=negative ++sff_cpld_reg.addr_50_8=0x00040033 ++sff_cpld_reg.len_50_8=1 ++sff_cpld_reg.bit_offset_50_8=1 ++ ++sff_cpld_reg.mode_51_8=config ++sff_cpld_reg.src_51_8=cpld ++sff_cpld_reg.frmt_51_8=bit ++sff_cpld_reg.pola_51_8=negative ++sff_cpld_reg.addr_51_8=0x00040033 ++sff_cpld_reg.len_51_8=1 ++sff_cpld_reg.bit_offset_51_8=2 ++ ++sff_cpld_reg.mode_52_8=config ++sff_cpld_reg.src_52_8=cpld ++sff_cpld_reg.frmt_52_8=bit ++sff_cpld_reg.pola_52_8=negative ++sff_cpld_reg.addr_52_8=0x00040033 ++sff_cpld_reg.len_52_8=1 ++sff_cpld_reg.bit_offset_52_8=3 ++ ++sff_cpld_reg.mode_53_8=config ++sff_cpld_reg.src_53_8=cpld ++sff_cpld_reg.frmt_53_8=bit ++sff_cpld_reg.pola_53_8=negative ++sff_cpld_reg.addr_53_8=0x00040033 ++sff_cpld_reg.len_53_8=1 ++sff_cpld_reg.bit_offset_53_8=4 ++ ++sff_cpld_reg.mode_54_8=config ++sff_cpld_reg.src_54_8=cpld ++sff_cpld_reg.frmt_54_8=bit ++sff_cpld_reg.pola_54_8=negative ++sff_cpld_reg.addr_54_8=0x00040033 ++sff_cpld_reg.len_54_8=1 ++sff_cpld_reg.bit_offset_54_8=5 ++ ++sff_cpld_reg.mode_55_8=config ++sff_cpld_reg.src_55_8=cpld ++sff_cpld_reg.frmt_55_8=bit ++sff_cpld_reg.pola_55_8=negative ++sff_cpld_reg.addr_55_8=0x00040033 ++sff_cpld_reg.len_55_8=1 ++sff_cpld_reg.bit_offset_55_8=6 ++ ++sff_cpld_reg.mode_56_8=config ++sff_cpld_reg.src_56_8=cpld ++sff_cpld_reg.frmt_56_8=bit ++sff_cpld_reg.pola_56_8=negative ++sff_cpld_reg.addr_56_8=0x00040033 ++sff_cpld_reg.len_56_8=1 ++sff_cpld_reg.bit_offset_56_8=7 +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/cfg_file_name b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/cfg_file_name +new file mode 100644 +index 000000000..5f4942044 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/cfg_file_name +@@ -0,0 +1,4 @@ ++WB_PLAT_CPLD ++WB_PLAT_FAN ++WB_PLAT_PSU ++WB_PLAT_SFF +diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/setup.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/setup.py +new file mode 100644 +index 000000000..6c3916921 +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/setup.py +@@ -0,0 +1,39 @@ ++from setuptools import setup ++ ++setup( ++ name='sonic-platform', ++ version='1.0', ++ description='SONiC platform API implementation', ++ license='Apache 2.0', ++ author='SONiC Team', ++ author_email='support', ++ url='', ++ maintainer='support', ++ maintainer_email='', ++ packages=[ ++ 'sonic_platform', ++ 'plat_hal', ++ 'wbutil', ++ 'eepromutil', ++ 'hal-config', ++ 'config', ++ ], ++ py_modules=[ ++ 'hal_pltfm', ++ 'platform_util', ++ 'platform_intf', ++ ], ++ classifiers=[ ++ 'Development Status :: 3 - Alpha', ++ 'Environment :: Plugins', ++ 'Intended Audience :: Developers', ++ 'Intended Audience :: Information Technology', ++ 'Intended Audience :: System Administrators', ++ 'License :: OSI Approved :: Apache Software License', ++ 'Natural Language :: English', ++ 'Operating System :: POSIX :: Linux', ++ 'Programming Language :: Python :: 3.7', ++ 'Topic :: Utilities', ++ ], ++ keywords='sonic SONiC platform PLATFORM', ++) +diff --git a/src/sonic-device-data/tests/permitted_list b/src/sonic-device-data/tests/permitted_list +index 253dfe27c..0bb199868 100644 +--- a/src/sonic-device-data/tests/permitted_list ++++ b/src/sonic-device-data/tests/permitted_list +@@ -336,3 +336,9 @@ hybrid_pfc_deadlock_enable + sai_pfc_dlr_init_capability + appl_param_nof_ports_per_modid + sai_disable_srcmacqedstmac_ctrl ++svi_my_station_optimization ++warmboot_knet_shutdown_mode ++sai_stats_support_mask ++oversubscribe_mixed_sister_25_50_enable ++sai_fdb_entry_l2_discard_src_enable ++sai_pfc_defaults_disable +-- +2.25.1 + diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/hwsku.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/hwsku.json new file mode 100644 index 000000000000..9a5a4d2b6420 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/hwsku.json @@ -0,0 +1,172 @@ +{ + "interfaces": { + "Ethernet1": { + "default_brkout_mode": "1x25G" + }, + "Ethernet2": { + "default_brkout_mode": "1x25G" + }, + "Ethernet3": { + "default_brkout_mode": "1x25G" + }, + "Ethernet4": { + "default_brkout_mode": "1x25G" + }, + "Ethernet5": { + "default_brkout_mode": "1x25G" + }, + "Ethernet6": { + "default_brkout_mode": "1x25G" + }, + "Ethernet7": { + "default_brkout_mode": "1x25G" + }, + "Ethernet8": { + "default_brkout_mode": "1x25G" + }, + "Ethernet9": { + "default_brkout_mode": "1x25G" + }, + "Ethernet10": { + "default_brkout_mode": "1x25G" + }, + "Ethernet11": { + "default_brkout_mode": "1x25G" + }, + "Ethernet12": { + "default_brkout_mode": "1x25G" + }, + "Ethernet13": { + "default_brkout_mode": "1x25G" + }, + "Ethernet14": { + "default_brkout_mode": "1x25G" + }, + "Ethernet15": { + "default_brkout_mode": "1x25G" + }, + "Ethernet16": { + "default_brkout_mode": "1x25G" + }, + "Ethernet17": { + "default_brkout_mode": "1x25G" + }, + "Ethernet18": { + "default_brkout_mode": "1x25G" + }, + "Ethernet19": { + "default_brkout_mode": "1x25G" + }, + "Ethernet20": { + "default_brkout_mode": "1x25G" + }, + "Ethernet21": { + "default_brkout_mode": "1x25G" + }, + "Ethernet22": { + "default_brkout_mode": "1x25G" + }, + "Ethernet23": { + "default_brkout_mode": "1x25G" + }, + "Ethernet24": { + "default_brkout_mode": "1x25G" + }, + "Ethernet25": { + "default_brkout_mode": "1x25G" + }, + "Ethernet26": { + "default_brkout_mode": "1x25G" + }, + "Ethernet27": { + "default_brkout_mode": "1x25G" + }, + "Ethernet28": { + "default_brkout_mode": "1x25G" + }, + "Ethernet29": { + "default_brkout_mode": "1x25G" + }, + "Ethernet30": { + "default_brkout_mode": "1x25G" + }, + "Ethernet31": { + "default_brkout_mode": "1x25G" + }, + "Ethernet32": { + "default_brkout_mode": "1x25G" + }, + "Ethernet33": { + "default_brkout_mode": "1x25G" + }, + "Ethernet34": { + "default_brkout_mode": "1x25G" + }, + "Ethernet35": { + "default_brkout_mode": "1x25G" + }, + "Ethernet36": { + "default_brkout_mode": "1x25G" + }, + "Ethernet37": { + "default_brkout_mode": "1x25G" + }, + "Ethernet38": { + "default_brkout_mode": "1x25G" + }, + "Ethernet39": { + "default_brkout_mode": "1x25G" + }, + "Ethernet40": { + "default_brkout_mode": "1x25G" + }, + "Ethernet41": { + "default_brkout_mode": "1x25G" + }, + "Ethernet42": { + "default_brkout_mode": "1x25G" + }, + "Ethernet43": { + "default_brkout_mode": "1x25G" + }, + "Ethernet44": { + "default_brkout_mode": "1x25G" + }, + "Ethernet45": { + "default_brkout_mode": "1x25G" + }, + "Ethernet46": { + "default_brkout_mode": "1x25G" + }, + "Ethernet47": { + "default_brkout_mode": "1x25G" + }, + "Ethernet48": { + "default_brkout_mode": "1x25G" + }, + "Ethernet49": { + "default_brkout_mode": "1x100G" + }, + "Ethernet53": { + "default_brkout_mode": "1x100G" + }, + "Ethernet57": { + "default_brkout_mode": "1x100G" + }, + "Ethernet61": { + "default_brkout_mode": "1x100G" + }, + "Ethernet65": { + "default_brkout_mode": "1x100G" + }, + "Ethernet69": { + "default_brkout_mode": "1x100G" + }, + "Ethernet73": { + "default_brkout_mode": "1x100G" + }, + "Ethernet77": { + "default_brkout_mode": "1x100G" + } + } +} \ No newline at end of file diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/port_config.ini b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/port_config.ini new file mode 100755 index 000000000000..57d6132aac04 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/port_config.ini @@ -0,0 +1,57 @@ +# name lanes alias index speed admin_status +Ethernet1 57 twentyfiveGigE0/1 1 25000 up +Ethernet2 58 twentyfiveGigE0/2 2 25000 up +Ethernet3 59 twentyfiveGigE0/3 3 25000 up +Ethernet4 60 twentyfiveGigE0/4 4 25000 up +Ethernet5 61 twentyfiveGigE0/5 5 25000 up +Ethernet6 62 twentyfiveGigE0/6 6 25000 up +Ethernet7 63 twentyfiveGigE0/7 7 25000 up +Ethernet8 64 twentyfiveGigE0/8 8 25000 up +Ethernet9 1 twentyfiveGigE0/9 9 25000 up +Ethernet10 2 twentyfiveGigE0/10 10 25000 up +Ethernet11 3 twentyfiveGigE0/11 11 25000 up +Ethernet12 4 twentyfiveGigE0/12 12 25000 up +Ethernet13 5 twentyfiveGigE0/13 13 25000 up +Ethernet14 6 twentyfiveGigE0/14 14 25000 up +Ethernet15 7 twentyfiveGigE0/15 15 25000 up +Ethernet16 8 twentyfiveGigE0/16 16 25000 up +Ethernet17 13 twentyfiveGigE0/17 17 25000 up +Ethernet18 14 twentyfiveGigE0/18 18 25000 up +Ethernet19 15 twentyfiveGigE0/19 19 25000 up +Ethernet20 16 twentyfiveGigE0/20 20 25000 up +Ethernet21 21 twentyfiveGigE0/21 21 25000 up +Ethernet22 22 twentyfiveGigE0/22 22 25000 up +Ethernet23 23 twentyfiveGigE0/23 23 25000 up +Ethernet24 24 twentyfiveGigE0/24 24 25000 up +Ethernet25 29 twentyfiveGigE0/25 25 25000 up +Ethernet26 30 twentyfiveGigE0/26 26 25000 up +Ethernet27 31 twentyfiveGigE0/27 27 25000 up +Ethernet28 32 twentyfiveGigE0/28 28 25000 up +Ethernet29 33 twentyfiveGigE0/29 29 25000 up +Ethernet30 34 twentyfiveGigE0/30 30 25000 up +Ethernet31 35 twentyfiveGigE0/31 31 25000 up +Ethernet32 36 twentyfiveGigE0/32 32 25000 up +Ethernet33 41 twentyfiveGigE0/33 33 25000 up +Ethernet34 42 twentyfiveGigE0/34 34 25000 up +Ethernet35 43 twentyfiveGigE0/35 35 25000 up +Ethernet36 44 twentyfiveGigE0/36 36 25000 up +Ethernet37 49 twentyfiveGigE0/37 37 25000 up +Ethernet38 50 twentyfiveGigE0/38 38 25000 up +Ethernet39 51 twentyfiveGigE0/39 39 25000 up +Ethernet40 52 twentyfiveGigE0/40 40 25000 up +Ethernet41 65 twentyfiveGigE0/41 41 25000 up +Ethernet42 66 twentyfiveGigE0/42 42 25000 up +Ethernet43 67 twentyfiveGigE0/43 43 25000 up +Ethernet44 68 twentyfiveGigE0/44 44 25000 up +Ethernet45 69 twentyfiveGigE0/45 45 25000 up +Ethernet46 70 twentyfiveGigE0/46 46 25000 up +Ethernet47 71 twentyfiveGigE0/47 47 25000 up +Ethernet48 72 twentyfiveGigE0/48 48 25000 up +Ethernet49 85,86,87,88 hundredGigE0/1 49 100000 up +Ethernet53 77,78,79,80 hundredGigE0/2 50 100000 up +Ethernet57 97,98,99,100 hundredGigE0/3 51 100000 up +Ethernet61 93,94,95,96 hundredGigE0/4 52 100000 up +Ethernet65 113,114,115,116 hundredGigE0/5 53 100000 up +Ethernet69 105,106,107,108 hundredGigE0/6 54 100000 up +Ethernet73 121,122,123,124 hundredGigE0/7 55 100000 up +Ethernet77 125,126,127,128 hundredGigE0/8 56 100000 up diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/sai.profile b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/sai.profile new file mode 100755 index 000000000000..9dffa1046f04 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm new file mode 100644 index 000000000000..559a49f4c887 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm @@ -0,0 +1,605 @@ +cancun_dir=/usr/share/sonic/platform/cancun/sdk_6.5.16/ +l2_mem_entries=32768 +l3_mem_entries=16384 +l3_alpm_enable=2 +ipv6_lpm_128b_enable=0x1 +l2xmsg_mode=0 +l3_max_ecmp_mode=1 +svi_my_station_optimization=1 +sai_nbr_bcast_ifp_optimized=2 +sai_stats_support_mask=0x1 +bcm_num_cos=8 +bcm_stat_interval=2000000 +cdma_timeout_usec=3000000 +core_clock_frequency=1525 +dpp_clock_ratio=2:3 +help_cli_enable=1 +ifp_inports_support_enable=1 +#lpm_scaling_enable=1 +max_vp_lags=0 +mem_cache_enable=0 +memlist_enable=1 +miim_intr_enable=0 +module_64ports=1 +oversubscribe_mode=1 +oversubscribe_mixed_sister_25_50_enable=1 +parity_enable=1 +parity_correction=1 +pbmp_gport_stack.0=0x0000000000000000000000000000000000000000000000000000000000000000 +#pbmp_xport_xe.0=0x00000000000000000000000000000000888ffffffffffff9fffffffffffffffe +pbmp_xport_xe=0xffffffffffffffffffffffffffffffffffffffffe +port_flex_enable=1 +phy_chain_tx_lane_map_physical{57.0}=0x0123 +phy_chain_tx_lane_map_physical{61.0}=0x0123 +phy_chain_tx_lane_map_physical{1.0}=0x0123 +phy_chain_tx_lane_map_physical{5.0}=0x0123 +phy_chain_tx_lane_map_physical{13.0}=0x0123 +phy_chain_tx_lane_map_physical{21.0}=0x0123 +phy_chain_tx_lane_map_physical{29.0}=0x0123 +phy_chain_tx_lane_map_physical{33.0}=0x0123 +phy_chain_tx_lane_map_physical{41.0}=0x0123 +phy_chain_tx_lane_map_physical{49.0}=0x0123 +phy_chain_tx_lane_map_physical{65.0}=0x3210 +phy_chain_tx_lane_map_physical{69.0}=0x3210 +phy_chain_tx_lane_map_physical{85.0}=0x3210 +phy_chain_tx_lane_map_physical{77.0}=0x0213 +phy_chain_tx_lane_map_physical{97.0}=0x3210 +phy_chain_tx_lane_map_physical{93.0}=0x0213 +phy_chain_tx_lane_map_physical{113.0}=0x3210 +phy_chain_tx_lane_map_physical{105.0}=0x0213 +phy_chain_tx_lane_map_physical{121.0}=0x3120 +phy_chain_tx_lane_map_physical{125.0}=0x1203 + +phy_chain_rx_lane_map_physical{57.0}=0x1032 +phy_chain_rx_lane_map_physical{61.0}=0x1032 +phy_chain_rx_lane_map_physical{1.0}=0x1032 +phy_chain_rx_lane_map_physical{5.0}=0x1032 +phy_chain_rx_lane_map_physical{13.0}=0x1032 +phy_chain_rx_lane_map_physical{21.0}=0x1032 +phy_chain_rx_lane_map_physical{29.0}=0x1032 +phy_chain_rx_lane_map_physical{33.0}=0x1032 +phy_chain_rx_lane_map_physical{41.0}=0x1032 +phy_chain_rx_lane_map_physical{49.0}=0x1032 +phy_chain_rx_lane_map_physical{65.0}=0x2301 +phy_chain_rx_lane_map_physical{69.0}=0x2301 +phy_chain_rx_lane_map_physical{85.0}=0x1032 +phy_chain_rx_lane_map_physical{77.0}=0x1032 +phy_chain_rx_lane_map_physical{97.0}=0x1032 +phy_chain_rx_lane_map_physical{93.0}=0x1032 +phy_chain_rx_lane_map_physical{113.0}=0x1032 +phy_chain_rx_lane_map_physical{105.0}=0x1032 +phy_chain_rx_lane_map_physical{121.0}=0x2031 +phy_chain_rx_lane_map_physical{125.0}=0x1023 + +portmap_57=57:25 +portmap_58=58:25 +portmap_59=59:25 +portmap_60=60:25 +portmap_61=61:25 +portmap_62=62:25 +portmap_63=63:25 +portmap_64=64:25 +portmap_1=1:25 +portmap_2=2:25 +portmap_3=3:25 +portmap_4=4:25 +portmap_5=5:25 +portmap_6=6:25 +portmap_7=7:25 +portmap_8=8:25 +portmap_13=13:25 +portmap_14=14:25 +portmap_15=15:25 +portmap_16=16:25 +portmap_21=21:25 +portmap_22=22:25 +portmap_23=23:25 +portmap_24=24:25 +portmap_29=29:25 +portmap_30=30:25 +portmap_31=31:25 +portmap_32=32:25 +portmap_33=33:25 +portmap_34=34:25 +portmap_35=35:25 +portmap_36=36:25 +portmap_41=41:25 +portmap_42=42:25 +portmap_43=43:25 +portmap_44=44:25 +portmap_49=49:25 +portmap_50=50:25 +portmap_51=51:25 +portmap_52=52:25 +portmap_67=65:25 +portmap_68=66:25 +portmap_69=67:25 +portmap_70=68:25 +portmap_71=69:25 +portmap_72=70:25 +portmap_73=71:25 +portmap_74=72:25 +portmap_87=85:100 +portmap_79=77:100 +portmap_99=97:100 +portmap_95=93:100 +portmap_115=113:100 +portmap_107=105:100 +portmap_123=121:100 +portmap_127=125:100 + +dport_map_port_57=1 +dport_map_port_58=2 +dport_map_port_59=3 +dport_map_port_60=4 +dport_map_port_61=5 +dport_map_port_62=6 +dport_map_port_63=7 +dport_map_port_64=8 +dport_map_port_1=9 +dport_map_port_2=10 +dport_map_port_3=11 +dport_map_port_4=12 +dport_map_port_5=13 +dport_map_port_6=14 +dport_map_port_7=15 +dport_map_port_8=16 +dport_map_port_13=17 +dport_map_port_14=18 +dport_map_port_15=19 +dport_map_port_16=20 +dport_map_port_21=21 +dport_map_port_22=22 +dport_map_port_23=23 +dport_map_port_24=24 +dport_map_port_29=25 +dport_map_port_30=26 +dport_map_port_31=27 +dport_map_port_32=28 +dport_map_port_33=29 +dport_map_port_34=30 +dport_map_port_35=31 +dport_map_port_36=32 +dport_map_port_41=33 +dport_map_port_42=34 +dport_map_port_43=35 +dport_map_port_44=36 +dport_map_port_49=37 +dport_map_port_50=38 +dport_map_port_51=39 +dport_map_port_52=40 +dport_map_port_67=41 +dport_map_port_68=42 +dport_map_port_69=43 +dport_map_port_70=44 +dport_map_port_71=45 +dport_map_port_72=46 +dport_map_port_73=47 +dport_map_port_74=48 +dport_map_port_87=49 +dport_map_port_79=50 +dport_map_port_99=51 +dport_map_port_95=52 +dport_map_port_115=53 +dport_map_port_107=54 +dport_map_port_123=55 +dport_map_port_127=56 + +phy_chain_tx_polarity_flip_physical{57.0}=0x1 +phy_chain_tx_polarity_flip_physical{58.0}=0x0 +phy_chain_tx_polarity_flip_physical{59.0}=0x1 +phy_chain_tx_polarity_flip_physical{60.0}=0x0 +phy_chain_tx_polarity_flip_physical{61.0}=0x1 +phy_chain_tx_polarity_flip_physical{62.0}=0x0 +phy_chain_tx_polarity_flip_physical{63.0}=0x1 +phy_chain_tx_polarity_flip_physical{64.0}=0x0 +phy_chain_tx_polarity_flip_physical{1.0}=0x0 +phy_chain_tx_polarity_flip_physical{2.0}=0x0 +phy_chain_tx_polarity_flip_physical{3.0}=0x0 +phy_chain_tx_polarity_flip_physical{4.0}=0x0 +phy_chain_tx_polarity_flip_physical{5.0}=0x0 +phy_chain_tx_polarity_flip_physical{6.0}=0x0 +phy_chain_tx_polarity_flip_physical{7.0}=0x0 +phy_chain_tx_polarity_flip_physical{8.0}=0x0 +phy_chain_tx_polarity_flip_physical{13.0}=0x0 +phy_chain_tx_polarity_flip_physical{14.0}=0x0 +phy_chain_tx_polarity_flip_physical{15.0}=0x0 +phy_chain_tx_polarity_flip_physical{16.0}=0x0 +phy_chain_tx_polarity_flip_physical{21.0}=0x0 +phy_chain_tx_polarity_flip_physical{22.0}=0x0 +phy_chain_tx_polarity_flip_physical{23.0}=0x0 +phy_chain_tx_polarity_flip_physical{24.0}=0x0 +phy_chain_tx_polarity_flip_physical{29.0}=0x0 +phy_chain_tx_polarity_flip_physical{30.0}=0x0 +phy_chain_tx_polarity_flip_physical{31.0}=0x0 +phy_chain_tx_polarity_flip_physical{32.0}=0x0 +phy_chain_tx_polarity_flip_physical{33.0}=0x0 +phy_chain_tx_polarity_flip_physical{34.0}=0x0 +phy_chain_tx_polarity_flip_physical{35.0}=0x0 +phy_chain_tx_polarity_flip_physical{36.0}=0x0 +phy_chain_tx_polarity_flip_physical{41.0}=0x0 +phy_chain_tx_polarity_flip_physical{42.0}=0x0 +phy_chain_tx_polarity_flip_physical{43.0}=0x0 +phy_chain_tx_polarity_flip_physical{44.0}=0x0 +phy_chain_tx_polarity_flip_physical{49.0}=0x0 +phy_chain_tx_polarity_flip_physical{50.0}=0x0 +phy_chain_tx_polarity_flip_physical{51.0}=0x0 +phy_chain_tx_polarity_flip_physical{52.0}=0x0 +phy_chain_tx_polarity_flip_physical{65.0}=0x0 +phy_chain_tx_polarity_flip_physical{66.0}=0x0 +phy_chain_tx_polarity_flip_physical{67.0}=0x0 +phy_chain_tx_polarity_flip_physical{68.0}=0x0 +phy_chain_tx_polarity_flip_physical{69.0}=0x0 +phy_chain_tx_polarity_flip_physical{70.0}=0x0 +phy_chain_tx_polarity_flip_physical{71.0}=0x0 +phy_chain_tx_polarity_flip_physical{72.0}=0x0 +phy_chain_tx_polarity_flip_physical{85.0}=0x0 +phy_chain_tx_polarity_flip_physical{86.0}=0x0 +phy_chain_tx_polarity_flip_physical{87.0}=0x1 +phy_chain_tx_polarity_flip_physical{88.0}=0x0 +phy_chain_tx_polarity_flip_physical{77.0}=0x1 +phy_chain_tx_polarity_flip_physical{78.0}=0x0 +phy_chain_tx_polarity_flip_physical{79.0}=0x1 +phy_chain_tx_polarity_flip_physical{80.0}=0x0 +phy_chain_tx_polarity_flip_physical{97.0}=0x0 +phy_chain_tx_polarity_flip_physical{98.0}=0x0 +phy_chain_tx_polarity_flip_physical{99.0}=0x1 +phy_chain_tx_polarity_flip_physical{100.0}=0x0 +phy_chain_tx_polarity_flip_physical{93.0}=0x0 +phy_chain_tx_polarity_flip_physical{94.0}=0x1 +phy_chain_tx_polarity_flip_physical{95.0}=0x1 +phy_chain_tx_polarity_flip_physical{96.0}=0x0 +phy_chain_tx_polarity_flip_physical{113.0}=0x0 +phy_chain_tx_polarity_flip_physical{114.0}=0x0 +phy_chain_tx_polarity_flip_physical{115.0}=0x1 +phy_chain_tx_polarity_flip_physical{116.0}=0x0 +phy_chain_tx_polarity_flip_physical{105.0}=0x0 +phy_chain_tx_polarity_flip_physical{106.0}=0x1 +phy_chain_tx_polarity_flip_physical{107.0}=0x1 +phy_chain_tx_polarity_flip_physical{108.0}=0x0 +phy_chain_tx_polarity_flip_physical{121.0}=0x1 +phy_chain_tx_polarity_flip_physical{122.0}=0x0 +phy_chain_tx_polarity_flip_physical{123.0}=0x1 +phy_chain_tx_polarity_flip_physical{124.0}=0x0 +phy_chain_tx_polarity_flip_physical{125.0}=0x1 +phy_chain_tx_polarity_flip_physical{126.0}=0x0 +phy_chain_tx_polarity_flip_physical{127.0}=0x1 +phy_chain_tx_polarity_flip_physical{128.0}=0x1 + +phy_chain_rx_polarity_flip_physical{57.0}=0x0 +phy_chain_rx_polarity_flip_physical{58.0}=0x0 +phy_chain_rx_polarity_flip_physical{59.0}=0x0 +phy_chain_rx_polarity_flip_physical{60.0}=0x0 +phy_chain_rx_polarity_flip_physical{61.0}=0x1 +phy_chain_rx_polarity_flip_physical{62.0}=0x1 +phy_chain_rx_polarity_flip_physical{63.0}=0x1 +phy_chain_rx_polarity_flip_physical{64.0}=0x1 +phy_chain_rx_polarity_flip_physical{1.0}=0x1 +phy_chain_rx_polarity_flip_physical{2.0}=0x1 +phy_chain_rx_polarity_flip_physical{3.0}=0x1 +phy_chain_rx_polarity_flip_physical{4.0}=0x1 +phy_chain_rx_polarity_flip_physical{5.0}=0x0 +phy_chain_rx_polarity_flip_physical{6.0}=0x0 +phy_chain_rx_polarity_flip_physical{7.0}=0x0 +phy_chain_rx_polarity_flip_physical{8.0}=0x0 +phy_chain_rx_polarity_flip_physical{13.0}=0x0 +phy_chain_rx_polarity_flip_physical{14.0}=0x0 +phy_chain_rx_polarity_flip_physical{15.0}=0x0 +phy_chain_rx_polarity_flip_physical{16.0}=0x0 +phy_chain_rx_polarity_flip_physical{21.0}=0x0 +phy_chain_rx_polarity_flip_physical{22.0}=0x0 +phy_chain_rx_polarity_flip_physical{23.0}=0x0 +phy_chain_rx_polarity_flip_physical{24.0}=0x0 +phy_chain_rx_polarity_flip_physical{29.0}=0x0 +phy_chain_rx_polarity_flip_physical{30.0}=0x1 +phy_chain_rx_polarity_flip_physical{31.0}=0x0 +phy_chain_rx_polarity_flip_physical{32.0}=0x0 +phy_chain_rx_polarity_flip_physical{33.0}=0x1 +phy_chain_rx_polarity_flip_physical{34.0}=0x1 +phy_chain_rx_polarity_flip_physical{35.0}=0x1 +phy_chain_rx_polarity_flip_physical{36.0}=0x1 +phy_chain_rx_polarity_flip_physical{41.0}=0x1 +phy_chain_rx_polarity_flip_physical{42.0}=0x1 +phy_chain_rx_polarity_flip_physical{43.0}=0x1 +phy_chain_rx_polarity_flip_physical{44.0}=0x1 +phy_chain_rx_polarity_flip_physical{49.0}=0x1 +phy_chain_rx_polarity_flip_physical{50.0}=0x1 +phy_chain_rx_polarity_flip_physical{51.0}=0x1 +phy_chain_rx_polarity_flip_physical{52.0}=0x1 +phy_chain_rx_polarity_flip_physical{65.0}=0x1 +phy_chain_rx_polarity_flip_physical{66.0}=0x1 +phy_chain_rx_polarity_flip_physical{67.0}=0x1 +phy_chain_rx_polarity_flip_physical{68.0}=0x1 +phy_chain_rx_polarity_flip_physical{69.0}=0x0 +phy_chain_rx_polarity_flip_physical{70.0}=0x0 +phy_chain_rx_polarity_flip_physical{71.0}=0x0 +phy_chain_rx_polarity_flip_physical{72.0}=0x0 +phy_chain_rx_polarity_flip_physical{85.0}=0x1 +phy_chain_rx_polarity_flip_physical{86.0}=0x1 +phy_chain_rx_polarity_flip_physical{87.0}=0x1 +phy_chain_rx_polarity_flip_physical{88.0}=0x1 +phy_chain_rx_polarity_flip_physical{77.0}=0x0 +phy_chain_rx_polarity_flip_physical{78.0}=0x0 +phy_chain_rx_polarity_flip_physical{79.0}=0x0 +phy_chain_rx_polarity_flip_physical{80.0}=0x0 +phy_chain_rx_polarity_flip_physical{97.0}=0x0 +phy_chain_rx_polarity_flip_physical{98.0}=0x0 +phy_chain_rx_polarity_flip_physical{99.0}=0x0 +phy_chain_rx_polarity_flip_physical{100.0}=0x0 +phy_chain_rx_polarity_flip_physical{93.0}=0x0 +phy_chain_rx_polarity_flip_physical{94.0}=0x0 +phy_chain_rx_polarity_flip_physical{95.0}=0x0 +phy_chain_rx_polarity_flip_physical{96.0}=0x0 +phy_chain_rx_polarity_flip_physical{113.0}=0x1 +phy_chain_rx_polarity_flip_physical{114.0}=0x1 +phy_chain_rx_polarity_flip_physical{115.0}=0x1 +phy_chain_rx_polarity_flip_physical{116.0}=0x1 +phy_chain_rx_polarity_flip_physical{105.0}=0x0 +phy_chain_rx_polarity_flip_physical{106.0}=0x0 +phy_chain_rx_polarity_flip_physical{107.0}=0x0 +phy_chain_rx_polarity_flip_physical{108.0}=0x0 +phy_chain_rx_polarity_flip_physical{121.0}=0x1 +phy_chain_rx_polarity_flip_physical{122.0}=0x1 +phy_chain_rx_polarity_flip_physical{123.0}=0x0 +phy_chain_rx_polarity_flip_physical{124.0}=0x1 +phy_chain_rx_polarity_flip_physical{125.0}=0x1 +phy_chain_rx_polarity_flip_physical{126.0}=0x0 +phy_chain_rx_polarity_flip_physical{127.0}=0x0 +phy_chain_rx_polarity_flip_physical{128.0}=0x0 + +serdes_preemphasis_lane0_57=0x0f480d +serdes_preemphasis_lane1_57=0x0f480d +serdes_preemphasis_lane2_57=0x0f480d +serdes_preemphasis_lane3_57=0x0f480d +serdes_preemphasis_lane0_58=0x0f480d +serdes_preemphasis_lane1_58=0x0f480d +serdes_preemphasis_lane2_58=0x0f480d +serdes_preemphasis_lane3_58=0x0f480d +serdes_preemphasis_lane0_59=0x0f480d +serdes_preemphasis_lane1_59=0x0f480d +serdes_preemphasis_lane2_59=0x0f480d +serdes_preemphasis_lane3_59=0x0f480d +serdes_preemphasis_lane0_60=0x0f480d +serdes_preemphasis_lane1_60=0x0f480d +serdes_preemphasis_lane2_60=0x0f480d +serdes_preemphasis_lane3_60=0x0f480d +serdes_preemphasis_lane0_61=0x0f480d +serdes_preemphasis_lane1_61=0x0f480d +serdes_preemphasis_lane2_61=0x0f480d +serdes_preemphasis_lane3_61=0x0f480d +serdes_preemphasis_lane0_62=0x0f480d +serdes_preemphasis_lane1_62=0x0f480d +serdes_preemphasis_lane2_62=0x0f480d +serdes_preemphasis_lane3_62=0x0f480d +serdes_preemphasis_lane0_63=0x0f480d +serdes_preemphasis_lane1_63=0x0f480d +serdes_preemphasis_lane2_63=0x0f480d +serdes_preemphasis_lane3_63=0x0f480d +serdes_preemphasis_lane0_64=0x0f480d +serdes_preemphasis_lane1_64=0x0f480d +serdes_preemphasis_lane2_64=0x0f480d +serdes_preemphasis_lane3_64=0x0f480d +serdes_preemphasis_lane0_1=0x0f480d +serdes_preemphasis_lane1_1=0x0f480d +serdes_preemphasis_lane2_1=0x0f480d +serdes_preemphasis_lane3_1=0x0f480d +serdes_preemphasis_lane0_2=0x0d4b0c +serdes_preemphasis_lane1_2=0x0d4b0c +serdes_preemphasis_lane2_2=0x0d4b0c +serdes_preemphasis_lane3_2=0x0d4b0c +serdes_preemphasis_lane0_3=0x0f480d +serdes_preemphasis_lane1_3=0x0f480d +serdes_preemphasis_lane2_3=0x0f480d +serdes_preemphasis_lane3_3=0x0f480d +serdes_preemphasis_lane0_4=0x0d4b0c +serdes_preemphasis_lane1_4=0x0d4b0c +serdes_preemphasis_lane2_4=0x0d4b0c +serdes_preemphasis_lane3_4=0x0d4b0c +serdes_preemphasis_lane0_5=0x0f480d +serdes_preemphasis_lane1_5=0x0f480d +serdes_preemphasis_lane2_5=0x0f480d +serdes_preemphasis_lane3_5=0x0f480d +serdes_preemphasis_lane0_6=0x0d4b0c +serdes_preemphasis_lane1_6=0x0d4b0c +serdes_preemphasis_lane2_6=0x0d4b0c +serdes_preemphasis_lane3_6=0x0d4b0c +serdes_preemphasis_lane0_7=0x0f480d +serdes_preemphasis_lane1_7=0x0f480d +serdes_preemphasis_lane2_7=0x0f480d +serdes_preemphasis_lane3_7=0x0f480d +serdes_preemphasis_lane0_8=0x0d4b0c +serdes_preemphasis_lane1_8=0x0d4b0c +serdes_preemphasis_lane2_8=0x0d4b0c +serdes_preemphasis_lane3_8=0x0d4b0c +serdes_preemphasis_lane0_13=0x0f480d +serdes_preemphasis_lane1_13=0x0f480d +serdes_preemphasis_lane2_13=0x0f480d +serdes_preemphasis_lane3_13=0x0f480d +serdes_preemphasis_lane0_14=0x0d4b0c +serdes_preemphasis_lane1_14=0x0d4b0c +serdes_preemphasis_lane2_14=0x0d4b0c +serdes_preemphasis_lane3_14=0x0d4b0c +serdes_preemphasis_lane0_15=0x0f480d +serdes_preemphasis_lane1_15=0x0f480d +serdes_preemphasis_lane2_15=0x0f480d +serdes_preemphasis_lane3_15=0x0f480d +serdes_preemphasis_lane0_16=0x0d4b0c +serdes_preemphasis_lane1_16=0x0d4b0c +serdes_preemphasis_lane2_16=0x0d4b0c +serdes_preemphasis_lane3_16=0x0d4b0c +serdes_preemphasis_lane0_21=0x0d4b0c +serdes_preemphasis_lane1_21=0x0d4b0c +serdes_preemphasis_lane2_21=0x0d4b0c +serdes_preemphasis_lane3_21=0x0d4b0c +serdes_preemphasis_lane0_22=0x0d4b0c +serdes_preemphasis_lane1_22=0x0d4b0c +serdes_preemphasis_lane2_22=0x0d4b0c +serdes_preemphasis_lane3_22=0x0d4b0c +serdes_preemphasis_lane0_23=0x0d4b0c +serdes_preemphasis_lane1_23=0x0d4b0c +serdes_preemphasis_lane2_23=0x0d4b0c +serdes_preemphasis_lane3_23=0x0d4b0c +serdes_preemphasis_lane0_24=0x0d4b0c +serdes_preemphasis_lane1_24=0x0d4b0c +serdes_preemphasis_lane2_24=0x0d4b0c +serdes_preemphasis_lane3_24=0x0d4b0c +serdes_preemphasis_lane0_29=0x0d4b0c +serdes_preemphasis_lane1_29=0x0d4b0c +serdes_preemphasis_lane2_29=0x0d4b0c +serdes_preemphasis_lane3_29=0x0d4b0c +serdes_preemphasis_lane0_30=0x0d4b0c +serdes_preemphasis_lane1_30=0x0d4b0c +serdes_preemphasis_lane2_30=0x0d4b0c +serdes_preemphasis_lane3_30=0x0d4b0c +serdes_preemphasis_lane0_31=0x0d4b0c +serdes_preemphasis_lane1_31=0x0d4b0c +serdes_preemphasis_lane2_31=0x0d4b0c +serdes_preemphasis_lane3_31=0x0d4b0c +serdes_preemphasis_lane0_32=0x0d4b0c +serdes_preemphasis_lane1_32=0x0d4b0c +serdes_preemphasis_lane2_32=0x0d4b0c +serdes_preemphasis_lane3_32=0x0d4b0c +serdes_preemphasis_lane0_33=0x0d4b0c +serdes_preemphasis_lane1_33=0x0d4b0c +serdes_preemphasis_lane2_33=0x0d4b0c +serdes_preemphasis_lane3_33=0x0d4b0c +serdes_preemphasis_lane0_34=0x0d4b0c +serdes_preemphasis_lane1_34=0x0d4b0c +serdes_preemphasis_lane2_34=0x0d4b0c +serdes_preemphasis_lane3_34=0x0d4b0c +serdes_preemphasis_lane0_35=0x0d4b0c +serdes_preemphasis_lane1_35=0x0d4b0c +serdes_preemphasis_lane2_35=0x0d4b0c +serdes_preemphasis_lane3_35=0x0d4b0c +serdes_preemphasis_lane0_36=0x0d4b0c +serdes_preemphasis_lane1_36=0x0d4b0c +serdes_preemphasis_lane2_36=0x0d4b0c +serdes_preemphasis_lane3_36=0x0d4b0c +serdes_preemphasis_lane0_41=0x0d4b0c +serdes_preemphasis_lane1_41=0x0d4b0c +serdes_preemphasis_lane2_41=0x0d4b0c +serdes_preemphasis_lane3_41=0x0d4b0c +serdes_preemphasis_lane0_42=0x0d4b0c +serdes_preemphasis_lane1_42=0x0d4b0c +serdes_preemphasis_lane2_42=0x0d4b0c +serdes_preemphasis_lane3_42=0x0d4b0c +serdes_preemphasis_lane0_43=0x0d4b0c +serdes_preemphasis_lane1_43=0x0d4b0c +serdes_preemphasis_lane2_43=0x0d4b0c +serdes_preemphasis_lane3_43=0x0d4b0c +serdes_preemphasis_lane0_44=0x0d4b0c +serdes_preemphasis_lane1_44=0x0d4b0c +serdes_preemphasis_lane2_44=0x0d4b0c +serdes_preemphasis_lane3_44=0x0d4b0c +serdes_preemphasis_lane0_49=0x0f480d +serdes_preemphasis_lane1_49=0x0f480d +serdes_preemphasis_lane2_49=0x0f480d +serdes_preemphasis_lane3_49=0x0f480d +serdes_preemphasis_lane0_50=0x0d4b0c +serdes_preemphasis_lane1_50=0x0d4b0c +serdes_preemphasis_lane2_50=0x0d4b0c +serdes_preemphasis_lane3_50=0x0d4b0c +serdes_preemphasis_lane0_51=0x0f480d +serdes_preemphasis_lane1_51=0x0f480d +serdes_preemphasis_lane2_51=0x0f480d +serdes_preemphasis_lane3_51=0x0f480d +serdes_preemphasis_lane0_52=0x0d4b0c +serdes_preemphasis_lane1_52=0x0d4b0c +serdes_preemphasis_lane2_52=0x0d4b0c +serdes_preemphasis_lane3_52=0x0d4b0c +serdes_preemphasis_lane0_67=0x0d4b0c +serdes_preemphasis_lane1_67=0x0d4b0c +serdes_preemphasis_lane2_67=0x0d4b0c +serdes_preemphasis_lane3_67=0x0d4b0c +serdes_preemphasis_lane0_68=0x0d4b0c +serdes_preemphasis_lane1_68=0x0d4b0c +serdes_preemphasis_lane2_68=0x0d4b0c +serdes_preemphasis_lane3_68=0x0d4b0c +serdes_preemphasis_lane0_69=0x0d4b0c +serdes_preemphasis_lane1_69=0x0d4b0c +serdes_preemphasis_lane2_69=0x0d4b0c +serdes_preemphasis_lane3_69=0x0d4b0c +serdes_preemphasis_lane0_70=0x0d4b0c +serdes_preemphasis_lane1_70=0x0d4b0c +serdes_preemphasis_lane2_70=0x0d4b0c +serdes_preemphasis_lane3_70=0x0d4b0c +serdes_preemphasis_lane0_71=0x0d4b0c +serdes_preemphasis_lane1_71=0x0d4b0c +serdes_preemphasis_lane2_71=0x0d4b0c +serdes_preemphasis_lane3_71=0x0d4b0c +serdes_preemphasis_lane0_72=0x0d4b0c +serdes_preemphasis_lane1_72=0x0d4b0c +serdes_preemphasis_lane2_72=0x0d4b0c +serdes_preemphasis_lane3_72=0x0d4b0c +serdes_preemphasis_lane0_73=0x0d4b0c +serdes_preemphasis_lane1_73=0x0d4b0c +serdes_preemphasis_lane2_73=0x0d4b0c +serdes_preemphasis_lane3_73=0x0d4b0c +serdes_preemphasis_lane0_74=0x0d4b0c +serdes_preemphasis_lane1_74=0x0d4b0c +serdes_preemphasis_lane2_74=0x0d4b0c +serdes_preemphasis_lane3_74=0x0d4b0c +serdes_preemphasis_lane0_87=0x0d4b0c +serdes_preemphasis_lane1_87=0x0d4b0c +serdes_preemphasis_lane2_87=0x0d4b0c +serdes_preemphasis_lane3_87=0x0d4b0c +serdes_preemphasis_lane0_79=0x0d4b0c +serdes_preemphasis_lane1_79=0x0d4b0c +serdes_preemphasis_lane2_79=0x0d4b0c +serdes_preemphasis_lane3_79=0x0d4b0c +serdes_preemphasis_lane0_99=0x0d4b0c +serdes_preemphasis_lane1_99=0x0d4b0c +serdes_preemphasis_lane2_99=0x0d4b0c +serdes_preemphasis_lane3_99=0x0d4b0c +serdes_preemphasis_lane0_95=0x0d4b0c +serdes_preemphasis_lane1_95=0x0d4b0c +serdes_preemphasis_lane2_95=0x0d4b0c +serdes_preemphasis_lane3_95=0x0d4b0c +serdes_preemphasis_lane0_115=0x0d4b0c +serdes_preemphasis_lane1_115=0x0d4b0c +serdes_preemphasis_lane2_115=0x0d4b0c +serdes_preemphasis_lane3_115=0x0d4b0c +serdes_preemphasis_lane0_107=0x0d4b0c +serdes_preemphasis_lane1_107=0x0d4b0c +serdes_preemphasis_lane2_107=0x0d4b0c +serdes_preemphasis_lane3_107=0x0d4b0c +serdes_preemphasis_lane0_123=0x14460a +serdes_preemphasis_lane1_123=0x14460a +serdes_preemphasis_lane2_123=0x14460a +serdes_preemphasis_lane3_123=0x14460a +serdes_preemphasis_lane0_127=0x14460a +serdes_preemphasis_lane1_127=0x14460a +serdes_preemphasis_lane2_127=0x14460a +serdes_preemphasis_lane3_127=0x14460a + + +reglist_enable=1 +scache_filename=/var/warmboot/wbscache +schan_intr_enable=0 +stable_size=0x55000000 +stable_location=3 +warmboot_knet_shutdown_mode=1 +tdma_timeout_usec=3000000 + +#vxlan flex flow mode +flow_init_mode=1 + +riot_enable=1 +riot_overlay_l3_intf_mem_size=4096 +riot_overlay_l3_egress_mem_size=32768 +riot_overlay_ecmp_resilient_hash_size=16384 + +l3_ecmp_levels=2 + +use_all_splithorizon_groups=1 +sai_tunnel_support=1 + +#This property allows to enable L2 FDB entry to discard based on Source Mac +sai_fdb_entry_l2_discard_src_enable=1 + +#RDMA +sai_pfc_defaults_disable=1 +sai_optimized_mmu=1 + +#ACL wb count +ctr_evict_enable=0 diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/custom_led.bin b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/custom_led.bin new file mode 100644 index 0000000000000000000000000000000000000000..e02f94e7ed87ffe60524721f4aec68d661880e7c GIT binary patch literal 236 zcmWN~%}N4M7=YpT%$NoC2ayV4HjWWfZN?-t`f=LVkf$CZeDzh_uF%kr>I`FYKD`eLmXf;U;{tHuD;Ze7>$f@av% zgCSlz(c*=6Vg!#wxw@UXuqvtQF#P>drO^$pZE}t_Ju@=OS5eW|Q7?+4_%^r@%5rR&XfcQvT1^* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev_exhaust.xml b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev_exhaust.xml new file mode 100644 index 000000000000..86851af90ec9 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev_exhaust.xml @@ -0,0 +1,420 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/fru.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/fru.py new file mode 100644 index 000000000000..f95164e03601 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/fru.py @@ -0,0 +1,961 @@ +#!/usr/bin/python3 +import collections +from datetime import datetime, timedelta +from bitarray import bitarray + + +__DEBUG__ = "N" + + +class FruException(Exception): + def __init__(self, message='fruerror', code=-100): + err = 'errcode: {0} message:{1}'.format(code, message) + Exception.__init__(self, err) + self.code = code + self.message = message + + +def e_print(err): + print("ERROR: " + err) + + +def d_print(debug_info): + if __DEBUG__ == "Y": + print(debug_info) + + +class FruUtil(): + @staticmethod + def decodeLength(value): + a = bitarray(8) + a.setall(True) + a[0:1] = 0 + a[1:2] = 0 + x = ord(a.tobytes()) + return x & ord(value) + + @staticmethod + def minToData(): + starttime = datetime(1996, 1, 1, 0, 0, 0) + endtime = datetime.now() + seconds = (endtime - starttime).total_seconds() + mins = seconds // 60 + m = int(round(mins)) + return m + + @staticmethod + def getTimeFormat(): + return datetime.now().strftime('%Y-%m-%d') + + @staticmethod + def getTypeLength(value): + if value is None or len(value) == 0: + return 0 + a = bitarray(8) + a.setall(False) + a[0:1] = 1 + a[1:2] = 1 + x = ord(a.tobytes()) + return x | len(value) + + @staticmethod + def checksum(b): + result = 0 + for item in b: + result += ord(item) + return (0x100 - (result & 0xff)) & 0xff + + +class BaseArea(object): + SUGGESTED_SIZE_COMMON_HEADER = 8 + SUGGESTED_SIZE_INTERNAL_USE_AREA = 72 + SUGGESTED_SIZE_CHASSIS_INFO_AREA = 32 + SUGGESTED_SIZE_BOARD_INFO_AREA = 80 + SUGGESTED_SIZE_PRODUCT_INFO_AREA = 80 + + INITVALUE = b'\x00' + resultvalue = INITVALUE * 256 + COMMON_HEAD_VERSION = b'\x01' + __childList = None + + def __init__(self, name="", size=0, offset=0): + self.__childList = [] + self._offset = offset + self.name = name + self._size = size + self._isPresent = False + self._data = b'\x00' * size + + @property + def childList(self): + return self.__childList + + @childList.setter + def childList(self, value): + self.__childList = value + + @property + def offset(self): + return self._offset + + @offset.setter + def offset(self, value): + self._offset = value + + @property + def size(self): + return self._size + + @size.setter + def size(self, value): + self._size = value + + @property + def data(self): + return self._data + + @data.setter + def data(self, value): + self._data = value + + @property + def isPresent(self): + return self._isPresent + + @isPresent.setter + def isPresent(self, value): + self._isPresent = value + + +class InternalUseArea(BaseArea): + pass + + +class ChassisInfoArea(BaseArea): + pass + + +class BoardInfoArea(BaseArea): + _boardTime = None + _fields = None + _mfg_date = None + areaversion = None + _boardversion = None + _language = None + + def __str__(self): + formatstr = "version : %x\n" \ + "length : %d \n" \ + "language : %x \n" \ + "mfg_date : %s \n" \ + "boardManufacturer : %s \n" \ + "boardProductName : %s \n" \ + "boardSerialNumber : %s \n" \ + "boardPartNumber : %s \n" \ + "fruFileId : %s \n" + + tmpstr = formatstr % (ord(self.boardversion), self.size, + self.language, self.getMfgRealData(), + self.boardManufacturer, self.boardProductName, + self.boardSerialNumber, self.boardPartNumber, + self.fruFileId) + for i in range(1, 11): + valtmp = "boardextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + tmpstr += "boardextra%d : %s \n" % (i, valtmpval) + else: + break + + return tmpstr + + def todict(self): + dic = collections.OrderedDict() + dic["boardversion"] = ord(self.boardversion) + dic["boardlength"] = self.size + dic["boardlanguage"] = self.language + dic["boardmfg_date"] = self.getMfgRealData() + dic["boardManufacturer"] = self.boardManufacturer + dic["boardProductName"] = self.boardProductName + dic["boardSerialNumber"] = self.boardSerialNumber + dic["boardPartNumber"] = self.boardPartNumber + dic["boardfruFileId"] = self.fruFileId + for i in range(1, 11): + valtmp = "boardextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + dic[valtmp] = valtmpval + else: + break + return dic + + def decodedata(self): + index = 0 + self.areaversion = self.data[index] + index += 1 + d_print("decode length :%d class size:%d" % + ((ord(self.data[index]) * 8), self.size)) + index += 2 + + timetmp = self.data[index: index + 3] + self.mfg_date = ord(timetmp[0]) | ( + ord(timetmp[1]) << 8) | (ord(timetmp[2]) << 16) + d_print("decode getMfgRealData :%s" % self.getMfgRealData()) + index += 3 + + templen = FruUtil.decodeLength(self.data[index]) + self.boardManufacturer = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardManufacturer:%s" % self.boardManufacturer) + + templen = FruUtil.decodeLength(self.data[index]) + self.boardProductName = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardProductName:%s" % self.boardProductName) + + templen = FruUtil.decodeLength(self.data[index]) + self.boardSerialNumber = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardSerialNumber:%s" % self.boardSerialNumber) + + templen = FruUtil.decodeLength(self.data[index]) + self.boardPartNumber = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardPartNumber:%s" % self.boardPartNumber) + + templen = FruUtil.decodeLength(self.data[index]) + self.fruFileId = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode fruFileId:%s" % self.fruFileId) + + for i in range(1, 11): + valtmp = "boardextra%d" % i + if self.data[index] != chr(0xc1): + templen = FruUtil.decodeLength(self.data[index]) + tmpval = self.data[index + 1: index + templen + 1] + setattr(self, valtmp, tmpval) + index += templen + 1 + d_print("decode boardextra%d:%s" % (i, tmpval)) + else: + break + + def fruSetValue(self, field, value): + tmp_field = getattr(self, field, None) + if tmp_field is not None: + setattr(self, field, value) + + def recalcute(self): + d_print("boardInfoArea version:%x" % ord(self.boardversion)) + d_print("boardInfoArea length:%d" % self.size) + d_print("boardInfoArea language:%x" % self.language) + self.mfg_date = FruUtil.minToData() + d_print("boardInfoArea mfg_date:%x" % self.mfg_date) + + self.data = chr(ord(self.boardversion)) + \ + chr(self.size // 8) + chr(self.language) + + self.data += chr(self.mfg_date & 0xFF) + self.data += chr((self.mfg_date >> 8) & 0xFF) + self.data += chr((self.mfg_date >> 16) & 0xFF) + + d_print("boardInfoArea boardManufacturer:%s" % self.boardManufacturer) + typelength = FruUtil.getTypeLength(self.boardManufacturer) + self.data += chr(typelength) + self.data += self.boardManufacturer + + d_print("boardInfoArea boardProductName:%s" % self.boardProductName) + self.data += chr(FruUtil.getTypeLength(self.boardProductName)) + self.data += self.boardProductName + + d_print("boardInfoArea boardSerialNumber:%s" % self.boardSerialNumber) + self.data += chr(FruUtil.getTypeLength(self.boardSerialNumber)) + self.data += self.boardSerialNumber + + d_print("boardInfoArea boardPartNumber:%s" % self.boardPartNumber) + self.data += chr(FruUtil.getTypeLength(self.boardPartNumber)) + self.data += self.boardPartNumber + + d_print("boardInfoArea fruFileId:%s" % self.fruFileId) + self.data += chr(FruUtil.getTypeLength(self.fruFileId)) + self.data += self.fruFileId + + for i in range(1, 11): + valtmp = "boardextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + d_print("boardInfoArea boardextra%d:%s" % (i, valtmpval)) + self.data += chr(FruUtil.getTypeLength(valtmpval)) + if valtmpval is not None: + self.data += valtmpval + else: + break + + self.data += chr(0xc1) + + if len(self.data) > (self.size - 1): + incr = (len(self.data) - self.size) // 8 + 1 + self.size += incr * 8 + + self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] + d_print("self data:%d" % len(self.data)) + d_print("self size:%d" % self.size) + d_print("adjust size:%d" % (self.size - len(self.data) - 1)) + self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) + + # checksum + checksum = FruUtil.checksum(self.data) + d_print("board info checksum:%x" % checksum) + self.data += chr(checksum) + + def getMfgRealData(self): + starttime = datetime(1996, 1, 1, 0, 0, 0) + mactime = starttime + timedelta(minutes=self.mfg_date) + return mactime + + @property + def language(self): + self._language = 25 + return self._language + + @property + def mfg_date(self): + return self._mfg_date + + @mfg_date.setter + def mfg_date(self, val): + self._mfg_date = val + + @property + def boardversion(self): + self._boardversion = self.COMMON_HEAD_VERSION + return self._boardversion + + @property + def fruFileId(self): + return self._FRUFileID + + @fruFileId.setter + def fruFileId(self, val): + self._FRUFileID = val + + @property + def boardPartNumber(self): + return self._boardPartNumber + + @boardPartNumber.setter + def boardPartNumber(self, val): + self._boardPartNumber = val + + @property + def boardSerialNumber(self): + return self._boardSerialNumber + + @boardSerialNumber.setter + def boardSerialNumber(self, val): + self._boardSerialNumber = val + + @property + def boardProductName(self): + return self._boradProductName + + @boardProductName.setter + def boardProductName(self, val): + self._boradProductName = val + + @property + def boardManufacturer(self): + return self._boardManufacturer + + @boardManufacturer.setter + def boardManufacturer(self, val): + self._boardManufacturer = val + + @property + def boardTime(self): + return self._boardTime + + @boardTime.setter + def boardTime(self, val): + self._boardTime = val + + @property + def fields(self): + return self._fields + + @fields.setter + def fields(self, val): + self._fields = val + + +class ProductInfoArea(BaseArea): + _productManufacturer = None + _productAssetTag = None + _FRUFileID = None + _language = None + + def __str__(self): + formatstr = "version : %x\n" \ + "length : %d \n" \ + "language : %x \n" \ + "productManufacturer : %s \n" \ + "productName : %s \n" \ + "productPartModelName: %s \n" \ + "productVersion : %s \n" \ + "productSerialNumber : %s \n" \ + "productAssetTag : %s \n" \ + "fruFileId : %s \n" + + tmpstr = formatstr % (ord(self.areaversion), self.size, + self.language, self.productManufacturer, + self.productName, self.productPartModelName, + self.productVersion, self.productSerialNumber, + self.productAssetTag, self.fruFileId) + + for i in range(1, 11): + valtmp = "productextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + tmpstr += "productextra%d : %s \n" % (i, valtmpval) + else: + break + + return tmpstr + + def todict(self): + dic = collections.OrderedDict() + dic["productversion"] = ord(self.areaversion) + dic["productlength"] = self.size + dic["productlanguage"] = self.language + dic["productManufacturer"] = self.productManufacturer + dic["productName"] = self.productName + dic["productPartModelName"] = self.productPartModelName + dic["productVersion"] = int(self.productVersion, 16) + dic["productSerialNumber"] = self.productSerialNumber + dic["productAssetTag"] = self.productAssetTag + dic["productfruFileId"] = self.fruFileId + for i in range(1, 11): + valtmp = "productextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + dic[valtmp] = valtmpval + else: + break + return dic + + def decodedata(self): + index = 0 + self.areaversion = self.data[index] # 0 + index += 1 + d_print("decode length %d" % (ord(self.data[index]) * 8)) + d_print("class size %d" % self.size) + index += 2 + + templen = FruUtil.decodeLength(self.data[index]) + self.productManufacturer = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productManufacturer:%s" % self.productManufacturer) + + templen = FruUtil.decodeLength(self.data[index]) + self.productName = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productName:%s" % self.productName) + + templen = FruUtil.decodeLength(self.data[index]) + self.productPartModelName = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productPartModelName:%s" % self.productPartModelName) + + templen = FruUtil.decodeLength(self.data[index]) + self.productVersion = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productVersion:%s" % self.productVersion) + + templen = FruUtil.decodeLength(self.data[index]) + self.productSerialNumber = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productSerialNumber:%s" % self.productSerialNumber) + + templen = FruUtil.decodeLength(self.data[index]) + self.productAssetTag = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productAssetTag:%s" % self.productAssetTag) + + templen = FruUtil.decodeLength(self.data[index]) + self.fruFileId = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode fruFileId:%s" % self.fruFileId) + + for i in range(1, 11): + valtmp = "productextra%d" % i + if self.data[index] != chr(0xc1) and index < self.size - 1: + templen = FruUtil.decodeLength(self.data[index]) + if templen == 0: + break + tmpval = self.data[index + 1: index + templen + 1] + d_print("decode boardextra%d:%s" % (i, tmpval)) + setattr(self, valtmp, tmpval) + index += templen + 1 + else: + break + + @property + def productVersion(self): + return self._productVersion + + @productVersion.setter + def productVersion(self, name): + self._productVersion = name + + @property + def areaversion(self): + self._areaversion = self.COMMON_HEAD_VERSION + return self._areaversion + + @areaversion.setter + def areaversion(self, name): + self._areaversion = name + + @property + def language(self): + self._language = 25 + return self._language + + @property + def productManufacturer(self): + return self._productManufacturer + + @productManufacturer.setter + def productManufacturer(self, name): + self._productManufacturer = name + + @property + def productName(self): + return self._productName + + @productName.setter + def productName(self, name): + self._productName = name + + @property + def productPartModelName(self): + return self._productPartModelName + + @productPartModelName.setter + def productPartModelName(self, name): + self._productPartModelName = name + + @property + def productSerialNumber(self): + return self._productSerialNumber + + @productSerialNumber.setter + def productSerialNumber(self, name): + self._productSerialNumber = name + + @property + def productAssetTag(self): + return self._productAssetTag + + @productAssetTag.setter + def productAssetTag(self, name): + self._productAssetTag = name + + @property + def fruFileId(self): + return self._FRUFileID + + @fruFileId.setter + def fruFileId(self, name): + self._FRUFileID = name + + def fruSetValue(self, field, value): + tmp_field = getattr(self, field, None) + if tmp_field is not None: + setattr(self, field, value) + + def recalcute(self): + d_print("product version:%x" % ord(self.areaversion)) + d_print("product length:%d" % self.size) + d_print("product language:%x" % self.language) + self.data = chr(ord(self.areaversion)) + \ + chr(self.size // 8) + chr(self.language) + + typelength = FruUtil.getTypeLength(self.productManufacturer) + self.data += chr(typelength) + self.data += self.productManufacturer + + self.data += chr(FruUtil.getTypeLength(self.productName)) + self.data += self.productName + + self.data += chr(FruUtil.getTypeLength(self.productPartModelName)) + self.data += self.productPartModelName + + self.data += chr(FruUtil.getTypeLength(self.productVersion)) + self.data += self.productVersion + + self.data += chr(FruUtil.getTypeLength(self.productSerialNumber)) + self.data += self.productSerialNumber + + self.data += chr(FruUtil.getTypeLength(self.productAssetTag)) + if self.productAssetTag is not None: + self.data += self.productAssetTag + + self.data += chr(FruUtil.getTypeLength(self.fruFileId)) + self.data += self.fruFileId + + for i in range(1, 11): + valtmp = "productextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + d_print("boardInfoArea productextra%d:%s" % (i, valtmpval)) + self.data += chr(FruUtil.getTypeLength(valtmpval)) + if valtmpval is not None: + self.data += valtmpval + else: + break + + self.data += chr(0xc1) + if len(self.data) > (self.size - 1): + incr = (len(self.data) - self.size) // 8 + 1 + self.size += incr * 8 + d_print("self.data:%d" % len(self.data)) + d_print("self.size:%d" % self.size) + + self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] + self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) + checksum = FruUtil.checksum(self.data) + d_print("board info checksum:%x" % checksum) + self.data += chr(checksum) + + +class MultiRecordArea(BaseArea): + pass + + +class Field(object): + + def __init__(self, fieldType="ASCII", fieldData=""): + self.fieldData = fieldData + self.fieldType = fieldType + + @property + def fieldType(self): + return self.fieldType + + @property + def fieldData(self): + return self.fieldData + + +class ipmifru(BaseArea): + _BoardInfoArea = None + _ProductInfoArea = None + _InternalUseArea = None + _ChassisInfoArea = None + _multiRecordArea = None + _productinfoAreaOffset = BaseArea.INITVALUE + _boardInfoAreaOffset = BaseArea.INITVALUE + _internalUserAreaOffset = BaseArea.INITVALUE + _chassicInfoAreaOffset = BaseArea.INITVALUE + _multiRecordAreaOffset = BaseArea.INITVALUE + _bindata = None + _bodybin = None + _version = BaseArea.COMMON_HEAD_VERSION + _zeroCheckSum = None + _frusize = 256 + + def __str__(self): + tmpstr = "" + if self.boardInfoArea.isPresent: + tmpstr += "\nboardinfoarea: \n" + tmpstr += self.boardInfoArea.__str__() + if self.productInfoArea.isPresent: + tmpstr += "\nproductinfoarea: \n" + tmpstr += self.productInfoArea.__str__() + return tmpstr + + def decodeBin(self, eeprom): + commonHead = eeprom[0:8] + d_print("decode version %x" % ord(commonHead[0])) + if ord(self.COMMON_HEAD_VERSION) != ord(commonHead[0]): + raise FruException("HEAD VERSION error,not Fru format!", -10) + if FruUtil.checksum(commonHead[0:7]) != ord(commonHead[7]): + strtemp = "check header checksum error [cal:%02x data:%02x]" % ( + FruUtil.checksum(commonHead[0:7]), ord(commonHead[7])) + raise FruException(strtemp, -3) + if ord(commonHead[1]) != ord(self.INITVALUE): + d_print("Internal Use Area is present") + self.internalUseArea = InternalUseArea( + name="Internal Use Area", size=self.SUGGESTED_SIZE_INTERNAL_USE_AREA) + self.internalUseArea.isPresent = True + self.internalUserAreaOffset = ord(commonHead[1]) + self.internalUseArea.data = eeprom[self.internalUserAreaOffset * 8: ( + self.internalUserAreaOffset * 8 + self.internalUseArea.size)] + if ord(commonHead[2]) != ord(self.INITVALUE): + d_print("Chassis Info Area is present") + self.chassisInfoArea = ChassisInfoArea( + name="Chassis Info Area", size=self.SUGGESTED_SIZE_CHASSIS_INFO_AREA) + self.chassisInfoArea.isPresent = True + self.chassicInfoAreaOffset = ord(commonHead[2]) + self.chassisInfoArea.data = eeprom[self.chassicInfoAreaOffset * 8: ( + self.chassicInfoAreaOffset * 8 + self.chassisInfoArea.size)] + if ord(commonHead[3]) != ord(self.INITVALUE): + self.boardInfoArea = BoardInfoArea( + name="Board Info Area", size=self.SUGGESTED_SIZE_BOARD_INFO_AREA) + self.boardInfoArea.isPresent = True + self.boardInfoAreaOffset = ord(commonHead[3]) + self.boardInfoArea.size = ord( + eeprom[self.boardInfoAreaOffset * 8 + 1]) * 8 + d_print("Board Info Area is present size:%d" % + (self.boardInfoArea.size)) + self.boardInfoArea.data = eeprom[self.boardInfoAreaOffset * 8: ( + self.boardInfoAreaOffset * 8 + self.boardInfoArea.size)] + if FruUtil.checksum(self.boardInfoArea.data[:-1]) != ord(self.boardInfoArea.data[-1:]): + strtmp = "check boardInfoArea checksum error[cal:%02x data:%02x]" % \ + (FruUtil.checksum( + self.boardInfoArea.data[:-1]), ord(self.boardInfoArea.data[-1:])) + raise FruException(strtmp, -3) + self.boardInfoArea.decodedata() + if ord(commonHead[4]) != ord(self.INITVALUE): + d_print("Product Info Area is present") + self.productInfoArea = ProductInfoArea( + name="Product Info Area ", size=self.SUGGESTED_SIZE_PRODUCT_INFO_AREA) + self.productInfoArea.isPresent = True + self.productinfoAreaOffset = ord(commonHead[4]) + d_print("length offset value: %02x" % + ord(eeprom[self.productinfoAreaOffset * 8 + 1])) + self.productInfoArea.size = ord( + eeprom[self.productinfoAreaOffset * 8 + 1]) * 8 + d_print("Product Info Area is present size:%d" % + (self.productInfoArea.size)) + + self.productInfoArea.data = eeprom[self.productinfoAreaOffset * 8: ( + self.productinfoAreaOffset * 8 + self.productInfoArea.size)] + if FruUtil.checksum(self.productInfoArea.data[:-1]) != ord(self.productInfoArea.data[-1:]): + strtmp = "check productInfoArea checksum error [cal:%02x data:%02x]" % ( + FruUtil.checksum(self.productInfoArea.data[:-1]), ord(self.productInfoArea.data[-1:])) + raise FruException(strtmp, -3) + self.productInfoArea.decodedata() + if ord(commonHead[5]) != ord(self.INITVALUE): + self.multiRecordArea = MultiRecordArea( + name="MultiRecord record Area ") + d_print("MultiRecord record present") + self.multiRecordArea.isPresent = True + self.multiRecordAreaOffset = ord(commonHead[5]) + self.multiRecordArea.data = eeprom[self.multiRecordAreaOffset * 8: ( + self.multiRecordAreaOffset * 8 + self.multiRecordArea.size)] + + def initDefault(self): + self.version = self.COMMON_HEAD_VERSION + self.internalUserAreaOffset = self.INITVALUE + self.chassicInfoAreaOffset = self.INITVALUE + self.boardInfoAreaOffset = self.INITVALUE + self.productinfoAreaOffset = self.INITVALUE + self.multiRecordAreaOffset = self.INITVALUE + self.zeroCheckSum = self.INITVALUE + self.offset = self.SUGGESTED_SIZE_COMMON_HEADER + self.productInfoArea = None + self.internalUseArea = None + self.boardInfoArea = None + self.chassisInfoArea = None + self.multiRecordArea = None + # self.recalcute() + + @property + def version(self): + return self._version + + @version.setter + def version(self, name): + self._version = name + + @property + def internalUserAreaOffset(self): + return self._internalUserAreaOffset + + @internalUserAreaOffset.setter + def internalUserAreaOffset(self, obj): + self._internalUserAreaOffset = obj + + @property + def chassicInfoAreaOffset(self): + return self._chassicInfoAreaOffset + + @chassicInfoAreaOffset.setter + def chassicInfoAreaOffset(self, obj): + self._chassicInfoAreaOffset = obj + + @property + def productinfoAreaOffset(self): + return self._productinfoAreaOffset + + @productinfoAreaOffset.setter + def productinfoAreaOffset(self, obj): + self._productinfoAreaOffset = obj + + @property + def boardInfoAreaOffset(self): + return self._boardInfoAreaOffset + + @boardInfoAreaOffset.setter + def boardInfoAreaOffset(self, obj): + self._boardInfoAreaOffset = obj + + @property + def multiRecordAreaOffset(self): + return self._multiRecordAreaOffset + + @multiRecordAreaOffset.setter + def multiRecordAreaOffset(self, obj): + self._multiRecordAreaOffset = obj + + @property + def zeroCheckSum(self): + return self._zeroCheckSum + + @zeroCheckSum.setter + def zeroCheckSum(self, obj): + self._zeroCheckSum = obj + + @property + def productInfoArea(self): + return self._ProductInfoArea + + @productInfoArea.setter + def productInfoArea(self, obj): + self._ProductInfoArea = obj + + @property + def internalUseArea(self): + return self._InternalUseArea + + @internalUseArea.setter + def internalUseArea(self, obj): + self.internalUseArea = obj + + @property + def boardInfoArea(self): + return self._BoardInfoArea + + @boardInfoArea.setter + def boardInfoArea(self, obj): + self._BoardInfoArea = obj + + @property + def chassisInfoArea(self): + return self._ChassisInfoArea + + @chassisInfoArea.setter + def chassisInfoArea(self, obj): + self._ChassisInfoArea = obj + + @property + def multiRecordArea(self): + return self._multiRecordArea + + @multiRecordArea.setter + def multiRecordArea(self, obj): + self._multiRecordArea = obj + + @property + def bindata(self): + return self._bindata + + @bindata.setter + def bindata(self, obj): + self._bindata = obj + + @property + def bodybin(self): + return self._bodybin + + @bodybin.setter + def bodybin(self, obj): + self._bodybin = obj + + def recalcuteCommonHead(self): + self.bindata = "" + self.offset = self.SUGGESTED_SIZE_COMMON_HEADER + d_print("common Header %d" % self.offset) + d_print("fru eeprom size %d" % self._frusize) + if self.internalUseArea is not None and self.internalUseArea.isPresent: + self.internalUserAreaOffset = self.offset // 8 + self.offset += self.internalUseArea.size + d_print("internalUseArea is present offset:%d" % self.offset) + + if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: + self.chassicInfoAreaOffset = self.offset // 8 + self.offset += self.chassisInfoArea.size + d_print("chassisInfoArea is present offset:%d" % self.offset) + + if self.boardInfoArea is not None and self.boardInfoArea.isPresent: + self.boardInfoAreaOffset = self.offset // 8 + self.offset += self.boardInfoArea.size + d_print("boardInfoArea is present offset:%d" % self.offset) + d_print("boardInfoArea is present size:%d" % + self.boardInfoArea.size) + + if self.productInfoArea is not None and self.productInfoArea.isPresent: + self.productinfoAreaOffset = self.offset // 8 + self.offset += self.productInfoArea.size + d_print("productInfoArea is present offset:%d" % self.offset) + + if self.multiRecordArea is not None and self.multiRecordArea.isPresent: + self.multiRecordAreaOffset = self.offset // 8 + d_print("multiRecordArea is present offset:%d" % self.offset) + + if self.internalUserAreaOffset == self.INITVALUE: + self.internalUserAreaOffset = 0 + if self.productinfoAreaOffset == self.INITVALUE: + self.productinfoAreaOffset = 0 + if self.chassicInfoAreaOffset == self.INITVALUE: + self.chassicInfoAreaOffset = 0 + if self.boardInfoAreaOffset == self.INITVALUE: + self.boardInfoAreaOffset = 0 + if self.multiRecordAreaOffset == self.INITVALUE: + self.multiRecordAreaOffset = 0 + + self.zeroCheckSum = (0x100 - ord(self.version) - self.internalUserAreaOffset - self.chassicInfoAreaOffset - self.productinfoAreaOffset + - self.boardInfoAreaOffset - self.multiRecordAreaOffset) & 0xff + d_print("zerochecksum:%x" % self.zeroCheckSum) + self.data = "" + self.data += chr(self.version[0]) + chr(self.internalUserAreaOffset) + chr(self.chassicInfoAreaOffset) + chr( + self.boardInfoAreaOffset) + chr(self.productinfoAreaOffset) + chr(self.multiRecordAreaOffset) + chr(self.INITVALUE[0]) + chr(self.zeroCheckSum) + + self.bindata = self.data + self.bodybin + totallen = len(self.bindata) + d_print("totallen %d" % totallen) + if totallen < self._frusize: + self.bindata = self.bindata.ljust(self._frusize, chr(self.INITVALUE[0])) + else: + raise FruException('bin data more than %d' % self._frusize, -2) + + def recalcutebin(self): + self.bodybin = "" + if self.internalUseArea is not None and self.internalUseArea.isPresent: + d_print("internalUseArea present") + self.bodybin += self.internalUseArea.data + if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: + d_print("chassisInfoArea present") + self.bodybin += self.chassisInfoArea.data + if self.boardInfoArea is not None and self.boardInfoArea.isPresent: + d_print("boardInfoArea present") + self.boardInfoArea.recalcute() + self.bodybin += self.boardInfoArea.data + if self.productInfoArea is not None and self.productInfoArea.isPresent: + d_print("productInfoAreapresent") + self.productInfoArea.recalcute() + self.bodybin += self.productInfoArea.data + if self.multiRecordArea is not None and self.multiRecordArea.isPresent: + d_print("multiRecordArea present") + self.bodybin += self.productInfoArea.data + + def recalcute(self, fru_eeprom_size=256): + self._frusize = fru_eeprom_size + self.recalcutebin() + self.recalcuteCommonHead() + + def setValue(self, area, field, value): + tmp_area = getattr(self, area, None) + if tmp_area is not None: + tmp_area.fruSetValue(field, value) diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/hwsku.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/hwsku.json new file mode 100644 index 000000000000..9a5a4d2b6420 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/hwsku.json @@ -0,0 +1,172 @@ +{ + "interfaces": { + "Ethernet1": { + "default_brkout_mode": "1x25G" + }, + "Ethernet2": { + "default_brkout_mode": "1x25G" + }, + "Ethernet3": { + "default_brkout_mode": "1x25G" + }, + "Ethernet4": { + "default_brkout_mode": "1x25G" + }, + "Ethernet5": { + "default_brkout_mode": "1x25G" + }, + "Ethernet6": { + "default_brkout_mode": "1x25G" + }, + "Ethernet7": { + "default_brkout_mode": "1x25G" + }, + "Ethernet8": { + "default_brkout_mode": "1x25G" + }, + "Ethernet9": { + "default_brkout_mode": "1x25G" + }, + "Ethernet10": { + "default_brkout_mode": "1x25G" + }, + "Ethernet11": { + "default_brkout_mode": "1x25G" + }, + "Ethernet12": { + "default_brkout_mode": "1x25G" + }, + "Ethernet13": { + "default_brkout_mode": "1x25G" + }, + "Ethernet14": { + "default_brkout_mode": "1x25G" + }, + "Ethernet15": { + "default_brkout_mode": "1x25G" + }, + "Ethernet16": { + "default_brkout_mode": "1x25G" + }, + "Ethernet17": { + "default_brkout_mode": "1x25G" + }, + "Ethernet18": { + "default_brkout_mode": "1x25G" + }, + "Ethernet19": { + "default_brkout_mode": "1x25G" + }, + "Ethernet20": { + "default_brkout_mode": "1x25G" + }, + "Ethernet21": { + "default_brkout_mode": "1x25G" + }, + "Ethernet22": { + "default_brkout_mode": "1x25G" + }, + "Ethernet23": { + "default_brkout_mode": "1x25G" + }, + "Ethernet24": { + "default_brkout_mode": "1x25G" + }, + "Ethernet25": { + "default_brkout_mode": "1x25G" + }, + "Ethernet26": { + "default_brkout_mode": "1x25G" + }, + "Ethernet27": { + "default_brkout_mode": "1x25G" + }, + "Ethernet28": { + "default_brkout_mode": "1x25G" + }, + "Ethernet29": { + "default_brkout_mode": "1x25G" + }, + "Ethernet30": { + "default_brkout_mode": "1x25G" + }, + "Ethernet31": { + "default_brkout_mode": "1x25G" + }, + "Ethernet32": { + "default_brkout_mode": "1x25G" + }, + "Ethernet33": { + "default_brkout_mode": "1x25G" + }, + "Ethernet34": { + "default_brkout_mode": "1x25G" + }, + "Ethernet35": { + "default_brkout_mode": "1x25G" + }, + "Ethernet36": { + "default_brkout_mode": "1x25G" + }, + "Ethernet37": { + "default_brkout_mode": "1x25G" + }, + "Ethernet38": { + "default_brkout_mode": "1x25G" + }, + "Ethernet39": { + "default_brkout_mode": "1x25G" + }, + "Ethernet40": { + "default_brkout_mode": "1x25G" + }, + "Ethernet41": { + "default_brkout_mode": "1x25G" + }, + "Ethernet42": { + "default_brkout_mode": "1x25G" + }, + "Ethernet43": { + "default_brkout_mode": "1x25G" + }, + "Ethernet44": { + "default_brkout_mode": "1x25G" + }, + "Ethernet45": { + "default_brkout_mode": "1x25G" + }, + "Ethernet46": { + "default_brkout_mode": "1x25G" + }, + "Ethernet47": { + "default_brkout_mode": "1x25G" + }, + "Ethernet48": { + "default_brkout_mode": "1x25G" + }, + "Ethernet49": { + "default_brkout_mode": "1x100G" + }, + "Ethernet53": { + "default_brkout_mode": "1x100G" + }, + "Ethernet57": { + "default_brkout_mode": "1x100G" + }, + "Ethernet61": { + "default_brkout_mode": "1x100G" + }, + "Ethernet65": { + "default_brkout_mode": "1x100G" + }, + "Ethernet69": { + "default_brkout_mode": "1x100G" + }, + "Ethernet73": { + "default_brkout_mode": "1x100G" + }, + "Ethernet77": { + "default_brkout_mode": "1x100G" + } + } +} \ No newline at end of file diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/installer.conf b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/installer.conf new file mode 100644 index 000000000000..7a9fec8cc99c --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/installer.conf @@ -0,0 +1,2 @@ +CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="intel_idle.max_cstate=0 idle=poll" \ No newline at end of file diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/led_proc_init.soc b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/led_proc_init.soc new file mode 100755 index 000000000000..59238f5cdc94 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/led_proc_init.soc @@ -0,0 +1,7 @@ +m0 load 0 0x3800 /usr/share/sonic/platform/custom_led.bin + +led auto on + +led start + +linkscan SwPortBitMap=xe,ce diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/media_settings.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/media_settings.json new file mode 100644 index 000000000000..e848307fd9bf --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/media_settings.json @@ -0,0 +1,2020 @@ +{ + "PORT_MEDIA_SETTINGS": { + "49": { + "Default": { + "pre1": { + "lane0": "0x0000000C", + "lane1": "0x0000000C", + "lane2": "0x0000000C", + "lane3": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B", + "lane1": "0x0000004B", + "lane2": "0x0000004B", + "lane3": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D", + "lane1": "0x0000000D", + "lane2": "0x0000000D", + "lane3": "0x0000000D" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000000", + "lane3": "0x00000000" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004", + "lane1": "0x00000004", + "lane2": "0x00000004", + "lane3": "0x00000004" + } + } + }, + "50": { + "Default": { + "pre1": { + "lane0": "0x0000000C", + "lane1": "0x0000000C", + "lane2": "0x0000000C", + "lane3": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B", + "lane1": "0x0000004B", + "lane2": "0x0000004B", + "lane3": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D", + "lane1": "0x0000000D", + "lane2": "0x0000000D", + "lane3": "0x0000000D" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000000", + "lane3": "0x00000000" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004", + "lane1": "0x00000004", + "lane2": "0x00000004", + "lane3": "0x00000004" + } + } + }, + "51": { + "Default": { + "pre1": { + "lane0": "0x0000000C", + "lane1": "0x0000000C", + "lane2": "0x0000000C", + "lane3": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B", + "lane1": "0x0000004B", + "lane2": "0x0000004B", + "lane3": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D", + "lane1": "0x0000000D", + "lane2": "0x0000000D", + "lane3": "0x0000000D" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000000", + "lane3": "0x00000000" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004", + "lane1": "0x00000006", + "lane2": "0x00000006", + "lane3": "0x00000004" + } + } + }, + "52": { + "Default": { + "pre1": { + "lane0": "0x0000000C", + "lane1": "0x0000000C", + "lane2": "0x0000000C", + "lane3": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B", + "lane1": "0x0000004B", + "lane2": "0x0000004B", + "lane3": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D", + "lane1": "0x0000000D", + "lane2": "0x0000000D", + "lane3": "0x0000000D" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000000", + "lane3": "0x00000000" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004", + "lane1": "0x00000005", + "lane2": "0x00000005", + "lane3": "0x00000005" + } + } + }, + "53": { + "Default": { + "pre1": { + "lane0": "0x0000000C", + "lane1": "0x0000000C", + "lane2": "0x0000000C", + "lane3": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B", + "lane1": "0x0000004B", + "lane2": "0x0000004B", + "lane3": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D", + "lane1": "0x0000000D", + "lane2": "0x0000000D", + "lane3": "0x0000000D" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000000", + "lane3": "0x00000000" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004", + "lane1": "0x00000006", + "lane2": "0x00000006", + "lane3": "0x00000006" + } + } + }, + "54": { + "Default": { + "pre1": { + "lane0": "0x0000000C", + "lane1": "0x0000000C", + "lane2": "0x0000000C", + "lane3": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B", + "lane1": "0x0000004B", + "lane2": "0x0000004B", + "lane3": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D", + "lane1": "0x0000000D", + "lane2": "0x0000000D", + "lane3": "0x0000000D" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000000", + "lane3": "0x00000000" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000005", + "lane1": "0x00000005", + "lane2": "0x00000005", + "lane3": "0x00000005" + } + } + }, + "55": { + "Default": { + "pre1": { + "lane0": "0x0000000A", + "lane1": "0x0000000A", + "lane2": "0x0000000A", + "lane3": "0x0000000A" + }, + "main": { + "lane0": "0x00000046", + "lane1": "0x00000046", + "lane2": "0x00000046", + "lane3": "0x00000046" + }, + "post1": { + "lane0": "0x00000014", + "lane1": "0x00000014", + "lane2": "0x00000014", + "lane3": "0x00000014" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000001", + "lane3": "0x00000001" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000006", + "lane1": "0x00000006", + "lane2": "0x00000006", + "lane3": "0x00000006" + } + } + }, + "56": { + "Default": { + "pre1": { + "lane0": "0x0000000A", + "lane1": "0x0000000A", + "lane2": "0x0000000A", + "lane3": "0x0000000A" + }, + "main": { + "lane0": "0x00000046", + "lane1": "0x00000046", + "lane2": "0x00000046", + "lane3": "0x00000046" + }, + "post1": { + "lane0": "0x00000014", + "lane1": "0x00000014", + "lane2": "0x00000014", + "lane3": "0x00000014" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000000", + "lane3": "0x00000000" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000006", + "lane1": "0x00000006", + "lane2": "0x00000006", + "lane3": "0x00000006" + } + } + }, + "1": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000006" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "2": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000006" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "3": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000006" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "4": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000005" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "5": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000005" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "6": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000005" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "7": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000005" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "8": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "9": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "10": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "11": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "12": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "13": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "14": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "15": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "16": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "17": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "18": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "19": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "20": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000003" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "21": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "22": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000003" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "23": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "24": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000002" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "25": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000003" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "26": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000002" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "27": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "28": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000002" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "29": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "30": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000002" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "31": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "32": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "33": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "34": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000003" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "35": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "36": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "37": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "38": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "39": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "40": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "41": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "42": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "43": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "44": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "45": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "46": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "47": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "48": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + } + } +} \ No newline at end of file diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/monitor.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/monitor.py new file mode 100644 index 000000000000..bdeaf190f099 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/monitor.py @@ -0,0 +1,402 @@ +#!/usr/bin/python3 +# * onboard temperature sensors +# * FAN trays +# * PSU +# +import os +import xml.etree.ElementTree as ET +import glob +import json +from decimal import Decimal +from fru import ipmifru + + +MAILBOX_DIR = "/sys/bus/i2c/devices/" +BOARD_ID_PATH = "/sys/module/platform_common/parameters/dfd_my_type" +BOARD_AIRFLOW_PATH = "/etc/sonic/.airflow" + + +CONFIG_NAME = "dev.xml" + + +def byteTostr(val): + strtmp = '' + for value in val: + strtmp += chr(value) + return strtmp + + +def typeTostr(val): + if isinstance(val, bytes): + strtmp = byteTostr(val) + return strtmp + return val + + +def get_board_id(): + if not os.path.exists(BOARD_ID_PATH): + return "NA" + with open(BOARD_ID_PATH) as fd: + id_str = fd.read().strip() + return "0x%x" % (int(id_str, 10)) + + +def getboardairflow(): + if not os.path.exists(BOARD_AIRFLOW_PATH): + return "NA" + with open(BOARD_AIRFLOW_PATH) as fd: + airflow_str = fd.read().strip() + data = json.loads(airflow_str) + airflow = data.get("board", "NA") + return airflow + + +boardid = get_board_id() +boardairflow = getboardairflow() + + +DEV_XML_FILE_LIST = [ + "dev_" + boardid + "_" + boardairflow + ".xml", + "dev_" + boardid + ".xml", + "dev_" + boardairflow + ".xml", +] + + +def dev_file_read(path, offset, read_len): + retval = "ERR" + val_list = [] + msg = "" + ret = "" + fd = -1 + + if not os.path.exists(path): + return False, "%s %s not found" % (retval, path) + + try: + fd = os.open(path, os.O_RDONLY) + os.lseek(fd, offset, os.SEEK_SET) + ret = os.read(fd, read_len) + for item in ret: + val_list.append(item) + except Exception as e: + msg = str(e) + return False, "%s %s" % (retval, msg) + finally: + if fd > 0: + os.close(fd) + return True, val_list + + +def getPMCreg(location): + retval = 'ERR' + if not os.path.isfile(location): + return "%s %s notfound" % (retval, location) + try: + with open(location, 'r') as fd: + retval = fd.read() + except Exception as error: + return "ERR %s" % str(error) + + retval = retval.rstrip('\r\n') + retval = retval.lstrip(" ") + return retval + + +# Get a mailbox register +def get_pmc_register(reg_name): + retval = 'ERR' + mb_reg_file = reg_name + filepath = glob.glob(mb_reg_file) + if len(filepath) == 0: + return "%s %s notfound" % (retval, mb_reg_file) + mb_reg_file = filepath[0] + if not os.path.isfile(mb_reg_file): + # print mb_reg_file, 'not found !' + return "%s %s notfound" % (retval, mb_reg_file) + try: + with open(mb_reg_file, 'rb') as fd: + retval = fd.read() + retval = typeTostr(retval) + except Exception as error: + retval = "%s %s read failed, msg: %s" % (retval, mb_reg_file, str(error)) + + retval = retval.rstrip('\r\n') + retval = retval.lstrip(" ") + return retval + + +class checktype(): + def __init__(self, test1): + self.test1 = test1 + + @staticmethod + def getValue(location, bit, data_type, coefficient=1, addend=0): + try: + value_t = get_pmc_register(location) + if value_t.startswith("ERR") or value_t.startswith("NA"): + return value_t + if data_type == 1: + return float('%.1f' % ((float(value_t) / 1000) + addend)) + if data_type == 2: + return float('%.1f' % (float(value_t) / 100)) + if data_type == 3: + psu_status = int(value_t, 16) + return (psu_status & (1 << bit)) >> bit + if data_type == 4: + return int(value_t, 10) + if data_type == 5: + return float('%.1f' % (float(value_t) / 1000 / 1000)) + if data_type == 6: + return Decimal(float(value_t) * coefficient / 1000).quantize(Decimal('0.000')) + return value_t + except Exception as e: + value_t = "ERR %s" % str(e) + return value_t + + # fanFRU + @staticmethod + def decodeBinByValue(retval): + fru = ipmifru() + fru.decodeBin(retval) + return fru + + @staticmethod + def getfruValue(prob_t, root, val): + try: + ret, binval_bytes = dev_file_read(val, 0, 256) + if ret is False: + return binval_bytes + binval = byteTostr(binval_bytes) + fanpro = {} + ret = checktype.decodeBinByValue(binval) + fanpro['fan_type'] = ret.productInfoArea.productName + fanpro['hw_version'] = str(int(ret.productInfoArea.productVersion, 16)) + fanpro['sn'] = ret.productInfoArea.productSerialNumber + fan_display_name_dict = status.getDecodValue(root, "fan_display_name") + fan_name = fanpro['fan_type'].strip() + if len(fan_display_name_dict) == 0: + return fanpro + if fan_name not in fan_display_name_dict: + prob_t['errcode'] = -1 + prob_t['errmsg'] = '%s' % ("ERR fan name: %s not support" % fan_name) + else: + fanpro['fan_type'] = fan_display_name_dict[fan_name] + return fanpro + except Exception as error: + return "ERR " + str(error) + + @staticmethod + def getslotfruValue(val): + try: + binval = checktype.getValue(val, 0, 0) + if binval.startswith("ERR"): + return binval + slotpro = {} + ret = checktype.decodeBinByValue(binval) + slotpro['slot_type'] = ret.boardInfoArea.boardProductName + slotpro['hw_version'] = ret.boardInfoArea.boardextra1 + slotpro['sn'] = ret.boardInfoArea.boardSerialNumber + return slotpro + except Exception as error: + return "ERR " + str(error) + + @staticmethod + def getpsufruValue(prob_t, root, val): + try: + psu_match = False + binval = checktype.getValue(val, 0, 0) + if binval.startswith("ERR"): + return binval + psupro = {} + ret = checktype.decodeBinByValue(binval) + psupro['type1'] = ret.productInfoArea.productPartModelName + psupro['sn'] = ret.productInfoArea.productSerialNumber + psupro['hw_version'] = ret.productInfoArea.productVersion + psu_dict = status.getDecodValue(root, "psutype") + psupro['type1'] = psupro['type1'].strip() + if len(psu_dict) == 0: + return psupro + for psu_name, display_name in psu_dict.items(): + if psu_name.strip() == psupro['type1']: + psupro['type1'] = display_name + psu_match = True + break + if psu_match is not True: + prob_t['errcode'] = -1 + prob_t['errmsg'] = '%s' % ("ERR psu name: %s not support" % psupro['type1']) + return psupro + except Exception as error: + return "ERR " + str(error) + + +class status(): + def __init__(self, productname): + self.productname = productname + + @staticmethod + def getETroot(filename): + tree = ET.parse(filename) + root = tree.getroot() + return root + + @staticmethod + def getDecodValue(collection, decode): + decodes = collection.find('decode') + testdecode = decodes.find(decode) + test = {} + if testdecode is None: + return test + for neighbor in testdecode.iter('code'): + test[neighbor.attrib["key"]] = neighbor.attrib["value"] + return test + + @staticmethod + def getfileValue(location): + return checktype.getValue(location, " ", " ") + + @staticmethod + def getETValue(a, filename, tagname): + root = status.getETroot(filename) + for neighbor in root.iter(tagname): + prob_t = {} + prob_t = neighbor.attrib + prob_t['errcode'] = 0 + prob_t['errmsg'] = '' + for pros in neighbor.iter("property"): + ret = dict(list(neighbor.attrib.items()) + list(pros.attrib.items())) + if ret.get('e2type') == 'fru' and ret.get("name") == "fru": + fruval = checktype.getfruValue(prob_t, root, ret["location"]) + if isinstance(fruval, str) and fruval.startswith("ERR"): + prob_t['errcode'] = -1 + prob_t['errmsg'] = fruval + break + prob_t.update(fruval) + continue + + if ret.get("name") == "psu" and ret.get('e2type') == 'fru': + psuval = checktype.getpsufruValue(prob_t, root, ret["location"]) + if isinstance(psuval, str) and psuval.startswith("ERR"): + prob_t['errcode'] = -1 + prob_t['errmsg'] = psuval + break + prob_t.update(psuval) + continue + + if ret.get("gettype") == "config": + prob_t[ret["name"]] = ret["value"] + continue + + if 'type' not in ret.keys(): + val = "0" + else: + val = ret["type"] + if 'bit' not in ret.keys(): + bit = "0" + else: + bit = ret["bit"] + if 'coefficient' not in ret.keys(): + coefficient = 1 + else: + coefficient = float(ret["coefficient"]) + if 'addend' not in ret.keys(): + addend = 0 + else: + addend = float(ret["addend"]) + + s = checktype.getValue(ret["location"], int(bit), int(val), coefficient, addend) + if isinstance(s, str) and s.startswith("ERR"): + prob_t['errcode'] = -1 + prob_t['errmsg'] = s + break + if 'default' in ret.keys(): + rt = status.getDecodValue(root, ret['decode']) + prob_t['errmsg'] = rt[str(s)] + if str(s) != ret["default"]: + prob_t['errcode'] = -1 + break + else: + if 'decode' in ret.keys(): + rt = status.getDecodValue(root, ret['decode']) + if (ret['decode'] == "psutype" and s.replace("\x00", "").rstrip() not in rt): + prob_t['errcode'] = -1 + prob_t['errmsg'] = '%s' % ("ERR psu name: %s not support" % + (s.replace("\x00", "").rstrip())) + else: + s = rt[str(s).replace("\x00", "").rstrip()] + name = ret["name"] + prob_t[name] = str(s) + a.append(prob_t) + + @staticmethod + def getCPUValue(a, filename, tagname): + root = status.getETroot(filename) + for neighbor in root.iter(tagname): + location = neighbor.attrib["location"] + L = [] + for dirpath, dirnames, filenames in os.walk(location): + for file in filenames: + if file.endswith("input"): + L.append(os.path.join(dirpath, file)) + L = sorted(L, reverse=False) + for i in range(len(L)): + prob_t = {} + prob_t["name"] = getPMCreg("%s/temp%d_label" % (location, i + 1)) + prob_t["temp"] = float(getPMCreg("%s/temp%d_input" % (location, i + 1))) / 1000 + prob_t["alarm"] = float(getPMCreg("%s/temp%d_crit_alarm" % (location, i + 1))) / 1000 + prob_t["crit"] = float(getPMCreg("%s/temp%d_crit" % (location, i + 1))) / 1000 + prob_t["max"] = float(getPMCreg("%s/temp%d_max" % (location, i + 1))) / 1000 + a.append(prob_t) + + @staticmethod + def getFileName(): + fpath = os.path.dirname(os.path.realpath(__file__)) + for file in DEV_XML_FILE_LIST: + xml = fpath + "/" + file + if os.path.exists(xml): + return xml + return fpath + "/" + CONFIG_NAME + + @staticmethod + def checkFan(ret): + _filename = status.getFileName() + # _filename = "/usr/local/bin/" + status.getFileName() + _tagname = "fan" + status.getETValue(ret, _filename, _tagname) + + @staticmethod + def getTemp(ret): + _filename = status.getFileName() + # _filename = "/usr/local/bin/" + status.getFileName() + _tagname = "temp" + status.getETValue(ret, _filename, _tagname) + + @staticmethod + def getPsu(ret): + _filename = status.getFileName() + # _filename = "/usr/local/bin/" + status.getFileName() + _tagname = "psu" + status.getETValue(ret, _filename, _tagname) + + @staticmethod + def getcputemp(ret): + _filename = status.getFileName() + _tagname = "cpus" + status.getCPUValue(ret, _filename, _tagname) + + @staticmethod + def getDcdc(ret): + _filename = status.getFileName() + _tagname = "dcdc" + status.getETValue(ret, _filename, _tagname) + + @staticmethod + def getmactemp(ret): + _filename = status.getFileName() + _tagname = "mactemp" + status.getETValue(ret, _filename, _tagname) + + @staticmethod + def getmacpower(ret): + _filename = status.getFileName() + _tagname = "macpower" + status.getETValue(ret, _filename, _tagname) diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml new file mode 100644 index 000000000000..7b026cec395e --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml @@ -0,0 +1,440 @@ +- bus: '00' + dev: '00' + fn: '0' + id: 6f00 + name: 'Host bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DMI2 + (rev 03)' +- bus: '00' + dev: '01' + fn: '0' + id: 6f02 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 1 (rev 03)' +- bus: '00' + dev: '01' + fn: '1' + id: 6f03 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 1 (rev 03)' +- bus: '00' + dev: '02' + fn: '0' + id: 6f04 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 2 (rev 03)' +- bus: '00' + dev: '02' + fn: '2' + id: 6f06 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 2 (rev 03)' +- bus: '00' + dev: '03' + fn: '0' + id: 6f08 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 3 (rev 03)' +- bus: '00' + dev: '05' + fn: '0' + id: 6f28 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Map/VTd_Misc/System Management (rev 03)' +- bus: '00' + dev: '05' + fn: '1' + id: 6f29 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D IIO Hot Plug (rev 03)' +- bus: '00' + dev: '05' + fn: '2' + id: 6f2a + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D IIO RAS/Control Status/Global Errors (rev 03)' +- bus: '00' + dev: '05' + fn: '4' + id: 6f2c + name: 'PIC: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D I/O APIC (rev + 03)' +- bus: '00' + dev: '14' + fn: '0' + id: 8c31 + name: 'USB controller: Intel Corporation 8 Series/C220 Series Chipset Family USB + xHCI (rev 05)' +- bus: '00' + dev: '16' + fn: '0' + id: 8c3a + name: 'Communication controller: Intel Corporation 8 Series/C220 Series Chipset + Family MEI Controller #1 (rev 04)' +- bus: '00' + dev: '16' + fn: '1' + id: 8c3b + name: 'Communication controller: Intel Corporation 8 Series/C220 Series Chipset + Family MEI Controller #2 (rev 04)' +- bus: '00' + dev: 1c + fn: '0' + id: 8c10 + name: 'PCI bridge: Intel Corporation 8 Series/C220 Series Chipset Family PCI Express + Root Port #1 (rev d5)' +- bus: '00' + dev: 1c + fn: '1' + id: 8c12 + name: 'PCI bridge: Intel Corporation 8 Series/C220 Series Chipset Family PCI Express + Root Port #2 (rev d5)' +- bus: '00' + dev: 1d + fn: '0' + id: 8c26 + name: 'USB controller: Intel Corporation 8 Series/C220 Series Chipset Family USB + EHCI #1 (rev 05)' +- bus: '00' + dev: 1f + fn: '0' + id: 8c54 + name: 'ISA bridge: Intel Corporation C224 Series Chipset Family Server Standard + SKU LPC Controller (rev 05)' +- bus: '00' + dev: 1f + fn: '2' + id: 8c02 + name: 'SATA controller: Intel Corporation 8 Series/C220 Series Chipset Family 6-port + SATA Controller 1 [AHCI mode] (rev 05)' +- bus: '00' + dev: 1f + fn: '3' + id: 8c22 + name: 'SMBus: Intel Corporation 8 Series/C220 Series Chipset Family SMBus Controller + (rev 05)' +- bus: '01' + dev: '00' + fn: '0' + id: b873 + name: 'Ethernet controller: Broadcom Inc. and subsidiaries Device b873 (rev 01)' +- bus: '03' + dev: '00' + fn: '0' + id: 6f50 + name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology + Register DMA Channel 0' +- bus: '03' + dev: '00' + fn: '1' + id: 6f51 + name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology + Register DMA Channel 1' +- bus: '03' + dev: '00' + fn: '2' + id: 6f52 + name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology + Register DMA Channel 2' +- bus: '03' + dev: '00' + fn: '3' + id: 6f53 + name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology + Register DMA Channel 3' +- bus: '04' + dev: '00' + fn: '0' + id: 15ab + name: 'Ethernet controller: Intel Corporation Ethernet Connection X552 10 GbE Backplane' +- bus: '04' + dev: '00' + fn: '1' + id: 15ab + name: 'Ethernet controller: Intel Corporation Ethernet Connection X552 10 GbE Backplane' +- bus: '07' + dev: '00' + fn: '0' + id: '1537' + name: 'Ethernet controller: Intel Corporation I210 Gigabit Backplane Connection + (rev 03)' +- bus: 08 + dev: '00' + fn: '0' + id: '7022' + name: 'Memory controller: Xilinx Corporation Device 7022' +- bus: ff + dev: 0b + fn: '0' + id: 6f81 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R3 QPI Link 0/1 (rev 03)' +- bus: ff + dev: 0b + fn: '1' + id: 6f36 + name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R3 QPI Link 0/1 (rev 03)' +- bus: ff + dev: 0b + fn: '2' + id: 6f37 + name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R3 QPI Link 0/1 (rev 03)' +- bus: ff + dev: 0b + fn: '3' + id: 6f76 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R3 QPI Link Debug (rev 03)' +- bus: ff + dev: 0c + fn: '0' + id: 6fe0 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0c + fn: '1' + id: 6fe1 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0c + fn: '2' + id: 6fe2 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0c + fn: '3' + id: 6fe3 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0f + fn: '0' + id: 6ff8 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0f + fn: '4' + id: 6ffc + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0f + fn: '5' + id: 6ffd + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0f + fn: '6' + id: 6ffe + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: '10' + fn: '0' + id: 6f1d + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R2PCIe Agent (rev 03)' +- bus: ff + dev: '10' + fn: '1' + id: 6f34 + name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R2PCIe Agent (rev 03)' +- bus: ff + dev: '10' + fn: '5' + id: 6f1e + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Ubox (rev 03)' +- bus: ff + dev: '10' + fn: '6' + id: 6f7d + name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Ubox (rev 03)' +- bus: ff + dev: '10' + fn: '7' + id: 6f1f + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Ubox (rev 03)' +- bus: ff + dev: '12' + fn: '0' + id: 6fa0 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Home Agent 0 (rev 03)' +- bus: ff + dev: '12' + fn: '1' + id: 6f30 + name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Home Agent 0 (rev 03)' +- bus: ff + dev: '13' + fn: '0' + id: 6fa8 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Target Address/Thermal/RAS (rev 03)' +- bus: ff + dev: '13' + fn: '1' + id: 6f71 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Target Address/Thermal/RAS (rev 03)' +- bus: ff + dev: '13' + fn: '2' + id: 6faa + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel Target Address Decoder (rev 03)' +- bus: ff + dev: '13' + fn: '3' + id: 6fab + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel Target Address Decoder (rev 03)' +- bus: ff + dev: '13' + fn: '4' + id: 6fac + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel Target Address Decoder (rev 03)' +- bus: ff + dev: '13' + fn: '5' + id: 6fad + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel Target Address Decoder (rev 03)' +- bus: ff + dev: '13' + fn: '6' + id: 6fae + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Channel 0/1 Broadcast (rev 03)' +- bus: ff + dev: '13' + fn: '7' + id: 6faf + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Global Broadcast (rev 03)' +- bus: ff + dev: '14' + fn: '0' + id: 6fb0 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 0 Thermal Control (rev 03)' +- bus: ff + dev: '14' + fn: '1' + id: 6fb1 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 1 Thermal Control (rev 03)' +- bus: ff + dev: '14' + fn: '2' + id: 6fb2 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 0 Error (rev 03)' +- bus: ff + dev: '14' + fn: '3' + id: 6fb3 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 1 Error (rev 03)' +- bus: ff + dev: '14' + fn: '4' + id: 6fbc + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Channel 0/1 Interface (rev 03)' +- bus: ff + dev: '14' + fn: '5' + id: 6fbd + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Channel 0/1 Interface (rev 03)' +- bus: ff + dev: '14' + fn: '6' + id: 6fbe + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Channel 0/1 Interface (rev 03)' +- bus: ff + dev: '14' + fn: '7' + id: 6fbf + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Channel 0/1 Interface (rev 03)' +- bus: ff + dev: '15' + fn: '0' + id: 6fb4 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 2 Thermal Control (rev 03)' +- bus: ff + dev: '15' + fn: '1' + id: 6fb5 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 3 Thermal Control (rev 03)' +- bus: ff + dev: '15' + fn: '2' + id: 6fb6 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 2 Error (rev 03)' +- bus: ff + dev: '15' + fn: '3' + id: 6fb7 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 3 Error (rev 03)' +- bus: ff + dev: 1e + fn: '0' + id: 6f98 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1e + fn: '1' + id: 6f99 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1e + fn: '2' + id: 6f9a + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1e + fn: '3' + id: 6fc0 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1e + fn: '4' + id: 6f9c + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1f + fn: '0' + id: 6f88 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1f + fn: '2' + id: 6f8a + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform.json new file mode 100644 index 000000000000..0fe70dd1411e --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform.json @@ -0,0 +1,819 @@ +{ + "chassis": { + "name": "M2-W6510-48V8C", + "thermal_manager": false, + "status_led": { + "controllable": false, + "colors": ["green", "blinking_green", "amber", "blinking_amber"] + }, + "components": [ + { + "name": "CPU_CPLD" + }, + { + "name": "CONNECT_CPLD" + }, + { + "name": "CONNECT_CPLD-FAN" + }, + { + "name": "MAC_CPLD1" + }, + { + "name": "MAC_CPLD2" + }, + { + "name": "FPGA" + }, + { + "name": "BIOS" + } + ], + "fans": [ + { + "name": "Fantray1_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + }, + { + "name": "Fantray1_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + }, + { + "name": "Fantray2_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + }, + { + "name": "Fantray2_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + }, + { + "name": "Fantray3_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + }, + { + "name": "Fantray3_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + }, + { + "name": "Fantray4_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + }, + { + "name": "Fantray4_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + } + ], + "fan_drawers":[ + { + "name": "Fantray1", + "num_fans" : 2, + "status_led": { + "controllable": false, + "colors": ["amber", "green", "off"] + }, + "fans": [ + { + "name": "Fantray1_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + }, + { + "name": "Fantray1_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "Fantray2", + "num_fans" : 2, + "status_led": { + "controllable": false, + "colors": ["amber", "green", "off"] + }, + "fans": [ + { + "name": "Fantray2_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + }, + { + "name": "Fantray2_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "Fantray3", + "num_fans" : 2, + "status_led": { + "controllable": false, + "colors": ["amber", "green", "off"] + }, + "fans": [ + { + "name": "Fantray3_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + }, + { + "name": "Fantray3_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "Fantray4", + "num_fans" : 2, + "status_led": { + "controllable": false, + "colors": ["amber", "green", "off"] + }, + "fans": [ + { + "name": "Fantray4_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + }, + { + "name": "Fantray4_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + } + ] + } + ], + "psus": [ + { + "name": "Psu1", + "voltage": true, + "current": true, + "power": true, + "max_power": false, + "voltage_high_threshold": true, + "voltage_low_threshold": true, + "temperature": true, + "fans_target_speed": true, + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU1_FAN1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "Psu2", + "voltage": true, + "current": true, + "power": true, + "max_power": false, + "voltage_high_threshold": true, + "voltage_low_threshold": true, + "temperature": true, + "fans_target_speed": true, + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU2_FAN1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + } + ] + } + ], + "thermals": [ + { + "name": "ASIC_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + }, + { + "name": "CPU_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + }, + { + "name": "INLET_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + }, + { + "name": "OUTLET_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + }, + { + "name": "MAC_OUT_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + }, + { + "name": "MAC_IN_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + }, + { + "name": "PSU1_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + }, + { + "name": "PSU2_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + } + ], + "modules": [], + "sfps": [] + }, + "interfaces": { + "Ethernet1": { + "index": "1", + "lanes": "57", + "breakout_modes": { + "1x25G": ["Eth1"] + } + }, + "Ethernet2": { + "index": "2", + "lanes": "58", + "breakout_modes": { + "1x25G": ["Eth2"] + } + }, + "Ethernet3": { + "index": "3", + "lanes": "59", + "breakout_modes": { + "1x25G": ["Eth3"] + } + }, + "Ethernet4": { + "index": "4", + "lanes": "60", + "breakout_modes": { + "1x25G": ["Eth4"] + } + }, + "Ethernet5": { + "index": "5", + "lanes": "61", + "breakout_modes": { + "1x25G": ["Eth5"] + } + }, + "Ethernet6": { + "index": "6", + "lanes": "62", + "breakout_modes": { + "1x25G": ["Eth6"] + } + }, + "Ethernet7": { + "index": "7", + "lanes": "63", + "breakout_modes": { + "1x25G": ["Eth7"] + } + }, + "Ethernet8": { + "index": "8", + "lanes": "64", + "breakout_modes": { + "1x25G": ["Eth8"] + } + }, + "Ethernet9": { + "index": "9", + "lanes": "1", + "breakout_modes": { + "1x25G": ["Eth9"] + } + }, + "Ethernet10": { + "index": "10", + "lanes": "2", + "breakout_modes": { + "1x25G": ["Eth10"] + } + }, + "Ethernet11": { + "index": "11", + "lanes": "3", + "breakout_modes": { + "1x25G": ["Eth11"] + } + }, + "Ethernet12": { + "index": "12", + "lanes": "4", + "breakout_modes": { + "1x25G": ["Eth12"] + } + }, + "Ethernet13": { + "index": "13", + "lanes": "5", + "breakout_modes": { + "1x25G": ["Eth13"] + } + }, + "Ethernet14": { + "index": "14", + "lanes": "6", + "breakout_modes": { + "1x25G": ["Eth14"] + } + }, + "Ethernet15": { + "index": "15", + "lanes": "7", + "breakout_modes": { + "1x25G": ["Eth15"] + } + }, + "Ethernet16": { + "index": "16", + "lanes": "8", + "breakout_modes": { + "1x25G": ["Eth16"] + } + }, + "Ethernet17": { + "index": "17", + "lanes": "13", + "breakout_modes": { + "1x25G": ["Eth17"] + } + }, + "Ethernet18": { + "index": "18", + "lanes": "14", + "breakout_modes": { + "1x25G": ["Eth18"] + } + }, + "Ethernet19": { + "index": "19", + "lanes": "15", + "breakout_modes": { + "1x25G": ["Eth19"] + } + }, + "Ethernet20": { + "index": "20", + "lanes": "16", + "breakout_modes": { + "1x25G": ["Eth20"] + } + }, + "Ethernet21": { + "index": "21", + "lanes": "21", + "breakout_modes": { + "1x25G": ["Eth21"] + } + }, + "Ethernet22": { + "index": "22", + "lanes": "22", + "breakout_modes": { + "1x25G": ["Eth22"] + } + }, + "Ethernet23": { + "index": "23", + "lanes": "23", + "breakout_modes": { + "1x25G": ["Eth23"] + } + }, + "Ethernet24": { + "index": "24", + "lanes": "24", + "breakout_modes": { + "1x25G": ["Eth24"] + } + }, + "Ethernet25": { + "index": "25", + "lanes": "29", + "breakout_modes": { + "1x25G": ["Eth25"] + } + }, + "Ethernet26": { + "index": "26", + "lanes": "30", + "breakout_modes": { + "1x25G": ["Eth26"] + } + }, + "Ethernet27": { + "index": "27", + "lanes": "31", + "breakout_modes": { + "1x25G": ["Eth27"] + } + }, + "Ethernet28": { + "index": "28", + "lanes": "32", + "breakout_modes": { + "1x25G": ["Eth28"] + } + }, + "Ethernet29": { + "index": "29", + "lanes": "33", + "breakout_modes": { + "1x25G": ["Eth29"] + } + }, + "Ethernet30": { + "index": "30", + "lanes": "34", + "breakout_modes": { + "1x25G": ["Eth30"] + } + }, + "Ethernet31": { + "index": "31", + "lanes": "35", + "breakout_modes": { + "1x25G": ["Eth31"] + } + }, + "Ethernet32": { + "index": "32", + "lanes": "36", + "breakout_modes": { + "1x25G": ["Eth32"] + } + }, + "Ethernet33": { + "index": "33", + "lanes": "41", + "breakout_modes": { + "1x25G": ["Eth33"] + } + }, + "Ethernet34": { + "index": "34", + "lanes": "42", + "breakout_modes": { + "1x25G": ["Eth34"] + } + }, + "Ethernet35": { + "index": "35", + "lanes": "43", + "breakout_modes": { + "1x25G": ["Eth35"] + } + }, + "Ethernet36": { + "index": "36", + "lanes": "44", + "breakout_modes": { + "1x25G": ["Eth36"] + } + }, + "Ethernet37": { + "index": "37", + "lanes": "49", + "breakout_modes": { + "1x25G": ["Eth37"] + } + }, + "Ethernet38": { + "index": "38", + "lanes": "50", + "breakout_modes": { + "1x25G": ["Eth38"] + } + }, + "Ethernet39": { + "index": "39", + "lanes": "51", + "breakout_modes": { + "1x25G": ["Eth39"] + } + }, + "Ethernet40": { + "index": "40", + "lanes": "52", + "breakout_modes": { + "1x25G": ["Eth40"] + } + }, + "Ethernet41": { + "index": "41", + "lanes": "65", + "breakout_modes": { + "1x25G": ["Eth41"] + } + }, + "Ethernet42": { + "index": "42", + "lanes": "66", + "breakout_modes": { + "1x25G": ["Eth42"] + } + }, + "Ethernet43": { + "index": "43", + "lanes": "67", + "breakout_modes": { + "1x25G": ["Eth43"] + } + }, + "Ethernet44": { + "index": "44", + "lanes": "68", + "breakout_modes": { + "1x25G": ["Eth44"] + } + }, + "Ethernet45": { + "index": "45", + "lanes": "69", + "breakout_modes": { + "1x25G": ["Eth45"] + } + }, + "Ethernet46": { + "index": "46", + "lanes": "70", + "breakout_modes": { + "1x25G": ["Eth46"] + } + }, + "Ethernet47": { + "index": "47", + "lanes": "71", + "breakout_modes": { + "1x25G": ["Eth47"] + } + }, + "Ethernet48": { + "index": "48", + "lanes": "72", + "breakout_modes": { + "1x25G": ["Eth48"] + } + }, + "Ethernet49": { + "index": "49,49,49,49", + "lanes": "85,86,87,88", + "breakout_modes": { + "1x100G": ["Eth49"], + "2x50G": ["Eth49/1", "Eth49/2"], + "4x25G[10G]": ["Eth49/1", "Eth49/2", "Eth49/3", "Eth49/4"], + "4x10G": ["Eth49/1", "Eth49/2", "Eth49/3", "Eth49/4"] + } + }, + "Ethernet53": { + "index": "50,50,50,50", + "lanes": "77,78,79,80", + "breakout_modes": { + "1x100G": ["Eth50"], + "2x50G": ["Eth50/1", "Eth50/2"], + "4x25G[10G]": ["Eth50/1", "Eth50/2", "Eth50/3", "Eth50/4"], + "4x10G": ["Eth50/1", "Eth50/2", "Eth50/3", "Eth50/4"] + } + }, + "Ethernet57": { + "index": "51,51,51,51", + "lanes": "97,98,99,100", + "breakout_modes": { + "1x100G": ["Eth51"], + "2x50G": ["Eth51/1", "Eth51/2"], + "4x25G[10G]": ["Eth51/1", "Eth51/2", "Eth51/3", "Eth51/4"], + "4x10G": ["Eth51/1", "Eth51/2", "Eth51/3", "Eth51/4"] + } + }, + "Ethernet61": { + "index": "52,52,52,52", + "lanes": "93,94,95,96", + "breakout_modes": { + "1x100G": ["Eth52"], + "2x50G": ["Eth52/1", "Eth52/2"], + "4x25G[10G]": ["Eth52/1", "Eth52/2", "Eth52/3", "Eth52/4"], + "4x10G": ["Eth52/1", "Eth52/2", "Eth52/3", "Eth52/4"] + } + }, + "Ethernet65": { + "index": "53,53,53,53", + "lanes": "113,114,115,116", + "breakout_modes": { + "1x100G": ["Eth53"], + "2x50G": ["Eth53/1", "Eth53/2"], + "4x25G[10G]": ["Eth53/1", "Eth53/2", "Eth53/3", "Eth53/4"], + "4x10G": ["Eth53/1", "Eth53/2", "Eth53/3", "Eth53/4"] + } + }, + "Ethernet69": { + "index": "54,54,54,54", + "lanes": "105,106,107,108", + "breakout_modes": { + "1x100G": ["Eth54"], + "2x50G": ["Eth54/1","Eth54/2"], + "4x25G[10G]": ["Eth54/1", "Eth54/2", "Eth54/3", "Eth54/4"], + "4x10G": ["Eth54/1", "Eth54/2", "Eth54/3", "Eth54/4"] + } + }, + "Ethernet73": { + "index": "55,55,55,55", + "lanes": "121,122,123,124", + "breakout_modes": { + "1x100G": ["Eth55"], + "2x50G": ["Eth55/1", "Eth55/2"], + "4x25G[10G]": ["Eth55/1", "Eth55/2", "Eth55/3", "Eth55/4"], + "4x10G": ["Eth55/1", "Eth55/2", "Eth55/3", "Eth55/4"] + } + }, + "Ethernet77": { + "index": "56,56,56,56", + "lanes": "125,126,127,128", + "breakout_modes": { + "1x100G": ["Eth56"], + "2x50G": ["Eth56/1", "Eth56/2"], + "4x25G[10G]": ["Eth56/1", "Eth56/2", "Eth56/3", "Eth56/4"], + "4x10G": ["Eth56/1", "Eth56/2", "Eth56/3", "Eth56/4"] + } + } + } +} diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_asic b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_asic new file mode 100644 index 000000000000..960467652765 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_asic @@ -0,0 +1 @@ +broadcom diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_components.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_components.json new file mode 100644 index 000000000000..7986fe321313 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_components.json @@ -0,0 +1,37 @@ +{ + "chassis": { + "M2-W6510-48V8C": { + "component": { + "CPU_CPLD": { + "firmware": "", + "version": "27190516" + }, + "CONNECT_CPLD": { + "firmware": "", + "version": "49191230" + }, + "CONNECT_CPLD-FAN": { + "firmware": "", + "version": "49191230" + }, + "MAC_CPLD1": { + "firmware" : "", + "version" : "16190108" + }, + "MAC_CPLD2": { + "firmware" : "", + "version" : "17200110" + }, + "FPGA": { + "firmware": "", + "version": "7a150016" + }, + "BIOS": { + "firmware" : "", + "version" : "5.11(3BARB029)" + } + } + } + } +} + diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/sfputil.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/sfputil.py new file mode 100644 index 000000000000..3e195a36f6cb --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/sfputil.py @@ -0,0 +1,243 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import time + import os + import traceback + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 1 + PORT_END = 56 + PORTS_IN_BLOCK = 57 + + EEPROM_OFFSET = 32 + SFP_DEVICE_TYPE = "optoe2" + QSFP_DEVICE_TYPE = "optoe1" + I2C_MAX_ATTEMPT = 3 + + _port_to_eeprom_mapping = {} + port_to_i2cbus_mapping ={} + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(49, self.PORTS_IN_BLOCK) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + for x in range(self.PORT_START, self.PORTS_IN_BLOCK): + self.port_to_i2cbus_mapping[x] = x + self.EEPROM_OFFSET - 1 + SfpUtilBase.__init__(self) + + def _sfp_read_file_path(self, file_path, offset, num_bytes): + attempts = 0 + while attempts < self.I2C_MAX_ATTEMPT: + try: + file_path.seek(offset) + read_buf = file_path.read(num_bytes) + except Exception: + attempts += 1 + time.sleep(0.05) + return True, read_buf + return False, None + + def _sfp_eeprom_present(self, sysfs_sfp_i2c_client_eeprompath, offset): + """Tries to read the eeprom file to determine if the + device/sfp is present or not. If sfp present, the read returns + valid bytes. If not, read returns error 'Connection timed out""" + + if not os.path.exists(sysfs_sfp_i2c_client_eeprompath): + return False + with open(sysfs_sfp_i2c_client_eeprompath, "rb", buffering=0) as sysfsfile: + rv, buf = self._sfp_read_file_path(sysfsfile, offset, 1) + return rv + + def _add_new_sfp_device(self, sysfs_sfp_i2c_adapter_path, devaddr, devtype): + try: + sysfs_nd_path = "%s/new_device" % sysfs_sfp_i2c_adapter_path + + # Write device address to new_device file + nd_str = "%s %s" % (devtype, hex(devaddr)) + with open(sysfs_nd_path, "w") as nd_file: + nd_file.write(nd_str) + + except Exception as err: + print("Error writing to new device file: %s" % str(err)) + return 1 + else: + return 0 + + def _get_port_eeprom_path(self, port_num, devid): + sysfs_i2c_adapter_base_path = "" + + if port_num in self.port_to_eeprom_mapping: + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[port_num] + else: + sysfs_i2c_adapter_base_path = "/sys/class/i2c-adapter" + + i2c_adapter_id = self._get_port_i2c_adapter_id(port_num) + if i2c_adapter_id is None: + print("Error getting i2c bus num") + return None + + # Get i2c virtual bus path for the sfp + sysfs_sfp_i2c_adapter_path = "%s/i2c-%s" % (sysfs_i2c_adapter_base_path, + str(i2c_adapter_id)) + + # If i2c bus for port does not exist + if not os.path.exists(sysfs_sfp_i2c_adapter_path): + print("Could not find i2c bus %s. Driver not loaded?" % sysfs_sfp_i2c_adapter_path) + return None + + sysfs_sfp_i2c_client_path = "%s/%s-00%s" % (sysfs_sfp_i2c_adapter_path, + str(i2c_adapter_id), + hex(devid)[-2:]) + + # If sfp device is not present on bus, Add it + if not os.path.exists(sysfs_sfp_i2c_client_path): + if port_num in self.qsfp_ports: + ret = self._add_new_sfp_device( + sysfs_sfp_i2c_adapter_path, devid, self.QSFP_DEVICE_TYPE) + else: + ret = self._add_new_sfp_device( + sysfs_sfp_i2c_adapter_path, devid, self.SFP_DEVICE_TYPE) + if ret != 0: + print("Error adding sfp device") + return None + + sysfs_sfp_i2c_client_eeprom_path = "%s/eeprom" % sysfs_sfp_i2c_client_path + + return sysfs_sfp_i2c_client_eeprom_path + + def _read_eeprom_specific_bytes(self, sysfsfile_eeprom, offset, num_bytes): + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + rv, raw = self._sfp_read_file_path(sysfsfile_eeprom, offset, num_bytes) + if rv is False: + return None + + try: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + except Exception: + return None + + return eeprom_raw + + def get_eeprom_dom_raw(self, port_num): + if port_num in self.qsfp_ports: + # QSFP DOM EEPROM is also at addr 0x50 and thus also stored in eeprom_ifraw + return None + # Read dom eeprom at addr 0x51 + return self._read_eeprom_devid(port_num, self.IDENTITY_EEPROM_ADDR, 256) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + presence_path = "/sys/wb_plat/sff/sff%d/present" % port_num + + try: + with open(presence_path, "rb") as data: + presence_data = data.read(2) + if presence_data == "": + return False + result = int(presence_data, 16) + except IOError: + return False + + if result == 1: + return True + return False + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + + return True + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + + return True + + def reset(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + return True + + def get_transceiver_change_event(self, timeout=0): + return False, {} + + def get_highest_temperature(self): + offset = 0 + hightest_temperature = -9999 + + presence_flag = False + read_eeprom_flag = False + temperature_valid_flag = False + + for port in range(49, self.PORTS_IN_BLOCK): + if self.get_presence(port) is False: + continue + + presence_flag = True + + if port in self.qsfp_ports: + offset = 22 + else: + offset = 96 + + eeprom_path = self._get_port_eeprom_path(port, 0x50) + try: + with open(eeprom_path, mode="rb", buffering=0) as eeprom: + read_eeprom_flag = True + eeprom_raw = self._read_eeprom_specific_bytes(eeprom, offset, 2) + msb = int(eeprom_raw[0], 16) + lsb = int(eeprom_raw[1], 16) + + result = (msb << 8) | (lsb & 0xff) + result = float(result / 256.0) + if -50 <= result <= 200: + temperature_valid_flag = True + hightest_temperature = max(hightest_temperature, result) + except Exception: + print(traceback.format_exc()) + + # all port not presence + if presence_flag is False: + hightest_temperature = -10000 + + # all port read eeprom fail + elif read_eeprom_flag is False: + hightest_temperature = -9999 + + # all port temperature invalid + elif read_eeprom_flag is True and temperature_valid_flag is False: + hightest_temperature = -10000 + + hightest_temperature = round(hightest_temperature, 2) + + return hightest_temperature diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/ssd_util.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/ssd_util.py new file mode 100755 index 000000000000..89d3ccd770bd --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/ssd_util.py @@ -0,0 +1,311 @@ +# +# ssd_util.py +# +# Generic implementation of the SSD health API +# SSD models supported: +# - InnoDisk +# - StorFly +# - Virtium + +try: + import re + import os + import subprocess + from sonic_platform_base.sonic_ssd.ssd_base import SsdBase +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +SMARTCTL = "smartctl {} -a" +INNODISK = "iSmart -d {}" +VIRTIUM = "SmartCmd -m {}" +DISK_LIST_CMD = "fdisk -l -o Device" +DISK_FREE_CMD = "df -h" +MOUNT_CMD = "mount" + +NOT_AVAILABLE = "N/A" +PE_CYCLE = 3000 +FAIL_PERCENT = 95 + +# Set Vendor Specific IDs +INNODISK_HEALTH_ID = 169 +INNODISK_TEMPERATURE_ID = 194 + +class SsdUtil(SsdBase): + """ + Generic implementation of the SSD health API + """ + model = NOT_AVAILABLE + serial = NOT_AVAILABLE + firmware = NOT_AVAILABLE + temperature = NOT_AVAILABLE + health = NOT_AVAILABLE + remaining_life = NOT_AVAILABLE + sata_rate = NOT_AVAILABLE + ssd_info = NOT_AVAILABLE + vendor_ssd_info = NOT_AVAILABLE + + def __init__(self, diskdev): + self.vendor_ssd_utility = { + "Generic" : { "utility" : SMARTCTL, "parser" : self.parse_generic_ssd_info }, + "InnoDisk" : { "utility" : INNODISK, "parser" : self.parse_innodisk_info }, + "M.2" : { "utility" : INNODISK, "parser" : self.parse_innodisk_info }, + "StorFly" : { "utility" : VIRTIUM, "parser" : self.parse_virtium_info }, + "Virtium" : { "utility" : VIRTIUM, "parser" : self.parse_virtium_info } + } + + """ + The dict model_attr keys relate the vendors + LITEON : "ER2-GD","AF2MA31DTDLT" + Intel : "SSDSCKKB" + SMI : "SM619GXC" + samsung: "MZNLH" + ADATA : "IM2S3134N" + """ + self.model_attr = { + "ER2-GD" : { "temperature" : "\n190\s+(.+?)\n", "remainingLife" : "\n202\s+(.+?)\n" }, + "AF2MA31DTDLT" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n202\s+(.+?)\n" }, + "SSDSCK" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n233\s+(.+?)\n" }, + "SM619GXC" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n169\s+(.+?)\n" }, + "MZNLH" : { "temperature" : "\n190\s+(.+?)\n", "remainingLife" : "\n245\s+(.+?)\n" }, + "IM2S3134N" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n231\s+(.+?)\n" } + } + + self.key_list = list(self.model_attr.keys()) + self.attr_info_rule = "[\s\S]*SMART Attributes Data Structure revision number: 1|SMART Error Log Version[\s\S]*" + self.dev = diskdev + # Generic part + self.fetch_generic_ssd_info(diskdev) + self.parse_generic_ssd_info() + self.fetch_vendor_ssd_info(diskdev, "Generic") + + # Known vendor part + if self.model: + model_short = self.model.split()[0] + if model_short in self.vendor_ssd_utility: + self.fetch_vendor_ssd_info(diskdev, model_short) + self.parse_vendor_ssd_info(model_short) + else: + # No handler registered for this disk model + pass + else: + # Failed to get disk model + self.model = "Unknown" + + def _execute_shell(self, cmd): + process = subprocess.Popen(cmd.split(), universal_newlines=True, stdout=subprocess.PIPE) + output, error = process.communicate() + exit_code = process.returncode + if exit_code: + return None + return output + + def _parse_re(self, pattern, buffer): + res_list = re.findall(pattern, str(buffer)) + return res_list[0] if res_list else NOT_AVAILABLE + + def fetch_generic_ssd_info(self, diskdev): + self.ssd_info = self._execute_shell(self.vendor_ssd_utility["Generic"]["utility"].format(diskdev)) + + # Health and temperature values may be overwritten with vendor specific data + def parse_generic_ssd_info(self): + if "nvme" in self.dev: + self.model = self._parse_re('Model Number:\s*(.+?)\n', self.ssd_info) + + health_raw = self._parse_re('Percentage Used\s*(.+?)\n', self.ssd_info) + if health_raw == NOT_AVAILABLE: + self.health = NOT_AVAILABLE + else: + health_raw = health_raw.split()[-1] + self.health = 100 - float(health_raw.strip('%')) + + temp_raw = self._parse_re('Temperature\s*(.+?)\n', self.ssd_info) + if temp_raw == NOT_AVAILABLE: + self.temperature = NOT_AVAILABLE + else: + temp_raw = temp_raw.split()[-2] + self.temperature = float(temp_raw) + else: + self.model = self._parse_re('Device Model:\s*(.+?)\n', self.ssd_info) + model_key = "" + for key in self.key_list: + if re.search(key, self.model): + model_key = key + break + if model_key != "": + self.remaining_life = self._parse_re(self.model_attr[model_key]["remainingLife"], re.sub(self.attr_info_rule,"",self.ssd_info)).split()[2] + self.temperature = self._parse_re(self.model_attr[model_key]["temperature"], re.sub(self.attr_info_rule,"",self.ssd_info)).split()[8] + self.health = self.remaining_life + # Get the LITEON ssd health value by (PE CYCLE - AVG ERASE CYCLE )/(PE CYCLE) + if model_key in ["ER2-GD", "AF2MA31DTDLT"]: + avg_erase = int(self._parse_re('\n173\s+(.+?)\n' ,re.sub(self.attr_info_rule,"",self.ssd_info)).split()[-1]) + self.health = int(round((PE_CYCLE - avg_erase)/PE_CYCLE*100,0)) + if self.remaining_life != NOT_AVAILABLE and int(self.remaining_life) < FAIL_PERCENT: + self.remaining_life = "Fail" + self.sata_rate = self._parse_re('SATA Version is:.*current: (.+?)\)\n', self.ssd_info) + self.serial = self._parse_re('Serial Number:\s*(.+?)\n', self.ssd_info) + self.firmware = self._parse_re('Firmware Version:\s*(.+?)\n', self.ssd_info) + + def parse_innodisk_info(self): + if self.vendor_ssd_info: + self.health = self._parse_re('Health:\s*(.+?)%', self.vendor_ssd_info) + self.temperature = self._parse_re('Temperature\s*\[\s*(.+?)\]', self.vendor_ssd_info) + else: + if self.health == NOT_AVAILABLE: + health_raw = self.parse_id_number(INNODISK_HEALTH_ID) + self.health = health_raw.split()[-1] + if self.temperature == NOT_AVAILABLE: + temp_raw = self.parse_id_number(INNODISK_TEMPERATURE_ID) + self.temperature = temp_raw.split()[-6] + + def parse_virtium_info(self): + if self.vendor_ssd_info: + self.temperature = self._parse_re('Temperature_Celsius\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info) + nand_endurance = self._parse_re('NAND_Endurance\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info) + avg_erase_count = self._parse_re('Average_Erase_Count\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info) + try: + self.health = 100 - (float(avg_erase_count) * 100 / float(nand_endurance)) + except (ValueError, ZeroDivisionError): + # Invalid avg_erase_count or nand_endurance. + pass + + def fetch_vendor_ssd_info(self, diskdev, model): + self.vendor_ssd_info = self._execute_shell(self.vendor_ssd_utility[model]["utility"].format(diskdev)) + + def parse_vendor_ssd_info(self, model): + self.vendor_ssd_utility[model]["parser"]() + + def check_readonly2(self, partition, filesystem): + # parse mount cmd output info + mount_info = self._execute_shell(MOUNT_CMD) + for line in mount_info.split('\n'): + column_list = line.split() + if line == '': + continue + if column_list[0] == partition and column_list[2] == filesystem: + if column_list[5].split(',')[0][1:] == "ro": + return partition + else: + return NOT_AVAILABLE + return NOT_AVAILABLE + + def check_readonly(self, partition, filesystem): + ret = os.access(filesystem, os.W_OK) + if ret == False: + return partition + else: + return NOT_AVAILABLE + + def get_health(self): + """ + Retrieves current disk health in percentages + + Returns: + A float number of current ssd health + e.g. 83.5 + """ + return float(self.health) + + def get_temperature(self): + """ + Retrieves current disk temperature in Celsius + + Returns: + A float number of current temperature in Celsius + e.g. 40.1 + """ + return float(self.temperature) + + def get_model(self): + """ + Retrieves model for the given disk device + + Returns: + A string holding disk model as provided by the manufacturer + """ + return self.model + + def get_firmware(self): + """ + Retrieves firmware version for the given disk device + + Returns: + A string holding disk firmware version as provided by the manufacturer + """ + return self.firmware + + def get_serial(self): + """ + Retrieves serial number for the given disk device + + Returns: + A string holding disk serial number as provided by the manufacturer + """ + return self.serial + def get_sata_rate(self): + """ + Retrieves SATA rate for the given disk device + Returns: + A string holding current SATA rate as provided by the manufacturer + """ + return self.sata_rate + def get_remaining_life(self): + """ + Retrieves remaining life for the given disk device + Returns: + A string holding disk remaining life as provided by the manufacturer + """ + return self.remaining_life + def get_vendor_output(self): + """ + Retrieves vendor specific data for the given disk device + + Returns: + A string holding some vendor specific disk information + """ + return self.vendor_ssd_info + + def parse_id_number(self, id): + return self._parse_re('{}\s*(.+?)\n'.format(id), self.ssd_info) + + def get_readonly_partition(self): + """ + Check the partition mount filesystem is readonly status,then output the result. + Returns: + The readonly partition list + """ + + ro_partition_list = [] + partition_list = [] + + # parse fdisk cmd output info + disk_info = self._execute_shell(DISK_LIST_CMD) + begin_flag = False + for line in disk_info.split('\n'): + if line == "Device": + begin_flag = True + continue + if begin_flag: + if line != "": + partition_list.append(line) + else: + break + + # parse df cmd output info + disk_free = self._execute_shell(DISK_FREE_CMD) + disk_dict = {} + line_num = 0 + for line in disk_free.split('\n'): + line_num = line_num + 1 + if line_num == 1 or line == "": + continue + column_list = line.split() + disk_dict[column_list[0]] = column_list[5] + + # get partition which is readonly + for partition in partition_list: + if partition in disk_dict: + ret = self.check_readonly(partition, disk_dict[partition]) + if (ret != NOT_AVAILABLE): + ro_partition_list.append(ret) + + return ro_partition_list diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pmon_daemon_control.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..94592fa8cebc --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pmon_daemon_control.json @@ -0,0 +1,3 @@ +{ + "skip_ledd": true +} diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/system_health_monitoring_config.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/system_health_monitoring_config.json new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index 6c668ee6894d..44a722e47d54 100755 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -81,6 +81,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(RAGILE_RA_B6910_64C_PLATFORM_MODULE) \ $(RAGILE_RA_B6510_32C_PLATFORM_MODULE) \ $(RAGILE_RA_B6920_4S_PLATFORM_MODULE) \ + $(MICAS_M2_W6510_48V8C_PLATFORM_MODULE) \ $(NOKIA_IXR7250_PLATFORM_MODULE) \ $(TENCENT_TCS8400_PLATFORM_MODULE) \ $(TENCENT_TCS9400_PLATFORM_MODULE) diff --git a/platform/broadcom/platform-modules-micas.dep b/platform/broadcom/platform-modules-micas.dep new file mode 100644 index 000000000000..6ae59a668b27 --- /dev/null +++ b/platform/broadcom/platform-modules-micas.dep @@ -0,0 +1,9 @@ +MPATH := $($(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) platform/broadcom/platform-modules-micas.mk platform/broadcom/platform-modules-micas.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +DEP_FILES += $(addprefix $(MPATH)/,$(shell cd $(MPATH) && git ls-files)) + + +$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_CACHE_MODE := GIT_CONTENT_SHA +$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_DEP_FILES := $(DEP_FILES) diff --git a/platform/broadcom/platform-modules-micas.mk b/platform/broadcom/platform-modules-micas.mk new file mode 100644 index 000000000000..7f2a95cade55 --- /dev/null +++ b/platform/broadcom/platform-modules-micas.mk @@ -0,0 +1,10 @@ +## M2-W6510-48V8C +MICAS_M2_W6510_48V8C_PLATFORM_MODULE_VERSION = 1.0 +export MICAS_M2_W6510_48V8C_PLATFORM_MODULE_VERSION + +MICAS_M2_W6510_48V8C_PLATFORM_MODULE = platform-modules-micas-m2-w6510-48v8c_$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE_VERSION)_amd64.deb +$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-micas +$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) $(PDDF_PLATFORM_MODULE) +$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_PLATFORM = x86_64-micas_m2-w6510-48v8c-r0 +SONIC_DPKG_DEBS += $(MICAS_M2_W6510_48V8C_PLATFORM_MODULE) +SONIC_STRETCH_DEBS += $(MICAS_M2_W6510_48V8C_PLATFORM_MODULE) diff --git a/platform/broadcom/rules.dep b/platform/broadcom/rules.dep index 47f7f849ed2f..2c8a29bf4357 100644 --- a/platform/broadcom/rules.dep +++ b/platform/broadcom/rules.dep @@ -15,6 +15,7 @@ include $(PLATFORM_PATH)/platform-modules-quanta.dep include $(PLATFORM_PATH)/platform-modules-juniper.dep include $(PLATFORM_PATH)/platform-modules-ragile.dep include $(PLATFORM_PATH)/platform-modules-ruijie.dep +include $(PLATFORM_PATH)/platform-modules-micas.dep include $(PLATFORM_PATH)/platform-modules-brcm-xlr-gts.dep include $(PLATFORM_PATH)/docker-syncd-brcm.dep include $(PLATFORM_PATH)/docker-syncd-brcm-rpc.dep diff --git a/platform/broadcom/rules.mk b/platform/broadcom/rules.mk index 5fa7bfca74a7..df56a0c8d8e1 100755 --- a/platform/broadcom/rules.mk +++ b/platform/broadcom/rules.mk @@ -17,6 +17,7 @@ include $(PLATFORM_PATH)/platform-modules-juniper.mk include $(PLATFORM_PATH)/platform-modules-ragile.mk #include $(PLATFORM_PATH)/platform-modules-tencent.mk include $(PLATFORM_PATH)/docker-syncd-brcm.mk +include $(PLATFORM_PATH)/platform-modules-micas.mk include $(PLATFORM_PATH)/docker-syncd-brcm-rpc.mk include $(PLATFORM_PATH)/docker-saiserver-brcm.mk ifeq ($(INCLUDE_PDE), y) diff --git a/platform/broadcom/sonic-platform-modules-micas/LICENSE b/platform/broadcom/sonic-platform-modules-micas/LICENSE new file mode 100644 index 000000000000..5681cac34476 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/LICENSE @@ -0,0 +1,14 @@ +Copyright (C) 2016 Microsoft, Inc +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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. diff --git a/platform/broadcom/sonic-platform-modules-micas/common/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/Makefile new file mode 100755 index 000000000000..385dae0884fb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/Makefile @@ -0,0 +1,41 @@ +PWD = $(shell pwd) +CC ?=gcc +INSTALL_MOD_DIR ?=extra +KVERSION ?= $(shell uname -r) +KERNEL_SRC ?= /lib/modules/$(KVERSION) +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall +SUB_BUILD_DIR = $(PWD)/build +DIR_KERNEL_SRC = $(PWD)/modules +SCRIPT_DIR = $(PWD)/script +SERVICE_DIR = $(PWD)/service +BLACK_DRIVER_CONF_DIR = $(PWD)/modprobe_conf + +app_dir = $(PWD)/app +app_build_dir = $(app_dir)/build +modules_build_dir = $(DIR_KERNEL_SRC)/build + +INSTALL_MODULE_DIR = $(SUB_BUILD_DIR)/$(KERNEL_SRC)/$(INSTALL_MOD_DIR) +INSTALL_SCRIPT_DIR = $(SUB_BUILD_DIR)/usr/local/bin +INSTALL_SERVICE_DIR = $(SUB_BUILD_DIR)/lib/systemd/system +INSTALL_LIB_DIR = $(SUB_BUILD_DIR)/usr/lib/python3/dist-packages +INSTALL_BLACK_DRIVER = $(SUB_BUILD_DIR)/etc/modprobe.d + +all: + $(MAKE) -C $(app_dir) + $(MAKE) -C $(DIR_KERNEL_SRC) + @if [ ! -d ${INSTALL_MODULE_DIR} ]; then mkdir -p ${INSTALL_MODULE_DIR} ;fi + @if [ ! -d ${INSTALL_SCRIPT_DIR} ]; then mkdir -p ${INSTALL_SCRIPT_DIR} ;fi + @if [ ! -d ${INSTALL_SERVICE_DIR} ]; then mkdir -p ${INSTALL_SERVICE_DIR} ;fi + @if [ ! -d ${INSTALL_LIB_DIR} ]; then mkdir -p ${INSTALL_LIB_DIR} ;fi + @if [ -d $(PWD)/lib/ ]; then cp -r $(PWD)/lib/* ${INSTALL_LIB_DIR} ;fi + @if [ -d $(PWD)/sonic_platform/ ]; then cp -rf $(PWD)/sonic_platform ${INSTALL_LIB_DIR} ;fi + cp -r $(modules_build_dir)/*.ko $(INSTALL_MODULE_DIR) + cp -r $(app_dir)/build/app/* $(INSTALL_SCRIPT_DIR) + cp -r $(SCRIPT_DIR)/* $(INSTALL_SCRIPT_DIR) + cp -r $(SERVICE_DIR)/* $(INSTALL_SERVICE_DIR) + @if [ -d $(INSTALL_SCRIPT_DIR) ]; then chmod +x $(INSTALL_SCRIPT_DIR)/* ;fi + @if [ ! -d ${INSTALL_BLACK_DRIVER} ]; then mkdir -p ${INSTALL_BLACK_DRIVER} ;fi + cp -r $(BLACK_DRIVER_CONF_DIR)/* $(INSTALL_BLACK_DRIVER) +clean: + rm -rf $(SUB_BUILD_DIR) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/Makefile new file mode 100644 index 000000000000..25ba3c5a9156 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/Makefile @@ -0,0 +1,25 @@ +pes_parent_dir:=$(shell pwd)/$(lastword $(MAKEFILE_LIST)) +pes_parent_dir:=$(shell dirname $(pes_parent_dir)) + +SUBDIRS=$(shell ls -l | grep ^d | awk '{if($$9 != "build") print $$9}') +INC = -I./inc + +COMMON_OUT_PUT := $(shell pwd)/build +common_out_put_dir := $(COMMON_OUT_PUT)/app +common_module_dir := $(COMMON_OUT_PUT)/module/ +export common_out_put_dir common_module_dir + +all : CHECK $(SUBDIRS) +CHECK : + @echo $(pes_parent_dir) + +$(SUBDIRS):ECHO + #@echo $@ + make -C $@ + +ECHO: + @echo $(SUBDIRS) + +.PHONY : clean +clean : + -rm -rf $(COMMON_OUT_PUT) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/Makefile new file mode 100644 index 000000000000..e4078716eb33 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/Makefile @@ -0,0 +1,30 @@ +top_srcdir:=$(shell pwd) +#include $(top_srcdir)/Rules.mk +DIR=$(shell pwd) +BUILD_OUTPUT=$(DIR)/tmp +SRCS=$(wildcard *.c) +OBJS=$(patsubst %.c, $(BUILD_OUTPUT)/%.o, $(SRCS)) +DEPS=$(patsubst %.o, %.d, $(OBJS)) +CFLAGS+=-Wall -W -g -I$(DIR)/include +LDFLAGS= +PROGRAM=dfd_debug + +.PHONY: all + +all:$(OBJS) + $(CC) $(OBJS) $(LDFLAGS) -o $(BUILD_OUTPUT)/$(PROGRAM) + @if [ ! -d ${common_out_put_dir} ]; then mkdir -p ${common_out_put_dir} ;fi + cp -p $(BUILD_OUTPUT)/$(PROGRAM) $(common_out_put_dir) + +$(OBJS):$(SRCS) + @if [ ! -d ${BUILD_OUTPUT} ]; then mkdir -p ${BUILD_OUTPUT} ;fi + $(CC) -c $(CFLAGS) $(INCLUDE) $(*F).c -o $@ + +.PHONY: install +install: + @mkdir -p $(common_out_put_dir) + cp -p $(BUILD_OUTPUT)/$(PROGRAM) $(common_out_put_dir) + +rebuild: clean all +clean: + @rm -rf $(BUILD_OUTPUT)/* diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_debug.c b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_debug.c new file mode 100644 index 000000000000..93ed6066efed --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_debug.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "dfd_utest.h" + +int g_dfd_debug_sw = 0; +int g_dfd_debugpp_sw = 0; + +void dfd_debug_set_init(void) +{ + FILE *fp; + char buf[10]; + + mem_clear(buf, sizeof(buf)); + fp = fopen(DFD_DEBUGP_DEBUG_FILE, "r"); + if (fp != NULL) { + + g_dfd_debug_sw = 1; + fclose(fp); + } + + fp = fopen(DFD_DEBUGPP_DEBUG_FILE, "r"); + if (fp != NULL) { + + g_dfd_debugpp_sw = 1; + fclose(fp); + } + + return; +} + +int main(int argc, char* argv[]) +{ + dfd_debug_set_init(); + dfd_utest_cmd_main(argc, argv); + + return 0; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.c b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.c new file mode 100644 index 000000000000..c82b0baad4c3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.c @@ -0,0 +1,2121 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dfd_utest.h" + +#define DFD_UTEST_MAX_RDWR_NUM (256) +#define DFD_UTEST_DEFAULT_WR_NUM (1) + +#define DEV_MEM_NAME "/dev/mem" +#define DEV_KMEM_NAME "/dev/kmem" + +#define WIDTH_1Byte (1) +#define WIDTH_2Byte (2) +#define WIDTH_4Byte (4) +#define DFD_UTEST_MAX_BIT_WIDTH (4) + +struct phydev_user_info { + int phy_index; + uint32_t regnum; + uint32_t regval; +}; + +#define CMD_PHY_LIST _IOR('P', 0, struct phydev_user_info) +#define CMD_PHY_READ _IOR('P', 1, struct phydev_user_info) +#define CMD_PHY_WRITE _IOR('P', 2, struct phydev_user_info) + +struct mdio_dev_user_info { + int mdio_index; + int phyaddr; + uint32_t regnum; + uint32_t regval; +}; + +#define CMD_MDIO_LIST _IOR('M', 0, struct mdio_dev_user_info) +#define CMD_MDIO_READ _IOR('M', 1, struct mdio_dev_user_info) +#define CMD_MDIO_WRITE _IOR('M', 2, struct mdio_dev_user_info) + +#ifdef DFD_UTEST_ITEM +#undef DFD_UTEST_ITEM +#endif +#define DFD_UTEST_ITEM(_id, _type_str, _help_info, _help_info_detail) {_id, #_type_str, dfd_utest_##_type_str, _help_info, _help_info_detail}, +static dfd_utest_t g_dfd_unit_test[] = { + DFD_UTEST_ITEM_ALL +}; + +static int g_sys_page_size; +#define SYS_PAGE_SIZE g_sys_page_size +#define SYS_PAGE_MASK (~(SYS_PAGE_SIZE - 1)) + +void dfd_utest_print_cmd(int argc, char* argv[]) +{ + int i; + + for (i = 1; i < argc; i++) { + if (i != 1) { + printf(" "); + } + printf("%s", argv[i]); + } + return; +} + +void dfd_utest_print_all_help(void) +{ + int i, tbl_size; + + tbl_size = sizeof(g_dfd_unit_test) / sizeof(g_dfd_unit_test[0]); + + for (i = 0; i < tbl_size; i++) { + printf("%-20s\t\t\t%s\r\n", g_dfd_unit_test[i].type_str, g_dfd_unit_test[i].help_info); + } + + return; +} + +void dfd_utest_printf_single_help(int utest_type) +{ + int i, tbl_size; + + tbl_size = sizeof(g_dfd_unit_test) / sizeof(g_dfd_unit_test[0]); + for (i = 0; i < tbl_size; i++) { + if (g_dfd_unit_test[i].utest_type == utest_type) { + printf("%-20s\t\t\t%s\r\n", g_dfd_unit_test[i].type_str, g_dfd_unit_test[i].help_info_detail); + return; + } + } + + DFD_DEBUG_DBG("type: %d not match.\n", utest_type); + return; + +} + +void dfd_utest_printf_reg(uint8_t *buf, int buf_len, uint32_t offset_addr) +{ + int i, j, tmp; + + j = offset_addr % 16; + tmp = j; + offset_addr -= j; + printf("\n "); + + for (i = 0; i < 16; i++) { + printf("%2x ", i); + } + + for (i = 0; i < buf_len + j; i++) { + if ((i % 16) == 0) { + printf("\n0x%08x ", offset_addr); + offset_addr = offset_addr + 16; + } + if (tmp) { + printf(" "); + tmp--; + } else { + printf("%02x ", buf[i-j]); + } + } + + printf("\n"); + return; +} + +#define I2C_RETRIES 0x0701 +#define I2C_TIMEOUT 0x0702 +#define I2C_RDWR 0x0707 + +#define I2C_SLAVE 0x0703 /* Use this slave address */ + +#define I2C_SLAVE_FORCE 0x0706 /* Use this slave address, even if it + is already in use by a driver! */ +#define I2C_PEC 0x0708 /* != 0 to use PEC with SMBus */ +#define I2C_SMBUS 0x0720 /* SMBus transfer */ + +struct i2c_msg +{ + unsigned short addr; + unsigned short flags; +#define I2C_M_TEN 0x0010 +#define I2C_M_RD 0x0001 + unsigned short len; + unsigned char *buf; +}; + +struct i2c_rdwr_ioctl_data +{ + struct i2c_msg *msgs; + int nmsgs; + +}; + +#define DFD_I2C_SHORT_ADDR_TYPE 0 +#define DFD_I2C_RETRY_SLEEP_TIME (10000) /* 10ms */ +#define DFD_I2C_RETRY_TIME (50000 / DFD_I2C_RETRY_SLEEP_TIME) +/* i2c_smbus_xfer read or write markers */ +#define I2C_SMBUS_READ 1 +#define I2C_SMBUS_WRITE 0 + +/* SMBus transaction types (size parameter in the above functions) + Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */ +#define I2C_SMBUS_QUICK 0 +#define I2C_SMBUS_BYTE 1 +#define I2C_SMBUS_BYTE_DATA 2 +#define I2C_SMBUS_WORD_DATA 3 +#define I2C_SMBUS_PROC_CALL 4 +#define I2C_SMBUS_BLOCK_DATA 5 +#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 +#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ +#define I2C_SMBUS_I2C_BLOCK_DATA 8 + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,36) +/* fix tjm */ + +#ifndef __ASSEMBLY__ +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +typedef __signed__ long __s64; +typedef unsigned long __u64; + +#endif /* __ASSEMBLY__ */ + +#else +/* do noting add tjm */ +#endif + +/* + * Data for SMBus Messages + */ +#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ +union i2c_smbus_data { + __u8 byte; + __u16 word; + __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */ + /* and one more for user-space compatibility */ +}; + +/* This is the structure as used in the I2C_SMBUS ioctl call */ +struct i2c_smbus_ioctl_data { + __u8 read_write; + __u8 command; + __u32 size; + union i2c_smbus_data *data; +}; +int32_t dfd_read_port_i2c_one_time_smbus(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, + uint8_t *recv_buf, int32_t size, int addr_type) +{ + union i2c_smbus_data data; + struct i2c_smbus_ioctl_data ioctl_data; + unsigned long addr = dev_addr; + int fd; + int rc; + int rv; + int i; + + mem_clear(&ioctl_data, sizeof(struct i2c_smbus_ioctl_data)); + if (i2c_name == NULL || recv_buf == NULL) { + DFD_DEBUG_ERROR("i2c_num = NULL, recv_buf = NULL\r\n"); + return -1; + } + + DFD_DEBUG_DBG("i2c name: %s, dev_addr: 0x%x, offset_addr: 0x%x, size: %d, addr_type: %d.\n", i2c_name, dev_addr, + offset_addr, size, addr_type); + + rv = 0; + fd = open(i2c_name, O_RDWR | O_SYNC); + if (fd < 0) { + DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); + rv = fd; + goto err; + } + if (ioctl(fd, I2C_SLAVE_FORCE , addr) < 0) { + DFD_DEBUG_ERROR("ioctl 2C_SLAVE_FORCE %d.\n", errno); + rv =-1; + goto fail; + } + for (i = 0 ;i < size; i++) { + data.byte = 0; + ioctl_data.read_write = I2C_SMBUS_READ; + ioctl_data.command = (offset_addr + i); + ioctl_data.size = I2C_SMBUS_BYTE_DATA; + ioctl_data.data= &data; + + rc = ioctl(fd, I2C_SMBUS, &ioctl_data); + if (rc < 0) { + DFD_DEBUG_ERROR("read, I2C_SMBUS failed: %d.\n", errno); + rv = -1; + goto fail; + } + *(recv_buf + i) = data.byte; + } + fail: + close(fd); + err: + return rv; + +} + +int32_t dfd_read_port_i2c_one_time(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, + uint8_t *recv_buf, int32_t size, int addr_type) +{ + + int32_t fd, rv; + struct i2c_rdwr_ioctl_data ioctl_data; + struct i2c_msg msgs[2]; + uint8_t buf[2]; + + if (i2c_name == NULL || recv_buf == NULL) { + DFD_DEBUG_ERROR("i2c_num = NULL, recv_buf = NULL\r\n"); + return -1; + } + + DFD_DEBUG_DBG("i2c name %s, dev_addr 0x%x, offset_addr 0x%x, size %d, addr_type %d.\n", i2c_name, dev_addr, + offset_addr, size, addr_type); + + rv = 0; + fd = open(i2c_name, O_RDWR | O_SYNC); + if (fd < 0) { + DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); + return -1; + } + mem_clear(&ioctl_data, sizeof(ioctl_data)); + mem_clear(msgs, sizeof(msgs)); + mem_clear(buf, sizeof(buf)); + if (ioctl(fd, I2C_SLAVE, dev_addr) < 0) { + + DFD_DEBUG_ERROR("%s %dioctl fail(ret:%d, errno:%s)!\r\n", __func__ , __LINE__, rv, strerror(errno)); + rv = -1; + goto fail; + } + + buf[0] = (uint8_t)(offset_addr); + msgs[0].addr= dev_addr; + msgs[0].len= 2; + msgs[0].buf= buf; + msgs[1].addr= dev_addr; + msgs[1].flags|= I2C_M_RD; + msgs[1].len= 1; + msgs[1].buf= recv_buf; + ioctl_data.nmsgs= 1; + ioctl_data.msgs= msgs; + + rv = ioctl(fd, I2C_RDWR, &ioctl_data); + if(rv < 0) { + DFD_DEBUG_ERROR("%s %dioctl fail(ret:%d, errno:%s)!\r\n", __func__ , __LINE__, rv, strerror(errno)); + goto fail; + } + ioctl_data.msgs= &msgs[1]; + DFD_DEBUG_DBG("ioctlread, return :%d/n", ioctl(fd, I2C_RDWR, &ioctl_data)); + DFD_DEBUG_DBG("dfd_read_port_i2c addr: 0x%X, offset: 0x%X, value: 0x%X\n", dev_addr, offset_addr, *recv_buf); + fail: + close(fd); + return rv; + +} + +int32_t dfd_read_port_i2c(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, + uint8_t *recv_buf, int32_t size) +{ + int i; + int rv; + + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + rv = dfd_read_port_i2c_one_time_smbus(i2c_name, dev_addr, offset_addr, recv_buf, size, DFD_I2C_SHORT_ADDR_TYPE); + if (rv < 0) { + DFD_DEBUG_ERROR("(read times %d)i2c name %s, dev_addr 0x%X, offset_addr 0x%X, addr_type %d\n", i, i2c_name, dev_addr, offset_addr, DFD_I2C_SHORT_ADDR_TYPE); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + + return rv; +} + +int32_t dfd_write_port_i2c_one_time(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, + uint8_t *write_buf, int32_t size,int addr_type) +{ + int32_t fd, rv; + int index; + struct i2c_smbus_ioctl_data ioctl_data; + union i2c_smbus_data data; + uint8_t addr_buf[2]; + uint8_t write_buf_tmp[256]; + + if (i2c_name == NULL || write_buf == NULL ) { + DFD_DEBUG_ERROR("i2c_num = NULL \r\n"); + return -1; + } + + if (size <= 0) { + DFD_DEBUG_ERROR("error:size\n"); + return -1; + } + DFD_DEBUG_DBG("i2c name %s, dev_addr 0x%x, offset_addr 0x%x, size %d, addr_type %d\n",i2c_name, dev_addr, + offset_addr, size, addr_type); + mem_clear(&ioctl_data, sizeof(ioctl_data)); + mem_clear(addr_buf, sizeof(addr_buf)); + mem_clear(write_buf_tmp, sizeof(write_buf_tmp)); + + rv = 0; + + fd = open(i2c_name, O_RDWR | O_SYNC); + if (fd < 0) { + DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); + return -1; + } + + if (ioctl(fd, I2C_SLAVE_FORCE, dev_addr) < 0) { + DFD_DEBUG_ERROR("ioctl, I2C_SLAVE failed: %d.\n", errno); + rv = -1; + goto fail; + } + + for (index = 0; index < size; index++) { + data.byte = *(write_buf + index); + ioctl_data.read_write = I2C_SMBUS_WRITE; + ioctl_data.command = (offset_addr + index); + ioctl_data.size = I2C_SMBUS_BYTE_DATA; + ioctl_data.data= &data; + rv = ioctl(fd, I2C_SMBUS, (unsigned long)&ioctl_data); + if(rv < 0) { + DFD_DEBUG_ERROR("ioctl fail(ret:%d, errno:%s %d) !\r\n", rv, strerror(errno),errno); + break; + } + DFD_DEBUG_DBG("ret:%d value:0x%02x\n", rv, data.byte); + usleep(5000); + } + +fail: + close(fd); + return rv; +} + +int32_t dfd_write_port_i2c(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, + uint8_t *write_buf, int32_t size) +{ + int i; + int rv; + + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + rv = dfd_write_port_i2c_one_time(i2c_name, dev_addr, offset_addr, write_buf,size, DFD_I2C_SHORT_ADDR_TYPE); + if (rv < 0) { + DFD_DEBUG_ERROR("(write times %d)i2c name %s, dev_addr 0x%X, offset_addr 0x%X, addr_type %d\n", + i, i2c_name, dev_addr, offset_addr, DFD_I2C_SHORT_ADDR_TYPE); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + + return rv; +} + +static int dfd_read_io_port(uint16_t offset_addr, uint8_t *recv_buf, int32_t size) +{ + int fd; + int ret; + + fd = open("/dev/port", O_RDWR); + if (fd < 0) { + printf("open failed ret %d.\n", fd); + return -1; + } + + ret = lseek(fd, offset_addr, SEEK_SET); + if (ret < 0) { + printf("lseek failed ret %d.\n", ret); + goto exit; + } + + ret = read(fd, recv_buf, size); + if (ret != size) { + printf("read failed ret %d size %d.\n", ret, size); + ret = -1; + goto exit; + } + +exit: + close(fd); + return ret; +} + +static int dfd_write_io_port(uint16_t offset_addr, uint8_t *write_buf, int32_t size) +{ + int fd; + int ret; + + fd = open("/dev/port", O_RDWR); + if (fd < 0) { + printf("open failed ret %d.\n", fd); + return -1; + } + + ret = lseek(fd, offset_addr, SEEK_SET); + if (ret < 0) { + printf("lseek failed ret %d.\n", ret); + goto exit; + } + + ret = write(fd, write_buf, size); + if (ret != size) { + printf("write failed ret %d size %d.\n", ret, size); + ret = -1; + goto exit; + } + +exit: + close(fd); + return ret; +} + +static int dfd_process_mem(char *dev_name, char is_wr, char width, off_t offset, uint8_t *buf, int32_t size) +{ + int mfd, ret = 0; + void *base; + int i, j; + unsigned int val; + off_t map_offset; + size_t map_size; + + if (size & (width - 1)) { + printf("size %d invalid.\n", size); + return -1; + } + + mfd = open(dev_name, O_RDWR); + if (mfd < 0) { + printf("Cannot open %s.\n", dev_name); + return -1; + } + + g_sys_page_size = getpagesize(); + map_offset = offset & SYS_PAGE_MASK; + map_size = size + offset - map_offset; + base = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, mfd, map_offset); + if (base == MAP_FAILED) { + printf("mmap offset 0x%lx failed error(%s).\n", map_offset, strerror(errno)); + close(mfd); + return -1; + } + printf("width %d map_offset 0x%lx, offset 0x%lx, mmap base %p, g_sys_page_size %d\n", + width, map_offset, offset, base, g_sys_page_size); + + if (is_wr) { + for (i = 0; i < size; i = i + width) { + val = 0; + for (j = 0; j < width; j++) { + val |= buf[i + j] << (8 * j); + } + switch (width) { + case 1: + *((volatile unsigned char*)(base + i + offset - map_offset)) = val; + break; + case 2: + *((volatile unsigned short*)(base + i + offset - map_offset)) = val; + break; + case 4: + *((volatile unsigned int*)(base + i + offset - map_offset)) = val; + break; + default: + ret = -1; + printf("Not support width %d.\n", width); + goto exit; + } + } + } else { + for (i = 0; i < size; i = i + width) { + switch (width) { + case 1: + val = *((volatile unsigned char*)(base + i + offset - map_offset)); + break; + case 2: + val = *((volatile unsigned short*)(base + i + offset - map_offset)); + break; + case 4: + val = *((volatile unsigned int*)(base + i + offset - map_offset)); + break; + default: + ret = -1; + printf("Not support width %d.\n", width); + goto exit; + } + for (j = 0; j < width; j++) { + buf[i + j] = (val >> (8 * j)) & 0xff; + } + } + } +exit: + munmap(base, map_size); + close(mfd); + return ret; +} + +int32_t dfd_i2c_gen_read_one_time(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, + uint32_t offset_addr, uint8_t *recv_buf, int32_t rd_len) +{ + int32_t fd, rv, i; + struct i2c_rdwr_ioctl_data ioctl_data; + struct i2c_msg msgs[2]; + uint8_t buf[DFD_UTEST_MAX_BIT_WIDTH]; + + fd = open(i2c_path, O_RDWR | O_SYNC); + if (fd < 0) { + DFD_DEBUG_ERROR("i2c open fail fd:%d\n", fd); + return -1; + } + mem_clear(&ioctl_data, sizeof(ioctl_data)); + mem_clear(msgs, sizeof(msgs)); + mem_clear(buf, sizeof(buf)); + + i = 0; + + switch (addr_bitwidth) { + case WIDTH_4Byte: + buf[i++] = (offset_addr >> 24) & 0xFF; + buf[i++] = (offset_addr >> 16) & 0xFF; + buf[i++] = (offset_addr >> 8) & 0xFF; + buf[i++] = offset_addr & 0xFF; + break; + case WIDTH_2Byte: + buf[i++] = (offset_addr >> 8) & 0xFF; + buf[i++] = offset_addr & 0xFF; + break; + case WIDTH_1Byte: + buf[i++] = offset_addr & 0xFF; + break; + default: + DFD_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set %u addr_bitwidth \n", addr_bitwidth); + rv = -1; + goto fail; + } + + msgs[0].addr = dev_addr; + msgs[0].flags = 0; + msgs[0].len = addr_bitwidth; + msgs[0].buf = buf; + msgs[1].addr = dev_addr; + msgs[1].flags |= I2C_M_RD; + msgs[1].len = rd_len; + msgs[1].buf = recv_buf; + ioctl_data.nmsgs = 2; + ioctl_data.msgs = msgs; + + rv = ioctl(fd, I2C_RDWR, &ioctl_data); + if(rv < 0) { + DFD_DEBUG_ERROR("%s %d Error: Sending messages failed:(ret:%d, errno:%s)!\n", __func__ , __LINE__, rv, strerror(errno)); + goto fail; + } + +fail: + close(fd); + return rv; +} + +int32_t dfd_i2c_gen_read(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, + uint32_t offset_addr, uint8_t *recv_buf, int32_t rd_len) +{ + int i; + int rv; + + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + rv = dfd_i2c_gen_read_one_time(i2c_path, dev_addr, addr_bitwidth, offset_addr, recv_buf, rd_len); + if (rv < 0) { + DFD_DEBUG_ERROR("(read times:%d) i2c_path:%s, dev_addr:0x%x, addr_bitwidth:%u, offset_addr:0x%x, rd_len:%u\n", + i, i2c_path, dev_addr, addr_bitwidth, offset_addr, rd_len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + + return rv; +} + +int dfd_utest_i2c_gen_rd(int argc, char* argv[]) +{ + int ret; + uint32_t i2c_bus, dev_addr, addr_bitwidth, offset_addr, data_bitwidth, rd_len, i, j; + char *stopstring; + char i2c_path[32]; + uint8_t tmp_value[DFD_UTEST_MAX_RDWR_NUM]; + uint8_t rd_value[DFD_UTEST_MAX_RDWR_NUM]; + + if (argc != 8) { + DFD_DEBUG_ERROR("params error\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_RD); + goto exit; + } + + i2c_bus = strtol(argv[2], &stopstring, 10); + dev_addr = strtol(argv[3], &stopstring, 16); + addr_bitwidth = strtol(argv[4], &stopstring, 10); + offset_addr = strtol(argv[5], &stopstring, 16); + data_bitwidth = strtol(argv[6], &stopstring, 10); + rd_len = strtol(argv[7], &stopstring, 10); + + if (rd_len > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", rd_len); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_RD); + goto exit; + } + + dfd_utest_print_cmd(argc, argv); + printf(":\n"); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); + mem_clear(tmp_value, sizeof(tmp_value)); + ret = dfd_i2c_gen_read(i2c_path, dev_addr, addr_bitwidth, offset_addr, tmp_value, rd_len); + if (ret < 0) { + printf("read failed. ret:%d\n", ret); + goto exit; + } + + mem_clear(rd_value, sizeof(rd_value)); + if (data_bitwidth == WIDTH_1Byte) { + memcpy(rd_value, tmp_value, rd_len); + } else { + for (i = 0; i < rd_len; i += data_bitwidth) { + for (j = 0; (j < data_bitwidth) && (i + j < rd_len); j++) { + rd_value[i + data_bitwidth - j - 1] = tmp_value[i + j]; + } + } + } + + dfd_utest_printf_reg(rd_value, rd_len, offset_addr); + +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int32_t dfd_i2c_gen_write_one_time(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, + uint32_t offset_addr, uint8_t *wr_value, uint32_t wr_len) +{ + int32_t fd, rv, i; + struct i2c_rdwr_ioctl_data ioctl_data; + struct i2c_msg msgs[1]; + uint8_t buf[DFD_UTEST_MAX_BIT_WIDTH + DFD_UTEST_MAX_RDWR_NUM]; + + fd = open(i2c_path, O_RDWR | O_SYNC); + if (fd < 0) { + DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); + return -1; + } + mem_clear(&ioctl_data, sizeof(ioctl_data)); + mem_clear(msgs, sizeof(msgs)); + mem_clear(buf, sizeof(buf)); + + i = 0; + + switch (addr_bitwidth) { + case WIDTH_4Byte: + buf[i++] = (offset_addr >> 24) & 0xFF; + buf[i++] = (offset_addr >> 16) & 0xFF; + buf[i++] = (offset_addr >> 8) & 0xFF; + buf[i++] = offset_addr & 0xFF; + break; + case WIDTH_2Byte: + buf[i++] = (offset_addr >> 8) & 0xFF; + buf[i++] = offset_addr & 0xFF; + break; + case WIDTH_1Byte: + buf[i++] = offset_addr & 0xFF; + break; + default: + DFD_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set %u addr_bitwidth \r\n", addr_bitwidth); + rv = -1; + goto fail; + } + + memcpy(buf + addr_bitwidth, wr_value, wr_len); + + msgs[0].addr= dev_addr; + msgs[0].flags = 0; + msgs[0].len= addr_bitwidth + wr_len; + msgs[0].buf= buf; + + ioctl_data.nmsgs= 1; + ioctl_data.msgs= msgs; + + rv = ioctl(fd, I2C_RDWR, &ioctl_data); + if(rv < 0) { + DFD_DEBUG_ERROR("%s %dError: Sending messages failed:(ret:%d, errno:%s)!\n", __func__ , __LINE__, rv, strerror(errno)); + goto fail; + } else if (rv < ioctl_data.nmsgs) { + DFD_DEBUG_ERROR("%s %dWarning: only %d/%d messages were sent\n", __func__ , __LINE__, rv, ioctl_data.nmsgs); + } + +fail: + close(fd); + return rv; +} + +int32_t dfd_i2c_gen_write(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, + uint32_t offset_addr, uint8_t *wr_value, uint32_t wr_len) +{ + int i; + int rv; + + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + rv = dfd_i2c_gen_write_one_time(i2c_path, dev_addr, addr_bitwidth, offset_addr, wr_value, wr_len); + if (rv < 0) { + DFD_DEBUG_ERROR("(write times:%d)i2c_path:%s, dev_addr:0x%x, addr_bitwidth:%u, offset_addr:0x%x, wr_len:%u\n", + i, i2c_path, dev_addr, addr_bitwidth, offset_addr, wr_len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + + return rv; +} + +int dfd_utest_i2c_gen_wr(int argc, char* argv[]) +{ + int ret; + uint32_t i2c_bus, dev_addr, addr_bitwidth, offset_addr, data_bitwidth, wr_len, tmp_data, para_len, i, j; + char *stopstring; + char i2c_path[32]; + uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; + + if (argc < 8) { + DFD_DEBUG_ERROR("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_WR); + goto exit; + } + + i2c_bus = strtol(argv[2], &stopstring, 10); + dev_addr = strtol(argv[3], &stopstring, 16); + addr_bitwidth = strtol(argv[4], &stopstring, 10); + offset_addr = strtol(argv[5], &stopstring, 16); + data_bitwidth = strtol(argv[6], &stopstring, 10); + + para_len = argc - 7; + wr_len = para_len * data_bitwidth; + + if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_WR); + goto exit; + } + + if (data_bitwidth == WIDTH_1Byte) { + for (i = 0; i < para_len; i++) { + wr_value[i] = strtol(argv[7 + i], &stopstring, 16); + DFD_DEBUG_DBG(" index :%d value 0x%x\n", i , wr_value[i]); + } + } else { + for (i = 0; i < para_len; i++) { + tmp_data = strtol(argv[7 + i], &stopstring, 16); + DFD_DEBUG_DBG(" index :%d value 0x%x\n", i , tmp_data); + for (j = 0; j < data_bitwidth; j++) { + tmp_data = strtol(argv[7 + i], &stopstring, 16); + wr_value[j + i * data_bitwidth] = (tmp_data >> (24 - 8 * j)) & 0xFF; + } + } + } + + dfd_utest_print_cmd(argc, argv); + + printf(":\n"); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); + + ret = dfd_i2c_gen_write(i2c_path, dev_addr, addr_bitwidth, offset_addr, wr_value, wr_len); + if (ret < 0) { + printf("write failed. ret:%d\n", ret); + } else { + printf("write success\n"); + } +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_i2c_rd(int argc, char* argv[]) +{ + int ret; + uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; + uint16_t dev_addr, offset_addr; + char *stopstring; + int num, i2c_bus; + char i2c_path[32]; + + if (argc != 6) { + DFD_DEBUG_ERROR("params error\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_RD); + goto exit; + } + + i2c_bus = strtol(argv[2], &stopstring, 10); + dev_addr = strtol(argv[3], &stopstring, 16); + offset_addr = strtol(argv[4], &stopstring, 16); + num = strtol(argv[5], &stopstring, 10); + + if (num > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_RD); + goto exit; + } + + dfd_utest_print_cmd(argc, argv); + printf(":\n"); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); + mem_clear(value, sizeof(value)); + ret = dfd_read_port_i2c(i2c_path, dev_addr, offset_addr, value, num); + if (ret < 0) { + printf("failed ret %d\n", ret); + goto exit; + } + + dfd_utest_printf_reg(value, num, offset_addr); + +exit: + return DFD_RV_MODE_NOTSUPPORT; + +} + +int dfd_utest_i2c_wr(int argc, char* argv[]) +{ + int ret; + uint16_t dev_addr, offset_addr; + char *stopstring; + int i2c_bus; + char i2c_path[32]; + uint8_t wr_len,i; + uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; + + if (argc < 6) { + DFD_DEBUG_ERROR("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_WR); + goto exit; + } + + wr_len = argc - 5; + i2c_bus = strtol(argv[2], &stopstring, 10); + dev_addr = strtol(argv[3], &stopstring, 16); + offset_addr = strtol(argv[4], &stopstring, 16); + + for (i = 0; i < wr_len; i++) { + wr_value[i] = strtol(argv[5+i], &stopstring, 16); + DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); + } + + dfd_utest_print_cmd(argc, argv); + + printf(":\n"); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); + + ret = dfd_write_port_i2c(i2c_path, dev_addr, offset_addr, wr_value, wr_len); + if (ret < 0) { + printf("failed ret %d\n", ret); + } else { + printf("success\n"); + } +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_io_rd(int argc, char* argv[]) +{ + int ret; + uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; + uint16_t offset_addr; + char *stopstring; + int num; + + if (argc != 4) { + DFD_DEBUG_ERROR("params error\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_RD); + goto exit; + } + + offset_addr = strtol(argv[2], &stopstring, 16); + num = strtol(argv[3], &stopstring, 10); + + if (num > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_RD); + goto exit; + } + + dfd_utest_print_cmd(argc, argv); + printf(":\n"); + mem_clear(value, sizeof(value)); + ret = dfd_read_io_port(offset_addr, value, num); + if (ret < 0) { + printf("failed ret %d\n", ret); + goto exit; + } + + dfd_utest_printf_reg(value, num, offset_addr); + +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_io_wr(int argc, char* argv[]) +{ + int ret; + uint16_t offset_addr; + char *stopstring; + int32_t wr_len,i; + uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; + + if (argc < 4) { + DFD_DEBUG_ERROR("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_WR); + goto exit; + } + + wr_len = argc - 3; + if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_WR); + goto exit; + } + + offset_addr = strtol(argv[2], &stopstring, 16); + + for (i = 0; i < wr_len; i++) { + wr_value[i] = strtol(argv[3 + i], &stopstring, 16); + DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); + } + + dfd_utest_print_cmd(argc, argv); + + printf(":\n"); + ret = dfd_write_io_port(offset_addr, wr_value, wr_len); + if (ret < 0) { + printf("failed ret %d\n", ret); + } else { + printf("success\n"); + } +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_phymem_rd(int argc, char* argv[]) +{ + int ret, width; + uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; + off_t offset_addr; + char *stopstring; + int num; + + if (argc != 5) { + DFD_DEBUG_ERROR("params error\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_RD); + goto exit; + } + + width = strtol(argv[2], &stopstring, 10); + offset_addr = strtol(argv[3], &stopstring, 16); + num = strtol(argv[4], &stopstring, 10); + + if (num > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_RD); + goto exit; + } + + dfd_utest_print_cmd(argc, argv); + printf(":\n"); + mem_clear(value, sizeof(value)); + ret = dfd_process_mem(DEV_MEM_NAME, 0, width, offset_addr, value, num); + if (ret < 0) { + printf("failed ret %d\n", ret); + goto exit; + } + + dfd_utest_printf_reg(value, num, offset_addr); + +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_phymem_wr(int argc, char* argv[]) +{ + int ret, width; + off_t offset_addr; + char *stopstring; + int32_t wr_len,i; + uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; + + if (argc < 5) { + DFD_DEBUG_ERROR("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_WR); + goto exit; + } + + wr_len = argc - 4; + if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_WR); + goto exit; + } + + width = strtol(argv[2], &stopstring, 10); + offset_addr = strtol(argv[3], &stopstring, 16); + + for (i = 0; i < wr_len; i++) { + wr_value[i] = strtol(argv[4 + i], &stopstring, 16); + DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); + } + + dfd_utest_print_cmd(argc, argv); + + printf(":\n"); + ret = dfd_process_mem(DEV_MEM_NAME, 1, width, offset_addr, wr_value, wr_len); + if (ret < 0) { + printf("failed ret %d\n", ret); + } else { + printf("success\n"); + } +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_kmem_rd(int argc, char* argv[]) +{ + int ret, width; + uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; + uint16_t offset_addr; + char *stopstring; + int num; + + if (argc != 5) { + DFD_DEBUG_ERROR("params error\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_RD); + goto exit; + } + + width = strtol(argv[2], &stopstring, 10); + offset_addr = strtol(argv[3], &stopstring, 16); + num = strtol(argv[4], &stopstring, 10); + + if (num > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_RD); + goto exit; + } + + dfd_utest_print_cmd(argc, argv); + printf(":\n"); + mem_clear(value, sizeof(value)); + ret = dfd_process_mem(DEV_KMEM_NAME, 0, width, offset_addr, value, num); + if (ret < 0) { + printf("failed ret %d\n", ret); + goto exit; + } + + dfd_utest_printf_reg(value, num, offset_addr); + +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_kmem_wr(int argc, char* argv[]) +{ + int ret; + uint16_t offset_addr, width; + char *stopstring; + int32_t wr_len,i; + uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; + + if (argc < 5) { + DFD_DEBUG_ERROR("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_WR); + goto exit; + } + + wr_len = argc - 4; + if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_WR); + goto exit; + } + + width = strtol(argv[2], &stopstring, 10); + offset_addr = strtol(argv[3], &stopstring, 16); + + for (i = 0; i < wr_len; i++) { + wr_value[i] = strtol(argv[4 + i], &stopstring, 16); + DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); + } + + dfd_utest_print_cmd(argc, argv); + + printf(":\n"); + ret = dfd_process_mem(DEV_KMEM_NAME, 1, width, offset_addr, wr_value, wr_len); + if (ret < 0) { + printf("failed ret %d\n", ret); + } else { + printf("success\n"); + } +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +static unsigned long dfd_utest_get_file_size(const char *path) +{ + unsigned long filesize; + struct stat statbuff; + + if (stat(path, &statbuff) < 0) { + filesize = -1; + } else { + filesize = statbuff.st_size; + } + + return filesize; +} + +int dfd_utest_i2c_file_wr(int argc, char* argv[]) +{ + int ret; + uint16_t dev_addr, offset_addr; + char *stopstring; + int i2c_bus; + char i2c_path[32]; + char *file_name; + unsigned long filesize; + int fd; + uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; + int len; + int bpt; /* byte per times*/ + int page_left; + + if (argc != 7) { + printf("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_FILE_WR); + goto exit; + } + + i2c_bus = strtol(argv[2], &stopstring, 10); + dev_addr = strtol(argv[3], &stopstring, 16); + offset_addr = strtol(argv[4], &stopstring, 16); + bpt = strtol(argv[5], &stopstring, 10); + file_name = argv[6]; + + if ((bpt <= 0) || (bpt > DFD_UTEST_MAX_RDWR_NUM)) { + bpt = DFD_UTEST_MAX_RDWR_NUM; + } + + if ((bpt & (bpt - 1)) != 0) { + printf("Bytes per times %d isn't power of two.\n",bpt); + goto exit; + } + + filesize = dfd_utest_get_file_size(file_name); + if (filesize <= 0) { + printf("Input invalid file %s, filesize %lu.\n", file_name, filesize); + goto exit; + } + + fd = open(file_name, O_RDONLY); + if (fd < 0) { + printf("open file[%s] fail.\n", file_name); + goto exit; + } + + dfd_utest_print_cmd(argc, argv); + + printf(":\n"); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); + + while (filesize > 0) { + mem_clear(wr_buf, DFD_UTEST_MAX_RDWR_NUM); + len = bpt; + if (offset_addr & (bpt - 1)) { + page_left = bpt - (offset_addr & (bpt - 1)); + len = len > page_left ? page_left : len; + } + + len = read(fd, wr_buf, len); + + ret = dfd_write_port_i2c(i2c_path, dev_addr, offset_addr, wr_buf, len); + if (ret < 0) { + break; + } + offset_addr += len; + filesize -= len; + } + + close(fd); + + if (ret < 0) { + printf("failed ret %d\n", ret); + } else { + printf("success\n"); + } + +exit: + return DFD_RV_MODE_NOTSUPPORT; + +} + +/* compare with sys_flie_wr, One more step is read back verification */ +int dfd_utest_sysfs_file_upg(int argc, char* argv[]) +{ + int ret = 0; + uint32_t offset_addr; + char *file_name; + char *sysfs_loc; + char *stopstring; + unsigned long filesize; + int fd, file_fd; + uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; + int len, write_len, per_wr_len; + int i; + uint8_t reread_buf[DFD_UTEST_MAX_RDWR_NUM]; + int reback_len, reread_len; + int j = 0; + + if (argc != 5 && argc != 6) { + printf("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_FILE_UPG); + goto exit; + } + + sysfs_loc = argv[2]; + offset_addr = strtol(argv[3], &stopstring, 16); + file_name = argv[4]; + + if (argc == 6) { + per_wr_len = strtol(argv[5], &stopstring, 10); + if (per_wr_len > DFD_UTEST_MAX_RDWR_NUM || per_wr_len <= 0) { + printf("per_wr_byte %d invalid, not in range (0, 256]\n", per_wr_len); + goto exit; + } + } else { + per_wr_len = DFD_UTEST_DEFAULT_WR_NUM; + } + DFD_DEBUG_DBG("per_wr_byte: %d\n", per_wr_len); + filesize = dfd_utest_get_file_size(file_name); + if (filesize <= 0) { + printf("Input invalid file %s, filesize %lu.\n", file_name, filesize); + goto exit; + } + + fd = open(sysfs_loc, O_RDWR | O_SYNC); + if (fd < 0) { + printf("open file[%s] fail.\n", sysfs_loc); + goto exit; + } + + file_fd = open(file_name, O_RDONLY); + if (file_fd < 0) { + printf("open file[%s] fail.\n", file_name); + goto open_dev_err; + } + + dfd_utest_print_cmd(argc, argv); + + ret = lseek(fd, offset_addr, SEEK_SET); + if (ret < 0) { + printf("lseek file[%s offset=%d] fail,\n", sysfs_loc, offset_addr); + goto fail; + } + + printf(":\n"); + while (filesize > 0) { + if (filesize > (unsigned long)per_wr_len) { + len = per_wr_len; + } else { + len = filesize; + } + + mem_clear(wr_buf, DFD_UTEST_MAX_RDWR_NUM); + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + len = read(file_fd, wr_buf, len); + if (len < 0) { + DFD_DEBUG_ERROR("read file[%s] fail, offset = 0x%x retrytimes = %d ret = %d\n", + sysfs_loc, offset_addr, i ,len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + if (i == DFD_I2C_RETRY_TIME) { + printf("read file[%s] fail, offset = 0x%x, ret = %d\n", sysfs_loc, offset_addr, len); + goto fail; + } + + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + write_len = write(fd, wr_buf, len); + if (write_len != len) { + DFD_DEBUG_ERROR("write file[%s] fail,offset = 0x%x retrytimes = %d len = %d,write_len =%d\n", + sysfs_loc, offset_addr, i ,len, write_len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + if (i == DFD_I2C_RETRY_TIME) { + printf("write file[%s] fail, offset = 0x%x, len = %d,write_len =%d\n", + sysfs_loc, offset_addr, len, write_len); + goto fail; + } + + reback_len = write_len; + ret = lseek(fd, -reback_len, SEEK_CUR); + if (ret < 0) { + printf("reread lseek file[%s offset=%d] fail,lseek len=%d\n", + sysfs_loc, offset_addr, reback_len); + goto fail; + } + + mem_clear(reread_buf, DFD_UTEST_MAX_RDWR_NUM); + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + reread_len = read(fd, reread_buf, reback_len); + if (reread_len != reback_len) { + DFD_DEBUG_ERROR("reread file[%s] fail,offset = 0x%x retrytimes = %d reread_len = %d,reback_len =%d\n", + sysfs_loc, offset_addr, i ,reread_len, reback_len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + if (i == DFD_I2C_RETRY_TIME) { + printf("reread file[%s] fail, offset = 0x%x, reread_len = %d,reback_len = %d\n", + sysfs_loc, offset_addr, reread_len, reback_len); + goto fail; + } + + if (memcmp(reread_buf, wr_buf, reread_len) != 0) { + if (j < DFD_I2C_RETRY_TIME) { + DFD_DEBUG_ERROR("memcmp file[%s] fail,offset = 0x%x retrytimes = %d\n", + sysfs_loc, offset_addr, j); + j++; + ret = lseek(file_fd, -len, SEEK_CUR); + if (ret < 0) { + printf("retry file_fd lseek fail,lseek len=%d\n", len); + goto fail; + } + ret = lseek(fd, -write_len, SEEK_CUR); + if (ret < 0) { + printf("retry fd lseek fail,lseek len=%d\n", write_len); + goto fail; + } + continue; + } + + printf("upgrade file[%s] fail, offset = 0x%x.\n", sysfs_loc, offset_addr); + printf("want to write buf :\n"); + for (i = 0; i < reread_len; i++) { + printf("0x%x ", wr_buf[i]); + } + printf("\n"); + + printf("actually reread buf :\n"); + for (i = 0; i < reread_len; i++) { + printf("0x%x ", reread_buf[i]); + } + printf("\n"); + + goto fail; + } + + offset_addr += len; + filesize -= len; + usleep(5000); + } + + printf("success\n"); + close(file_fd); + close(fd); + return DFD_RV_OK; + +fail: + close(file_fd); +open_dev_err: + close(fd); +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_sysfs_file_wr(int argc, char* argv[]) +{ + int ret = 0; + uint32_t offset_addr; + char *file_name; + char *sysfs_loc; + char *stopstring; + unsigned long filesize; + int fd, file_fd; + uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; + int len, write_len, per_wr_len; + int i; + + if (argc != 5 && argc != 6) { + printf("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_FILE_WR); + goto exit; + } + + sysfs_loc = argv[2]; + offset_addr = strtol(argv[3], &stopstring, 16); + file_name = argv[4]; + + if (argc == 6) { + per_wr_len = strtol(argv[5], &stopstring, 10); + if (per_wr_len > DFD_UTEST_MAX_RDWR_NUM || per_wr_len <= 0) { + printf("per_wr_byte %d invalid, not in range (0, 256]\n", per_wr_len); + goto exit; + } + } else { + per_wr_len = DFD_UTEST_DEFAULT_WR_NUM; + } + DFD_DEBUG_DBG("per_wr_byte: %d\n", per_wr_len); + filesize = dfd_utest_get_file_size(file_name); + if (filesize <= 0) { + printf("Input invalid file %s, filesize %lu.\n", file_name, filesize); + goto exit; + } + + fd = open(sysfs_loc, O_RDWR | O_SYNC); + if (fd < 0) { + printf("open file[%s] fail.\n", sysfs_loc); + goto exit; + } + + file_fd = open(file_name, O_RDONLY); + if (file_fd < 0) { + printf("open file[%s] fail.\n", file_name); + goto open_dev_err; + } + + dfd_utest_print_cmd(argc, argv); + + ret = lseek(fd, offset_addr, SEEK_SET); + if (ret < 0) { + printf("lseek file[%s offset=%d] fail,\n", sysfs_loc, offset_addr); + goto fail; + } + + printf(":\n"); + while (filesize > 0) { + if (filesize > (unsigned long)per_wr_len) { + len = per_wr_len; + } else { + len = filesize; + } + + mem_clear(wr_buf, DFD_UTEST_MAX_RDWR_NUM); + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + len = read(file_fd, wr_buf, len); + if (len < 0) { + DFD_DEBUG_ERROR("read file[%s] fail, offset = 0x%x retrytimes = %d ret = %d\n", + sysfs_loc, offset_addr, i ,len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + if (i == DFD_I2C_RETRY_TIME) { + printf("read file[%s] fail, offset = 0x%x, ret = %d\n", sysfs_loc, offset_addr, len); + goto fail; + } + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + write_len = write(fd, wr_buf, len); + if (write_len != len) { + DFD_DEBUG_ERROR("write file[%s] fail,offset = 0x%x retrytimes = %d len = %d,write_len =%d\n", sysfs_loc, offset_addr, i ,len, write_len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + + if(i == DFD_I2C_RETRY_TIME) { + printf("write file[%s] fail, offset = 0x%x, len = %d,write_len =%d\n", sysfs_loc, offset_addr, len, write_len); + ret = -1; + goto fail; + } + offset_addr += len; + filesize -= len; + usleep(5000); + } + + printf("success\n"); + close(file_fd); + close(fd); + return DFD_RV_OK; + +fail: + close(file_fd); +open_dev_err: + close(fd); +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_sysfs_file_rd(int argc, char* argv[]) +{ + int ret = 0; + uint32_t offset_addr; + char *sysfs_loc; + char *stopstring; + int fd; + uint8_t rd_buf[DFD_UTEST_MAX_RDWR_NUM]; + int len, read_len;; + + if (argc != 5) { + printf("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_FILE_RD); + goto exit; + } + + sysfs_loc = argv[2]; + offset_addr = strtol(argv[3], &stopstring, 16); + len = strtol(argv[4], &stopstring, 10); + + if (len > DFD_UTEST_MAX_RDWR_NUM) { + printf("Input num %d exceed max 256.\n", len); + goto exit; + } + + fd = open(sysfs_loc, O_RDONLY); + if (fd < 0) { + printf("open file[%s] fail.\n", sysfs_loc); + goto exit; + } + dfd_utest_print_cmd(argc, argv); + + printf(":\n"); + + ret = lseek(fd, offset_addr, SEEK_SET); + if (ret < 0) { + printf("lseek failed ret %d.\n", ret); + goto fail; + } + + mem_clear(rd_buf, DFD_UTEST_MAX_RDWR_NUM); + read_len = read(fd, rd_buf, len); + if (read_len != len) { + printf("read failed read_len %d len %d.\n", read_len, len); + goto fail; + } + dfd_utest_printf_reg(rd_buf, read_len, offset_addr); + close(fd); + return DFD_RV_OK; + +fail: + close(fd); +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_msr_rd(int argc, char* argv[]) +{ + int fd; + char msr_file_name[64]; + uint64_t data; + uint64_t read_result; + char *stopstring; + uint8_t cpu_index, width; + uint64_t offset; + + if (argc != 5) { + printf("rdmsr failed: Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_MSR_RD); + goto exit; + } + + cpu_index = strtol(argv[2], &stopstring, 10); + offset = strtol(argv[3], &stopstring, 16); + width = strtol(argv[4], &stopstring, 10); + + if (width != 8 && width != 16 && width != 32 && width != 64) { + printf("rdmsr failed: width:%u Input invalid.only support 8 16 32 64\n", width); + goto exit; + } + + mem_clear(msr_file_name, sizeof(msr_file_name)); + sprintf(msr_file_name, "/dev/cpu/%u/msr", cpu_index); + + fd = open(msr_file_name, O_RDONLY); + if (fd < 0) { + if (errno == ENXIO) { + fprintf(stderr, "rdmsr failed: No CPU %u\n", cpu_index); + } else if (errno == EIO) { + fprintf(stderr, "rdmsr failed: CPU %u doesn't support MSRs\n", cpu_index); + } else if (errno == ENOENT) { + fprintf(stderr, "rdmsr failed: can't find %s file, Please check if modprobe msr driver already\n", msr_file_name); + } else { + printf("rdmsr failed: %s open failed. errno:%d\n", msr_file_name, errno); + } + goto exit; + } + + if (pread(fd, &data, sizeof(data), offset) != sizeof(data)) { + fprintf(stderr, "rdmsr failed: CPU:%u offset:0x%lx read failed\n", cpu_index, offset); + goto fail; + } + + switch (width) { + case 8: + read_result = (volatile uint8_t)data; + break; + case 16: + read_result = (volatile uint16_t)data; + break; + case 32: + read_result = (volatile uint32_t)data; + break; + case 64: + read_result = (volatile uint64_t)data; + break; + default: + printf("rdmsr failed: width:%u illegal width.\n", width); + goto fail; + } + + printf("0x%lx\n", read_result); + close(fd); + return DFD_RV_OK; + +fail: + close(fd); +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_sysfs_data_wr(int argc, char* argv[]) +{ + uint32_t offset; + char *sysfs_loc; + char *stopstring; + uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; + int ret, i; + int fd, len, write_len, index; + + if (argc < 5) { + DFD_DEBUG_ERROR("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_DATA_WR); + goto exit; + } + + dfd_utest_print_cmd(argc, argv); + printf(":\n"); + + sysfs_loc = argv[2]; + offset = strtol(argv[3], &stopstring, 16); + len = argc - 4; + mem_clear(wr_buf, sizeof(wr_buf)); + for (i = 0; i < len; i++) { + wr_buf[i] = strtol(argv[4 + i], &stopstring, 16); + DFD_DEBUG_DBG("index :%d value %x\n", i , wr_buf[i]); + } + + fd = open(sysfs_loc, O_RDWR | O_SYNC); + if (fd < 0) { + printf("open file[%s] fail.\n", sysfs_loc); + goto exit; + } + + ret = lseek(fd, offset, SEEK_SET); + if (ret < 0) { + printf("lseek file[%s offset=%d] fail,\n", sysfs_loc, offset); + goto fail; + } + index = 0; + while (len > 0) { + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + write_len = write(fd, &wr_buf[index], len); + if (write_len < 0) { + DFD_DEBUG_ERROR("write file[%s] fail, retrytimes: %d, offset: 0x%x, len: %d, write_len: %d\n", + sysfs_loc, offset, i, len, write_len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + if (write_len == 0) { + DFD_DEBUG_ERROR("write file[%s] EOF, offset: 0x%x, len: %d, write_len: %d\n", + sysfs_loc, offset, len, write_len); + goto fail; + } + break; + } + if(i == DFD_I2C_RETRY_TIME) { + printf("write file[%s] fail, offset: 0x%x, len: %d, write_len: %d\n", + sysfs_loc, offset, len, write_len); + goto fail; + } + offset += write_len; + index += write_len; + len -= write_len; + usleep(5000); + } + printf("success\n"); + close(fd); + return DFD_RV_OK; +fail: + close(fd); +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +static void phy_help(char *name) +{ + fprintf(stderr, + "Usage: %s phy_index(dec) regnum(hex) [regval(hex)] \n" + " phy_index phydev index \n" + " regnum phydev register address \n" + " regval phydev register value \n", + name); + return; +} + +static void mdio_help(char *name) +{ + fprintf(stderr, + "Usage: %s mdio_index(dec) phyaddr(hex) regnum(hex) [regval(hex)] \n" + " mdio_index mdiodev index \n" + " phyaddr phydev address \n" + " regnum phydev register address \n" + " regval phydev register value \n", + name); + return; +} + +static int phydev_arg_parse(int argc, char* argv[], int *phy_index, uint32_t *regnum, uint32_t *regval, + int num_arg) +{ + + unsigned long index, regaddr, value; + char *end; + + if (argc != num_arg) { + return -EINVAL; + } + + index = strtoul(argv[2], &end, 0); + if (*end) { + fprintf(stderr, "Error: index invalid!\n"); + return -EINVAL; + } + + regaddr = strtoul(argv[3], &end, 0); + if (*end || regaddr > 0xffff) { + fprintf(stderr, "Error: regaddr invalid!\n"); + return -EINVAL; + } + + if (argc > 4) { + value = strtoul(argv[4], &end, 0); + if (*end || value > 0xffff) { + fprintf(stderr, "Error: reg data invalid!\n"); + return -EINVAL; + } + + *regval = (uint32_t)value; + } + + *phy_index = (uint32_t)index; + *regnum = (uint32_t)regaddr; + + return 0; +} + +static int mdiodev_arg_parse(int argc, char* argv[], int *mdio_index, int *phyaddr, uint32_t *regnum, + uint32_t *regval, int num_arg) +{ + + unsigned long index, addr, regaddr, value; + char *end; + + if (argc != num_arg) { + return -EINVAL; + } + + index = strtoul(argv[2], &end, 0); + if (*end) { + fprintf(stderr, "Error: index invalid!\n"); + return -EINVAL; + } + + addr = strtoul(argv[3], &end, 0); + if (*end || addr > 0x1f) { + fprintf(stderr, "Error: phyaddr invalid!\n"); + return -EINVAL; + } + + regaddr = strtoul(argv[4], &end, 0); + if (*end || regaddr > 0xffff) { + fprintf(stderr, "Error: regaddr invalid!\n"); + return -EINVAL; + } + + if (argc > 5) { + value = strtoul(argv[5], &end, 0); + if (*end || value > 0xffff) { + fprintf(stderr, "Error: reg data invalid!\n"); + return -EINVAL; + } + + *regval = (uint32_t)value; + } + + *mdio_index = (uint32_t)index; + *phyaddr = (int)addr; + *regnum = (uint32_t)regaddr; + + return 0; +} + +int dfd_utest_phydev_list(int argc, char* argv[]) +{ + int fd; + + if (argc != 2) { + printf("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYDEV_LIST); + return DFD_RV_MODE_NOTSUPPORT; + } + + argv = argv; + fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); + if (fd < 0) { + fprintf(stderr, "Error: Could not open file " + "/dev/dram: %s\n", strerror(errno)); + return -1; + } + + (void)ioctl(fd, CMD_PHY_LIST, NULL); + + close(fd); + + return 0; +} + +int dfd_utest_phydev_rd(int argc, char* argv[]) +{ + struct phydev_user_info phy_info; + int fd; + long int ret; + + ret = phydev_arg_parse(argc, argv, &phy_info.phy_index, &phy_info.regnum, &phy_info.regval, 4); + if (ret < 0) { + phy_help("phydev_rd"); + return -1; + } + + fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); + if (fd < 0) { + fprintf(stderr, "Error: Could not open file " + "/dev/dram: %s\n", strerror(errno)); + return -1; + } + + ret = ioctl(fd, CMD_PHY_READ, &phy_info); + if (ret < 0) { + fprintf(stderr, "Error: phy read error : %s\n", strerror(errno)); + close(fd); + return -1; + } + + close(fd); + + printf("Read success --- phydev%d regnum: 0x%x, value: 0x%x\n",phy_info.phy_index, + phy_info.regnum, phy_info.regval); + + return 0; +} + +int dfd_utest_phydev_wr(int argc, char* argv[]) +{ + struct phydev_user_info phy_info; + int fd; + long int ret; + + ret = phydev_arg_parse(argc, argv, &phy_info.phy_index, &phy_info.regnum, &phy_info.regval, 5); + if (ret < 0) { + phy_help("phydev_wr"); + return -1; + } + + fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); + if (fd < 0) { + fprintf(stderr, "Error: Could not open file " + "/dev/dram: %s\n", strerror(errno)); + return -1; + } + + ret = ioctl(fd, CMD_PHY_WRITE, &phy_info); + if (ret < 0) { + fprintf(stderr, "Error: phy write error : %s\n", strerror(errno)); + close(fd); + return -1; + } + + close(fd); + + printf("write success --- phydev%d regnum: 0x%x, value: 0x%x\n",phy_info.phy_index, + phy_info.regnum, phy_info.regval); + + return 0; +} + +int dfd_utest_mdiodev_list(int argc, char* argv[]) +{ + int fd; + + if (argc != 2) { + printf("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_MDIODEV_LIST); + return DFD_RV_MODE_NOTSUPPORT; + } + + argv = argv; + fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); + if (fd < 0) { + fprintf(stderr, "Error: Could not open file " + "/dev/dram: %s\n", strerror(errno)); + return -1; + } + + (void)ioctl(fd, CMD_MDIO_LIST, NULL); + + close(fd); + + return 0; +} + +int dfd_utest_mdiodev_rd(int argc, char* argv[]) +{ + struct mdio_dev_user_info mdio_info; + int fd; + long int ret; + + ret = mdiodev_arg_parse(argc, argv, &mdio_info.mdio_index, &mdio_info.phyaddr, + &mdio_info.regnum, &mdio_info.regval, 5); + if (ret < 0) { + mdio_help("mdiodev_rd"); + return -1; + } + + fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); + if (fd < 0) { + fprintf(stderr, "Error: Could not open file " + "/dev/dram: %s\n", strerror(errno)); + return -1; + } + + ret = ioctl(fd, CMD_MDIO_READ, &mdio_info); + if (ret < 0) { + fprintf(stderr, "Error: mdio read error : %s\n", strerror(errno)); + close(fd); + return -1; + } + + close(fd); + + printf("Read success\n mdio_index phyaddr regnum value\n"); + printf(" %-10d %#-10x %#-10x %#-10x\n", mdio_info.mdio_index, mdio_info.phyaddr, + mdio_info.regnum, mdio_info.regval); + + return 0; +} + +int dfd_utest_mdiodev_wr(int argc, char* argv[]) +{ + struct mdio_dev_user_info mdio_info; + int fd; + long int ret; + + ret = mdiodev_arg_parse(argc, argv, &mdio_info.mdio_index, &mdio_info.phyaddr, + &mdio_info.regnum, &mdio_info.regval, 6); + if (ret < 0) { + mdio_help("mdiodev_wr"); + return -1; + } + + fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); + if (fd < 0) { + fprintf(stderr, "Error: Could not open file " + "/dev/dram: %s\n", strerror(errno)); + return -1; + } + + ret = ioctl(fd, CMD_MDIO_WRITE, &mdio_info); + if (ret < 0) { + fprintf(stderr, "Error: mdio write error : %s\n", strerror(errno)); + close(fd); + return -1; + } + + close(fd); + + printf("write success\n mdio_index phyaddr regnum value\n"); + printf(" %-10d %#-10x %#-10x %#-10x\n", mdio_info.mdio_index, mdio_info.phyaddr, + mdio_info.regnum, mdio_info.regval); + + return 0; +} + +dfd_utest_proc_fun dfd_utest_get_proc_func(char *type_str) +{ + int i, tbl_size; + + tbl_size = sizeof(g_dfd_unit_test) / sizeof(g_dfd_unit_test[0]); + + for (i = 0; i < tbl_size; i++) { + if (!strncmp(g_dfd_unit_test[i].type_str, type_str, strlen(g_dfd_unit_test[i].type_str))) { + return g_dfd_unit_test[i].utest_func; + } + } + DFD_DEBUG_DBG("type: %s not match.\n", type_str); + return NULL; +} + +void dfd_utest_cmd_main(int argc, char* argv[]) +{ + dfd_utest_proc_fun pfunc; + int ret; + + if (argc < 2) { + dfd_utest_print_all_help(); + return; + } + + pfunc = dfd_utest_get_proc_func(argv[1]); + if (pfunc == NULL) { + DFD_DEBUG_DBG("utest type %s in not support.\n", argv[1]); + dfd_utest_print_all_help(); + return; + } + ret = pfunc(argc, argv); + if ((ret != DFD_RV_MODE_NOTSUPPORT) && (ret != DFD_RV_INDEX_INVALID)) { + if (ret == DFD_RV_OK) { + DFD_DEBUG_DBG(" [SUCCESS]\n"); + } else { + DFD_DEBUG_DBG(" [FAIL(%d)]\n", ret); + } + } + + return; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.h b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.h new file mode 100644 index 000000000000..1ae65148ea9c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.h @@ -0,0 +1,109 @@ +/* monitor_utest.h */ +#ifndef __DFD_UTEST_H__ +#define __DFD_UTEST_H__ + +#include + +extern int g_dfd_debug_sw; +extern int g_dfd_debugpp_sw; + +#define DFD_UTEST_TRUE_FALSE_STRING(flag) ((flag == true) ? "true" : "false") + +#define DFD_DEBUG_DBG(fmt, args...) do { \ + if (g_dfd_debug_sw) { \ + printf("" fmt,\ + ##args); \ + } \ +} while (0) + +#define DFD_DEBUG_ERROR(fmt, args...) do { \ + if (g_dfd_debugpp_sw) { \ + printf("" fmt,\ + ##args); \ + } \ +} while (0) + +#define mem_clear(data, size) memset((data), 0, (size)) + +typedef enum dfd_rv_s { + DFD_RV_OK = 0, + DFD_RV_INIT_ERR = 1, + DFD_RV_SLOT_INVALID = 2, + DFD_RV_MODE_INVALID = 3, + DFD_RV_MODE_NOTSUPPORT = 4, + DFD_RV_TYPE_ERR = 5, + DFD_RV_DEV_NOTSUPPORT = 6, + DFD_RV_DEV_FAIL = 7, + DFD_RV_INDEX_INVALID = 8, + DFD_RV_NO_INTF = 9, + DFD_RV_NO_NODE = 10, + DFD_RV_NODE_FAIL = 11, +} dfd_rv_t; + +#define DFD_DEBUG_BUF_LEN (32) +#define DFD_DEBUGP_DEBUG_FILE "/sbin/.dfd_debugp_flag" +#define DFD_DEBUGPP_DEBUG_FILE "/sbin/.dfd_debugpp_flag" + +#define DFD_UTEST_MAX_PARA_NUM (4) +#define DFD_UTEST_TYPE_STRING_LEN (64) +#define DFD_UTEST_MATCH_STRING_LEN (64) +#define DFD_UTEST_HELP_STRING_LEN (256) +#define DFD_UTEST_INVALID_PARA (-1) +#define DFD_UTEST_BUFF_LEN (64) + +typedef enum dfd_fpga_cpld_flag_e { + DFD_CPLD_RW_FLAG = 0x00, + DFD_FPGA_RW_FLAG = 0x01, +} dfd_fpga_cpld_flag_t; + +typedef int (* dfd_utest_proc_fun)(int argc, char* argv[]); + +#define DFD_UTEST_ITEM_ALL \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_RD, i2c_rd, "i2c_rd [i2c_bus] [slave_addr] [offset] [len]", "i2c_rd [i2c_bus] [slave_addr] [offset] [len]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_WR, i2c_wr, "i2c_wr [i2c_bus] [slave_addr] [offset] [data0] ... [dataN]", "i2c_wr [i2c_bus] [slave_addr] [offset] [data0] ... [dataN]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_IO_RD, io_rd, "io_rd [offset] [len]", "io_rd [offset] [len]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_IO_WR, io_wr, "io_wr [offset] [data0]... [dataN]", "io_wr [offset] [data0]... [dataN]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYMEM_RD, phymem_rd, "phymem_rd [bit_width] [offset] [len]", "phymem_rd [bit_width] [offset] [len]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYMEM_WR, phymem_wr, "phymem_wr [bit_width] [offset] [data0]... [dataN]", "phymem_wr [bit_width] [offset] [data0]... [dataN]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_KMEM_RD, kmem_rd, "kmem_rd [bit_width] [offset] [len]", "kmem_rd [bit_width] [offset] [len]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_KMEM_WR, kmem_wr, "kmem_wr [bit_width][offset] [data0]... [dataN]", "kmem_wr [bit_width] [offset] [data0]... [dataN]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_FILE_WR, i2c_file_wr, "i2c_file_wr [i2c_bus] [slave_addr] [offset] [bpt] [filename]", "i2c_file_wr [i2c_bus] [slave_addr] [offset] [bpt] [filename]\nbpt:bytes per times") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_FILE_WR, sysfs_file_wr, "sysfs_file_wr [sysfs_loc] [offset] [filename] [per_wr_byte]", "sysfs_file_wr [sysfs_loc] [offset] [filename] [per_wr_byte]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_FILE_RD, sysfs_file_rd, "sysfs_file_rd [sysfs_loc] [offset] [len]", "sysfs_file_rd [sysfs_loc] [offset] [len]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_FILE_UPG, sysfs_file_upg, "sysfs_file_upg [sysfs_loc] [offset] [filename] [per_wr_byte]", "sysfs_file_upg [sysfs_loc] [offset] [filename] [per_wr_byte]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_GEN_RD, i2c_gen_rd, "i2c_gen_rd [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [len]", "i2c_gen_rd [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [len]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_GEN_WR, i2c_gen_wr, "i2c_gen_wr [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [data0]... [dataN]", "i2c_gen_wr [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [data0]... [dataN]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_MSR_RD, msr_rd, "msr_rd [cpu_index] [offset] [width]", "msr_rd [cpu_index] [offset] [width]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_DATA_WR, sysfs_data_wr, "sysfs_data_wr [sysfs_loc] [offset] [data0] ... [dataN]", "sysfs_data_wr [sysfs_loc] [offset] [data0] ... [dataN]]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYDEV_LIST, phydev_list, "phydev_list", "phydev_list") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYDEV_RD, phydev_rd, "phydev_rd phy_index reg_addr", "phydev_rd phy_index reg_addr") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYDEV_WR, phydev_wr, "phydev_wr phy_index reg_addr reg_data", "phydev_wr phy_index reg_addr reg_data") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_MDIODEV_LIST, mdiodev_list, "mdiodev_list", "mdiodev_list") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_MDIODEV_RD, mdiodev_rd, "mdiodev_rd mdio_index phyaddr reg_addr", "mdiodev_rd mdio_index phyaddr reg_addr") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_MDIODEV_WR, mdiodev_wr, "mdiodev_wr mdio_index phyaddr reg_addr reg_data", "mdiodev_wr mdio_index phyaddr reg_addr reg_data") \ + +#ifdef DFD_UTEST_ITEM +#undef DFD_UTEST_ITEM +#endif +#define DFD_UTEST_ITEM(_id, _type_str, _help_info, _help_info_detail) _id, +typedef enum dfd_utest_item_id_s { + DFD_UTEST_ITEM_ALL +} dfd_utest_item_id_t; + +typedef struct { + int utest_type; + char type_str[DFD_UTEST_TYPE_STRING_LEN]; + dfd_utest_proc_fun utest_func; + char help_info[DFD_UTEST_HELP_STRING_LEN]; + char help_info_detail[DFD_UTEST_HELP_STRING_LEN]; +} dfd_utest_t; + +void dfd_utest_cmd_main(int argc, char* argv[]); + +#ifdef DFD_UTEST_ITEM +#undef DFD_UTEST_ITEM +#endif +#define DFD_UTEST_ITEM(_id, _type_str, _help_info, _help_info_detail) int dfd_utest_##_type_str(int argc, char* argv[]); +DFD_UTEST_ITEM_ALL + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Makefile new file mode 100644 index 000000000000..1701b5f62114 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Makefile @@ -0,0 +1,18 @@ +top_srcdir:=$(shell pwd) +include $(top_srcdir)/Rules.mk + +firmware-y:= +firmware-y += fw_upgrade + +.PHONY: all +all: build + +.PHONY: build +build: $(firmware-y) +$(foreach dir,$(firmware-y),$(eval $(call compile_dirs,$(dir)))) + +.PHONY: rpmpkg +rpmpkg: +ifeq ("$(CONFIG_CPLD_UPGRADE_ISPVME)", "y") + #$(RPMPKG) $(install_cpld_dir) firmware-cpld-ispvme.spec git +endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Rules.mk b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Rules.mk new file mode 100644 index 000000000000..5fb5a09d34fd --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Rules.mk @@ -0,0 +1,42 @@ +CC ?= $(CROSS)gcc +AR ?= $(CROSS)ar +AS ?= $(CROSS)as +LD ?= $(CROSS)ld +STRIP ?= $(CROSS)strip + +install_root:=${top_srcdir}/images + +install_header_dir:=${install_root}/header +install_adir:=$(install_root)/lib +install_symbol_dir:=$(install_root)/symbol +symbol_files:=$(shell find $(EXPORT_SYMBOL) -name 'Module.symvers') +# +# symbol_files += $(shell find $(install_symbol_dir) -name 'Module.symvers') +# KBUILD_EXTRA_SYMBOLS += $(symbol_files) +# export KBUILD_EXTRA_SYMBOLS + +# top root: install_rootfs_dir +install_rootfs_dir:=$(install_root)/rootfs + +install_sodir:=$(install_rootfs_dir)/$(INSTALL_SODIR) + +install_usr_bin_dir:=$(install_rootfs_dir)/usr/bin +install_sbin_dir:=$(install_rootfs_dir)/sbin +install_etc_dir:=$(install_rootfs_dir)/etc + +export INSTALL_MOD_PATH:=$(ROOT) + +BUILD_CFLAGS:=$(CFLAGS) -I$(install_header_dir) +BUILD_LDFLAGS:=$(LDFLAGS) -L/$(install_sodir) -L/$(install_adir) + +define compile_dirs +.PHONY: $(1) +$(1): + @echo;echo "building $(1)..." + @$(MAKE) -C ${1} +endef + +compile.c = $(CC) $(BUILD_CFLAGS) -d -c -o $@ $< +%.o: %.c + $(compile.c) + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/Makefile new file mode 100644 index 000000000000..8b4bca739087 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/Makefile @@ -0,0 +1,39 @@ +include ../Rules.mk + +OBJ = fw_upgrade.o fw_upgrade_debug.o + +LIB += $(BUILD_CFALGS) $(BUILD_LDFLAGS) -lpthread +ifdef ENABLE_GCOV +ifeq ($(ENABLE_GCOV), y) +LIB += -fprofile-arcs +endif +endif # ENABLE_GCOV + +APP = fw_upgrade +BUILD_DIR = tmp +ELF_FILE = $(BUILD_DIR)/$(APP) +MAP_FILE = $(BUILD_DIR)/$(APP).map.sym +INCLUDE = -Iinclude +CFLAGS+=-Wall -W -g + +.PHONY: build +build:make-dir $(addprefix $(BUILD_DIR)/,$(OBJ)) + $(CC) -o $(ELF_FILE) $(addprefix $(BUILD_DIR)/,$(OBJ)) $(LINKFLAGS) $(LIB) + + cp -p $(ELF_FILE) $(common_out_put_dir) + +.PHONY: make-dir +make-dir: + @mkdir -p $(BUILD_DIR) + +$(BUILD_DIR)/%.o:%.c + $(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@ + +.PHONY: install +install: + echo "fw_upgrade install success." + cp -p $(ELF_FILE) $(common_out_put_dir) + +.PHONY: clean +clean: + rm -rf $(BUILD_DIR) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade.c b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade.c new file mode 100644 index 000000000000..2045608d5c3b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade.c @@ -0,0 +1,1632 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fw_upgrade.h" + +static flash_info_t flash_info[] = { + { + .flash_name = "M25L6433F", + .flash_size = M32, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = MX25L6433F, + .block_size = STEP_64, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "S25FL512S", + .flash_size = M64, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = S25FL512S, + .block_size = STEP_256, + .full_erase = 0, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "MX25l512", + .flash_size = M64, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = MX25l512, + .block_size = STEP_64, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "STM25P64", + .flash_size = M12, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = STM25P64, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "STM25P128", + .flash_size = M16, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = STM25P128, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "N25Q256", + .flash_size = M16, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = N25Q256, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "N25Q512", + .flash_size = M16, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = N25Q512, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "W25X16", + .flash_size = M3, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = W25X16, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "W25X64", + .flash_size = M12, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = W25X64, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "W25Q64BV", + .flash_size = M12, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = W25Q64BV, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "W25Q128BV", + .flash_size = M16, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = W25Q128BV, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "W25Q256FV", + .flash_size = M16, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = W25Q256FV, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "MX25L1605D", + .flash_size = M32, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = MX25L1605D, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "MX25L12805D", + .flash_size = M32, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = MX25L12805D, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "MX66L1G45G", + .flash_size = M128, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = MX66L1G45G, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "GD25Q256", + .flash_size = M16, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = GD25Q256, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, +}; + +static int debug_on; + +static void help(void) +{ + printf("------------------------------BMC Upgrade Tool--------------------------------\n"); + printf("Program Flash:\n"); + printf("\tfw_upgrade upgrade [file name] [chip select: 0 | 1 | 2] "); + printf("[erase type: full | block]\n"); + printf("\t[file name] if file is not located at /home/admin, path should be added\n"); + printf("\t[chip select] 0:master, 1:slave, 2:both\n"); + printf("\t[erase type] choose a way to erase chip, full erase would be faster\n"); + printf("Read BMC Reg:\n"); + printf("\tfw_upgrade rd [address] [length]\n"); + printf("\t[address(Hexadecimal)] register address of BMC\n"); + printf("\t[length(decimal)] length of read data, should be times of 4\n"); + + return; +} + +static int set_ioport_rw_access(void) +{ + + if ( iopl(3) < 0) { + printf("Can't get access to /dev/port \n"); + return -1; + } + + return 0; +} + +static int get_file_size(char *file_name) +{ + FILE * pFile; + int size; + + pFile = fopen(file_name,"rb"); + if (pFile == NULL) { + printf("Error opening file\n"); + return -1; + } + fseek (pFile, 0, SEEK_END); + size = ftell(pFile); + fclose (pFile); + return size; +} + +static uint8_t _read(uint16_t addr) +{ + return inb(addr); +} + +static void _write(uint16_t addr, uint8_t val) +{ + outb(val, addr); + + return; +} + +static void write_addr_port(uint8_t addr_val, uint16_t addr_port) +{ + _write(addr_port, addr_val); + + return; +} + +static void write_data_port(uint8_t val, uint16_t data_port) +{ + _write(data_port, val); + + return; +} + +static uint8_t read_data_port(uint16_t data_port) +{ + return _read(data_port); +} + +static void write_ilpc2ahb_addr(uint32_t addr) +{ + int i; + + for (i = 0; i < 4; i++) { + write_addr_port(SUPERIO_REG0 + i, LPC_ADDR_PORT); + write_data_port((addr >> (8 * (3 - i))) & MASK, LPC_DATA_PORT); + } + + return; +} + +static void write_ilpc2ahb_data(uint32_t data) +{ + int i; + + for (i = 0; i < 4; i++) { + write_addr_port(SUPERIO_REG4 + i, LPC_ADDR_PORT); + write_data_port((data >> (8 * (3 - i))) & MASK, LPC_DATA_PORT); + } + + return; +} + +static uint32_t read_ilpc2ahb_data(void) +{ + int i, tmp; + uint32_t res; + + res = 0; + for (i = 0; i < 4; i++) { + write_addr_port(SUPERIO_REG4 + i, LPC_ADDR_PORT); + tmp = read_data_port(LPC_DATA_PORT); + res |= (tmp << (8 * (3 - i))); + } + + return res; +} + +static void trigger_ilpc2ahb_read(void) +{ + write_addr_port(SUPERIO_FE, LPC_ADDR_PORT); + read_data_port(LPC_DATA_PORT); + + return; +} + +static void trigger_ilpc2ahb_write(void) +{ + write_addr_port(SUPERIO_FE, LPC_ADDR_PORT); + write_data_port(TOGGLE_WRITE, LPC_DATA_PORT); + + return; +} + +static uint32_t read_bmc_reg(uint32_t addr) +{ + uint32_t res; + + write_ilpc2ahb_addr(addr); + trigger_ilpc2ahb_read(); + res = read_ilpc2ahb_data(); + + return res; +} + +static void write_bmc_reg(uint32_t addr, uint32_t val) +{ + write_ilpc2ahb_addr(addr); + write_ilpc2ahb_data(val); + trigger_ilpc2ahb_write(); + + return; +} + +static uint32_t read_bmc_flash_data(void) +{ + uint32_t res; + + trigger_ilpc2ahb_read(); + res = read_ilpc2ahb_data(); + + return res; +} + +static void write_bmc_flash_data(uint32_t data) +{ + write_ilpc2ahb_data(data); + trigger_ilpc2ahb_write(); + + return; +} + +static void write_bmc_flash_addr(uint32_t addr) +{ + int i; + + for (i = 0; i < 4; i++) { + write_addr_port(SUPERIO_REG4 + i, LPC_ADDR_PORT); + write_data_port((addr >> (8 * i)) & MASK, LPC_DATA_PORT); + } + + trigger_ilpc2ahb_write(); + + return; +} + +static void enable_bytes(int byte) +{ + write_addr_port(SUPERIO_REG8, LPC_ADDR_PORT); + switch (byte) { + case BYTE1: + write_data_port(SUPERIO_A0 + BYTE1_VAL, LPC_DATA_PORT); + break; + case BYTE2: + write_data_port(SUPERIO_A0 + BYTE2_VAL, LPC_DATA_PORT); + break; + case BYTE4: + write_data_port(SUPERIO_A0 + BYTE4_VAL, LPC_DATA_PORT); + break; + default: + write_data_port(SUPERIO_A0 + BYTE_RESERVED, LPC_DATA_PORT); + break; + } + + return; +} + +static void pull_ce_down(flash_info_t* info) +{ + write_bmc_reg(info->ce_control_reg, USER_MODE_PULL_CE_DOWN); + + return; +} + +static void pull_ce_up(flash_info_t* info) +{ + write_bmc_reg(info->ce_control_reg, USER_MODE_PULL_CE_UP); + + return; +} + +static void send_cmd(uint32_t flash_base_addr, int cmd) +{ + write_ilpc2ahb_addr(flash_base_addr); + enable_bytes(1); + write_addr_port(SUPERIO_REG7, LPC_ADDR_PORT); + write_data_port(cmd & MASK, LPC_DATA_PORT); + trigger_ilpc2ahb_write(); + enable_bytes(4); + + return; +} + +static void send_cmd_to_flash(flash_info_t* info, int cmd) +{ + pull_ce_down(info); + send_cmd(info->flash_base_addr, cmd); + pull_ce_up(info); + + return; +} + +static void check_data_length(void) +{ + uint8_t tmp; + /* Data length check, 4 bytes */ + write_addr_port(SUPERIO_REG8, LPC_ADDR_PORT); + tmp = read_data_port(LPC_DATA_PORT); + if (tmp != SUPERIO_A2) { + write_data_port(SUPERIO_A2, LPC_DATA_PORT); + } + + return; +} + +static void enable_ilpc2ahb(void) +{ + /* Write 0xAA then write 0xA5 twice to enable super IO*/ + write_addr_port(DISABLE_LPC, LPC_ADDR_PORT); + write_addr_port(ENABLE_LPC, LPC_ADDR_PORT); + write_addr_port(ENABLE_LPC, LPC_ADDR_PORT); + + /* Enable iLPC2AHB */ + write_addr_port(SUPERIO_07, LPC_ADDR_PORT); + write_data_port(LPC_TO_AHB, LPC_DATA_PORT); + write_addr_port(SUPERIO_30, LPC_ADDR_PORT); + write_data_port(ENABLE_LPC_TO_AHB, LPC_DATA_PORT); + + /* Data length */ + check_data_length(); + + return; +} + +static void disable_ilpc2ahb(void) +{ + /* disable ilpc2ahb */ + write_addr_port(SUPERIO_30, LPC_ADDR_PORT); + write_data_port(DISABLE_LPC_TO_AHB, LPC_DATA_PORT); + /* disable super IO */ + write_addr_port(DISABLE_LPC, LPC_ADDR_PORT); + + return; +} + +/* Enable CPU */ +static void enable_cpu(void) +{ + /* unlock SCU register */ + write_bmc_reg(SCU_ADDR, UNLOCK_SCU_KEY); + /* enable ARM */ + write_bmc_reg(REBOOT_CPU_REGISTER, SET_BMC_CPU_BOOT); + /* lock SCU register */ + write_bmc_reg(SCU_ADDR, LOCK_SCU_KEY); + + return; +} + +/* diasble CPU */ +static void disable_cpu(void) +{ + uint32_t scu_hw_strap_val; + + /* unlock SCU register */ + write_bmc_reg(SCU_ADDR, UNLOCK_SCU_KEY); + /* disable ARM */ + scu_hw_strap_val = read_bmc_reg(HARDWARE_STRAP_REGISTER); + write_bmc_reg(HARDWARE_STRAP_REGISTER, scu_hw_strap_val |0x01); + /* lock SCU register */ + write_bmc_reg(SCU_ADDR, LOCK_SCU_KEY); + + return; +} + +static void enable_upgrade(void) +{ + + enable_ilpc2ahb(); + /* diasble CPU */ + disable_cpu(); + /* init CE control register */ + write_bmc_reg(CE0_CONTROL_REGISTER, 0); + write_bmc_reg(CE1_CONTROL_REGISTER, 0); + /* disable WDT2 */ + write_bmc_reg(WATCHDOG2_CONTROL, DISABLE_WATCHDOG); + + return; +} + +static void disable_upgrade(void) +{ + enable_cpu(); + dbg_print(debug_on, "DEBUG 0x%x\n", read_bmc_reg(HARDWARE_STRAP_REGISTER)); + disable_ilpc2ahb(); + + return; +} + +static void watchdog_status_debug(void) +{ + uint32_t watchdog_reg; + + /* Watchdog Control Register */ + watchdog_reg = read_bmc_reg(WATCHDOG2_CONTROL); + dbg_print(debug_on,"Watchdog Control Register: 0x%x\n", watchdog_reg); + dbg_print(debug_on,"Watchdog Enable Signal: 0x%x\n", watchdog_reg & BIT1); + dbg_print(debug_on,"Watchdog Reset SyS En: 0x%x\n", (watchdog_reg & BIT2) >> 1); + dbg_print(debug_on,"Watchdog Reset Mode: 0x%x\n", (watchdog_reg & (BIT6 | BIT7)) >> 5); + switch (watchdog_reg & (BIT6 | BIT7)) { + case SOC_SYS: + dbg_print(debug_on,"\tReset Mode En: SoC System\n"); + break; + case FULL_CHIP: + dbg_print(debug_on,"\tReset Mode En: Full Chip\n"); + break; + case ARM_CPU: + dbg_print(debug_on,"\tReset Mode En: ARM Cpu\n"); + break; + default: + break; + } + + /* Watchdog Timeout Status Register */ + watchdog_reg = read_bmc_reg(WATCHDOG2_TSR); + dbg_print(debug_on,"Watchdog Timeout Occur: 0x%x\n", watchdog_reg & BIT1); + dbg_print(debug_on,"Watchdog Boot from: CD%d\n", watchdog_reg & BIT2); + dbg_print(debug_on,"Watchdog Interrupt Occur: 0x%x\n", watchdog_reg & BIT3); + + return; +} + +/* CE Type Setting Register */ +static void ce_type_setting_debug(void) +{ + uint32_t fmc_reg; + + fmc_reg = read_bmc_reg(FMC_CE_TYPE_SETTING_REG); + if ((fmc_reg & CE0_SPI_TYPE) == SPI) { + dbg_print(debug_on,"CE0 Type Seeting: 0x%x, Type: SPI\n", fmc_reg & CE0_SPI_TYPE); + } else { + dbg_print(debug_on,"CE0 Type Seeting: 0x%x, Type: Unknown\n", fmc_reg & CE0_SPI_TYPE); + } + if (((fmc_reg & CE1_SPI_TYPE) >> BIT2) == SPI) { + dbg_print(debug_on,"CE1 Type Seeting: 0x%x, Type: SPI\n", (fmc_reg & CE1_SPI_TYPE) >> BIT2); + } else { + dbg_print(debug_on,"CE1 Type Seeting: 0x%x, Type: Unknown\n", (fmc_reg & CE1_SPI_TYPE) >> BIT2); + } + + return; +} +/* CE Control Register */ +static void ce_control_debug(void) +{ + uint32_t fmc_reg; + + fmc_reg = read_bmc_reg(CE_CONTROL_REGISTER); + dbg_print(debug_on,"CE0 Address Mode: 0x%x, Mode: %d Bytes\n", + fmc_reg & BIT1, (fmc_reg & BIT1) + 3); + dbg_print(debug_on,"CE1 Address Mode: 0x%x, Mode: %d Bytes\n", + (fmc_reg & BIT2) >> 1, ((fmc_reg & BIT2) >> 1) + 3); + + return; +} + +/* Interrupt Control & Status Register */ +static void irq_control_status_debug(void) +{ + uint32_t fmc_reg; + + fmc_reg = read_bmc_reg(INR_STATUS_CONTROL_REGISTER); + dbg_print(debug_on,"SPI Write Address Protected Interrupt EN: 0x%x\n", fmc_reg & BIT2); + dbg_print(debug_on,"SPI Command Abort Interrupt EN: 0x%x\n", fmc_reg & BIT3); + dbg_print(debug_on,"SPI Write Address Protected Status: 0x%x, Status: %s\n", + RIGHT_SHIFT_8(fmc_reg) & BIT2, (RIGHT_SHIFT_8(fmc_reg) & BIT2) == BIT2 ? "Occur" : "Normal"); + dbg_print(debug_on,"SPI Command Abort Status: 0x%x, Status: %s\n", + RIGHT_SHIFT_8(fmc_reg) & BIT3, (RIGHT_SHIFT_8(fmc_reg) & BIT3) == BIT3 ? "Occur" : "Normal"); + /*Clear Abnormal Status*/ + if ((RIGHT_SHIFT_8(fmc_reg) & BIT3) || (RIGHT_SHIFT_8(fmc_reg) & BIT2)) { + write_bmc_reg(INR_STATUS_CONTROL_REGISTER, CLEAR_INR_STATUS_CONTROL); + } + + return; +} + +/* Command Control Register */ +static void command_control_debug(void) +{ + uint32_t fmc_reg; + + fmc_reg = read_bmc_reg(COMMAND_CONTROL_REGISTER); + dbg_print(debug_on,"Data Byte Line 0: %s\n", ((fmc_reg & BIT4) != 0) ? "Disable" : "Enable"); + dbg_print(debug_on,"Data Byte Line 1: %s\n", ((fmc_reg & BIT3) != 0) ? "Disable" : "Enable"); + dbg_print(debug_on,"Data Byte Line 2: %s\n", ((fmc_reg & BIT2) != 0) ? "Disable" : "Enable"); + dbg_print(debug_on,"Data Byte Line 3: %s\n", ((fmc_reg & BIT1) != 0) ? "Disable" : "Enable"); + + dbg_print(debug_on,"Address Byte Line 0: %s\n", ((fmc_reg & BIT8) != 0) ? "Disable" : "Enable"); + dbg_print(debug_on,"Address Byte Line 1: %s\n", ((fmc_reg & BIT7) != 0) ? "Disable" : "Enable"); + dbg_print(debug_on,"Address Byte Line 2: %s\n", ((fmc_reg & BIT6) != 0) ? "Disable" : "Enable"); + dbg_print(debug_on,"Address Byte Line 3: %s\n", ((fmc_reg & BIT5) != 0) ? "Disable" : "Enable"); + + return; +} + +static void ce_control_reg_debug(void) +{ + uint32_t fmc_reg; + + /* CE0 Control Register */ + fmc_reg = read_bmc_reg(CE0_CONTROL_REGISTER); + switch (fmc_reg & (BIT1 | BIT2)){ + case NORMAL_READ: + dbg_print(debug_on,"CE0 Command Mode: Normal Read\n"); + break; + case READ_MODE: + dbg_print(debug_on,"CE0 Command Mode: Read Command\n"); + break; + case WRITE_MODE: + dbg_print(debug_on,"CE0 Command Mode: Write Command\n"); + break; + case USER_MODE: + dbg_print(debug_on,"CE0 Command Mode: User Mode\n"); + break; + default: + break; + } + switch((RIGHT_SHIFT_24(fmc_reg) & (BIT5 | BIT6 | BIT7))){ + case 0: + dbg_print(debug_on,"CE0 IO Mode: Single Mode\n"); + break; + case 2: + case 3: + dbg_print(debug_on,"CE0 IO Mode: Dual Mode\n"); + break; + default: + break; + } + + dbg_print(debug_on,"CE0 Inactive Pulse Width: %d HCLK\n", + DEFAULT_WIDTH - (RIGHT_SHIFT_24(fmc_reg) & (BIT1 | BIT2 | BIT3 | BIT4))); + dbg_print(debug_on,"CE0 Data Input Mode: %s Mode\n", (fmc_reg & BIT4) == 0 ? "Single" : "Dual"); + dbg_print(debug_on,"CE0 MSB | LSB: %s First\n", (fmc_reg & BIT6) == 0 ? "MSB" : "LSB"); + + /* CE1 Control Register */ + fmc_reg = read_bmc_reg(CE1_CONTROL_REGISTER); + switch (fmc_reg & (BIT1 | BIT2)){ + case NORMAL_READ: + dbg_print(debug_on,"CE1 Command Mode: Normal Read\n"); + break; + case READ_MODE: + dbg_print(debug_on,"CE1 Command Mode: Read Command\n"); + break; + case WRITE_MODE: + dbg_print(debug_on,"CE1 Command Mode: Write Command\n"); + break; + case USER_MODE: + dbg_print(debug_on,"CE1 Command Mode: User Mode\n"); + break; + default: + break; + } + switch((RIGHT_SHIFT_24(fmc_reg) & (BIT5 | BIT6 | BIT7))){ + case 0: + dbg_print(debug_on,"CE1 IO Mode: Single Mode\n"); + break; + case 2: + case 3: + dbg_print(debug_on,"CE1 IO Mode: Dual Mode\n"); + break; + default: + break; + } + + dbg_print(debug_on,"CE1 Inactive Pulse Width: %d HCLK\n", + DEFAULT_WIDTH - (RIGHT_SHIFT_24(fmc_reg) & (BIT1 | BIT2 | BIT3 | BIT4))); + dbg_print(debug_on,"CE1 Data Input Mode: %s Mode\n", (fmc_reg & BIT4) == 0 ? "Single" : "Dual"); + dbg_print(debug_on,"CE1 MSB | LSB: %s First\n", (fmc_reg & BIT6) == 0 ? "MSB" : "LSB"); + + return; +} + +static void fmc_debug(void) +{ + ce_type_setting_debug(); + ce_control_debug(); + irq_control_status_debug(); + command_control_debug(); + ce_control_reg_debug(); + + return; +} + +/* Enable WatchDog to reset BMC*/ +static void enable_watchdog(int cs) +{ + uint32_t enable_watch_cmd; + + enable_watch_cmd = (cs == CE0) ? ENABLE_WATCHDOG : ENABLE_WATCHDOG | BOOT_DEFAULT_MASK; + write_bmc_reg(WATCHDOG2_CLEAR_STATUS, CLEAR_WATCHDOG_STATUS); + write_bmc_reg(WATCHDOG2_RESET_FUN_MASK, WATCHDOG_GATEMASK); + write_bmc_reg(WATCHDOG2_RELOAD_VALUE, WATCHDOG_NEW_COUNT); + write_bmc_reg(WATCHDOG2_COUNTER_RST, WATCHDOG_RELOAD_COUNTER); + write_bmc_reg(WATCHDOG2_CONTROL, enable_watch_cmd); + + return; +} + +static void bmc_reboot(int cs) +{ + enable_watchdog(cs); + watchdog_status_debug(); + disable_upgrade(); + printf("Upgrade-Complete, BMC rebooting...\n"); + + return; +} + +static int get_current_bmc(void) +{ + return (read_bmc_reg(WATCHDOG2_TSR) & 0x02) >> 1; +} + +static void get_flash_base_and_ce_ctrl(int current_bmc, int cs, uint32_t *flash_base_addr, uint32_t *ce_ctrl_addr) +{ + uint32_t ce0_addr_range_reg_val, ce0_decode_addr; + uint32_t ce1_addr_range_reg_val, ce1_decode_addr; + + ce0_addr_range_reg_val = read_bmc_reg(CE0_ADDRESS_RANGE_REGISTER); + ce0_decode_addr = SEGMENT_ADDR_START(ce0_addr_range_reg_val); + ce1_addr_range_reg_val = read_bmc_reg(CE1_ADDRESS_RANGE_REGISTER); + ce1_decode_addr = SEGMENT_ADDR_START(ce1_addr_range_reg_val); + dbg_print(debug_on,"CE0 addr decode range reg value:0x%08x, decode addr:0x%08x.\n", + ce0_addr_range_reg_val, ce0_decode_addr); + dbg_print(debug_on,"CE1 addr decode range reg value:0x%08x, decode addr:0x%08x.\n", + ce1_addr_range_reg_val, ce1_decode_addr); + + if (((current_bmc == CURRENT_MASTER) && (cs ==CE0)) || ((current_bmc == CURRENT_SLAVE) && (cs ==CE1))) { + *ce_ctrl_addr = CE0_CONTROL_REGISTER; + *flash_base_addr = ce0_decode_addr; + } else { + *ce_ctrl_addr = CE1_CONTROL_REGISTER; + *flash_base_addr = ce1_decode_addr; + } + + return; +} + +static int get_flash_id(uint32_t flash_base_addr, uint32_t ce_ctrl_addr) +{ + uint32_t origin_flash_id, flash_id; + + write_bmc_reg(ce_ctrl_addr, USER_MODE_PULL_CE_DOWN); + send_cmd(flash_base_addr, READID); + origin_flash_id = read_bmc_flash_data(); + write_bmc_reg(ce_ctrl_addr, USER_MODE_PULL_CE_UP); + flash_id = origin_flash_id & 0xFFFFFF; + dbg_print(debug_on,"origin flash id:0x%x, flash id:0x%x\n", origin_flash_id, flash_id); + + return flash_id; +} + +static uint8_t get_flash_status(flash_info_t* info) +{ + uint8_t flash_status; + + pull_ce_down(info); + + send_cmd(info->flash_base_addr, READ_FLASH_STATUS); + + flash_status = read_bmc_flash_data() & MASK; + pull_ce_up(info); + + dbg_print(debug_on,"get_flash_status:0x%x\n", flash_status); + return flash_status; +} + +static int check_flash_write_enable(flash_info_t* info) +{ + uint8_t flash_status; + int i, count; + + count = FLASH_WEL_TIMEOUT / FLASH_WEL_SLEEP_TIME; + for (i = 0; i <= count; i++) { + flash_status = get_flash_status(info); + if ((flash_status & FLASH_WRITE_ENABLE_MASK) != FLASH_WRITE_ENABLE_MASK) { + usleep(FLASH_WEL_SLEEP_TIME); + } else { + dbg_print(debug_on,"Check flash WEL success, RDSR:0x%x\n", flash_status); + return 0; + } + } + printf("Check flash WEL timeout, RDSR:0x%x\n", flash_status); + return -1; +} + +static int check_flash_write_process(flash_info_t* info, int timeout, int sleep_time) +{ + int i, count; + uint8_t flash_status; + + count = timeout / sleep_time; + for (i = 0; i <= count; i++) { + flash_status = get_flash_status(info); + if ((flash_status & FLASH_WIP_MASK) != 0) { + usleep(sleep_time); + } else { + dbg_print(debug_on,"Check flash WIP success, RDSR:0x%x\n", flash_status); + return 0; + } + } + printf("Check flash WIP timeout, RDSR:0x%x.\n", flash_status); + return -1; +} + +static int flash_write_enable(flash_info_t* info) +{ + int ret; + + send_cmd_to_flash(info, WRITE_ENABLE_FLASH); + ret = check_flash_write_enable(info); + if (ret < 0) { + return -1; + } + return 0; +} + +static void send_block_erase_cmd(flash_info_t* info, uint32_t block_addr) +{ + pull_ce_down(info); + send_cmd(info->flash_base_addr, info->erase_block_command); + write_bmc_flash_addr(block_addr); /* Erase Block addr */ + pull_ce_up(info); + + return; +} + +static void send_chip_erase_cmd(flash_info_t* info) +{ + send_cmd_to_flash(info, CHIP_ERASE_FLASH); + + return; +} + +static int write_bmc_flash_page(flash_info_t* info, uint32_t page_addr, uint8_t *p, int len) +{ + int pos; + + if (len % 4) { + printf("Page size %d invalid.\n", len); + return -1; + } + + pos = 0; + pull_ce_down(info); + send_cmd(info->flash_base_addr, info->page_program); + write_bmc_flash_addr(page_addr); /* page address */ + while (len) { + write_bmc_flash_data((*(uint32_t *)(p + pos))); + pos += 4; + len -= 4; + } + pull_ce_up(info); + + return 0; +} + +static int erase_chip_full(flash_info_t* info) +{ + time_t timep; + int ret; + + if (info->full_erase == 0) { + printf("Flash not support full erase function.\n"); + return -1; + } + + ret = flash_write_enable(info); + if(ret < 0) { + printf("Chip erase, enable flash write error.\n"); + return -1; + } + + time(&timep); + printf("Full chip erasing, please wait...\n"); + dbg_print(debug_on,"Erase Start-%s\n",asctime(gmtime(&timep))); + send_chip_erase_cmd(info); + ret = check_flash_write_process(info, CHIP_ERASE_TIMEOUT, CHIP_ERASE_SLEEP_TIME); + if (ret < 0) { + printf("Chip erase timeout.\n"); + return -1; + } + time(&timep); + dbg_print(debug_on,"Erase Finish-%s\n",asctime(gmtime(&timep))); + printf("Erase Finish\n"); + printf("=========================================\n"); + return 0; +} + +static int erase_chip_block(flash_info_t* info) +{ + uint32_t block_addr, end_addr; + time_t timep; + int ret; + + printf("Block erasing...\n"); + time (&timep); + dbg_print(debug_on,"Erase-Start-%s\n", asctime(gmtime(&timep))); + end_addr = info->flash_base_addr + info->flash_size; + block_addr = info->flash_base_addr; + while (1) { + /* Enable write */ + ret = flash_write_enable(info); + if(ret < 0) { + printf("Block erase, enable flash write error, block addr:0x%x\n", block_addr); + return -1; + } + + send_block_erase_cmd(info, block_addr); + /* Erase Block(64KB) MAX time 650ms*/ + ret = check_flash_write_process(info, BLOCK_ERASE_TIMEOUT, BLOCK_ERASE_SLEEP_TIME); + if (ret < 0) { + printf("Block erase, check write status error, block addr:0x%x\n", block_addr); + return -1; + } + printf("\r0x%x", block_addr); + fflush(stdout); + if (block_addr >= end_addr) { + time(&timep); + printf("\r\nErase Finish\n"); + printf("=========================================\n"); + dbg_print(debug_on,"\nEnd-Earse-%s\n",asctime(gmtime(&timep))); + break; + } + block_addr += info->block_size; + } + return 0; +} + +static int program_chip(uint32_t file_size, uint8_t *p, flash_info_t* info) +{ + time_t timep; + uint32_t page_addr, end_addr; + int ret, page_size; + + page_addr = info->flash_base_addr; + page_size = info->page_size; + end_addr = file_size + info->flash_base_addr; + time (&timep); + printf("Programming...\n"); + dbg_print(debug_on,"Program Start-%s\n",asctime(gmtime(&timep))); + /* Debug info */ + fmc_debug(); + while (1) { + /* Write enable */ + ret = flash_write_enable(info); + if(ret < 0) { + printf("Page program, enable flash write error, page addr:0x%x\n", page_addr); + return -1; + } + ret = write_bmc_flash_page(info, page_addr, p, page_size); + if (ret < 0) { + printf("Page program, write bmc flash page error, page addr:0x%x\n", page_addr); + return -1; + } + /* page program MAX time 1.5ms */ + ret = check_flash_write_process(info, PAGE_PROGRAM_TIMEOUT, PAGE_PROGRAM_SLEEP_TIME); + if (ret < 0) { + printf("Page program, check write status error, page addr:0x%x\n", page_addr); + return -1; + } + page_addr += page_size; + p += page_size; + if ((page_addr % 0x10000) == 0) { + printf("\r0x%x", page_addr); + fflush(stdout); + } + + if (page_addr >= end_addr) { + printf("\nProgram Finish\n"); + printf("=========================================\n"); + time(&timep); + dbg_print(debug_on,"\nProgram-End-%s\n",asctime(gmtime(&timep))); + break; + } + } /* End of while (1) */ + return 0; +} + +static int check_chip(uint32_t file_size, uint8_t *p, flash_info_t* info) +{ + time_t timep; + uint32_t offset_addr, rd_val, end_addr; + int pos; + + offset_addr = info->flash_base_addr; + end_addr = file_size + info->flash_base_addr; + pos=0; + /* Checking */ + time(&timep); + printf("Checking...\n"); + dbg_print(debug_on,"Checking-Start-%s\n",asctime(gmtime(&timep))); + + pull_ce_down(info); + send_cmd(info->flash_base_addr, COMMON_FLASH_READ); + write_bmc_flash_addr(info->flash_base_addr); + while (1) { + if (offset_addr >= end_addr) { + break; + } + rd_val = read_bmc_flash_data(); + if (rd_val != (*(uint32_t *)(p + pos))) { + printf("Check Error at 0x%08x\n", offset_addr); + printf("READ:0x%08x VALUE:0x%08x\n", rd_val, (*(uint32_t *)(p + pos))); + pull_ce_up(info); + return -1; + } + if ((offset_addr % 0x10000) == 0) { + printf("\r0x%x ", offset_addr); + fflush(stdout); + } + offset_addr += 4; + pos += 4; + } + pull_ce_up(info); + printf("\r\nFlash Checked\n"); + printf("=========================================\n"); + time(&timep); + dbg_print(debug_on,"Checking-End-%s\n",asctime(gmtime(&timep))); + return 0; +} + +flash_info_t* get_flash_info(int current_bmc, int cs) +{ + int i, size; + uint32_t flash_base_addr, ce_ctrl_addr, flash_id; + + get_flash_base_and_ce_ctrl(current_bmc, cs, &flash_base_addr, &ce_ctrl_addr); + + size = (sizeof(flash_info) / sizeof((flash_info)[0])); + + flash_id = get_flash_id(flash_base_addr, ce_ctrl_addr); + for (i = 0; i < size; i++) { + if (flash_info[i].flash_id == flash_id) { + flash_info[i].flash_base_addr = flash_base_addr; + flash_info[i].ce_control_reg = ce_ctrl_addr; + flash_info[i].cs = cs; + return &flash_info[i]; + } + } + printf("Cannot get flash info, cs:%d, flash base addr:0x%x, ce control addr:0x%x, flash_id:0x%x.\n", + cs, flash_base_addr, ce_ctrl_addr, flash_id); + return NULL; +} + +static void init_flash(flash_info_t* info) +{ + send_cmd_to_flash(info, RSTEN); + send_cmd_to_flash(info, RST); + send_cmd_to_flash(info, EXIT_OTP); + send_cmd_to_flash(info, ENABLE_BYTE4); + + return; +} + +static int upgrade_bmc_core(char *file_name, int erase_type, flash_info_t* info) +{ + int file_size, fp, ret; + uint8_t *p; + + file_size = get_file_size(file_name); + if (file_size < 0) { + printf("file size %d Error\n", file_size); + return -1; + } + + fp = open(file_name, O_RDWR); + if (fp < 0) { + printf("Cannot open %s.\n", file_name); + return -1; + } + + p = mmap(NULL, file_size, PROT_READ, MAP_SHARED, fp, 0); + if (p == MAP_FAILED) { + printf("Could not mmap %s, error(%s).\n", file_name, strerror(errno)); + close(fp); + return -1; + } + + printf("* CE%d FLASH TYPE: SPI FLASH\n", info->cs); + printf("* FLASH NAME: %s\n", info->flash_name); + printf("* File Size:%d, 0x%x\n", file_size, file_size); + printf("=========================================\n"); + + /* Select erase type */ + switch (erase_type) { + case FULL_ERASE: + ret = erase_chip_full(info); + break; + case BLOCK_ERASE: + ret = erase_chip_block(info); + break; + default: + printf("Unsupport earse type:%d\n", erase_type); + goto exit; + break; + } + + if (ret < 0) { + printf("Erase Chip Error\n"); + goto exit; + } + + /* Program the flash */ + ret = program_chip(file_size, p, info); + if(ret < 0) { + printf("Program Chip Error\n"); + goto exit; + } + /* Check */ + ret = check_chip(file_size, p, info); + if(ret < 0) { + printf("Check Chip Error\n"); + goto exit; + } + + munmap(p, file_size); + close(fp); + return 0; +exit: + munmap(p, file_size); + close(fp); + return -1; +} + +static int upgrade_bmc_flash(char *filename, int current_bmc, int cs, int erase_type) +{ + int ret; + flash_info_t* info; + + info = get_flash_info(current_bmc, cs); + if(info == NULL) { + return -1; + } + + init_flash(info); + + ret = upgrade_bmc_core(filename, erase_type, info); + + return ret; +} + +static int upgrade_both_flash(char *filename, int erase_type) +{ + int ret, current_bmc; + + enable_upgrade(); + + current_bmc = get_current_bmc(); + if (current_bmc == CURRENT_MASTER) { + printf("* Current Bmc Default Boot: CE0\n"); + } else { + printf("* Current Bmc Default Boot: CE1\n"); + } + + ret = upgrade_bmc_flash(filename, current_bmc, CE0, erase_type); + if (ret < 0) { + printf("Upgrade master bmc flash failed, stop upgrade.\n"); + goto err; + } + printf("Upgrade master bmc flash success.\n"); + + ret = upgrade_bmc_flash(filename, current_bmc, CE1, erase_type); + if (ret < 0) { + printf("Upgrade slave bmc flash failed.\n"); + goto err; + } + printf("Upgrade slave bmc flash success.\n"); + + bmc_reboot(CE0); + return 0; +err: + disable_upgrade(); + return -1; +} + +static int upgrade_single_flash(char *filename, int cs, int erase_type) +{ + int ret, current_bmc; + + enable_upgrade(); + + current_bmc = get_current_bmc(); + if (current_bmc == CURRENT_MASTER) { + printf("* Current Bmc Default Boot: CE0\n"); + } else { + printf("* Current Bmc Default Boot: CE1\n"); + } + + ret = upgrade_bmc_flash(filename, current_bmc, cs, erase_type); + if (ret < 0) { + printf("Upgrade %s bmc flash failed.\n", cs == 0 ? "master":"slave"); + goto err; + } + printf("Upgrade %s bmc flash success.\n", cs == 0 ? "master":"slave"); + + bmc_reboot(cs); + return 0; +err: + disable_upgrade(); + return -1; +} + +static int upgrade_bmc(char *filename, int cs, int erase_type) +{ + int ret; + + if (access(filename, F_OK) < 0) { + printf("Can't find file\n"); + help(); + return -1; + } + + ret = set_ioport_rw_access(); + if (ret < 0) { + printf("IO ERROR\n"); + return -1; + } + + switch(cs) { + /* Single */ + case CE0: + case CE1: + ret = upgrade_single_flash(filename, cs, erase_type); + break; + /* Both */ + case BOTHFLASH: + ret = upgrade_both_flash(filename, erase_type); + break; + default: + ret = -1; + printf("Unsupport cs:%d\n", cs); + break; + } + + return ret; +} + +static int read_single_bmc_flash(flash_info_t* info, uint32_t start_addr, int read_size, int is_print) +{ + uint32_t res, flash_start_addr, flash_end_addr; + char filename[MAX_FILENAME_LENGTH]; + int fd, ret; + + flash_start_addr = info->flash_base_addr + start_addr; + flash_end_addr = flash_start_addr + read_size; + ret = 0; + fd = 0; + if (!is_print) { + mem_clear(filename, MAX_FILENAME_LENGTH); + snprintf(filename, MAX_FILENAME_LENGTH, "/tmp/image-bmc%d", info->cs); + fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRWXG|S_IRWXU|S_IRWXO); + if (fd < 0) { + printf("open file %s fail(err:%d)!\r\n", filename, errno); + return -1; + } + } + + printf("* CE%d FLASH TYPE: SPI FLASH\n", info->cs); + printf("* FLASH NAME: %s\n", info->flash_name); + printf("* Read flash addr:0x%x, size:0x%x\n", flash_start_addr, read_size); + printf("=========================================\n"); + printf("Reading...\n"); + + pull_ce_down(info); + send_cmd(info->flash_base_addr, COMMON_FLASH_READ); + write_bmc_flash_addr(flash_start_addr); + while (1) { + if (flash_start_addr >= flash_end_addr) { + break; + } + res = read_bmc_flash_data(); + if (is_print) { + printf("addr:0x%08x, val:0x%08x\n", flash_start_addr, res); + } else { + ret = write(fd, &res, sizeof(res)); + if (ret < 0) { + printf("write failed (errno: %d).\n", errno); + ret = -1; + goto exit; + } + } + if (((flash_start_addr % 0x10000) == 0) && (!is_print)) { + printf("\r0x%x ", flash_start_addr); + fflush(stdout); + } + flash_start_addr += 4; + } + printf("\r\nRead Finish\n"); + printf("=========================================\n"); +exit: + pull_ce_up(info); + if (fd > 0) { + close(fd); + } + return ret; +} + +static int read_bmc_flash(int cs, uint32_t start_addr, int read_size, int is_print) +{ + int ret, current_bmc; + flash_info_t* info; + + ret = set_ioport_rw_access(); + if (ret < 0) { + printf("IO ERROR\n"); + return -1; + } + + enable_upgrade(); + + current_bmc = get_current_bmc(); + if (current_bmc == CURRENT_MASTER) { + printf("* Current Bmc Default Boot: CE0\n"); + } else { + printf("* Current Bmc Default Boot: CE1\n"); + } + + info = get_flash_info(current_bmc, cs); + if(info == NULL) { + goto err; + } + + if (start_addr >= info->flash_size) { + printf("start_addr 0x%x out of range.\n", start_addr); + goto err; + } + + if ((start_addr + read_size) > info->flash_size) { + printf("read size %d exceed flash size.\n", read_size); + read_size = info->flash_size - start_addr; + } + + init_flash(info); + + ret = read_single_bmc_flash(info, start_addr, read_size, is_print); + if (ret < 0) { + printf("Read %s bmc flash failed.\n", cs == 0 ? "master" : "slave"); + goto err; + } + disable_upgrade(); + return 0; +err: + disable_upgrade(); + return -1; +} + +static int read_bmc_reg_main(int argc, char* argv[]) +{ + uint32_t start_addr, read_val; + int read_size, ret; + char *stopstring; + + if (argc != 4) { + printf("Input invalid.\n"); + help(); + return -1; + } + + start_addr = strtoul(argv[2], &stopstring, 16); + read_size = strtol(argv[3], &stopstring, 10); + + if (read_size <= 0) { + printf("read length %d invalid\n", read_size); + return -1; + } + + if (((start_addr % 4) != 0) || ((read_size % 4) != 0)) { + printf("Params invalid, start_addr:0x%08x, read_size:%d\n", start_addr, read_size); + printf("Please input address/length times of 4\n"); + return -1; + } + + ret = set_ioport_rw_access(); + if (ret < 0) { + printf("IO ERROR\n"); + return -1; + } + + enable_ilpc2ahb(); + + printf("read bcm reg, start_addr:0x%08x, read length:%d\n", start_addr, read_size); + printf("===Addr=== | ===Cont===\n"); + while (read_size) { + read_val = read_bmc_reg(start_addr); + printf("0x%08x | 0x%08x\n", start_addr, read_val); + start_addr += 4; + read_size -= 4; + } + + disable_ilpc2ahb(); + return 0; +} + +static int write_bmc_reg_main(int argc, char* argv[]) +{ + uint32_t addr, wr_val; + int ret; + char *stopstring; + + if (argc != 4) { + printf("Input invalid.\n"); + help(); + return -1; + } + + addr = strtoul(argv[2], &stopstring, 16); + wr_val = strtoul(argv[3], &stopstring, 16); + + if (((addr & MASK_BYTE) != REGISTER_HEAD) || ((addr % 4) != 0)) { + printf("Address[0x%08x] invalid, address should be register address and times of 4.\n", addr); + return -1; + } + + ret = set_ioport_rw_access(); + if (ret < 0) { + printf("IO ERROR\n"); + return -1; + } + + printf("write bcm reg, addr:0x%08x, val:0x%08x\n", addr, wr_val); + + enable_ilpc2ahb(); + write_bmc_reg(addr, wr_val); + disable_ilpc2ahb(); + + return 0; +} + +static int get_fmc_info_main(void) +{ + int ret; + + ret = set_ioport_rw_access(); + if (ret < 0) { + printf("IO ERROR\n"); + return -1; + } + + enable_ilpc2ahb(); + + debug_on = 3; + fmc_debug(); + debug_on = 0; + + disable_ilpc2ahb(); + return 0; +} + +static int program_flash_main(int argc, char* argv[]) +{ + int cs, erase_way, ret; + char *stopstring; + char tmp[128]; + + if (argc != 5) { + printf("Input invalid.\n"); + help(); + return -1; + } + + cs = strtol(argv[3], &stopstring, 10); + if ((strlen(stopstring) != 0) || cs < 0 || cs > 2) { + snprintf(tmp, sizeof(tmp), "%s", argv[3]); + printf("Incorrect chip select %s\n", tmp); + help(); + return -1; + } + + if (strcmp(argv[4], "full") == 0) { + erase_way = FULL_ERASE; + } else if (strcmp(argv[4], "block") == 0) { + erase_way = BLOCK_ERASE; + } else { + snprintf(tmp, sizeof(tmp), "%s", argv[4]); + printf("Incorrect erase type %s\n", tmp); + help(); + return -1; + } + + printf("============BMC Upgrade Tool=============\n"); + ret = upgrade_bmc(argv[2], cs, erase_way); + return ret; +} + +static int read_bmc_flash_main(int argc, char* argv[]) +{ + int cs, ret, read_size, is_print; + uint32_t start_addr; + char *stopstring; + char tmp[128]; + + if (argc != 6) { + printf("Input invalid.\n"); + help(); + return -1; + } + + cs = strtol(argv[2], &stopstring, 10); + if ((strlen(stopstring) != 0) || cs < 0 || cs > 1) { + snprintf(tmp, sizeof(tmp), "%s", argv[2]); + printf("Incorrect chip select %s\n", tmp); + help(); + return -1; + } + + start_addr = strtoul(argv[3], &stopstring, 16); + read_size = strtol(argv[4], &stopstring, 10); + + if (read_size <= 0) { + printf("read length %d invalid\n", read_size); + return -1; + } + + if (((start_addr % 4) != 0) || ((read_size % 4) != 0)) { + printf("Params invalid, start_addr:0x%08x, read_size:%d\n", start_addr, read_size); + printf("Please input address/length times of 4\n"); + return -1; + } + + if (strcmp(argv[5], "print") == 0) { + is_print = 1; + } else { + is_print = 0; + } + + printf("============READ BMC FLASH=============\n"); + ret = read_bmc_flash(cs, start_addr, read_size, is_print); + return ret; +} + +int main(int argc, char *argv[]) +{ + int ret; + + debug_on = fw_upgrade_debug(); + + if (argc < 2) { + help(); + return -1; + } + + if (argc == 2) { + if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { + help(); + return 0; + } + } + + if (strcmp(argv[1], "rd") == 0) { + ret = read_bmc_reg_main(argc, argv); + if (ret < 0) { + printf("Read Failed\n"); + } + return ret; + } + + if (strcmp(argv[1], "wr") == 0 && debug_on == 3) { + ret = write_bmc_reg_main(argc, argv); + if (ret < 0) { + printf("Write Failed\n"); + } + return ret; + } + + if (strcmp(argv[1], "info") == 0) { + ret = get_fmc_info_main(); + if (ret < 0) { + printf("Get fmc info Failed\n"); + } + return ret; + } + + if (strcmp(argv[1], "upgrade") == 0) { + ret = program_flash_main(argc, argv); + if (ret < 0) { + printf("Upgrade BMC failed.\n"); + } + return ret; + } + + if (strcmp(argv[1], "read_bmc_flash") == 0) { + ret = read_bmc_flash_main(argc, argv); + if (ret < 0) { + printf("Read BMC flash failed.\n"); + } + return ret; + } + + printf("Input invalid.\n"); + help(); + + return -1; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade_debug.c b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade_debug.c new file mode 100644 index 000000000000..a7a78d011011 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade_debug.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "fw_upgrade_debug.h" + +int fw_upgrade_debug(void) +{ + int size; + FILE *fp; + char debug_info[DEBUG_INFO_LEN]; + + fp = fopen(DEBUG_FILE, "r"); + if (fp == NULL) { + return DEBUG_IGNORE; + } + + mem_clear(debug_info, DEBUG_INFO_LEN); + size = fread(debug_info, DEBUG_INFO_LEN - 1, 1, fp); + if (size < 0) { + fclose(fp); + return DEBUG_IGNORE; + } + + if (strncmp(debug_info, DEBUG_ON_INFO, 1) == 0) { + fclose(fp); + return DEBUG_APP_ON; + } + + if (strncmp(debug_info, DEBUG_ON_KERN, 1) == 0) { + fclose(fp); + return DEBUG_KERN_ON; + } + + if (strncmp(debug_info, DEBUG_ON_ALL, 1) == 0) { + fclose(fp); + return DEBUG_ALL_ON; + } + + if (strncmp(debug_info, DEBUG_OFF_INFO, 1) == 0) { + fclose(fp); + return DEBUG_OFF; + } + + fclose(fp); + return DEBUG_IGNORE; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade.h b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade.h new file mode 100644 index 000000000000..bd806a94b154 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade.h @@ -0,0 +1,230 @@ +#ifndef _FW_UPGRADE_H_ +#define _FW_UPGRADE_H_ + +#include "fw_upgrade_debug.h" + +#define dbg_print(debug, fmt, arg...) \ + if (debug == DEBUG_APP_ON || debug == DEBUG_ALL_ON) \ + { do{printf(fmt,##arg);} while(0); } + +/* LPC Interface */ +#define LPC_ADDR_PORT (0x4E) +#define LPC_DATA_PORT (0x4F) + +/* FMC REGISTER ADDR */ +#define FMC_BASE_ADDR (0x1E620000) +#define FMC_CE_TYPE_SETTING_REG (FMC_BASE_ADDR + 0x00) +#define CE_CONTROL_REGISTER (FMC_BASE_ADDR + 0x04) +#define INR_STATUS_CONTROL_REGISTER (FMC_BASE_ADDR + 0x08) +#define COMMAND_CONTROL_REGISTER (FMC_BASE_ADDR + 0x0C) +#define CE0_CONTROL_REGISTER (FMC_BASE_ADDR + 0x10) +#define CE1_CONTROL_REGISTER (FMC_BASE_ADDR + 0x14) +#define CE0_ADDRESS_RANGE_REGISTER (FMC_BASE_ADDR + 0x30) +#define CE1_ADDRESS_RANGE_REGISTER (FMC_BASE_ADDR + 0x34) + +/* SCU REGISTER ADDR */ +#define SCU_ADDR (0x1E6E2000) +#define HARDWARE_STRAP_REGISTER (SCU_ADDR + 0x70) +#define REBOOT_CPU_REGISTER (SCU_ADDR + 0x7C) + +/* SCU KEY */ +#define UNLOCK_SCU_KEY (0x1688A8A8) +#define LOCK_SCU_KEY (0x11111111) + +/* WATCHDOG REGISTER ADDR */ +#define WATCHDOG_ADDR (0x1E785000) +#define WATCHDOG1_RELOAD_VALUE (WATCHDOG_ADDR + 0x04) +#define WATCHDOG1_COUNTER_RST (WATCHDOG_ADDR + 0x08) +#define WATCHDOG1_CONTROL (WATCHDOG_ADDR + 0x0C) +#define WATCHDOG1_TSR (WATCHDOG_ADDR + 0x10) +#define WATCHDOG1_CLEAR_STATUS (WATCHDOG_ADDR + 0x14) +#define WATCHDOG1_RESET_FUN_MASK (WATCHDOG_ADDR + 0x1C) + +#define WATCHDOG2_RELOAD_VALUE (WATCHDOG_ADDR + 0x24) +#define WATCHDOG2_COUNTER_RST (WATCHDOG_ADDR + 0x28) +#define WATCHDOG2_CONTROL (WATCHDOG_ADDR + 0x2C) +#define WATCHDOG2_TSR (WATCHDOG_ADDR + 0x30) +#define WATCHDOG2_CLEAR_STATUS (WATCHDOG_ADDR + 0x34) +#define WATCHDOG2_RESET_FUN_MASK (WATCHDOG_ADDR + 0x3C) + +/* User Mode Command */ +#define WRITE_STATUS (0x01) +#define COMMON_PAGE_PROGRAM (0x02) +#define COMMON_FLASH_READ (0x03) +#define WRITE_DISABLE_FLASH (0x04) +#define READ_FLASH_STATUS (0x05) +#define WRITE_ENABLE_FLASH (0x06) +#define PAGE_PROGRAM_FLASH (0x12) +#define SECTOR_ERASE (0x20) +#define CLEAR_FLAG (0x50) +#define SUBBLOCK_ERASE (0x52) +#define CHIP_ERASE_FLASH (0x60) +#define BLOCK_ERASE_64 (0xD8) +#define READID (0x9F) +#define ENABLE_BYTE4 (0xB7) +#define EXIT_OTP (0xC1) +#define RSTEN (0x66) +#define RST (0x99) + +#define BIT1 (0x01) +#define BIT2 (0x02) +#define BIT3 (0x04) +#define BIT4 (0x08) +#define BIT5 (0x10) +#define BIT6 (0x20) +#define BIT7 (0x40) +#define BIT8 (0x80) +#define RIGHT_SHIFT_8(reg) (reg >> 8) +#define RIGHT_SHIFT_16(reg) (reg >> 16) +#define RIGHT_SHIFT_24(reg) (reg >> 24) +#define MASK (0xFF) +#define FLASH_TYPE_MASK (BIT1 | BIT2) +#define BOOT_DEFAULT_MASK (BIT8) +#define HEAD_MASK (0x00FFFF00) +#define MASK_BYTE (0xFF000000) +#define BYTE1 (1) +#define BYTE2 (2) +#define BYTE4 (4) +#define BYTE1_VAL (0) +#define BYTE2_VAL (1) +#define BYTE4_VAL (2) +#define BYTE_RESERVED (3) + +/* SuperIO */ +#define SUPERIO_07 (0x07) +#define SUPERIO_30 (0x30) +#define SUPERIO_A0 (0xA0) +#define SUPERIO_A2 (0xA2) +#define SUPERIO_REG0 (0xF0) +#define SUPERIO_REG1 (0xF1) +#define SUPERIO_REG2 (0xF2) +#define SUPERIO_REG3 (0xF3) +#define SUPERIO_REG4 (0xF4) +#define SUPERIO_REG5 (0xF5) +#define SUPERIO_REG6 (0xF6) +#define SUPERIO_REG7 (0xF7) +#define SUPERIO_REG8 (0xF8) +#define SUPERIO_FE (0xFE) + +/* SPI Command */ +#define HIGH_CLOCK (0x00000000) +#define NORMAL_READ (0x00000000) +#define READ_MODE (0x00000001) +#define WRITE_MODE (0x00000002) +#define USER_MODE (0x00000003) +#define PULL_DOWN (0x00000000) +#define PULL_UP (0x00000004) + +#define CHIP_ERASE_TIME (60) +#define CHIP_ERASE_TIMEOUT (300 * 1000 * 1000) +#define CHIP_ERASE_SLEEP_TIME (5 * 1000 * 1000) +#define BLOCK_ERASE_TIMEOUT (10 * 1000 * 1000) +#define BLOCK_ERASE_SLEEP_TIME (100 * 1000) +#define PAGE_PROGRAM_TIMEOUT (100 * 1000) +#define PAGE_PROGRAM_SLEEP_TIME (1000) +#define FLASH_WEL_TIMEOUT (100 * 1000) +#define FLASH_WEL_SLEEP_TIME (1000) +#define FLASH_WIP_MASK (0x00000001) +#define FLASH_WRITE_ENABLE_MASK (0x00000002) + +#define DATA_LENGTH_MASK (0xA2) +#define TOGGLE_WRITE (0xCF) +#define DISABLE_LPC (0xAA) +#define ENABLE_LPC (0xA5) +#define LPC_TO_AHB (0x0D) +#define ENABLE_LPC_TO_AHB (0x01) +#define DISABLE_LPC_TO_AHB (0x00) +#define ENABLE_BMC_CPU_BOOT (0xF10BD286) +#define DISABLE_BMC_CPU_BOOT (0xF10BD287) +#define SET_BMC_CPU_BOOT (0x01) +#define CLEAR_WATCHDOG_STATUS (0x01) +#define DISABLE_WATCHDOG (0x00000030) +#define ENABLE_WATCHDOG (0x00000033) +#define WATCHDOG_GATEMASK (0x033FFFF3) +#define WATCHDOG_NEW_COUNT (0x00050000) +#define WATCHDOG_RELOAD_COUNTER (0x4755) + +#define CE0_SPI_TYPE (0x00000002) +#define CE1_SPI_TYPE (0x00000008) +#define ERROR_COMMAND (0x00000400) +#define ADDRESS_PROTECT (0x00000200) +#define CLEAR_INR_STATUS_CONTROL (ERROR_COMMAND | ADDRESS_PROTECT) +#define USER_MODE_PULL_CE_DOWN (HIGH_CLOCK | USER_MODE | PULL_DOWN) +#define USER_MODE_PULL_CE_UP (HIGH_CLOCK | USER_MODE | PULL_UP) + +#define STEP_64 (64 * 1024) +#define STEP_256 (256 * 1024) +#define BYTE_256 (256) + +#define CE0 (0) +#define CE1 (1) +#define BOTHFLASH (2) +#define SOC_SYS (0) +#define FULL_CHIP (1) +#define ARM_CPU (2) +#define FULL_ERASE (0) +#define BLOCK_ERASE (1) +#define READ_ALL (2) +#define CURRENT_SLAVE (1) +#define CURRENT_MASTER (0) +#define REGISTER_HEAD (0x1e000000) +#define DEFAULT_WIDTH (16) +#define MAX_FILENAME_LENGTH (64) +#define SEGMENT_ADDR_START(_r) ((((_r) >> 16) & 0xFF) << 23) + +typedef struct flash_info { + uint32_t flash_size; + int cs; + int flash_type; + uint32_t flash_id; + int page_size; + char flash_name[64]; + int erase_block_command; + int page_program; + int block_size; + int full_erase; + uint32_t ce_control_reg; + uint32_t flash_base_addr; +} flash_info_t; + +typedef enum flash_id { + MX25L6433F = 0x1920c2, + S25FL512S = 0x200201, + MX25l512 = 0x1a20c2, + STM25P64 = 0x172020, + STM25P128 = 0x182020, + N25Q256 = 0x19ba20, + N25Q512 = 0x20ba20, + W25X16 = 0x1530ef, + W25X64 = 0x1730ef, + W25Q64BV = 0x1740ef, + W25Q128BV = 0x1840ef, + W25Q256FV = 0x1940ef, + MX25L1605D = 0x1520C2, + MX25L12805D = 0x1820C2, + MX66L1G45G = 0x1B20C2, + SST25VF016B = 0x4125bf, + SST25VF064C = 0x4b25bf, + SST25VF040B = 0x8d25bf, + AT25DF161 = 0x02461F, + AT25DF321 = 0x01471F, + GD25Q256 = 0X1940c8, +} flash_id_t; + +typedef enum flash_type { + NOR = 0, + SPI = 2, +} flash_type_t; + +typedef enum flash_size { + M1 = 0x00080000, + M3 = 0x00200000, /* 3M */ + M6 = 0x00400000, /* 6M */ + M12 = 0x00800000, /* 12M */ + M16 = 0x01000000, /* 16M */ + M32 = 0x02000000, /* 32M */ + M64 = 0x04000000, /* 64M */ + M128 = 0x08000000, /* 128M */ +} flash_size_t; + +#endif /*_FW_UPGRADE_H_*/ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade_debug.h b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade_debug.h new file mode 100644 index 000000000000..05911da62a7e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade_debug.h @@ -0,0 +1,25 @@ +#ifndef __FW_UPGRADE_DEBUG_H__ +#define __FW_UPGRADE_DEBUG_H__ + +#include + +#define DEBUG_INFO_LEN 20 +#define DEBUG_FILE "/tmp/.fw_upgrade_debug" +#define DEBUG_ON_ALL "3" +#define DEBUG_ON_KERN "2" +#define DEBUG_ON_INFO "1" +#define DEBUG_OFF_INFO "0" + +#define mem_clear(data, size) memset((data), 0, (size)) + +enum debug_s { + DEBUG_OFF = 0, + DEBUG_APP_ON, + DEBUG_KERN_ON, + DEBUG_ALL_ON, + DEBUG_IGNORE, +}; + +extern int fw_upgrade_debug(void); + +#endif /* End of __FW_UPGRADE_DEBUG_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/hysteresis.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/hysteresis.py new file mode 100644 index 000000000000..81fd596e7fee --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/hysteresis.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +import os +import syslog +import copy + +from plat_hal.baseutil import baseutil + +HYST_DEBUG_FILE = "/etc/.hysteresis_debug_flag" + +HYSTERROR = 1 +HYSTDEBUG = 2 + +debuglevel = 0 + + +def hyst_debug(s): + if HYSTDEBUG & debuglevel: + syslog.openlog("FANCONTROL-HYST", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def hyst_error(s): + if HYSTERROR & debuglevel: + syslog.openlog("FANCONTROL-HYST", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +class hysteresis(object): + __config = None + __hyst_config = None + + def __init__(self): + self.__config = baseutil.get_monitor_config() + self.__hyst_config = copy.deepcopy(self.__config.get("hyst", {})) + # init check + errcnt = 0 + errmsg = "" + self.debug_init() + for temp_hyst_conf in self.__hyst_config.values(): + if temp_hyst_conf["flag"] == 0: + continue + for i in range(temp_hyst_conf["temp_min"], temp_hyst_conf["temp_max"] + 1): + if i not in temp_hyst_conf["rising"]: + errcnt -= 1 + msg = "%s hyst config error, temp value %d not in rising curve;" % (temp_hyst_conf["name"], i) + hyst_error(msg) + errmsg += msg + if i not in temp_hyst_conf["descending"]: + errcnt -= 1 + msg = "%s hyst config error, temp value %d not in descending curve;" % (temp_hyst_conf["name"], i) + hyst_error(msg) + errmsg += msg + if errcnt < 0: + raise KeyError(errmsg) + + def debug_init(self): + global debuglevel + if os.path.exists(HYST_DEBUG_FILE): + debuglevel = debuglevel | HYSTDEBUG | HYSTERROR + else: + debuglevel = debuglevel & ~(HYSTDEBUG | HYSTERROR) + + def get_temp_hyst_conf(self, temp_name): + temp_hyst_conf = self.__hyst_config.get(temp_name) + return temp_hyst_conf + + def get_temp_update(self, hyst_para, current_temp): + temp = hyst_para["value"] + if temp is None: + return None + temp.append(current_temp) + del temp[0] + return temp + + def duty_to_pwm(self, duty): + pwm = int(round(float(duty) * 255 / 100)) + return pwm + + def pwm_to_duty(self, pwm): + duty = int(round(float(pwm) * 100 / 255)) + return duty + + def calc_hyst_val(self, temp_name, temp_list): + + temp_hyst_conf = self.get_temp_hyst_conf(temp_name) + hyst_min = temp_hyst_conf["hyst_min"] + hyst_max = temp_hyst_conf["hyst_max"] + temp_min = temp_hyst_conf["temp_min"] + temp_max = temp_hyst_conf["temp_max"] + rising = temp_hyst_conf["rising"] + descending = temp_hyst_conf["descending"] + last_hyst_value = temp_hyst_conf["last_hyst_value"] + current_temp = temp_list[1] + last_temp = temp_list[0] + + hyst_debug("calc_hyst_val, temp_name: %s, current_temp: %s, last_temp: %s, last_hyst_value: %s" % + (temp_name, current_temp, last_temp, last_hyst_value)) + + if current_temp < temp_min: + hyst_debug("%s current_temp %s less than temp_min %s, set min hyst value: %s" % + (temp_name, current_temp, temp_min, hyst_min)) + return hyst_min + + if current_temp > temp_max: + hyst_debug("%s current_temp %s more than temp_max %s, set max hyst value: %s" % + (temp_name, current_temp, temp_max, hyst_max)) + return hyst_max + + if last_temp is None: # first time + hyst_value = rising[current_temp] + hyst_debug("last_temp is None, it's first hysteresis, using rising hyst value: %s" % hyst_value) + return hyst_value + + if current_temp == last_temp: # temp unchanging + hyst_debug("current_temp equal last_temp, keep last hyst value: %s" % last_hyst_value) + return last_hyst_value + + if current_temp > last_temp: + calc_hyst_value = rising[current_temp] + if calc_hyst_value < last_hyst_value: + hyst_value = last_hyst_value + else: + hyst_value = calc_hyst_value + hyst_debug("temp rising, last_hyst_value: %s, calc_hyst_value: %s, set hyst value: %s" % + (last_hyst_value, calc_hyst_value, hyst_value)) + return hyst_value + + calc_hyst_value = descending[current_temp] + if calc_hyst_value > last_hyst_value: + hyst_value = last_hyst_value + else: + hyst_value = calc_hyst_value + hyst_debug("temp descending, last_hyst_value: %s, calc_hyst_value: %s, set hyst value: %s" % + (last_hyst_value, calc_hyst_value, hyst_value)) + return hyst_value + + def cacl(self, temp_name, current_temp): + self.debug_init() + try: + temp_hyst_conf = self.get_temp_hyst_conf(temp_name) + if temp_hyst_conf is None: + hyst_debug("get %s hysteresis config failed" % temp_name) + return None + + flag = temp_hyst_conf["flag"] + if flag != 1: + hyst_debug("%s hysteresis flag == 0, skip" % temp_name) + return None + + temp = self.get_temp_update(temp_hyst_conf, current_temp) + if temp is None: + hyst_debug("get %s update failed" % temp_name) + return None + + value = self.calc_hyst_val(temp_name, temp) + + temp_hyst_conf["last_hyst_value"] = value + + speed_type = temp_hyst_conf["type"] + if speed_type == "duty": + pwm = self.duty_to_pwm(value) + else: + pwm = value + + hyst_debug("temp_name: %s, current_temp: %s, set pwm 0x%x" % (temp_name, current_temp, pwm)) + return pwm + except Exception as e: + hyst_error("temp_name: %s calc hysteresis pwm error, msg: %s" % (temp_name, str(e))) + return None diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/openloop.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/openloop.py new file mode 100644 index 000000000000..6ff731fa7eb2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/openloop.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +import os +import syslog + +from plat_hal.baseutil import baseutil + +OPENLOOP_DEBUG_FILE = "/etc/.openloop_debug_flag" + +OPENLOOPERROR = 1 +OPENLOOPDEBUG = 2 + +debuglevel = 0 + + +def openloop_debug(s): + if OPENLOOPDEBUG & debuglevel: + syslog.openlog("FANCONTROL-OPENLOOP", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def openloop_error(s): + if OPENLOOPERROR & debuglevel: + syslog.openlog("FANCONTROL-OPENLOOP", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +class openloop(object): + __config = None + __openloop_config = None + + def __init__(self): + self.__config = baseutil.get_monitor_config() + self.__openloop_config = self.__config["openloop"] + + def debug_init(self): + global debuglevel + if os.path.exists(OPENLOOP_DEBUG_FILE): + debuglevel = debuglevel | OPENLOOPDEBUG | OPENLOOPERROR + else: + debuglevel = debuglevel & ~(OPENLOOPDEBUG | OPENLOOPERROR) + + def get_para(self, t): + para = self.__openloop_config.get(t) + return para + + def linear_cacl(self, temp): + self.debug_init() + openloop_para = self.get_para("linear") + if openloop_para is None: + openloop_debug("linear openloop: get para failed") + return None + + K = openloop_para["K"] + tin_min = openloop_para["tin_min"] + pwm_min = openloop_para["pwm_min"] + pwm_max = openloop_para["pwm_max"] + flag = openloop_para["flag"] + + if flag != 1: + openloop_debug("linear openloop: flag == 0") + return None + + if temp <= tin_min: + openloop_debug("linear openloop: temp = %d less than tin_min[%d]" % (temp, tin_min)) + return pwm_min + + pwm = int(pwm_min + (temp - tin_min) * K) + openloop_debug("linear openloop: cacl_pwm = 0x%x" % pwm) + + pwm = min(pwm, pwm_max) + pwm = max(pwm, pwm_min) + openloop_debug("linear openloop: temp = %d, pwm = 0x%x" % (temp, pwm)) + return pwm + + def curve_cacl(self, temp): + self.debug_init() + openloop_para = self.get_para("curve") + if openloop_para is None: + openloop_debug("curve openloop: get para failed") + return None + + a = openloop_para["a"] + b = openloop_para["b"] + c = openloop_para["c"] + tin_min = openloop_para["tin_min"] + pwm_min = openloop_para["pwm_min"] + pwm_max = openloop_para["pwm_max"] + flag = openloop_para["flag"] + + if flag != 1: + openloop_debug("curve openloop: flag == 0") + return None + + if temp <= tin_min: + openloop_debug("curve openloop: temp = %d less than tin_min[%d]" % (temp, tin_min)) + return pwm_min + + pwm = int(a * temp * temp + b * temp + c) + openloop_debug("curve openloop: cacl_pwm = 0x%x" % pwm) + + pwm = min(pwm, pwm_max) + pwm = max(pwm, pwm_min) + openloop_debug("curve openloop: temp = %d, pwm = 0x%x" % (temp, pwm)) + return pwm diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/pid.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/pid.py new file mode 100644 index 000000000000..c33c1df33b4e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/pid.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +import os +import syslog +import copy + +from plat_hal.baseutil import baseutil + +PID_DEBUG_FILE = "/etc/.pid_debug_flag" + +PIDERROR = 1 +PIDDEBUG = 2 + +debuglevel = 0 + + +def pid_debug(s): + if PIDDEBUG & debuglevel: + syslog.openlog("FANCONTROL-PID", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def pid_error(s): + if PIDERROR & debuglevel: + syslog.openlog("FANCONTROL-PID", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +class pid(object): + __config = None + __pid_config = None + + def __init__(self): + self.__config = baseutil.get_monitor_config() + self.__pid_config = copy.deepcopy(self.__config["pid"]) + + def debug_init(self): + global debuglevel + if os.path.exists(PID_DEBUG_FILE): + debuglevel = debuglevel | PIDDEBUG | PIDERROR + else: + debuglevel = debuglevel & ~(PIDDEBUG | PIDERROR) + + def get_para(self, name): + para = self.__pid_config.get(name) + return para + + def get_temp_update(self, pid_para, current_temp): + temp = pid_para["value"] + if temp is None: + return None + temp.append(current_temp) + del temp[0] + return temp + + def cacl(self, last_pwm, name, current_temp): + delta_pwm = 0 + self.debug_init() + pid_debug("last_pwm = %d" % last_pwm) + + pid_para = self.get_para(name) + if pid_para is None: + pid_debug("get %s pid para failed" % name) + return None + + temp = self.get_temp_update(pid_para, current_temp) + if temp is None: + pid_debug("get %s update failed" % name) + return None + + speed_type = pid_para["type"] + Kp = pid_para["Kp"] + Ki = pid_para["Ki"] + Kd = pid_para["Kd"] + target = pid_para["target"] + pwm_min = pid_para["pwm_min"] + pwm_max = pid_para["pwm_max"] + flag = pid_para["flag"] + + if flag != 1: + pid_debug("%s pid flag == 0" % name) + return None + + if speed_type == "duty": + current_pwm = round(last_pwm * 100 / 255) + else: + current_pwm = last_pwm + + if temp[2] is None: + tmp_pwm = current_pwm + elif ((temp[0] is None) or (temp[1] is None)): + delta_pwm = Ki * (temp[2] - target) + tmp_pwm = current_pwm + delta_pwm + else: + delta_pwm = Kp * (temp[2] - temp[1]) + Ki * (temp[2] - target) + Kd * (temp[2] - 2 * temp[1] + temp[0]) + tmp_pwm = current_pwm + delta_pwm + + pid_debug("delta_pwm = %d" % delta_pwm) + if speed_type == "duty": + pwm = round(tmp_pwm * 255 / 100) + else: + pwm = int(tmp_pwm) + + pwm = min(pwm, pwm_max) + pwm = max(pwm, pwm_min) + pid_debug("last_pwm = 0x%x, pwm = 0x%x" % (last_pwm, pwm)) + return pwm diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/cust_fru.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/cust_fru.py new file mode 100644 index 000000000000..940c722ce467 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/cust_fru.py @@ -0,0 +1,135 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import sys +import os + + +class CustFruException(Exception): + def __init__(self, message='custfrueerror', code=-100): + err = 'errcode: {0} message:{1}'.format(code, message) + Exception.__init__(self, err) + self.code = code + self.message = message + + +class CustFru(): + MAGIC_HEAD_INFO = 0x7a + + _CUST_MAGIC_OFFSET = 0 + _CUST_MAGIC_LEN = 1 + _CUST_VERSION_OFFSET = 1 + _CUST_VERSION_LEN = 6 + _CUST_CRC_OFFSET = 7 + _CUST_CRC_LEN = 1 + _CUST_PRODUCT_NAME_OFFSET = 10 + _CUST_PRODUCT_NAME_LEN = 17 + _CUST_MANUFACTURER_OFFSET = 27 + _CUST_MANUFACTURER_LEN = 7 + _CUST_SERIAL_NUMBER_OFFSET = 34 + _CUST_SERIAL_NUMBER_LEN = 25 + _CUST_INPUT_TYPE_OFFSET = 78 + _CUST_INPUT_TYPE_LEN = 2 + _CUST_INPUT_OFFSET = 86 + _CUST_INPUT_LEN = 15 + _CUST_OUTPUT_OFFSET = 108 + _CUST_OUTPUT_LEN = 11 + _CUST_POWER_OFFSET = 200 + _CUST_POWER_LEN = 10 + _CUST_MANUFACTURER_DATE_OFFSET = 210 + _CUST_MANUFACTURER_DATE_LEN = 3 + + def __init__(self): + self.magic = "" + self.version = "" + self.crc = "" + self.product_name = "" + self.manufacturer = "" + self.serial_number = "" + self.input_type = "" + self.input = "" + self.output = "" + self.power = "" + self.manufacturer_date = "" + + def checksum(self, v): + result = 0 + for item in v: + result += ord(item) + return (result & 0xff) + + def decode(self, e2): + # header + e2_index = 0 + head = ord(e2[0]) + if head != self.MAGIC_HEAD_INFO: + raise CustFruException("Customization fru eeprom head info error, head:0x%x" % head, -10) + self.magic = "0x%02x" % self.MAGIC_HEAD_INFO + + # version + version = "%s" % (e2[self._CUST_VERSION_OFFSET:self._CUST_VERSION_OFFSET + self._CUST_VERSION_LEN]) + self.version = version.replace("\xff", "").strip() + + # crc + crc_calc = self.checksum(e2[0:self._CUST_CRC_OFFSET]) + if crc_calc != ord(e2[self._CUST_CRC_OFFSET]): + raise CustFruException("Customization fru eeprom crc check error, calc: 0x%x, read: 0x%x" % (crc_calc, ord(e2[self._CUST_CRC_OFFSET])), -10) + self.crc = crc_calc + + # Product Name + product_name = "%s" % (e2[self._CUST_PRODUCT_NAME_OFFSET:self._CUST_PRODUCT_NAME_OFFSET + self._CUST_PRODUCT_NAME_LEN]) + self.product_name = product_name.replace("\xff", "").strip() + + # manufacturer + manufacturer = "%s" % (e2[self._CUST_MANUFACTURER_OFFSET:self._CUST_MANUFACTURER_OFFSET + self._CUST_MANUFACTURER_LEN]) + self.manufacturer = manufacturer.strip() + + # serial_number + serial_number = "%s" % (e2[self._CUST_SERIAL_NUMBER_OFFSET:self._CUST_SERIAL_NUMBER_OFFSET + self._CUST_SERIAL_NUMBER_LEN]) + self.serial_number = serial_number.strip() + + # input_type + input_type = "%s" % (e2[self._CUST_INPUT_TYPE_OFFSET:self._CUST_INPUT_TYPE_OFFSET + self._CUST_INPUT_TYPE_LEN]) + self.input_type = input_type.strip() + + # input + input = "%s" % (e2[self._CUST_INPUT_OFFSET:self._CUST_INPUT_OFFSET + self._CUST_INPUT_LEN]) + self.input = input.strip() + + # output + output = "%s" % (e2[self._CUST_OUTPUT_OFFSET:self._CUST_OUTPUT_OFFSET + self._CUST_OUTPUT_LEN]) + self.output = output.strip() + + # power + power = "%s" % (e2[self._CUST_POWER_OFFSET:self._CUST_POWER_OFFSET + self._CUST_POWER_LEN]) + self.power = power.replace("\xff", "").strip() + + # manufacturer_date + manufacturer_year = ord(e2[self._CUST_MANUFACTURER_DATE_OFFSET]) + 2000 + manufacturer_month = ord(e2[self._CUST_MANUFACTURER_DATE_OFFSET + 1]) + manufacturer_day = ord(e2[self._CUST_MANUFACTURER_DATE_OFFSET + 2]) + self.manufacturer_date = "%04d-%02d-%02d" % (manufacturer_year, manufacturer_month, manufacturer_day) + + return + + + def __str__(self): + formatstr = "Version : %s \n" \ + "Product Name : %s \n" \ + "Manufacturer : %s \n" \ + "Serial Number : %s \n" \ + "AC/DC Power Module : %s \n" \ + "INPUT : %s \n" \ + "OUTPUT : %s \n" \ + "POWER : %s \n" \ + "Manufacturer Date : %s \n" + str_tmp = formatstr % (self.version, + self.product_name, + self.manufacturer, + self.serial_number, + self.input_type, + self.input, + self.output, + self.power, + self.manufacturer_date) + return str_tmp.replace("\x00","") + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fantlv.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fantlv.py new file mode 100644 index 000000000000..4be78e7fdc03 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fantlv.py @@ -0,0 +1,192 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +class FantlvException(Exception): + def __init__(self, message='fantlverror', code=-100): + err = 'errcode: {0} message:{1}'.format(code, message) + Exception.__init__(self, err) + self.code = code + self.message = message + + +class fan_tlv(): + HEAD_INFO = "\x01\x7e\x01\xf1" + VERSION = 0x01 + FLAG = 0x7E + HW_VER = 0X01 + TYPE = 0xf1 + TLV_LEN = 00 + _FAN_TLV_HDR_LEN = 6 + _FAN_TLV_CRC_LEN = 2 + + _FAN_TLV_TYPE_NAME = 0x02 + _FAN_TLV_TYPE_SN = 0x03 + _FAN_TLV_TYPE_HW_INFO = 0x05 + _FAN_TLV_TYPE_DEV_TYPE = 0x06 + + @property + def dstatus(self): + return self._dstatus + + @property + def typename(self): + return self._typename + + @property + def typesn(self): + return self._typesn + + @property + def typehwinfo(self): + return self._typehwinfo + + @property + def typedevtype(self): + return self._typedevtype + + def __init__(self): + self._typename = "" + self._typesn = "" + self._typehwinfo = "" + self._typedevtype = "" + self._dstatus = 0 + + def strtoarr(self, val): + s = [] + if not isinstance(val, str): + return s + for index in val: + s.append(index) + return s + + def hex_to_str(self, s): + len_t = len(s) + if len_t % 2 != 0: + return 0 + ret = "" + for t in range(0, len_t / 2): + ret += chr(int(s[2 * t:2 * t + 2], 16)) + return ret + + def generate_fan_value(self): + bin_buffer = [chr(0xff)] * 256 + bin_buffer[0] = chr(self.VERSION) + bin_buffer[1] = chr(self.FLAG) + bin_buffer[2] = chr(self.HW_VER) + bin_buffer[3] = chr(self.TYPE) + + temp_t = "%08x" % self.typedevtype + typedevtype_t = self.hex_to_str(temp_t) + total_len = len(self.typename) + len(self.typesn) + \ + len(self.typehwinfo) + len(typedevtype_t) + 8 + + bin_buffer[4] = chr(total_len >> 8) + bin_buffer[5] = chr(total_len & 0x00FF) + + index_start = 6 + bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_NAME) + bin_buffer[index_start + 1] = chr(len(self.typename)) + bin_buffer[index_start + 2: index_start + 2 + + len(self.typename)] = self.strtoarr(self.typename) + index_start = index_start + 2 + len(self.typename) + + bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_SN) + bin_buffer[index_start + 1] = chr(len(self.typesn)) + bin_buffer[index_start + 2:index_start + 2 + + len(self.typesn)] = self.strtoarr(self.typesn) + index_start = index_start + 2 + len(self.typesn) + + bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_HW_INFO) + bin_buffer[index_start + 1] = chr(len(self.typehwinfo)) + bin_buffer[index_start + 2:index_start + 2 + + len(self.typehwinfo)] = self.strtoarr(self.typehwinfo) + index_start = index_start + 2 + len(self.typehwinfo) + + bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_DEV_TYPE) + bin_buffer[index_start + 1] = chr(len(typedevtype_t)) + bin_buffer[index_start + 2:index_start + 2 + + len(typedevtype_t)] = self.strtoarr(typedevtype_t) + index_start = index_start + 2 + len(typedevtype_t) + + crcs = fan_tlv.fancrc(''.join(bin_buffer[0:index_start])) + bin_buffer[index_start] = chr(crcs >> 8) + bin_buffer[index_start + 1] = chr(crcs & 0x00ff) + return bin_buffer + + def decode(self, e2): + if e2[0:4] != self.HEAD_INFO: + raise FantlvException("Fan tlv head info error,not fan tlv type", -10) + ret = [] + self.VERSION = ord(e2[0]) + self.FLAG = ord(e2[1]) + self.HW_VER = ord(e2[2]) + self.TYPE = ord(e2[3]) + self.TLV_LEN = (ord(e2[4]) << 8) | ord(e2[5]) + + tlv_index = self._FAN_TLV_HDR_LEN + tlv_end = self._FAN_TLV_HDR_LEN + self.TLV_LEN + + if len(e2) < self._FAN_TLV_HDR_LEN + self.TLV_LEN + 2: + raise FantlvException("Fan tlv eeprom len error!", -2) + sumcrc = fan_tlv.fancrc(e2[0:self._FAN_TLV_HDR_LEN + self.TLV_LEN]) + readcrc = ord(e2[self._FAN_TLV_HDR_LEN + self.TLV_LEN] + ) << 8 | ord(e2[self._FAN_TLV_HDR_LEN + self.TLV_LEN + 1]) + if sumcrc != readcrc: + raise FantlvException("Fan tlv eeprom checksum error!", -1) + self._dstatus = 0 + while (tlv_index + 2) < len(e2) and tlv_index < tlv_end: + s = self.decoder( + e2[tlv_index:tlv_index + 2 + ord(e2[tlv_index + 1])]) + tlv_index += ord(e2[tlv_index + 1]) + 2 + ret.append(s) + + return ret + + @staticmethod + def fancrc(t): + crc = 0 + for item in t: + crc += ord(item) + return crc + + def decoder(self, t): + try: + name = "" + value = "" + _len = 0 + if ord(t[0]) == self._FAN_TLV_TYPE_NAME: + name = "Product Name" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._typename = value + elif ord(t[0]) == self._FAN_TLV_TYPE_SN: + name = "serial Number" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._typesn = value + elif ord(t[0]) == self._FAN_TLV_TYPE_HW_INFO: + name = "hardware info" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._typehwinfo = value + elif ord(t[0]) == self._FAN_TLV_TYPE_DEV_TYPE: + name = "dev type" + _len = ord(t[1]) + value = "0x" + for c in t[2:2 + ord(t[1])]: + value += "%02X" % (ord(c),) + self._typedevtype = int(value, 16) + except Exception as e: + print(e) + return {"name": name, "code": ord(t[0]), "value": value, "lens": _len} + + def __str__(self): + formatstr = "VERSION : 0x%02x \n" \ + " FLAG : 0x%02x \n" \ + " HW_VER : 0x%02x \n" \ + " TYPE : 0x%02x \n" \ + "typename : %s \n" \ + "typesn : %s \n" \ + "typehwinfo : %s \n" + return formatstr % (self.VERSION, self.FLAG, self.HW_VER, self.TYPE, + self.typename, self.typesn, self.typehwinfo) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fru.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fru.py new file mode 100644 index 000000000000..f95164e03601 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fru.py @@ -0,0 +1,961 @@ +#!/usr/bin/python3 +import collections +from datetime import datetime, timedelta +from bitarray import bitarray + + +__DEBUG__ = "N" + + +class FruException(Exception): + def __init__(self, message='fruerror', code=-100): + err = 'errcode: {0} message:{1}'.format(code, message) + Exception.__init__(self, err) + self.code = code + self.message = message + + +def e_print(err): + print("ERROR: " + err) + + +def d_print(debug_info): + if __DEBUG__ == "Y": + print(debug_info) + + +class FruUtil(): + @staticmethod + def decodeLength(value): + a = bitarray(8) + a.setall(True) + a[0:1] = 0 + a[1:2] = 0 + x = ord(a.tobytes()) + return x & ord(value) + + @staticmethod + def minToData(): + starttime = datetime(1996, 1, 1, 0, 0, 0) + endtime = datetime.now() + seconds = (endtime - starttime).total_seconds() + mins = seconds // 60 + m = int(round(mins)) + return m + + @staticmethod + def getTimeFormat(): + return datetime.now().strftime('%Y-%m-%d') + + @staticmethod + def getTypeLength(value): + if value is None or len(value) == 0: + return 0 + a = bitarray(8) + a.setall(False) + a[0:1] = 1 + a[1:2] = 1 + x = ord(a.tobytes()) + return x | len(value) + + @staticmethod + def checksum(b): + result = 0 + for item in b: + result += ord(item) + return (0x100 - (result & 0xff)) & 0xff + + +class BaseArea(object): + SUGGESTED_SIZE_COMMON_HEADER = 8 + SUGGESTED_SIZE_INTERNAL_USE_AREA = 72 + SUGGESTED_SIZE_CHASSIS_INFO_AREA = 32 + SUGGESTED_SIZE_BOARD_INFO_AREA = 80 + SUGGESTED_SIZE_PRODUCT_INFO_AREA = 80 + + INITVALUE = b'\x00' + resultvalue = INITVALUE * 256 + COMMON_HEAD_VERSION = b'\x01' + __childList = None + + def __init__(self, name="", size=0, offset=0): + self.__childList = [] + self._offset = offset + self.name = name + self._size = size + self._isPresent = False + self._data = b'\x00' * size + + @property + def childList(self): + return self.__childList + + @childList.setter + def childList(self, value): + self.__childList = value + + @property + def offset(self): + return self._offset + + @offset.setter + def offset(self, value): + self._offset = value + + @property + def size(self): + return self._size + + @size.setter + def size(self, value): + self._size = value + + @property + def data(self): + return self._data + + @data.setter + def data(self, value): + self._data = value + + @property + def isPresent(self): + return self._isPresent + + @isPresent.setter + def isPresent(self, value): + self._isPresent = value + + +class InternalUseArea(BaseArea): + pass + + +class ChassisInfoArea(BaseArea): + pass + + +class BoardInfoArea(BaseArea): + _boardTime = None + _fields = None + _mfg_date = None + areaversion = None + _boardversion = None + _language = None + + def __str__(self): + formatstr = "version : %x\n" \ + "length : %d \n" \ + "language : %x \n" \ + "mfg_date : %s \n" \ + "boardManufacturer : %s \n" \ + "boardProductName : %s \n" \ + "boardSerialNumber : %s \n" \ + "boardPartNumber : %s \n" \ + "fruFileId : %s \n" + + tmpstr = formatstr % (ord(self.boardversion), self.size, + self.language, self.getMfgRealData(), + self.boardManufacturer, self.boardProductName, + self.boardSerialNumber, self.boardPartNumber, + self.fruFileId) + for i in range(1, 11): + valtmp = "boardextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + tmpstr += "boardextra%d : %s \n" % (i, valtmpval) + else: + break + + return tmpstr + + def todict(self): + dic = collections.OrderedDict() + dic["boardversion"] = ord(self.boardversion) + dic["boardlength"] = self.size + dic["boardlanguage"] = self.language + dic["boardmfg_date"] = self.getMfgRealData() + dic["boardManufacturer"] = self.boardManufacturer + dic["boardProductName"] = self.boardProductName + dic["boardSerialNumber"] = self.boardSerialNumber + dic["boardPartNumber"] = self.boardPartNumber + dic["boardfruFileId"] = self.fruFileId + for i in range(1, 11): + valtmp = "boardextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + dic[valtmp] = valtmpval + else: + break + return dic + + def decodedata(self): + index = 0 + self.areaversion = self.data[index] + index += 1 + d_print("decode length :%d class size:%d" % + ((ord(self.data[index]) * 8), self.size)) + index += 2 + + timetmp = self.data[index: index + 3] + self.mfg_date = ord(timetmp[0]) | ( + ord(timetmp[1]) << 8) | (ord(timetmp[2]) << 16) + d_print("decode getMfgRealData :%s" % self.getMfgRealData()) + index += 3 + + templen = FruUtil.decodeLength(self.data[index]) + self.boardManufacturer = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardManufacturer:%s" % self.boardManufacturer) + + templen = FruUtil.decodeLength(self.data[index]) + self.boardProductName = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardProductName:%s" % self.boardProductName) + + templen = FruUtil.decodeLength(self.data[index]) + self.boardSerialNumber = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardSerialNumber:%s" % self.boardSerialNumber) + + templen = FruUtil.decodeLength(self.data[index]) + self.boardPartNumber = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardPartNumber:%s" % self.boardPartNumber) + + templen = FruUtil.decodeLength(self.data[index]) + self.fruFileId = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode fruFileId:%s" % self.fruFileId) + + for i in range(1, 11): + valtmp = "boardextra%d" % i + if self.data[index] != chr(0xc1): + templen = FruUtil.decodeLength(self.data[index]) + tmpval = self.data[index + 1: index + templen + 1] + setattr(self, valtmp, tmpval) + index += templen + 1 + d_print("decode boardextra%d:%s" % (i, tmpval)) + else: + break + + def fruSetValue(self, field, value): + tmp_field = getattr(self, field, None) + if tmp_field is not None: + setattr(self, field, value) + + def recalcute(self): + d_print("boardInfoArea version:%x" % ord(self.boardversion)) + d_print("boardInfoArea length:%d" % self.size) + d_print("boardInfoArea language:%x" % self.language) + self.mfg_date = FruUtil.minToData() + d_print("boardInfoArea mfg_date:%x" % self.mfg_date) + + self.data = chr(ord(self.boardversion)) + \ + chr(self.size // 8) + chr(self.language) + + self.data += chr(self.mfg_date & 0xFF) + self.data += chr((self.mfg_date >> 8) & 0xFF) + self.data += chr((self.mfg_date >> 16) & 0xFF) + + d_print("boardInfoArea boardManufacturer:%s" % self.boardManufacturer) + typelength = FruUtil.getTypeLength(self.boardManufacturer) + self.data += chr(typelength) + self.data += self.boardManufacturer + + d_print("boardInfoArea boardProductName:%s" % self.boardProductName) + self.data += chr(FruUtil.getTypeLength(self.boardProductName)) + self.data += self.boardProductName + + d_print("boardInfoArea boardSerialNumber:%s" % self.boardSerialNumber) + self.data += chr(FruUtil.getTypeLength(self.boardSerialNumber)) + self.data += self.boardSerialNumber + + d_print("boardInfoArea boardPartNumber:%s" % self.boardPartNumber) + self.data += chr(FruUtil.getTypeLength(self.boardPartNumber)) + self.data += self.boardPartNumber + + d_print("boardInfoArea fruFileId:%s" % self.fruFileId) + self.data += chr(FruUtil.getTypeLength(self.fruFileId)) + self.data += self.fruFileId + + for i in range(1, 11): + valtmp = "boardextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + d_print("boardInfoArea boardextra%d:%s" % (i, valtmpval)) + self.data += chr(FruUtil.getTypeLength(valtmpval)) + if valtmpval is not None: + self.data += valtmpval + else: + break + + self.data += chr(0xc1) + + if len(self.data) > (self.size - 1): + incr = (len(self.data) - self.size) // 8 + 1 + self.size += incr * 8 + + self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] + d_print("self data:%d" % len(self.data)) + d_print("self size:%d" % self.size) + d_print("adjust size:%d" % (self.size - len(self.data) - 1)) + self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) + + # checksum + checksum = FruUtil.checksum(self.data) + d_print("board info checksum:%x" % checksum) + self.data += chr(checksum) + + def getMfgRealData(self): + starttime = datetime(1996, 1, 1, 0, 0, 0) + mactime = starttime + timedelta(minutes=self.mfg_date) + return mactime + + @property + def language(self): + self._language = 25 + return self._language + + @property + def mfg_date(self): + return self._mfg_date + + @mfg_date.setter + def mfg_date(self, val): + self._mfg_date = val + + @property + def boardversion(self): + self._boardversion = self.COMMON_HEAD_VERSION + return self._boardversion + + @property + def fruFileId(self): + return self._FRUFileID + + @fruFileId.setter + def fruFileId(self, val): + self._FRUFileID = val + + @property + def boardPartNumber(self): + return self._boardPartNumber + + @boardPartNumber.setter + def boardPartNumber(self, val): + self._boardPartNumber = val + + @property + def boardSerialNumber(self): + return self._boardSerialNumber + + @boardSerialNumber.setter + def boardSerialNumber(self, val): + self._boardSerialNumber = val + + @property + def boardProductName(self): + return self._boradProductName + + @boardProductName.setter + def boardProductName(self, val): + self._boradProductName = val + + @property + def boardManufacturer(self): + return self._boardManufacturer + + @boardManufacturer.setter + def boardManufacturer(self, val): + self._boardManufacturer = val + + @property + def boardTime(self): + return self._boardTime + + @boardTime.setter + def boardTime(self, val): + self._boardTime = val + + @property + def fields(self): + return self._fields + + @fields.setter + def fields(self, val): + self._fields = val + + +class ProductInfoArea(BaseArea): + _productManufacturer = None + _productAssetTag = None + _FRUFileID = None + _language = None + + def __str__(self): + formatstr = "version : %x\n" \ + "length : %d \n" \ + "language : %x \n" \ + "productManufacturer : %s \n" \ + "productName : %s \n" \ + "productPartModelName: %s \n" \ + "productVersion : %s \n" \ + "productSerialNumber : %s \n" \ + "productAssetTag : %s \n" \ + "fruFileId : %s \n" + + tmpstr = formatstr % (ord(self.areaversion), self.size, + self.language, self.productManufacturer, + self.productName, self.productPartModelName, + self.productVersion, self.productSerialNumber, + self.productAssetTag, self.fruFileId) + + for i in range(1, 11): + valtmp = "productextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + tmpstr += "productextra%d : %s \n" % (i, valtmpval) + else: + break + + return tmpstr + + def todict(self): + dic = collections.OrderedDict() + dic["productversion"] = ord(self.areaversion) + dic["productlength"] = self.size + dic["productlanguage"] = self.language + dic["productManufacturer"] = self.productManufacturer + dic["productName"] = self.productName + dic["productPartModelName"] = self.productPartModelName + dic["productVersion"] = int(self.productVersion, 16) + dic["productSerialNumber"] = self.productSerialNumber + dic["productAssetTag"] = self.productAssetTag + dic["productfruFileId"] = self.fruFileId + for i in range(1, 11): + valtmp = "productextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + dic[valtmp] = valtmpval + else: + break + return dic + + def decodedata(self): + index = 0 + self.areaversion = self.data[index] # 0 + index += 1 + d_print("decode length %d" % (ord(self.data[index]) * 8)) + d_print("class size %d" % self.size) + index += 2 + + templen = FruUtil.decodeLength(self.data[index]) + self.productManufacturer = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productManufacturer:%s" % self.productManufacturer) + + templen = FruUtil.decodeLength(self.data[index]) + self.productName = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productName:%s" % self.productName) + + templen = FruUtil.decodeLength(self.data[index]) + self.productPartModelName = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productPartModelName:%s" % self.productPartModelName) + + templen = FruUtil.decodeLength(self.data[index]) + self.productVersion = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productVersion:%s" % self.productVersion) + + templen = FruUtil.decodeLength(self.data[index]) + self.productSerialNumber = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productSerialNumber:%s" % self.productSerialNumber) + + templen = FruUtil.decodeLength(self.data[index]) + self.productAssetTag = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productAssetTag:%s" % self.productAssetTag) + + templen = FruUtil.decodeLength(self.data[index]) + self.fruFileId = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode fruFileId:%s" % self.fruFileId) + + for i in range(1, 11): + valtmp = "productextra%d" % i + if self.data[index] != chr(0xc1) and index < self.size - 1: + templen = FruUtil.decodeLength(self.data[index]) + if templen == 0: + break + tmpval = self.data[index + 1: index + templen + 1] + d_print("decode boardextra%d:%s" % (i, tmpval)) + setattr(self, valtmp, tmpval) + index += templen + 1 + else: + break + + @property + def productVersion(self): + return self._productVersion + + @productVersion.setter + def productVersion(self, name): + self._productVersion = name + + @property + def areaversion(self): + self._areaversion = self.COMMON_HEAD_VERSION + return self._areaversion + + @areaversion.setter + def areaversion(self, name): + self._areaversion = name + + @property + def language(self): + self._language = 25 + return self._language + + @property + def productManufacturer(self): + return self._productManufacturer + + @productManufacturer.setter + def productManufacturer(self, name): + self._productManufacturer = name + + @property + def productName(self): + return self._productName + + @productName.setter + def productName(self, name): + self._productName = name + + @property + def productPartModelName(self): + return self._productPartModelName + + @productPartModelName.setter + def productPartModelName(self, name): + self._productPartModelName = name + + @property + def productSerialNumber(self): + return self._productSerialNumber + + @productSerialNumber.setter + def productSerialNumber(self, name): + self._productSerialNumber = name + + @property + def productAssetTag(self): + return self._productAssetTag + + @productAssetTag.setter + def productAssetTag(self, name): + self._productAssetTag = name + + @property + def fruFileId(self): + return self._FRUFileID + + @fruFileId.setter + def fruFileId(self, name): + self._FRUFileID = name + + def fruSetValue(self, field, value): + tmp_field = getattr(self, field, None) + if tmp_field is not None: + setattr(self, field, value) + + def recalcute(self): + d_print("product version:%x" % ord(self.areaversion)) + d_print("product length:%d" % self.size) + d_print("product language:%x" % self.language) + self.data = chr(ord(self.areaversion)) + \ + chr(self.size // 8) + chr(self.language) + + typelength = FruUtil.getTypeLength(self.productManufacturer) + self.data += chr(typelength) + self.data += self.productManufacturer + + self.data += chr(FruUtil.getTypeLength(self.productName)) + self.data += self.productName + + self.data += chr(FruUtil.getTypeLength(self.productPartModelName)) + self.data += self.productPartModelName + + self.data += chr(FruUtil.getTypeLength(self.productVersion)) + self.data += self.productVersion + + self.data += chr(FruUtil.getTypeLength(self.productSerialNumber)) + self.data += self.productSerialNumber + + self.data += chr(FruUtil.getTypeLength(self.productAssetTag)) + if self.productAssetTag is not None: + self.data += self.productAssetTag + + self.data += chr(FruUtil.getTypeLength(self.fruFileId)) + self.data += self.fruFileId + + for i in range(1, 11): + valtmp = "productextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + d_print("boardInfoArea productextra%d:%s" % (i, valtmpval)) + self.data += chr(FruUtil.getTypeLength(valtmpval)) + if valtmpval is not None: + self.data += valtmpval + else: + break + + self.data += chr(0xc1) + if len(self.data) > (self.size - 1): + incr = (len(self.data) - self.size) // 8 + 1 + self.size += incr * 8 + d_print("self.data:%d" % len(self.data)) + d_print("self.size:%d" % self.size) + + self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] + self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) + checksum = FruUtil.checksum(self.data) + d_print("board info checksum:%x" % checksum) + self.data += chr(checksum) + + +class MultiRecordArea(BaseArea): + pass + + +class Field(object): + + def __init__(self, fieldType="ASCII", fieldData=""): + self.fieldData = fieldData + self.fieldType = fieldType + + @property + def fieldType(self): + return self.fieldType + + @property + def fieldData(self): + return self.fieldData + + +class ipmifru(BaseArea): + _BoardInfoArea = None + _ProductInfoArea = None + _InternalUseArea = None + _ChassisInfoArea = None + _multiRecordArea = None + _productinfoAreaOffset = BaseArea.INITVALUE + _boardInfoAreaOffset = BaseArea.INITVALUE + _internalUserAreaOffset = BaseArea.INITVALUE + _chassicInfoAreaOffset = BaseArea.INITVALUE + _multiRecordAreaOffset = BaseArea.INITVALUE + _bindata = None + _bodybin = None + _version = BaseArea.COMMON_HEAD_VERSION + _zeroCheckSum = None + _frusize = 256 + + def __str__(self): + tmpstr = "" + if self.boardInfoArea.isPresent: + tmpstr += "\nboardinfoarea: \n" + tmpstr += self.boardInfoArea.__str__() + if self.productInfoArea.isPresent: + tmpstr += "\nproductinfoarea: \n" + tmpstr += self.productInfoArea.__str__() + return tmpstr + + def decodeBin(self, eeprom): + commonHead = eeprom[0:8] + d_print("decode version %x" % ord(commonHead[0])) + if ord(self.COMMON_HEAD_VERSION) != ord(commonHead[0]): + raise FruException("HEAD VERSION error,not Fru format!", -10) + if FruUtil.checksum(commonHead[0:7]) != ord(commonHead[7]): + strtemp = "check header checksum error [cal:%02x data:%02x]" % ( + FruUtil.checksum(commonHead[0:7]), ord(commonHead[7])) + raise FruException(strtemp, -3) + if ord(commonHead[1]) != ord(self.INITVALUE): + d_print("Internal Use Area is present") + self.internalUseArea = InternalUseArea( + name="Internal Use Area", size=self.SUGGESTED_SIZE_INTERNAL_USE_AREA) + self.internalUseArea.isPresent = True + self.internalUserAreaOffset = ord(commonHead[1]) + self.internalUseArea.data = eeprom[self.internalUserAreaOffset * 8: ( + self.internalUserAreaOffset * 8 + self.internalUseArea.size)] + if ord(commonHead[2]) != ord(self.INITVALUE): + d_print("Chassis Info Area is present") + self.chassisInfoArea = ChassisInfoArea( + name="Chassis Info Area", size=self.SUGGESTED_SIZE_CHASSIS_INFO_AREA) + self.chassisInfoArea.isPresent = True + self.chassicInfoAreaOffset = ord(commonHead[2]) + self.chassisInfoArea.data = eeprom[self.chassicInfoAreaOffset * 8: ( + self.chassicInfoAreaOffset * 8 + self.chassisInfoArea.size)] + if ord(commonHead[3]) != ord(self.INITVALUE): + self.boardInfoArea = BoardInfoArea( + name="Board Info Area", size=self.SUGGESTED_SIZE_BOARD_INFO_AREA) + self.boardInfoArea.isPresent = True + self.boardInfoAreaOffset = ord(commonHead[3]) + self.boardInfoArea.size = ord( + eeprom[self.boardInfoAreaOffset * 8 + 1]) * 8 + d_print("Board Info Area is present size:%d" % + (self.boardInfoArea.size)) + self.boardInfoArea.data = eeprom[self.boardInfoAreaOffset * 8: ( + self.boardInfoAreaOffset * 8 + self.boardInfoArea.size)] + if FruUtil.checksum(self.boardInfoArea.data[:-1]) != ord(self.boardInfoArea.data[-1:]): + strtmp = "check boardInfoArea checksum error[cal:%02x data:%02x]" % \ + (FruUtil.checksum( + self.boardInfoArea.data[:-1]), ord(self.boardInfoArea.data[-1:])) + raise FruException(strtmp, -3) + self.boardInfoArea.decodedata() + if ord(commonHead[4]) != ord(self.INITVALUE): + d_print("Product Info Area is present") + self.productInfoArea = ProductInfoArea( + name="Product Info Area ", size=self.SUGGESTED_SIZE_PRODUCT_INFO_AREA) + self.productInfoArea.isPresent = True + self.productinfoAreaOffset = ord(commonHead[4]) + d_print("length offset value: %02x" % + ord(eeprom[self.productinfoAreaOffset * 8 + 1])) + self.productInfoArea.size = ord( + eeprom[self.productinfoAreaOffset * 8 + 1]) * 8 + d_print("Product Info Area is present size:%d" % + (self.productInfoArea.size)) + + self.productInfoArea.data = eeprom[self.productinfoAreaOffset * 8: ( + self.productinfoAreaOffset * 8 + self.productInfoArea.size)] + if FruUtil.checksum(self.productInfoArea.data[:-1]) != ord(self.productInfoArea.data[-1:]): + strtmp = "check productInfoArea checksum error [cal:%02x data:%02x]" % ( + FruUtil.checksum(self.productInfoArea.data[:-1]), ord(self.productInfoArea.data[-1:])) + raise FruException(strtmp, -3) + self.productInfoArea.decodedata() + if ord(commonHead[5]) != ord(self.INITVALUE): + self.multiRecordArea = MultiRecordArea( + name="MultiRecord record Area ") + d_print("MultiRecord record present") + self.multiRecordArea.isPresent = True + self.multiRecordAreaOffset = ord(commonHead[5]) + self.multiRecordArea.data = eeprom[self.multiRecordAreaOffset * 8: ( + self.multiRecordAreaOffset * 8 + self.multiRecordArea.size)] + + def initDefault(self): + self.version = self.COMMON_HEAD_VERSION + self.internalUserAreaOffset = self.INITVALUE + self.chassicInfoAreaOffset = self.INITVALUE + self.boardInfoAreaOffset = self.INITVALUE + self.productinfoAreaOffset = self.INITVALUE + self.multiRecordAreaOffset = self.INITVALUE + self.zeroCheckSum = self.INITVALUE + self.offset = self.SUGGESTED_SIZE_COMMON_HEADER + self.productInfoArea = None + self.internalUseArea = None + self.boardInfoArea = None + self.chassisInfoArea = None + self.multiRecordArea = None + # self.recalcute() + + @property + def version(self): + return self._version + + @version.setter + def version(self, name): + self._version = name + + @property + def internalUserAreaOffset(self): + return self._internalUserAreaOffset + + @internalUserAreaOffset.setter + def internalUserAreaOffset(self, obj): + self._internalUserAreaOffset = obj + + @property + def chassicInfoAreaOffset(self): + return self._chassicInfoAreaOffset + + @chassicInfoAreaOffset.setter + def chassicInfoAreaOffset(self, obj): + self._chassicInfoAreaOffset = obj + + @property + def productinfoAreaOffset(self): + return self._productinfoAreaOffset + + @productinfoAreaOffset.setter + def productinfoAreaOffset(self, obj): + self._productinfoAreaOffset = obj + + @property + def boardInfoAreaOffset(self): + return self._boardInfoAreaOffset + + @boardInfoAreaOffset.setter + def boardInfoAreaOffset(self, obj): + self._boardInfoAreaOffset = obj + + @property + def multiRecordAreaOffset(self): + return self._multiRecordAreaOffset + + @multiRecordAreaOffset.setter + def multiRecordAreaOffset(self, obj): + self._multiRecordAreaOffset = obj + + @property + def zeroCheckSum(self): + return self._zeroCheckSum + + @zeroCheckSum.setter + def zeroCheckSum(self, obj): + self._zeroCheckSum = obj + + @property + def productInfoArea(self): + return self._ProductInfoArea + + @productInfoArea.setter + def productInfoArea(self, obj): + self._ProductInfoArea = obj + + @property + def internalUseArea(self): + return self._InternalUseArea + + @internalUseArea.setter + def internalUseArea(self, obj): + self.internalUseArea = obj + + @property + def boardInfoArea(self): + return self._BoardInfoArea + + @boardInfoArea.setter + def boardInfoArea(self, obj): + self._BoardInfoArea = obj + + @property + def chassisInfoArea(self): + return self._ChassisInfoArea + + @chassisInfoArea.setter + def chassisInfoArea(self, obj): + self._ChassisInfoArea = obj + + @property + def multiRecordArea(self): + return self._multiRecordArea + + @multiRecordArea.setter + def multiRecordArea(self, obj): + self._multiRecordArea = obj + + @property + def bindata(self): + return self._bindata + + @bindata.setter + def bindata(self, obj): + self._bindata = obj + + @property + def bodybin(self): + return self._bodybin + + @bodybin.setter + def bodybin(self, obj): + self._bodybin = obj + + def recalcuteCommonHead(self): + self.bindata = "" + self.offset = self.SUGGESTED_SIZE_COMMON_HEADER + d_print("common Header %d" % self.offset) + d_print("fru eeprom size %d" % self._frusize) + if self.internalUseArea is not None and self.internalUseArea.isPresent: + self.internalUserAreaOffset = self.offset // 8 + self.offset += self.internalUseArea.size + d_print("internalUseArea is present offset:%d" % self.offset) + + if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: + self.chassicInfoAreaOffset = self.offset // 8 + self.offset += self.chassisInfoArea.size + d_print("chassisInfoArea is present offset:%d" % self.offset) + + if self.boardInfoArea is not None and self.boardInfoArea.isPresent: + self.boardInfoAreaOffset = self.offset // 8 + self.offset += self.boardInfoArea.size + d_print("boardInfoArea is present offset:%d" % self.offset) + d_print("boardInfoArea is present size:%d" % + self.boardInfoArea.size) + + if self.productInfoArea is not None and self.productInfoArea.isPresent: + self.productinfoAreaOffset = self.offset // 8 + self.offset += self.productInfoArea.size + d_print("productInfoArea is present offset:%d" % self.offset) + + if self.multiRecordArea is not None and self.multiRecordArea.isPresent: + self.multiRecordAreaOffset = self.offset // 8 + d_print("multiRecordArea is present offset:%d" % self.offset) + + if self.internalUserAreaOffset == self.INITVALUE: + self.internalUserAreaOffset = 0 + if self.productinfoAreaOffset == self.INITVALUE: + self.productinfoAreaOffset = 0 + if self.chassicInfoAreaOffset == self.INITVALUE: + self.chassicInfoAreaOffset = 0 + if self.boardInfoAreaOffset == self.INITVALUE: + self.boardInfoAreaOffset = 0 + if self.multiRecordAreaOffset == self.INITVALUE: + self.multiRecordAreaOffset = 0 + + self.zeroCheckSum = (0x100 - ord(self.version) - self.internalUserAreaOffset - self.chassicInfoAreaOffset - self.productinfoAreaOffset + - self.boardInfoAreaOffset - self.multiRecordAreaOffset) & 0xff + d_print("zerochecksum:%x" % self.zeroCheckSum) + self.data = "" + self.data += chr(self.version[0]) + chr(self.internalUserAreaOffset) + chr(self.chassicInfoAreaOffset) + chr( + self.boardInfoAreaOffset) + chr(self.productinfoAreaOffset) + chr(self.multiRecordAreaOffset) + chr(self.INITVALUE[0]) + chr(self.zeroCheckSum) + + self.bindata = self.data + self.bodybin + totallen = len(self.bindata) + d_print("totallen %d" % totallen) + if totallen < self._frusize: + self.bindata = self.bindata.ljust(self._frusize, chr(self.INITVALUE[0])) + else: + raise FruException('bin data more than %d' % self._frusize, -2) + + def recalcutebin(self): + self.bodybin = "" + if self.internalUseArea is not None and self.internalUseArea.isPresent: + d_print("internalUseArea present") + self.bodybin += self.internalUseArea.data + if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: + d_print("chassisInfoArea present") + self.bodybin += self.chassisInfoArea.data + if self.boardInfoArea is not None and self.boardInfoArea.isPresent: + d_print("boardInfoArea present") + self.boardInfoArea.recalcute() + self.bodybin += self.boardInfoArea.data + if self.productInfoArea is not None and self.productInfoArea.isPresent: + d_print("productInfoAreapresent") + self.productInfoArea.recalcute() + self.bodybin += self.productInfoArea.data + if self.multiRecordArea is not None and self.multiRecordArea.isPresent: + d_print("multiRecordArea present") + self.bodybin += self.productInfoArea.data + + def recalcute(self, fru_eeprom_size=256): + self._frusize = fru_eeprom_size + self.recalcutebin() + self.recalcuteCommonHead() + + def setValue(self, area, field, value): + tmp_area = getattr(self, area, None) + if tmp_area is not None: + tmp_area.fruSetValue(field, value) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/onietlv.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/onietlv.py new file mode 100644 index 000000000000..a90f8f8453c8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/onietlv.py @@ -0,0 +1,441 @@ +#!/usr/bin/python3 +import binascii + + +class OnietlvException(Exception): + def __init__(self, message='onietlverror', code=-100): + err = 'errcode: {0} message:{1}'.format(code, message) + Exception.__init__(self, err) + self.code = code + self.message = message + + +class onie_tlv(object): + TLV_INFO_ID_STRING = "TlvInfo\x00" + TLV_INFO_INIA_ID = "\x00\x00\x13\x11" + TLV_INFO_VERSION = 0x01 + TLV_INFO_LENGTH = 0x00 + TLV_INFO_LENGTH_VALUE = 0xba + + TLV_CODE_PRODUCT_NAME = 0x21 + TLV_CODE_PART_NUMBER = 0x22 + TLV_CODE_SERIAL_NUMBER = 0x23 + TLV_CODE_MAC_BASE = 0x24 + TLV_CODE_MANUF_DATE = 0x25 + TLV_CODE_DEVICE_VERSION = 0x26 + TLV_CODE_LABEL_REVISION = 0x27 + TLV_CODE_PLATFORM_NAME = 0x28 + TLV_CODE_ONIE_VERSION = 0x29 + TLV_CODE_MAC_SIZE = 0x2A + TLV_CODE_MANUF_NAME = 0x2B + TLV_CODE_MANUF_COUNTRY = 0x2C + TLV_CODE_VENDOR_NAME = 0x2D + TLV_CODE_DIAG_VERSION = 0x2E + TLV_CODE_SERVICE_TAG = 0x2F + TLV_CODE_VENDOR_EXT = 0xFD + TLV_CODE_CRC_32 = 0xFE + _TLV_DISPLAY_VENDOR_EXT = 1 + TLV_CODE_WB_CARID = 0x01 + _TLV_INFO_HDR_LEN = 11 + TLV_CODE_PRODUCT_ID = 0x40 + TLV_CODE_HW_VERSION = 0x41 + TLV_CODE_MAIN_FILENAME = 0x42 + TLV_CODE_DTS_FINENAME = 0x43 + TLV_CODE_SY_SERIAL0 = 0x44 + TLV_CODE_SY_SERIAL1 = 0x45 + TLV_CODE_SY_SERIAL2 = 0x46 + TLV_CODE_SY_SERIAL3 = 0x47 + TLV_CODE_PROJECT_ID = 0x48 + TLV_CODE_SETMAC_VERSION = 0x49 + TLV_CODE_EEPROM_TYPE = 0x4A + + @property + def dstatus(self): + return self._dstatus + + @property + def cardid(self): + return self._cardid + + @property + def productname(self): + return self._productname + + @property + def partnum(self): + return self._partnum + + @property + def serialnum(self): + return self._serialnum + + @property + def macbase(self): + return self._macbase + + @property + def manufdate(self): + return self._manufdate + + @property + def deviceversion(self): + return self._deviceversion + + @property + def labelrevision(self): + return self._labelrevision + + @property + def platformname(self): + return self._platformname + + @property + def onieversion(self): + return self._onieversion + + @property + def macsize(self): + return self._macsize + + @property + def manufname(self): + return self._manufname + + @property + def manufcountry(self): + return self._manufcountry + + @property + def vendorname(self): + return self._vendorname + + @property + def diagname(self): + return self._diagname + + @property + def servicetag(self): + return self._servicetag + + @property + def vendorext(self): + return self._vendorext + + def __init__(self): + self._cardid = "" + self._productname = "" + self._partnum = "" + self._serialnum = "" + self._macbase = "" + self._manufdate = "" + self._deviceversion = "" + self._labelrevision = "" + self._platformname = "" + self._onieversion = "" + self._macsize = "" + self._manufname = "" + self._manufcountry = "" + self._vendorname = "" + self._diagname = "" + self._servicetag = "" + self._vendorext = "" + self._productid = "" + self._hwversion = "" + self._mainfilename = "" + self._dtsfilename = "" + self._syserial0 = "" + self._syserial1 = "" + self._syserial2 = "" + self._syserial3 = "" + self._projectid = "" + self._setmacversion = "" + self._eepromtype = "" + self._crc32 = "" + self._dstatus = 0 + + def oniecrc32(self, v): + data_array = bytearray() + for x in v: + data_array.append(ord(x)) + return '0x%08x' % (binascii.crc32(bytes(data_array)) & 0xffffffff) + + def getTLV_BODY(self, tlv_type, value): + x = [] + temp_t = "" + if tlv_type == self.TLV_CODE_MAC_BASE: + arr = value.split(':') + for tt in arr: + temp_t += chr(int(tt, 16)) + elif tlv_type == self.TLV_CODE_DEVICE_VERSION: + temp_t = chr(value) + elif tlv_type == self.TLV_CODE_MAC_SIZE: + temp_t = chr(value >> 8) + chr(value & 0x00ff) + else: + temp_t = value + x.append(chr(tlv_type)) + x.append(chr(len(temp_t))) + for i in temp_t: + x.append(i) + return x + + def generate_ext(self, cardid): + s = "%08x" % cardid + ret = "" + for t in range(0, 4): + ret += chr(int(s[2 * t:2 * t + 2], 16)) + ret = chr(0x01) + chr(len(ret)) + ret + return ret + + def generate_value(self, _t): + ret = [] + for i in self.TLV_INFO_ID_STRING: + ret.append(i) + ret.append(chr(self.TLV_INFO_VERSION)) + ret.append(chr(self.TLV_INFO_LENGTH)) + ret.append(chr(self.TLV_INFO_LENGTH_VALUE)) + + total_len = 0 + for key in _t: + x = self.getTLV_BODY(key, _t[key]) + ret += x + total_len += len(x) + ret[10] = chr(total_len + 6) + + ret.append(chr(0xFE)) + ret.append(chr(0x04)) + s = self.oniecrc32(''.join(ret)) + for t in range(0, 4): + ret.append(chr(int(s[2 * t + 2:2 * t + 4], 16))) + totallen = len(ret) + if totallen < 256: + for left_t in range(0, 256 - totallen): + ret.append(chr(0x00)) + return (ret, True) + + def decode_tlv(self, e): + tlv_index = 0 + tlv_end = len(e) + ret = [] + while tlv_index < tlv_end and (tlv_index + 2 + ord(e[tlv_index + 1])) <= len(e): + rt = self.decoder(e[tlv_index:tlv_index + 2 + ord(e[tlv_index + 1])]) + ret.append(rt) + if ord(e[tlv_index]) == self.TLV_CODE_CRC_32: + break + tlv_index += ord(e[tlv_index + 1]) + 2 + return ret + + def decode(self, e): + if e[0:8] != self.TLV_INFO_ID_STRING: + raise OnietlvException("ONIE tlv head info error,not onie tlv type", -1) + total_len = (ord(e[9]) << 8) | ord(e[10]) + tlv_index = self._TLV_INFO_HDR_LEN + tlv_end = self._TLV_INFO_HDR_LEN + total_len + if tlv_end > len(e): + raise OnietlvException("ONIE tlv length error", -2) + ret = [] + ret = self.decode_tlv(e[tlv_index:tlv_end]) + for item in ret: + if item['code'] == self.TLV_CODE_VENDOR_EXT: + if item["value"][0:4] == self.TLV_INFO_INIA_ID: + rt = self.decode_tlv(item["value"][4:]) + else: + rt = self.decode_tlv(item["value"][0:]) + ret.extend(rt) + return ret + + def decoder(self, t): + if ord(t[0]) == self.TLV_CODE_PRODUCT_NAME: + name = "Product Name" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._productname = value + elif ord(t[0]) == self.TLV_CODE_PART_NUMBER: + name = "Part Number" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._partnum = value + elif ord(t[0]) == self.TLV_CODE_SERIAL_NUMBER: + name = "Serial Number" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._serialnum = value + elif ord(t[0]) == self.TLV_CODE_MAC_BASE: + name = "Base MAC Address" + _len = ord(t[1]) + value = ":".join(['%02X' % ord(T) for T in t[2:8]]).upper() + self._macbase = value + elif ord(t[0]) == self.TLV_CODE_MANUF_DATE: + name = "Manufacture Date" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._manufdate = value + elif ord(t[0]) == self.TLV_CODE_DEVICE_VERSION: + name = "Device Version" + _len = ord(t[1]) + value = ord(t[2]) + self._deviceversion = value + elif ord(t[0]) == self.TLV_CODE_LABEL_REVISION: + name = "Label Revision" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._labelrevision = value + elif ord(t[0]) == self.TLV_CODE_PLATFORM_NAME: + name = "Platform Name" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._platformname = value + elif ord(t[0]) == self.TLV_CODE_ONIE_VERSION: + name = "ONIE Version" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._onieversion = value + elif ord(t[0]) == self.TLV_CODE_MAC_SIZE: + name = "MAC Addresses" + _len = ord(t[1]) + value = str((ord(t[2]) << 8) | ord(t[3])) + self._macsize = value + elif ord(t[0]) == self.TLV_CODE_MANUF_NAME: + name = "Manufacturer" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._manufname = value + elif ord(t[0]) == self.TLV_CODE_MANUF_COUNTRY: + name = "Manufacture Country" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._manufcountry = value + elif ord(t[0]) == self.TLV_CODE_VENDOR_NAME: + name = "Vendor Name" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._vendorname = value + elif ord(t[0]) == self.TLV_CODE_DIAG_VERSION: + name = "Diag Version" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._diagname = value + elif ord(t[0]) == self.TLV_CODE_SERVICE_TAG: + name = "Service Tag" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._servicetag = value + elif ord(t[0]) == self.TLV_CODE_VENDOR_EXT: + name = "Vendor Extension" + _len = ord(t[1]) + value = "" + if self._TLV_DISPLAY_VENDOR_EXT: + value = t[2:2 + ord(t[1])] + self._vendorext = value + elif ord(t[0]) == self.TLV_CODE_CRC_32 and len(t) == 6: + name = "CRC-32" + _len = ord(t[1]) + value = "0x%08X" % (((ord(t[2]) << 24) | ( + ord(t[3]) << 16) | (ord(t[4]) << 8) | ord(t[5])),) + self._crc32 = value + elif ord(t[0]) == self.TLV_CODE_WB_CARID: + name = "Card id" + _len = ord(t[1]) + value = "" + for c in t[2:2 + ord(t[1])]: + value += "%02X" % (ord(c),) + self._cardid = value + elif ord(t[0]) == self.TLV_CODE_PRODUCT_ID: + name = "Product id" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._productid = value + elif ord(t[0]) == self.TLV_CODE_HW_VERSION: + name = "Hardware Version" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._hwversion = value + elif ord(t[0]) == self.TLV_CODE_MAIN_FILENAME: + name = "Main File Name" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._mainfilename = value + elif ord(t[0]) == self.TLV_CODE_DTS_FINENAME: + name = "DTS File Name" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._dtsfilename = value + elif ord(t[0]) == self.TLV_CODE_SY_SERIAL0: + name = "SY Serial 0" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._syserial0 = value + elif ord(t[0]) == self.TLV_CODE_SY_SERIAL1: + name = "SY Serial 1" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._syserial1 = value + elif ord(t[0]) == self.TLV_CODE_SY_SERIAL2: + name = "SY Serial 2" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._syserial2 = value + elif ord(t[0]) == self.TLV_CODE_SY_SERIAL3: + name = "SY Serial 3" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._syserial3 = value + elif ord(t[0]) == self.TLV_CODE_PROJECT_ID: + name = "Project id" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._projectid = value + elif ord(t[0]) == self.TLV_CODE_SETMAC_VERSION: + name = "Setmac Version" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._setmacversion = value + elif ord(t[0]) == self.TLV_CODE_EEPROM_TYPE: + name = "EEPROM Type" + _len = ord(t[1]) + value = "" + for c in t[2:2 + ord(t[1])]: + value += "%02X" % (ord(c),) + self._eepromtype = value + else: + name = "Unknown" + _len = ord(t[1]) + value = "" + for c in t[2:2 + ord(t[1])]: + value += "0x%02X " % (ord(c),) + return {"name": name, "code": ord(t[0]), "value": value, "lens": _len} + + def __str__(self): + formatstr = "Card id : %s \n" \ + "Product Name : %s \n" \ + "Part Number : %s \n" \ + "Serial Number : %s \n" \ + "Base MAC Address : %s \n" \ + "Manufacture Date : %s \n" \ + "Device Version : %s \n" \ + "Label Revision : %s \n" \ + "Platform Name : %s \n" \ + "ONIE Version : %s \n" \ + "MAC Addresses : %s \n" \ + "Manufacturer : %s \n" \ + "Manufacture Country : %s \n" \ + "Vendor Name : %s \n" \ + "Diag Version : %s \n" \ + "Service Tag : %s \n" \ + "CRC-32 : %s \n" + return formatstr % (self._cardid, + self._productname, + self._partnum, + self._serialnum, + self._macbase, + self._manufdate, + self._deviceversion, + self._labelrevision, + self._platformname, + self._onieversion, + self._macsize, + self._manufname, + self._manufcountry, + self._vendorname, + self._diagname, + self._servicetag, + self._crc32) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/baseutil.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/baseutil.py new file mode 100644 index 000000000000..5260107c91be --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/baseutil.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 +####################################################### +# +# baseutil.py +# Python implementation of the Class baseutil +# +####################################################### +import importlib.machinery +import os +import syslog +import json +from plat_hal.osutil import osutil + +SYSLOG_IDENTIFIER = "HAL" + +CONFIG_DB_PATH = "/etc/sonic/config_db.json" +BOARD_ID_PATH = "/sys/module/platform_common/parameters/dfd_my_type" +BOARD_AIRFLOW_PATH = "/etc/sonic/.airflow" + + +def getonieplatform(path): + if not os.path.isfile(path): + return "" + machine_vars = {} + with open(path) as machine_file: + for line in machine_file: + tokens = line.split('=') + if len(tokens) < 2: + continue + machine_vars[tokens[0]] = tokens[1].strip() + return machine_vars.get("onie_platform") + + +def getboardid(): + if not os.path.exists(BOARD_ID_PATH): + return "NA" + with open(BOARD_ID_PATH) as fd: + id_str = fd.read().strip() + return "0x%x" % (int(id_str, 10)) + + +def getboardairflow(): + if not os.path.exists(BOARD_AIRFLOW_PATH): + return "NA" + with open(BOARD_AIRFLOW_PATH) as fd: + airflow_str = fd.read().strip() + data = json.loads(airflow_str) + airflow = data.get("board", "NA") + return airflow + + +def getplatform_config_db(): + if not os.path.isfile(CONFIG_DB_PATH): + return "" + val = os.popen("sonic-cfggen -j %s -v DEVICE_METADATA.localhost.platform" % CONFIG_DB_PATH).read().strip() + if len(val) <= 0: + return "" + return val + + +def getplatform_name(): + if os.path.isfile('/host/machine.conf'): + return getonieplatform('/host/machine.conf') + if os.path.isfile('/etc/sonic/machine.conf'): + return getonieplatform('/etc/sonic/machine.conf') + return getplatform_config_db() + + +platform = (getplatform_name()).replace("-", "_") +boardid = getboardid() +boardairflow = getboardairflow() + + +CONFIG_FILE_PATH_LIST = [ + "/usr/local/bin/", + "/usr/lib/python3/dist-packages/", + "/usr/local/lib/python3.7/dist-packages/hal-config/", + "/usr/local/lib/python3.9/dist-packages/hal-config/" +] + + +DEVICE_CONFIG_FILE_LIST = [ + platform + "_" + boardid + "_" + boardairflow + "_device.py", + platform + "_" + boardid + "_device.py", + platform + "_" + boardairflow + "_device.py", + platform + "_device.py" +] + + +MONITOR_CONFIG_FILE_LIST = [ + platform + "_" + boardid + "_" + boardairflow + "_monitor.py", + platform + "_" + boardid + "_monitor.py", + platform + "_" + boardairflow + "_monitor.py", + platform + "_monitor.py" +] + + +class baseutil: + + CONFIG_NAME = 'devices' + MONITOR_CONFIG_NAME = 'monitor' + UBOOT_ENV_URL = '/etc/device/uboot_env' + + @staticmethod + def get_config(): + real_path = None + for configfile_path in CONFIG_FILE_PATH_LIST: + for config_file in DEVICE_CONFIG_FILE_LIST: + file = configfile_path + config_file + if os.path.exists(file): + real_path = file + break + if real_path is not None: + break + + if real_path is None: + raise Exception("get hal device config error") + devices = importlib.machinery.SourceFileLoader(baseutil.CONFIG_NAME, real_path).load_module() + return devices.devices + + @staticmethod + def get_monitor_config(): + real_path = None + for configfile_path in CONFIG_FILE_PATH_LIST: + for config_file in MONITOR_CONFIG_FILE_LIST: + file = configfile_path + config_file + if os.path.exists(file): + real_path = file + break + if real_path is not None: + break + + if real_path is None: + raise Exception("get hal monitor config error") + monitor = importlib.machinery.SourceFileLoader(baseutil.MONITOR_CONFIG_NAME, real_path).load_module() + return monitor.monitor + + @staticmethod + def get_productname(): + ret, val = osutil.command("cat %s |grep productname | awk -F\"=\" '{print $2;}'" % baseutil.UBOOT_ENV_URL) + tmp = val.lower().replace('-', '_') + if ret != 0 or len(val) <= 0: + raise Exception("get productname error") + return tmp + + @staticmethod + def get_platform(): + ret, val = osutil.command("cat %s |grep conffitname | awk -F\"=\" '{print $2;}'" % baseutil.UBOOT_ENV_URL) + if ret != 0 or len(val) <= 0: + raise Exception("get platform error") + return val + + @staticmethod + def get_product_fullname(): + ret, val = osutil.command("cat %s |grep productname | awk -F\"=\" '{print $2;}'" % baseutil.UBOOT_ENV_URL) + if ret != 0 or len(val) <= 0: + raise Exception("get productname error") + return val + + @staticmethod + def logger_debug(msg): + syslog.openlog(SYSLOG_IDENTIFIER) + syslog.syslog(syslog.LOG_DEBUG, msg) + syslog.closelog() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/chassisbase.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/chassisbase.py new file mode 100644 index 000000000000..767d6da34ba9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/chassisbase.py @@ -0,0 +1,318 @@ +#!/usr/bin/env python3 +####################################################### +# +# chassisbase.py +# Python implementation of the Class chassisbase +# +####################################################### +from plat_hal.dcdc import dcdc +from plat_hal.onie_e2 import onie_e2 +from plat_hal.psu import psu +from plat_hal.led import led +from plat_hal.temp import temp +from plat_hal.fan import fan +from plat_hal.cpld import cpld +from plat_hal.component import component +from plat_hal.cpu import cpu +from plat_hal.baseutil import baseutil + + +class chassisbase(object): + __onie_e2_list = [] + __psu_list = [] + __led_list = [] + __temp_list = [] + __fan_list = [] + __card_list = [] + __sensor_list = [] + __dcdc_list = [] + __cpld_list = [] + __comp_list = [] + __bios_list = [] + __bmc_list = [] + __cpu = None + + def __init__(self, conftype=0, conf=None): + # type: (object, object, object) -> object + """ + init chassisbase as order + + type = 0 use default conf, maybe auto find by platform + type = 1 use given conf, conf is not None + + BITMAP + bit 16 + bit 0 PSU + bit 1 LED + bit 2 TEMP + bit 3 fan + bit 4 card + bit 5 sensor + """ + __confTemp = None + + if conftype == 0: + # user + __confTemp = baseutil.get_config() + elif conftype == 1: + __confTemp = conf + + # onie_e2 + onie_e2temp = [] + onie_e2config = __confTemp.get('onie_e2', []) + for item in onie_e2config: + onie_e2_1 = onie_e2(item) + onie_e2temp.append(onie_e2_1) + self.onie_e2_list = onie_e2temp + + # psu + psutemp = [] + psuconfig = __confTemp.get('psus', []) + for item in psuconfig: + psu1 = psu(item) + psutemp.append(psu1) + self.psu_list = psutemp + + # led + ledtemp = [] + ledconfig = __confTemp.get('leds', []) + for item in ledconfig: + led1 = led(item) + ledtemp.append(led1) + self.led_list = ledtemp + + # temp + temptemp = [] + tempconfig = __confTemp.get('temps', []) + for item in tempconfig: + temp1 = temp(item) + temptemp.append(temp1) + self.temp_list = temptemp + + # fan + fantemp = [] + fanconfig = __confTemp.get('fans', []) + for item in fanconfig: + fan1 = fan(item) + fantemp.append(fan1) + self.fan_list = fantemp + + # dcdc + dcdctemp = [] + dcdcconfig = __confTemp.get('dcdc', []) + for item in dcdcconfig: + dcdc1 = dcdc(item) + dcdctemp.append(dcdc1) + self.dcdc_list = dcdctemp + + # cpld + cpldtemp = [] + cpldconfig = __confTemp.get('cplds', []) + for item in cpldconfig: + cpld1 = cpld(item) + cpldtemp.append(cpld1) + self.cpld_list = cpldtemp + + # compoment: cpld/fpga/bios + comptemp = [] + compconfig = __confTemp.get('comp_cpld', []) + for item in compconfig: + comp1 = component(item) + comptemp.append(comp1) + self.comp_list = comptemp + + compconfig = __confTemp.get('comp_fpga', []) + for item in compconfig: + comp1 = component(item) + self.comp_list.append(comp1) + + compconfig = __confTemp.get('comp_bios', []) + for item in compconfig: + comp1 = component(item) + self.comp_list.append(comp1) + + # cpu + cpuconfig = __confTemp.get('cpu', []) + if len(cpuconfig): + self.cpu = cpu(cpuconfig[0]) + + # dcdc + @property + def dcdc_list(self): + return self.__dcdc_list + + @dcdc_list.setter + def dcdc_list(self, val): + self.__dcdc_list = val + + # sensor + @property + def sensor_list(self): + return self.__sensor_list + + @sensor_list.setter + def sensor_list(self, val): + self.__sensor_list = val + + def get_sensor_byname(self, name): + tmp = self.sensor_list + for item in tmp: + if name == item.name: + return item + return None + + # onie_e2 + @property + def onie_e2_list(self): + return self.__onie_e2_list + + @onie_e2_list.setter + def onie_e2_list(self, val): + self.__onie_e2_list = val + + def get_onie_e2_byname(self, name): + tmp = self.onie_e2_list + for item in tmp: + if name == item.name: + return item + return None + + # psu + @property + def psu_list(self): + return self.__psu_list + + @psu_list.setter + def psu_list(self, val): + self.__psu_list = val + + def get_psu_byname(self, name): + tmp = self.psu_list + for item in tmp: + if name == item.name: + return item + return None + + # fan + @property + def fan_list(self): + return self.__fan_list + + @fan_list.setter + def fan_list(self, val): + self.__fan_list = val + + def get_fan_byname(self, name): + tmp = self.fan_list + for item in tmp: + if name == item.name: + return item + return None + + # led + + @property + def led_list(self): + return self.__led_list + + @led_list.setter + def led_list(self, val): + self.__led_list = val + + def get_led_byname(self, name): + tmp = self.led_list + for item in tmp: + if name == item.name: + return item + return None + + # temp + @property + def temp_list(self): + return self.__temp_list + + @temp_list.setter + def temp_list(self, val): + self.__temp_list = val + + def get_temp_byname(self, name): + tmp = self.temp_list + for item in tmp: + if name == item.name: + return item + return None + + # cpld + @property + def cpld_list(self): + return self.__cpld_list + + @cpld_list.setter + def cpld_list(self, val): + self.__cpld_list = val + + def get_cpld_byname(self, name): + tmp = self.cpld_list + for item in tmp: + if name == item.name: + return item + return None + + @property + def comp_list(self): + return self.__comp_list + + @comp_list.setter + def comp_list(self, val): + self.__comp_list = val + + def get_comp_byname(self, name): + tmp = self.comp_list + for item in tmp: + if name == item.name: + return item + return None + + # bios + @property + def bios_list(self): + return self.__bios_list + + @bios_list.setter + def bios_list(self, val): + self.__bios_list = val + + def get_bios_byname(self, name): + tmp = self.bios_list + for item in tmp: + if name == item.name: + return item + return None + + # bmc + @property + def bmc_list(self): + return self.__bmc_list + + @bmc_list.setter + def bmc_list(self, val): + self.__bmc_list = val + + def get_bmc_byname(self, name): + tmp = self.bmc_list + for item in tmp: + if name == item.name: + return item + return None + + # cpu + @property + def cpu(self): + return self.__cpu + + @cpu.setter + def cpu(self, val): + self.__cpu = val + + def get_cpu_byname(self, name): + return self.cpu diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/component.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/component.py new file mode 100644 index 000000000000..0f2ad2167485 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/component.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +####################################################### +# +# component.py +# Python implementation of the Class fan +# +####################################################### +from plat_hal.devicebase import devicebase +from plat_hal.osutil import osutil + + +class component(devicebase): + __user_reg = None + + def __init__(self, conf=None): + if conf is not None: + self.name = conf.get('name', None) + self.version_file = conf.get('VersionFile', None) + self.comp_id = conf.get("comp_id", None) + self.desc = conf.get("desc", None) + self.slot = conf.get("slot", None) + + def get_version(self): + version = "NA" + try: + ret, version = self.get_value(self.version_file) + if ret is False: + return version + pattern = self.version_file.get('pattern', None) + version = osutil.std_match(version, pattern) + except Exception: + return version + return version diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpld.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpld.py new file mode 100644 index 000000000000..09eed5f975ee --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpld.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +####################################################### +# +# fan.py +# Python implementation of the Class fan +# +####################################################### +from plat_hal.devicebase import devicebase + + +class cpld(devicebase): + __user_reg = None + + def __init__(self, conf=None): + if conf is not None: + self.name = conf.get('name', None) + self.user_reg = conf.get('UserReg', None) + self.console_reg = conf.get('ConsoleReg', None) + self.console_reg_attrs = conf.get('ConsoleRegAttrs', None) + self.version_file = conf.get('VersionFile', None) + self.cpld_id = conf.get("cpld_id", None) + self.desc = conf.get("desc", None) + self.slot = conf.get("slot", None) + self.format = conf.get("format", "big_endian") + self.warm = conf.get("warm", None) + self.type = conf.get("type", None) + + def get_user_reg(self): + if self.user_reg is None: + return False + ret, val = self.get_value(self.user_reg) + return val + + def set_user_reg(self, value): + if self.user_reg is None: + return False + byte = value & 0xFF + ret, val = self.set_value(self.user_reg, byte) + return ret + + def set_console_owner(self, owner): + ret = False + + if self.console_reg is None: + return False + tmpattr = self.console_reg_attrs.get(owner, None) + if tmpattr is not None: + ret, val = self.set_value(self.console_reg, tmpattr) + return ret + + def get_version(self): + ret, val = self.get_value(self.version_file) + if ret is False: + val = "N/A" + return val + if self.type == "str": + return val.strip('\n') + val = val.strip('\n').split(" ") + if len(val) < 4: + val = "N/A" + return val + if self.format == "little_endian": + cpld_version = "%s%s%s%s" % (val[3], val[2], val[1], val[0]) + else: + cpld_version = "%s%s%s%s" % (val[0], val[1], val[2], val[3]) + return cpld_version diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpu.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpu.py new file mode 100644 index 000000000000..c6bec1abd1c2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpu.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +############################################################################### +# +# Hardware Abstraction Layer APIs -- CPU APIs. +# +############################################################################### +from plat_hal.devicebase import devicebase + + +class cpu(devicebase): + + def __init__(self, conf=None): + if conf is not None: + self.name = conf.get('name', None) + self.cpu_reset_cnt_reg = conf.get('CpuResetCntReg', None) + self.reboot_cause_path = conf.get('reboot_cause_path', "/etc/sonic/.reboot/.previous-reboot-cause.txt") + + def get_cpu_reset_num(self): + """ + get cpu reset num. + @return cpu reset number, -1 for failure + """ + ret = -1 + if self.cpu_reset_cnt_reg is None: + self.logger_debug("ERR: no support get cpu reset num") + return ret + ret, reset_num = self.get_value(self.cpu_reset_cnt_reg) + if ret is False or reset_num is None: + self.logger_debug("ERR: i2c read cpu_reset_cnt_reg,result:%s" % reset_num) + else: + if isinstance(reset_num, str): + ret = int(reset_num, 16) + else: + ret = reset_num + return ret + + def get_cpu_reboot_cause(self): + """ + get_cpu_reboot_cause + @return cpu reset number, -1 for failure + """ + try: + with open(self.reboot_cause_path) as fd: + reboot_cause = fd.read().strip() + return reboot_cause + except Exception: + return "Unknown reboot cause" + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/dcdc.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/dcdc.py new file mode 100644 index 000000000000..ba604995043d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/dcdc.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 +from plat_hal.devicebase import devicebase +from plat_hal.sensor import sensor + + +class dcdc(devicebase): + def __init__(self, conf=None): + if conf is not None: + self.name = conf.get('name', None) + self.dcdc_id = conf.get("dcdc_id", None) + self.sensor = sensor(conf) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/devicebase.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/devicebase.py new file mode 100644 index 000000000000..001b4ee239bf --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/devicebase.py @@ -0,0 +1,351 @@ +#!/usr/bin/env python3 +####################################################### +# +# devicebase.py +# Python implementation of the Class devicebase +# +####################################################### +import subprocess +import shlex +import ast +from plat_hal.osutil import osutil +from plat_hal.baseutil import baseutil + +class CodeVisitor(ast.NodeVisitor): + + def __init__(self): + self.value = None + + def get_value(self): + return self.value + + def get_op_value(self, node): + if isinstance(node, ast.Call): # node is func call + value = self.visit_Call(node) + elif isinstance(node, ast.BinOp): # node is BinOp + value = self.visit_BinOp(node) + elif isinstance(node, ast.UnaryOp): # node is UnaryOp + value = self.visit_UnaryOp(node) + elif isinstance(node, ast.Num): # node is Num Constant + value = node.n + elif isinstance(node, ast.Str): # node is Str Constant + value = node.s + else: + raise NotImplementedError("Unsupport operand type: %s" % type(node)) + return value + + def visit_UnaryOp(self, node): + ''' + node.op: operand type, only support ast.UAdd/ast.USub + node.operand: only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.UnaryOp + ''' + + operand_value = self.get_op_value(node.operand) + if isinstance(node.op, ast.UAdd): + self.value = operand_value + elif isinstance(node.op, ast.USub): + self.value = 0 - operand_value + else: + raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) + return self.value + + def visit_BinOp(self, node): + ''' + node.left: left operand, only support ast.Call/ast.Constant(ast.Num)/ast.BinOp + node.op: operand type, only support ast.Add/ast.Sub/ast.Mult/ast.Div + node.right: right operan, only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp + ''' + left_value = self.get_op_value(node.left) + right_value = self.get_op_value(node.right) + + if isinstance(node.op, ast.Add): + self.value = left_value + right_value + elif isinstance(node.op, ast.Sub): + self.value = left_value - right_value + elif isinstance(node.op, ast.Mult): + self.value = left_value * right_value + elif isinstance(node.op, ast.Div): + self.value = left_value / right_value + else: + raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) + return self.value + + def visit_Call(self, node): + ''' + node.func.id: func name, only support 'float', 'int', 'str' + node.args: func args list,only support ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.Call + str/float only support one parameter, eg: float(XXX), str(xxx) + int support one or two parameters, eg: int(xxx) or int(xxx, 16) + xxx can be ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp + ''' + calc_tuple = ("float", "int", "str") + + if node.func.id not in calc_tuple: + raise NotImplementedError("Unsupport function call type: %s" % node.func.id) + + args_val_list = [] + for item in node.args: + ret = self.get_op_value(item) + args_val_list.append(ret) + + if node.func.id == "str": + if len(args_val_list) != 1: + raise TypeError("str() takes 1 positional argument but %s were given" % len(args_val_list)) + value = str(args_val_list[0]) + self.value = value + return value + + if node.func.id == "float": + if len(args_val_list) != 1: + raise TypeError("float() takes 1 positional argument but %s were given" % len(args_val_list)) + value = float(args_val_list[0]) + self.value = value + return value + # int + if len(args_val_list) == 1: + value = int(args_val_list[0]) + self.value = value + return value + if len(args_val_list) == 2: + value = int(args_val_list[0], args_val_list[1]) + self.value = value + return value + raise TypeError("int() takes 1 or 2 arguments (%s given)" % len(args_val_list)) + + +class devicebase(object): + _name = None + __error_ret = -99999 + + @property + def name(self): + return self._name + + @name.setter + def name(self, val): + self._name = val + + def dumpValueByI2c(self, bus, loc): + value = "" + for i in range(256): + ret, val = self.get_i2c(bus, loc, i) + value += chr(val) + return value + + def byteTostr(self, val): + strtmp = '' + for value in val: + strtmp += chr(value) + return strtmp + + def get_eeprom_info(self, conf): + eeprom = "" + if conf.get('way') == 'sysfs': + ret, eeprom = self.get_value(conf) + if ret is False: + return None + elif conf.get('way') == 'devfile': + ret, eeprom_list = self.get_value(conf) + if ret is False: + return None + for item in eeprom_list: + eeprom += chr(item) + else: + eeprom = self.dumpValueByI2c(conf.get('bus'), conf.get('addr')) + return eeprom + + def exec_os_cmd(self, cmd): + status, output = subprocess.getstatusoutput(cmd) + return status, output + + def get_value(self, config): + ''' + get value by config way + way i2c/sysfs/lpc + ''' + way = config.get("way") + if way == 'sysfs': + return self.get_sysfs(config.get("loc"), config.get("flock_path")) + if way == "i2c": + bus = config.get("bus") + addr = config.get("addr") + offset = config.get("offset") + return self.get_i2c(bus, addr, offset) + if way == "io": + io_addr = config.get('io_addr') + read_len = config.get('read_len', 1) + return self.get_io(io_addr, read_len) + if way == "i2cword": + bus = config.get("bus") + addr = config.get("addr") + offset = config.get("offset") + return self.get_i2cword(bus, addr, offset) + if way == "devmem": + addr = config.get("addr") + digit = config.get("digit") + mask = config.get("mask", None) + return self.get_devmem(addr, digit, mask) + if way == "sdk": + get_type = config.get("type") + if get_type == "bcm_temp": + return self.getbcmtemp() + if get_type == "bcm_reg": + reg = config.get("reg") + return self.getbcmreg(reg) + raise Exception("cannot found sdk type deal") + if way == "devfile": + loc = config.get("loc") + offset = config.get("offset") + length = config.get("len") + ret, val_list = self.devfile_read(loc, offset, length) + if ret is True: + if length == 1: + val = val_list[0] + return True, val + return True, val_list + return False, ("devfile read failed. path:%s, offset:0x%x, read_len:%d" % (loc, offset, length)) + if way == "devfile_ascii": + loc = config.get("loc") + offset = config.get("offset") + length = config.get("len") + return self.devfile_read_ascii(loc, offset, length) + if way == 'cmd': + cmd = config.get("cmd") + ret, log = self.exec_os_cmd(cmd) + if ret: + return False, ("cmd write exec %s failed, log: %s" % (cmd, log)) + return True, log + if way == 'config': + value = config.get("value") + return True, value + raise Exception("cannot found way deal") + + def devfile_read(self, loc, offset, length): + return osutil.readdevfile(loc, offset, length) + + def devfile_read_ascii(self, loc, offset, length): + return osutil.readdevfile_ascii(loc, offset, length) + + def get_sysfs(self, loc, flock_path=None): + return self.getsysfs(loc, flock_path) + + def getsysfs(self, loc, flock_path=None): + ret, val = osutil.readsysfs(loc, flock_path) + return ret, val + + def get_devmem(self, addr, digit, mask): + return osutil.getdevmem(addr, digit, mask) + + def get_i2cword(self, bus, addr, offset): + return self.geti2cword(bus, addr, offset) + + def geti2cword(self, bus, addr, offset): + ret, val = osutil.geti2cword(bus, addr, offset) + return ret, val + + def get_io(self, reg_addr, read_len): + return self.getio(reg_addr, read_len) + + def getio(self, reg_addr, read_len): + ret, val = osutil.io_rd(reg_addr, read_len) + return ret, val + + def get_i2c(self, bus, addr, offset): + return self.geti2c(bus, addr, offset) + + def geti2c(self, bus, addr, offset): + ret, val = osutil.wbi2cget(bus, addr, offset) + return ret, val + + def set_value(self, config, val): + ''' + get value by config way + way i2c/sysfs/lpc + ''' + way = config.get("way") + if way == 'sysfs': + return self.set_sysfs(config.get("loc"), "0x%02x" % val) + if way == "i2c": + bus = config.get("bus") + addr = config.get("addr") + offset = config.get("offset") + return self.set_i2c(bus, addr, offset, val) + if way == "i2cpec": + bus = config.get("bus") + addr = config.get("addr") + offset = config.get("offset") + return self.seti2c_byte_pec(bus, addr, offset, val) + if way == 'i2cword': + bus = config.get("bus") + addr = config.get("addr") + offset = config.get("offset") + return self.set_i2cword(bus, addr, offset, val) + if way == "i2cwordpec": + bus = config.get("bus") + addr = config.get("addr") + offset = config.get("offset") + return self.set_i2cwordpec(bus, addr, offset, val) + if way == "devfile": + loc = config.get("loc") + offset = config.get("offset") + return self.devfile_write(loc, offset, val) + return False, "unsupport way: %s" % way + + def set_sysfs(self, loc, value): + return self.setsysfs(loc, value) + + def setsysfs(self, loc, value): + return osutil.writesysfs(loc, value) + + def set_i2cword(self, bus, addr, offset, byte): + return self.seti2cword(bus, addr, offset, byte) + + def seti2cword(self, bus, addr, offset, byte): + return osutil.seti2cword(bus, addr, offset, byte) + + def set_i2cwordpec(self, bus, addr, offset, val): + return osutil.seti2cwordpec(bus, addr, offset, val) + + def seti2c_byte_pec(self, bus, addr, offset, val): + return osutil.seti2c_byte_pec(bus, addr, offset, val) + + def set_i2c(self, bus, addr, offset, byte): + return self.seti2c(bus, addr, offset, byte) + + def seti2c(self, bus, addr, offset, byte): + ret, val = osutil.wbi2cset(bus, addr, offset, byte) + return ret, val + + def devfile_write(self, loc, offset, val): + ret, val = osutil.writedevfile(loc, offset, val) + return ret, val + + def getbcmtemp(self): + try: + sta, ret = osutil.getmactemp() + if sta is True: + mac_aver = float(ret.get("average", self.__error_ret)) + mac_aver = mac_aver * 1000 + else: + return False, ret + except AttributeError as e: + return False, str(e) + return True, mac_aver + + def getbcmreg(self, reg): + ret, val = osutil.getsdkreg(reg) + return ret, val + + def logger_debug(self, msg): + baseutil.logger_debug(msg) + + def command(self, cmd): + ret, output = osutil.command(cmd) + return ret, output + + def get_format_value(self, format_str): + ast_obj = ast.parse(format_str, mode='eval') + visitor = CodeVisitor() + visitor.visit(ast_obj) + ret = visitor.get_value() + return ret diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/fan.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/fan.py new file mode 100644 index 000000000000..1424c14a4a94 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/fan.py @@ -0,0 +1,417 @@ +#!/usr/bin/env python3 +####################################################### +# +# fan.py +# Python implementation of the Class fan +# +####################################################### +from eepromutil.fru import ipmifru +from eepromutil.fantlv import fan_tlv +from plat_hal.devicebase import devicebase +from plat_hal.rotor import rotor + + +class fan(devicebase): + __rotor_list = [] + __pn = None + __raweeprom = None + __sn = None + __hw_version = None + __e2loc = None + __rotors = None + __AirFlow = None + __SpeedMin = None + __SpeedMax = None + __PowerMax = None + __productName = None + __productSerialNumber = None + __WatchdogStatus = None + __led_attrs_config = None + __led_config = None + __WatchdogStatus_config = None + __AirFlowconifg = None + __EnableWatchdogConf = None + __Rotor_config = None + __fan_display_name = None # 'N/A' + __fan_display_name_conifg = None + + def __init__(self, conf=None): + if conf is not None: + self.name = conf.get('name', None) + self.sn = conf.get('sn', None) + self.present = conf.get('present', None) + self.e2loc = conf.get('e2loc', None) + self.e2_type = conf.get('e2_type', "fru") + self.SpeedMin = conf.get('SpeedMin', None) + self.SpeedMax = conf.get('SpeedMax', None) + self.PowerMax = conf.get('PowerMax', None) + self.AirFlowconifg = conf.get("airflow", None) + self.WatchdogStatus_config = conf.get('WatchdogStatus', None) + self.EnableWatchdogConf = conf.get('EnableWatchdogConf', None) + self.led_attrs_config = conf.get('led_attrs', None) + self.led_config = conf.get('led', None) + self.Rotor_config = conf.get('Rotor', None) + self.fan_display_name_conifg = conf.get("fan_display_name", None) + rotor_tmp = [] + for value in self.Rotor_config.values(): + rotor_tmp.append(rotor(value)) + rotor_tmp.sort(key=lambda x: x.name, reverse=False) + self.rotor_list = rotor_tmp + self.rotors = len(self.rotor_list) + + @property + def EnableWatchdogConf(self): + return self.__EnableWatchdogConf + + @EnableWatchdogConf.setter + def EnableWatchdogConf(self, val): + self.__EnableWatchdogConf = val + + @property + def rotor_list(self): + return self.__rotor_list + + @rotor_list.setter + def rotor_list(self, val): + self.__rotor_list = val + + @property + def Rotor_config(self): + return self.__Rotor_config + + @Rotor_config.setter + def Rotor_config(self, val): + self.__Rotor_config = val + + @property + def productName(self): + return self.__productName + + @productName.setter + def productName(self, val): + self.__productName = val + + @property + def productSerialNumber(self): + return self.__productSerialNumber + + @productSerialNumber.setter + def productSerialNumber(self, val): + self.__productSerialNumber = val + + @property + def hw_version(self): + return self.__hw_version + + @hw_version.setter + def hw_version(self, val): + self.__hw_version = val + + @property + def sn(self): + return self.__sn + + @sn.setter + def sn(self, val): + self.__sn = val + + @property + def pn(self): + return self.__pn + + @pn.setter + def pn(self, val): + self.__pn = val + + @property + def raweeprom(self): + return self.__raweeprom + + @raweeprom.setter + def raweeprom(self, val): + self.__raweeprom = val + + @property + def SpeedMax(self): + return self.__SpeedMax + + @SpeedMax.setter + def SpeedMax(self, val): + self.__SpeedMax = val + + @property + def SpeedMin(self): + return self.__SpeedMin + + @SpeedMin.setter + def SpeedMin(self, val): + self.__SpeedMin = val + + @property + def PowerMax(self): + return self.__PowerMax + + @PowerMax.setter + def PowerMax(self, val): + self.__PowerMax = val + + @property + def rotors(self): + return self.__rotors + + @property + def AirFlow(self): + return self.__AirFlow + + @AirFlow.setter + def AirFlow(self, val): + self.__AirFlow = val + + @rotors.setter + def rotors(self, val): + self.__rotors = val + + @property + def fan_display_name_conifg(self): + return self.__fan_display_name_conifg + + @fan_display_name_conifg.setter + def fan_display_name_conifg(self, val): + self.__fan_display_name_conifg = val + + @property + def fan_display_name(self): + return self.__fan_display_name + + @fan_display_name.setter + def fan_display_name(self, val): + self.__fan_display_name = val + + def getspeed(self, conf): + tmp = None + if conf is None: + return -1 + ret, val = self.get_value(conf) + if ret is True: + tmp = int(str(val), 10) + else: + val = None + if val is not None: + return int(15000000 / tmp) + return -1 + + def get_speed(self, rotor_index): + rotor_item = self.get_rotor_index(rotor_index) + if rotor_item is None: + return None + speed = rotor_item.rotor_Speed.Value + if speed is None: + return None + return int(speed) + + def set_led(self, color): + status = self.led_attrs_config.get(color, None) + if status is None: + return False + + mask = self.led_attrs_config.get('mask', 0xff) + ret, value = self.get_value(self.led_config) + if ret is False or value is None: + return False + setval = (int(value) & ~mask) | (status) + ret, val = self.set_value(self.led_config, setval) + return ret + + def get_led(self): + mask = self.led_attrs_config.get('mask', 0xff) + ret, value = self.get_value(self.led_config) + if ret is False or value is None: + return False, 'N/A' + ledval = int(value) & mask + for key, val in self.led_attrs_config.items(): + if (ledval == val) and (key != "mask"): + return True, key + return False, 'N/A' + + def set_speed(self, rotor_index, level): + if level > 255 or level < 0: + return False + rotor_item = self.get_rotor_index(rotor_index) + if rotor_item is None: + return False + ret, val = self.set_value(rotor_item.Speedconfig, int(level)) + return ret + + def get_rotor_index(self, rotor_index): + if rotor_index > len(self.rotor_list): + return None + rotor_item = self.rotor_list[rotor_index - 1] + return rotor_item + + def get_rotor_byname(self, rotor_index): + for rotor_item in self.rotor_list: + if rotor_item.name == rotor_index: + return rotor_item + return None + + def get_presence(self): + ret, val = self.get_value(self.present) + if ret is False or val is None: + return -1 + if isinstance(val, str): + value = int(val, 16) + else: + value = val + mask = self.present.get("mask") + flag = value & mask + okval = self.present.get("okval", 0) + if flag == okval: + return True + return False + + def get_speed_pwm(self, rotor_index): + rotor_item = self.get_rotor_index(rotor_index) + if rotor_item is None: + return False + if rotor_item.i2c_speed is None: + return False + val = round(rotor_item.i2c_speed * 100 / 255) + return val + + def feed_watchdog(self): + ret = False + for rotor_item in self.rotor_list: + ret, val = rotor_item.feed_watchdog() + if ret is False: + return ret + return ret + + def get_fru_info(self): + try: + if self.get_presence() is False: + raise Exception("%s: not present" % self.name) + eeprom = self.get_eeprom_info(self.e2loc) + if eeprom is None: + raise Exception("%s: value is none" % self.name) + fru = ipmifru() + if isinstance(eeprom, bytes): + eeprom = self.byteTostr(eeprom) + fru.decodeBin(eeprom) + self.productName = fru.productInfoArea.productName.strip() # PN + self.productSerialNumber = fru.productInfoArea.productSerialNumber.strip() # SN + self.hw_version = fru.productInfoArea.productVersion.strip() # HW + except Exception: + self.productName = None + self.productSerialNumber = None + self.hw_version = None + return False + return True + + def get_tlv_info(self): + try: + if self.get_presence() is False: + raise Exception("%s: not present" % self.name) + eeprom = self.get_eeprom_info(self.e2loc) + if eeprom is None: + raise Exception("%s: value is none" % self.name) + tlv = fan_tlv() + rets = tlv.decode(eeprom) + for item in rets: + if item["name"] == "Product Name": + self.productName = item["value"].replace("\x00", "").strip() + elif item["name"] == "serial Number": + self.productSerialNumber = item["value"].replace("\x00", "").strip() + elif item["name"] == "hardware info": + self.hw_version = item["value"].replace("\x00", "").strip() + except Exception: + self.productName = None + self.productSerialNumber = None + self.hw_version = None + return False + return True + + def decode_eeprom_info(self): + '''get fan name, hw version, sn''' + if self.e2_type == "fru": + return self.get_fru_info() + + if self.e2_type == "fantlv": + return self.get_tlv_info() + + return False + + def get_AirFlow(self): + if self.productName is None: + ret = self.decode_eeprom_info() + if ret is False: + self.AirFlow = None + return False + if self.AirFlowconifg is None: + self.AirFlow = None + return False + for i in self.AirFlowconifg: + if self.productName in self.AirFlowconifg[i]: + self.AirFlow = i + return True + self.AirFlow = None + return False + + def enable_watchdog(self, enable): + ret = False + if enable is True: + byte = self.EnableWatchdogConf.get("enable_byte", None) + ret, val = self.set_value(self.EnableWatchdogConf, byte) + elif enable is False: + byte = self.EnableWatchdogConf.get("disable_byte", None) + ret, val = self.set_value(self.EnableWatchdogConf, byte) + return ret + + def get_watchdog_status(self): + dic = {"support": None, "open": None, "work_full": None, "work_allow_set": None} + if self.WatchdogStatus_config is None: + return None + ret, val = self.get_value(self.WatchdogStatus_config) + if ret is False or val is None: + return None + support_watchdog_off = self.WatchdogStatus_config.get("support_watchdog_off", None) + is_open_off = self.WatchdogStatus_config.get("is_open_off", None) + full_running_off = self.WatchdogStatus_config.get("full_running_off", None) + running_setting_off = self.WatchdogStatus_config.get("running_setting_off", None) + if support_watchdog_off is not None: + if support_watchdog_off & val == self.WatchdogStatus_config.get("support_watchdog_mask", None): + dic["support"] = True + else: + dic["support"] = False + return dic + if is_open_off is not None: + if is_open_off & val == self.WatchdogStatus_config.get("is_open_mask", None): + dic["open"] = True + else: + dic["open"] = False + if full_running_off is not None: + if full_running_off & val == self.WatchdogStatus_config.get("full_running_mask", None): + dic["work_full"] = True + else: + dic["work_full"] = False + if running_setting_off is not None: + if running_setting_off & val == self.WatchdogStatus_config.get("running_setting_mask", None): + dic["work_allow_set"] = True + else: + dic["work_allow_set"] = False + return dic + + def get_fan_display_name(self): + if self.productName is None: + ret = self.decode_eeprom_info() + if ret is False: + self.fan_display_name = None + return False + if self.fan_display_name_conifg is None: + self.fan_display_name = self.productName + return False + for i in self.fan_display_name_conifg: + if self.productName in self.fan_display_name_conifg[i]: + self.fan_display_name = i + return True + self.fan_display_name = self.productName + return False diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/interface.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/interface.py new file mode 100644 index 000000000000..7092f555c496 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/interface.py @@ -0,0 +1,1334 @@ +#!/usr/bin/env python3 +####################################################### +# +# interface.py +# Python implementation of the Class interface +# +####################################################### +import collections +from plat_hal.chassisbase import chassisbase +from plat_hal.baseutil import baseutil +from plat_hal.osutil import osutil + + +def Singleton(cls): + _instance = {} + + def _singleton(*args, **kargs): + if cls not in _instance: + _instance[cls] = cls(*args, **kargs) + return _instance[cls] + + return _singleton + + +@Singleton +class interface(object): + __chas = None + __error_ret = None + + def __init__(self): + self.chas = chassisbase() + self.__error_ret = -99999 + self.__na_ret = 'N/A' + + @property + def na_ret(self): + return self.__na_ret + + @na_ret.setter + def na_ret(self, val): + self.__na_ret = val + + @property + def error_ret(self): + return self.__error_ret + + @error_ret.setter + def error_ret(self, val): + self.__error_ret = val + + @property + def chas(self): + return self.__chas + + @chas.setter + def chas(self, val): + self.__chas = val + + # onie_e2 + def get_onie_e2(self): + onie_e2_list = self.chas.onie_e2_list + return onie_e2_list + + def get_onie_e2_path(self, name): + onie_e2 = self.chas.get_onie_e2_byname(name) + if onie_e2 is None: + return None + return onie_e2.e2_path + + def get_device_airflow(self, name): + onie_e2 = self.chas.get_onie_e2_byname(name) + if onie_e2 is None: + return None + return onie_e2.airflow + + def get_onie_e2_obj(self, name): + onie_e2 = self.chas.get_onie_e2_byname(name) + if onie_e2 is None: + return None + onie_e2.get_onie_e2_info() + return onie_e2 + + # temp + def get_temps(self): + templist = self.chas.temp_list + return templist + + def get_temp_total_number(self): + templist = self.chas.temp_list + return len(templist) + + def check_temp_id_exist(self, temp_id): + templist = self.chas.temp_list + for temp in templist: + if temp.temp_id == temp_id: + return True + return False + + def get_temp_id_number(self): + templist = self.chas.temp_list + temp_num = 0 + for i in range(len(templist)): + temp_id = "TEMP" + str(i + 1) + ret = self.check_temp_id_exist(temp_id) + if ret is True: + temp_num = temp_num + 1 + else: + return temp_num + return temp_num + + def get_temp_location(self, temp_name): + temp = self.chas.get_temp_byname(temp_name) + return temp.get_location() + + def set_temp_location(self, temp_name, location): + temp = self.chas.get_temp_byname(temp_name) + return temp.set_location(location) + + def set_temp_name(self, temp_name, name): + temp = self.chas.get_temp_byname(temp_name) + return temp.set_name(name) + + def get_appoint_temp(self, temp_name): + temp = self.chas.get_led_byname(temp_name) + return temp.get_temp() + + def set_appoint_temp(self, temp_name, val): + temp = self.chas.get_temp_byname(temp_name) + return temp.set_temp(val) + + def get_temp_mintemp(self, temp_name): + temp = self.chas.get_temp_byname(temp_name) + return temp.get_mintemp() + + def set_temp_mintemp(self, temp_name, val): + temp = self.chas.get_temp_byname(temp_name) + return temp.set_mintemp(val) + + # led + def get_leds(self): + ledlist = self.chas.led_list + return ledlist + + def get_led_total_number(self): + ledlist = self.chas.led_list + return len(ledlist) + + def get_led_color(self, led_name): + led = self.chas.get_led_byname(led_name) + if led is None: + return -1 + return led.get_color() + + def get_led_color_by_type(self, led_type): + ledlist = self.chas.led_list + ledtmp = None + for temp in ledlist: + if temp.led_type == led_type: + ledtmp = temp + break + if ledtmp is None: + return -1 + return ledtmp.get_color() + + def set_led_color(self, led_name, color): + led = self.chas.get_led_byname(led_name) + if led is None: + return -1 + return led.set_color(color) + + # psu + def get_psu_total_number(self): + psulist = self.chas.psu_list + if psulist is None: + return -1 + return len(psulist) + + def get_psus(self): + psulist = self.chas.psu_list + return psulist + + def get_psu_presence(self, psu_name): + psu = self.chas.get_psu_byname(psu_name) + if psu is None: + return -1 + return psu.present + + def get_psu_fru_info(self, psu_name): + ''' + { + "Name": "PSU1", + "SN": "serial_number_example", # 'N/A' + "PN": "part_number_example", # 'N/A' + "AirFlow": "B2F" # 'N/A' + } + ''' + psu = self.chas.get_psu_byname(psu_name) + if psu is None: + return -1 + psu.get_fru_info() + psu.get_AirFlow() + psu.get_psu_display_name() + + dic = collections.OrderedDict() + dic["Name"] = psu.name + dic["SN"] = psu.productSerialNumber if (psu.productSerialNumber is not None) else self.na_ret + dic["PN"] = psu.productPartModelName if (psu.productPartModelName is not None) else self.na_ret + dic["DisplayName"] = psu.psu_display_name if (psu.psu_display_name is not None) else self.na_ret + dic["VENDOR"] = psu.productManufacturer if (psu.productManufacturer is not None) else self.na_ret + dic["HW"] = psu.productVersion if (psu.productVersion is not None) else self.na_ret + dic["AirFlow"] = psu.AirFlow if (psu.AirFlow is not None) else self.na_ret + return dic + + def get_psu_input_output_status(self, psu_name): + psu = self.chas.get_psu_byname(psu_name) + if psu is None: + return -1 + psu.InputsCurrent.Value # just for clear faults + if psu.InputStatus is True and psu.OutputStatus is True: + return True + # only has outputstatus + if psu.InputStatus is None and psu.OutputStatus is True: + return True + return False + + def get_psu_status(self, psu_name): + """ + Get status of a specific PSU + @return dict of the specific PSU's status, None for failure + Example return value(all keys are mandatory) + { + "Name": "PSU1", + "InputType": "DC", # "AC" or 'N/A' + "InputStatus": True, # H/W status bit + "OutputStatus": True # H/W status bit + "FanSpeed": { + "Value": 4000, # -99999 + "Min": 2000, # -99999 + "Max": 10000 # -99999 + }, + "Temperature": { + "Value": 40.0, # -99999.0 + "Min": -30.0, # -99999.0 + "Max": 50.0 # -99999.0 + } + } + """ + psu = self.chas.get_psu_byname(psu_name) + if psu is None: + return -1 + + if psu.get_threshold_by_model == 1: + psu.get_fru_info() + + dic = collections.OrderedDict() + # psu.get_Temperature() + temp_dict = collections.OrderedDict() + temp_dict['Min'] = psu.Temperature.Min + temp_dict['Max'] = psu.Temperature.Max + temp_dict['Value'] = psu.Temperature.Value + temp_dict['Unit'] = psu.Temperature.Unit + dic["Temperature"] = temp_dict + + # psu.get_FanSpeed() + fan_speed_dict = collections.OrderedDict() + fan_speed_dict['Min'] = psu.FanSpeed.Min + fan_speed_dict['Max'] = psu.FanSpeed.Max + fan_speed_dict['Tolerance'] = psu.FanSpeedTolerance + fan_speed_dict['Value'] = psu.FanSpeed.Value + fan_speed_dict['Unit'] = psu.FanSpeed.Unit + dic["FanSpeed"] = fan_speed_dict + + dic["Name"] = psu.name + dic["InputType"] = psu.InputsType + dic["InputStatus"] = psu.InputStatus + dic["OutputStatus"] = psu.OutputStatus + dic["TempStatus"] = psu.TempStatus + dic["FanStatus"] = psu.FanStatus + return dic + + def get_psu_power_status(self, psu_name): + """ + Get power status of a specific PSU + @return dict of the specific PSU's power status, None for failure + Example return value + { + "Name": "PSU1", + "Inputs": { + "Status": True, # H/W status bit + "Type": "DC", # or "AC" or "N/A" + "Voltage": { + "Value": 220, # -1 + "LowAlarm": 200, # -1 + "HighAlarm": 240, # -1 + "Unit": "V" + }, + "Current": { + "Value": 6.0, # -99999.0 + "LowAlarm": 0.2, # -99999.0 + "HighAlarm": 7.0, # -99999.0 + "Unit": "A" + }, + "Power": { + "Value": 1000, # -99999 + "LowAlarm": -1, # -99999 + "HighAlarm": 1400, # -99999 + "Unit": "W" + } + }, + "Outputs": { + "Status": True, + "Voltage": { + "Value": 220, + "LowAlarm": 200, + "HighAlarm": 240, + "Unit": "V" + }, + "Current": { + "Value": 6.0, + "LowAlarm": 0.2, + "HighAlarm": 7.0, + "Unit": "A" + }, + "Power": { + "Value": 1000, + "LowAlarm": -1, # Don't care + "HighAlarm": 1400, + "Unit": "W" + } + } + } + """ + psu = self.chas.get_psu_byname(psu_name) + if psu is None: + return -1 + if psu.get_threshold_by_model == 1: + psu.get_fru_info() + dic = collections.OrderedDict() + inputdic = collections.OrderedDict() + Outputsdic = collections.OrderedDict() + dic["Name"] = psu.name + inputdic["Status"] = psu.InputStatus + inputdic["Type"] = psu.InputsType + + # psu.get_InputsVoltage() + inputdic_voltage = collections.OrderedDict() + + inputdic_voltage["Value"] = psu.InputsVoltage.Value + inputdic_voltage["LowAlarm"] = psu.InputsVoltage.Min + inputdic_voltage["HighAlarm"] = psu.InputsVoltage.Max + inputdic_voltage["Unit"] = psu.InputsVoltage.Unit + + inputdic["Voltage"] = inputdic_voltage + inputdic_current = collections.OrderedDict() + inputdic_current["Value"] = psu.InputsCurrent.Value + inputdic_current["LowAlarm"] = psu.InputsCurrent.Min + inputdic_current["HighAlarm"] = psu.InputsCurrent.Max + inputdic_current["Unit"] = psu.InputsCurrent.Unit + inputdic["Current"] = inputdic_current + + inputdic_power = collections.OrderedDict() + inputdic_power["Value"] = psu.InputsPower.Value + inputdic_power["LowAlarm"] = psu.InputsPower.Min + inputdic_power["HighAlarm"] = psu.InputsPower.Max + inputdic_power["Unit"] = psu.InputsPower.Unit + inputdic["Power"] = inputdic_power + Outputsdic["Status"] = psu.InputStatus + + outputdic_voltage = collections.OrderedDict() + outputdic_current = collections.OrderedDict() + outputdic_power = collections.OrderedDict() + + outputdic_voltage["Value"] = psu.OutputsVoltage.Value + outputdic_voltage["LowAlarm"] = psu.OutputsVoltage.Min + outputdic_voltage["HighAlarm"] = psu.OutputsVoltage.Max + outputdic_voltage["Unit"] = psu.OutputsVoltage.Unit + + outputdic_current["Value"] = psu.OutputsCurrent.Value + outputdic_current["LowAlarm"] = psu.OutputsCurrent.Min + outputdic_current["HighAlarm"] = psu.OutputsCurrent.Max + outputdic_current["Unit"] = psu.OutputsCurrent.Unit + + outputdic_power["Value"] = psu.OutputsPower.Value + outputdic_power["LowAlarm"] = psu.OutputsPower.Min + outputdic_power["HighAlarm"] = psu.OutputsPower.Max + outputdic_power["Unit"] = psu.OutputsPower.Unit + + Outputsdic["Voltage"] = outputdic_voltage + Outputsdic["Current"] = outputdic_current + Outputsdic["Power"] = outputdic_power + + dic["Inputs"] = inputdic + dic["Outputs"] = Outputsdic + + return dic + + def set_psu_fan_speed_pwm(self, psu_name, pwm): + psu = self.chas.get_psu_byname(psu_name) + if psu is None: + return -1 + return psu.set_fan_speed_pwm(pwm) + + def get_psu_fan_speed_pwm(self, psu_name): + psu = self.chas.get_psu_byname(psu_name) + if psu is None: + return -1 + return psu.get_fan_speed_pwm() + + def get_psu_info_all(self): + """ + { + "Number": 2, + "PSU1": { + "SN": "serial_number_example", # 'N/A' + "PN": "part_number_example", # 'N/A' + "AirFlow": "intake", # 'N/A' + + "FanSpeed": { + "Value": 4000, + "Min": 2000, + "Max": 30000 + }, + "Temperature": { + "Value": 35.0, + "Min": -20.0, + "Max": 45.0 + }, + "Inputs": { + "Status": True, # H/W status bit + "Type": "DC", # or "AC" + "Voltage": { + "Value": 220, + "LowAlarm": 200, + "HighAlarm": 240, + "Unit": "V" + }, + "Current": { + "Value": 6.0, + "LowAlarm": 0.2, + "HighAlarm": 7.0, + "Unit": "A" + }, + "Power": { + "Value": 1000, + "LowAlarm": -1, + "HighAlarm": 1400, + "Unit": "W" + } + }, + "Outputs": { + "Status": True, + "Voltage": { + "Value": 220, + "LowAlarm": 200, + "HighAlarm": 240, + "Unit": "V" + }, + "Current": { + "Value": 6.0, + "LowAlarm": 0.2, + "HighAlarm": 7.0, + "Unit": "A" + }, + "Power": { + "Value": 1000, + "LowAlarm": -1, # Don't care + "HighAlarm": 1400, + "Unit": "W" + } + } + } + } + """ + + psus = self.get_psus() + psu_dict = collections.OrderedDict() + psu_dict['Number'] = len(psus) + for psu in psus: + dicttmp = self.get_psu_fru_info(psu.name) + dicttmp.update(self.get_psu_status(psu.name)) + dicttmp.update(self.get_psu_power_status(psu.name)) + if self.get_psu_presence(psu.name) is True: + dicttmp['Present'] = 'yes' + else: + dicttmp['Present'] = 'no' + psu_dict[psu.name] = dicttmp + return psu_dict + + def get_fans(self): + fanlist = self.chas.fan_list + return fanlist + + # fan + def get_fan_total_number(self): + fanlist = self.chas.fan_list + if fanlist is None: + return -1 + return len(fanlist) + + def get_fan_rotor_number(self, fan_name): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + ret = fan.rotors + if ret is None: + return -1 + return ret + + def get_fan_speed(self, fan_name, rotor_index): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + ret = fan.get_speed(rotor_index) + if ret is None: + return -1 + return ret + + def fan_speed_set_level(self, fan_name, rotor_index, level): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + ret = fan.set_speed(rotor_index, level) + if ret is True: + return 0 + return -1 + + def get_fan_speed_pwm(self, fan_name, rotor_index): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + val = fan.get_speed_pwm(rotor_index) + if val is False: + return -1 + return val + + def set_fan_speed_pwm(self, fan_name, rotor_index, pwm): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + if isinstance(pwm, str): + rate = float(pwm.strip('%s')) + speed = round(rate * 255 / 100) + elif isinstance(pwm, int): + speed = round(pwm * 255 / 100) + elif isinstance(pwm, float): + speed = round(pwm * 255 / 100) + else: + return -1 + ret = self.fan_speed_set_level(fan.name, rotor_index, speed) + if ret == 0: + return 0 + return -1 + + def get_fan_watchdog_status(self): + fan = self.chas.fan_list[0] + dic = fan.get_watchdog_status() + if dic is None or dic["support"] is False: + return self.na_ret + if dic["open"] is False or dic["work_allow_set"] is True: + return "Normal" + if dic["work_full"] is True: + return "Abnormal" + return "Abnormal" + + def enable_fan_watchdog(self, enable=True): + fan = self.chas.fan_list[0] + ret = fan.enable_watchdog(enable) + if ret is True: + return 0 + return -1 + + def feed_fan_watchdog(self): + fan_list = self.chas.fan_list + if fan_list is None: + return -1 + for fan in fan_list: + ret = fan.feed_watchdog() + if ret is False: + return -1 + return 0 + + def set_fan_led(self, fan_name, color): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + ret = fan.set_led(color) + if ret is True: + return 0 + return -1 + + def get_fan_led(self, fan_name): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return False, 'N/A' + return fan.get_led() + + def get_fan_presence(self, fan_name): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + return fan.get_presence() + + def get_fan_fru_info(self, fan_name): + """ + Get specific fan's information + # Properties + "Name": "FAN1", + "SN": "serial_number_example", # 'N/A' + "PN": "part_number_exampple", # 'N/A' + "Rotors": 2, # -1 + "AirFlow": "intake", # 'N/A' + "SpeedMin": 2000, # -1 + "SpeedMax": 30000 # -1 + """ + fan = self.chas.get_fan_byname(fan_name) + fan.decode_eeprom_info() + fan.get_AirFlow() + fan.get_fan_display_name() + + dic = collections.OrderedDict() + dic["Name"] = fan.name + dic["SN"] = fan.productSerialNumber + if dic["SN"] is None: + dic["SN"] = self.na_ret + dic["PN"] = fan.productName + if dic["PN"] is None: + dic["PN"] = self.na_ret + dic["DisplayName"] = fan.fan_display_name + if dic["DisplayName"] is None: + dic["DisplayName"] = self.na_ret + + dic["Rotors"] = fan.rotors + dic["AirFlow"] = fan.AirFlow + if dic["AirFlow"] is None: + dic["AirFlow"] = self.na_ret + dic["SpeedMin"] = fan.SpeedMin + dic["SpeedMax"] = fan.SpeedMax + return dic + + def get_fan_eeprom_info(self, fan_name): + """ + Get specific fan's information + # Properties + "Name": "M6510-FAN-F", # 'N/A' + "SN": "serial_number_example", # 'N/A' + "HW": "hw_version_exampple", # 'N/A' + """ + fan = self.chas.get_fan_byname(fan_name) + fan.decode_eeprom_info() + fan.get_fan_display_name() + dic = collections.OrderedDict() + dic["NAME"] = fan.productName + if dic["NAME"] is None: + dic["NAME"] = self.na_ret + dic["SN"] = fan.productSerialNumber + if dic["SN"] is None: + dic["SN"] = self.na_ret + dic["HW"] = fan.hw_version + if dic["HW"] is None: + dic["HW"] = self.na_ret + dic["DisplayName"] = fan.fan_display_name + if dic["DisplayName"] is None: + dic["DisplayName"] = self.na_ret + return dic + + def get_product_fullname(self): + return baseutil.get_product_fullname() + + def get_fan_status(self, fan_name): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + rotorlist = fan.rotor_list + dic = collections.OrderedDict() + for rotor in rotorlist: + dic_val = collections.OrderedDict() + if rotor.rotor_Running is True: + dic_val['Running'] = 'yes' + else: + dic_val['Running'] = 'no' + if rotor.rotor_HwAlarm is True: + dic_val['HwAlarm'] = 'yes' + else: + dic_val['HwAlarm'] = 'no' + dic_val['Speed'] = int(rotor.rotor_Speed.Value) + dic[rotor.name] = dic_val + return dic + + def get_fan_rotor_status(self, fan_name, rotor_name): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + rotorlist = fan.rotor_list + for rotor in rotorlist: + if rotor_name == rotor.name: + if rotor.rotor_Running is True: + return True + return False + return -1 + + def get_fan_roll_status(self, fan_name, rotor_index): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + rotor = fan.get_rotor_index(rotor_index) + if rotor is None: + return -1 + if rotor.rotor_Running is True: + return True + return False + + def get_fan_info_fru(self, fan_name): + fan = self.chas.get_fan_byname(fan_name) + fan.get_fru_info() + fan.get_AirFlow() + dic = collections.OrderedDict() + dic["Name"] = fan.name + dic["SN"] = fan.productSerialNumber + if dic["SN"] is None: + dic["SN"] = self.na_ret + dic["PN"] = fan.productPartModelName + if dic["PN"] is None: + dic["PN"] = self.na_ret + flag = self.get_fan_presence(fan_name) + if flag is True: + dic["Present"] = "yes" + elif flag is False: + dic["Present"] = "no" + else: + dic["Present"] = self.na_ret + dic["Rotors"] = fan.rotors + dic["AirFlow"] = fan.AirFlow + if dic["AirFlow"] is None: + dic["AirFlow"] = self.na_ret + return dic + + # support TLV and FRU FAN E2 + def get_fan_info(self, fan_name): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return None + fan.get_AirFlow() + dic = self.get_fan_eeprom_info(fan_name) + flag = self.get_fan_presence(fan_name) + if flag is True: + dic["Present"] = "yes" + elif flag is False: + dic["Present"] = "no" + else: + dic["Present"] = self.na_ret + dic["Rotors"] = fan.rotors + dic["AirFlow"] = fan.AirFlow + if dic["AirFlow"] is None: + dic["AirFlow"] = self.na_ret + dic["PowerMax"] = fan.PowerMax + if dic["PowerMax"] is None: + dic["PowerMax"] = self.na_ret + return dic + + def get_fan_info_rotor(self, fan_name): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + rotorlist = fan.rotor_list + dic = collections.OrderedDict() + for rotor in rotorlist: + dic_val = collections.OrderedDict() + if rotor.rotor_Running is True: + dic_val['Running'] = 'yes' + else: + dic_val['Running'] = 'no' + if rotor.rotor_HwAlarm is True: + dic_val['HwAlarm'] = 'yes' + else: + dic_val['HwAlarm'] = 'no' + speed_value = rotor.rotor_Speed.Value + if speed_value is None: + dic_val['Speed'] = self.error_ret + else: + dic_val['Speed'] = int(speed_value) + if rotor.SpeedMin is None: + dic_val['SpeedMin'] = self.error_ret + else: + dic_val['SpeedMin'] = rotor.SpeedMin + if rotor.SpeedMax is None: + dic_val['SpeedMax'] = self.error_ret + else: + dic_val['SpeedMax'] = rotor.SpeedMax + if rotor.Tolerance is None: + dic_val['Tolerance'] = self.error_ret + else: + dic_val['Tolerance'] = rotor.Tolerance + + dic[rotor.name] = dic_val + return dic + + def get_fan_info_all(self): + fanlist = self.chas.fan_list + dic = collections.OrderedDict() + dic['Number'] = len(fanlist) + dic['WatchdogStatus'] = self.get_fan_watchdog_status() + for fan in fanlist: + dic[fan.name] = self.get_fan_info(fan.name) + dic[fan.name].update(self.get_fan_info_rotor(fan.name)) + return dic + + def temp_test(self): + templist = self.chas.temp_list + dicret = collections.OrderedDict() + + for temp in templist: + dic = collections.OrderedDict() + temp_value = temp.Value + dic["Value"] = temp_value if (temp_value is not None) else self.error_ret + dic["LowAlarm"] = temp.Min + dic["HighAlarm"] = temp.Max + dicret[temp.name] = dic + return dicret + + # dcdc + def get_dcdc_total_number(self): + dcdclist = self.chas.dcdc_list + if dcdclist is None: + return -1 + return len(dcdclist) + + def get_dcdc_by_id(self, dcdc_id): + dcdclist = self.chas.dcdc_list + dcdctmp = None + for dcdc in dcdclist: + if dcdc.dcdc_id == dcdc_id: + dcdctmp = dcdc + dic = collections.OrderedDict() + if dcdctmp is None: + dic["Name"] = self.error_ret + dic["Min"] = self.error_ret + dic["Max"] = self.error_ret + dic["Low"] = self.error_ret + dic["High"] = self.error_ret + dic["Value"] = self.error_ret + dic["Unit"] = self.error_ret + else: + dic["Name"] = dcdctmp.name + dic["Min"] = dcdctmp.sensor.Min + dic["Max"] = dcdctmp.sensor.Max + dic["Low"] = dcdctmp.sensor.Low + dic["High"] = dcdctmp.sensor.High + tmp = dcdctmp.sensor.Value + if tmp is not None: + dic['Value'] = tmp + else: + dic['Value'] = self.error_ret + dic["Unit"] = dcdctmp.sensor.Unit + return dic + + def get_dcdc_all_info(self): + val_list = collections.OrderedDict() + dcdclist = self.chas.dcdc_list + for dcdc in dcdclist: + dicttmp = {} + sensorname = "%s" % (dcdc.name) + dicttmp['Min'] = dcdc.sensor.Min + dicttmp['Max'] = dcdc.sensor.Max + tmp = dcdc.sensor.Value + if tmp is not None: + dicttmp['Value'] = tmp + else: + dicttmp['Value'] = self.error_ret + dicttmp['Unit'] = dcdc.sensor.Unit + val_list[sensorname] = dicttmp + return val_list + + # sensors + def get_monitor_temp(self, name): + templist = self.chas.temp_list + temptmp = None + for temp in templist: + if temp.name == name: + temptmp = temp + + dic = collections.OrderedDict() + if temptmp is None: + dic["Min"] = self.error_ret + dic["Max"] = self.error_ret + dic["Value"] = self.error_ret + dic["Unit"] = self.error_ret + else: + dic["Min"] = temptmp.Min + dic["Max"] = temptmp.Max + temp_value = temptmp.Value + dic["Value"] = temp_value if (temp_value is not None) else self.error_ret + dic["Unit"] = temptmp.Unit + return dic + + def get_monitor_temp_by_id(self, temp_id): + templist = self.chas.temp_list + temptmp = None + for temp in templist: + if temp.temp_id == temp_id: + temptmp = temp + + dic = collections.OrderedDict() + if temptmp is None: + dic["Name"] = self.error_ret + dic["Api_name"] = self.error_ret + dic["Min"] = self.error_ret + dic["Max"] = self.error_ret + dic["Low"] = self.error_ret + dic["High"] = self.error_ret + dic["Value"] = self.error_ret + dic["Unit"] = self.error_ret + else: + dic["Name"] = temptmp.name + dic["Api_name"] = temptmp.api_name + dic["Min"] = temptmp.Min + dic["Max"] = temptmp.Max + dic["Low"] = temptmp.Low + dic["High"] = temptmp.High + temp_value = temptmp.Value + dic["Value"] = temp_value if (temp_value is not None) else self.error_ret + dic["Unit"] = temptmp.Unit + return dic + + def get_temp_info(self): + val_list = collections.OrderedDict() + # temp + templist = self.chas.temp_list + for temp in templist: + dic = collections.OrderedDict() + dic["Min"] = temp.Min + dic["Max"] = temp.Max + dic["Low"] = temp.Low + dic["High"] = temp.High + temp_value = temp.Value + dic["Value"] = temp_value if (temp_value is not None) else self.error_ret + dic["Unit"] = temp.Unit + val_list[temp.name] = dic + return val_list + + def get_sensor_info(self): + val_list = collections.OrderedDict() + # temp + templist = self.chas.temp_list + for temp in templist: + dic = collections.OrderedDict() + dic["Min"] = temp.Min + dic["Max"] = temp.Max + dic["Low"] = temp.Low + dic["High"] = temp.High + temp_value = temp.Value + dic["Value"] = temp_value if (temp_value is not None) else self.error_ret + dic["Unit"] = temp.Unit + val_list[temp.name] = dic + # fan + fanlist = self.chas.fan_list + for fan in fanlist: + for rotor in fan.rotor_list: + sensorname = "%s%s" % (fan.name, rotor.name) + speed = collections.OrderedDict() + speed['Min'] = rotor.rotor_Speed.Min + speed['Max'] = rotor.rotor_Speed.Max + rotor_speed_Value = rotor.rotor_Speed.Value + speed['Value'] = rotor_speed_Value if (rotor_speed_Value is not None) else self.error_ret + speed['Unit'] = rotor.rotor_Speed.Unit + val_list[sensorname] = speed + + val_list.update(self.get_dcdc_all_info()) + + # psu + psulist = self.chas.psu_list + for psu in psulist: + inputdic_voltage = collections.OrderedDict() + inputdic_current = collections.OrderedDict() + inputdic_power = collections.OrderedDict() + outputdic_voltage = collections.OrderedDict() + outputdic_current = collections.OrderedDict() + outputdic_power = collections.OrderedDict() + temperature = collections.OrderedDict() + fanspeed = collections.OrderedDict() + + psu_temp_value = psu.Temperature.Value + temperature["Value"] = psu_temp_value if (psu_temp_value is not None) else self.error_ret + temperature["Min"] = psu.Temperature.Min + temperature["Max"] = psu.Temperature.Max + temperature["Unit"] = psu.Temperature.Unit + + fanspeed["Value"] = psu.FanSpeed.Value + fanspeed["Min"] = psu.FanSpeed.Min + fanspeed["Max"] = psu.FanSpeed.Max + fanspeed["Unit"] = psu.FanSpeed.Unit + + psu_inputvoltage_value = psu.InputsVoltage.Value + inputdic_voltage["Value"] = psu_inputvoltage_value if ( + psu_inputvoltage_value is not None) else self.error_ret + inputdic_voltage["Min"] = psu.InputsVoltage.Min + inputdic_voltage["Max"] = psu.InputsVoltage.Max + inputdic_voltage["Unit"] = psu.InputsVoltage.Unit + + psu_inputcurrent_value = psu.InputsCurrent.Value + inputdic_current["Value"] = psu_inputcurrent_value if ( + psu_inputcurrent_value is not None) else self.error_ret + inputdic_current["Min"] = psu.InputsCurrent.Min + inputdic_current["Max"] = psu.InputsCurrent.Max + inputdic_current["Unit"] = psu.InputsCurrent.Unit + + psu_inputpower_value = psu.InputsPower.Value + inputdic_power["Value"] = psu_inputpower_value if (psu_inputpower_value is not None) else self.error_ret + inputdic_power["Min"] = psu.InputsPower.Min + inputdic_power["Max"] = psu.InputsPower.Max + inputdic_power["Unit"] = psu.InputsPower.Unit + + psu_outputvoltage_value = psu.OutputsVoltage.Value + outputdic_voltage["Value"] = psu_outputvoltage_value if ( + psu_outputvoltage_value is not None) else self.error_ret + outputdic_voltage["Min"] = psu.OutputsVoltage.Min + outputdic_voltage["Max"] = psu.OutputsVoltage.Max + outputdic_voltage["Unit"] = psu.OutputsVoltage.Unit + + psu_outputcurrent_value = psu.OutputsCurrent.Value + outputdic_current["Value"] = psu_outputcurrent_value if ( + psu_outputcurrent_value is not None) else self.error_ret + outputdic_current["Min"] = psu.OutputsCurrent.Min + outputdic_current["Max"] = psu.OutputsCurrent.Max + outputdic_current["Unit"] = psu.OutputsCurrent.Unit + + psu_outputpower_value = psu.OutputsPower.Value + outputdic_power["Value"] = psu_outputpower_value if ( + psu_outputpower_value is not None) else self.error_ret + outputdic_power["Min"] = psu.OutputsPower.Min + outputdic_power["Max"] = psu.OutputsPower.Max + outputdic_power["Unit"] = psu.OutputsPower.Unit + + val_list["%s%s" % (psu.name, "Vol_I")] = inputdic_voltage + val_list["%s%s" % (psu.name, "Curr_I")] = inputdic_current + val_list["%s%s" % (psu.name, "Power_I")] = inputdic_power + val_list["%s%s" % (psu.name, "Vol_O")] = outputdic_voltage + val_list["%s%s" % (psu.name, "Curr_O")] = outputdic_current + val_list["%s%s" % (psu.name, "Power_O")] = outputdic_power + val_list["%s%s" % (psu.name, "Fan")] = fanspeed + val_list["%s%s" % (psu.name, "Temp")] = temperature + + return val_list + + # cpld + def get_cpld_total_number(self): + cpldlist = self.chas.cpld_list + return len(cpldlist) + + def get_cpld_user_reg(self): + cpld = self.chas.get_cpld_byname("BASE_CPLD") + if cpld is None: + return None + return cpld.get_user_reg() + + def set_cpld_user_reg(self, value): + if isinstance(value, int) is False: + baseutil.logger_debug("value must int %s" % type(value)) + return -1 + if (int(value) < 0 or int(value) > 255): + baseutil.logger_debug("value must [0 - 255]") + return -1 + cpld = self.chas.get_cpld_byname("BASE_CPLD") + if cpld is None: + baseutil.logger_debug("name BASE_CPLD not find") + return -1 + if cpld.set_user_reg(value) is True: + return 0 + return -1 + + def set_cpld_console_owner(self, owner): + """ + Set console I/O owner + + @param owner I/O owner of the console, either "cpu" or "bmc" + + @return 0 for success, -1 for failure + """ + if owner is None: + baseutil.logger_debug("owner is None") + return -1 + owner_tuple = ("cpu", "bmc") + if owner not in owner_tuple: + baseutil.logger_debug("owner is %s, must cpu or bmc" % owner) + return -1 + cpld = self.chas.get_cpld_byname("BASE_CPLD") + if cpld is None: + baseutil.logger_debug("name BASE_CPLD not find") + return -1 + if cpld.set_console_owner(owner) is True: + return 0 + return -1 + + def get_cpld_version_by_id(self, cpld_id): + cpldlist = self.chas.cpld_list + cpldtmp = None + for cpld in cpldlist: + if cpld.cpld_id == cpld_id: + cpldtmp = cpld + + dic = collections.OrderedDict() + if cpldtmp is None: + dic["Name"] = self.na_ret + dic["Version"] = self.na_ret + dic["Desc"] = self.na_ret + dic["Slot"] = None + dic["Warm"] = None + else: + dic["Name"] = cpldtmp.name + dic["Version"] = cpldtmp.get_version() + dic["Desc"] = cpldtmp.desc + dic["Slot"] = cpldtmp.slot + dic["Warm"] = cpldtmp.warm + return dic + + def get_cpld_all_version(self): + """ + Get version of all CPLDs' that can be read from BMC + + @return dict of CPLDs' version or None for failure. + example outputs: + { + "BASE_CPLD": "0.1", # or "N/A" for read failure + "FAN_CPLD": "0.2" + } + """ + cpld_version = { + "BASE_CPLD": "N/A", + "FAN_CPLD": "N/A" + } + for cpld_name in cpld_version: + cpld = self.chas.get_cpld_byname(cpld_name) + if cpld is None: + baseutil.logger_debug("name %s not find" % cpld_name) + continue + cpld_version[cpld_name] = cpld.get_version() + return cpld_version + + # comp + def get_comp_total_number(self): + complist = self.chas.comp_list + return len(complist) + + def get_comp_list(self): + return self.chas.comp_list + + def get_comp_id(self, comp): + return comp.comp_id + + def get_comp_version_by_id(self, comp_id): + comp_list = self.chas.comp_list + comptmp = None + for comp in comp_list: + if comp.comp_id == comp_id: + comptmp = comp + break + + dic = collections.OrderedDict() + if comptmp is None: + dic["Name"] = self.na_ret + dic["Version"] = self.na_ret + dic["Desc"] = self.na_ret + dic["Slot"] = None + else: + dic["Name"] = comptmp.name + dic["Version"] = comptmp.get_version() + dic["Desc"] = comptmp.desc + dic["Slot"] = comptmp.slot + return dic + + def get_bmc_productname(self): + """ + Get product name + + @return product name string, e.g. $(device name)-F-$(VENDOR_NAME), if error return "N/A" + """ + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + baseutil.logger_debug("name bmc(master) not find") + return self.na_ret + return bmc.get_productname() + + def call_bmc_diagcmd(self, cmdstr): + """ + Call BMC diag comman func + + @return ret: 0 sucess , -1 fail + outmsg: if success is out msg, or fail is err msg + """ + if (cmdstr is None or cmdstr == ""): + outmsg = "cmdstr is empty" + baseutil.logger_debug(outmsg) + return -1, outmsg + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + outmsg = "name bmc(master) not find" + baseutil.logger_debug(outmsg) + return -1, outmsg + baseutil.logger_debug("call cmdstr %s" % cmdstr) + return bmc.call_diagcmd(cmdstr) + + def write_bios_version(self, flash, version): + bios = self.chas.get_bios_byname("master") + if bios is None: + baseutil.logger_debug("name bios(master) not find") + return -1 + return bios.set_bios_version(flash, version) + + def get_bios_version(self): + bios = self.chas.get_bios_byname("master") + if bios is None: + baseutil.logger_debug("name bios(master) not find") + return -1 + return bios.get_bios_version() + + def get_bios_status(self): + bios = self.chas.get_bios_byname("master") + if bios is None: + baseutil.logger_debug("name bios(master) not find") + return -1 + return bios.get_bios_boot_status() + + def get_bmc_mac_rov(self): + """ + Get BMC mac rov + + @return ret: 0 sucess , -1 fail + outmsg: if success is out msg, or fail is err msg + """ + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + msg = "name master not find" + baseutil.logger_debug(msg) + return -1, msg + return bmc.get_mac_rov() + + def get_bmc_next_boot(self): + """ + Get next booting flash of BMC + + @return 'master'/'slave' on success, "N/A" for failure + """ + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + baseutil.logger_debug("name master not find") + return self.na_ret + return bmc.get_next_boot() + + def set_bmc_next_boot(self, flash): + """ + Set flash from which next BMC boot + + @param flash Booting flash of BMC, "master" or "slave" + + @return 0 on success, -1 for failure + """ + flash_status = ("master", "slave") + if flash is None or flash not in flash_status: + baseutil.logger_debug("parameter flash illegal, should be [master|slave]") + return -1 + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + baseutil.logger_debug("name master not find") + return -1 + return bmc.set_next_boot(flash) + + def reboot_bmc(self): + """ + Reboot running BMC + """ + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + baseutil.logger_debug("name master not find") + return -1 + return bmc.reboot() + + def get_bmc_info(self): + """ + Get BMC info + + @return dict of BMC info or None for failure + "Version": "1.1.1", # "N/A" + "Flash": "master", # "N/A" + "Next": "master" # "N/A" + """ + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + baseutil.logger_debug("name master not find") + return self.na_ret + return bmc.get_info() + + def get_bmc_version_all(self): + """ + @return dict of BMCs + { + "MasterVersion": "1.1.1", # "N/A" + "SlaveVersion": "1.1.1" # "N/A" + } + """ + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + baseutil.logger_debug("name master not find") + return self.na_ret + return bmc.get_version_all() + + def bmc_execute_command(self, cmd_str): + ret, output = osutil.command(cmd_str) + if ret: + baseutil.logger_debug("execute %s command failed" % (cmd_str)) + return ret, output + + def get_cpu_reset_num(self): + """ + Get CPU reset num + @return CPU reset num on success, -1 for failure + """ + cpu = self.chas.get_cpu_byname("cpu") + if cpu is None: + msg = "name cpu not find" + baseutil.logger_debug(msg) + return -1 + return cpu.get_cpu_reset_num() + + def get_cpu_reboot_cause(self): + """ + Get CPU reboot cause + @return string of cpu reboot reason + """ + cpu = self.chas.get_cpu_byname("cpu") + if cpu is None: + msg = "name cpu not find" + baseutil.logger_debug(msg) + return "Unknown reboot cause" + return cpu.get_cpu_reboot_cause() + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/led.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/led.py new file mode 100644 index 000000000000..7fb869c74d7f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/led.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +####################################################### +# +# led.py +# Python implementation of the Class led +# +####################################################### +from plat_hal.devicebase import devicebase + + +class led(devicebase): + def __init__(self, conf=None): + if conf is not None: + self.name = conf.get('name', None) + self.led_type = conf.get('led_type', None) + self.led_attrs_config = conf.get('led_attrs', None) + self.led_config = conf.get('led', None) + + def set_color(self, color): + status = self.led_attrs_config.get(color, None) + if status is None: + return False + + mask = self.led_attrs_config.get('mask', 0xff) + + if isinstance(self.led_config, list): + for led_config_index in self.led_config: + ret, value = self.get_value(led_config_index) + if (ret is False) or (value is None): + return False + setval = (int(value) & ~mask) | (status) + ret, val = self.set_value(led_config_index, setval) + if ret is False: + return ret + else: + ret, value = self.get_value(self.led_config) + if (ret is False) or (value is None): + return False + setval = (int(value) & ~mask) | (status) + ret, val = self.set_value(self.led_config, setval) + return ret + + def get_color(self): + mask = self.led_attrs_config.get('mask', 0xff) + ret, value = self.get_value(self.led_config) + if ret is False or value is None: + return False, 'N/A' + ledval = int(value) & mask + for key, val in self.led_attrs_config.items(): + if (ledval == val) and (key != "mask"): + return True, key + return False, 'N/A' diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/onie_e2.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/onie_e2.py new file mode 100644 index 000000000000..9ac32cace263 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/onie_e2.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +####################################################### +# +# onie_e2.py +# Python implementation of the Class onie_e2 +# +####################################################### +from plat_hal.devicebase import devicebase +from eepromutil.onietlv import onie_tlv + + +class onie_e2(devicebase): + + def __init__(self, conf=None): + self._cardid = "" + self._productname = "" + self._partnum = "" + self._serialnum = "" + self._macbase = "" + self._manufdate = "" + self._deviceversion = "" + self._labelrevision = "" + self._platformname = "" + self._onieversion = "" + self._macsize = "" + self._manufname = "" + self._manufcountry = "" + self._vendorname = "" + self._diagname = "" + self._servicetag = "" + + if conf is not None: + self.name = conf.get('name', None) + self.e2loc = conf.get('e2loc', None) + self.e2_path = self.e2loc.get('loc', None) + self.airflow = conf.get('airflow', "intake") + + @property + def cardid(self): + return self._cardid + + @property + def productname(self): + return self._productname + + @property + def partnum(self): + return self._partnum + + @property + def serialnum(self): + return self._serialnum + + @property + def macbase(self): + return self._macbase + + @property + def manufdate(self): + return self._manufdate + + @property + def deviceversion(self): + return self._deviceversion + + @property + def labelrevision(self): + return self._labelrevision + + @property + def platformname(self): + return self._platformname + + @property + def onieversion(self): + return self._onieversion + + @property + def macsize(self): + return self._macsize + + @property + def manufname(self): + return self._manufname + + @property + def manufcountry(self): + return self._manufcountry + + @property + def vendorname(self): + return self._vendorname + + @property + def diagname(self): + return self._diagname + + @property + def servicetag(self): + return self._servicetag + + def get_onie_e2_info(self): + try: + eeprom = self.get_eeprom_info(self.e2loc) + if eeprom is None: + raise Exception("%s: value is none" % self.name) + onietlv = onie_tlv() + onietlv.decode(eeprom) + self._cardid = onietlv.cardid + self._productname = onietlv.productname + self._partnum = onietlv.partnum + self._serialnum = onietlv.serialnum + self._macbase = onietlv.macbase + self._manufdate = onietlv.manufdate + self._deviceversion = onietlv.deviceversion + self._labelrevision = onietlv.labelrevision + self._platformname = onietlv.platformname + self._onieversion = onietlv.onieversion + self._macsize = onietlv.macsize + self._manufname = onietlv.manufname + self._manufcountry = onietlv.manufcountry + self._vendorname = onietlv.vendorname + self._diagname = onietlv.diagname + self._servicetag = onietlv.servicetag + except Exception: + return False + return True diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/osutil.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/osutil.py new file mode 100644 index 000000000000..684e26bb9ecd --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/osutil.py @@ -0,0 +1,440 @@ +#!/usr/bin/env python3 +####################################################### +# +# osutil.py +# Python implementation of the Class osutil +# +####################################################### + +import os +import glob +import re +import time +import subprocess +import fcntl +import syslog +from functools import wraps +from wbutil.smbus import SMBus + + +PLATFORM_HAL_DEBUG_FILE = "/etc/.platform_hal_debug_flag" + + +def platform_hal_debug(s): + if os.path.exists(PLATFORM_HAL_DEBUG_FILE): + syslog.openlog("PLATFORM_HAL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def retry(maxretry=6, delay=0.01): + ''' + maxretry: max retry times + delay : interval after last retry + ''' + def decorator(f): + @wraps(f) + def wrapper(*args, **kwargs): + time_retry = maxretry + time_delay = delay + result_msg = "" + while time_retry: + try: + val, result_msg = f(*args, **kwargs) + if val is True: + return val, result_msg + time_retry -= 1 + time.sleep(time_delay) + except Exception as e: + time_retry -= 1 + result_msg = str(e) + time.sleep(time_delay) + return False, "max time retry last errmsg is {}".format(result_msg) + return wrapper + return decorator + + +pidfile = None + + +def file_rw_lock(file_path): + global pidfile + pidfile = open(file_path, "r") + try: + fcntl.flock(pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB) + platform_hal_debug("file_rw_lock success") + return True + except Exception: + if pidfile is not None: + pidfile.close() + pidfile = None + return False + + +def file_rw_unlock(): + try: + global pidfile + + if pidfile is not None: + fcntl.flock(pidfile, fcntl.LOCK_UN) + pidfile.close() + pidfile = None + platform_hal_debug("file_rw_unlock success") + else: + platform_hal_debug("pidfile is invalid, do nothing") + return True + except Exception as e: + platform_hal_debug("file_rw_unlock err, msg: %s" % (str(e))) + return False + + +def take_file_rw_lock(file_path): + loop = 1000 + ret = False + for i in range(0, loop): + ret = file_rw_lock(file_path) + if ret is True: + break + time.sleep(0.001) + return ret + + +class osutil(object): + """ + osutil + """ + + @staticmethod + @retry(maxretry=6) + def wbi2cget_python(bus, addr, reg): + with SMBus(bus) as y: + val, ind = y.read_byte_data(addr, reg, True) + return val, ind + + @staticmethod + @retry(maxretry=6) + def wbi2cset_python(bus, addr, reg, value): + with SMBus(bus) as y: + val, ind = y.write_byte_data(addr, reg, value, True) + return val, ind + + @staticmethod + @retry(maxretry=6) + def wbi2cgetword_python(bus, addr, reg): + with SMBus(bus) as y: + val, ind = y.read_word_data(addr, reg, True) + return val, ind + + @staticmethod + @retry(maxretry=6) + def wbi2csetword_python(bus, addr, reg, value): + with SMBus(bus) as y: + val, ind = y.write_word_data(addr, reg, value, True) + return val, ind + + @staticmethod + @retry(maxretry=6) + def wbi2csetwordpec_python(bus, addr, reg, value): + with SMBus(bus) as y: + val, ind = y.write_word_data_pec(addr, reg, value, True) + return val, ind + + @staticmethod + @retry(maxretry=6) + def wbi2cset_byte_pec_python(bus, addr, reg, value): + with SMBus(bus) as y: + val, ind = y.write_byte_data_pec(addr, reg, value, True) + return val, ind + + @staticmethod + def command(cmdstr): + retcode, output = subprocess.getstatusoutput(cmdstr) + return retcode, output + + @staticmethod + def geti2cword_i2ctool(bus, addr, offset): + command_line = "i2cget -f -y %d 0x%02x 0x%02x wp" % (bus, addr, offset) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = osutil.command(command_line) + if ret == 0: + return True, int(ret_t, 16) + time.sleep(0.1) + return False, ret_t + + @staticmethod + def seti2cword_i2ctool(bus, addr, offset, val): + command_line = "i2cset -f -y %d 0x%02x 0x%0x 0x%04x wp" % (bus, addr, offset, val) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = osutil.command(command_line) + if ret == 0: + return True, ret_t + time.sleep(0.1) + return False, ret_t + + @staticmethod + def wbi2cget_i2ctool(bus, devno, address): + command_line = "i2cget -f -y %d 0x%02x 0x%02x " % (bus, devno, address) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = osutil.command(command_line) + if ret == 0: + return True, int(ret_t, 16) + time.sleep(0.1) + return False, ret_t + + @staticmethod + def wbi2cset_i2ctool(bus, devno, address, byte): + command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x" % ( + bus, devno, address, byte) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = osutil.command(command_line) + if ret == 0: + return True, ret_t + return False, ret_t + + @staticmethod + def geti2cword(bus, addr, offset): + return osutil.wbi2cgetword_python(bus, addr, offset) + + @staticmethod + def seti2cword(bus, addr, offset, val): + return osutil.wbi2csetword_python(bus, addr, offset, val) + + @staticmethod + def seti2cwordpec(bus, addr, offset, val): + return osutil.wbi2csetwordpec_python(bus, addr, offset, val) + + @staticmethod + def seti2c_byte_pec(bus, addr, offset, val): + return osutil.wbi2cset_byte_pec_python(bus, addr, offset, val) + + @staticmethod + def wbi2cget(bus, devno, address): + return osutil.wbi2cget_python(bus, devno, address) + + @staticmethod + def wbi2cset(bus, devno, address, byte): + return osutil.wbi2cset_python(bus, devno, address, byte) + + @staticmethod + def byteTostr(val): + strtmp = '' + for value in val: + strtmp += chr(value) + return strtmp + + @staticmethod + def io_rd(reg_addr, read_len=1): + try: + regaddr = 0 + if isinstance(reg_addr, int): + regaddr = reg_addr + else: + regaddr = int(reg_addr, 16) + devfile = "/dev/port" + fd = os.open(devfile, os.O_RDWR | os.O_CREAT) + os.lseek(fd, regaddr, os.SEEK_SET) + val = os.read(fd, read_len) + return True, "".join(["%02x" % item for item in val]) + except ValueError as e: + return False, str(e) + except Exception as e: + return False, str(e) + finally: + os.close(fd) + + @staticmethod + def readsysfs(location, flock_path=None): + flock_path_tmp = None + platform_hal_debug("readsysfs, location:%s, flock_path:%s" % (location, flock_path)) + try: + if flock_path is not None: + flock_paths = glob.glob(flock_path) + if len(flock_paths) != 0: + flock_path_tmp = flock_paths[0] + platform_hal_debug("try to get file lock, path:%s" % flock_path_tmp) + ret = take_file_rw_lock(flock_path_tmp) + if ret is False: + platform_hal_debug("take file lock timeout, path:%s" % flock_path_tmp) + return False, ("take file rw lock timeout, path:%s" % flock_path_tmp) + else: + platform_hal_debug("config error, can't find flock_path:%s" % flock_path) + + locations = glob.glob(location) + with open(locations[0], 'rb') as fd1: + retval = fd1.read() + retval = osutil.byteTostr(retval) + if flock_path_tmp is not None: + file_rw_unlock() + + retval = retval.rstrip('\r\n') + retval = retval.lstrip(" ") + except Exception as e: + if flock_path_tmp is not None: + file_rw_unlock() + platform_hal_debug("readsysfs error, msg:%s" % str(e)) + return False, (str(e) + " location[%s]" % location) + return True, retval + + @staticmethod + def writesysfs(location, value): + try: + if not os.path.isfile(location): + print(location, 'not found !') + return False, ("location[%s] not found !" % location) + with open(location, 'w') as fd1: + fd1.write(value) + except Exception as e: + return False, (str(e) + " location[%s]" % location) + return True, ("set location[%s] %s success !" % (location, value)) + + @staticmethod + def getdevmem(addr, digit, mask): + command_line = "devmem 0x%02x %d" % (addr, digit) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = osutil.command(command_line) + if ret == 0: + if mask is not None: + ret_t = str(int(ret_t, 16) & mask) + return True, ret_t + return False, ret_t + + @staticmethod + def readdevfile_ascii(path, offset, length): + msg = "" + ret = "" + joinstr = '' + fd = -1 + + if not os.path.exists(path): + msg = path + " not found !" + return False, msg + + try: + fd = os.open(path, os.O_RDONLY) + os.lseek(fd, offset, os.SEEK_SET) + ret = os.read(fd, length) + for item in ret: + joinstr += '%02x ' % item # like sysfs, display in hex + except Exception as e: + msg = str(e) + return False, msg + finally: + if fd > 0: + os.close(fd) + return True, joinstr + + @staticmethod + def readdevfile(path, offset, length): + msg = "" + ret = "" + fd = -1 + val_list = [] + + if not os.path.exists(path): + msg = path + " not found !" + return False, msg + + try: + fd = os.open(path, os.O_RDONLY) + os.lseek(fd, offset, os.SEEK_SET) + ret = os.read(fd, length) + for item in ret: + val_list.append(item) + except Exception as e: + msg = str(e) + return False, msg + finally: + if fd > 0: + os.close(fd) + return True, val_list + + @staticmethod + def writedevfile(path, offset, buf): + msg = "" + fd = -1 + + if not os.path.exists(path): + msg = path + " not found !" + return False, msg + + if isinstance(buf, list): + if len(buf) == 0: + msg = "buf:%s is NONE !" % buf + return False, msg + elif isinstance(buf, int): + buf = [buf] + else: + msg = "buf:%s is not list type or not int type !" % buf + return False, msg + + try: + fd = os.open(path, os.O_WRONLY) + os.lseek(fd, offset, os.SEEK_SET) + ret = os.write(fd, bytes(buf)) + except Exception as e: + msg = str(e) + return False, msg + finally: + if fd > 0: + os.close(fd) + + return True, ret + + @staticmethod + def wb_os_system(cmd): + status, output = subprocess.getstatusoutput(cmd) + return status, output + + @staticmethod + def getsdkreg(reg): + try: + cmd = "bcmcmd -t 1 'getr %s ' < /dev/null" % reg + ret, result = osutil.wb_os_system(cmd) + result_t = result.strip().replace("\r", "").replace("\n", "") + if ret != 0 or "Error:" in result_t: + return False, result + patt = r"%s.(.*):(.*)>drivshell" % reg + rt = re.findall(patt, result_t, re.S) + test = re.findall("=(.*)", rt[0][0])[0] + except Exception as e: + return False, 'get sdk register error, msg: %s' % str(e) + return True, test + + @staticmethod + def getmactemp(): + try: + result = {} + # need to exec twice + osutil.wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") + ret, log = osutil.wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") + if ret: + return False, result + logs = log.splitlines() + for line in logs: + if "average" in line: + b = re.findall(r'\d+.\d+', line) + result["average"] = b[0] + elif "maximum" in line: + b = re.findall(r'\d+.\d+', line) + result["maximum"] = b[0] + except Exception as e: + return False, str(e) + return True, result + + @staticmethod + def std_match(stdout, pattern): + if pattern is None: + return stdout.strip() + for line in stdout.splitlines(): + if re.match(pattern, line): + return line.strip() + return None diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/psu.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/psu.py new file mode 100644 index 000000000000..a5fc3bf77098 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/psu.py @@ -0,0 +1,701 @@ +#!/usr/bin/env python3 +####################################################### +# +# psu.py +# Python implementation of the Class psu +# +####################################################### +from eepromutil.fru import ipmifru +from eepromutil.cust_fru import CustFru +from plat_hal.devicebase import devicebase +from plat_hal.sensor import sensor + + +class psu(devicebase): + __pmbus = None + __e2loc = None + __productManufacturer = None # : ARTESYN + __productName = None # : CRPS550W + __productPartModelName = None # : CSU550AP-3-300 + __productVersion = None # : AB + __productSerialNumber = None # : M623UZ00JYABL + __AirFlow = None # 'N/A' + __AirFlowconifg = None + __psu_display_name = None # 'N/A' + __psu_display_name_conifg = None + __psu_not_present_pwm = None + __InputStatus_config = None + __OutputStatus_config = None + __FanSpeed_config = None + __Temperature_config = None + __InputStatus = None + __OutputStatus = None + __FanSpeed = None + __Temperature = None + __FanSpeedMin = None + __FanSpeedMax = None + __FanSpeedTolerance = None + __InputsVoltage_config = None + __InputsCurrent_config = None + __InputsPower_config = None + __OutputsVoltage_config = None + __OutputsCurrent_config = None + __OutputsPower_config = None + __InputsVoltage = {} + __InputsCurrent = None + __InputsPower = None + __OutputsVoltage = None + __OutputsCurrent = None + __OutputsPower = None + __InputsType_config = None + __InputsType = None + __psu_sn_config = None + __psu_hw_config = None + __psu_pn_config = None + __psu_vendor_config = None + __TempStatus_config = None + __FanStatus_config = None + __TempStatus = None + __FanStatus = None + + def __init__(self, conf=None): + self.pmbus = conf.get("pmbusloc", None) + self.e2loc = conf.get("e2loc", None) + self.e2_type = conf.get('e2_type', "fru") + self.__presentconfig = conf.get("present", None) + self.name = conf.get("name", None) + self.get_threshold_by_model = conf.get("get_threshold_by_model", 0) + self.AirFlowconifg = conf.get("airflow", None) + self.psu_display_name_conifg = conf.get("psu_display_name", None) + self.psu_not_present_pwm = conf.get("psu_not_present_pwm", 100) + self.Temperature_config = conf.get("Temperature", None) + self.Temperature = sensor(self.Temperature_config, self.get_psu_model) + + self.FanSpeedTolerance = conf.get('psu_fan_tolerance', 30) + self.FanSpeed_config = conf.get("FanSpeed", None) + self.FanSpeed = sensor(self.FanSpeed_config, self.get_psu_model) + + self.__InputsVoltage_config = conf.get("InputsVoltage", None) + self.generate_psu_input_vol(self.__InputsVoltage_config) + self.__InputsCurrent_config = conf.get("InputsCurrent", None) + self.InputsCurrent = sensor(self.__InputsCurrent_config, self.get_psu_model) + self.__InputsPower_config = conf.get("InputsPower", None) + self.InputsPower = sensor(self.__InputsPower_config, self.get_psu_model) + self.__OutputsVoltage_config = conf.get("OutputsVoltage", None) + self.OutputsVoltage = sensor(self.__OutputsVoltage_config, self.get_psu_model) + self.__OutputsCurrent_config = conf.get("OutputsCurrent", None) + self.OutputsCurrent = sensor(self.__OutputsCurrent_config, self.get_psu_model) + self.__OutputsPower_config = conf.get("OutputsPower", None) + self.OutputsPower = sensor(self.__OutputsPower_config, self.get_psu_model) + + self.__InputStatus_config = conf.get("InputsStatus", None) + self.__OutputStatus_config = conf.get("OutputsStatus", None) + self.__InputsType_config = conf.get('InputsType', None) + self.__psu_sn_config = conf.get('psu_sn', None) + self.__psu_hw_config = conf.get('psu_hw', None) + self.__psu_pn_config = conf.get('psu_pn', None) + self.__psu_vendor_config = conf.get('psu_vendor', None) + self.__TempStatus_config = conf.get("TempStatus", None) + self.__FanStatus_config = conf.get("FanStatus", None) + + def get_psu_model(self): + if self.productPartModelName is None: + ret = self.get_fru_info() + if ret is False: + return None + return self.productPartModelName + + def generate_psu_input_vol(self, config): + tmp = {} + for (key, item) in config.items(): + tmp.setdefault(key, sensor(item, self.get_psu_model)) + self.__InputsVoltage = tmp + + def get_psu_sensor_by_name(self, psutype): + return self.__InputsVoltage.get(psutype) or self.__InputsVoltage.get('other') + + @property + def InputsVoltage(self): + psutype = self.InputsType + input_sensor = self.get_psu_sensor_by_name(psutype) + if input_sensor is None: + return None + return input_sensor + + @InputsVoltage.setter + def InputsVoltage(self, val): + self.__InputsVoltage = val + + @property + def InputsCurrent(self): + return self.__InputsCurrent + + @InputsCurrent.setter + def InputsCurrent(self, val): + self.__InputsCurrent = val + + @property + def InputsPower(self): + return self.__InputsPower + + @InputsPower.setter + def InputsPower(self, val): + self.__InputsPower = val + + @property + def OutputsVoltage(self): + return self.__OutputsVoltage + + @OutputsVoltage.setter + def OutputsVoltage(self, val): + self.__OutputsVoltage = val + + @property + def OutputsCurrent(self): + return self.__OutputsCurrent + + @OutputsCurrent.setter + def OutputsCurrent(self, val): + self.__OutputsCurrent = val + + @property + def OutputsPower(self): + return self.__OutputsPower + + @OutputsPower.setter + def OutputsPower(self, val): + self.__OutputsPower = val + + @property + def InputStatus(self): + if self.__InputStatus_config is None: + return None + if self.present is False: + self.__InputStatus = False + else: + ret, val = self.get_value(self.__InputStatus_config) + mask = self.__InputStatus_config.get("mask") + if ret is True: + if isinstance(val, str): + value = int(val, 16) + else: + value = val + ttt = value & mask + okval = self.__InputStatus_config.get("okval", 0) + if ttt == okval: + self.__InputStatus = True + else: + self.__InputStatus = False + else: + self.__InputStatus = False + return self.__InputStatus + + @InputStatus.setter + def InputStatus(self, val): + self.__InputStatus = val + + @property + def TempStatus(self): + if self.__TempStatus_config is None: + return None + if self.present is False: + self.__TempStatus = False + else: + ret, val = self.get_value(self.__TempStatus_config) + mask = self.__TempStatus_config.get("mask") + if ret is True: + if isinstance(val, str): + value = int(val, 16) + else: + value = val + ttt = value & mask + okval = self.__TempStatus_config.get("okval", 0) + if ttt == okval: + self.__TempStatus = True + else: + self.__TempStatus = False + else: + self.__TempStatus = False + return self.__TempStatus + + @TempStatus.setter + def TempStatus(self, val): + self.__TempStatus = val + + @property + def FanStatus(self): + if self.__FanStatus_config is None: + return None + if self.present is False: + self.__FanStatus = False + else: + ret, val = self.get_value(self.__FanStatus_config) + mask = self.__FanStatus_config.get("mask") + if ret is True: + if isinstance(val, str): + value = int(val, 16) + else: + value = val + ttt = value & mask + okval = self.__FanStatus_config.get("okval", 0) + if ttt == okval: + self.__FanStatus = True + else: + self.__FanStatus = False + else: + self.__FanStatus = False + return self.__FanStatus + + @FanStatus.setter + def FanStatus(self, val): + self.__FanStatus = val + + def get_input_type_pmbus(self): + psutypedecode = self.__InputsType_config.get('psutypedecode', {}) + if self.present is False: + self.__InputsType = psutypedecode.get(0x00) + else: + ret, val = self.get_value(self.__InputsType_config) + self.__InputsType = self.__InputsType_config.get(val, None) + if self.__InputsType is not None: + return self.__InputsType + if ret is True and val in psutypedecode: + self.__InputsType = psutypedecode.get(val) + else: + self.__InputsType = psutypedecode.get(0x00) + return self.__InputsType + + def get_input_type_fru(self): + self.__InputsType = 'N/A' + if self.productPartModelName is None: + ret = self.get_fru_info() + if ret is False: + return self.__InputsType + psutypedecode = self.__InputsType_config.get('psutypedecode', {}) + for key, value in psutypedecode.items(): + if self.productPartModelName in value: + self.__InputsType = key + return self.__InputsType + + @property + def InputsType(self): + gettype = self.__InputsType_config.get('gettype', "pmbus") + if gettype == "pmbus": + return self.get_input_type_pmbus() + + if gettype == "fru": + return self.get_input_type_fru() + + self.__InputsType = 'N/A' + return self.__InputsType + + @InputsType.setter + def InputsType(self, val): + self.__InputsType = val + + @property + def FanSpeedMin(self): + return self.__FanSpeedMin + + @FanSpeedMin.setter + def FanSpeedMin(self, val): + self.__FanSpeedMin = val + + @property + def FanSpeedMax(self): + return self.__FanSpeedMax + + @FanSpeedMax.setter + def FanSpeedMax(self, val): + self.__FanSpeedMax = val + + @property + def FanSpeedTolerance(self): + return self.__FanSpeedTolerance + + @FanSpeedTolerance.setter + def FanSpeedTolerance(self, val): + self.__FanSpeedTolerance = val + + @property + def OutputStatus(self): + if self.__OutputStatus_config is None: + return None + if self.present is False: + self.__OutputStatus = False + else: + ret, val = self.get_value(self.__OutputStatus_config) + mask = self.__OutputStatus_config.get("mask") + if ret is True: + if isinstance(val, str): + value = int(val, 16) + else: + value = val + ttt = value & mask + okval = self.__OutputStatus_config.get("okval", 0) + if ttt == okval: + self.__OutputStatus = True + else: + self.__OutputStatus = False + else: + self.__OutputStatus = False + return self.__OutputStatus + + @OutputStatus.setter + def OutputStatus(self, val): + self.__OutputStatus = val + + @property + def FanSpeed(self): + return self.__FanSpeed + + @FanSpeed.setter + def FanSpeed(self, val): + self.__FanSpeed = val + + @property + def Temperature(self): + return self.__Temperature + + @Temperature.setter + def Temperature(self, val): + self.__Temperature = val + + @property + def Temperature_config(self): + return self.__Temperature_config + + @Temperature_config.setter + def Temperature_config(self, val): + self.__Temperature_config = val + + @property + def AirFlowconifg(self): + return self.__AirFlowconifg + + @AirFlowconifg.setter + def AirFlowconifg(self, val): + self.__AirFlowconifg = val + + @property + def psu_display_name_conifg(self): + return self.__psu_display_name_conifg + + @psu_display_name_conifg.setter + def psu_display_name_conifg(self, val): + self.__psu_display_name_conifg = val + + @property + def pmbus(self): + return self.__pmbus + + @pmbus.setter + def pmbus(self, val): + self.__pmbus = val + + @property + def e2loc(self): + return self.__e2loc + + @e2loc.setter + def e2loc(self, val): + self.__e2loc = val + + @property + def AirFlow(self): + return self.__AirFlow + + @AirFlow.setter + def AirFlow(self, val): + self.__AirFlow = val + + @property + def psu_display_name(self): + return self.__psu_display_name + + @psu_display_name.setter + def psu_display_name(self, val): + self.__psu_display_name = val + + @property + def psu_not_present_pwm(self): + return self.__psu_not_present_pwm + + @psu_not_present_pwm.setter + def psu_not_present_pwm(self, val): + self.__psu_not_present_pwm = val + + @property + def present(self): + ret, val = self.get_value(self.__presentconfig) + if ret is False or val is None: + return False + mask = self.__presentconfig.get("mask") + if isinstance(val, str): + value = int(val, 16) + else: + value = val + ttt = value & mask + okval = self.__presentconfig.get("okval", 0) + if ttt == okval: + return True + return False + + @property + def productManufacturer(self): + return self.__productManufacturer + + @productManufacturer.setter + def productManufacturer(self, val): + self.__productManufacturer = val + + @property + def productName(self): + return self.__productName + + @productName.setter + def productName(self, val): + self.__productName = val + + @property + def productPartModelName(self): + return self.__productPartModelName + + @productPartModelName.setter + def productPartModelName(self, val): + self.__productPartModelName = val + + @property + def productVersion(self): + return self.__productVersion + + @productVersion.setter + def productVersion(self, val): + self.__productVersion = val + + @property + def productSerialNumber(self): + return self.__productSerialNumber + + @productSerialNumber.setter + def productSerialNumber(self, val): + self.__productSerialNumber = val + + @property + def psu_sn_sysfs(self): + if self.__psu_sn_config is None: + return None + ret, val = self.get_value(self.__psu_sn_config) + if ret is False or val is None: + return None + return val + + @property + def psu_hw_sysfs(self): + if self.__psu_hw_config is None: + return None + ret, val = self.get_value(self.__psu_hw_config) + if ret is False or val is None: + return None + return val + + @property + def psu_pn_sysfs(self): + if self.__psu_pn_config is None: + return None + ret, val = self.get_value(self.__psu_pn_config) + if ret is False or val is None: + return None + return val + + @property + def psu_vendor_sysfs(self): + if self.__psu_vendor_config is None: + return None + ret, val = self.get_value(self.__psu_vendor_config) + if ret is False or val is None: + return None + return val + + def __str__(self): + formatstr = \ + "name : %s \n" \ + "productManufacturer : %s \n" \ + "productName : %s \n" \ + "productPartModelName: %s \n" \ + "productVersion : %s \n" \ + "productSerialNumber : %s \n" \ + "AirFlow : %s \n" \ + + tmpstr = formatstr % (self.name, self.productManufacturer, + self.productName, self.productPartModelName, + self.productVersion, self.productSerialNumber, self.AirFlow) + return tmpstr + + def get_fan_speed_pwm(self): + if self.pmbus is None: + return None + if self.present is False: + return self.psu_not_present_pwm + selfconfig = {} + selfconfig['bus'] = self.pmbus['bus'] + selfconfig['addr'] = self.pmbus['addr'] + selfconfig['way'] = 'i2cword' + selfconfig['offset'] = 0x3b + ret, val = self.get_value(selfconfig) + if ret is True: + return val + return None + + def set_fan_speed_pwm(self, pwm): + ''' + pmbus + if duty: + i2cset -f -y 0x3b 0x0064 wp + ''' + if self.present is False: + return None + + if self.pmbus is None: + return None + + if 0 <= pwm <= 100: + # enable duty first + selfconfig = {} + + selfconfig['bus'] = self.pmbus['bus'] + selfconfig['addr'] = self.pmbus['addr'] + selfconfig['way'] = 'i2cpec' + selfconfig['offset'] = 0x3a + self.set_value(selfconfig, 0x80) + + selfconfig['way'] = 'i2cwordpec' + selfconfig['offset'] = 0x3b + bytetmp = pwm + ret, val = self.set_value(selfconfig, int(bytetmp)) + if ret is True: + return True + return None + raise Exception("pwm not in range [0,100]") + + def get_fru_info_by_sysfs(self): + try: + psu_sn = self.psu_sn_sysfs + psu_hw = self.psu_hw_sysfs + psu_pn = self.psu_pn_sysfs + psu_vendor = self.psu_vendor_sysfs + if psu_sn is None or psu_hw is None or psu_pn is None or psu_vendor is None: + return False + self.productSerialNumber = psu_sn.strip().replace(chr(0), "") + self.productVersion = psu_hw.strip() + self.productPartModelName = psu_pn.strip() + self.productManufacturer = psu_vendor.strip().replace(chr(0), "") + except Exception: + self.productSerialNumber = None + self.productVersion = None + self.productPartModelName = None + self.productManufacturer = None + return False + return True + + def get_fru_info_by_decode(self): + try: + eeprom = self.get_eeprom_info(self.e2loc) + if eeprom is None: + raise Exception("%s:value is none" % self.name) + fru = ipmifru() + if isinstance(eeprom, bytes): + eeprom = self.byteTostr(eeprom) + fru.decodeBin(eeprom) + if fru.productInfoArea is not None: + self.productManufacturer = fru.productInfoArea.productManufacturer.strip() + self.productName = fru.productInfoArea.productName.strip() + self.productPartModelName = fru.productInfoArea.productPartModelName.strip() + self.productVersion = fru.productInfoArea.productVersion.strip() + self.productSerialNumber = fru.productInfoArea.productSerialNumber.strip().replace(chr(0), "") + except Exception: + self.productManufacturer = None + self.productName = None + self.productPartModelName = None + self.productVersion = None + self.productSerialNumber = None + return False + return True + + def get_custfru_info_by_decode(self): + try: + eeprom = self.get_eeprom_info(self.e2loc) + if eeprom is None: + raise Exception("%s:value is none" % self.name) + custfru = CustFru() + if isinstance(eeprom, bytes): + eeprom = self.byteTostr(eeprom) + custfru.decode(eeprom) + self.productManufacturer = custfru.manufacturer.strip() + self.productName = custfru.product_name.strip() + self.productPartModelName = custfru.product_name.strip() + self.productVersion = custfru.version.strip() + self.productSerialNumber = custfru.serial_number.strip().replace(chr(0), "") + except Exception: + self.productManufacturer = None + self.productName = None + self.productPartModelName = None + self.productVersion = None + self.productSerialNumber = None + return False + return True + + def get_fru_info(self): + try: + if self.present is not True: + raise Exception("%s: not present" % self.name) + + if self.get_fru_info_by_sysfs() is True: + return True + + if self.e2_type == "fru": + return self.get_fru_info_by_decode() + + if self.e2_type == "custfru": + return self.get_custfru_info_by_decode() + + raise Exception("%s: unsupport e2_type: %s" % (self.name, self.e2_type)) + except Exception: + self.productManufacturer = None + self.productName = None + self.productPartModelName = None + self.productVersion = None + self.productSerialNumber = None + return False + + def get_AirFlow(self): + if self.productPartModelName is None: + ret = self.get_fru_info() + if ret is False: + self.AirFlow = None + return False + if self.AirFlowconifg is None: + self.AirFlow = None + return False + for i in self.AirFlowconifg: + if self.productPartModelName in self.AirFlowconifg[i]: + self.AirFlow = i + return True + self.AirFlow = None + return False + + def get_psu_display_name(self): + if self.productPartModelName is None: + ret = self.get_fru_info() + if ret is False: + self.psu_display_name = None + return False + if self.psu_display_name_conifg is None: + self.psu_display_name = self.productPartModelName + return False + for i in self.psu_display_name_conifg: + if self.productPartModelName in self.psu_display_name_conifg[i]: + self.psu_display_name = i + return True + self.psu_display_name = self.productPartModelName + return False diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/rotor.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/rotor.py new file mode 100644 index 000000000000..2b4e4ffd5f0e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/rotor.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +####################################################### +# +# rotor.py +# Python implementation of the Class rotor +# +####################################################### +from plat_hal.devicebase import devicebase +from plat_hal.sensor import sensor + + +class rotor(devicebase): + __rotor_Running = None + __rotor_HwAlarm_conf = None + __rotor_Speed = None + __rotor_run_conf = None + __Speedconfig = None + __i2c_speed = None + __SpeedMin = None + __SpeedMax = None + __SpeedTolerance = None + + def __init__(self, conf=None): + self.name = conf.get('name', None) + self.rotor_HwAlarm_conf = conf.get('HwAlarm', None) + self.rotor_run_conf = conf.get('Running', None) + self.SpeedMin = conf.get('SpeedMin', None) + self.SpeedMax = conf.get('SpeedMax', None) + self.Tolerance = conf.get('tolerance', 30) + self.rotor_Speed = sensor(conf.get('Speed', None)) + self.Speedconfig = conf.get('Set_speed', None) + + def getRunning(self): + ret, val = self.get_value(self.rotor_run_conf) + if ret is False or val is None: + return False + if isinstance(val, str): + value = int(val, 16) + else: + value = val + mask = self.rotor_run_conf.get("mask") + is_runing_value = self.rotor_run_conf.get("is_runing") + flag = value & mask + if flag == is_runing_value: + return True + return False + + @property + def SpeedMin(self): + return self.__SpeedMin + + @SpeedMin.setter + def SpeedMin(self, val): + self.__SpeedMin = val + + @property + def SpeedMax(self): + return self.__SpeedMax + + @SpeedMax.setter + def SpeedMax(self, val): + self.__SpeedMax = val + + @property + def Tolerance(self): + return self.__SpeedTolerance + + @Tolerance.setter + def Tolerance(self, val): + self.__SpeedTolerance = val + + @property + def i2c_speed(self): + ret, val = self.get_value(self.Speedconfig) + if ret is False: + return None + if val is not None: + self.__i2c_speed = val + return self.__i2c_speed + + def feed_watchdog(self): + ret, val = self.get_value(self.Speedconfig) + if ret is False: + return False, None + if val is not None: + ret, val = self.set_value(self.Speedconfig, val) + return ret, val + return False, None + + @i2c_speed.setter + def i2c_speed(self, val): + self.__i2c_speed = val + + @property + def Speedconfig(self): + return self.__Speedconfig + + @Speedconfig.setter + def Speedconfig(self, val): + self.__Speedconfig = val + + @property + def rotor_run_conf(self): + return self.__rotor_run_conf + + @rotor_run_conf.setter + def rotor_run_conf(self, val): + self.__rotor_run_conf = val + + @property + def rotor_Speed(self): + return self.__rotor_Speed + + @rotor_Speed.setter + def rotor_Speed(self, val): + self.__rotor_Speed = val + + @property + def rotor_HwAlarm(self): + ret, val = self.get_value(self.rotor_HwAlarm_conf) + mask = self.rotor_HwAlarm_conf.get("mask") + no_alarm_value = self.rotor_HwAlarm_conf.get("no_alarm") + if ret is False or val is None: + return False + if isinstance(val, str): + value = int(val, 16) + else: + value = val + flag = value & mask + if flag == no_alarm_value: + return False + return True + + @property + def rotor_HwAlarm_conf(self): + return self.__rotor_HwAlarm_conf + + @rotor_HwAlarm_conf.setter + def rotor_HwAlarm_conf(self, val): + self.__rotor_HwAlarm_conf = val + + @property + def rotor_Running(self): + self.__rotor_Running = self.getRunning() + return self.__rotor_Running + + @rotor_Running.setter + def rotor_Running(self, val): + self.__rotor_Running = val diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/sensor.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/sensor.py new file mode 100644 index 000000000000..af2a5384b618 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/sensor.py @@ -0,0 +1,274 @@ +#!/usr/bin/env python3 +####################################################### +# +# sensor.py +# Python implementation of the Class sensor +# +####################################################### +import time +from plat_hal.devicebase import devicebase + + +class sensor(devicebase): + + __Value = None + __Min = None + __Max = None + __Low = None + __High = None + __ValueConfig = None + __Flag = None + __Unit = None + __format = None + __read_times = None + + __Min_config = None + __Max_config = None + __Low_config = None + __High_config = None + + @property + def Min_config(self): + return self.__Min_config + + @Min_config.setter + def Min_config(self, val): + self.__Min_config = val + + @property + def Max_config(self): + return self.__Max_config + + @Max_config.setter + def Max_config(self, val): + self.__Max_config = val + + @property + def Low_config(self): + return self.__Low_config + + @Low_config.setter + def Low_config(self, val): + self.__Low_config = val + + @property + def High_config(self): + return self.__High_config + + @High_config.setter + def High_config(self, val): + self.__High_config = val + + @property + def Unit(self): + return self.__Unit + + @Unit.setter + def Unit(self, val): + self.__Unit = val + + @property + def format(self): + return self.__format + + @format.setter + def format(self, val): + self.__format = val + + @property + def read_times(self): + return self.__read_times + + @read_times.setter + def read_times(self, val): + self.__read_times = val + + @property + def ValueConfig(self): + return self.__ValueConfig + + @ValueConfig.setter + def ValueConfig(self, val): + self.__ValueConfig = val + + @property + def Flag(self): + return self.__Flag + + @Flag.setter + def Flag(self, val): + self.__Flag = val + + def get_median(self, value_config, read_times): + val_list = [] + for i in range(0, read_times): + ret, real_value = self.get_value(value_config) + if i != (read_times - 1): + time.sleep(0.01) + if ret is False or real_value is None: + continue + val_list.append(real_value) + val_list.sort() + if val_list: + return True, val_list[int((len(val_list) - 1) / 2)] + return False, None + + @property + def Value(self): + try: + ret, val = self.get_median(self.ValueConfig, self.read_times) + if ret is False or val is None: + return None + if self.format is None: + self.__Value = int(val) + else: + self.__Value = self.get_format_value(self.format % val) + self.__Value = round(float(self.__Value), 3) + except Exception: + return None + return self.__Value + + @Value.setter + def Value(self, val): + self.__Value = val + + @property + def Min(self): + try: + if isinstance(self.Min_config, dict): + if self.call_back is None: + self.__Min = self.Min_config.get("other") + else: + ret = self.call_back() + if ret not in self.Min_config: + self.__Min = self.Min_config.get("other") + else: + self.__Min = self.Min_config[ret] + else: + self.__Min = self.Min_config + + if self.__Min is None: + return None + + if self.format is not None: + self.__Min = self.get_format_value(self.format % self.__Min) + self.__Min = round(float(self.__Min), 3) + except Exception: + return None + return self.__Min + + @Min.setter + def Min(self, val): + self.__Min = val + + @property + def Max(self): + try: + if isinstance(self.Max_config, dict): + if self.call_back is None: + self.__Max = self.Max_config.get("other") + else: + ret = self.call_back() + if ret not in self.Max_config: + self.__Max = self.Max_config.get("other") + else: + self.__Max = self.Max_config[ret] + else: + self.__Max = self.Max_config + + if self.__Max is None: + return None + + if self.format is not None: + self.__Max = self.get_format_value(self.format % self.__Max) + self.__Max = round(float(self.__Max), 3) + except Exception: + return None + return self.__Max + + @Max.setter + def Max(self, val): + self.__Max = val + + @property + def Low(self): + try: + if isinstance(self.Low_config, dict): + if self.call_back is None: + self.__Low = self.Low_config.get("other") + else: + ret = self.call_back() + if ret not in self.Low_config: + self.__Low = self.Low_config.get("other") + else: + self.__Low = self.Low_config[ret] + else: + self.__Low = self.Low_config + + if self.__Low is None: + return None + + if self.format is not None: + self.__Low = self.get_format_value(self.format % self.__Low) + self.__Low = round(float(self.__Low), 3) + except Exception: + return None + return self.__Low + + @Low.setter + def Low(self, val): + self.__Low = val + + @property + def High(self): + try: + if isinstance(self.High_config, dict): + if self.call_back is None: + self.__High = self.High_config.get("other") + else: + ret = self.call_back() + if ret not in self.High_config: + self.__High = self.High_config.get("other") + else: + self.__High = self.High_config[ret] + else: + self.__High = self.High_config + + if self.__High is None: + return None + + if self.format is not None: + self.__High = self.get_format_value(self.format % self.__High) + self.__High = round(float(self.__High), 3) + except Exception: + return None + return self.__High + + @High.setter + def High(self, val): + self.__High = val + + def __init__(self, conf=None, call_back=None): + self.ValueConfig = conf.get("value", None) + self.Flag = conf.get("flag", None) + self.Min_config = conf.get("Min", None) + self.Max_config = conf.get("Max", None) + self.Low_config = conf.get("Low", None) + self.High_config = conf.get("High", None) + self.Unit = conf.get('Unit', None) + self.format = conf.get('format', None) + self.read_times = conf.get('read_times', 1) + self.call_back = call_back + + def __str__(self): + formatstr = \ + "ValueConfig: : %s \n" \ + "Min : %s \n" \ + "Max : %s \n" \ + "Unit : %s \n" \ + "format: : %s \n" + + tmpstr = formatstr % (self.ValueConfig, self.Min, + self.Max, self.Unit, + self.format) + return tmpstr diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/temp.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/temp.py new file mode 100644 index 000000000000..a202c20339c9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/temp.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 +####################################################### +# +# temp.py +# Python implementation of the Class temp +# +####################################################### +import os +import syslog +from plat_hal.sensor import sensor + + +PLATFORM_HAL_TEMP_DEBUG_FILE = "/etc/.platform_hal_temp_debug_flag" + + +def platform_hal_temp_debug(s): + if os.path.exists(PLATFORM_HAL_TEMP_DEBUG_FILE): + syslog.openlog("PLATFORM_HAL_TEPM", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +class temp(sensor): + def __init__(self, conf=None): + super(temp, self).__init__(conf.get('Temperature', None)) + self.name = conf.get("name", None) + self.temp_id = conf.get("temp_id", None) + self.api_name = conf.get("api_name", self.name) + self.fix_value = conf.get("fix_value", None) + self.temp_invalid = conf.get("invalid", None) + self.temp_error = conf.get("error", None) + + def temp_cali_by_fan_pwm(self, param, origin_value): + fan_pwm_conf = param.get("fan_pwm") + temp_fix_list = param.get("temp_fix_list") + + ret, val = self.get_value(fan_pwm_conf) + if ret is False or val is None: + platform_hal_temp_debug("temp calibration get fan pwm failed, msg: %s, return None" % (val)) + return None + + fan_pwm = int(val) + for item in temp_fix_list: + if item["min"] <= fan_pwm <= item["max"]: + fix_value = origin_value + item["fix"] + platform_hal_temp_debug("temp calibration by fan pwm, origin_value: %s, pwm: %s, fix_value: %s" % + (origin_value, fan_pwm, fix_value)) + return fix_value + platform_hal_temp_debug("temp calibration by fan pwm, origin_value: %s, pwm: %s, not match return None" % + (origin_value, fan_pwm)) + return None + + def fix_temp_value(self, origin_value): + try: + fix_type = self.fix_value.get("fix_type") + + if fix_type == "func": + func_name = self.fix_value.get("func_name") + func_param = self.fix_value.get("func_param") + func = getattr(self, func_name) + if func is None: + platform_hal_temp_debug("function %s, not defined" % func_name) + return None + value = func(func_param, origin_value) + return value + + if fix_type == "config": + coefficient = self.fix_value.get("coefficient", 1) + addend = self.fix_value.get("addend", 0) + value = (origin_value + addend) * coefficient + platform_hal_temp_debug("temp calibration by config, coefficient: %s, addend: %s, origin_value: %s, fix_value: %s" % + (coefficient, addend, origin_value, value)) + return value + + platform_hal_temp_debug("unsupport fix type: %s, return origin value: %s" % (fix_type, origin_value)) + return origin_value + except Exception as e: + platform_hal_temp_debug("fix_temp_value raise exception, msg: %s" % (str(e))) + return None + + def get_max_value(self, conf): + try: + ret, val = self.get_value(conf) + if ret is False or val is None: + return None + return val + except Exception: + return None + + def check_flag(self): + try: + okbit = self.Flag.get('okbit') + okval = self.Flag.get('okval') + ret, val = self.get_value(self.Flag) + if (ret is False) or (val is None): + return False + val_t = (int(val) & (1 << okbit)) >> okbit + if val_t != okval: + return False + except Exception: + return False + return True + + @property + def Value(self): + try: + if self.Flag is not None: + if self.check_flag() is False: + return None + if isinstance(self.ValueConfig, list): + max_val = None + for i in self.ValueConfig: + tmp = self.get_max_value(i) + if tmp is None: + continue + if max_val is None or max_val < tmp: + max_val = tmp + if max_val is None: + return None + if self.format is None: + self.__Value = int(max_val) + else: + self.__Value = self.get_format_value(self.format % max_val) + else: + ret, val = self.get_value(self.ValueConfig) + if ret is False or val is None: + return None + if self.format is None: + self.__Value = int(val) + else: + self.__Value = self.get_format_value(self.format % val) + except Exception: + return None + if self.fix_value is not None and self.__Value != self.temp_invalid and self.__Value != self.temp_error: + self.__Value = self.fix_temp_value(self.__Value) + return self.__Value + + @Value.setter + def Value(self, val): + self.__Value = val diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/baseutil.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/baseutil.py new file mode 100644 index 000000000000..340a1f7a733f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/baseutil.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +import os + + +def get_machine_info(): + if not os.path.isfile('/host/machine.conf'): + return None + machine_vars = {} + with open('/host/machine.conf') as machine_file: + for line in machine_file: + tokens = line.split('=') + if len(tokens) < 2: + continue + machine_vars[tokens[0]] = tokens[1].strip() + return machine_vars + + +def get_platform_info(machine_info): + if machine_info is not None: + if 'onie_platform' in machine_info: + return machine_info['onie_platform'] + if 'aboot_platform' in machine_info: + return machine_info['aboot_platform'] + return None + + +def get_board_id(machine_info): + if machine_info is not None: + if 'onie_board_id' in machine_info: + return machine_info['onie_board_id'].lower() + return "NA" + + +def get_onie_machine(machine_info): + if machine_info is not None: + if 'onie_machine' in machine_info: + return machine_info['onie_machine'] + return None diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/smbus.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/smbus.py new file mode 100644 index 000000000000..5f1659b3bbf0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/smbus.py @@ -0,0 +1,772 @@ +#!/usr/bin/env python3 +# smbus2 - A drop-in replacement for smbus-cffi/smbus-python +# The MIT License (MIT) +# Copyright (c) 2017 Karl-Petter Lindegaard +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import os +import sys +from fcntl import ioctl +from ctypes import c_uint32, c_uint8, c_uint16, c_char, POINTER, Structure, Array, Union, create_string_buffer, string_at + + +# Commands from uapi/linux/i2c-dev.h +I2C_SLAVE = 0x0703 # Use this slave address +I2C_SLAVE_FORCE = 0x0706 # Use this slave address, even if it is already in use by a driver! +I2C_FUNCS = 0x0705 # Get the adapter functionality mask +I2C_RDWR = 0x0707 # Combined R/W transfer (one STOP only) +I2C_SMBUS = 0x0720 # SMBus transfer. Takes pointer to i2c_smbus_ioctl_data +I2C_PEC = 0x0708 + +# SMBus transfer read or write markers from uapi/linux/i2c.h +I2C_SMBUS_WRITE = 0 +I2C_SMBUS_READ = 1 + +# Size identifiers uapi/linux/i2c.h +I2C_SMBUS_QUICK = 0 +I2C_SMBUS_BYTE = 1 +I2C_SMBUS_BYTE_DATA = 2 +I2C_SMBUS_WORD_DATA = 3 +I2C_SMBUS_PROC_CALL = 4 +# This isn't supported by Pure-I2C drivers with SMBUS emulation, like those in RaspberryPi, OrangePi, etc :( +I2C_SMBUS_BLOCK_DATA = 5 +I2C_SMBUS_BLOCK_PROC_CALL = 7 # Like I2C_SMBUS_BLOCK_DATA, it isn't supported by Pure-I2C drivers either. +I2C_SMBUS_I2C_BLOCK_DATA = 8 +I2C_SMBUS_BLOCK_MAX = 32 + +# To determine what functionality is present (uapi/linux/i2c.h) +try: + from enum import IntFlag +except ImportError: + IntFlag = int + + +class I2cFunc(IntFlag): + """ + These flags identify the operations supported by an I2C/SMBus device. + + You can test these flags on your `smbus.funcs` + + On newer python versions, I2cFunc is an IntFlag enum, but it + falls back to class with a bunch of int constants on older releases. + """ + I2C = 0x00000001 + ADDR_10BIT = 0x00000002 + PROTOCOL_MANGLING = 0x00000004 # I2C_M_IGNORE_NAK etc. + SMBUS_PEC = 0x00000008 + NOSTART = 0x00000010 # I2C_M_NOSTART + SLAVE = 0x00000020 + SMBUS_BLOCK_PROC_CALL = 0x00008000 # SMBus 2.0 + SMBUS_QUICK = 0x00010000 + SMBUS_READ_BYTE = 0x00020000 + SMBUS_WRITE_BYTE = 0x00040000 + SMBUS_READ_BYTE_DATA = 0x00080000 + SMBUS_WRITE_BYTE_DATA = 0x00100000 + SMBUS_READ_WORD_DATA = 0x00200000 + SMBUS_WRITE_WORD_DATA = 0x00400000 + SMBUS_PROC_CALL = 0x00800000 + SMBUS_READ_BLOCK_DATA = 0x01000000 + SMBUS_WRITE_BLOCK_DATA = 0x02000000 + SMBUS_READ_I2C_BLOCK = 0x04000000 # I2C-like block xfer + SMBUS_WRITE_I2C_BLOCK = 0x08000000 # w/ 1-byte reg. addr. + SMBUS_HOST_NOTIFY = 0x10000000 + + SMBUS_BYTE = 0x00060000 + SMBUS_BYTE_DATA = 0x00180000 + SMBUS_WORD_DATA = 0x00600000 + SMBUS_BLOCK_DATA = 0x03000000 + SMBUS_I2C_BLOCK = 0x0c000000 + SMBUS_EMUL = 0x0eff0008 + + +# i2c_msg flags from uapi/linux/i2c.h +I2C_M_RD = 0x0001 + +# Pointer definitions +LP_c_uint8 = POINTER(c_uint8) +LP_c_uint16 = POINTER(c_uint16) +LP_c_uint32 = POINTER(c_uint32) + + +############################################################# +# Type definitions as in i2c.h + + +class i2c_smbus_data(Array): + """ + Adaptation of the i2c_smbus_data union in ``i2c.h``. + + Data for SMBus messages. + """ + _length_ = I2C_SMBUS_BLOCK_MAX + 2 + _type_ = c_uint8 + + +class union_i2c_smbus_data(Union): + _fields_ = [ + ("byte", c_uint8), + ("word", c_uint16), + ("block", i2c_smbus_data) + ] + + +union_pointer_type = POINTER(union_i2c_smbus_data) + + +class i2c_smbus_ioctl_data(Structure): + """ + As defined in ``i2c-dev.h``. + """ + _fields_ = [ + ('read_write', c_uint8), + ('command', c_uint8), + ('size', c_uint32), + ('data', union_pointer_type)] + __slots__ = [name for name, type in _fields_] + + @staticmethod + def create(read_write=I2C_SMBUS_READ, command=0, size=I2C_SMBUS_BYTE_DATA): + u = union_i2c_smbus_data() + return i2c_smbus_ioctl_data( + read_write=read_write, command=command, size=size, + data=union_pointer_type(u)) + + +############################################################# +# Type definitions for i2c_rdwr combined transactions + + +class i2c_msg(Structure): + """ + As defined in ``i2c.h``. + """ + _fields_ = [ + ('addr', c_uint16), + ('flags', c_uint16), + ('len', c_uint16), + ('buf', POINTER(c_char))] + + def __iter__(self): + """ Iterator / Generator + + :return: iterates over :py:attr:`buf` + :rtype: :py:class:`generator` which returns int values + """ + idx = 0 + while idx < self.len: + yield ord(self.buf[idx]) + idx += 1 + + def __len__(self): + return self.len + + def __bytes__(self): + return string_at(self.buf, self.len) + + def __repr__(self): + return 'i2c_msg(%d,%d,%r)' % (self.addr, self.flags, self.__bytes__()) + + def __str__(self): + s = self.__bytes__() + if sys.version_info.major >= 3: + s = ''.join(map(chr, s)) + return s + + @staticmethod + def read(address, length): + """ + Prepares an i2c read transaction. + + :param address: Slave address. + :type: address: int + :param length: Number of bytes to read. + :type: length: int + :return: New :py:class:`i2c_msg` instance for read operation. + :rtype: :py:class:`i2c_msg` + """ + arr = create_string_buffer(length) + return i2c_msg( + addr=address, flags=I2C_M_RD, len=length, + buf=arr) + + @staticmethod + def write(address, buf): + """ + Prepares an i2c write transaction. + + :param address: Slave address. + :type address: int + :param buf: Bytes to write. Either list of values or str. + :type buf: list + :return: New :py:class:`i2c_msg` instance for write operation. + :rtype: :py:class:`i2c_msg` + """ + if sys.version_info.major >= 3: + if isinstance(buf, str): + buf = bytes(map(ord, buf)) + else: + buf = bytes(buf) + else: + if not isinstance(buf, str): + buf = ''.join([chr(x) for x in buf]) + arr = create_string_buffer(buf, len(buf)) + return i2c_msg( + addr=address, flags=0, len=len(arr), + buf=arr) + + +class i2c_rdwr_ioctl_data(Structure): + """ + As defined in ``i2c-dev.h``. + """ + _fields_ = [ + ('msgs', POINTER(i2c_msg)), + ('nmsgs', c_uint32) + ] + __slots__ = [name for name, type in _fields_] + + @staticmethod + def create(*i2c_msg_instances): + """ + Factory method for creating a i2c_rdwr_ioctl_data struct that can + be called with ``ioctl(fd, I2C_RDWR, data)``. + + :param i2c_msg_instances: Up to 42 i2c_msg instances + :rtype: i2c_rdwr_ioctl_data + """ + n_msg = len(i2c_msg_instances) + msg_array = (i2c_msg * n_msg)(*i2c_msg_instances) + return i2c_rdwr_ioctl_data( + msgs=msg_array, + nmsgs=n_msg + ) + + +############################################################# + + +class SMBus(object): + + def __init__(self, bus=None, force=False): + """ + Initialize and (optionally) open an i2c bus connection. + + :param bus: i2c bus number (e.g. 0 or 1) + or an absolute file path (e.g. `/dev/i2c-42`). + If not given, a subsequent call to ``open()`` is required. + :type bus: int or str + :param force: force using the slave address even when driver is + already using it. + :type force: boolean + """ + self.fd = None + self.funcs = I2cFunc(0) + if bus is not None: + self.open(bus) + self.address = None + self.force = force + self._force_last = None + + def __enter__(self): + """Enter handler.""" + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """Exit handler.""" + self.close() + + def open(self, bus): + """ + Open a given i2c bus. + + :param bus: i2c bus number (e.g. 0 or 1) + or an absolute file path (e.g. '/dev/i2c-42'). + :type bus: int or str + :raise TypeError: if type(bus) is not in (int, str) + """ + if isinstance(bus, int): + filepath = "/dev/i2c-{}".format(bus) + elif isinstance(bus, str): + filepath = bus + else: + raise TypeError("Unexpected type(bus)={}".format(type(bus))) + + self.fd = os.open(filepath, os.O_RDWR) + self.funcs = self._get_funcs() + + def close(self): + """ + Close the i2c connection. + """ + if self.fd: + os.close(self.fd) + self.fd = None + + def _set_address(self, address, force=None): + """ + Set i2c slave address to use for subsequent calls. + + :param address: + :type address: int + :param force: + :type force: Boolean + """ + force = force if force is not None else self.force + if self.address != address or self._force_last != force: + if force is True: + ioctl(self.fd, I2C_SLAVE_FORCE, address) + else: + ioctl(self.fd, I2C_SLAVE, address) + self.address = address + self._force_last = force + + def _get_funcs(self): + """ + Returns a 32-bit value stating supported I2C functions. + + :rtype: int + """ + f = c_uint32() + ioctl(self.fd, I2C_FUNCS, f) + return f.value + + def write_quick(self, i2c_addr, force=None): + """ + Perform quick transaction. Throws IOError if unsuccessful. + :param i2c_addr: i2c address + :type i2c_addr: int + :param force: + :type force: Boolean + """ + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=0, size=I2C_SMBUS_QUICK) + ioctl(self.fd, I2C_SMBUS, msg) + + def read_byte(self, i2c_addr, force=None): + """ + Read a single byte from a device. + + :rtype: int + :param i2c_addr: i2c address + :type i2c_addr: int + :param force: + :type force: Boolean + :return: Read byte value + """ + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_READ, command=0, size=I2C_SMBUS_BYTE + ) + ioctl(self.fd, I2C_SMBUS, msg) + return msg.data.contents.byte + + def write_byte(self, i2c_addr, value, force=None): + """ + Write a single byte to a device. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param value: value to write + :type value: int + :param force: + :type force: Boolean + """ + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=value, size=I2C_SMBUS_BYTE + ) + ioctl(self.fd, I2C_SMBUS, msg) + + def read_byte_data(self, i2c_addr, register, force=None): + """ + Read a single byte from a designated register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to read + :type register: int + :param force: + :type force: Boolean + :return: Read byte value + :rtype: int + """ + val_t = -1 + returnmsg = "" + try: + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_BYTE_DATA + ) + val_t = ioctl(self.fd, I2C_SMBUS, msg) + except Exception as e: + self.close() + returnmsg = str(e) + if val_t < 0: + return False, returnmsg + return True, msg.data.contents.byte + + def write_byte_data(self, i2c_addr, register, value, force=None): + """ + Write a byte to a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to write to + :type register: int + :param value: Byte value to transmit + :type value: int + :param force: + :type force: Boolean + :rtype: None + """ + val_t = -1 + returnmsg = "" + try: + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BYTE_DATA + ) + msg.data.contents.byte = value + val_t = ioctl(self.fd, I2C_SMBUS, msg) + except Exception as e: + returnmsg = str(e) + self.close() + if val_t < 0: + return False, returnmsg or "" + return True, "" + + def write_byte_data_pec(self, i2c_addr, register, value, force=None): + """ + Write a byte to a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to write to + :type register: int + :param value: Byte value to transmit + :type value: int + :param force: + :type force: Boolean + :rtype: None + """ + val_t = -1 + returnmsg = "" + try: + val_t = ioctl(self.fd, I2C_PEC, 1) + if val_t < 0: + raise Exception("set pec mod error") + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BYTE_DATA + ) + msg.data.contents.byte = value + val_t = ioctl(self.fd, I2C_SMBUS, msg) + except Exception as e: + returnmsg = str(e) + self.close() + if val_t < 0: + return False, returnmsg or "" + return True, "" + + def read_word_data(self, i2c_addr, register, force=None): + """ + Read a single word (2 bytes) from a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to read + :type register: int + :param force: + :type force: Boolean + :return: 2-byte word + :rtype: int + """ + val_t = -1 + returnmsg = "" + try: + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_WORD_DATA + ) + val_t = ioctl(self.fd, I2C_SMBUS, msg) + except Exception as e: + returnmsg = str(e) + self.close() + if val_t < 0: + return False, returnmsg or "" + return True, msg.data.contents.word + + def write_word_data_pec(self, i2c_addr, register, value, force=None): + """ + Write a byte to a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to write to + :type register: int + :param value: Word value to transmit + :type value: int + :param force: + :type force: Boolean + :rtype: None + """ + val_t = -1 + returnmsg = "" + try: + val_t = ioctl(self.fd, I2C_PEC, 1) + if val_t < 0: + raise Exception("set pec mod error") + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_WORD_DATA + ) + msg.data.contents.word = value + val_t = ioctl(self.fd, I2C_SMBUS, msg) + except Exception as e: + returnmsg = str(e) + self.close() + if val_t < 0: + return False, returnmsg or "" + return True, "" + + def write_word_data(self, i2c_addr, register, value, force=None): + """ + Write a byte to a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to write to + :type register: int + :param value: Word value to transmit + :type value: int + :param force: + :type force: Boolean + :rtype: None + """ + val_t = -1 + returnmsg = "" + try: + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_WORD_DATA + ) + msg.data.contents.word = value + val_t = ioctl(self.fd, I2C_SMBUS, msg) + except Exception as e: + returnmsg = str(e) + self.close() + if val_t < 0: + return False, returnmsg or "" + return True, "" + + def process_call(self, i2c_addr, register, value, force=None): + """ + Executes a SMBus Process Call, sending a 16-bit value and receiving a 16-bit response + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to read/write to + :type register: int + :param value: Word value to transmit + :type value: int + :param force: + :type force: Boolean + :rtype: int + """ + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_PROC_CALL + ) + msg.data.contents.word = value + ioctl(self.fd, I2C_SMBUS, msg) + return msg.data.contents.word + + def read_block_data(self, i2c_addr, register, force=None): + """ + Read a block of up to 32-bytes from a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Start register + :type register: int + :param force: + :type force: Boolean + :return: List of bytes + :rtype: list + """ + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_BLOCK_DATA + ) + ioctl(self.fd, I2C_SMBUS, msg) + length = msg.data.contents.block[0] + return msg.data.contents.block[1:length + 1] + + def write_block_data(self, i2c_addr, register, data, force=None): + """ + Write a block of byte data to a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Start register + :type register: int + :param data: List of bytes + :type data: list + :param force: + :type force: Boolean + :rtype: None + """ + length = len(data) + if length > I2C_SMBUS_BLOCK_MAX: + raise ValueError("Data length cannot exceed %d bytes" % I2C_SMBUS_BLOCK_MAX) + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BLOCK_DATA + ) + msg.data.contents.block[0] = length + msg.data.contents.block[1:length + 1] = data + ioctl(self.fd, I2C_SMBUS, msg) + + def block_process_call(self, i2c_addr, register, data, force=None): + """ + Executes a SMBus Block Process Call, sending a variable-size data + block and receiving another variable-size response + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to read/write to + :type register: int + :param data: List of bytes + :type data: list + :param force: + :type force: Boolean + :return: List of bytes + :rtype: list + """ + length = len(data) + if length > I2C_SMBUS_BLOCK_MAX: + raise ValueError("Data length cannot exceed %d bytes" % I2C_SMBUS_BLOCK_MAX) + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BLOCK_PROC_CALL + ) + msg.data.contents.block[0] = length + msg.data.contents.block[1:length + 1] = data + ioctl(self.fd, I2C_SMBUS, msg) + length = msg.data.contents.block[0] + return msg.data.contents.block[1:length + 1] + + def read_i2c_block_data(self, i2c_addr, register, length, force=None): + """ + Read a block of byte data from a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Start register + :type register: int + :param length: Desired block length + :type length: int + :param force: + :type force: Boolean + :return: List of bytes + :rtype: list + """ + if length > I2C_SMBUS_BLOCK_MAX: + raise ValueError("Desired block length over %d bytes" % I2C_SMBUS_BLOCK_MAX) + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_I2C_BLOCK_DATA + ) + msg.data.contents.byte = length + ioctl(self.fd, I2C_SMBUS, msg) + return msg.data.contents.block[1:length + 1] + + def write_i2c_block_data(self, i2c_addr, register, data, force=None): + """ + Write a block of byte data to a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Start register + :type register: int + :param data: List of bytes + :type data: list + :param force: + :type force: Boolean + :rtype: None + """ + length = len(data) + if length > I2C_SMBUS_BLOCK_MAX: + raise ValueError("Data length cannot exceed %d bytes" % I2C_SMBUS_BLOCK_MAX) + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_I2C_BLOCK_DATA + ) + msg.data.contents.block[0] = length + msg.data.contents.block[1:length + 1] = data + ioctl(self.fd, I2C_SMBUS, msg) + + def i2c_rdwr(self, *i2c_msgs): + """ + Combine a series of i2c read and write operations in a single + transaction (with repeated start bits but no stop bits in between). + + This method takes i2c_msg instances as input, which must be created + first with :py:meth:`i2c_msg.read` or :py:meth:`i2c_msg.write`. + + :param i2c_msgs: One or more i2c_msg class instances. + :type i2c_msgs: i2c_msg + :rtype: None + """ + ioctl_data = i2c_rdwr_ioctl_data.create(*i2c_msgs) + ioctl(self.fd, I2C_RDWR, ioctl_data) + + +class SMBusWrapper: + """ + Wrapper class around the SMBus. + Deprecated as of version 0.3.0. Please replace with :py:class:`SMBus`. + + Enables the user to wrap access to the :py:class:`SMBus` class in a + "with" statement. If auto_cleanup is True (default), the + :py:class:`SMBus` handle will be automatically closed + upon exit of the ``with`` block. + """ + + def __init__(self, bus_number=0, auto_cleanup=True, force=False): + """ + :param auto_cleanup: Close bus when leaving scope. + :type auto_cleanup: Boolean + :param force: Force using the slave address even when driver is already using it. + :type force: Boolean + """ + self.bus_number = bus_number + self.auto_cleanup = auto_cleanup + self.force = force + self.bus = None + + def __enter__(self): + self.bus = SMBus(bus=self.bus_number, force=self.force) + return self.bus + + def __exit__(self, exc_type, exc_val, exc_tb): + if self.auto_cleanup: + self.bus.close() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modprobe_conf/kernel_drivers_blacklist.conf b/platform/broadcom/sonic-platform-modules-micas/common/modprobe_conf/kernel_drivers_blacklist.conf new file mode 100644 index 000000000000..39d56582bd1d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modprobe_conf/kernel_drivers_blacklist.conf @@ -0,0 +1,7 @@ +blacklist wb_fpga_pcie +blacklist wb_i2c_i801 +blacklist wb_spi_gpio +blacklist intel_spi +blacklist intel_spi_platform +blacklist wb_i2c_ismt +blacklist intel_spi_pci diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/COPYING b/platform/broadcom/sonic-platform-modules-micas/common/modules/COPYING new file mode 100644 index 000000000000..a635a38ef940 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/COPYING @@ -0,0 +1,20 @@ +The Linux Kernel is provided under: + + SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note + +Being under the terms of the GNU General Public License version 2 only, +according with: + + LICENSES/preferred/GPL-2.0 + +With an explicit syscall exception, as stated at: + + LICENSES/exceptions/Linux-syscall-note + +In addition, other licenses may also apply. Please see: + + Documentation/process/license-rules.rst + +for more details. + +All contributions to the Linux Kernel are subject to this COPYING file. diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/GPL-2.0 b/platform/broadcom/sonic-platform-modules-micas/common/modules/GPL-2.0 new file mode 100644 index 000000000000..ff0812fd89cc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/GPL-2.0 @@ -0,0 +1,359 @@ +Valid-License-Identifier: GPL-2.0 +Valid-License-Identifier: GPL-2.0-only +Valid-License-Identifier: GPL-2.0+ +Valid-License-Identifier: GPL-2.0-or-later +SPDX-URL: https://spdx.org/licenses/GPL-2.0.html +Usage-Guide: + To use this license in source code, put one of the following SPDX + tag/value pairs into a comment according to the placement + guidelines in the licensing rules documentation. + For 'GNU General Public License (GPL) version 2 only' use: + SPDX-License-Identifier: GPL-2.0 + or + SPDX-License-Identifier: GPL-2.0-only + For 'GNU General Public License (GPL) version 2 or any later version' use: + SPDX-License-Identifier: GPL-2.0+ + or + SPDX-License-Identifier: GPL-2.0-or-later +License-Text: + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/Makefile new file mode 100644 index 000000000000..29375059105a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/Makefile @@ -0,0 +1,62 @@ +PWD = $(shell pwd) +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall +KVERSION ?= $(shell uname -r) +KERNEL_SRC ?= /lib/modules/$(KVERSION) + +module_out_put_dir := $(PWD)/build +export module_out_put_dir + +KERNEL_MODULES_SRC = $(PWD)/linux-5.10 + +PLAT_SYSFS_DIR = $(PWD)/plat_sysfs +INTEL_SPI = $(PWD)/intel_spi +PHY = $(PWD)/phy +PINCTRL = $(PWD)/pinctrl +SDHCI = $(PWD)/sdhci + +export PLAT_SYSFS_DIR + +platform_common-objs := platform_common_module.o dfd_tlveeprom.o +obj-m += platform_common.o +obj-m += wb_mac_bsc.o +obj-m += wb_fpga_pcie.o +obj-m += wb_pcie_dev.o +obj-m += wb_fpga_i2c_bus_drv.o +obj-m += wb_fpga_pca954x_drv.o +obj-m += wb_lpc_drv.o +obj-m += wb_i2c_dev.o +obj-m += wb_platform_i2c_dev.o +obj-m += wb_io_dev.o +obj-m += wb_eeprom_93xx46.o +obj-m += wb_spi_93xx46.o +obj-m += wb_gpio_d1500.o +obj-m += wb_gpio_device.o +obj-m += wb_i2c_ocores.o +obj-m += wb_spi_ocores.o +obj-m += wb_spi_dev.o +obj-m += wb_wdt.o +obj-m += wb_optoe.o +obj-m += wb_spi_gpio.o +obj-m += wb_spi_gpio_device.o +obj-m += wb_spi_nor_device.o +obj-m += wb_xdpe132g5c.o +obj-m += wb_uio_irq.o +obj-m += hw_test.o + +all : + $(MAKE) -C $(KERNEL_MODULES_SRC) + $(MAKE) -C $(PLAT_SYSFS_DIR) + $(MAKE) -C $(INTEL_SPI) + $(MAKE) -C $(PHY) + $(MAKE) -C $(PINCTRL) + $(MAKE) -C $(SDHCI) + $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules + @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi + cp -p $(PWD)/*.ko $(module_out_put_dir) + +clean : + rm -rf $(module_out_put_dir) + rm -f ${PWD}/*.o ${PWD}/*.ko ${PWD}/*.mod.c ${PWD}/.*.cmd ${PWD}/.*.o.d ${PWD}/*.mod + rm -f ${PWD}/Module.markers ${PWD}/Module.symvers ${PWD}/modules.order + rm -rf ${PWD}/.tmp_versions diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.c new file mode 100644 index 000000000000..0d6f38ecc551 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.c @@ -0,0 +1,516 @@ +/* + * Copyright (C) 2003-2014 FreeIPMI Core Team + * + * 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 + * (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, see . + * + */ +/*****************************************************************************\ + * Copyright (C) 2007-2014 Lawrence Livermore National Security, LLC. + * Copyright (C) 2007 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Albert Chu + * UCRL-CODE-232183 + * + * This file is part of Ipmi-fru, a tool used for retrieving + * motherboard field replaceable unit (FRU) information. For details, + * see http://www.llnl.gov/linux/. + * + * Ipmi-fru 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 (at your + * option) any later version. + * + * Ipmi-fru 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 Ipmi-fru. If not, see . +\*****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "platform_common.h" +#include "dfd_tlveeprom.h" + +/* using in is_valid_tlvinfo_header */ +static u_int32_t eeprom_size; + +/* + * List of TLV codes and names. + */ +static const struct tlv_code_desc tlv_code_list[] = { + { TLV_CODE_PRODUCT_NAME , "Product Name"}, + { TLV_CODE_PART_NUMBER , "Part Number"}, + { TLV_CODE_SERIAL_NUMBER , "Serial Number"}, + { TLV_CODE_MAC_BASE , "Base MAC Address"}, + { TLV_CODE_MANUF_DATE , "Manufacture Date"}, + { TLV_CODE_DEVICE_VERSION , "Device Version"}, + { TLV_CODE_LABEL_REVISION , "Label Revision"}, + { TLV_CODE_PLATFORM_NAME , "Platform Name"}, + { TLV_CODE_ONIE_VERSION , "ONIE Version"}, + { TLV_CODE_MAC_SIZE , "MAC Addresses"}, + { TLV_CODE_MANUF_NAME , "Manufacturer"}, + { TLV_CODE_MANUF_COUNTRY , "Country Code"}, + { TLV_CODE_VENDOR_NAME , "Vendor Name"}, + { TLV_CODE_DIAG_VERSION , "Diag Version"}, + { TLV_CODE_SERVICE_TAG , "Service Tag"}, + { TLV_CODE_VENDOR_EXT , "Vendor Extension"}, + { TLV_CODE_CRC_32 , "CRC-32"}, +}; + +#if 0 +#define OPENBMC_VPD_KEY_INVAIL_VAL 0 + +static const tlv_code_map_t tlv_code_map[] = { + { TLV_CODE_PRODUCT_NAME , OPENBMC_VPD_KEY_PRODUCT_NAME}, + { TLV_CODE_PART_NUMBER , OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM}, + { TLV_CODE_SERIAL_NUMBER , OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM}, + { TLV_CODE_MAC_BASE , OPENBMC_VPD_KEY_INVAIL_VAL}, + { TLV_CODE_MANUF_DATE , OPENBMC_VPD_KEY_BOARD_MFG_DATE}, + { TLV_CODE_DEVICE_VERSION , OPENBMC_VPD_KEY_PRODUCT_VER}, + { TLV_CODE_LABEL_REVISION , OPENBMC_VPD_KEY_PRODUCT_CUSTOM7}, + { TLV_CODE_PLATFORM_NAME , OPENBMC_VPD_KEY_PRODUCT_CUSTOM1}, + { TLV_CODE_ONIE_VERSION , OPENBMC_VPD_KEY_PRODUCT_CUSTOM2}, + { TLV_CODE_MAC_SIZE , OPENBMC_VPD_KEY_INVAIL_VAL}, + { TLV_CODE_MANUF_NAME , OPENBMC_VPD_KEY_PRODUCT_MFR}, + { TLV_CODE_MANUF_COUNTRY , OPENBMC_VPD_KEY_PRODUCT_CUSTOM3}, + { TLV_CODE_VENDOR_NAME , OPENBMC_VPD_KEY_PRODUCT_CUSTOM4}, + { TLV_CODE_DIAG_VERSION , OPENBMC_VPD_KEY_PRODUCT_CUSTOM8}, + { TLV_CODE_SERVICE_TAG , OPENBMC_VPD_KEY_PRODUCT_CUSTOM5}, + { TLV_CODE_VENDOR_EXT , OPENBMC_VPD_KEY_PRODUCT_CUSTOM6}, + { TLV_CODE_CRC_32 , OPENBMC_VPD_KEY_INVAIL_VAL}, +}; +#endif + +#define TLV_CODE_NUM (sizeof(tlv_code_list) / sizeof(tlv_code_list[0])) + +#if 0 +#define TLV_CODE_MAP_NUM (sizeof(tlv_code_map) / sizeof(tlv_code_map[0])) +#endif + +const unsigned long crc_table[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; + +static unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned len) +{ + unsigned i; + if (len < 1) + return 0xffffffff; + + for (i = 0; i != len; ++i) + { + crc = crc_table[(crc ^ buf[i]) & 0xff] ^ (crc >> 8); + } + + crc = crc ^ 0xffffffff; + + return crc; +} + +/* + * is_valid_tlv + * + * Perform basic sanity checks on a TLV field. The TLV is pointed to + * by the parameter provided. + * 1. The type code is not reserved (0x00 or 0xFF) + */ +static inline bool is_valid_tlv(tlvinfo_tlv_t *tlv) +{ + return ((tlv->type != 0x00) && (tlv->type != 0xFF)); +} + +/* + * is_valid_tlvinfo_header + * + * Perform sanity checks on the first 11 bytes of the TlvInfo EEPROM + * data pointed to by the parameter: + * 1. First 8 bytes contain null-terminated ASCII string "TlvInfo" + * 2. Version byte is 1 + * 3. Total length bytes contain value which is less than or equal + * to the allowed maximum (2048-11) + * + */ +static inline bool is_valid_tlvinfo_header(tlvinfo_header_t *hdr) +{ + int max_size = eeprom_size; + return((strcmp(hdr->signature, TLV_INFO_ID_STRING) == 0) && + (hdr->version == TLV_INFO_VERSION) && + (be16_to_cpu(hdr->totallen) <= max_size) ); +} + +/* + * decode_tlv_value + * + * Decode a single TLV value into a string. + + * The validity of EEPROM contents and the TLV field have been verified + * prior to calling this function. + */ +static void decode_tlv_value(tlvinfo_tlv_t *tlv, tlv_decode_value_t *decode_value) +{ + int i; + char *value; + u_int32_t length; + + value = (char *)decode_value->value; + + switch (tlv->type) { + case TLV_CODE_PRODUCT_NAME: + case TLV_CODE_PART_NUMBER: + case TLV_CODE_SERIAL_NUMBER: + case TLV_CODE_MANUF_DATE: + case TLV_CODE_LABEL_REVISION: + case TLV_CODE_PLATFORM_NAME: + case TLV_CODE_ONIE_VERSION: + case TLV_CODE_MANUF_NAME: + case TLV_CODE_MANUF_COUNTRY: + case TLV_CODE_VENDOR_NAME: + case TLV_CODE_DIAG_VERSION: + case TLV_CODE_SERVICE_TAG: + case TLV_CODE_VENDOR_EXT: + memcpy(value, tlv->value, tlv->length); + value[tlv->length] = 0; + length = tlv->length; + break; + case TLV_CODE_MAC_BASE: + length = sprintf(value, "%02X:%02X:%02X:%02X:%02X:%02X", + tlv->value[0], tlv->value[1], tlv->value[2], + tlv->value[3], tlv->value[4], tlv->value[5]); + break; + case TLV_CODE_DEVICE_VERSION: + length = sprintf(value, "%u", tlv->value[0]); + break; + case TLV_CODE_MAC_SIZE: + length = sprintf(value, "%u", (tlv->value[0] << 8) | tlv->value[1]); + break; + #if 0 + case TLV_CODE_VENDOR_EXT: + value[0] = 0; + length = 0; + for (i = 0; (i < (TLV_DECODE_VALUE_MAX_LEN/5)) && (i < tlv->length); i++) { + length += sprintf(value, "%s 0x%02X", value, tlv->value[i]); + } + break; + #endif + case TLV_CODE_CRC_32: + length = sprintf(value, "0x%02X%02X%02X%02X", tlv->value[0], + tlv->value[1], tlv->value[2], tlv->value[3]); + break; + default: + value[0] = 0; + length = 0; + for (i = 0; (i < (TLV_DECODE_VALUE_MAX_LEN/5)) && (i < tlv->length); i++) { + length += sprintf(value, "%s 0x%02X", value, tlv->value[i]); + } + break; + } + + decode_value->length = length; +} + +/* + * is_checksum_valid + * + * Validate the checksum in the provided TlvInfo EEPROM data. First, + * verify that the TlvInfo header is valid, then make sure the last + * TLV is a CRC-32 TLV. Then calculate the CRC over the EEPROM data + * and compare it to the value stored in the EEPROM CRC-32 TLV. + */ +static bool is_checksum_valid(u_int8_t *eeprom) +{ + tlvinfo_header_t *eeprom_hdr; + tlvinfo_tlv_t *eeprom_crc; + unsigned int calc_crc; + unsigned int stored_crc; + + eeprom_hdr = (tlvinfo_header_t *) eeprom; + + // Is the eeprom header valid? + if (!is_valid_tlvinfo_header(eeprom_hdr)) { + return false; + } + + // Is the last TLV a CRC? + eeprom_crc = (tlvinfo_tlv_t *) &eeprom[sizeof(tlvinfo_header_t) + + be16_to_cpu(eeprom_hdr->totallen) - (sizeof(tlvinfo_tlv_t) + 4)]; + if ((eeprom_crc->type != TLV_CODE_CRC_32) || (eeprom_crc->length != 4)) { + return false; + } + + // Calculate the checksum + calc_crc = crc32(0xffffffffL, (const unsigned char *)eeprom, sizeof(tlvinfo_header_t) + + be16_to_cpu(eeprom_hdr->totallen) - 4); + stored_crc = ((eeprom_crc->value[0] << 24) | (eeprom_crc->value[1] << 16) | + (eeprom_crc->value[2] << 8) | eeprom_crc->value[3]); + + return (calc_crc == stored_crc); +} + +/* + * tlvinfo_find_tlv + * + * This function finds the TLV with the supplied code in the EERPOM. + * An offset from the beginning of the EEPROM is returned in the + * eeprom_index parameter if the TLV is found. + */ +static bool tlvinfo_find_tlv(u_int8_t *eeprom, u_int8_t tcode, int *eeprom_index) +{ + tlvinfo_header_t *eeprom_hdr; + tlvinfo_tlv_t *eeprom_tlv; + int eeprom_end; + + eeprom_hdr = (tlvinfo_header_t *) eeprom; + + // Search through the TLVs, looking for the first one which matches the + // supplied type code. + *eeprom_index = sizeof(tlvinfo_header_t); + eeprom_end = sizeof(tlvinfo_header_t) + be16_to_cpu(eeprom_hdr->totallen); + while (*eeprom_index < eeprom_end) { + eeprom_tlv = (tlvinfo_tlv_t *) &eeprom[*eeprom_index]; + if (!is_valid_tlv(eeprom_tlv)) { + return false; + } + + if (eeprom_tlv->type == tcode) { + return true; + } + + *eeprom_index += sizeof(tlvinfo_tlv_t) + eeprom_tlv->length; + } + + return false; +} + +/* + * tlvinfo_decode_tlv + * + * This function finds the TLV with the supplied code in the EERPOM + * and decodes the value into the buffer provided. + */ +static bool tlvinfo_decode_tlv(u_int8_t *eeprom, u_int8_t tcode, tlv_decode_value_t *decode_value) +{ + int eeprom_index; + tlvinfo_tlv_t *eeprom_tlv; + + // Find the TLV and then decode it + if (tlvinfo_find_tlv(eeprom, tcode, &eeprom_index)) { + eeprom_tlv = (tlvinfo_tlv_t *) &eeprom[eeprom_index]; + decode_tlv_value(eeprom_tlv, decode_value); + return true; + } + + return false; +} + +/* + * parse_tlv_eeprom + * + * parse the EEPROM into memory, if it hasn't already been read. + */ +int parse_tlv_eeprom(u_int8_t *eeprom, u_int32_t size) +{ + unsigned int i; + bool ret; + tlvinfo_header_t *eeprom_hdr; + //tlv_info_vec_t tlv_info; + tlv_decode_value_t decode_value; + int j; + + eeprom_hdr = (tlvinfo_header_t *) eeprom; + eeprom_size = size; /* eeprom real size */ + + if (!is_valid_tlvinfo_header(eeprom_hdr)) { + DBG_ERROR("Failed to check tlv header.\n"); + return -1; + } + + if (!is_checksum_valid(eeprom)) { + DBG_ERROR("Failed to check tlv crc.\n"); + return -1; + } + + for (i = 0; i < TLV_CODE_NUM; i++) { + mem_clear((void *)&decode_value, sizeof(tlv_decode_value_t)); + ret = tlvinfo_decode_tlv(eeprom, tlv_code_list[i].m_code, &decode_value); + if (!ret) { + DBG_ERROR("No found type: %s\n", tlv_code_list[i].m_name); + continue; + } + + DBG_DEBUG("i: %d,Found type: %s tlv[%d]:%s\n", i, tlv_code_list[i].m_name, tlv_code_list[i].m_code, + decode_value.value); + for (j = 0; j < decode_value.length; j++) { + if ((j % 16) == 0) { + DBG_DEBUG("\n"); + } + DBG_DEBUG("%02x ", decode_value.value[j]); + } + DBG_DEBUG("\n\n"); + } + return 0; +} +static int dfd_parse_tlv_eeprom(u_int8_t *eeprom, u_int32_t size, u_int8_t main_type, tlv_decode_value_t *decode_value) +{ + bool ret; + tlvinfo_header_t *eeprom_hdr; + //tlv_info_vec_t tlv_info; + int j; + + eeprom_hdr = (tlvinfo_header_t *) eeprom; + eeprom_size = size; /* eeprom real size */ + + if (!is_valid_tlvinfo_header(eeprom_hdr)) { + DBG_ERROR("Failed to check tlv header.\n"); + return -1; + } + + if (!is_checksum_valid(eeprom)) { + DBG_ERROR("Failed to check tlv crc.\n"); + return -1; + } + + ret = tlvinfo_decode_tlv(eeprom, main_type, decode_value); + if (!ret) { + DBG_ERROR("No found type: %d\n", main_type); + return -1; + } + + DBG_DEBUG("Found type: %d, value: %s\n", main_type,decode_value->value); + for (j = 0; j < decode_value->length; j++) { + if ((j % 16) == 0) { + DBG_DEBUG("\n"); + } + DBG_DEBUG("%02x ", decode_value->value[j]); + } + DBG_DEBUG("\n\n"); + + return 0; +} + +static int tlvinfo_find_wb_ext_tlv(tlv_decode_value_t *ext_tlv_value, u_int8_t ext_type, + u_int8_t *buf, u_int8_t *buf_len) +{ + tlvinfo_tlv_t *eeprom_tlv; + int eeprom_end, eeprom_index; + + // Search through the TLVs, looking for the first one which matches the + // supplied type code. + DBG_DEBUG("ext_tlv_value->length: %d.\n", ext_tlv_value->length); + for (eeprom_index = 0; eeprom_index < ext_tlv_value->length; eeprom_index++) { + if ((eeprom_index % 16) == 0) { + DBG_DEBUG("\n"); + } + DBG_DEBUG("%02x ", ext_tlv_value->value[eeprom_index]); + } + + DBG_DEBUG("\n"); + + eeprom_index = 0; + eeprom_end = ext_tlv_value->length; + while (eeprom_index < eeprom_end) { + eeprom_tlv = (tlvinfo_tlv_t *) &(ext_tlv_value->value[eeprom_index]); + if (!is_valid_tlv(eeprom_tlv)) { + DBG_ERROR("tlv is not valid, eeprom_tlv->type 0x%x.\n", eeprom_tlv->type); + return -1; + } + + DBG_DEBUG("eeprom_tlv->length %d.\n", eeprom_tlv->length); + if (eeprom_tlv->type == ext_type) { + if (*buf_len >= eeprom_tlv->length) { + memcpy(buf, eeprom_tlv->value, eeprom_tlv->length); + DBG_DEBUG("eeprom_tlv->length %d.\n", eeprom_tlv->length); + *buf_len = eeprom_tlv->length; + return 0; + } + DBG_ERROR("buf_len %d small than info_len %d.\n", *buf_len, eeprom_tlv->length); + return -1; + } + + eeprom_index += sizeof(tlvinfo_tlv_t) + eeprom_tlv->length; + } + + DBG_ERROR("ext_type %d: tlv is not found.\n", ext_type); + return -1; +} + +int dfd_tlvinfo_get_e2prom_info(u_int8_t *eeprom, u_int32_t size, dfd_tlv_type_t *tlv_type, u_int8_t* buf, u_int8_t *buf_len) +{ + tlv_decode_value_t decode_value; + int ret; + + if (eeprom == NULL || tlv_type == NULL || buf == NULL) { + DBG_ERROR("Input para invalid.\n"); + return -1; + } + + mem_clear((void *)&decode_value, sizeof(tlv_decode_value_t)); + ret = dfd_parse_tlv_eeprom(eeprom, size, tlv_type->main_type, &decode_value); + if (ret) { + DBG_ERROR("dfd_parse_tlv_eeprom failed ret %d.\n", ret); + return ret; + } + + if (tlv_type->main_type != TLV_CODE_VENDOR_EXT) { + if (*buf_len >= decode_value.length) { + memcpy(buf, decode_value.value, decode_value.length); + *buf_len = decode_value.length; + return 0; + } + DBG_ERROR("buf_len %d small than info_len %d.\n", *buf_len, decode_value.length); + return -1; + } + DBG_DEBUG("info_len %d.\n", decode_value.length); + + return tlvinfo_find_wb_ext_tlv(&decode_value, tlv_type->ext_type, buf, buf_len); +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.h new file mode 100644 index 000000000000..6eaac5848223 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.h @@ -0,0 +1,121 @@ +#ifndef DFD_OPENBMC_TLVEEPROM_H +#define DFD_OPENBMC_TLVEEPROM_H + +#ifndef u_int8_t +#define u_int8_t unsigned char +#endif + +#ifndef u_int16_t +#define u_int16_t unsigned short +#endif + +#ifndef u_int32_t +#define u_int32_t unsigned int +#endif + +#ifndef be16_to_cpu +#define be16_to_cpu(x) ntohs(x) +#endif + +#ifndef cpu_to_be16 +#define cpu_to_be16(x) htons(x) +#endif + +/** + * The TLV Types. + * + * Keep these in sync with tlv_code_list in cmd_sys_eeprom.c + */ +#define TLV_CODE_PRODUCT_NAME 0x21 +#define TLV_CODE_PART_NUMBER 0x22 +#define TLV_CODE_SERIAL_NUMBER 0x23 +#define TLV_CODE_MAC_BASE 0x24 +#define TLV_CODE_MANUF_DATE 0x25 +#define TLV_CODE_DEVICE_VERSION 0x26 +#define TLV_CODE_LABEL_REVISION 0x27 +#define TLV_CODE_PLATFORM_NAME 0x28 +#define TLV_CODE_ONIE_VERSION 0x29 +#define TLV_CODE_MAC_SIZE 0x2A +#define TLV_CODE_MANUF_NAME 0x2B +#define TLV_CODE_MANUF_COUNTRY 0x2C +#define TLV_CODE_VENDOR_NAME 0x2D +#define TLV_CODE_DIAG_VERSION 0x2E +#define TLV_CODE_SERVICE_TAG 0x2F +#define TLV_CODE_VENDOR_EXT 0xFD +#define TLV_CODE_CRC_32 0xFE + +#define TLV_CODE_NAME_LEN 64 +/* + * Struct for displaying the TLV codes and names. + */ +struct tlv_code_desc { + u_int8_t m_code; + char m_name[TLV_CODE_NAME_LEN]; +}; + +typedef struct dfd_tlv_type_s { + u_int8_t main_type; + u_int8_t ext_type; +} dfd_tlv_type_t; + +// Header Field Constants +#define TLV_INFO_ID_STRING "TlvInfo" +#define TLV_INFO_VERSION 0x01 +/*#define TLV_TOTAL_LEN_MAX (XXXXXXXX - sizeof(tlvinfo_header_t))*/ + +struct __attribute__ ((__packed__)) tlvinfo_header_s { + char signature[8]; /* 0x00 - 0x07 EEPROM Tag "TlvInfo" */ + u_int8_t version; /* 0x08 Structure version */ + u_int16_t totallen; /* 0x09 - 0x0A Length of all data which follows */ +}; +typedef struct tlvinfo_header_s tlvinfo_header_t; + +/* + * TlvInfo TLV: Layout of a TLV field + */ +struct __attribute__ ((__packed__)) tlvinfo_tlv_s { + u_int8_t type; + u_int8_t length; + u_int8_t value[0]; +}; +typedef struct tlvinfo_tlv_s tlvinfo_tlv_t; + +#define TLV_VALUE_MAX_LEN 255 +/* + * The max decode value is currently for the 'raw' type or the 'vendor + * extension' type, both of which have the same decode format. The + * max decode string size is computed as follows: + * + * strlen(" 0xFF") * TLV_VALUE_MAX_LEN + 1 + * + */ +#define TLV_DECODE_VALUE_MAX_LEN ((5 * TLV_VALUE_MAX_LEN) + 1) + +typedef struct tlv_decode_value_s { + u_int8_t value[TLV_DECODE_VALUE_MAX_LEN]; + u_int32_t length; +} tlv_decode_value_t; + +typedef enum dfd_tlvinfo_ext_tlv_type_e { + DFD_TLVINFO_EXT_TLV_TYPE_DEV_TYPE = 1, +} dfd_tlvinfo_ext_tlv_type_t; + +#if 0 +#define TLV_TIME_LEN 64 + +int ipmi_tlv_validate_fru_area(const uint8_t fruid, const char *fru_file_name, + sd_bus *bus_type, const bool bmc_fru); + +extern const char *get_vpd_key_names(int key_id); +extern std::string getService(sdbusplus::bus::bus& bus, + const std::string& intf, + const std::string& path); +extern std::string getFRUValue(const std::string& section, + const std::string& key, + const std::string& delimiter, + IPMIFruInfo& fruData); +#endif + +int dfd_tlvinfo_get_e2prom_info(u_int8_t *eeprom, u_int32_t size, dfd_tlv_type_t *tlv_type, u_int8_t* buf, u_int8_t *buf_len); + +#endif /* endif DFD_OPENBMC_TLVEEPROM_H */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/fpga_i2c.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/fpga_i2c.h new file mode 100644 index 000000000000..649a8452debe --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/fpga_i2c.h @@ -0,0 +1,133 @@ +#ifndef _FPGA_I2C_H +#define _FPGA_I2C_H + +#include +#include +#include +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +#if 0 + +#define FPGA_I2C_EXT_9548_ADDR (0x00) +#define FPGA_I2C_EXT_9548_CHAN (0x04) +#define FPGA_I2C_DEV_SLAVE_ADDR (0x08) +#define FPGA_I2C_DEV_REG_ADDR (0x0C) +#define FPGA_I2C_DEV_RDWR_LEN (0x10) +#define FPGA_I2C_CTRL_REG (0x14) +#define FPGA_I2C_STATUS_REG (0x18) +#define FPGA_I2C_SCALE_REG (0x1C) +#define FPGA_I2C_FILTER_REG (0x20) +#define FPGA_I2C_STRETCH_REG (0x24) +#define FPGA_I2C_EXT_9548_EXITS_FLAG (0x28) +#define FPGA_I2C_INTERNAL_9548_CHAN (0x2C) +#define FPGA_I2C_RDWR_DATA_BUF (0x80) +#endif +#define FPGA_I2C_RDWR_MAX_LEN_DEFAULT (128) +#define I2C_REG_MAX_WIDTH (16) + +#define DEV_NAME_MAX_LEN (64) + +#define FPGA_I2C_MAX_TIMES (10) +#define FPGA_I2C_XFER_TIME_OUT (100000) +#define FPGA_I2C_SLEEP_TIME (40) + +typedef struct fpga_i2c_reg_s { + uint32_t i2c_scale; + uint32_t i2c_filter; + uint32_t i2c_stretch; + uint32_t i2c_ext_9548_exits_flag; + uint32_t i2c_ext_9548_addr; + uint32_t i2c_ext_9548_chan; + uint32_t i2c_in_9548_chan; + uint32_t i2c_slave; + uint32_t i2c_reg; + uint32_t i2c_reg_len; + uint32_t i2c_data_len; + uint32_t i2c_ctrl; + uint32_t i2c_status; + uint32_t i2c_err_vec; + uint32_t i2c_data_buf; + uint32_t i2c_data_buf_len; +} fpga_i2c_reg_t; + +typedef struct fpga_i2c_reset_cfg_s { + uint32_t i2c_adap_reset_flag; + uint32_t reset_addr; + uint32_t reset_on; + uint32_t reset_off; + uint32_t reset_delay_b; + uint32_t reset_delay; + uint32_t reset_delay_a; +} fpga_i2c_reset_cfg_t; + +typedef struct fpga_i2c_reg_addr_s { + uint8_t reg_addr_len; + uint8_t read_reg_addr[I2C_REG_MAX_WIDTH]; +} fpga_i2c_reg_addr_t; + +typedef struct fpga_i2c_dev_s { + fpga_i2c_reg_t reg; + fpga_i2c_reset_cfg_t reset_cfg; + fpga_i2c_reg_addr_t i2c_addr_desc; + const char *dev_name; + uint32_t i2c_scale_value; + uint32_t i2c_filter_value; + uint32_t i2c_stretch_value; + uint32_t i2c_timeout; + uint32_t i2c_func_mode; + wait_queue_head_t queue; + struct i2c_adapter adap; + int adap_nr; + struct device *dev; + bool i2c_params_check; +} fpga_i2c_dev_t; + +typedef struct fpga_i2c_bus_device_s { + int i2c_timeout; + int i2c_scale; + int i2c_filter; + int i2c_stretch; + int i2c_ext_9548_exits_flag; + int i2c_ext_9548_addr; + int i2c_ext_9548_chan; + int i2c_in_9548_chan; + int i2c_slave; + int i2c_reg; + int i2c_reg_len; + int i2c_data_len; + int i2c_ctrl; + int i2c_status; + int i2c_err_vec; + int i2c_data_buf; + int i2c_data_buf_len; + char dev_name[DEV_NAME_MAX_LEN]; + int adap_nr; + int i2c_scale_value; + int i2c_filter_value; + int i2c_stretch_value; + int i2c_func_mode; + int i2c_adap_reset_flag; + int i2c_reset_addr; + int i2c_reset_on; + int i2c_reset_off; + int i2c_rst_delay_b; /* delay time before reset(us) */ + int i2c_rst_delay; /* reset time(us) */ + int i2c_rst_delay_a; /* delay time after reset(us) */ + int device_flag; + bool i2c_params_check; + int i2c_data_buf_len_reg; + int i2c_offset_reg; +} fpga_i2c_bus_device_t; + +typedef struct fpga_pca954x_device_s { + struct i2c_client *client; + uint32_t i2c_bus; + uint32_t i2c_addr; + uint32_t fpga_9548_flag; + uint32_t fpga_9548_reset_flag; + uint32_t pca9548_base_nr; +} fpga_pca954x_device_t; + +#endif /* _FPGA_I2C_H */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.c new file mode 100644 index 000000000000..e74f4e800582 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.c @@ -0,0 +1,608 @@ +/* + * hw_test.c + * Original Author : support, 2020-10-15 + * + * History + * v1.0 support 2020-10-15 Initial version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hw_test.h" + +extern struct bus_type mdio_bus_type; + +struct board_mdio_dev { + struct list_head list; + struct mii_bus *mdio_bus; + int mdio_index; +}; + +struct board_phy_dev { + struct list_head list; + struct phy_device *phydev; + int phy_index; +}; + +static LIST_HEAD(mdio_dev_list); +static LIST_HEAD(phydev_list); +static struct class *class_mdio_bus = NULL; + +#define PRINT_BUF_SIZE (256) +#define INVALID_PHY_ADDR (0xFF) +#define MAX_MDIO_DEVICE_NUMS (1000) +#define MAX_PHY_DEVICE_NUMS (1000) + +#define dram_debug(fmt, ...) \ + printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__) + +static ssize_t dram_dev_read (struct file *file, char __user *buf, size_t count, + loff_t *offset) +{ + u8 value8; + u16 value16; + u32 value32; + + if (file->private_data != NULL) { + return -EINVAL; + } + + file->private_data = ioremap(file->f_pos, count); + + if (!file->private_data) { + pr_notice("%s, %d\n", __FUNCTION__, __LINE__); + return -ENODEV; + } + + rmb(); + switch (count) { + case 1: + value8 = readb(file->private_data); + if (copy_to_user(buf, &value8, sizeof(u8))) { + return -EFAULT; + } + break; + case 2: + value16 = readw(file->private_data); + if (copy_to_user(buf, &value16, sizeof(u16))) { + return -EFAULT; + } + break; + case 4: + value32 = readl(file->private_data); + if (copy_to_user(buf, &value32, sizeof(u32))) { + return -EFAULT; + } + break; + default: + return -EINVAL; + } + + iounmap(file->private_data); + file->private_data = NULL; + return count; + +} + +static ssize_t dram_dev_write (struct file *file, const char __user *buf, size_t count, + loff_t *offset) +{ + u8 value8; + u16 value16; + u32 value32; + + if (file->private_data != NULL) { + return -EINVAL; + } + + file->private_data = ioremap(file->f_pos, count); + + if (!file->private_data) { + pr_err("%s, %d\n", __FUNCTION__, __LINE__); + return -ENODEV; + } + + switch (count) { + case 1: + if (copy_from_user(&value8, buf, sizeof(u8))) { + return -EFAULT; + } + writeb(value8, file->private_data); + break; + case 2: + if (copy_from_user(&value16, buf, sizeof(u16))) { + return -EFAULT; + } + writew(value16, file->private_data); + break; + case 4: + if (copy_from_user(&value32, buf, sizeof(u32))) { + return -EFAULT; + } + writel(value32, file->private_data); + break; + default: + return -EINVAL; + } + + wmb(); + iounmap(file->private_data); + file->private_data = NULL; + return count; +} + +static loff_t dram_dev_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t ret; + + switch (origin) { + case 0: + file->f_pos = offset; + ret = file->f_pos; + break; + case 1: + file->f_pos += offset; + ret = file->f_pos; + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int temp_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum) +{ + return 0; +} + +static int temp_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value) +{ + return 0; +} + +static int init_class_mdio_bus(void) +{ + struct mii_bus *bus; + int err = 0; + + bus = mdiobus_alloc(); + + bus->name = "temp_mdio_bus"; + snprintf(bus->id, MII_BUS_ID_SIZE, "temp_mdio_bus0"); + bus->read = temp_mdiobus_read; + bus->write = temp_mdiobus_write; + + err = mdiobus_register(bus); + if (err) { + printk(KERN_ERR "temp mdio bus register fail\n"); + return -1; + } + + class_mdio_bus = bus->dev.class; + mdiobus_unregister(bus); + + return 0; +} + +static int mdio_match_success(struct device *dev, const void * data) +{ + + return 1; +} + +static int add_all_mdio_devices_to_list(void) +{ + struct device *dev, *dev_start = NULL; + struct board_mdio_dev *mdio_dev = NULL; + int i = 0; + struct class *bus_class = class_mdio_bus; + + for (i = 0; i < MAX_MDIO_DEVICE_NUMS; i++) { + dev = class_find_device(bus_class, dev_start, NULL, mdio_match_success); + if (dev != NULL) { + mdio_dev = kzalloc(sizeof(struct board_mdio_dev), GFP_KERNEL); + if (mdio_dev == NULL) { + printk(KERN_ERR "%s: alloc fail\n", __func__); + return -EFAULT; + } + + mdio_dev->mdio_index = i; + mdio_dev->mdio_bus = to_mii_bus(dev); + list_add_tail(&mdio_dev->list, &mdio_dev_list); + + dev_start = dev; + } else { + break; + } + } + + printk(KERN_INFO "mdio dev numbers = %d\n", i); + + return 0; +} + +static void delete_all_mdio_devices_from_list(void) +{ + struct list_head *n, *pos; + struct board_mdio_dev *mdio_dev; + + list_for_each_safe(pos, n, &mdio_dev_list) { + list_del(pos); + mdio_dev = list_entry(pos, struct board_mdio_dev, list); + kfree(mdio_dev); + } + + return; +} + +void list_all_mdio_devices_info(void) +{ + struct board_mdio_dev *mdio_dev; + unsigned char phyaddr[PHY_MAX_ADDR]; + int i = 0, j = 0; + int phydev_num = 0; + char buf[PRINT_BUF_SIZE]; + int len = 0; + + printk(KERN_INFO "all the mdio devs info:\n"); + printk(KERN_INFO "index busid name phy_num phyaddr \n"); + list_for_each_entry(mdio_dev, &mdio_dev_list, list) { + i = 0; + j = 0; + phydev_num = 0; + mem_clear(phyaddr, INVALID_PHY_ADDR, sizeof(phyaddr)); + mem_clear(buf, 0, sizeof(buf)); + + for (i = 0; i < PHY_MAX_ADDR; i++) { + if (mdio_dev->mdio_bus->mdio_map[i]) { + phydev_num++; + phyaddr[j] = (unsigned char)i; + j++; + } + } + + len = snprintf(buf, sizeof(buf), " %-10d %-20s %-20s %-10d ", mdio_dev->mdio_index, + mdio_dev->mdio_bus->id, mdio_dev->mdio_bus->name, phydev_num); + + for (i = 0; i < PHY_MAX_ADDR; i++) { + if (phyaddr[i] == INVALID_PHY_ADDR) { + break; + } + + len += snprintf(&buf[len], sizeof(buf) - len, " %#x", phyaddr[i]); + } + + printk(KERN_INFO "%s\n", buf); + } + + return; +} + +static struct mii_bus *get_mdio_dev_according_to_index(int mdio_index) +{ + struct board_mdio_dev *mdio_dev; + list_for_each_entry(mdio_dev, &mdio_dev_list, list) { + if (mdio_dev->mdio_index == mdio_index) { + return mdio_dev->mdio_bus; + } + } + + printk(KERN_ERR "no exist the mdio dev it's mdio_index = %d, please exec cmd [hw_test.bin mdiodev_list] to view mdiodev info\n", + mdio_index); + + return NULL; +} + +int board_mdio_read(int mdio_index, int phyaddr, u32 regnum) +{ + struct mii_bus *bus; + int reg_val; + + bus = get_mdio_dev_according_to_index(mdio_index); + if (bus == NULL) { + return -1; + } + + reg_val = mdiobus_read(bus, phyaddr, regnum); + + return reg_val; +} + +int board_mdio_write(int mdio_index, int phyaddr, u32 regnum, u16 val) +{ + struct mii_bus *bus; + int ret; + + bus = get_mdio_dev_according_to_index(mdio_index); + if (bus == NULL) { + return -1; + } + + ret = mdiobus_write(bus, phyaddr, regnum, val); + + return ret; +} + +static int phy_match_success(struct device *dev, const void * data) +{ + + return 1; +} + +static int add_all_phydevs_to_list(void) +{ + struct device *dev, *dev_start = NULL; + struct board_phy_dev *board_phydev = NULL; + int i = 0; + + for (i = 0; i < MAX_PHY_DEVICE_NUMS; i++) { + dev = bus_find_device(&mdio_bus_type, dev_start, NULL, phy_match_success); + if (dev != NULL) { + board_phydev = kzalloc(sizeof(struct board_phy_dev), GFP_KERNEL); + if (board_phydev == NULL) { + printk(KERN_ERR "%s: alloc fail\n", __func__); + return -EFAULT; + } + + board_phydev->phy_index = i; + board_phydev->phydev = to_phy_device(dev); + list_add_tail(&board_phydev->list, &phydev_list); + + dev_start = dev; + } else { + break; + } + } + + printk(KERN_INFO "phydev num = %d\n", i); + + return 0; +} + +static void delete_all_phydevs_from_list(void) +{ + struct list_head *n, *pos; + struct board_phy_dev *board_phydev; + + list_for_each_safe(pos, n, &phydev_list) { + list_del(pos); + board_phydev = list_entry(pos, struct board_phy_dev, list); + kfree(board_phydev); + } + + return; +} + +void list_all_phydevs_info(void) +{ + struct board_phy_dev *board_phydev; + + printk(KERN_INFO "all the phydevs info:\n"); + printk(KERN_INFO "index phyaddr phyId phydev_name\n"); + list_for_each_entry(board_phydev, &phydev_list, list) { + printk(KERN_INFO " %-10d %#-10x %#-10x %-20s\n", board_phydev->phy_index, board_phydev->phydev->mdio.addr,\ + board_phydev->phydev->phy_id, dev_name(&board_phydev->phydev->mdio.dev)); + } + + return; +} + +static struct phy_device *get_phy_dev_according_to_index(int phy_index) +{ + struct board_phy_dev *board_phydev; + list_for_each_entry(board_phydev, &phydev_list, list) { + if (board_phydev->phy_index == phy_index) { + return board_phydev->phydev; + } + } + + printk(KERN_ERR "no exist the phydev it's phy_index = %d, please exec cmd [hw_test.bin phydev_list] to view phydev info\n", phy_index); + + return NULL; +} + +int board_phy_read(int phy_index, u32 regnum) +{ + struct phy_device *phydev; + int reg_val; + + phydev = get_phy_dev_according_to_index(phy_index); + if (phydev == NULL) { + return -1; + } + + reg_val = phy_read(phydev, regnum); + + return reg_val; +} + +int board_phy_write(int phy_index, u32 regnum, u16 val) +{ + struct phy_device *phydev; + int ret; + + phydev = get_phy_dev_according_to_index(phy_index); + if (phydev == NULL) { + return -1; + } + + ret = phy_write(phydev, regnum, val); + + return ret; +} + +static long dram_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int ret = 0; + struct phydev_user_info phy_user_info; + struct mdio_dev_user_info mdio_user_info; + + switch (cmd) { + case CMD_PHY_LIST: + list_all_phydevs_info(); + break; + + case CMD_PHY_READ: + if (copy_from_user(&phy_user_info, argp, sizeof(struct phydev_user_info))) + return -EFAULT; + + ret = board_phy_read(phy_user_info.phy_index, phy_user_info.regnum); + if (ret < 0) { + return -EFAULT; + } + + phy_user_info.regval = (u32)ret; + + if (copy_to_user(argp, &phy_user_info, sizeof(struct phydev_user_info))) + return -EFAULT; + + break; + + case CMD_PHY_WRITE: + if (copy_from_user(&phy_user_info, argp, sizeof(struct phydev_user_info))) + return -EFAULT; + + ret = board_phy_write(phy_user_info.phy_index, phy_user_info.regnum, (u16)phy_user_info.regval); + if (ret < 0) { + return -EFAULT; + } + + break; + + case CMD_MDIO_LIST: + list_all_mdio_devices_info(); + break; + + case CMD_MDIO_READ: + if (copy_from_user(&mdio_user_info, argp, sizeof(struct mdio_dev_user_info))) + return -EFAULT; + + ret = board_mdio_read(mdio_user_info.mdio_index, mdio_user_info.phyaddr, mdio_user_info.regnum); + if (ret < 0) { + return -EFAULT; + } + + mdio_user_info.regval = (u32)ret; + + if (copy_to_user(argp, &mdio_user_info, sizeof(struct mdio_dev_user_info))) + return -EFAULT; + + break; + + case CMD_MDIO_WRITE: + if (copy_from_user(&mdio_user_info, argp, sizeof(struct mdio_dev_user_info))) + return -EFAULT; + + ret = board_mdio_write(mdio_user_info.mdio_index, mdio_user_info.phyaddr, mdio_user_info.regnum, (u16)mdio_user_info.regval); + if (ret < 0) { + return -EFAULT; + } + + break; + + default: + printk("unknown ioctl cmd\n"); + break; + } + + return 0; +} + +static int dram_dev_open(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + file->f_pos = 0; + return 0; + +} + +static int dram_dev_release(struct inode *inode, struct file *file) +{ + if (file->private_data) { + iounmap(file->private_data); + } + return 0; +} + +static const struct file_operations dram_dev_fops = { + .owner = THIS_MODULE, + .llseek = dram_dev_llseek, + .read = dram_dev_read, + .write = dram_dev_write, + .unlocked_ioctl = dram_dev_ioctl, + .open = dram_dev_open, + .release = dram_dev_release, +}; + +static struct miscdevice dram_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "dram_test", + .fops = &dram_dev_fops, +}; + +static int __init dram_init(void) +{ + if (add_all_phydevs_to_list() != 0) { + printk(KERN_ERR "add all phydev to list fail\n"); + delete_all_phydevs_from_list(); + return -ENXIO; + } + + if (init_class_mdio_bus() == 0) { + if (add_all_mdio_devices_to_list() == -EFAULT) { + printk(KERN_ERR "add all mdiodev to list fail\n"); + delete_all_mdio_devices_from_list(); + delete_all_phydevs_from_list(); + return -ENXIO; + } + } + + if (misc_register(&dram_dev) != 0) { + pr_notice("Register %s failed.\n", dram_dev.name); + delete_all_mdio_devices_from_list(); + delete_all_phydevs_from_list(); + return -ENXIO; + } + + return 0; +} + +static void __exit dram_exit(void) +{ + misc_deregister(&dram_dev); + + delete_all_mdio_devices_from_list(); + delete_all_phydevs_from_list(); +} + +module_init(dram_init); +module_exit(dram_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.h new file mode 100644 index 000000000000..695fa336c4ff --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.h @@ -0,0 +1,31 @@ + +#ifndef _LINUX_DRAM_DRIVER_H +#define _LINUX_DRAM_DRIVER_H + +#include +#include + +#define mem_clear(data, val, size) memset((data), val, (size)) + +struct phydev_user_info { + int phy_index; + u32 regnum; + u32 regval; +}; + +#define CMD_PHY_LIST _IOR('P', 0, struct phydev_user_info) +#define CMD_PHY_READ _IOR('P', 1, struct phydev_user_info) +#define CMD_PHY_WRITE _IOR('P', 2, struct phydev_user_info) + +struct mdio_dev_user_info { + int mdio_index; + int phyaddr; + u32 regnum; + u32 regval; +}; + +#define CMD_MDIO_LIST _IOR('M', 0, struct mdio_dev_user_info) +#define CMD_MDIO_READ _IOR('M', 1, struct mdio_dev_user_info) +#define CMD_MDIO_WRITE _IOR('M', 2, struct mdio_dev_user_info) + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/Makefile new file mode 100644 index 000000000000..b84963167b0b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/Makefile @@ -0,0 +1,22 @@ +PWD = $(shell pwd) + +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall +#ifdef ENABLE_GCOV +#ifeq ($(ENABLE_GCOV), y) +#EXTRA_CFLAGS+= -fprofile-arcs -ftest-coverage -lgcov +#endif +#endif # ENABLE_GCOV + +obj-m := intel_spi.o +obj-m += intel_spi_platform.o +obj-m += intel_spi_pci.o + +all: + $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules + @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi + cp -p $(PWD)/*.ko $(module_out_put_dir) +clean: + rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd + rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order + rm -rf $(PWD)/.tmp_versions diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/include/intel_spi.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/include/intel_spi.h new file mode 100644 index 000000000000..d0a570b1f3b0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/include/intel_spi.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Intel PCH/PCU SPI flash driver. + * + * Copyright (C) 2016, Intel Corporation + * Author: Mika Westerberg + */ + +#ifndef INTEL_SPI_H +#define INTEL_SPI_H + +#include +#include + +#define mem_clear(data, size) memset((data), 0, (size)) +struct intel_spi; +struct resource; + +struct intel_spi *intel_spi_probe(struct device *dev, + struct resource *mem, const struct intel_spi_boardinfo *info); +int intel_spi_remove(struct intel_spi *ispi); + +#endif /* INTEL_SPI_H */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi.c new file mode 100644 index 000000000000..a111d52211e4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi.c @@ -0,0 +1,966 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel PCH/PCU SPI flash driver. + * + * Copyright (C) 2016, Intel Corporation + * Author: Mika Westerberg + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "intel_spi.h" + +/* Offsets are from @ispi->base */ +#define BFPREG 0x00 + +#define HSFSTS_CTL 0x04 +#define HSFSTS_CTL_FSMIE BIT(31) +#define HSFSTS_CTL_FDBC_SHIFT 24 +#define HSFSTS_CTL_FDBC_MASK (0x3f << HSFSTS_CTL_FDBC_SHIFT) + +#define HSFSTS_CTL_FCYCLE_SHIFT 17 +#define HSFSTS_CTL_FCYCLE_MASK (0x0f << HSFSTS_CTL_FCYCLE_SHIFT) +/* HW sequencer opcodes */ +#define HSFSTS_CTL_FCYCLE_READ (0x00 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_WRITE (0x02 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_ERASE (0x03 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_ERASE_64K (0x04 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_RDID (0x06 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_WRSR (0x07 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_RDSR (0x08 << HSFSTS_CTL_FCYCLE_SHIFT) + +#define HSFSTS_CTL_FGO BIT(16) +#define HSFSTS_CTL_FLOCKDN BIT(15) +#define HSFSTS_CTL_FDV BIT(14) +#define HSFSTS_CTL_SCIP BIT(5) +#define HSFSTS_CTL_AEL BIT(2) +#define HSFSTS_CTL_FCERR BIT(1) +#define HSFSTS_CTL_FDONE BIT(0) + +#define FADDR 0x08 +#define DLOCK 0x0c +#define FDATA(n) (0x10 + ((n) * 4)) + +#define FRACC 0x50 + +#define FREG(n) (0x54 + ((n) * 4)) +#define FREG_BASE_MASK GENMASK(14, 0) +#define FREG_LIMIT_SHIFT 16 +#define FREG_LIMIT_MASK GENMASK(30, 16) + +/* Offset is from @ispi->pregs */ +#define PR(n) ((n) * 4) +#define PR_WPE BIT(31) +#define PR_LIMIT_SHIFT 16 +#define PR_LIMIT_MASK GENMASK(30, 16) +#define PR_RPE BIT(15) +#define PR_BASE_MASK GENMASK(14, 0) + +/* Offsets are from @ispi->sregs */ +#define SSFSTS_CTL 0x00 +#define SSFSTS_CTL_FSMIE BIT(23) +#define SSFSTS_CTL_DS BIT(22) +#define SSFSTS_CTL_DBC_SHIFT 16 +#define SSFSTS_CTL_SPOP BIT(11) +#define SSFSTS_CTL_ACS BIT(10) +#define SSFSTS_CTL_SCGO BIT(9) +#define SSFSTS_CTL_COP_SHIFT 12 +#define SSFSTS_CTL_FRS BIT(7) +#define SSFSTS_CTL_DOFRS BIT(6) +#define SSFSTS_CTL_AEL BIT(4) +#define SSFSTS_CTL_FCERR BIT(3) +#define SSFSTS_CTL_FDONE BIT(2) +#define SSFSTS_CTL_SCIP BIT(0) + +#define PREOP_OPTYPE 0x04 +#define OPMENU0 0x08 +#define OPMENU1 0x0c + +#define OPTYPE_READ_NO_ADDR 0 +#define OPTYPE_WRITE_NO_ADDR 1 +#define OPTYPE_READ_WITH_ADDR 2 +#define OPTYPE_WRITE_WITH_ADDR 3 + +/* CPU specifics */ +#define BYT_PR 0x74 +#define BYT_SSFSTS_CTL 0x90 +#define BYT_BCR 0xfc +#define BYT_BCR_WPD BIT(0) +#define BYT_FREG_NUM 5 +#define BYT_PR_NUM 5 + +#define LPT_PR 0x74 +#define LPT_SSFSTS_CTL 0x90 +#define LPT_FREG_NUM 5 +#define LPT_PR_NUM 5 + +#define BXT_PR 0x84 +#define BXT_SSFSTS_CTL 0xa0 +#define BXT_FREG_NUM 12 +#define BXT_PR_NUM 6 + +#define CNL_PR 0x84 +#define CNL_FREG_NUM 6 +#define CNL_PR_NUM 5 + +#define LVSCC 0xc4 +#define UVSCC 0xc8 +#define ERASE_OPCODE_SHIFT 8 +#define ERASE_OPCODE_MASK (0xff << ERASE_OPCODE_SHIFT) +#define ERASE_64K_OPCODE_SHIFT 16 +#define ERASE_64K_OPCODE_MASK (0xff << ERASE_64K_OPCODE_SHIFT) + +#define INTEL_SPI_TIMEOUT 5000 /* ms */ +#define INTEL_SPI_FIFO_SZ 64 + +/** + * struct intel_spi - Driver private data + * @dev: Device pointer + * @info: Pointer to board specific info + * @nor: SPI NOR layer structure + * @base: Beginning of MMIO space + * @pregs: Start of protection registers + * @sregs: Start of software sequencer registers + * @nregions: Maximum number of regions + * @pr_num: Maximum number of protected range registers + * @locked: Is SPI setting locked + * @swseq_reg: Use SW sequencer in register reads/writes + * @swseq_erase: Use SW sequencer in erase operation + * @erase_64k: 64k erase supported + * @atomic_preopcode: Holds preopcode when atomic sequence is requested + * @opcodes: Opcodes which are supported. This are programmed by BIOS + * before it locks down the controller. + */ +struct intel_spi { + struct device *dev; + const struct intel_spi_boardinfo *info; + struct spi_nor nor; + void __iomem *base; + void __iomem *pregs; + void __iomem *sregs; + size_t nregions; + size_t pr_num; + bool locked; + bool swseq_reg; + bool swseq_erase; + bool erase_64k; + u8 atomic_preopcode; + u8 opcodes[8]; +}; + +static bool writeable; +module_param(writeable, bool, 0); +MODULE_PARM_DESC(writeable, "Enable write access to SPI flash chip (default=0)"); + +static void intel_spi_dump_regs(struct intel_spi *ispi) +{ + u32 value; + int i; + + dev_dbg(ispi->dev, "BFPREG=0x%08x\n", readl(ispi->base + BFPREG)); + + value = readl(ispi->base + HSFSTS_CTL); + dev_dbg(ispi->dev, "HSFSTS_CTL=0x%08x\n", value); + if (value & HSFSTS_CTL_FLOCKDN) + dev_dbg(ispi->dev, "-> Locked\n"); + + dev_dbg(ispi->dev, "FADDR=0x%08x\n", readl(ispi->base + FADDR)); + dev_dbg(ispi->dev, "DLOCK=0x%08x\n", readl(ispi->base + DLOCK)); + + for (i = 0; i < 16; i++) + dev_dbg(ispi->dev, "FDATA(%d)=0x%08x\n", + i, readl(ispi->base + FDATA(i))); + + dev_dbg(ispi->dev, "FRACC=0x%08x\n", readl(ispi->base + FRACC)); + + for (i = 0; i < ispi->nregions; i++) + dev_dbg(ispi->dev, "FREG(%d)=0x%08x\n", i, + readl(ispi->base + FREG(i))); + for (i = 0; i < ispi->pr_num; i++) + dev_dbg(ispi->dev, "PR(%d)=0x%08x\n", i, + readl(ispi->pregs + PR(i))); + + if (ispi->sregs) { + value = readl(ispi->sregs + SSFSTS_CTL); + dev_dbg(ispi->dev, "SSFSTS_CTL=0x%08x\n", value); + dev_dbg(ispi->dev, "PREOP_OPTYPE=0x%08x\n", + readl(ispi->sregs + PREOP_OPTYPE)); + dev_dbg(ispi->dev, "OPMENU0=0x%08x\n", + readl(ispi->sregs + OPMENU0)); + dev_dbg(ispi->dev, "OPMENU1=0x%08x\n", + readl(ispi->sregs + OPMENU1)); + } + + if (ispi->info->type == INTEL_SPI_BYT) + dev_dbg(ispi->dev, "BCR=0x%08x\n", readl(ispi->base + BYT_BCR)); + + dev_dbg(ispi->dev, "LVSCC=0x%08x\n", readl(ispi->base + LVSCC)); + dev_dbg(ispi->dev, "UVSCC=0x%08x\n", readl(ispi->base + UVSCC)); + + dev_dbg(ispi->dev, "Protected regions:\n"); + for (i = 0; i < ispi->pr_num; i++) { + u32 base, limit; + + value = readl(ispi->pregs + PR(i)); + if (!(value & (PR_WPE | PR_RPE))) + continue; + + limit = (value & PR_LIMIT_MASK) >> PR_LIMIT_SHIFT; + base = value & PR_BASE_MASK; + + dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x [%c%c]\n", + i, base << 12, (limit << 12) | 0xfff, + value & PR_WPE ? 'W' : '.', + value & PR_RPE ? 'R' : '.'); + } + + dev_dbg(ispi->dev, "Flash regions:\n"); + for (i = 0; i < ispi->nregions; i++) { + u32 region, base, limit; + + region = readl(ispi->base + FREG(i)); + base = region & FREG_BASE_MASK; + limit = (region & FREG_LIMIT_MASK) >> FREG_LIMIT_SHIFT; + + if (base >= limit || (i > 0 && limit == 0)) + dev_dbg(ispi->dev, " %02d disabled\n", i); + else + dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x\n", + i, base << 12, (limit << 12) | 0xfff); + } + + dev_dbg(ispi->dev, "Using %cW sequencer for register access\n", + ispi->swseq_reg ? 'S' : 'H'); + dev_dbg(ispi->dev, "Using %cW sequencer for erase operation\n", + ispi->swseq_erase ? 'S' : 'H'); +} + +/* Reads max INTEL_SPI_FIFO_SZ bytes from the device fifo */ +static int intel_spi_read_block(struct intel_spi *ispi, void *buf, size_t size) +{ + size_t bytes; + int i = 0; + + if (size > INTEL_SPI_FIFO_SZ) + return -EINVAL; + + while (size > 0) { + bytes = min_t(size_t, size, 4); + memcpy_fromio(buf, ispi->base + FDATA(i), bytes); + size -= bytes; + buf += bytes; + i++; + } + + return 0; +} + +/* Writes max INTEL_SPI_FIFO_SZ bytes to the device fifo */ +static int intel_spi_write_block(struct intel_spi *ispi, const void *buf, + size_t size) +{ + size_t bytes; + int i = 0; + + if (size > INTEL_SPI_FIFO_SZ) + return -EINVAL; + + while (size > 0) { + bytes = min_t(size_t, size, 4); + memcpy_toio(ispi->base + FDATA(i), buf, bytes); + size -= bytes; + buf += bytes; + i++; + } + + return 0; +} + +static int intel_spi_wait_hw_busy(struct intel_spi *ispi) +{ + u32 val; + + return readl_poll_timeout(ispi->base + HSFSTS_CTL, val, + !(val & HSFSTS_CTL_SCIP), 0, + INTEL_SPI_TIMEOUT * 1000); +} + +static int intel_spi_wait_sw_busy(struct intel_spi *ispi) +{ + u32 val; + + return readl_poll_timeout(ispi->sregs + SSFSTS_CTL, val, + !(val & SSFSTS_CTL_SCIP), 0, + INTEL_SPI_TIMEOUT * 1000); +} + +static bool intel_spi_set_writeable(struct intel_spi *ispi) +{ + if (!ispi->info->set_writeable) + return false; + + return ispi->info->set_writeable(ispi->base, ispi->info->data); +} + +static int intel_spi_init(struct intel_spi *ispi) +{ + u32 opmenu0, opmenu1, lvscc, uvscc, val; + int i; + + switch (ispi->info->type) { + case INTEL_SPI_BYT: + ispi->sregs = ispi->base + BYT_SSFSTS_CTL; + ispi->pregs = ispi->base + BYT_PR; + ispi->nregions = BYT_FREG_NUM; + ispi->pr_num = BYT_PR_NUM; + ispi->swseq_reg = true; + break; + + case INTEL_SPI_LPT: + ispi->sregs = ispi->base + LPT_SSFSTS_CTL; + ispi->pregs = ispi->base + LPT_PR; + ispi->nregions = LPT_FREG_NUM; + ispi->pr_num = LPT_PR_NUM; + ispi->swseq_reg = true; + break; + + case INTEL_SPI_BXT: + ispi->sregs = ispi->base + BXT_SSFSTS_CTL; + ispi->pregs = ispi->base + BXT_PR; + ispi->nregions = BXT_FREG_NUM; + ispi->pr_num = BXT_PR_NUM; + ispi->erase_64k = true; + break; + + case INTEL_SPI_CNL: + ispi->sregs = NULL; + ispi->pregs = ispi->base + CNL_PR; + ispi->nregions = CNL_FREG_NUM; + ispi->pr_num = CNL_PR_NUM; + break; + + default: + return -EINVAL; + } + + /* Try to disable write protection if user asked to do so */ + if (writeable && !intel_spi_set_writeable(ispi)) { + dev_warn(ispi->dev, "can't disable chip write protection\n"); + writeable = false; + } + + /* Disable #SMI generation from HW sequencer */ + val = readl(ispi->base + HSFSTS_CTL); + val &= ~HSFSTS_CTL_FSMIE; + writel(val, ispi->base + HSFSTS_CTL); + + /* + * Determine whether erase operation should use HW or SW sequencer. + * + * The HW sequencer has a predefined list of opcodes, with only the + * erase opcode being programmable in LVSCC and UVSCC registers. + * If these registers don't contain a valid erase opcode, erase + * cannot be done using HW sequencer. + */ + lvscc = readl(ispi->base + LVSCC); + uvscc = readl(ispi->base + UVSCC); + if (!(lvscc & ERASE_OPCODE_MASK) || !(uvscc & ERASE_OPCODE_MASK)) + ispi->swseq_erase = true; + /* SPI controller on Intel BXT supports 64K erase opcode */ + if (ispi->info->type == INTEL_SPI_BXT && !ispi->swseq_erase) + if (!(lvscc & ERASE_64K_OPCODE_MASK) || + !(uvscc & ERASE_64K_OPCODE_MASK)) + ispi->erase_64k = false; + + if (ispi->sregs == NULL && (ispi->swseq_reg || ispi->swseq_erase)) { + dev_err(ispi->dev, "software sequencer not supported, but required\n"); + return -EINVAL; + } + + /* + * Some controllers can only do basic operations using hardware + * sequencer. All other operations are supposed to be carried out + * using software sequencer. + */ + if (ispi->swseq_reg) { + /* Disable #SMI generation from SW sequencer */ + val = readl(ispi->sregs + SSFSTS_CTL); + val &= ~SSFSTS_CTL_FSMIE; + writel(val, ispi->sregs + SSFSTS_CTL); + } + + /* Check controller's lock status */ + val = readl(ispi->base + HSFSTS_CTL); + ispi->locked = !!(val & HSFSTS_CTL_FLOCKDN); + + if (ispi->locked && ispi->sregs) { + /* + * BIOS programs allowed opcodes and then locks down the + * register. So read back what opcodes it decided to support. + * That's the set we are going to support as well. + */ + opmenu0 = readl(ispi->sregs + OPMENU0); + opmenu1 = readl(ispi->sregs + OPMENU1); + + if (opmenu0 && opmenu1) { + for (i = 0; i < ARRAY_SIZE(ispi->opcodes) / 2; i++) { + ispi->opcodes[i] = opmenu0 >> i * 8; + ispi->opcodes[i + 4] = opmenu1 >> i * 8; + } + } + } + + intel_spi_dump_regs(ispi); + + return 0; +} + +static int intel_spi_opcode_index(struct intel_spi *ispi, u8 opcode, int optype) +{ + int i; + int preop; + + if (ispi->locked) { + for (i = 0; i < ARRAY_SIZE(ispi->opcodes); i++) + if (ispi->opcodes[i] == opcode) + return i; + + return -EINVAL; + } + + /* The lock is off, so just use index 0 */ + writel(opcode, ispi->sregs + OPMENU0); + preop = readw(ispi->sregs + PREOP_OPTYPE); + writel(optype << 16 | preop, ispi->sregs + PREOP_OPTYPE); + + return 0; +} + +static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, size_t len) +{ + u32 val, status; + int ret; + + val = readl(ispi->base + HSFSTS_CTL); + val &= ~(HSFSTS_CTL_FCYCLE_MASK | HSFSTS_CTL_FDBC_MASK); + + switch (opcode) { + case SPINOR_OP_RDID: + val |= HSFSTS_CTL_FCYCLE_RDID; + break; + case SPINOR_OP_WRSR: + val |= HSFSTS_CTL_FCYCLE_WRSR; + break; + case SPINOR_OP_RDSR: + val |= HSFSTS_CTL_FCYCLE_RDSR; + break; + default: + return -EINVAL; + } + + if (len > INTEL_SPI_FIFO_SZ) + return -EINVAL; + + val |= (len - 1) << HSFSTS_CTL_FDBC_SHIFT; + val |= HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; + val |= HSFSTS_CTL_FGO; + writel(val, ispi->base + HSFSTS_CTL); + + ret = intel_spi_wait_hw_busy(ispi); + if (ret) + return ret; + + status = readl(ispi->base + HSFSTS_CTL); + if (status & HSFSTS_CTL_FCERR) + return -EIO; + else if (status & HSFSTS_CTL_AEL) + return -EACCES; + + return 0; +} + +static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, size_t len, + int optype) +{ + u32 val = 0, status; + u8 atomic_preopcode; + int ret; + + ret = intel_spi_opcode_index(ispi, opcode, optype); + if (ret < 0) + return ret; + + if (len > INTEL_SPI_FIFO_SZ) + return -EINVAL; + + /* + * Always clear it after each SW sequencer operation regardless + * of whether it is successful or not. + */ + atomic_preopcode = ispi->atomic_preopcode; + ispi->atomic_preopcode = 0; + + /* Only mark 'Data Cycle' bit when there is data to be transferred */ + if (len > 0) + val = ((len - 1) << SSFSTS_CTL_DBC_SHIFT) | SSFSTS_CTL_DS; + val |= ret << SSFSTS_CTL_COP_SHIFT; + val |= SSFSTS_CTL_FCERR | SSFSTS_CTL_FDONE; + val |= SSFSTS_CTL_SCGO; + if (atomic_preopcode) { + u16 preop; + + switch (optype) { + case OPTYPE_WRITE_NO_ADDR: + case OPTYPE_WRITE_WITH_ADDR: + /* Pick matching preopcode for the atomic sequence */ + preop = readw(ispi->sregs + PREOP_OPTYPE); + if ((preop & 0xff) == atomic_preopcode) + ; /* Do nothing */ + else if ((preop >> 8) == atomic_preopcode) + val |= SSFSTS_CTL_SPOP; + else + return -EINVAL; + + /* Enable atomic sequence */ + val |= SSFSTS_CTL_ACS; + break; + + default: + return -EINVAL; + } + + } + writel(val, ispi->sregs + SSFSTS_CTL); + + ret = intel_spi_wait_sw_busy(ispi); + if (ret) + return ret; + + status = readl(ispi->sregs + SSFSTS_CTL); + if (status & SSFSTS_CTL_FCERR) + return -EIO; + else if (status & SSFSTS_CTL_AEL) + return -EACCES; + + return 0; +} + +static int intel_spi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, + size_t len) +{ + struct intel_spi *ispi = nor->priv; + int ret; + + /* Address of the first chip */ + writel(0, ispi->base + FADDR); + + if (ispi->swseq_reg) + ret = intel_spi_sw_cycle(ispi, opcode, len, + OPTYPE_READ_NO_ADDR); + else + ret = intel_spi_hw_cycle(ispi, opcode, len); + + if (ret) + return ret; + + return intel_spi_read_block(ispi, buf, len); +} + +static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf, + size_t len) +{ + struct intel_spi *ispi = nor->priv; + int ret; + + /* + * This is handled with atomic operation and preop code in Intel + * controller so we only verify that it is available. If the + * controller is not locked, program the opcode to the PREOP + * register for later use. + * + * When hardware sequencer is used there is no need to program + * any opcodes (it handles them automatically as part of a command). + */ + if (opcode == SPINOR_OP_WREN) { + u16 preop; + + if (!ispi->swseq_reg) + return 0; + + preop = readw(ispi->sregs + PREOP_OPTYPE); + if ((preop & 0xff) != opcode && (preop >> 8) != opcode) { + if (ispi->locked) + return -EINVAL; + writel(opcode, ispi->sregs + PREOP_OPTYPE); + } + + /* + * This enables atomic sequence on next SW sycle. Will + * be cleared after next operation. + */ + ispi->atomic_preopcode = opcode; + return 0; + } + + /* + * We hope that HW sequencer will do the right thing automatically and + * with the SW sequencer we cannot use preopcode anyway, so just ignore + * the Write Disable operation and pretend it was completed + * successfully. + */ + if (opcode == SPINOR_OP_WRDI) + return 0; + + writel(0, ispi->base + FADDR); + + /* Write the value beforehand */ + ret = intel_spi_write_block(ispi, buf, len); + if (ret) + return ret; + + if (ispi->swseq_reg) + return intel_spi_sw_cycle(ispi, opcode, len, + OPTYPE_WRITE_NO_ADDR); + return intel_spi_hw_cycle(ispi, opcode, len); +} + +static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len, + u_char *read_buf) +{ + struct intel_spi *ispi = nor->priv; + size_t block_size, retlen = 0; + u32 val, status; + ssize_t ret; + + /* + * Atomic sequence is not expected with HW sequencer reads. Make + * sure it is cleared regardless. + */ + if (WARN_ON_ONCE(ispi->atomic_preopcode)) + ispi->atomic_preopcode = 0; + + switch (nor->read_opcode) { + case SPINOR_OP_READ: + case SPINOR_OP_READ_FAST: + case SPINOR_OP_READ_4B: + case SPINOR_OP_READ_FAST_4B: + break; + default: + return -EINVAL; + } + + while (len > 0) { + block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ); + + /* Read cannot cross 4K boundary */ + block_size = min_t(loff_t, from + block_size, + round_up(from + 1, SZ_4K)) - from; + + writel(from, ispi->base + FADDR); + + val = readl(ispi->base + HSFSTS_CTL); + val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); + val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; + val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT; + val |= HSFSTS_CTL_FCYCLE_READ; + val |= HSFSTS_CTL_FGO; + writel(val, ispi->base + HSFSTS_CTL); + + ret = intel_spi_wait_hw_busy(ispi); + if (ret) + return ret; + + status = readl(ispi->base + HSFSTS_CTL); + if (status & HSFSTS_CTL_FCERR) + ret = -EIO; + else if (status & HSFSTS_CTL_AEL) + ret = -EACCES; + + if (ret < 0) { + dev_err(ispi->dev, "read error: %llx: %#x\n", from, + status); + return ret; + } + + ret = intel_spi_read_block(ispi, read_buf, block_size); + if (ret) + return ret; + + len -= block_size; + from += block_size; + retlen += block_size; + read_buf += block_size; + } + + return retlen; +} + +static ssize_t intel_spi_write(struct spi_nor *nor, loff_t to, size_t len, + const u_char *write_buf) +{ + struct intel_spi *ispi = nor->priv; + size_t block_size, retlen = 0; + u32 val, status; + ssize_t ret; + + /* Not needed with HW sequencer write, make sure it is cleared */ + ispi->atomic_preopcode = 0; + + while (len > 0) { + block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ); + + /* Write cannot cross 4K boundary */ + block_size = min_t(loff_t, to + block_size, + round_up(to + 1, SZ_4K)) - to; + + writel(to, ispi->base + FADDR); + + val = readl(ispi->base + HSFSTS_CTL); + val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); + val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; + val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT; + val |= HSFSTS_CTL_FCYCLE_WRITE; + + ret = intel_spi_write_block(ispi, write_buf, block_size); + if (ret) { + dev_err(ispi->dev, "failed to write block\n"); + return ret; + } + + /* Start the write now */ + val |= HSFSTS_CTL_FGO; + writel(val, ispi->base + HSFSTS_CTL); + + ret = intel_spi_wait_hw_busy(ispi); + if (ret) { + dev_err(ispi->dev, "timeout\n"); + return ret; + } + + status = readl(ispi->base + HSFSTS_CTL); + if (status & HSFSTS_CTL_FCERR) + ret = -EIO; + else if (status & HSFSTS_CTL_AEL) + ret = -EACCES; + + if (ret < 0) { + dev_err(ispi->dev, "write error: %llx: %#x\n", to, + status); + return ret; + } + + len -= block_size; + to += block_size; + retlen += block_size; + write_buf += block_size; + } + + return retlen; +} + +static int intel_spi_erase(struct spi_nor *nor, loff_t offs) +{ + size_t erase_size, len = nor->mtd.erasesize; + struct intel_spi *ispi = nor->priv; + u32 val, status, cmd; + int ret; + + /* If the hardware can do 64k erase use that when possible */ + if (len >= SZ_64K && ispi->erase_64k) { + cmd = HSFSTS_CTL_FCYCLE_ERASE_64K; + erase_size = SZ_64K; + } else { + cmd = HSFSTS_CTL_FCYCLE_ERASE; + erase_size = SZ_4K; + } + + if (ispi->swseq_erase) { + while (len > 0) { + writel(offs, ispi->base + FADDR); + + ret = intel_spi_sw_cycle(ispi, nor->erase_opcode, + 0, OPTYPE_WRITE_WITH_ADDR); + if (ret) + return ret; + + offs += erase_size; + len -= erase_size; + } + + return 0; + } + + /* Not needed with HW sequencer erase, make sure it is cleared */ + ispi->atomic_preopcode = 0; + + while (len > 0) { + writel(offs, ispi->base + FADDR); + + val = readl(ispi->base + HSFSTS_CTL); + val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); + val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; + val |= cmd; + val |= HSFSTS_CTL_FGO; + writel(val, ispi->base + HSFSTS_CTL); + + ret = intel_spi_wait_hw_busy(ispi); + if (ret) + return ret; + + status = readl(ispi->base + HSFSTS_CTL); + if (status & HSFSTS_CTL_FCERR) + return -EIO; + else if (status & HSFSTS_CTL_AEL) + return -EACCES; + + offs += erase_size; + len -= erase_size; + } + + return 0; +} + +static bool intel_spi_is_protected(const struct intel_spi *ispi, + unsigned int base, unsigned int limit) +{ + int i; + + for (i = 0; i < ispi->pr_num; i++) { + u32 pr_base, pr_limit, pr_value; + + pr_value = readl(ispi->pregs + PR(i)); + if (!(pr_value & (PR_WPE | PR_RPE))) + continue; + + pr_limit = (pr_value & PR_LIMIT_MASK) >> PR_LIMIT_SHIFT; + pr_base = pr_value & PR_BASE_MASK; + + if (pr_base >= base && pr_limit <= limit) + return true; + } + + return false; +} + +/* + * There will be a single partition holding all enabled flash regions. We + * call this "BIOS". + */ +static void intel_spi_fill_partition(struct intel_spi *ispi, + struct mtd_partition *part) +{ + u64 end; + int i; + + mem_clear(part, sizeof(*part)); + + /* Start from the mandatory descriptor region */ + part->size = 4096; + part->name = "BIOS"; + + /* + * Now try to find where this partition ends based on the flash + * region registers. + */ + for (i = 1; i < ispi->nregions; i++) { + u32 region, base, limit; + + region = readl(ispi->base + FREG(i)); + base = region & FREG_BASE_MASK; + limit = (region & FREG_LIMIT_MASK) >> FREG_LIMIT_SHIFT; + + if (base >= limit || limit == 0) + continue; + + /* + * If any of the regions have protection bits set, make the + * whole partition read-only to be on the safe side. + * + * Also if the user did not ask the chip to be writeable + * mask the bit too. + */ + if (!writeable || intel_spi_is_protected(ispi, base, limit)) + part->mask_flags |= MTD_WRITEABLE; + + end = (limit << 12) + 4096; + if (end > part->size) + part->size = end; + } +} + +static const struct spi_nor_controller_ops intel_spi_controller_ops = { + .read_reg = intel_spi_read_reg, + .write_reg = intel_spi_write_reg, + .read = intel_spi_read, + .write = intel_spi_write, + .erase = intel_spi_erase, +}; + +struct intel_spi *intel_spi_probe(struct device *dev, + struct resource *mem, const struct intel_spi_boardinfo *info) +{ + const struct spi_nor_hwcaps hwcaps = { + .mask = SNOR_HWCAPS_READ | + SNOR_HWCAPS_READ_FAST | + SNOR_HWCAPS_PP, + }; + struct mtd_partition part; + struct intel_spi *ispi; + int ret; + + if (!info || !mem) + return ERR_PTR(-EINVAL); + + ispi = devm_kzalloc(dev, sizeof(*ispi), GFP_KERNEL); + if (!ispi) + return ERR_PTR(-ENOMEM); + + ispi->base = devm_ioremap_resource(dev, mem); + if (IS_ERR(ispi->base)) + return ERR_CAST(ispi->base); + + ispi->dev = dev; + ispi->info = info; + + ret = intel_spi_init(ispi); + if (ret) + return ERR_PTR(ret); + + ispi->nor.dev = ispi->dev; + ispi->nor.priv = ispi; + ispi->nor.controller_ops = &intel_spi_controller_ops; + + ret = spi_nor_scan(&ispi->nor, NULL, &hwcaps); + if (ret) { + dev_info(dev, "failed to locate the chip\n"); + return ERR_PTR(ret); + } + + intel_spi_fill_partition(ispi, &part); + + ret = mtd_device_register(&ispi->nor.mtd, &part, 1); + if (ret) + return ERR_PTR(ret); + + return ispi; +} +EXPORT_SYMBOL_GPL(intel_spi_probe); + +int intel_spi_remove(struct intel_spi *ispi) +{ + return mtd_device_unregister(&ispi->nor.mtd); +} +EXPORT_SYMBOL_GPL(intel_spi_remove); + +MODULE_DESCRIPTION("Intel PCH/PCU SPI flash core driver"); +MODULE_AUTHOR("support"); +MODULE_LICENSE("GPL v2"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_pci.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_pci.c new file mode 100644 index 000000000000..a89050b8a525 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_pci.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel PCH/PCU SPI flash PCI driver. + * + * Copyright (C) 2016, Intel Corporation + * Author: Mika Westerberg + */ + +#include +#include +#include +#include + +#include "intel_spi.h" + +#define BCR 0xdc +#define BCR_WPD BIT(0) + +static bool intel_spi_pci_set_writeable(void __iomem *base, void *data) +{ + struct pci_dev *pdev = data; + u32 bcr; + + /* Try to make the chip read/write */ + pci_read_config_dword(pdev, BCR, &bcr); + if (!(bcr & BCR_WPD)) { + bcr |= BCR_WPD; + pci_write_config_dword(pdev, BCR, bcr); + pci_read_config_dword(pdev, BCR, &bcr); + } + + return bcr & BCR_WPD; +} + +static const struct intel_spi_boardinfo bxt_info = { + .type = INTEL_SPI_BXT, + .set_writeable = intel_spi_pci_set_writeable, +}; + +static const struct intel_spi_boardinfo cnl_info = { + .type = INTEL_SPI_CNL, + .set_writeable = intel_spi_pci_set_writeable, +}; + +static int intel_spi_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct intel_spi_boardinfo *info; + struct intel_spi *ispi; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->data = pdev; + ispi = intel_spi_probe(&pdev->dev, &pdev->resource[0], info); + if (IS_ERR(ispi)) + return PTR_ERR(ispi); + + pci_set_drvdata(pdev, ispi); + return 0; +} + +static void intel_spi_pci_remove(struct pci_dev *pdev) +{ + intel_spi_remove(pci_get_drvdata(pdev)); +} + +static const struct pci_device_id intel_spi_pci_ids[] = { + { PCI_VDEVICE(INTEL, 0x02a4), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x1bca), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&bxt_info }, + { }, +}; +MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids); + +static struct pci_driver intel_spi_pci_driver = { + .name = "intel-spi", + .id_table = intel_spi_pci_ids, + .probe = intel_spi_pci_probe, + .remove = intel_spi_pci_remove, +}; + +module_pci_driver(intel_spi_pci_driver); + +MODULE_DESCRIPTION("Intel PCH/PCU SPI flash PCI driver"); +MODULE_AUTHOR("support"); +MODULE_LICENSE("GPL v2"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_platform.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_platform.c new file mode 100644 index 000000000000..489716d4d545 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_platform.c @@ -0,0 +1,168 @@ +/* + * Intel PCH/PCU SPI flash platform driver. + * + * Copyright (C) 2016, Intel Corporation + * Author: Mika Westerberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include "intel_spi.h" + +#define PCI_VENDOR_ID_D1527_LPC (0x8c54) + +#define BIOS_CNTL (0xdc) +#define BIOS_CNTL_SRC_SHIFT 2 +#define BIOS_CNTL_WN BIT(0) +#define BIOS_CNTL_BLE BIT(1) +#define BIOS_CNTL_SMM_BMP BIT(5) + +#define RCBABASE 0xf0 + +int intel_spi_platform_debug = 0; +module_param(intel_spi_platform_debug, int, S_IRUGO | S_IWUSR); +int intel_spi_platform_error = 0; +module_param(intel_spi_platform_error, int, S_IRUGO | S_IWUSR); + +static bool writeable; +module_param(writeable, bool, 0); +MODULE_PARM_DESC(writeable, "Enable write access to BIOS (default=0)"); + +#define INTEL_SPI_PLATFORM_VERBOSE(fmt, args...) do { \ + if (intel_spi_platform_debug) { \ + printk(KERN_INFO "[INTEL_SPI_PLATFORM][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ + } while (0) + +#define INTEL_SPI_PLATFORM_ERROR(fmt, args...) do { \ + if (intel_spi_platform_error) { \ + printk(KERN_ERR "[INTEL_SPI_PLATFORM][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ + } while (0) + +static void intel_spi_enable_bios_write(struct pci_dev *pci_dev, struct intel_spi_boardinfo *info, int *writeable_flag) +{ + u8 bios_cntl, value, want, new; + + if (writeable) { + pci_read_config_byte(pci_dev, BIOS_CNTL, &bios_cntl); + want = bios_cntl; + value = (bios_cntl >> BIOS_CNTL_SRC_SHIFT) & 0x3 ; + if (value == 0x3) { + INTEL_SPI_PLATFORM_VERBOSE("invalid prefetching/caching settings, "); + } else { + INTEL_SPI_PLATFORM_VERBOSE("prefetching %sabled, caching %sabled, ", + (value & 0x2) ? "en" : "dis", + (value & 0x1) ? "dis" : "en"); + } + + /* writeable regardless */ + want &= ~BIOS_CNTL_SMM_BMP; + /* write enable */ + want |= BIOS_CNTL_WN; + /* BIOS lock disabled */ + want &= ~BIOS_CNTL_BLE; + INTEL_SPI_PLATFORM_VERBOSE("bios cntl is:0x%x, want is:0x%x\n", bios_cntl, want); + pci_write_config_byte(pci_dev, BIOS_CNTL, want); + pci_read_config_byte(pci_dev, BIOS_CNTL, &new); + INTEL_SPI_PLATFORM_VERBOSE("\nBIOS_CNTL = 0x%02x: ", new); + INTEL_SPI_PLATFORM_VERBOSE("BIOS Lock Enable: %sabled, ", (new & BIOS_CNTL_BLE) ? "en" : "dis"); + INTEL_SPI_PLATFORM_VERBOSE("BIOS Write Enable: %sabled\n", (new & BIOS_CNTL_WN) ? "en" : "dis"); + + if (new & BIOS_CNTL_SMM_BMP) { + INTEL_SPI_PLATFORM_VERBOSE("BIOS region SMM protection is enabled!\n"); + } + + if (new != want) { + INTEL_SPI_PLATFORM_VERBOSE("Warning: Setting Bios Control at 0x%x from 0x%02x to 0x%02x failed.\n" + "New value is 0x%02x.\n", BIOS_CNTL, value, want, new); + } else { + *writeable_flag = !!(new & BIOS_CNTL_WN); + } + INTEL_SPI_PLATFORM_VERBOSE("Bios Control is 0x%x\n", new); + } else { + INTEL_SPI_PLATFORM_VERBOSE("Bios don't write\n"); + } + + return ; +} + +static int intel_spi_platform_probe(struct platform_device *pdev) +{ + struct intel_spi_boardinfo *info; + struct intel_spi *ispi; + struct resource *mem; + struct pci_dev *pci_dev = NULL; + u32 rcba; + int writeable_flag = 0; + + info = dev_get_platdata(&pdev->dev); + if (!info) + return -EINVAL; + + pci_dev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_VENDOR_ID_D1527_LPC, pci_dev); + if (!pci_dev) { + INTEL_SPI_PLATFORM_ERROR("pci_get_device(0x8086, 0x8c54) failed!\n"); + return -1; + } + + switch (info->type) { + case INTEL_SPI_LPT: + pci_read_config_dword(pci_dev, RCBABASE, &rcba); + if (rcba & 1) { + intel_spi_enable_bios_write(pci_dev, info, &writeable_flag); + } + break; + default: + INTEL_SPI_PLATFORM_ERROR("info type[%d] not need set writeable.\n",info->type); + break; + } + INTEL_SPI_PLATFORM_VERBOSE("intel spi boardinfo writeable is %sabled\n", + writeable_flag ? "en" : "dis"); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ispi = intel_spi_probe(&pdev->dev, mem, info); + if (IS_ERR(ispi)) + return PTR_ERR(ispi); + + platform_set_drvdata(pdev, ispi); + return 0; +} + +static int intel_spi_platform_remove(struct platform_device *pdev) +{ + struct intel_spi *ispi = platform_get_drvdata(pdev); + + return intel_spi_remove(ispi); +} + +static struct of_device_id intel_spi_match[] = { + { + .compatible = "spi-c224", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, intel_spi_match); + +static struct platform_driver intel_spi_platform_driver = { + .probe = intel_spi_platform_probe, + .remove = intel_spi_platform_remove, + .driver = { + .name = "intel-spi", + .of_match_table = intel_spi_match, + }, +}; + +module_platform_driver(intel_spi_platform_driver); + +MODULE_DESCRIPTION("Intel PCH/PCU SPI flash platform driver"); +MODULE_AUTHOR("support"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:intel-spi"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/Makefile new file mode 100644 index 000000000000..02d659d6c8b2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/Makefile @@ -0,0 +1,37 @@ +PWD = $(shell pwd) + +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall +#ifdef ENABLE_GCOV +#ifeq ($(ENABLE_GCOV), y) +#EXTRA_CFLAGS+= -fprofile-arcs -ftest-coverage -lgcov +#endif +#endif # ENABLE_GCOV + +obj-m := wb_lm75.o +obj-m += wb_tmp401.o +obj-m += wb_i2c_mux_pca9641.o +obj-m += wb_i2c_mux_pca954x.o +obj-m += wb_i2c_i801.o +obj-m += wb_i2c_algo_bit.o +obj-m += wb_i2c_gpio.o +obj-m += wb_i2c_gpio_device.o +obj-m += wb_at24.o +obj-m += wb_pmbus_core.o +obj-m += wb_csu550.o +obj-m += wb_ina3221.o +obj-m += wb_isl68137.o +obj-m += wb_tps53622.o +obj-m += wb_ucd9000.o +obj-m += wb_xdpe12284.o +obj-m += wb_xdpe132g5c_pmbus.o +obj-m += wb_i2c_ismt.o + +all: + $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules + @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi + cp -p $(PWD)/*.ko $(module_out_put_dir) +clean: + rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/*.mod + rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order + rm -rf $(PWD)/.tmp_versions diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_at24.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_at24.c new file mode 100644 index 000000000000..1075e6ef18de --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_at24.c @@ -0,0 +1,861 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * at24.c - handle most I2C EEPROMs + * + * Copyright (C) 2005-2007 David Brownell + * Copyright (C) 2008 Wolfram Sang, Pengutronix + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Address pointer is 16 bit. */ +#define AT24_FLAG_ADDR16 BIT(7) +/* sysfs-entry will be read-only. */ +#define AT24_FLAG_READONLY BIT(6) +/* sysfs-entry will be world-readable. */ +#define AT24_FLAG_IRUGO BIT(5) +/* Take always 8 addresses (24c00). */ +#define AT24_FLAG_TAKE8ADDR BIT(4) +/* Factory-programmed serial number. */ +#define AT24_FLAG_SERIAL BIT(3) +/* Factory-programmed mac address. */ +#define AT24_FLAG_MAC BIT(2) +/* Does not auto-rollover reads to the next slave address. */ +#define AT24_FLAG_NO_RDROL BIT(1) + +/* + * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable. + * Differences between different vendor product lines (like Atmel AT24C or + * MicroChip 24LC, etc) won't much matter for typical read/write access. + * There are also I2C RAM chips, likewise interchangeable. One example + * would be the PCF8570, which acts like a 24c02 EEPROM (256 bytes). + * + * However, misconfiguration can lose data. "Set 16-bit memory address" + * to a part with 8-bit addressing will overwrite data. Writing with too + * big a page size also loses data. And it's not safe to assume that the + * conventional addresses 0x50..0x57 only hold eeproms; a PCF8563 RTC + * uses 0x51, for just one example. + * + * Accordingly, explicit board-specific configuration data should be used + * in almost all cases. (One partial exception is an SMBus used to access + * "SPD" data for DRAM sticks. Those only use 24c02 EEPROMs.) + * + * So this driver uses "new style" I2C driver binding, expecting to be + * told what devices exist. That may be in arch/X/mach-Y/board-Z.c or + * similar kernel-resident tables; or, configuration data coming from + * a bootloader. + * + * Other than binding model, current differences from "eeprom" driver are + * that this one handles write access and isn't restricted to 24c02 devices. + * It also handles larger devices (32 kbit and up) with two-byte addresses, + * which won't work on pure SMBus systems. + */ + +struct at24_client { + struct i2c_client *client; + struct regmap *regmap; +}; + +struct at24_data { + /* + * Lock protects against activities from other Linux tasks, + * but not from changes by other I2C masters. + */ + struct mutex lock; + + unsigned int write_max; + unsigned int num_addresses; + unsigned int offset_adj; + + u32 byte_len; + u16 page_size; + u8 flags; + + struct nvmem_device *nvmem; + struct regulator *vcc_reg; + void (*read_post)(unsigned int off, char *buf, size_t count); + + /* + * Some chips tie up multiple I2C addresses; dummy devices reserve + * them for us, and we'll use them with SMBus calls. + */ + struct at24_client client[]; +}; + +/* + * This parameter is to help this driver avoid blocking other drivers out + * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C + * clock, one 256 byte read takes about 1/43 second which is excessive; + * but the 1/170 second it takes at 400 kHz may be quite reasonable; and + * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible. + * + * This value is forced to be a power of two so that writes align on pages. + */ +static unsigned int at24_io_limit = 128; +module_param_named(io_limit, at24_io_limit, uint, 0); +MODULE_PARM_DESC(at24_io_limit, "Maximum bytes per I/O (default 128)"); + +/* + * Specs often allow 5 msec for a page write, sometimes 20 msec; + * it's important to recover from write timeouts. + */ +static unsigned int at24_write_timeout = 25; +module_param_named(write_timeout, at24_write_timeout, uint, 0); +MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)"); + +struct at24_chip_data { + u32 byte_len; + u8 flags; + void (*read_post)(unsigned int off, char *buf, size_t count); +}; + +#define AT24_CHIP_DATA(_name, _len, _flags) \ + static const struct at24_chip_data _name = { \ + .byte_len = _len, .flags = _flags, \ + } + +#define AT24_CHIP_DATA_CB(_name, _len, _flags, _read_post) \ + static const struct at24_chip_data _name = { \ + .byte_len = _len, .flags = _flags, \ + .read_post = _read_post, \ + } + +static void at24_read_post_vaio(unsigned int off, char *buf, size_t count) +{ + int i; + + if (capable(CAP_SYS_ADMIN)) + return; + + /* + * Hide VAIO private settings to regular users: + * - BIOS passwords: bytes 0x00 to 0x0f + * - UUID: bytes 0x10 to 0x1f + * - Serial number: 0xc0 to 0xdf + */ + for (i = 0; i < count; i++) { + if ((off + i <= 0x1f) || + (off + i >= 0xc0 && off + i <= 0xdf)) + buf[i] = 0; + } +} + +/* needs 8 addresses as A0-A2 are ignored */ +AT24_CHIP_DATA(at24_data_24c00, 128 / 8, AT24_FLAG_TAKE8ADDR); +/* old variants can't be handled with this generic entry! */ +AT24_CHIP_DATA(at24_data_24c01, 1024 / 8, 0); +AT24_CHIP_DATA(at24_data_24cs01, 16, + AT24_FLAG_SERIAL | AT24_FLAG_READONLY); +AT24_CHIP_DATA(at24_data_24c02, 2048 / 8, AT24_FLAG_IRUGO); +AT24_CHIP_DATA(at24_data_24cs02, 16, + AT24_FLAG_SERIAL | AT24_FLAG_READONLY); +AT24_CHIP_DATA(at24_data_24mac402, 48 / 8, + AT24_FLAG_MAC | AT24_FLAG_READONLY); +AT24_CHIP_DATA(at24_data_24mac602, 64 / 8, + AT24_FLAG_MAC | AT24_FLAG_READONLY); +/* spd is a 24c02 in memory DIMMs */ +AT24_CHIP_DATA(at24_data_spd, 2048 / 8, + AT24_FLAG_READONLY | AT24_FLAG_IRUGO); +/* 24c02_vaio is a 24c02 on some Sony laptops */ +AT24_CHIP_DATA_CB(at24_data_24c02_vaio, 2048 / 8, + AT24_FLAG_READONLY | AT24_FLAG_IRUGO, + at24_read_post_vaio); +AT24_CHIP_DATA(at24_data_24c04, 4096 / 8, 0); +AT24_CHIP_DATA(at24_data_24cs04, 16, + AT24_FLAG_SERIAL | AT24_FLAG_READONLY); +/* 24rf08 quirk is handled at i2c-core */ +AT24_CHIP_DATA(at24_data_24c08, 8192 / 8, 0); +AT24_CHIP_DATA(at24_data_24cs08, 16, + AT24_FLAG_SERIAL | AT24_FLAG_READONLY); +AT24_CHIP_DATA(at24_data_24c16, 16384 / 8, 0); +AT24_CHIP_DATA(at24_data_24cs16, 16, + AT24_FLAG_SERIAL | AT24_FLAG_READONLY); +AT24_CHIP_DATA(at24_data_24c32, 32768 / 8, AT24_FLAG_ADDR16); +AT24_CHIP_DATA(at24_data_24cs32, 16, + AT24_FLAG_ADDR16 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY); +AT24_CHIP_DATA(at24_data_24c64, 65536 / 8, AT24_FLAG_ADDR16 | AT24_FLAG_IRUGO); +AT24_CHIP_DATA(at24_data_24cs64, 16, + AT24_FLAG_ADDR16 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY); +AT24_CHIP_DATA(at24_data_24c128, 131072 / 8, AT24_FLAG_ADDR16); +AT24_CHIP_DATA(at24_data_24c256, 262144 / 8, AT24_FLAG_ADDR16); +AT24_CHIP_DATA(at24_data_24c512, 524288 / 8, AT24_FLAG_ADDR16); +AT24_CHIP_DATA(at24_data_24c1024, 1048576 / 8, AT24_FLAG_ADDR16); +AT24_CHIP_DATA(at24_data_24c2048, 2097152 / 8, AT24_FLAG_ADDR16); +/* identical to 24c08 ? */ +AT24_CHIP_DATA(at24_data_INT3499, 8192 / 8, 0); + +static const struct i2c_device_id at24_ids[] = { + { "wb_24c00", (kernel_ulong_t)&at24_data_24c00 }, + { "wb_24c01", (kernel_ulong_t)&at24_data_24c01 }, + { "wb_24cs01", (kernel_ulong_t)&at24_data_24cs01 }, + { "wb_24c02", (kernel_ulong_t)&at24_data_24c02 }, + { "wb_24cs02", (kernel_ulong_t)&at24_data_24cs02 }, + { "wb_24mac402", (kernel_ulong_t)&at24_data_24mac402 }, + { "wb_24mac602", (kernel_ulong_t)&at24_data_24mac602 }, + { "wb_spd", (kernel_ulong_t)&at24_data_spd }, + { "wb_24c02-vaio", (kernel_ulong_t)&at24_data_24c02_vaio }, + { "wb_24c04", (kernel_ulong_t)&at24_data_24c04 }, + { "wb_24cs04", (kernel_ulong_t)&at24_data_24cs04 }, + { "wb_24c08", (kernel_ulong_t)&at24_data_24c08 }, + { "wb_24cs08", (kernel_ulong_t)&at24_data_24cs08 }, + { "wb_24c16", (kernel_ulong_t)&at24_data_24c16 }, + { "wb_24cs16", (kernel_ulong_t)&at24_data_24cs16 }, + { "wb_24c32", (kernel_ulong_t)&at24_data_24c32 }, + { "wb_24cs32", (kernel_ulong_t)&at24_data_24cs32 }, + { "wb_24c64", (kernel_ulong_t)&at24_data_24c64 }, + { "wb_24cs64", (kernel_ulong_t)&at24_data_24cs64 }, + { "wb_24c128", (kernel_ulong_t)&at24_data_24c128 }, + { "wb_24c256", (kernel_ulong_t)&at24_data_24c256 }, + { "wb_24c512", (kernel_ulong_t)&at24_data_24c512 }, + { "wb_24c1024", (kernel_ulong_t)&at24_data_24c1024 }, + { "wb_24c2048", (kernel_ulong_t)&at24_data_24c2048 }, + { "wb_at24", 0 }, + { /* END OF LIST */ } +}; +MODULE_DEVICE_TABLE(i2c, at24_ids); + +static const struct of_device_id at24_of_match[] = { + { .compatible = "atmel,24c00", .data = &at24_data_24c00 }, + { .compatible = "atmel,24c01", .data = &at24_data_24c01 }, + { .compatible = "atmel,24cs01", .data = &at24_data_24cs01 }, + { .compatible = "atmel,24c02", .data = &at24_data_24c02 }, + { .compatible = "atmel,24cs02", .data = &at24_data_24cs02 }, + { .compatible = "atmel,24mac402", .data = &at24_data_24mac402 }, + { .compatible = "atmel,24mac602", .data = &at24_data_24mac602 }, + { .compatible = "atmel,spd", .data = &at24_data_spd }, + { .compatible = "atmel,24c04", .data = &at24_data_24c04 }, + { .compatible = "atmel,24cs04", .data = &at24_data_24cs04 }, + { .compatible = "atmel,24c08", .data = &at24_data_24c08 }, + { .compatible = "atmel,24cs08", .data = &at24_data_24cs08 }, + { .compatible = "atmel,24c16", .data = &at24_data_24c16 }, + { .compatible = "atmel,24cs16", .data = &at24_data_24cs16 }, + { .compatible = "atmel,24c32", .data = &at24_data_24c32 }, + { .compatible = "atmel,24cs32", .data = &at24_data_24cs32 }, + { .compatible = "atmel,24c64", .data = &at24_data_24c64 }, + { .compatible = "atmel,24cs64", .data = &at24_data_24cs64 }, + { .compatible = "atmel,24c128", .data = &at24_data_24c128 }, + { .compatible = "atmel,24c256", .data = &at24_data_24c256 }, + { .compatible = "atmel,24c512", .data = &at24_data_24c512 }, + { .compatible = "atmel,24c1024", .data = &at24_data_24c1024 }, + { .compatible = "atmel,24c2048", .data = &at24_data_24c2048 }, + { /* END OF LIST */ }, +}; +MODULE_DEVICE_TABLE(of, at24_of_match); + +static const struct acpi_device_id __maybe_unused at24_acpi_ids[] = { + { "INT3499", (kernel_ulong_t)&at24_data_INT3499 }, + { "TPF0001", (kernel_ulong_t)&at24_data_24c1024 }, + { /* END OF LIST */ } +}; +MODULE_DEVICE_TABLE(acpi, at24_acpi_ids); + +/* + * This routine supports chips which consume multiple I2C addresses. It + * computes the addressing information to be used for a given r/w request. + * Assumes that sanity checks for offset happened at sysfs-layer. + * + * Slave address and byte offset derive from the offset. Always + * set the byte address; on a multi-master board, another master + * may have changed the chip's "current" address pointer. + */ +static struct at24_client *at24_translate_offset(struct at24_data *at24, + unsigned int *offset) +{ + unsigned int i; + + if (at24->flags & AT24_FLAG_ADDR16) { + i = *offset >> 16; + *offset &= 0xffff; + } else { + i = *offset >> 8; + *offset &= 0xff; + } + + return &at24->client[i]; +} + +static struct device *at24_base_client_dev(struct at24_data *at24) +{ + return &at24->client[0].client->dev; +} + +static size_t at24_adjust_read_count(struct at24_data *at24, + unsigned int offset, size_t count) +{ + unsigned int bits; + size_t remainder; + + /* + * In case of multi-address chips that don't rollover reads to + * the next slave address: truncate the count to the slave boundary, + * so that the read never straddles slaves. + */ + if (at24->flags & AT24_FLAG_NO_RDROL) { + bits = (at24->flags & AT24_FLAG_ADDR16) ? 16 : 8; + remainder = BIT(bits) - offset; + if (count > remainder) + count = remainder; + } + + if (count > at24_io_limit) + count = at24_io_limit; + + return count; +} + +static ssize_t at24_regmap_read(struct at24_data *at24, char *buf, + unsigned int offset, size_t count) +{ + unsigned long timeout, read_time; + struct at24_client *at24_client; + struct i2c_client *client; + struct regmap *regmap; + int ret; + + at24_client = at24_translate_offset(at24, &offset); + regmap = at24_client->regmap; + client = at24_client->client; + count = at24_adjust_read_count(at24, offset, count); + + /* adjust offset for mac and serial read ops */ + offset += at24->offset_adj; + + timeout = jiffies + msecs_to_jiffies(at24_write_timeout); + do { + /* + * The timestamp shall be taken before the actual operation + * to avoid a premature timeout in case of high CPU load. + */ + read_time = jiffies; + + ret = regmap_bulk_read(regmap, offset, buf, count); + dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n", + count, offset, ret, jiffies); + if (!ret) + return count; + + usleep_range(1000, 1500); + } while (time_before(read_time, timeout)); + + return -ETIMEDOUT; +} + +/* + * Note that if the hardware write-protect pin is pulled high, the whole + * chip is normally write protected. But there are plenty of product + * variants here, including OTP fuses and partial chip protect. + * + * We only use page mode writes; the alternative is sloooow. These routines + * write at most one page. + */ + +static size_t at24_adjust_write_count(struct at24_data *at24, + unsigned int offset, size_t count) +{ + unsigned int next_page; + + /* write_max is at most a page */ + if (count > at24->write_max) + count = at24->write_max; + + /* Never roll over backwards, to the start of this page */ + next_page = roundup(offset + 1, at24->page_size); + if (offset + count > next_page) + count = next_page - offset; + + return count; +} + +static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf, + unsigned int offset, size_t count) +{ + unsigned long timeout, write_time; + struct at24_client *at24_client; + struct i2c_client *client; + struct regmap *regmap; + int ret; + + at24_client = at24_translate_offset(at24, &offset); + regmap = at24_client->regmap; + client = at24_client->client; + count = at24_adjust_write_count(at24, offset, count); + timeout = jiffies + msecs_to_jiffies(at24_write_timeout); + + do { + /* + * The timestamp shall be taken before the actual operation + * to avoid a premature timeout in case of high CPU load. + */ + write_time = jiffies; + + ret = regmap_bulk_write(regmap, offset, buf, count); + dev_dbg(&client->dev, "write %zu@%d --> %d (%ld)\n", + count, offset, ret, jiffies); + if (!ret) + return count; + + usleep_range(1000, 1500); + } while (time_before(write_time, timeout)); + + return -ETIMEDOUT; +} + +static int at24_read(void *priv, unsigned int off, void *val, size_t count) +{ + struct at24_data *at24; + struct device *dev; + char *buf = val; + int i, ret; + + at24 = priv; + dev = at24_base_client_dev(at24); + + if (unlikely(!count)) + return count; + + if (off + count > at24->byte_len) + return -EINVAL; + + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + return ret; + } + + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&at24->lock); + + for (i = 0; count; i += ret, count -= ret) { + ret = at24_regmap_read(at24, buf + i, off + i, count); + if (ret < 0) { + mutex_unlock(&at24->lock); + pm_runtime_put(dev); + return ret; + } + } + + mutex_unlock(&at24->lock); + + pm_runtime_put(dev); + + if (unlikely(at24->read_post)) + at24->read_post(off, buf, i); + + return 0; +} + +static int at24_write(void *priv, unsigned int off, void *val, size_t count) +{ + struct at24_data *at24; + struct device *dev; + char *buf = val; + int ret; + + at24 = priv; + dev = at24_base_client_dev(at24); + + if (unlikely(!count)) + return -EINVAL; + + if (off + count > at24->byte_len) + return -EINVAL; + + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + return ret; + } + + /* + * Write data to chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&at24->lock); + + while (count) { + ret = at24_regmap_write(at24, buf, off, count); + if (ret < 0) { + mutex_unlock(&at24->lock); + pm_runtime_put(dev); + return ret; + } + buf += ret; + off += ret; + count -= ret; + } + + mutex_unlock(&at24->lock); + + pm_runtime_put(dev); + + return 0; +} + +static const struct at24_chip_data *at24_get_chip_data(struct device *dev) +{ + struct device_node *of_node = dev->of_node; + const struct at24_chip_data *cdata; + const struct i2c_device_id *id; + + id = i2c_match_id(at24_ids, to_i2c_client(dev)); + + /* + * The I2C core allows OF nodes compatibles to match against the + * I2C device ID table as a fallback, so check not only if an OF + * node is present but also if it matches an OF device ID entry. + */ + if (of_node && of_match_device(at24_of_match, dev)) + cdata = of_device_get_match_data(dev); + else if (id) + cdata = (void *)id->driver_data; + else + cdata = acpi_device_get_match_data(dev); + + if (!cdata) + return ERR_PTR(-ENODEV); + + return cdata; +} + +static int at24_make_dummy_client(struct at24_data *at24, unsigned int index, + struct regmap_config *regmap_config) +{ + struct i2c_client *base_client, *dummy_client; + struct regmap *regmap; + struct device *dev; + + base_client = at24->client[0].client; + dev = &base_client->dev; + + dummy_client = devm_i2c_new_dummy_device(dev, base_client->adapter, + base_client->addr + index); + if (IS_ERR(dummy_client)) + return PTR_ERR(dummy_client); + + regmap = devm_regmap_init_i2c(dummy_client, regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + at24->client[index].client = dummy_client; + at24->client[index].regmap = regmap; + + return 0; +} + +static unsigned int at24_get_offset_adj(u8 flags, unsigned int byte_len) +{ + if (flags & AT24_FLAG_MAC) { + /* EUI-48 starts from 0x9a, EUI-64 from 0x98 */ + return 0xa0 - byte_len; + } else if (flags & AT24_FLAG_SERIAL && flags & AT24_FLAG_ADDR16) { + /* + * For 16 bit address pointers, the word address must contain + * a '10' sequence in bits 11 and 10 regardless of the + * intended position of the address pointer. + */ + return 0x0800; + } else if (flags & AT24_FLAG_SERIAL) { + /* + * Otherwise the word address must begin with a '10' sequence, + * regardless of the intended address. + */ + return 0x0080; + } else { + return 0; + } +} + +static int at24_probe(struct i2c_client *client) +{ + struct regmap_config regmap_config = { }; + struct nvmem_config nvmem_config = { }; + u32 byte_len, page_size, flags, addrw; + const struct at24_chip_data *cdata; + struct device *dev = &client->dev; + bool i2c_fn_i2c, i2c_fn_block; + unsigned int i, num_addresses; + struct at24_data *at24; + struct regmap *regmap; + bool writable; + u8 test_byte; + int err; + + i2c_fn_i2c = i2c_check_functionality(client->adapter, I2C_FUNC_I2C); + i2c_fn_block = i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK); + + cdata = at24_get_chip_data(dev); + if (IS_ERR(cdata)) + return PTR_ERR(cdata); + + err = device_property_read_u32(dev, "pagesize", &page_size); + if (err) + /* + * This is slow, but we can't know all eeproms, so we better + * play safe. Specifying custom eeprom-types via device tree + * or properties is recommended anyhow. + */ + page_size = 1; + + flags = cdata->flags; + if (device_property_present(dev, "read-only")) + flags |= AT24_FLAG_READONLY; + if (device_property_present(dev, "no-read-rollover")) + flags |= AT24_FLAG_NO_RDROL; + + err = device_property_read_u32(dev, "address-width", &addrw); + if (!err) { + switch (addrw) { + case 8: + if (flags & AT24_FLAG_ADDR16) + dev_warn(dev, + "Override address width to be 8, while default is 16\n"); + flags &= ~AT24_FLAG_ADDR16; + break; + case 16: + flags |= AT24_FLAG_ADDR16; + break; + default: + dev_warn(dev, "Bad \"address-width\" property: %u\n", + addrw); + } + } + + err = device_property_read_u32(dev, "size", &byte_len); + if (err) + byte_len = cdata->byte_len; + + if (!i2c_fn_i2c && !i2c_fn_block) + page_size = 1; + + if (!page_size) { + dev_err(dev, "page_size must not be 0!\n"); + return -EINVAL; + } + + if (!is_power_of_2(page_size)) + dev_warn(dev, "page_size looks suspicious (no power of 2)!\n"); + + err = device_property_read_u32(dev, "num-addresses", &num_addresses); + if (err) { + if (flags & AT24_FLAG_TAKE8ADDR) + num_addresses = 8; + else + num_addresses = DIV_ROUND_UP(byte_len, + (flags & AT24_FLAG_ADDR16) ? 65536 : 256); + } + + if ((flags & AT24_FLAG_SERIAL) && (flags & AT24_FLAG_MAC)) { + dev_err(dev, + "invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC."); + return -EINVAL; + } + + regmap_config.val_bits = 8; + regmap_config.reg_bits = (flags & AT24_FLAG_ADDR16) ? 16 : 8; + regmap_config.disable_locking = true; + + regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + at24 = devm_kzalloc(dev, struct_size(at24, client, num_addresses), + GFP_KERNEL); + if (!at24) + return -ENOMEM; + + mutex_init(&at24->lock); + at24->byte_len = byte_len; + at24->page_size = page_size; + at24->flags = flags; + at24->read_post = cdata->read_post; + at24->num_addresses = num_addresses; + at24->offset_adj = at24_get_offset_adj(flags, byte_len); + at24->client[0].client = client; + at24->client[0].regmap = regmap; + + at24->vcc_reg = devm_regulator_get(dev, "vcc"); + if (IS_ERR(at24->vcc_reg)) + return PTR_ERR(at24->vcc_reg); + + writable = !(flags & AT24_FLAG_READONLY); + if (writable) { + at24->write_max = min_t(unsigned int, + page_size, at24_io_limit); + if (!i2c_fn_i2c && at24->write_max > I2C_SMBUS_BLOCK_MAX) + at24->write_max = I2C_SMBUS_BLOCK_MAX; + } + + /* use dummy devices for multiple-address chips */ + for (i = 1; i < num_addresses; i++) { + err = at24_make_dummy_client(at24, i, ®map_config); + if (err) + return err; + } + + /* + * If the 'label' property is not present for the AT24 EEPROM, + * then nvmem_config.id is initialised to NVMEM_DEVID_AUTO, + * and this will append the 'devid' to the name of the NVMEM + * device. This is purely legacy and the AT24 driver has always + * defaulted to this. However, if the 'label' property is + * present then this means that the name is specified by the + * firmware and this name should be used verbatim and so it is + * not necessary to append the 'devid'. + */ + if (device_property_present(dev, "label")) { + nvmem_config.id = NVMEM_DEVID_NONE; + err = device_property_read_string(dev, "label", + &nvmem_config.name); + if (err) + return err; + } else { + nvmem_config.id = NVMEM_DEVID_AUTO; + nvmem_config.name = dev_name(dev); + } + + nvmem_config.type = NVMEM_TYPE_EEPROM; + nvmem_config.dev = dev; + nvmem_config.read_only = !writable; + nvmem_config.root_only = !(flags & AT24_FLAG_IRUGO); + nvmem_config.owner = THIS_MODULE; + nvmem_config.compat = true; + nvmem_config.base_dev = dev; + nvmem_config.reg_read = at24_read; + nvmem_config.reg_write = at24_write; + nvmem_config.priv = at24; + nvmem_config.stride = 1; + nvmem_config.word_size = 1; + nvmem_config.size = byte_len; + + i2c_set_clientdata(client, at24); + + err = regulator_enable(at24->vcc_reg); + if (err) { + dev_err(dev, "Failed to enable vcc regulator\n"); + return err; + } + + /* enable runtime pm */ + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + at24->nvmem = devm_nvmem_register(dev, &nvmem_config); + if (IS_ERR(at24->nvmem)) { + pm_runtime_disable(dev); + if (!pm_runtime_status_suspended(dev)) + regulator_disable(at24->vcc_reg); + return PTR_ERR(at24->nvmem); + } + + /* + * Perform a one-byte test read to verify that the + * chip is functional. + */ + err = at24_read(at24, 0, &test_byte, 1); + if (err) { + pm_runtime_disable(dev); + if (!pm_runtime_status_suspended(dev)) + regulator_disable(at24->vcc_reg); + return -ENODEV; + } + + pm_runtime_idle(dev); + + if (writable) + dev_info(dev, "%u byte %s EEPROM, writable, %u bytes/write\n", + byte_len, client->name, at24->write_max); + else + dev_info(dev, "%u byte %s EEPROM, read-only\n", + byte_len, client->name); + + return 0; +} + +static int at24_remove(struct i2c_client *client) +{ + struct at24_data *at24 = i2c_get_clientdata(client); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + regulator_disable(at24->vcc_reg); + pm_runtime_set_suspended(&client->dev); + + return 0; +} + +static int __maybe_unused at24_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct at24_data *at24 = i2c_get_clientdata(client); + + return regulator_disable(at24->vcc_reg); +} + +static int __maybe_unused at24_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct at24_data *at24 = i2c_get_clientdata(client); + + return regulator_enable(at24->vcc_reg); +} + +static const struct dev_pm_ops at24_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(at24_suspend, at24_resume, NULL) +}; + +static struct i2c_driver at24_driver = { + .driver = { + .name = "wb_at24", + .pm = &at24_pm_ops, + .of_match_table = at24_of_match, + .acpi_match_table = ACPI_PTR(at24_acpi_ids), + }, + .probe_new = at24_probe, + .remove = at24_remove, + .id_table = at24_ids, +}; + +static int __init at24_init(void) +{ + if (!at24_io_limit) { + pr_err("at24: at24_io_limit must not be 0!\n"); + return -EINVAL; + } + + at24_io_limit = rounddown_pow_of_two(at24_io_limit); + return i2c_add_driver(&at24_driver); +} +module_init(at24_init); + +static void __exit at24_exit(void) +{ + i2c_del_driver(&at24_driver); +} +module_exit(at24_exit); + +MODULE_DESCRIPTION("Driver for most I2C EEPROMs"); +MODULE_AUTHOR("support"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_csu550.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_csu550.c new file mode 100644 index 000000000000..36d07f071a71 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_csu550.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for PMBus devices + * + * Copyright (c) 2010, 2011 Ericsson AB. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "wb_pmbus.h" + +struct pmbus_device_info { + int pages; + u32 flags; +}; + +static const struct i2c_device_id pmbus_id[]; + +/* + * Find sensor groups and status registers on each page. + */ +static void pmbus_find_sensor_groups(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + int page; + + /* Sensors detected on page 0 only */ + if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_VIN)) + info->func[0] |= PMBUS_HAVE_VIN; + if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_IIN)) + info->func[0] |= PMBUS_HAVE_IIN; + if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_PIN)) + info->func[0] |= PMBUS_HAVE_PIN; + if (info->func[0] + && wb_pmbus_check_byte_register(client, 0, PMBUS_STATUS_INPUT)) + info->func[0] |= PMBUS_HAVE_STATUS_INPUT; + if (wb_pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_12) && + wb_pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_1)) { + info->func[0] |= PMBUS_HAVE_FAN12; + if (wb_pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_12)) + info->func[0] |= PMBUS_HAVE_STATUS_FAN12; + } + if (wb_pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_34) && + wb_pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_3)) { + info->func[0] |= PMBUS_HAVE_FAN34; + if (wb_pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_34)) + info->func[0] |= PMBUS_HAVE_STATUS_FAN34; + } + if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_1)) + info->func[0] |= PMBUS_HAVE_TEMP; + if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_2)) + info->func[0] |= PMBUS_HAVE_TEMP2; + if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_3)) + info->func[0] |= PMBUS_HAVE_TEMP3; + if (info->func[0] & (PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 + | PMBUS_HAVE_TEMP3) + && wb_pmbus_check_byte_register(client, 0, + PMBUS_STATUS_TEMPERATURE)) + info->func[0] |= PMBUS_HAVE_STATUS_TEMP; + + /* Sensors detected on all pages */ + for (page = 0; page < info->pages; page++) { + if (wb_pmbus_check_word_register(client, page, PMBUS_READ_VOUT)) { + info->func[page] |= PMBUS_HAVE_VOUT; + if (wb_pmbus_check_byte_register(client, page, + PMBUS_STATUS_VOUT)) + info->func[page] |= PMBUS_HAVE_STATUS_VOUT; + } + if (wb_pmbus_check_word_register(client, page, PMBUS_READ_IOUT)) { + info->func[page] |= PMBUS_HAVE_IOUT; + if (wb_pmbus_check_byte_register(client, 0, + PMBUS_STATUS_IOUT)) + info->func[page] |= PMBUS_HAVE_STATUS_IOUT; + } + if (wb_pmbus_check_word_register(client, page, PMBUS_READ_POUT)) + info->func[page] |= PMBUS_HAVE_POUT; + } +} + +/* + * Identify chip parameters. + */ +static int pmbus_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + int ret = 0; + + if (!info->pages) { + /* + * Check if the PAGE command is supported. If it is, + * keep setting the page number until it fails or until the + * maximum number of pages has been reached. Assume that + * this is the number of pages supported by the chip. + */ + if (wb_pmbus_check_byte_register(client, 0, PMBUS_PAGE)) { + int page; + + for (page = 1; page < PMBUS_PAGES; page++) { + if (wb_pmbus_set_page(client, page, 0xff) < 0) + break; + } + wb_pmbus_set_page(client, 0, 0xff); + info->pages = page; + } else { + info->pages = 1; + } + + wb_pmbus_clear_faults(client); + } + + if (wb_pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) { + int vout_mode, i; + + vout_mode = wb_pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); + if (vout_mode >= 0 && vout_mode != 0xff) { + switch (vout_mode >> 5) { + case 0: + break; + case 1: + info->format[PSC_VOLTAGE_OUT] = vid; + for (i = 0; i < info->pages; i++) + info->vrm_version[i] = vr11; + break; + case 2: + info->format[PSC_VOLTAGE_OUT] = direct; + break; + default: + ret = -ENODEV; + goto abort; + } + } + } + + /* + * We should check if the COEFFICIENTS register is supported. + * If it is, and the chip is configured for direct mode, we can read + * the coefficients from the chip, one set per group of sensor + * registers. + * + * To do this, we will need access to a chip which actually supports the + * COEFFICIENTS command, since the command is too complex to implement + * without testing it. Until then, abort if a chip configured for direct + * mode was detected. + */ + if (info->format[PSC_VOLTAGE_OUT] == direct) { + ret = -ENODEV; + goto abort; + } + + /* Try to find sensor groups */ + pmbus_find_sensor_groups(client, info); +abort: + return ret; +} + +static int pmbus_probe(struct i2c_client *client) +{ + struct pmbus_driver_info *info; + struct pmbus_platform_data *pdata = NULL; + struct device *dev = &client->dev; + struct pmbus_device_info *device_info; + + info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + device_info = (struct pmbus_device_info *)i2c_match_id(pmbus_id, client)->driver_data; + if (device_info->flags & PMBUS_SKIP_STATUS_CHECK) { + pdata = devm_kzalloc(dev, sizeof(struct pmbus_platform_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->flags = PMBUS_SKIP_STATUS_CHECK; + } + + info->pages = device_info->pages; + info->identify = pmbus_identify; + dev->platform_data = pdata; + + return wb_pmbus_do_probe(client, info); +} + +static const struct pmbus_device_info pmbus_info_one = { + .pages = 1, + .flags = 0 +}; + +static const struct pmbus_device_info pmbus_info_zero = { + .pages = 0, + .flags = 0 +}; + +static const struct pmbus_device_info pmbus_info_one_skip = { + .pages = 1, + .flags = PMBUS_SKIP_STATUS_CHECK +}; + +static const struct pmbus_device_info pmbus_info_zero_skip = { + .pages = 0, + .flags = PMBUS_SKIP_STATUS_CHECK +}; +/* + * Use driver_data to set the number of pages supported by the chip. + */ +static const struct i2c_device_id pmbus_id[] = { + {"wb_csu550", (kernel_ulong_t)&pmbus_info_zero_skip}, + {"wb_csu800", (kernel_ulong_t)&pmbus_info_one_skip}, + {"wb_fsp1200", (kernel_ulong_t)&pmbus_info_one_skip}, + {"wb_dps550", (kernel_ulong_t)&pmbus_info_one_skip}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, pmbus_id); + +/* This is the driver that will be inserted */ +static struct i2c_driver pmbus_driver = { + .driver = { + .name = "wb_pmbus", + }, + .probe_new = pmbus_probe, + .remove = wb_pmbus_do_remove, + .id_table = pmbus_id, +}; + +module_i2c_driver(pmbus_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("Generic PMBus driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_algo_bit.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_algo_bit.c new file mode 100644 index 000000000000..c98ac7a1c5b6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_algo_bit.c @@ -0,0 +1,725 @@ +/* ------------------------------------------------------------------------- + * i2c-algo-bit.c i2c driver algorithms for bit-shift adapters + * ------------------------------------------------------------------------- + * Copyright (C) 1995-2000 Simon G. Vogl + + 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. + * ------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include + +static int g_i2c_algo_bit_debug = 0; +static int g_i2c_algo_bit_error = 0; + +module_param(g_i2c_algo_bit_debug, int, S_IRUGO | S_IWUSR); +module_param(g_i2c_algo_bit_error, int, S_IRUGO | S_IWUSR); + +#define I2C_ALGO_BIT_DEBUG(fmt, args...) do { \ + if (g_i2c_algo_bit_debug) { \ + printk(KERN_INFO "[I2C_ALGO_BIT][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define I2C_ALGO_BIT_ERROR(fmt, args...) do { \ + if (g_i2c_algo_bit_error) { \ + printk(KERN_ERR "[I2C_ALGO_BIT][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +/* ----- global defines ----------------------------------------------- */ + +#ifdef DEBUG +#define bit_dbg(level, dev, format, args...) \ + do { \ + if (i2c_debug >= level) \ + dev_dbg(dev, format, ##args); \ + } while (0) +#else +#define bit_dbg(level, dev, format, args...) \ + do {} while (0) +#endif /* DEBUG */ + +/* ----- global variables --------------------------------------------- */ + +static int bit_test; /* see if the line-setting functions work */ +module_param(bit_test, int, S_IRUGO); +MODULE_PARM_DESC(bit_test, "lines testing - 0 off; 1 report; 2 fail if stuck"); + +#ifdef DEBUG +static int i2c_debug = 1; +module_param(i2c_debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(i2c_debug, + "debug level - 0 off; 1 normal; 2 verbose; 3 very verbose"); +#endif + +/* --- setting states on the bus with the right timing: --------------- */ + +#define setsda(adap, val) adap->setsda(adap->data, val) +#define setscl(adap, val) adap->setscl(adap->data, val) +#define getsda(adap) adap->getsda(adap->data) +#define getscl(adap) adap->getscl(adap->data) + +static inline void sdalo(struct i2c_algo_bit_data *adap) +{ + setsda(adap, 0); + udelay((adap->udelay + 1) / 2); +} + +static inline void sdahi(struct i2c_algo_bit_data *adap) +{ + setsda(adap, 1); + udelay((adap->udelay + 1) / 2); +} + +static inline void scllo(struct i2c_algo_bit_data *adap) +{ + setscl(adap, 0); + udelay(adap->udelay / 2); +} + +/* + * Raise scl line, and do checking for delays. This is necessary for slower + * devices. + */ +static int sclhi(struct i2c_algo_bit_data *adap) +{ + unsigned long start; + + setscl(adap, 1); + + /* Not all adapters have scl sense line... */ + if (!adap->getscl) + goto done; + + start = jiffies; + while (!getscl(adap)) { + /* This hw knows how to read the clock line, so we wait + * until it actually gets high. This is safer as some + * chips may hold it low ("clock stretching") while they + * are processing data internally. + */ + if (time_after(jiffies, start + adap->timeout)) { + /* Test one last time, as we may have been preempted + * between last check and timeout test. + */ + if (getscl(adap)) + break; + return -ETIMEDOUT; + } + cpu_relax(); + } +#ifdef DEBUG + if (jiffies != start && i2c_debug >= 3) + pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go " + "high\n", jiffies - start); +#endif + +done: + udelay(adap->udelay); + return 0; +} + +/* --- other auxiliary functions -------------------------------------- */ +static void i2c_start(struct i2c_algo_bit_data *adap) +{ + /* assert: scl, sda are high */ + setsda(adap, 0); + udelay(adap->udelay); + scllo(adap); +} + +static void i2c_repstart(struct i2c_algo_bit_data *adap) +{ + /* assert: scl is low */ + sdahi(adap); + sclhi(adap); + setsda(adap, 0); + udelay(adap->udelay); + scllo(adap); +} + +static void i2c_stop(struct i2c_algo_bit_data *adap) +{ + /* assert: scl is low */ + sdalo(adap); + sclhi(adap); + setsda(adap, 1); + udelay(adap->udelay); +} + +/* send a byte without start cond., look for arbitration, + check ackn. from slave */ +/* returns: + * 1 if the device acknowledged + * 0 if the device did not ack + * -ETIMEDOUT if an error occurred (while raising the scl line) + */ +static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c) +{ + int i; + int sb; + int ack; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + /* assert: scl is low */ + for (i = 7; i >= 0; i--) { + sb = (c >> i) & 1; + setsda(adap, sb); + udelay((adap->udelay + 1) / 2); + if (sclhi(adap) < 0) { /* timed out */ + bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " + "timeout at bit #%d\n", (int)c, i); + return -ETIMEDOUT; + } + /* FIXME do arbitration here: + * if (sb && !getsda(adap)) -> ouch! Get out of here. + * + * Report a unique code, so higher level code can retry + * the whole (combined) message and *NOT* issue STOP. + */ + scllo(adap); + } + sdahi(adap); + if (sclhi(adap) < 0) { /* timeout */ + bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " + "timeout at ack\n", (int)c); + return -ETIMEDOUT; + } + + /* read ack: SDA should be pulled down by slave, or it may + * NAK (usually to report problems with the data we wrote). + */ + ack = !getsda(adap); /* ack: sda is pulled low -> success */ + bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c, + ack ? "A" : "NA"); + + scllo(adap); + return ack; + /* assert: scl is low (sda undef) */ +} + +static int i2c_inb(struct i2c_adapter *i2c_adap) +{ + /* read byte via i2c port, without start/stop sequence */ + /* acknowledge is sent in i2c_read. */ + int i; + unsigned char indata = 0; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + /* assert: scl is low */ + sdahi(adap); + for (i = 0; i < 8; i++) { + if (sclhi(adap) < 0) { /* timeout */ + bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit " + "#%d\n", 7 - i); + return -ETIMEDOUT; + } + indata *= 2; + if (getsda(adap)) + indata |= 0x01; + setscl(adap, 0); + udelay(i == 7 ? adap->udelay / 2 : adap->udelay); + } + /* assert: scl is low */ + return indata; +} + +/* + * Sanity check for the adapter hardware - check the reaction of + * the bus lines only if it seems to be idle. + */ +static int test_bus(struct i2c_adapter *i2c_adap) +{ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + const char *name = i2c_adap->name; + int scl, sda, ret; + + if (adap->pre_xfer) { + ret = adap->pre_xfer(i2c_adap); + if (ret < 0) + return -ENODEV; + } + + if (adap->getscl == NULL) + pr_info("%s: Testing SDA only, SCL is not readable\n", name); + + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (!scl || !sda) { + printk(KERN_WARNING + "%s: bus seems to be busy (scl=%d, sda=%d)\n", + name, scl, sda); + goto bailout; + } + + sdalo(adap); + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (sda) { + printk(KERN_WARNING "%s: SDA stuck high!\n", name); + goto bailout; + } + if (!scl) { + printk(KERN_WARNING "%s: SCL unexpected low " + "while pulling SDA low!\n", name); + goto bailout; + } + + sdahi(adap); + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (!sda) { + printk(KERN_WARNING "%s: SDA stuck low!\n", name); + goto bailout; + } + if (!scl) { + printk(KERN_WARNING "%s: SCL unexpected low " + "while pulling SDA high!\n", name); + goto bailout; + } + + scllo(adap); + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 0 : getscl(adap); + if (scl) { + printk(KERN_WARNING "%s: SCL stuck high!\n", name); + goto bailout; + } + if (!sda) { + printk(KERN_WARNING "%s: SDA unexpected low " + "while pulling SCL low!\n", name); + goto bailout; + } + + sclhi(adap); + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (!scl) { + printk(KERN_WARNING "%s: SCL stuck low!\n", name); + goto bailout; + } + if (!sda) { + printk(KERN_WARNING "%s: SDA unexpected low " + "while pulling SCL high!\n", name); + goto bailout; + } + + if (adap->post_xfer) + adap->post_xfer(i2c_adap); + + pr_info("%s: Test OK\n", name); + return 0; +bailout: + sdahi(adap); + sclhi(adap); + + if (adap->post_xfer) + adap->post_xfer(i2c_adap); + + return -ENODEV; +} + +/* ----- Utility functions + */ + +/* try_address tries to contact a chip for a number of + * times before it gives up. + * return values: + * 1 chip answered + * 0 chip did not answer + * -x transmission error + */ +static int try_address(struct i2c_adapter *i2c_adap, + unsigned char addr, int retries) +{ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + int i, ret = 0; + + for (i = 0; i <= retries; i++) { + ret = i2c_outb(i2c_adap, addr); + if (ret == 1 || i == retries) + break; + bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); + i2c_stop(adap); + udelay(adap->udelay); + yield(); + bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); + i2c_start(adap); + } + if (i && ret) + bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at " + "0x%02x: %s\n", i + 1, + addr & 1 ? "read from" : "write to", addr >> 1, + ret == 1 ? "success" : "failed, timeout?"); + return ret; +} + +static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) +{ + const unsigned char *temp = msg->buf; + int count = msg->len; + unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; + int retval; + int wrcount = 0; + + while (count > 0) { + retval = i2c_outb(i2c_adap, *temp); + + /* OK/ACK; or ignored NAK */ + if ((retval > 0) || (nak_ok && (retval == 0))) { + count--; + temp++; + wrcount++; + + /* A slave NAKing the master means the slave didn't like + * something about the data it saw. For example, maybe + * the SMBus PEC was wrong. + */ + } else if (retval == 0) { + dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n"); + return -EIO; + + /* Timeout; or (someday) lost arbitration + * + * FIXME Lost ARB implies retrying the transaction from + * the first message, after the "winning" master issues + * its STOP. As a rule, upper layer code has no reason + * to know or care about this ... it is *NOT* an error. + */ + } else { + dev_err(&i2c_adap->dev, "sendbytes: error %d\n", + retval); + return retval; + } + } + return wrcount; +} + +static int acknak(struct i2c_adapter *i2c_adap, int is_ack) +{ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + /* assert: sda is high */ + if (is_ack) /* send ack */ + setsda(adap, 0); + udelay((adap->udelay + 1) / 2); + if (sclhi(adap) < 0) { /* timeout */ + dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n"); + return -ETIMEDOUT; + } + scllo(adap); + return 0; +} + +static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) +{ + int inval; + int rdcount = 0; /* counts bytes read */ + unsigned char *temp = msg->buf; + int count = msg->len; + const unsigned flags = msg->flags; + + while (count > 0) { + inval = i2c_inb(i2c_adap); + if (inval >= 0) { + *temp = inval; + rdcount++; + } else { /* read timed out */ + break; + } + + temp++; + count--; + + /* Some SMBus transactions require that we receive the + transaction length as the first read byte. */ + if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) { + if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) { + if (!(flags & I2C_M_NO_RD_ACK)) + acknak(i2c_adap, 0); + dev_err(&i2c_adap->dev, "readbytes: invalid " + "block length (%d)\n", inval); + return -EPROTO; + } + /* The original count value accounts for the extra + bytes, that is, either 1 for a regular transaction, + or 2 for a PEC transaction. */ + count += inval; + msg->len += inval; + } + + bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n", + inval, + (flags & I2C_M_NO_RD_ACK) + ? "(no ack/nak)" + : (count ? "A" : "NA")); + + if (!(flags & I2C_M_NO_RD_ACK)) { + inval = acknak(i2c_adap, count); + if (inval < 0) + return inval; + } + } + return rdcount; +} + +/* doAddress initiates the transfer by generating the start condition (in + * try_address) and transmits the address in the necessary format to handle + * reads, writes as well as 10bit-addresses. + * returns: + * 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set + * -x an error occurred (like: -ENXIO if the device did not answer, or + * -ETIMEDOUT, for example if the lines are stuck...) + */ +static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) +{ + unsigned short flags = msg->flags; + unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + unsigned char addr; + int ret, retries; + + retries = nak_ok ? 0 : i2c_adap->retries; + + if (flags & I2C_M_TEN) { + /* a ten bit address */ + addr = 0xf0 | ((msg->addr >> 7) & 0x06); + bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr); + /* try extended address code...*/ + ret = try_address(i2c_adap, addr, retries); + if ((ret != 1) && !nak_ok) { + dev_err(&i2c_adap->dev, + "died at extended address code\n"); + return -ENXIO; + } + /* the remaining 8 bit address */ + ret = i2c_outb(i2c_adap, msg->addr & 0xff); + if ((ret != 1) && !nak_ok) { + /* the chip did not ack / xmission error occurred */ + dev_err(&i2c_adap->dev, "died at 2nd address code\n"); + return -ENXIO; + } + if (flags & I2C_M_RD) { + bit_dbg(3, &i2c_adap->dev, "emitting repeated " + "start condition\n"); + i2c_repstart(adap); + /* okay, now switch into reading mode */ + addr |= 0x01; + ret = try_address(i2c_adap, addr, retries); + if ((ret != 1) && !nak_ok) { + dev_err(&i2c_adap->dev, + "died at repeated address code\n"); + return -EIO; + } + } + } else { /* normal 7bit address */ + addr = msg->addr << 1; + if (flags & I2C_M_RD) + addr |= 1; + if (flags & I2C_M_REV_DIR_ADDR) + addr ^= 1; + ret = try_address(i2c_adap, addr, retries); + if ((ret != 1) && !nak_ok) + return -ENXIO; + } + + return 0; +} + +static void bit_i2c_unblock(struct i2c_adapter *i2c_adap) +{ + int i; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + for (i = 0; i < 9; i++) { + setscl(adap, 0); + udelay(5); + setscl(adap, 1); + udelay(5); + } + setscl(adap, 0); + setsda(adap, 0); + udelay(5); + setscl(adap, 1); + udelay(5); + setsda(adap, 1); +} + +static int check_bit_i2c_unblock(struct i2c_adapter *i2c_adap) +{ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + int sda, scl; + + sda = getsda(adap); + scl = getscl(adap); + if ((sda == 0) && scl) { + I2C_ALGO_BIT_ERROR("SCL is high and SDA is low, send 9 clock to device.\n"); + bit_i2c_unblock(i2c_adap); + } + + sda = getsda(adap); + scl = getscl(adap); + if (sda && scl) { + I2C_ALGO_BIT_DEBUG("SCL and SDA are both high, i2c level check ok.\n"); + return 0; + } + dev_warn(&i2c_adap->dev, "Check i2c level failed, SCL %s, SDA %s.\n", scl ? "high" : "low", sda ? "high" : "low"); + return -EIO; +} + +static int bit_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], int num) +{ + struct i2c_msg *pmsg; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + int i, ret; + unsigned short nak_ok; + + if (adap->pre_xfer) { + ret = adap->pre_xfer(i2c_adap); + if (ret < 0) + return ret; + } + + if (check_bit_i2c_unblock(i2c_adap) < 0) { + I2C_ALGO_BIT_ERROR("check i2c is block.\n"); + return -EIO; + } + + bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); + i2c_start(adap); + for (i = 0; i < num; i++) { + pmsg = &msgs[i]; + nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; + if (!(pmsg->flags & I2C_M_NOSTART)) { + if (i) { + bit_dbg(3, &i2c_adap->dev, "emitting " + "repeated start condition\n"); + i2c_repstart(adap); + } + ret = bit_doAddress(i2c_adap, pmsg); + if ((ret != 0) && !nak_ok) { + bit_dbg(1, &i2c_adap->dev, "NAK from " + "device addr 0x%02x msg #%d\n", + msgs[i].addr, i); + goto bailout; + } + } + if (pmsg->flags & I2C_M_RD) { + /* read bytes into buffer*/ + ret = readbytes(i2c_adap, pmsg); + if (ret >= 1) + bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n", + ret, ret == 1 ? "" : "s"); + if (ret < pmsg->len) { + if (ret >= 0) + ret = -EIO; + goto bailout; + } + } else { + /* write bytes from buffer */ + ret = sendbytes(i2c_adap, pmsg); + if (ret >= 1) + bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n", + ret, ret == 1 ? "" : "s"); + if (ret < pmsg->len) { + if (ret >= 0) + ret = -EIO; + goto bailout; + } + } + } + ret = i; + +bailout: + bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); + i2c_stop(adap); + + if (adap->post_xfer) + adap->post_xfer(i2c_adap); + return ret; +} + +static u32 bit_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_SMBUS_READ_BLOCK_DATA | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL | + I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; +} + +/* -----exported algorithm data: ------------------------------------- */ + +const struct i2c_algorithm wb_i2c_bit_algo = { + .master_xfer = bit_xfer, + .functionality = bit_func, +}; +EXPORT_SYMBOL(wb_i2c_bit_algo); + +static const struct i2c_adapter_quirks i2c_bit_quirk_no_clk_stretch = { + .flags = I2C_AQ_NO_CLK_STRETCH, +}; + +/* + * registering functions to load algorithms at runtime + */ +static int __i2c_bit_add_bus(struct i2c_adapter *adap, + int (*add_adapter)(struct i2c_adapter *)) +{ + struct i2c_algo_bit_data *bit_adap = adap->algo_data; + int ret; + + if (bit_test) { + ret = test_bus(adap); + if (bit_test >= 2 && ret < 0) + return -ENODEV; + } + + /* register new adapter to i2c module... */ + adap->algo = &wb_i2c_bit_algo; + adap->retries = 3; + if (bit_adap->getscl == NULL) + adap->quirks = &i2c_bit_quirk_no_clk_stretch; + + ret = add_adapter(adap); + if (ret < 0) + return ret; + + /* Complain if SCL can't be read */ + if (bit_adap->getscl == NULL) { + dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n"); + dev_warn(&adap->dev, "Bus may be unreliable\n"); + } + return 0; +} + +int wb_i2c_bit_add_bus(struct i2c_adapter *adap) +{ + return __i2c_bit_add_bus(adap, i2c_add_adapter); +} +EXPORT_SYMBOL(wb_i2c_bit_add_bus); + +int wb_i2c_bit_add_numbered_bus(struct i2c_adapter *adap) +{ + return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter); +} +EXPORT_SYMBOL(wb_i2c_bit_add_numbered_bus); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio.c new file mode 100644 index 000000000000..0362e905fddb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio.c @@ -0,0 +1,431 @@ +/* + * Bitbanging I2C bus driver using the GPIO API + * + * Copyright (C) 2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int wb_i2c_bit_add_numbered_bus(struct i2c_adapter *adap); + +struct i2c_gpio_private_data { + struct gpio_desc *sda; + struct gpio_desc *scl; + struct i2c_adapter adap; + struct i2c_algo_bit_data bit_data; + struct i2c_gpio_platform_data pdata; +#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR + struct dentry *debug_dir; +#endif +}; + +/* + * Toggle SDA by changing the output value of the pin. This is only + * valid for pins configured as open drain (i.e. setting the value + * high effectively turns off the output driver.) + */ +static void i2c_gpio_setsda_val(void *data, int state) +{ + struct i2c_gpio_private_data *priv = data; + + gpiod_set_value_cansleep(priv->sda, state); +} + +/* + * Toggle SCL by changing the output value of the pin. This is used + * for pins that are configured as open drain and for output-only + * pins. The latter case will break the i2c protocol, but it will + * often work in practice. + */ +static void i2c_gpio_setscl_val(void *data, int state) +{ + struct i2c_gpio_private_data *priv = data; + + gpiod_set_value_cansleep(priv->scl, state); +} + +static int i2c_gpio_getsda(void *data) +{ + struct i2c_gpio_private_data *priv = data; + + return gpiod_get_value_cansleep(priv->sda); +} + +static int i2c_gpio_getscl(void *data) +{ + struct i2c_gpio_private_data *priv = data; + + return gpiod_get_value_cansleep(priv->scl); +} + +#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR +static struct dentry *i2c_gpio_debug_dir; + +#define setsda(bd, val) ((bd)->setsda((bd)->data, val)) +#define setscl(bd, val) ((bd)->setscl((bd)->data, val)) +#define getsda(bd) ((bd)->getsda((bd)->data)) +#define getscl(bd) ((bd)->getscl((bd)->data)) + +#define WIRE_ATTRIBUTE(wire) \ +static int fops_##wire##_get(void *data, u64 *val) \ +{ \ + struct i2c_gpio_private_data *priv = data; \ + \ + i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + *val = get##wire(&priv->bit_data); \ + i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + return 0; \ +} \ +static int fops_##wire##_set(void *data, u64 val) \ +{ \ + struct i2c_gpio_private_data *priv = data; \ + \ + i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + set##wire(&priv->bit_data, val); \ + i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + return 0; \ +} \ +DEFINE_DEBUGFS_ATTRIBUTE(fops_##wire, fops_##wire##_get, fops_##wire##_set, "%llu\n") + +WIRE_ATTRIBUTE(scl); +WIRE_ATTRIBUTE(sda); + +static void i2c_gpio_incomplete_transfer(struct i2c_gpio_private_data *priv, + u32 pattern, u8 pattern_size) +{ + struct i2c_algo_bit_data *bit_data = &priv->bit_data; + int i; + + i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); + + /* START condition */ + setsda(bit_data, 0); + udelay(bit_data->udelay); + + /* Send pattern, request ACK, don't send STOP */ + for (i = pattern_size - 1; i >= 0; i--) { + setscl(bit_data, 0); + udelay(bit_data->udelay / 2); + setsda(bit_data, (pattern >> i) & 1); + udelay((bit_data->udelay + 1) / 2); + setscl(bit_data, 1); + udelay(bit_data->udelay); + } + + i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); +} + +static int fops_incomplete_addr_phase_set(void *data, u64 addr) +{ + struct i2c_gpio_private_data *priv = data; + u32 pattern; + + if (addr > 0x7f) + return -EINVAL; + + /* ADDR (7 bit) + RD (1 bit) + Client ACK, keep SDA hi (1 bit) */ + pattern = (addr << 2) | 3; + + i2c_gpio_incomplete_transfer(priv, pattern, 9); + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_addr_phase, NULL, fops_incomplete_addr_phase_set, "%llu\n"); + +static int fops_incomplete_write_byte_set(void *data, u64 addr) +{ + struct i2c_gpio_private_data *priv = data; + u32 pattern; + + if (addr > 0x7f) + return -EINVAL; + + /* ADDR (7 bit) + WR (1 bit) + Client ACK (1 bit) */ + pattern = (addr << 2) | 1; + /* 0x00 (8 bit) + Client ACK, keep SDA hi (1 bit) */ + pattern = (pattern << 9) | 1; + + i2c_gpio_incomplete_transfer(priv, pattern, 18); + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write_byte_set, "%llu\n"); + +static void i2c_gpio_fault_injector_init(struct platform_device *pdev) +{ + struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); + + /* + * If there will be a debugfs-dir per i2c adapter somewhen, put the + * 'fault-injector' dir there. Until then, we have a global dir with + * all adapters as subdirs. + */ + if (!i2c_gpio_debug_dir) { + i2c_gpio_debug_dir = debugfs_create_dir("i2c-fault-injector", NULL); + if (!i2c_gpio_debug_dir) + return; + } + + priv->debug_dir = debugfs_create_dir(pdev->name, i2c_gpio_debug_dir); + if (!priv->debug_dir) + return; + + debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl); + debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda); + debugfs_create_file_unsafe("incomplete_address_phase", 0200, priv->debug_dir, + priv, &fops_incomplete_addr_phase); + debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->debug_dir, + priv, &fops_incomplete_write_byte); +} + +static void i2c_gpio_fault_injector_exit(struct platform_device *pdev) +{ + struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); + + debugfs_remove_recursive(priv->debug_dir); +} +#else +static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {} +static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {} +#endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/ + +static void of_i2c_gpio_get_props(struct device_node *np, + struct i2c_gpio_platform_data *pdata) +{ + u32 reg; + + of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay); + + if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", ®)) + pdata->timeout = msecs_to_jiffies(reg); + + pdata->sda_is_open_drain = + of_property_read_bool(np, "i2c-gpio,sda-open-drain"); + pdata->scl_is_open_drain = + of_property_read_bool(np, "i2c-gpio,scl-open-drain"); + pdata->scl_is_output_only = + of_property_read_bool(np, "i2c-gpio,scl-output-only"); +} + +static struct gpio_desc *i2c_gpio_get_desc(struct device *dev, + const char *con_id, + unsigned int index, + enum gpiod_flags gflags) +{ + struct gpio_desc *retdesc; + int ret; + + retdesc = devm_gpiod_get(dev, con_id, gflags); + if (!IS_ERR(retdesc)) { + dev_dbg(dev, "got GPIO from name %s\n", con_id); + return retdesc; + } + + retdesc = devm_gpiod_get_index(dev, NULL, index, gflags); + if (!IS_ERR(retdesc)) { + dev_dbg(dev, "got GPIO from index %u\n", index); + return retdesc; + } + + ret = PTR_ERR(retdesc); + + /* FIXME: hack in the old code, is this really necessary? */ + if (ret == -EINVAL) + retdesc = ERR_PTR(-EPROBE_DEFER); + + /* This happens if the GPIO driver is not yet probed, let's defer */ + if (ret == -ENOENT) + retdesc = ERR_PTR(-EPROBE_DEFER); + + if (PTR_ERR(retdesc) != -EPROBE_DEFER) + dev_err(dev, "error trying to get descriptor: %d\n", ret); + + return retdesc; +} + +static int i2c_gpio_probe(struct platform_device *pdev) +{ + struct i2c_gpio_private_data *priv; + struct i2c_gpio_platform_data *pdata; + struct i2c_algo_bit_data *bit_data; + struct i2c_adapter *adap; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + enum gpiod_flags gflags; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + adap = &priv->adap; + bit_data = &priv->bit_data; + pdata = &priv->pdata; + + if (np) { + of_i2c_gpio_get_props(np, pdata); + } else { + /* + * If all platform data settings are zero it is OK + * to not provide any platform data from the board. + */ + if (dev_get_platdata(dev)) + memcpy(pdata, dev_get_platdata(dev), sizeof(*pdata)); + } + + /* + * First get the GPIO pins; if it fails, we'll defer the probe. + * If the SDA line is marked from platform data or device tree as + * "open drain" it means something outside of our control is making + * this line being handled as open drain, and we should just handle + * it as any other output. Else we enforce open drain as this is + * required for an I2C bus. + */ + if (pdata->sda_is_open_drain) + gflags = GPIOD_OUT_HIGH; + else + gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; + priv->sda = i2c_gpio_get_desc(dev, "sda", 0, gflags); + if (IS_ERR(priv->sda)) + return PTR_ERR(priv->sda); + + /* + * If the SCL line is marked from platform data or device tree as + * "open drain" it means something outside of our control is making + * this line being handled as open drain, and we should just handle + * it as any other output. Else we enforce open drain as this is + * required for an I2C bus. + */ + if (pdata->scl_is_open_drain) + gflags = GPIOD_OUT_HIGH; + else + gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; + priv->scl = i2c_gpio_get_desc(dev, "scl", 1, gflags); + if (IS_ERR(priv->scl)) + return PTR_ERR(priv->scl); + + if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl)) + dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing"); + + bit_data->setsda = i2c_gpio_setsda_val; + bit_data->setscl = i2c_gpio_setscl_val; + + if (!pdata->scl_is_output_only) + bit_data->getscl = i2c_gpio_getscl; + bit_data->getsda = i2c_gpio_getsda; + + if (pdata->udelay) + bit_data->udelay = pdata->udelay; + else if (pdata->scl_is_output_only) + bit_data->udelay = 50; /* 10 kHz */ + else + bit_data->udelay = 5; /* 100 kHz */ + + if (pdata->timeout) + bit_data->timeout = pdata->timeout; + else + bit_data->timeout = HZ / 10; /* 100 ms */ + + bit_data->data = priv; + + adap->owner = THIS_MODULE; + if (np) + strlcpy(adap->name, dev_name(dev), sizeof(adap->name)); + else + snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); + + adap->algo_data = bit_data; + adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + adap->dev.parent = dev; + adap->dev.of_node = np; + + adap->nr = pdev->id; + ret = wb_i2c_bit_add_numbered_bus(adap); + if (ret) + return ret; + + platform_set_drvdata(pdev, priv); + + /* + * FIXME: using global GPIO numbers is not helpful. If/when we + * get accessors to get the actual name of the GPIO line, + * from the descriptor, then provide that instead. + */ + dev_info(dev, "using lines %u (SDA) and %u (SCL%s)\n", + desc_to_gpio(priv->sda), desc_to_gpio(priv->scl), + pdata->scl_is_output_only + ? ", no clock stretching" : ""); + + i2c_gpio_fault_injector_init(pdev); + + return 0; +} + +static int i2c_gpio_remove(struct platform_device *pdev) +{ + struct i2c_gpio_private_data *priv; + struct i2c_adapter *adap; + + i2c_gpio_fault_injector_exit(pdev); + + priv = platform_get_drvdata(pdev); + adap = &priv->adap; + + i2c_del_adapter(adap); + + return 0; +} + +#if defined(CONFIG_OF) +static const struct of_device_id i2c_gpio_dt_ids[] = { + { .compatible = "wb-i2c-gpio", }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids); +#endif + +static struct platform_driver i2c_gpio_driver = { + .driver = { + .name = "wb-i2c-gpio", + .of_match_table = of_match_ptr(i2c_gpio_dt_ids), + }, + .probe = i2c_gpio_probe, + .remove = i2c_gpio_remove, +}; + +static int __init i2c_gpio_init(void) +{ + int ret; + + ret = platform_driver_register(&i2c_gpio_driver); + if (ret) + printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret); + + return ret; +} +subsys_initcall(i2c_gpio_init); + +static void __exit i2c_gpio_exit(void) +{ + platform_driver_unregister(&i2c_gpio_driver); +} +module_exit(i2c_gpio_exit); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:i2c-gpio"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio_device.c new file mode 100644 index 000000000000..1e1d815eedf1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio_device.c @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define I2C_GPIO_DEV_NAME_LEN (16) +static char i2c_gpio_dev_name[I2C_GPIO_DEV_NAME_LEN] = {0}; + +static int gpio_sda = 17; +module_param(gpio_sda, int, S_IRUGO | S_IWUSR); + +static int gpio_scl = 1; +module_param(gpio_scl, int, S_IRUGO | S_IWUSR); + +static int gpio_udelay = 2; +module_param(gpio_udelay, int, S_IRUGO | S_IWUSR); + +static int bus_num = -1; +module_param(bus_num, int, S_IRUGO | S_IWUSR); + +static char *gpio_chip_name = NULL; +module_param(gpio_chip_name, charp, 0644); +MODULE_PARM_DESC(str_var, "A string variable for GPIO controller"); + +static int g_wb_i2c_gpio_device_debug = 0; +static int g_wb_i2c_gpio_device_error = 0; + +module_param(g_wb_i2c_gpio_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_i2c_gpio_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_I2C_GPIO_DEVICE_VERBOSE(fmt, args...) do { \ + if (g_wb_i2c_gpio_device_debug) { \ + printk(KERN_INFO "[WB_I2C_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_I2C_GPIO_DEVICE_ERROR(fmt, args...) do { \ + if (g_wb_i2c_gpio_device_error) { \ + printk(KERN_ERR "[WB_I2C_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +/****************** i2c adapter with gpio ***********************/ +static struct i2c_gpio_platform_data i2c_pdata = { + .udelay = 2, + .scl_is_output_only = 0, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, +}; + +static void i2c_gpio_release(struct device *dev) +{ + return; +} + +static struct platform_device wb_i2c_gpio_device = { + .name = "wb-i2c-gpio", + .id = -1, + .num_resources = 0, + .resource = NULL, + .dev = { + .platform_data = &i2c_pdata, + .release = i2c_gpio_release, + }, +}; + +/* + * i2c + */ +static struct gpiod_lookup_table wb_i2c_gpio_table = { + .dev_id = "wb-i2c-gpio", + .table = { + GPIO_LOOKUP("wb_gpio_d1500", 17, "sda", + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP("wb_gpio_d1500", 1, "scl", + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + { }, + }, +}; + +static int __init wb_i2c_gpio_device_init(void) +{ + int err; + + WB_I2C_GPIO_DEVICE_VERBOSE("wb_i2c_gpio_device_init enter!\n"); + wb_i2c_gpio_table.table[0].chip_hwnum = gpio_sda; + wb_i2c_gpio_table.table[1].chip_hwnum = gpio_scl; + i2c_pdata.udelay = gpio_udelay; + + if (gpio_chip_name) { + wb_i2c_gpio_table.table[0].key = gpio_chip_name; + wb_i2c_gpio_table.table[1].key = gpio_chip_name; + } + + if (bus_num >= 0) { + wb_i2c_gpio_device.id = bus_num; + snprintf(i2c_gpio_dev_name, I2C_GPIO_DEV_NAME_LEN, "wb-i2c-gpio.%d", bus_num); + wb_i2c_gpio_table.dev_id = i2c_gpio_dev_name; + } + + gpiod_add_lookup_table(&wb_i2c_gpio_table); + + err = platform_device_register(&wb_i2c_gpio_device); + if (err < 0) { + printk(KERN_ERR "register i2c gpio device fail(%d). \n", err); + gpiod_remove_lookup_table(&wb_i2c_gpio_table); + return -1; + } + return 0; +} + +static void __exit wb_i2c_gpio_device_exit(void) +{ + WB_I2C_GPIO_DEVICE_VERBOSE("wb_i2c_gpio_device_exit enter!\n"); + platform_device_unregister(&wb_i2c_gpio_device); + gpiod_remove_lookup_table(&wb_i2c_gpio_table); +} + +module_init(wb_i2c_gpio_device_init); +module_exit(wb_i2c_gpio_device_exit); +MODULE_DESCRIPTION("I2C GPIO Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_i801.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_i801.c new file mode 100644 index 000000000000..a733c115487e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_i801.c @@ -0,0 +1,2114 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + Copyright (c) 1998 - 2002 Frodo Looijaard , + Philip Edelbrock , and Mark D. Studebaker + + Copyright (C) 2007 - 2014 Jean Delvare + Copyright (C) 2010 Intel Corporation, + David Woodhouse + +*/ + +/* + * Supports the following Intel I/O Controller Hubs (ICH): + * + * I/O Block I2C + * region SMBus Block proc. block + * Chip name PCI ID size PEC buffer call read + * --------------------------------------------------------------------------- + * 82801AA (ICH) 0x2413 16 no no no no + * 82801AB (ICH0) 0x2423 16 no no no no + * 82801BA (ICH2) 0x2443 16 no no no no + * 82801CA (ICH3) 0x2483 32 soft no no no + * 82801DB (ICH4) 0x24c3 32 hard yes no no + * 82801E (ICH5) 0x24d3 32 hard yes yes yes + * 6300ESB 0x25a4 32 hard yes yes yes + * 82801F (ICH6) 0x266a 32 hard yes yes yes + * 6310ESB/6320ESB 0x269b 32 hard yes yes yes + * 82801G (ICH7) 0x27da 32 hard yes yes yes + * 82801H (ICH8) 0x283e 32 hard yes yes yes + * 82801I (ICH9) 0x2930 32 hard yes yes yes + * EP80579 (Tolapai) 0x5032 32 hard yes yes yes + * ICH10 0x3a30 32 hard yes yes yes + * ICH10 0x3a60 32 hard yes yes yes + * 5/3400 Series (PCH) 0x3b30 32 hard yes yes yes + * 6 Series (PCH) 0x1c22 32 hard yes yes yes + * Patsburg (PCH) 0x1d22 32 hard yes yes yes + * Patsburg (PCH) IDF 0x1d70 32 hard yes yes yes + * Patsburg (PCH) IDF 0x1d71 32 hard yes yes yes + * Patsburg (PCH) IDF 0x1d72 32 hard yes yes yes + * DH89xxCC (PCH) 0x2330 32 hard yes yes yes + * Panther Point (PCH) 0x1e22 32 hard yes yes yes + * Lynx Point (PCH) 0x8c22 32 hard yes yes yes + * Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes + * Avoton (SOC) 0x1f3c 32 hard yes yes yes + * Wellsburg (PCH) 0x8d22 32 hard yes yes yes + * Wellsburg (PCH) MS 0x8d7d 32 hard yes yes yes + * Wellsburg (PCH) MS 0x8d7e 32 hard yes yes yes + * Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes + * Coleto Creek (PCH) 0x23b0 32 hard yes yes yes + * Wildcat Point (PCH) 0x8ca2 32 hard yes yes yes + * Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes + * BayTrail (SOC) 0x0f12 32 hard yes yes yes + * Braswell (SOC) 0x2292 32 hard yes yes yes + * Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes + * Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes + * DNV (SOC) 0x19df 32 hard yes yes yes + * Emmitsburg (PCH) 0x1bc9 32 hard yes yes yes + * Broxton (SOC) 0x5ad4 32 hard yes yes yes + * Lewisburg (PCH) 0xa1a3 32 hard yes yes yes + * Lewisburg Supersku (PCH) 0xa223 32 hard yes yes yes + * Kaby Lake PCH-H (PCH) 0xa2a3 32 hard yes yes yes + * Gemini Lake (SOC) 0x31d4 32 hard yes yes yes + * Cannon Lake-H (PCH) 0xa323 32 hard yes yes yes + * Cannon Lake-LP (PCH) 0x9da3 32 hard yes yes yes + * Cedar Fork (PCH) 0x18df 32 hard yes yes yes + * Ice Lake-LP (PCH) 0x34a3 32 hard yes yes yes + * Comet Lake (PCH) 0x02a3 32 hard yes yes yes + * Comet Lake-H (PCH) 0x06a3 32 hard yes yes yes + * Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes + * Tiger Lake-LP (PCH) 0xa0a3 32 hard yes yes yes + * Tiger Lake-H (PCH) 0x43a3 32 hard yes yes yes + * Jasper Lake (SOC) 0x4da3 32 hard yes yes yes + * Comet Lake-V (PCH) 0xa3a3 32 hard yes yes yes + * Alder Lake-S (PCH) 0x7aa3 32 hard yes yes yes + * + * Features supported by this driver: + * Software PEC no + * Hardware PEC yes + * Block buffer yes + * Block process call transaction yes + * I2C block read transaction yes (doesn't use the block buffer) + * Slave mode no + * SMBus Host Notify yes + * Interrupt processing yes + * + * See the file Documentation/i2c/busses/i2c-i801.rst for details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI +#include +#include +#endif + +#define mem_clear(data, size) memset((data), 0, (size)) + +/* I801 SMBus address offsets */ +#define SMBHSTSTS(p) (0 + (p)->smba) +#define SMBHSTCNT(p) (2 + (p)->smba) +#define SMBHSTCMD(p) (3 + (p)->smba) +#define SMBHSTADD(p) (4 + (p)->smba) +#define SMBHSTDAT0(p) (5 + (p)->smba) +#define SMBHSTDAT1(p) (6 + (p)->smba) +#define SMBBLKDAT(p) (7 + (p)->smba) +#define SMBPEC(p) (8 + (p)->smba) /* ICH3 and later */ +#define SMBAUXSTS(p) (12 + (p)->smba) /* ICH4 and later */ +#define SMBAUXCTL(p) (13 + (p)->smba) /* ICH4 and later */ +#define SMBSLVSTS(p) (16 + (p)->smba) /* ICH3 and later */ +#define SMBSLVCMD(p) (17 + (p)->smba) /* ICH3 and later */ +#define SMBNTFDADD(p) (20 + (p)->smba) /* ICH3 and later */ +#define SMBPINCTL(p) (15 + (p)->smba) /* SMBus Pin Control Register */ + +/* PCI Address Constants */ +#define SMBBAR 4 +#define SMBPCICTL 0x004 +#define SMBPCISTS 0x006 +#define SMBHSTCFG 0x040 +#define TCOBASE 0x050 +#define TCOCTL 0x054 + +#define SBREG_BAR 0x10 +#define SBREG_SMBCTRL 0xc6000c +#define SBREG_SMBCTRL_DNV 0xcf000c + +/* Host status bits for SMBPCISTS */ +#define SMBPCISTS_INTS BIT(3) + +/* Control bits for SMBPCICTL */ +#define SMBPCICTL_INTDIS BIT(10) + +/* Host configuration bits for SMBHSTCFG */ +#define SMBHSTCFG_HST_EN BIT(0) +#define SMBHSTCFG_SMB_SMI_EN BIT(1) +#define SMBHSTCFG_I2C_EN BIT(2) +#define SMBHSTCFG_SSRESET BIT(3) +#define SSRESET_SLEEP_TIME 1 /* 1us */ +#define SSRESET_RETRY_TIME (1000 / SSRESET_SLEEP_TIME) + +/* Pin status for SMBPINCTL */ +#define SMBPINCTL_CLK_STS 1 /* bit0 SMBCLK_CUR_STS*/ +#define SMBPINCTL_SDA_STS 2 /* bit1 SMBDATA_CUR_STS*/ +#define SMBPINCTL_CLK_CTL 4 /* bit2 SMBCLK_CTL */ + +#define SMBHSTCFG_SPD_WD BIT(4) + +/* TCO configuration bits for TCOCTL */ +#define TCOCTL_EN BIT(8) + +/* Auxiliary status register bits, ICH4+ only */ +#define SMBAUXSTS_CRCE BIT(0) +#define SMBAUXSTS_STCO BIT(1) + +/* Auxiliary control register bits, ICH4+ only */ +#define SMBAUXCTL_CRC BIT(0) +#define SMBAUXCTL_E32B BIT(1) + +/* Other settings */ +#define MAX_RETRIES 400 + +/* I801 command constants */ +#define I801_QUICK 0x00 +#define I801_BYTE 0x04 +#define I801_BYTE_DATA 0x08 +#define I801_WORD_DATA 0x0C +#define I801_PROC_CALL 0x10 /* unimplemented */ +#define I801_BLOCK_DATA 0x14 +#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ +#define I801_BLOCK_PROC_CALL 0x1C + +/* I801 Host Control register bits */ +#define SMBHSTCNT_INTREN BIT(0) +#define SMBHSTCNT_KILL BIT(1) +#define SMBHSTCNT_LAST_BYTE BIT(5) +#define SMBHSTCNT_START BIT(6) +#define SMBHSTCNT_PEC_EN BIT(7) /* ICH3 and later */ + +/* I801 Hosts Status register bits */ +#define SMBHSTSTS_BYTE_DONE BIT(7) +#define SMBHSTSTS_INUSE_STS BIT(6) +#define SMBHSTSTS_SMBALERT_STS BIT(5) +#define SMBHSTSTS_FAILED BIT(4) +#define SMBHSTSTS_BUS_ERR BIT(3) +#define SMBHSTSTS_DEV_ERR BIT(2) +#define SMBHSTSTS_INTR BIT(1) +#define SMBHSTSTS_HOST_BUSY BIT(0) + +/* Host Notify Status register bits */ +#define SMBSLVSTS_HST_NTFY_STS BIT(0) + +/* Host Notify Command register bits */ +#define SMBSLVCMD_HST_NTFY_INTREN BIT(0) + +#define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \ + SMBHSTSTS_DEV_ERR) + +#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR | \ + STATUS_ERROR_FLAGS) + +/* Older devices have their ID defined in */ +#define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS 0x02a3 +#define PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS 0x06a3 +#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12 +#define PCI_DEVICE_ID_INTEL_CDF_SMBUS 0x18df +#define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df +#define PCI_DEVICE_ID_INTEL_EBG_SMBUS 0x1bc9 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 +/* Patsburg also has three 'Integrated Device Function' SMBus controllers */ +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70 +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71 +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22 +#define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS 0x1f3c +#define PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS 0x2292 +#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 +#define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0 +#define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4 +#define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS 0x34a3 +#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 +#define PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS 0x43a3 +#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23 +#define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS 0x4da3 +#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4 +#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS 0x7aa3 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 +#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS 0x8ca2 +#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22 +#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0 0x8d7d +#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1 0x8d7e +#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2 0x8d7f +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22 +#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2 +#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23 +#define PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS 0x9da3 +#define PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS 0xa0a3 +#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123 +#define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS 0xa1a3 +#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223 +#define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS 0xa2a3 +#define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323 +#define PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS 0xa3a3 + +struct i801_mux_config { + char *gpio_chip; + unsigned values[3]; + int n_values; + unsigned classes[3]; + unsigned gpios[2]; /* Relative to gpio_chip->base */ + int n_gpios; +}; + +struct i801_priv { + struct i2c_adapter adapter; + unsigned long smba; + unsigned char original_hstcfg; + unsigned char original_slvcmd; + struct pci_dev *pci_dev; + unsigned int features; + + /* isr processing */ + wait_queue_head_t waitq; + u8 status; + + /* Command state used by isr for byte-by-byte block transactions */ + u8 cmd; + bool is_read; + int count; + int len; + u8 *data; + +#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI + const struct i801_mux_config *mux_drvdata; + struct platform_device *mux_pdev; + struct gpiod_lookup_table *lookup; +#endif + struct platform_device *tco_pdev; + + /* + * If set to true the host controller registers are reserved for + * ACPI AML use. Protected by acpi_lock. + */ + bool acpi_reserved; + struct mutex acpi_lock; +}; + +#define FEATURE_SMBUS_PEC BIT(0) +#define FEATURE_BLOCK_BUFFER BIT(1) +#define FEATURE_BLOCK_PROC BIT(2) +#define FEATURE_I2C_BLOCK_READ BIT(3) +#define FEATURE_IRQ BIT(4) +#define FEATURE_HOST_NOTIFY BIT(5) +/* Not really a feature, but it's convenient to handle it as such */ +#define FEATURE_IDF BIT(15) +#define FEATURE_TCO_SPT BIT(16) +#define FEATURE_TCO_CNL BIT(17) + +static const char *i801_feature_names[] = { + "SMBus PEC", + "Block buffer", + "Block process call", + "I2C block read", + "Interrupt", + "SMBus Host Notify", +}; + +static unsigned int disable_features; +module_param(disable_features, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n" + "\t\t 0x01 disable SMBus PEC\n" + "\t\t 0x02 disable the block buffer\n" + "\t\t 0x08 disable the I2C block read functionality\n" + "\t\t 0x10 don't use interrupts\n" + "\t\t 0x20 disable SMBus Host Notify "); + +static void i801_setscl(struct i801_priv *priv, unsigned int level) +{ + int pin_status; + pin_status = inb_p(SMBPINCTL(priv)); + if (level == 0) { + pin_status &= (~SMBPINCTL_CLK_CTL); + } + else { + pin_status |= SMBPINCTL_CLK_CTL; + } + outb_p(pin_status, SMBPINCTL(priv)); + return; +} + +static void i801_i2c_unblock(struct i801_priv *priv) +{ + int i; + for (i = 0; i < 10; i++) { + i801_setscl(priv, 0); + udelay(5); + i801_setscl(priv, 1); + udelay(5); + } + return; +} + +static int i801_check_i2c_unblock(struct i801_priv *priv) +{ + int pin_status; + + pin_status = inb_p(SMBPINCTL(priv)); + if ( (!(pin_status & SMBPINCTL_SDA_STS) ) && (pin_status & SMBPINCTL_CLK_STS) ) { + dev_dbg(&priv->pci_dev->dev, "SDA is low, send 9 clock to device!\n"); + i801_i2c_unblock(priv); + } + return 0; +} + +static void i801_do_reset(struct i801_priv *priv) +{ + unsigned char tmp; + unsigned int retry_count = 0; + + pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &tmp); + tmp |= SMBHSTCFG_SSRESET; + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, tmp); + pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &tmp); + + while( ((tmp & SMBHSTCFG_SSRESET) != 0) && (retry_count < SSRESET_RETRY_TIME)) { + usleep_range(SSRESET_SLEEP_TIME, SSRESET_SLEEP_TIME + 1); + retry_count++; + pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &tmp); + } + + return ; +} + +static int i801_check_i2c_scl(struct i801_priv *priv) +{ + int pin_status; + + pin_status = inb_p(SMBPINCTL(priv)); + if ( (pin_status & SMBPINCTL_SDA_STS) && (pin_status & SMBPINCTL_CLK_STS) ) { + return 0; + } + + dev_dbg(&priv->pci_dev->dev, "SDA or SCL is low, begin to reset SMBus adapter, pin_status: 0x%x\n",pin_status); + i801_do_reset(priv); + pin_status = inb_p(SMBPINCTL(priv)); + if ( (pin_status & SMBPINCTL_SDA_STS) && (pin_status & SMBPINCTL_CLK_STS) ) { + return 0; + } + dev_warn(&priv->pci_dev->dev, "SDA or SCL is low.pin_status:0x%x\n",pin_status); + return -1; +} + +/* Make sure the SMBus host is ready to start transmitting. + Return 0 if it is, -EBUSY if it is not. */ +static int i801_check_pre(struct i801_priv *priv) +{ + int status; + + i801_check_i2c_unblock(priv); + + if (i801_check_i2c_scl(priv)) { + return -EIO; + } + + status = inb_p(SMBHSTSTS(priv)); + if (status & SMBHSTSTS_HOST_BUSY) { + dev_dbg(&priv->pci_dev->dev, "SMBus is busy, begin to reset SMBus adapter!\n"); + + i801_do_reset(priv); + + status = inb_p(SMBHSTSTS(priv)); + if (status & SMBHSTSTS_HOST_BUSY) { + dev_err(&priv->pci_dev->dev, "SMBus is busy, can't use it!\n"); + return -EBUSY; + } + } + + status &= STATUS_FLAGS; + if (status) { + dev_dbg(&priv->pci_dev->dev, "Clearing status flags (%02x)\n", + status); + outb_p(status, SMBHSTSTS(priv)); + status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS; + if (status) { + dev_err(&priv->pci_dev->dev, + "Failed clearing status flags (%02x)\n", + status); + return -EBUSY; + } + } + + /* + * Clear CRC status if needed. + * During normal operation, i801_check_post() takes care + * of it after every operation. We do it here only in case + * the hardware was already in this state when the driver + * started. + */ + if (priv->features & FEATURE_SMBUS_PEC) { + status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; + if (status) { + dev_dbg(&priv->pci_dev->dev, + "Clearing aux status flags (%02x)\n", status); + outb_p(status, SMBAUXSTS(priv)); + status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; + if (status) { + dev_err(&priv->pci_dev->dev, + "Failed clearing aux status flags (%02x)\n", + status); + return -EBUSY; + } + } + } + + return 0; +} + +/* + * Convert the status register to an error code, and clear it. + * Note that status only contains the bits we want to clear, not the + * actual register value. + */ +static int i801_check_post(struct i801_priv *priv, int status) +{ + int result = 0; + + /* + * If the SMBus is still busy, we give up + * Note: This timeout condition only happens when using polling + * transactions. For interrupt operation, NAK/timeout is indicated by + * DEV_ERR. + */ + if (unlikely(status < 0)) { + dev_err(&priv->pci_dev->dev, "Transaction timeout\n"); + /* try to stop the current command */ + dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n"); + outb_p(SMBHSTCNT_KILL, SMBHSTCNT(priv)); + usleep_range(1000, 2000); + outb_p(0, SMBHSTCNT(priv)); + + /* Check if it worked */ + status = inb_p(SMBHSTSTS(priv)); + if ((status & SMBHSTSTS_HOST_BUSY) || + !(status & SMBHSTSTS_FAILED)) + dev_err(&priv->pci_dev->dev, + "Failed terminating the transaction\n"); + outb_p(STATUS_FLAGS, SMBHSTSTS(priv)); + return -ETIMEDOUT; + } + + if (status & SMBHSTSTS_FAILED) { + result = -EIO; + dev_err(&priv->pci_dev->dev, "Transaction failed\n"); + } + if (status & SMBHSTSTS_DEV_ERR) { + /* + * This may be a PEC error, check and clear it. + * + * AUXSTS is handled differently from HSTSTS. + * For HSTSTS, i801_isr() or i801_wait_intr() + * has already cleared the error bits in hardware, + * and we are passed a copy of the original value + * in "status". + * For AUXSTS, the hardware register is left + * for us to handle here. + * This is asymmetric, slightly iffy, but safe, + * since all this code is serialized and the CRCE + * bit is harmless as long as it's cleared before + * the next operation. + */ + if ((priv->features & FEATURE_SMBUS_PEC) && + (inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE)) { + outb_p(SMBAUXSTS_CRCE, SMBAUXSTS(priv)); + result = -EBADMSG; + dev_dbg(&priv->pci_dev->dev, "PEC error\n"); + } else { + result = -ENXIO; + dev_dbg(&priv->pci_dev->dev, "No response\n"); + } + } + if (status & SMBHSTSTS_BUS_ERR) { + result = -EAGAIN; + dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n"); + } + + /* Clear status flags except BYTE_DONE, to be cleared by caller */ + outb_p(status, SMBHSTSTS(priv)); + + return result; +} + +/* Wait for BUSY being cleared and either INTR or an error flag being set */ +static int i801_wait_intr(struct i801_priv *priv) +{ + int timeout = 0; + int status; + + /* We will always wait for a fraction of a second! */ + do { + usleep_range(250, 500); + status = inb_p(SMBHSTSTS(priv)); + } while (((status & SMBHSTSTS_HOST_BUSY) || + !(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR))) && + (timeout++ < MAX_RETRIES)); + + if (timeout > MAX_RETRIES) { + dev_dbg(&priv->pci_dev->dev, "INTR Timeout!\n"); + return -ETIMEDOUT; + } + return status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR); +} + +/* Wait for either BYTE_DONE or an error flag being set */ +static int i801_wait_byte_done(struct i801_priv *priv) +{ + int timeout = 0; + int status; + + /* We will always wait for a fraction of a second! */ + do { + usleep_range(250, 500); + status = inb_p(SMBHSTSTS(priv)); + } while (!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE)) && + (timeout++ < MAX_RETRIES)); + + if (timeout > MAX_RETRIES) { + dev_dbg(&priv->pci_dev->dev, "BYTE_DONE Timeout!\n"); + return -ETIMEDOUT; + } + return status & STATUS_ERROR_FLAGS; +} + +static int i801_transaction(struct i801_priv *priv, int xact) +{ + int status; + int result; + const struct i2c_adapter *adap = &priv->adapter; + + result = i801_check_pre(priv); + if (result < 0) + return result; + + if (priv->features & FEATURE_IRQ) { + outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START, + SMBHSTCNT(priv)); + result = wait_event_timeout(priv->waitq, + (status = priv->status), + adap->timeout); + if (!result) { + status = -ETIMEDOUT; + dev_warn(&priv->pci_dev->dev, + "Timeout waiting for interrupt!\n"); + } + priv->status = 0; + return i801_check_post(priv, status); + } + + /* the current contents of SMBHSTCNT can be overwritten, since PEC, + * SMBSCMD are passed in xact */ + outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv)); + + status = i801_wait_intr(priv); + return i801_check_post(priv, status); +} + +static int i801_block_transaction_by_block(struct i801_priv *priv, + union i2c_smbus_data *data, + char read_write, int command, + int hwpec) +{ + int i, len; + int status; + int xact = hwpec ? SMBHSTCNT_PEC_EN : 0; + + switch (command) { + case I2C_SMBUS_BLOCK_PROC_CALL: + xact |= I801_BLOCK_PROC_CALL; + break; + case I2C_SMBUS_BLOCK_DATA: + xact |= I801_BLOCK_DATA; + break; + default: + return -EOPNOTSUPP; + } + + inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */ + + /* Use 32-byte buffer to process this transaction */ + if (read_write == I2C_SMBUS_WRITE) { + len = data->block[0]; + outb_p(len, SMBHSTDAT0(priv)); + for (i = 0; i < len; i++) + outb_p(data->block[i+1], SMBBLKDAT(priv)); + } + + status = i801_transaction(priv, xact); + if (status) + return status; + + if (read_write == I2C_SMBUS_READ || + command == I2C_SMBUS_BLOCK_PROC_CALL) { + len = inb_p(SMBHSTDAT0(priv)); + if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) + return -EPROTO; + + data->block[0] = len; + for (i = 0; i < len; i++) + data->block[i + 1] = inb_p(SMBBLKDAT(priv)); + } + return 0; +} + +static void i801_isr_byte_done(struct i801_priv *priv) +{ + if (priv->is_read) { + /* For SMBus block reads, length is received with first byte */ + if (((priv->cmd & 0x1c) == I801_BLOCK_DATA) && + (priv->count == 0)) { + priv->len = inb_p(SMBHSTDAT0(priv)); + if (priv->len < 1 || priv->len > I2C_SMBUS_BLOCK_MAX) { + dev_err(&priv->pci_dev->dev, + "Illegal SMBus block read size %d\n", + priv->len); + /* FIXME: Recover */ + priv->len = I2C_SMBUS_BLOCK_MAX; + } else { + dev_dbg(&priv->pci_dev->dev, + "SMBus block read size is %d\n", + priv->len); + } + priv->data[-1] = priv->len; + } + + /* Read next byte */ + if (priv->count < priv->len) + priv->data[priv->count++] = inb(SMBBLKDAT(priv)); + else + dev_dbg(&priv->pci_dev->dev, + "Discarding extra byte on block read\n"); + + /* Set LAST_BYTE for last byte of read transaction */ + if (priv->count == priv->len - 1) + outb_p(priv->cmd | SMBHSTCNT_LAST_BYTE, + SMBHSTCNT(priv)); + } else if (priv->count < priv->len - 1) { + /* Write next byte, except for IRQ after last byte */ + outb_p(priv->data[++priv->count], SMBBLKDAT(priv)); + } + + /* Clear BYTE_DONE to continue with next byte */ + outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); +} + +static irqreturn_t i801_host_notify_isr(struct i801_priv *priv) +{ + unsigned short addr; + + addr = inb_p(SMBNTFDADD(priv)) >> 1; + + /* + * With the tested platforms, reading SMBNTFDDAT (22 + (p)->smba) + * always returns 0. Our current implementation doesn't provide + * data, so we just ignore it. + */ + i2c_handle_smbus_host_notify(&priv->adapter, addr); + + /* clear Host Notify bit and return */ + outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); + return IRQ_HANDLED; +} + +/* + * There are three kinds of interrupts: + * + * 1) i801 signals transaction completion with one of these interrupts: + * INTR - Success + * DEV_ERR - Invalid command, NAK or communication timeout + * BUS_ERR - SMI# transaction collision + * FAILED - transaction was canceled due to a KILL request + * When any of these occur, update ->status and wake up the waitq. + * ->status must be cleared before kicking off the next transaction. + * + * 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt + * occurs for each byte of a byte-by-byte to prepare the next byte. + * + * 3) Host Notify interrupts + */ +static irqreturn_t i801_isr(int irq, void *dev_id) +{ + struct i801_priv *priv = dev_id; + u16 pcists; + u8 status; + + /* Confirm this is our interrupt */ + pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists); + if (!(pcists & SMBPCISTS_INTS)) + return IRQ_NONE; + + if (priv->features & FEATURE_HOST_NOTIFY) { + status = inb_p(SMBSLVSTS(priv)); + if (status & SMBSLVSTS_HST_NTFY_STS) + return i801_host_notify_isr(priv); + } + + status = inb_p(SMBHSTSTS(priv)); + if (status & SMBHSTSTS_BYTE_DONE) + i801_isr_byte_done(priv); + + /* + * Clear irq sources and report transaction result. + * ->status must be cleared before the next transaction is started. + */ + status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS; + if (status) { + outb_p(status, SMBHSTSTS(priv)); + priv->status = status; + wake_up(&priv->waitq); + } + + return IRQ_HANDLED; +} + +/* + * For "byte-by-byte" block transactions: + * I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1 + * I2C read uses cmd=I801_I2C_BLOCK_DATA + */ +static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, + union i2c_smbus_data *data, + char read_write, int command, + int hwpec) +{ + int i, len; + int smbcmd; + int status; + int result; + const struct i2c_adapter *adap = &priv->adapter; + + if (command == I2C_SMBUS_BLOCK_PROC_CALL) + return -EOPNOTSUPP; + + result = i801_check_pre(priv); + if (result < 0) + return result; + + len = data->block[0]; + + if (read_write == I2C_SMBUS_WRITE) { + outb_p(len, SMBHSTDAT0(priv)); + outb_p(data->block[1], SMBBLKDAT(priv)); + } + + if (command == I2C_SMBUS_I2C_BLOCK_DATA && + read_write == I2C_SMBUS_READ) + smbcmd = I801_I2C_BLOCK_DATA; + else + smbcmd = I801_BLOCK_DATA; + + if (priv->features & FEATURE_IRQ) { + priv->is_read = (read_write == I2C_SMBUS_READ); + if (len == 1 && priv->is_read) + smbcmd |= SMBHSTCNT_LAST_BYTE; + priv->cmd = smbcmd | SMBHSTCNT_INTREN; + priv->len = len; + priv->count = 0; + priv->data = &data->block[1]; + + outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv)); + result = wait_event_timeout(priv->waitq, + (status = priv->status), + adap->timeout); + if (!result) { + status = -ETIMEDOUT; + dev_warn(&priv->pci_dev->dev, + "Timeout waiting for interrupt!\n"); + } + priv->status = 0; + return i801_check_post(priv, status); + } + + for (i = 1; i <= len; i++) { + if (i == len && read_write == I2C_SMBUS_READ) + smbcmd |= SMBHSTCNT_LAST_BYTE; + outb_p(smbcmd, SMBHSTCNT(priv)); + + if (i == 1) + outb_p(inb(SMBHSTCNT(priv)) | SMBHSTCNT_START, + SMBHSTCNT(priv)); + + status = i801_wait_byte_done(priv); + if (status) + goto exit; + + if (i == 1 && read_write == I2C_SMBUS_READ + && command != I2C_SMBUS_I2C_BLOCK_DATA) { + len = inb_p(SMBHSTDAT0(priv)); + if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) { + dev_err(&priv->pci_dev->dev, + "Illegal SMBus block read size %d\n", + len); + /* Recover */ + while (inb_p(SMBHSTSTS(priv)) & + SMBHSTSTS_HOST_BUSY) + outb_p(SMBHSTSTS_BYTE_DONE, + SMBHSTSTS(priv)); + outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv)); + return -EPROTO; + } + data->block[0] = len; + } + + /* Retrieve/store value in SMBBLKDAT */ + if (read_write == I2C_SMBUS_READ) + data->block[i] = inb_p(SMBBLKDAT(priv)); + if (read_write == I2C_SMBUS_WRITE && i+1 <= len) + outb_p(data->block[i+1], SMBBLKDAT(priv)); + + /* signals SMBBLKDAT ready */ + outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); + } + + status = i801_wait_intr(priv); +exit: + return i801_check_post(priv, status); +} + +static int i801_set_block_buffer_mode(struct i801_priv *priv) +{ + outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv)); + if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0) + return -EIO; + return 0; +} + +/* Block transaction function */ +static int i801_block_transaction(struct i801_priv *priv, + union i2c_smbus_data *data, char read_write, + int command, int hwpec) +{ + int result = 0; + unsigned char hostc; + + if (command == I2C_SMBUS_I2C_BLOCK_DATA) { + if (read_write == I2C_SMBUS_WRITE) { + /* set I2C_EN bit in configuration register */ + pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc); + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, + hostc | SMBHSTCFG_I2C_EN); + } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) { + dev_err(&priv->pci_dev->dev, + "I2C block read is unsupported!\n"); + return -EOPNOTSUPP; + } + } + + if (read_write == I2C_SMBUS_WRITE + || command == I2C_SMBUS_I2C_BLOCK_DATA) { + if (data->block[0] < 1) + data->block[0] = 1; + if (data->block[0] > I2C_SMBUS_BLOCK_MAX) + data->block[0] = I2C_SMBUS_BLOCK_MAX; + } else { + data->block[0] = 32; /* max for SMBus block reads */ + } + + /* Experience has shown that the block buffer can only be used for + SMBus (not I2C) block transactions, even though the datasheet + doesn't mention this limitation. */ + if ((priv->features & FEATURE_BLOCK_BUFFER) + && command != I2C_SMBUS_I2C_BLOCK_DATA + && i801_set_block_buffer_mode(priv) == 0) + result = i801_block_transaction_by_block(priv, data, + read_write, + command, hwpec); + else + result = i801_block_transaction_byte_by_byte(priv, data, + read_write, + command, hwpec); + + if (command == I2C_SMBUS_I2C_BLOCK_DATA + && read_write == I2C_SMBUS_WRITE) { + /* restore saved configuration register value */ + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc); + } + return result; +} + +/* Return negative errno on error. */ +static s32 i801_access(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) +{ + int hwpec; + int block = 0; + int ret = 0, xact = 0; + struct i801_priv *priv = i2c_get_adapdata(adap); + + mutex_lock(&priv->acpi_lock); + if (priv->acpi_reserved) { + mutex_unlock(&priv->acpi_lock); + return -EBUSY; + } + + pm_runtime_get_sync(&priv->pci_dev->dev); + + hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) + && size != I2C_SMBUS_QUICK + && size != I2C_SMBUS_I2C_BLOCK_DATA; + + switch (size) { + case I2C_SMBUS_QUICK: + outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMBHSTADD(priv)); + xact = I801_QUICK; + break; + case I2C_SMBUS_BYTE: + outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMBHSTADD(priv)); + if (read_write == I2C_SMBUS_WRITE) + outb_p(command, SMBHSTCMD(priv)); + xact = I801_BYTE; + break; + case I2C_SMBUS_BYTE_DATA: + outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMBHSTADD(priv)); + outb_p(command, SMBHSTCMD(priv)); + if (read_write == I2C_SMBUS_WRITE) + outb_p(data->byte, SMBHSTDAT0(priv)); + xact = I801_BYTE_DATA; + break; + case I2C_SMBUS_WORD_DATA: + outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMBHSTADD(priv)); + outb_p(command, SMBHSTCMD(priv)); + if (read_write == I2C_SMBUS_WRITE) { + outb_p(data->word & 0xff, SMBHSTDAT0(priv)); + outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv)); + } + xact = I801_WORD_DATA; + break; + case I2C_SMBUS_BLOCK_DATA: + outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMBHSTADD(priv)); + outb_p(command, SMBHSTCMD(priv)); + block = 1; + break; + case I2C_SMBUS_I2C_BLOCK_DATA: + /* + * NB: page 240 of ICH5 datasheet shows that the R/#W + * bit should be cleared here, even when reading. + * However if SPD Write Disable is set (Lynx Point and later), + * the read will fail if we don't set the R/#W bit. + */ + outb_p(((addr & 0x7f) << 1) | + ((priv->original_hstcfg & SMBHSTCFG_SPD_WD) ? + (read_write & 0x01) : 0), + SMBHSTADD(priv)); + if (read_write == I2C_SMBUS_READ) { + /* NB: page 240 of ICH5 datasheet also shows + * that DATA1 is the cmd field when reading */ + outb_p(command, SMBHSTDAT1(priv)); + } else + outb_p(command, SMBHSTCMD(priv)); + block = 1; + break; + case I2C_SMBUS_BLOCK_PROC_CALL: + /* + * Bit 0 of the slave address register always indicate a write + * command. + */ + outb_p((addr & 0x7f) << 1, SMBHSTADD(priv)); + outb_p(command, SMBHSTCMD(priv)); + block = 1; + break; + default: + dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n", + size); + ret = -EOPNOTSUPP; + goto out; + } + + if (hwpec) /* enable/disable hardware PEC */ + outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv)); + else + outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC), + SMBAUXCTL(priv)); + + if (block) + ret = i801_block_transaction(priv, data, read_write, size, + hwpec); + else + ret = i801_transaction(priv, xact); + + /* Some BIOSes don't like it when PEC is enabled at reboot or resume + time, so we forcibly disable it after every transaction. Turn off + E32B for the same reason. */ + if (hwpec || block) + outb_p(inb_p(SMBAUXCTL(priv)) & + ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); + + if (block) + goto out; + if (ret) + goto out; + if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) + goto out; + + switch (xact & 0x7f) { + case I801_BYTE: /* Result put in SMBHSTDAT0 */ + case I801_BYTE_DATA: + data->byte = inb_p(SMBHSTDAT0(priv)); + break; + case I801_WORD_DATA: + data->word = inb_p(SMBHSTDAT0(priv)) + + (inb_p(SMBHSTDAT1(priv)) << 8); + break; + } + +out: + pm_runtime_mark_last_busy(&priv->pci_dev->dev); + pm_runtime_put_autosuspend(&priv->pci_dev->dev); + mutex_unlock(&priv->acpi_lock); + return ret; +} + +static u32 i801_func(struct i2c_adapter *adapter) +{ + struct i801_priv *priv = i2c_get_adapdata(adapter); + + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | + ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | + ((priv->features & FEATURE_BLOCK_PROC) ? + I2C_FUNC_SMBUS_BLOCK_PROC_CALL : 0) | + ((priv->features & FEATURE_I2C_BLOCK_READ) ? + I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) | + ((priv->features & FEATURE_HOST_NOTIFY) ? + I2C_FUNC_SMBUS_HOST_NOTIFY : 0); +} + +static void i801_enable_host_notify(struct i2c_adapter *adapter) +{ + struct i801_priv *priv = i2c_get_adapdata(adapter); + + if (!(priv->features & FEATURE_HOST_NOTIFY)) + return; + + if (!(SMBSLVCMD_HST_NTFY_INTREN & priv->original_slvcmd)) + outb_p(SMBSLVCMD_HST_NTFY_INTREN | priv->original_slvcmd, + SMBSLVCMD(priv)); + + /* clear Host Notify bit to allow a new notification */ + outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); +} + +static void i801_disable_host_notify(struct i801_priv *priv) +{ + if (!(priv->features & FEATURE_HOST_NOTIFY)) + return; + + outb_p(priv->original_slvcmd, SMBSLVCMD(priv)); +} + +static const struct i2c_algorithm smbus_algorithm = { + .smbus_xfer = i801_access, + .functionality = i801_func, +}; + +static const struct pci_device_id i801_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_3) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_3) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_3) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_4) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_16) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EP80579_1) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EBG_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, i801_ids); + +#if defined CONFIG_X86 && defined CONFIG_DMI +static unsigned char apanel_addr; + +/* Scan the system ROM for the signature "FJKEYINF" */ +static __init const void __iomem *bios_signature(const void __iomem *bios) +{ + ssize_t offset; + const unsigned char signature[] = "FJKEYINF"; + + for (offset = 0; offset < 0x10000; offset += 0x10) { + if (check_signature(bios + offset, signature, + sizeof(signature)-1)) + return bios + offset; + } + return NULL; +} + +static void __init input_apanel_init(void) +{ + void __iomem *bios; + const void __iomem *p; + + bios = ioremap(0xF0000, 0x10000); /* Can't fail */ + p = bios_signature(bios); + if (p) { + /* just use the first address */ + apanel_addr = readb(p + 8 + 3) >> 1; + } + iounmap(bios); +} + +struct dmi_onboard_device_info { + const char *name; + u8 type; + unsigned short i2c_addr; + const char *i2c_type; +}; + +static const struct dmi_onboard_device_info dmi_devices[] = { + { "Syleus", DMI_DEV_TYPE_OTHER, 0x73, "fscsyl" }, + { "Hermes", DMI_DEV_TYPE_OTHER, 0x73, "fscher" }, + { "Hades", DMI_DEV_TYPE_OTHER, 0x73, "fschds" }, +}; + +static void dmi_check_onboard_device(u8 type, const char *name, + struct i2c_adapter *adap) +{ + int i; + struct i2c_board_info info; + + for (i = 0; i < ARRAY_SIZE(dmi_devices); i++) { + /* & ~0x80, ignore enabled/disabled bit */ + if ((type & ~0x80) != dmi_devices[i].type) + continue; + if (strcasecmp(name, dmi_devices[i].name)) + continue; + + mem_clear(&info, sizeof(struct i2c_board_info)); + info.addr = dmi_devices[i].i2c_addr; + strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE); + i2c_new_client_device(adap, &info); + break; + } +} + +/* We use our own function to check for onboard devices instead of + dmi_find_device() as some buggy BIOS's have the devices we are interested + in marked as disabled */ +static void dmi_check_onboard_devices(const struct dmi_header *dm, void *adap) +{ + int i, count; + + if (dm->type != 10) + return; + + count = (dm->length - sizeof(struct dmi_header)) / 2; + for (i = 0; i < count; i++) { + const u8 *d = (char *)(dm + 1) + (i * 2); + const char *name = ((char *) dm) + dm->length; + u8 type = d[0]; + u8 s = d[1]; + + if (!s) + continue; + s--; + while (s > 0 && name[0]) { + name += strlen(name) + 1; + s--; + } + if (name[0] == 0) /* Bogus string reference */ + continue; + + dmi_check_onboard_device(type, name, adap); + } +} + +/* NOTE: Keep this list in sync with drivers/platform/x86/dell-smo8800.c */ +static const char *const acpi_smo8800_ids[] = { + "SMO8800", + "SMO8801", + "SMO8810", + "SMO8811", + "SMO8820", + "SMO8821", + "SMO8830", + "SMO8831", +}; + +static acpi_status check_acpi_smo88xx_device(acpi_handle obj_handle, + u32 nesting_level, + void *context, + void **return_value) +{ + struct acpi_device_info *info; + acpi_status status; + char *hid; + int i; + + status = acpi_get_object_info(obj_handle, &info); + if (ACPI_FAILURE(status)) + return AE_OK; + + if (!(info->valid & ACPI_VALID_HID)) + goto smo88xx_not_found; + + hid = info->hardware_id.string; + if (!hid) + goto smo88xx_not_found; + + i = match_string(acpi_smo8800_ids, ARRAY_SIZE(acpi_smo8800_ids), hid); + if (i < 0) + goto smo88xx_not_found; + + kfree(info); + + *((bool *)return_value) = true; + return AE_CTRL_TERMINATE; + +smo88xx_not_found: + kfree(info); + return AE_OK; +} + +static bool is_dell_system_with_lis3lv02d(void) +{ + bool found; + const char *vendor; + + vendor = dmi_get_system_info(DMI_SYS_VENDOR); + if (!vendor || strcmp(vendor, "Dell Inc.")) + return false; + + /* + * Check that ACPI device SMO88xx is present and is functioning. + * Function acpi_get_devices() already filters all ACPI devices + * which are not present or are not functioning. + * ACPI device SMO88xx represents our ST microelectronics lis3lv02d + * accelerometer but unfortunately ACPI does not provide any other + * information (like I2C address). + */ + found = false; + acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL, + (void **)&found); + + return found; +} + +/* + * Accelerometer's I2C address is not specified in DMI nor ACPI, + * so it is needed to define mapping table based on DMI product names. + */ +static const struct { + const char *dmi_product_name; + unsigned short i2c_addr; +} dell_lis3lv02d_devices[] = { + /* + * Dell platform team told us that these Latitude devices have + * ST microelectronics accelerometer at I2C address 0x29. + */ + { "Latitude E5250", 0x29 }, + { "Latitude E5450", 0x29 }, + { "Latitude E5550", 0x29 }, + { "Latitude E6440", 0x29 }, + { "Latitude E6440 ATG", 0x29 }, + { "Latitude E6540", 0x29 }, + /* + * Additional individual entries were added after verification. + */ + { "Latitude 5480", 0x29 }, + { "Vostro V131", 0x1d }, +}; + +static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv) +{ + struct i2c_board_info info; + const char *dmi_product_name; + int i; + + dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME); + for (i = 0; i < ARRAY_SIZE(dell_lis3lv02d_devices); ++i) { + if (strcmp(dmi_product_name, + dell_lis3lv02d_devices[i].dmi_product_name) == 0) + break; + } + + if (i == ARRAY_SIZE(dell_lis3lv02d_devices)) { + dev_warn(&priv->pci_dev->dev, + "Accelerometer lis3lv02d is present on SMBus but its" + " address is unknown, skipping registration\n"); + return; + } + + mem_clear(&info, sizeof(struct i2c_board_info)); + info.addr = dell_lis3lv02d_devices[i].i2c_addr; + strlcpy(info.type, "lis3lv02d", I2C_NAME_SIZE); + i2c_new_client_device(&priv->adapter, &info); +} + +/* Register optional slaves */ +static void i801_probe_optional_slaves(struct i801_priv *priv) +{ + /* Only register slaves on main SMBus channel */ + if (priv->features & FEATURE_IDF) + return; + + if (apanel_addr) { + struct i2c_board_info info; + + mem_clear(&info, sizeof(struct i2c_board_info)); + info.addr = apanel_addr; + strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE); + i2c_new_client_device(&priv->adapter, &info); + } + + if (dmi_name_in_vendors("FUJITSU")) + dmi_walk(dmi_check_onboard_devices, &priv->adapter); + + if (is_dell_system_with_lis3lv02d()) + register_dell_lis3lv02d_i2c_device(priv); + + /* Instantiate SPD EEPROMs unless the SMBus is multiplexed */ +#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) + if (!priv->mux_drvdata) +#endif + i2c_register_spd(&priv->adapter); +} +#else +static void __init input_apanel_init(void) {} +static void i801_probe_optional_slaves(struct i801_priv *priv) {} +#endif /* CONFIG_X86 && CONFIG_DMI */ + +#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI +static struct i801_mux_config i801_mux_config_asus_z8_d12 = { + .gpio_chip = "gpio_ich", + .values = { 0x02, 0x03 }, + .n_values = 2, + .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD }, + .gpios = { 52, 53 }, + .n_gpios = 2, +}; + +static struct i801_mux_config i801_mux_config_asus_z8_d18 = { + .gpio_chip = "gpio_ich", + .values = { 0x02, 0x03, 0x01 }, + .n_values = 3, + .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD, I2C_CLASS_SPD }, + .gpios = { 52, 53 }, + .n_gpios = 2, +}; + +static const struct dmi_system_id mux_dmi_table[] = { + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8NA-D6(C)"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)E-D12(X)"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8NH-D12"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8PH-D12/IFB"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8NR-D12"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)H-D12"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8PG-D18"), + }, + .driver_data = &i801_mux_config_asus_z8_d18, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8PE-D18"), + }, + .driver_data = &i801_mux_config_asus_z8_d18, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8PS-D12"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { } +}; + +/* Setup multiplexing if needed */ +static int i801_add_mux(struct i801_priv *priv) +{ + struct device *dev = &priv->adapter.dev; + const struct i801_mux_config *mux_config; + struct i2c_mux_gpio_platform_data gpio_data; + struct gpiod_lookup_table *lookup; + int err, i; + + if (!priv->mux_drvdata) + return 0; + mux_config = priv->mux_drvdata; + + /* Prepare the platform data */ + mem_clear(&gpio_data, sizeof(struct i2c_mux_gpio_platform_data)); + gpio_data.parent = priv->adapter.nr; + gpio_data.values = mux_config->values; + gpio_data.n_values = mux_config->n_values; + gpio_data.classes = mux_config->classes; + gpio_data.idle = I2C_MUX_GPIO_NO_IDLE; + + /* Register GPIO descriptor lookup table */ + lookup = devm_kzalloc(dev, + struct_size(lookup, table, mux_config->n_gpios + 1), + GFP_KERNEL); + if (!lookup) + return -ENOMEM; + lookup->dev_id = "i2c-mux-gpio"; + for (i = 0; i < mux_config->n_gpios; i++) { + lookup->table[i] = (struct gpiod_lookup) + GPIO_LOOKUP(mux_config->gpio_chip, + mux_config->gpios[i], "mux", 0); + } + gpiod_add_lookup_table(lookup); + priv->lookup = lookup; + + /* + * Register the mux device, we use PLATFORM_DEVID_NONE here + * because since we are referring to the GPIO chip by name we are + * anyways in deep trouble if there is more than one of these + * devices, and there should likely only be one platform controller + * hub. + */ + priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio", + PLATFORM_DEVID_NONE, &gpio_data, + sizeof(struct i2c_mux_gpio_platform_data)); + if (IS_ERR(priv->mux_pdev)) { + err = PTR_ERR(priv->mux_pdev); + gpiod_remove_lookup_table(lookup); + priv->mux_pdev = NULL; + dev_err(dev, "Failed to register i2c-mux-gpio device\n"); + return err; + } + + return 0; +} + +static void i801_del_mux(struct i801_priv *priv) +{ + if (priv->mux_pdev) + platform_device_unregister(priv->mux_pdev); + if (priv->lookup) + gpiod_remove_lookup_table(priv->lookup); +} + +static unsigned int i801_get_adapter_class(struct i801_priv *priv) +{ + const struct dmi_system_id *id; + const struct i801_mux_config *mux_config; + unsigned int class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + int i; + + id = dmi_first_match(mux_dmi_table); + if (id) { + /* Remove branch classes from trunk */ + mux_config = id->driver_data; + for (i = 0; i < mux_config->n_values; i++) + class &= ~mux_config->classes[i]; + + /* Remember for later */ + priv->mux_drvdata = mux_config; + } + + return class; +} +#else +static inline int i801_add_mux(struct i801_priv *priv) { return 0; } +static inline void i801_del_mux(struct i801_priv *priv) { } + +static inline unsigned int i801_get_adapter_class(struct i801_priv *priv) +{ + return I2C_CLASS_HWMON | I2C_CLASS_SPD; +} +#endif + +static const struct itco_wdt_platform_data spt_tco_platform_data = { + .name = "Intel PCH", + .version = 4, +}; + +static DEFINE_SPINLOCK(p2sb_spinlock); + +static struct platform_device * +i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev, + struct resource *tco_res) +{ + struct resource *res; + unsigned int devfn; + u64 base64_addr; + u32 base_addr; + u8 hidden; + + /* + * We must access the NO_REBOOT bit over the Primary to Sideband + * bridge (P2SB). The BIOS prevents the P2SB device from being + * enumerated by the PCI subsystem, so we need to unhide/hide it + * to lookup the P2SB BAR. + */ + spin_lock(&p2sb_spinlock); + + devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 1); + + /* Unhide the P2SB device, if it is hidden */ + pci_bus_read_config_byte(pci_dev->bus, devfn, 0xe1, &hidden); + if (hidden) + pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, 0x0); + + pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR, &base_addr); + base64_addr = base_addr & 0xfffffff0; + + pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR + 0x4, &base_addr); + base64_addr |= (u64)base_addr << 32; + + /* Hide the P2SB device, if it was hidden before */ + if (hidden) + pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden); + spin_unlock(&p2sb_spinlock); + + res = &tco_res[1]; + if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS) + res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL_DNV; + else + res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL; + + res->end = res->start + 3; + res->flags = IORESOURCE_MEM; + + return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1, + tco_res, 2, &spt_tco_platform_data, + sizeof(spt_tco_platform_data)); +} + +static const struct itco_wdt_platform_data cnl_tco_platform_data = { + .name = "Intel PCH", + .version = 6, +}; + +static struct platform_device * +i801_add_tco_cnl(struct i801_priv *priv, struct pci_dev *pci_dev, + struct resource *tco_res) +{ + return platform_device_register_resndata(&pci_dev->dev, + "iTCO_wdt", -1, tco_res, 1, &cnl_tco_platform_data, + sizeof(cnl_tco_platform_data)); +} + +static void i801_add_tco(struct i801_priv *priv) +{ + struct pci_dev *pci_dev = priv->pci_dev; + struct resource tco_res[2], *res; + u32 tco_base, tco_ctl; + + /* If we have ACPI based watchdog use that instead */ + if (acpi_has_watchdog()) + return; + + if (!(priv->features & (FEATURE_TCO_SPT | FEATURE_TCO_CNL))) + return; + + pci_read_config_dword(pci_dev, TCOBASE, &tco_base); + pci_read_config_dword(pci_dev, TCOCTL, &tco_ctl); + if (!(tco_ctl & TCOCTL_EN)) + return; + + mem_clear(tco_res, sizeof(tco_res)); + /* + * Always populate the main iTCO IO resource here. The second entry + * for NO_REBOOT MMIO is filled by the SPT specific function. + */ + res = &tco_res[0]; + res->start = tco_base & ~1; + res->end = res->start + 32 - 1; + res->flags = IORESOURCE_IO; + + if (priv->features & FEATURE_TCO_CNL) + priv->tco_pdev = i801_add_tco_cnl(priv, pci_dev, tco_res); + else + priv->tco_pdev = i801_add_tco_spt(priv, pci_dev, tco_res); + + if (IS_ERR(priv->tco_pdev)) + dev_warn(&pci_dev->dev, "failed to create iTCO device\n"); +} + +#ifdef CONFIG_ACPI +static bool i801_acpi_is_smbus_ioport(const struct i801_priv *priv, + acpi_physical_address address) +{ + return address >= priv->smba && + address <= pci_resource_end(priv->pci_dev, SMBBAR); +} + +static acpi_status +i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, + u64 *value, void *handler_context, void *region_context) +{ + struct i801_priv *priv = handler_context; + struct pci_dev *pdev = priv->pci_dev; + acpi_status status; + + /* + * Once BIOS AML code touches the OpRegion we warn and inhibit any + * further access from the driver itself. This device is now owned + * by the system firmware. + */ + mutex_lock(&priv->acpi_lock); + + if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) { + priv->acpi_reserved = true; + + dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n"); + dev_warn(&pdev->dev, "Driver SMBus register access inhibited\n"); + + /* + * BIOS is accessing the host controller so prevent it from + * suspending automatically from now on. + */ + pm_runtime_get_sync(&pdev->dev); + } + + if ((function & ACPI_IO_MASK) == ACPI_READ) + status = acpi_os_read_port(address, (u32 *)value, bits); + else + status = acpi_os_write_port(address, (u32)*value, bits); + + mutex_unlock(&priv->acpi_lock); + + return status; +} + +static int i801_acpi_probe(struct i801_priv *priv) +{ + struct acpi_device *adev; + acpi_status status; + + adev = ACPI_COMPANION(&priv->pci_dev->dev); + if (adev) { + status = acpi_install_address_space_handler(adev->handle, + ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler, + NULL, priv); + if (ACPI_SUCCESS(status)) + return 0; + } + + return acpi_check_resource_conflict(&priv->pci_dev->resource[SMBBAR]); +} + +static void i801_acpi_remove(struct i801_priv *priv) +{ + struct acpi_device *adev; + + adev = ACPI_COMPANION(&priv->pci_dev->dev); + if (!adev) + return; + + acpi_remove_address_space_handler(adev->handle, + ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler); + + mutex_lock(&priv->acpi_lock); + if (priv->acpi_reserved) + pm_runtime_put(&priv->pci_dev->dev); + mutex_unlock(&priv->acpi_lock); +} +#else +static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; } +static inline void i801_acpi_remove(struct i801_priv *priv) { } +#endif + +static unsigned char i801_setup_hstcfg(struct i801_priv *priv) +{ + unsigned char hstcfg = priv->original_hstcfg; + + hstcfg &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */ + hstcfg |= SMBHSTCFG_HST_EN; + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hstcfg); + return hstcfg; +} + +static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + unsigned char temp; + int err, i; + struct i801_priv *priv; + + priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + i2c_set_adapdata(&priv->adapter, priv); + priv->adapter.owner = THIS_MODULE; + priv->adapter.class = i801_get_adapter_class(priv); + priv->adapter.algo = &smbus_algorithm; + priv->adapter.dev.parent = &dev->dev; + ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev)); + priv->adapter.retries = 3; + mutex_init(&priv->acpi_lock); + + priv->pci_dev = dev; + switch (dev->device) { + case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS: + case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS: + case PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS: + case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS: + case PCI_DEVICE_ID_INTEL_DNV_SMBUS: + case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS: + case PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS: + priv->features |= FEATURE_BLOCK_PROC; + priv->features |= FEATURE_I2C_BLOCK_READ; + priv->features |= FEATURE_IRQ; + priv->features |= FEATURE_SMBUS_PEC; + priv->features |= FEATURE_BLOCK_BUFFER; + priv->features |= FEATURE_TCO_SPT; + priv->features |= FEATURE_HOST_NOTIFY; + break; + + case PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS: + case PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS: + case PCI_DEVICE_ID_INTEL_CDF_SMBUS: + case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS: + case PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS: + case PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS: + case PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS: + case PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS: + case PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS: + case PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS: + case PCI_DEVICE_ID_INTEL_EBG_SMBUS: + case PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS: + priv->features |= FEATURE_BLOCK_PROC; + priv->features |= FEATURE_I2C_BLOCK_READ; + priv->features |= FEATURE_IRQ; + priv->features |= FEATURE_SMBUS_PEC; + priv->features |= FEATURE_BLOCK_BUFFER; + priv->features |= FEATURE_TCO_CNL; + priv->features |= FEATURE_HOST_NOTIFY; + break; + + case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0: + case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1: + case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2: + case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0: + case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1: + case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2: + priv->features |= FEATURE_IDF; + fallthrough; + default: + priv->features |= FEATURE_BLOCK_PROC; + priv->features |= FEATURE_I2C_BLOCK_READ; + priv->features |= FEATURE_IRQ; + fallthrough; + case PCI_DEVICE_ID_INTEL_82801DB_3: + priv->features |= FEATURE_SMBUS_PEC; + priv->features |= FEATURE_BLOCK_BUFFER; + fallthrough; + case PCI_DEVICE_ID_INTEL_82801CA_3: + priv->features |= FEATURE_HOST_NOTIFY; + fallthrough; + case PCI_DEVICE_ID_INTEL_82801BA_2: + case PCI_DEVICE_ID_INTEL_82801AB_3: + case PCI_DEVICE_ID_INTEL_82801AA_3: + break; + } + + /* Disable features on user request */ + for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) { + if (priv->features & disable_features & (1 << i)) + dev_notice(&dev->dev, "%s disabled by user\n", + i801_feature_names[i]); + } + priv->features &= ~disable_features; + + err = pcim_enable_device(dev); + if (err) { + dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n", + err); + return err; + } + pcim_pin_device(dev); + + /* Determine the address of the SMBus area */ + priv->smba = pci_resource_start(dev, SMBBAR); + if (!priv->smba) { + dev_err(&dev->dev, + "SMBus base address uninitialized, upgrade BIOS\n"); + return -ENODEV; + } + + if (i801_acpi_probe(priv)) + return -ENODEV; + + err = pcim_iomap_regions(dev, 1 << SMBBAR, + dev_driver_string(&dev->dev)); + if (err) { + dev_err(&dev->dev, + "Failed to request SMBus region 0x%lx-0x%Lx\n", + priv->smba, + (unsigned long long)pci_resource_end(dev, SMBBAR)); + i801_acpi_remove(priv); + return err; + } + + pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &priv->original_hstcfg); + temp = i801_setup_hstcfg(priv); + if (!(priv->original_hstcfg & SMBHSTCFG_HST_EN)) + dev_info(&dev->dev, "Enabling SMBus device\n"); + + if (temp & SMBHSTCFG_SMB_SMI_EN) { + dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n"); + /* Disable SMBus interrupt feature if SMBus using SMI# */ + priv->features &= ~FEATURE_IRQ; + } + if (temp & SMBHSTCFG_SPD_WD) + dev_info(&dev->dev, "SPD Write Disable is set\n"); + + /* Clear special mode bits */ + if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER)) + outb_p(inb_p(SMBAUXCTL(priv)) & + ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); + + /* Remember original Host Notify setting */ + if (priv->features & FEATURE_HOST_NOTIFY) + priv->original_slvcmd = inb_p(SMBSLVCMD(priv)); + + /* Default timeout in interrupt mode: 200 ms */ + priv->adapter.timeout = HZ / 5; + + if (dev->irq == IRQ_NOTCONNECTED) + priv->features &= ~FEATURE_IRQ; + + if (priv->features & FEATURE_IRQ) { + u16 pcictl, pcists; + + /* Complain if an interrupt is already pending */ + pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists); + if (pcists & SMBPCISTS_INTS) + dev_warn(&dev->dev, "An interrupt is pending!\n"); + + /* Check if interrupts have been disabled */ + pci_read_config_word(priv->pci_dev, SMBPCICTL, &pcictl); + if (pcictl & SMBPCICTL_INTDIS) { + dev_info(&dev->dev, "Interrupts are disabled\n"); + priv->features &= ~FEATURE_IRQ; + } + } + + if (priv->features & FEATURE_IRQ) { + init_waitqueue_head(&priv->waitq); + + err = devm_request_irq(&dev->dev, dev->irq, i801_isr, + IRQF_SHARED, + dev_driver_string(&dev->dev), priv); + if (err) { + dev_err(&dev->dev, "Failed to allocate irq %d: %d\n", + dev->irq, err); + priv->features &= ~FEATURE_IRQ; + } + } + dev_info(&dev->dev, "SMBus using %s\n", + priv->features & FEATURE_IRQ ? "PCI interrupt" : "polling"); + + i801_add_tco(priv); + + snprintf(priv->adapter.name, sizeof(priv->adapter.name), + "SMBus I801 adapter at %04lx", priv->smba); + err = i2c_add_adapter(&priv->adapter); + if (err) { + i801_acpi_remove(priv); + return err; + } + + i801_enable_host_notify(&priv->adapter); + + i801_probe_optional_slaves(priv); + /* We ignore errors - multiplexing is optional */ + i801_add_mux(priv); + + pci_set_drvdata(dev, priv); + + dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_NO_DIRECT_COMPLETE); + pm_runtime_set_autosuspend_delay(&dev->dev, 1000); + pm_runtime_use_autosuspend(&dev->dev); + pm_runtime_put_autosuspend(&dev->dev); + pm_runtime_allow(&dev->dev); + dev_info(&dev->dev, "wb-i2c-i801 probe ok.\n"); + + return 0; +} + +static void i801_remove(struct pci_dev *dev) +{ + struct i801_priv *priv = pci_get_drvdata(dev); + + pm_runtime_forbid(&dev->dev); + pm_runtime_get_noresume(&dev->dev); + + i801_disable_host_notify(priv); + i801_del_mux(priv); + i2c_del_adapter(&priv->adapter); + i801_acpi_remove(priv); + pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); + + platform_device_unregister(priv->tco_pdev); + + /* + * do not call pci_disable_device(dev) since it can cause hard hangs on + * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010) + */ +} + +static void i801_shutdown(struct pci_dev *dev) +{ + struct i801_priv *priv = pci_get_drvdata(dev); + + /* Restore config registers to avoid hard hang on some systems */ + i801_disable_host_notify(priv); + pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); +} + +#ifdef CONFIG_PM_SLEEP +static int i801_suspend(struct device *dev) +{ + struct i801_priv *priv = dev_get_drvdata(dev); + + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, priv->original_hstcfg); + return 0; +} + +static int i801_resume(struct device *dev) +{ + struct i801_priv *priv = dev_get_drvdata(dev); + + i801_setup_hstcfg(priv); + i801_enable_host_notify(&priv->adapter); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume); + +static struct pci_driver i801_driver = { + .name = "wb_i801_smbus", + .id_table = i801_ids, + .probe = i801_probe, + .remove = i801_remove, + .shutdown = i801_shutdown, + .driver = { + .pm = &i801_pm_ops, + }, +}; + +static int __init i2c_i801_init(void) +{ + if (dmi_name_in_vendors("FUJITSU")) + input_apanel_init(); + return pci_register_driver(&i801_driver); +} + +static void __exit i2c_i801_exit(void) +{ + pci_unregister_driver(&i801_driver); +} + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("I801 SMBus driver"); +MODULE_LICENSE("GPL"); + +module_init(i2c_i801_init); +module_exit(i2c_i801_exit); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_ismt.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_ismt.c new file mode 100644 index 000000000000..2015c8ca2e18 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_ismt.c @@ -0,0 +1,1105 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2012 Intel Corporation. All rights reserved. + * + * GPL LICENSE SUMMARY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Supports the SMBus Message Transport (SMT) in the Intel Atom Processor + * S12xx Product Family. + * + * Features supported by this driver: + * Hardware PEC yes + * Block buffer yes + * Block process call transaction no + * Slave mode no + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +/* PCI Address Constants */ +#define SMBBAR 0 + +#define ISMT_DBCTRL 0x388 /* ISMT PIN Control Register */ +#define ISMT_DBSTS 0X38C /* ISMT PIN Status Register */ + +#define ISMT_DBSTS_CLK_STS (1<<9) /* bit9 SMBCLK_CUR_STS */ +#define ISMT_DBSTS_SDA_STS (1<<8) /* bit8 SMBDATA_CUR_STS */ +#define ISMT_DBCTRL_CLK_CTL (1<<1) /* bit1 SMBCLK_CTL */ +#define ISMT_DBCTRL_ENABLE (1<<31) /* bit31 EN */ + +/* PCI DIDs for the Intel SMBus Message Transport (SMT) Devices */ +#define PCI_DEVICE_ID_INTEL_S1200_SMT0 0x0c59 +#define PCI_DEVICE_ID_INTEL_S1200_SMT1 0x0c5a +#define PCI_DEVICE_ID_INTEL_CDF_SMT 0x18ac +#define PCI_DEVICE_ID_INTEL_DNV_SMT 0x19ac +#define PCI_DEVICE_ID_INTEL_EBG_SMT 0x1bff +#define PCI_DEVICE_ID_INTEL_AVOTON_SMT 0x1f15 + +#define ISMT_DESC_ENTRIES 2 /* number of descriptor entries */ +#define ISMT_MAX_RETRIES 3 /* number of SMBus retries to attempt */ + +/* Hardware Descriptor Constants - Control Field */ +#define ISMT_DESC_CWRL 0x01 /* Command/Write Length */ +#define ISMT_DESC_BLK 0X04 /* Perform Block Transaction */ +#define ISMT_DESC_FAIR 0x08 /* Set fairness flag upon successful arbit. */ +#define ISMT_DESC_PEC 0x10 /* Packet Error Code */ +#define ISMT_DESC_I2C 0x20 /* I2C Enable */ +#define ISMT_DESC_INT 0x40 /* Interrupt */ +#define ISMT_DESC_SOE 0x80 /* Stop On Error */ + +/* Hardware Descriptor Constants - Status Field */ +#define ISMT_DESC_SCS 0x01 /* Success */ +#define ISMT_DESC_DLTO 0x04 /* Data Low Time Out */ +#define ISMT_DESC_NAK 0x08 /* NAK Received */ +#define ISMT_DESC_CRC 0x10 /* CRC Error */ +#define ISMT_DESC_CLTO 0x20 /* Clock Low Time Out */ +#define ISMT_DESC_COL 0x40 /* Collisions */ +#define ISMT_DESC_LPR 0x80 /* Large Packet Received */ + +/* Macros */ +#define ISMT_DESC_ADDR_RW(addr, rw) (((addr) << 1) | (rw)) + +/* iSMT General Register address offsets (SMBBAR + ) */ +#define ISMT_GR_GCTRL 0x000 /* General Control */ +#define ISMT_GR_SMTICL 0x008 /* SMT Interrupt Cause Location */ +#define ISMT_GR_ERRINTMSK 0x010 /* Error Interrupt Mask */ +#define ISMT_GR_ERRAERMSK 0x014 /* Error AER Mask */ +#define ISMT_GR_ERRSTS 0x018 /* Error Status */ +#define ISMT_GR_ERRINFO 0x01c /* Error Information */ + +/* iSMT Master Registers */ +#define ISMT_MSTR_MDBA 0x100 /* Master Descriptor Base Address */ +#define ISMT_MSTR_MCTRL 0x108 /* Master Control */ +#define ISMT_MSTR_MSTS 0x10c /* Master Status */ +#define ISMT_MSTR_MDS 0x110 /* Master Descriptor Size */ +#define ISMT_MSTR_RPOLICY 0x114 /* Retry Policy */ + +/* iSMT Miscellaneous Registers */ +#define ISMT_SPGT 0x300 /* SMBus PHY Global Timing */ + +/* General Control Register (GCTRL) bit definitions */ +#define ISMT_GCTRL_TRST 0x04 /* Target Reset */ +#define ISMT_GCTRL_KILL 0x08 /* Kill */ +#define ISMT_GCTRL_SRST 0x40 /* Soft Reset */ + +/* Master Control Register (MCTRL) bit definitions */ +#define ISMT_MCTRL_SS 0x01 /* Start/Stop */ +#define ISMT_MCTRL_MEIE 0x10 /* Master Error Interrupt Enable */ +#define ISMT_MCTRL_FMHP 0x00ff0000 /* Firmware Master Head Ptr (FMHP) */ + +/* Master Status Register (MSTS) bit definitions */ +#define ISMT_MSTS_HMTP 0xff0000 /* HW Master Tail Pointer (HMTP) */ +#define ISMT_MSTS_MIS 0x20 /* Master Interrupt Status (MIS) */ +#define ISMT_MSTS_MEIS 0x10 /* Master Error Int Status (MEIS) */ +#define ISMT_MSTS_IP 0x01 /* In Progress */ + +/* Master Descriptor Size (MDS) bit definitions */ +#define ISMT_MDS_MASK 0xff /* Master Descriptor Size mask (MDS) */ + +/* SMBus PHY Global Timing Register (SPGT) bit definitions */ +#define ISMT_SPGT_SPD_MASK 0xc0000000 /* SMBus Speed mask */ +#define ISMT_SPGT_SPD_80K 0x00 /* 80 kHz */ +#define ISMT_SPGT_SPD_100K (0x1 << 30) /* 100 kHz */ +#define ISMT_SPGT_SPD_400K (0x2 << 30) /* 400 kHz */ +#define ISMT_SPGT_SPD_1M (0x3 << 30) /* 1 MHz */ + +/* MSI Control Register (MSICTL) bit definitions */ +#define ISMT_MSICTL_MSIE 0x01 /* MSI Enable */ + +/* iSMT Hardware Descriptor */ +struct ismt_desc { + u8 tgtaddr_rw; /* target address & r/w bit */ + u8 wr_len_cmd; /* write length in bytes or a command */ + u8 rd_len; /* read length */ + u8 control; /* control bits */ + u8 status; /* status bits */ + u8 retry; /* collision retry and retry count */ + u8 rxbytes; /* received bytes */ + u8 txbytes; /* transmitted bytes */ + u32 dptr_low; /* lower 32 bit of the data pointer */ + u32 dptr_high; /* upper 32 bit of the data pointer */ +} __packed; + +struct ismt_priv { + struct i2c_adapter adapter; + void __iomem *smba; /* PCI BAR */ + struct pci_dev *pci_dev; + struct ismt_desc *hw; /* descriptor virt base addr */ + dma_addr_t io_rng_dma; /* descriptor HW base addr */ + u8 head; /* ring buffer head pointer */ + struct completion cmp; /* interrupt completion */ + u8 buffer[I2C_SMBUS_BLOCK_MAX + 16]; /* temp R/W data buffer */ +}; + +static const struct pci_device_id ismt_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMT) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMT) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EBG_SMT) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, ismt_ids); + +/* Bus speed control bits for slow debuggers - refer to the docs for usage */ +static unsigned int bus_speed = 100; +static unsigned int delay = 1000; +module_param(bus_speed, uint, S_IRUGO); +MODULE_PARM_DESC(bus_speed, "Bus Speed in kHz (100 by default)"); +module_param(delay, uint, S_IRUGO); +MODULE_PARM_DESC(delay, "Delay in microsecs before access (1000 by default)"); + +static unsigned int dma_reset_timeout = 1000; +module_param(dma_reset_timeout, uint, S_IRUGO); + +static void ismt_hw_init(struct ismt_priv *priv); + +/** + * __ismt_desc_dump() - dump the contents of a specific descriptor + * @dev: the iSMT device + * @desc: the iSMT hardware descriptor + */ +static void __ismt_desc_dump(struct device *dev, const struct ismt_desc *desc) +{ + + dev_dbg(dev, "Descriptor struct: %p\n", desc); + dev_dbg(dev, "\ttgtaddr_rw=0x%02X\n", desc->tgtaddr_rw); + dev_dbg(dev, "\twr_len_cmd=0x%02X\n", desc->wr_len_cmd); + dev_dbg(dev, "\trd_len= 0x%02X\n", desc->rd_len); + dev_dbg(dev, "\tcontrol= 0x%02X\n", desc->control); + dev_dbg(dev, "\tstatus= 0x%02X\n", desc->status); + dev_dbg(dev, "\tretry= 0x%02X\n", desc->retry); + dev_dbg(dev, "\trxbytes= 0x%02X\n", desc->rxbytes); + dev_dbg(dev, "\ttxbytes= 0x%02X\n", desc->txbytes); + dev_dbg(dev, "\tdptr_low= 0x%08X\n", desc->dptr_low); + dev_dbg(dev, "\tdptr_high= 0x%08X\n", desc->dptr_high); +} +/** + * ismt_desc_dump() - dump the contents of a descriptor for debug purposes + * @priv: iSMT private data + */ +static void ismt_desc_dump(struct ismt_priv *priv) +{ + struct device *dev = &priv->pci_dev->dev; + struct ismt_desc *desc = &priv->hw[priv->head]; + + dev_dbg(dev, "Dump of the descriptor struct: 0x%X\n", priv->head); + __ismt_desc_dump(dev, desc); +} + +static void ismt_reset_dma(struct ismt_priv *priv) +{ + uint val; + u16 ctrl; + struct pci_dev *pdev; + u32 addr_lo, addr_hi; + + /* save msiaddr */ + pdev = priv->pci_dev; + pci_read_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_LO, &addr_lo); + pci_read_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_HI, &addr_hi); + + /* Clear the start bit */ + val = readl(priv->smba + ISMT_MSTR_MCTRL); + val &= ~ISMT_MCTRL_SS; + writel(val, priv->smba + ISMT_MSTR_MCTRL); + + val = readl(priv->smba + ISMT_GR_GCTRL); + writel(val | ISMT_GCTRL_KILL | ISMT_GCTRL_TRST | ISMT_GCTRL_SRST, priv->smba + ISMT_GR_GCTRL); + + if (dma_reset_timeout > 0) { + usleep_range(dma_reset_timeout, dma_reset_timeout + 1); + } + + ismt_hw_init(priv); + pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_LO, addr_lo); + pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_HI, addr_hi); + /* enable msi */ + pci_read_config_word(pdev, pdev->msi_cap + PCI_MSI_FLAGS, &ctrl); + ctrl |= PCI_MSI_FLAGS_ENABLE; + pci_write_config_word(pdev, pdev->msi_cap + PCI_MSI_FLAGS, ctrl); +} + +/** + * ismt_gen_reg_dump() - dump the iSMT General Registers + * @priv: iSMT private data + */ +static void ismt_gen_reg_dump(struct ismt_priv *priv) +{ + struct device *dev = &priv->pci_dev->dev; + + dev_dbg(dev, "Dump of the iSMT General Registers\n"); + dev_dbg(dev, " GCTRL.... : (0x%p)=0x%X\n", + priv->smba + ISMT_GR_GCTRL, + readl(priv->smba + ISMT_GR_GCTRL)); + dev_dbg(dev, " SMTICL... : (0x%p)=0x%016llX\n", + priv->smba + ISMT_GR_SMTICL, + (long long unsigned int)readq(priv->smba + ISMT_GR_SMTICL)); + dev_dbg(dev, " ERRINTMSK : (0x%p)=0x%X\n", + priv->smba + ISMT_GR_ERRINTMSK, + readl(priv->smba + ISMT_GR_ERRINTMSK)); + dev_dbg(dev, " ERRAERMSK : (0x%p)=0x%X\n", + priv->smba + ISMT_GR_ERRAERMSK, + readl(priv->smba + ISMT_GR_ERRAERMSK)); + dev_dbg(dev, " ERRSTS... : (0x%p)=0x%X\n", + priv->smba + ISMT_GR_ERRSTS, + readl(priv->smba + ISMT_GR_ERRSTS)); + dev_dbg(dev, " ERRINFO.. : (0x%p)=0x%X\n", + priv->smba + ISMT_GR_ERRINFO, + readl(priv->smba + ISMT_GR_ERRINFO)); +} + +/** + * ismt_mstr_reg_dump() - dump the iSMT Master Registers + * @priv: iSMT private data + */ +static void ismt_mstr_reg_dump(struct ismt_priv *priv) +{ + struct device *dev = &priv->pci_dev->dev; + + dev_dbg(dev, "Dump of the iSMT Master Registers\n"); + dev_dbg(dev, " MDBA..... : (0x%p)=0x%016llX\n", + priv->smba + ISMT_MSTR_MDBA, + (long long unsigned int)readq(priv->smba + ISMT_MSTR_MDBA)); + dev_dbg(dev, " MCTRL.... : (0x%p)=0x%X\n", + priv->smba + ISMT_MSTR_MCTRL, + readl(priv->smba + ISMT_MSTR_MCTRL)); + dev_dbg(dev, " MSTS..... : (0x%p)=0x%X\n", + priv->smba + ISMT_MSTR_MSTS, + readl(priv->smba + ISMT_MSTR_MSTS)); + dev_dbg(dev, " MDS...... : (0x%p)=0x%X\n", + priv->smba + ISMT_MSTR_MDS, + readl(priv->smba + ISMT_MSTR_MDS)); + dev_dbg(dev, " RPOLICY.. : (0x%p)=0x%X\n", + priv->smba + ISMT_MSTR_RPOLICY, + readl(priv->smba + ISMT_MSTR_RPOLICY)); + dev_dbg(dev, " SPGT..... : (0x%p)=0x%X\n", + priv->smba + ISMT_SPGT, + readl(priv->smba + ISMT_SPGT)); +} + +/** + * ismt_submit_desc() - add a descriptor to the ring + * @priv: iSMT private data + */ +static void ismt_submit_desc(struct ismt_priv *priv) +{ + uint fmhp; + uint val; + + ismt_desc_dump(priv); + ismt_gen_reg_dump(priv); + ismt_mstr_reg_dump(priv); + + /* Set the FMHP (Firmware Master Head Pointer)*/ + fmhp = ((priv->head + 1) % ISMT_DESC_ENTRIES) << 16; + val = readl(priv->smba + ISMT_MSTR_MCTRL); + writel((val & ~ISMT_MCTRL_FMHP) | fmhp, + priv->smba + ISMT_MSTR_MCTRL); + + /* Set the start bit */ + val = readl(priv->smba + ISMT_MSTR_MCTRL); + writel(val | ISMT_MCTRL_SS, + priv->smba + ISMT_MSTR_MCTRL); +} + +/** + * ismt_process_desc() - handle the completion of the descriptor + * @desc: the iSMT hardware descriptor + * @data: data buffer from the upper layer + * @priv: ismt_priv struct holding our dma buffer + * @size: SMBus transaction type + * @read_write: flag to indicate if this is a read or write + */ +static int ismt_process_desc(const struct ismt_desc *desc, + union i2c_smbus_data *data, + struct ismt_priv *priv, int size, + char read_write) +{ + u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16); + + dev_dbg(&priv->pci_dev->dev, "Processing completed descriptor\n"); + __ismt_desc_dump(&priv->pci_dev->dev, desc); + ismt_gen_reg_dump(priv); + ismt_mstr_reg_dump(priv); + + if (desc->status & ISMT_DESC_SCS) { + if (read_write == I2C_SMBUS_WRITE && + size != I2C_SMBUS_PROC_CALL) + return 0; + + switch (size) { + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + data->byte = dma_buffer[0]; + break; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + data->word = dma_buffer[0] | (dma_buffer[1] << 8); + break; + case I2C_SMBUS_BLOCK_DATA: + if (desc->rxbytes != dma_buffer[0] + 1) + return -EMSGSIZE; + + memcpy(data->block, dma_buffer, desc->rxbytes); + break; + case I2C_SMBUS_I2C_BLOCK_DATA: + memcpy(&data->block[1], dma_buffer, desc->rxbytes); + data->block[0] = desc->rxbytes; + break; + } + return 0; + } + + if (likely(desc->status & ISMT_DESC_NAK)) + return -ENXIO; + + if (desc->status & ISMT_DESC_CRC) + return -EBADMSG; + + if (desc->status & ISMT_DESC_COL) + return -EAGAIN; + + if (desc->status & ISMT_DESC_LPR) + return -EPROTO; + + if (desc->status & (ISMT_DESC_DLTO | ISMT_DESC_CLTO)) + return -ETIMEDOUT; + + return -EIO; +} + +static void ismt_setscl(struct ismt_priv *priv, unsigned int level) +{ + int pin_status; + + pin_status = readl(priv->smba + ISMT_DBCTRL); + if (level == 0) { + pin_status &= (~ISMT_DBCTRL_CLK_CTL); + } else { + pin_status |= ISMT_DBCTRL_CLK_CTL; + } + writel(pin_status, priv->smba + ISMT_DBCTRL); + pin_status = readl(priv->smba + ISMT_DBCTRL); + dev_dbg(&priv->pci_dev->dev, "dbctrl status = 0x%04x\r\n", pin_status); + return; +} + +static void ismt_i2c_unblock(struct ismt_priv *priv) +{ + int i; + int pin_status, ori_status; + + pin_status = readl(priv->smba + ISMT_DBCTRL); + ori_status = pin_status; + if ((pin_status & ISMT_DBCTRL_ENABLE) == 0) { + pin_status |= ISMT_DBCTRL_ENABLE; + writel(pin_status, priv->smba + ISMT_DBCTRL); + pin_status = readl(priv->smba + ISMT_DBCTRL); + dev_dbg(&priv->pci_dev->dev, "enable dbctrl pin status = 0x%04x\r\n", pin_status); + } + + for (i = 0; i < 10; i++) { + ismt_setscl(priv, 0); + udelay(5); + ismt_setscl(priv, 1); + udelay(5); + } + + pin_status = readl(priv->smba + ISMT_DBCTRL); + if (pin_status != ori_status) { + writel(ori_status, priv->smba + ISMT_DBCTRL); + pin_status = readl(priv->smba + ISMT_DBCTRL); + dev_dbg(&priv->pci_dev->dev, "reback dbctrl pin status = 0x%04x\r\n", pin_status); + } + + return; +} + +static int ismt_check_i2c_unblock(struct ismt_priv *priv) +{ + int pin_status; + + pin_status = readl(priv->smba + ISMT_DBSTS); + + if ( (!(pin_status & ISMT_DBSTS_SDA_STS) ) && (pin_status & ISMT_DBSTS_CLK_STS) ) { + dev_dbg(&priv->pci_dev->dev, "SDA is low, send 9 clock to device!\n"); + ismt_i2c_unblock(priv); + } + return 0; +} + +static int ismt_check_i2c_scl(struct ismt_priv *priv) +{ + int pin_status; + + pin_status = readl(priv->smba + ISMT_DBSTS); + + if ( (pin_status & ISMT_DBSTS_SDA_STS) && (pin_status & ISMT_DBSTS_CLK_STS) ) { + return 0; + } + + dev_warn(&priv->pci_dev->dev, "SDA or SCL is low.pin_status:0x%x\n", pin_status); + return -1; +} + +/* Make sure the SMBus host is ready to start transmitting. + Return 0 if it is, -EIO if it is not. */ +static int ismt_check_pre(struct ismt_priv *priv) +{ + ismt_check_i2c_unblock(priv); + + /* SDA or SCL is low, return -EIO */ + if (ismt_check_i2c_scl(priv)) { + return -EIO; + } + + return 0; +} + +/** + * ismt_access() - process an SMBus command + * @adap: the i2c host adapter + * @addr: address of the i2c/SMBus target + * @flags: command options + * @read_write: read from or write to device + * @command: the i2c/SMBus command to issue + * @size: SMBus transaction type + * @data: read/write data buffer + */ +static int ismt_access(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) +{ + int ret; + unsigned long time_left; + dma_addr_t dma_addr = 0; /* address of the data buffer */ + u8 dma_size = 0; + enum dma_data_direction dma_direction = 0; + struct ismt_desc *desc; + struct ismt_priv *priv = i2c_get_adapdata(adap); + struct device *dev = &priv->pci_dev->dev; + u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16); + + if (delay > 0) { + usleep_range(delay, delay + 1); + } + + ret = ismt_check_pre(priv); + if (ret < 0) { + return ret; + } + + desc = &priv->hw[priv->head]; + + /* Initialize the DMA buffer */ + mem_clear(priv->buffer, sizeof(priv->buffer)); + + /* Initialize the descriptor */ + mem_clear(desc, sizeof(struct ismt_desc)); + desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write); + + /* Initialize common control bits */ + if (likely(pci_dev_msi_enabled(priv->pci_dev))) + desc->control = ISMT_DESC_INT | ISMT_DESC_FAIR; + else + desc->control = ISMT_DESC_FAIR; + + if ((flags & I2C_CLIENT_PEC) && (size != I2C_SMBUS_QUICK) + && (size != I2C_SMBUS_I2C_BLOCK_DATA)) + desc->control |= ISMT_DESC_PEC; + + switch (size) { + case I2C_SMBUS_QUICK: + dev_dbg(dev, "I2C_SMBUS_QUICK\n"); + break; + + case I2C_SMBUS_BYTE: + if (read_write == I2C_SMBUS_WRITE) { + /* + * Send Byte + * The command field contains the write data + */ + dev_dbg(dev, "I2C_SMBUS_BYTE: WRITE\n"); + desc->control |= ISMT_DESC_CWRL; + desc->wr_len_cmd = command; + } else { + /* Receive Byte */ + dev_dbg(dev, "I2C_SMBUS_BYTE: READ\n"); + dma_size = 1; + dma_direction = DMA_FROM_DEVICE; + desc->rd_len = 1; + } + break; + + case I2C_SMBUS_BYTE_DATA: + if (read_write == I2C_SMBUS_WRITE) { + /* + * Write Byte + * Command plus 1 data byte + */ + dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: WRITE\n"); + desc->wr_len_cmd = 2; + dma_size = 2; + dma_direction = DMA_TO_DEVICE; + dma_buffer[0] = command; + dma_buffer[1] = data->byte; + } else { + /* Read Byte */ + dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: READ\n"); + desc->control |= ISMT_DESC_CWRL; + desc->wr_len_cmd = command; + desc->rd_len = 1; + dma_size = 1; + dma_direction = DMA_FROM_DEVICE; + } + break; + + case I2C_SMBUS_WORD_DATA: + if (read_write == I2C_SMBUS_WRITE) { + /* Write Word */ + dev_dbg(dev, "I2C_SMBUS_WORD_DATA: WRITE\n"); + desc->wr_len_cmd = 3; + dma_size = 3; + dma_direction = DMA_TO_DEVICE; + dma_buffer[0] = command; + dma_buffer[1] = data->word & 0xff; + dma_buffer[2] = data->word >> 8; + } else { + /* Read Word */ + dev_dbg(dev, "I2C_SMBUS_WORD_DATA: READ\n"); + desc->wr_len_cmd = command; + desc->control |= ISMT_DESC_CWRL; + desc->rd_len = 2; + dma_size = 2; + dma_direction = DMA_FROM_DEVICE; + } + break; + + case I2C_SMBUS_PROC_CALL: + dev_dbg(dev, "I2C_SMBUS_PROC_CALL\n"); + desc->wr_len_cmd = 3; + desc->rd_len = 2; + dma_size = 3; + dma_direction = DMA_BIDIRECTIONAL; + dma_buffer[0] = command; + dma_buffer[1] = data->word & 0xff; + dma_buffer[2] = data->word >> 8; + break; + + case I2C_SMBUS_BLOCK_DATA: + if (read_write == I2C_SMBUS_WRITE) { + /* Block Write */ + dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: WRITE\n"); + dma_size = data->block[0] + 1; + dma_direction = DMA_TO_DEVICE; + desc->wr_len_cmd = dma_size; + desc->control |= ISMT_DESC_BLK; + dma_buffer[0] = command; + memcpy(&dma_buffer[1], &data->block[1], dma_size - 1); + } else { + /* Block Read */ + dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: READ\n"); + dma_size = I2C_SMBUS_BLOCK_MAX; + dma_direction = DMA_FROM_DEVICE; + desc->rd_len = dma_size; + desc->wr_len_cmd = command; + desc->control |= (ISMT_DESC_BLK | ISMT_DESC_CWRL); + } + break; + + case I2C_SMBUS_I2C_BLOCK_DATA: + /* Make sure the length is valid */ + if (data->block[0] < 1) + data->block[0] = 1; + + if (data->block[0] > I2C_SMBUS_BLOCK_MAX) + data->block[0] = I2C_SMBUS_BLOCK_MAX; + + if (read_write == I2C_SMBUS_WRITE) { + /* i2c Block Write */ + dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: WRITE\n"); + dma_size = data->block[0] + 1; + dma_direction = DMA_TO_DEVICE; + desc->wr_len_cmd = dma_size; + desc->control |= ISMT_DESC_I2C; + dma_buffer[0] = command; + memcpy(&dma_buffer[1], &data->block[1], dma_size - 1); + } else { + /* i2c Block Read */ + dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: READ\n"); + dma_size = data->block[0]; + dma_direction = DMA_FROM_DEVICE; + desc->rd_len = dma_size; + desc->wr_len_cmd = command; + desc->control |= (ISMT_DESC_I2C | ISMT_DESC_CWRL); + /* + * Per the "Table 15-15. I2C Commands", + * in the External Design Specification (EDS), + * (Document Number: 508084, Revision: 2.0), + * the _rw bit must be 0 + */ + desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, 0); + } + break; + + default: + dev_err(dev, "Unsupported transaction %d\n", + size); + return -EOPNOTSUPP; + } + + /* map the data buffer */ + if (dma_size != 0) { + dev_dbg(dev, " dev=%p\n", dev); + dev_dbg(dev, " data=%p\n", data); + dev_dbg(dev, " dma_buffer=%p\n", dma_buffer); + dev_dbg(dev, " dma_size=%d\n", dma_size); + dev_dbg(dev, " dma_direction=%d\n", dma_direction); + + dma_addr = dma_map_single(dev, + dma_buffer, + dma_size, + dma_direction); + + if (dma_mapping_error(dev, dma_addr)) { + dev_err(dev, "Error in mapping dma buffer %p\n", + dma_buffer); + return -EIO; + } + + dev_dbg(dev, " dma_addr = %pad\n", &dma_addr); + + desc->dptr_low = lower_32_bits(dma_addr); + desc->dptr_high = upper_32_bits(dma_addr); + } + + reinit_completion(&priv->cmp); + + /* Add the descriptor */ + ismt_submit_desc(priv); + + /* Now we wait for interrupt completion, 1s */ + time_left = wait_for_completion_timeout(&priv->cmp, HZ*1); + + /* unmap the data buffer */ + if (dma_size != 0) + dma_unmap_single(dev, dma_addr, dma_size, dma_direction); + + if (unlikely(!time_left)) { + dev_warn(dev, "completion wait timed out:addr[%d-0x%x], read_write[%d], command[0x%x], size[%d]\n", + adap->nr, addr, read_write, command, size); + ismt_reset_dma(priv); + ret = -ETIMEDOUT; + priv->head = 0; + return ret; + } + + /* do any post processing of the descriptor here */ + ret = ismt_process_desc(desc, data, priv, size, read_write); + /* Update the ring pointer */ + priv->head++; + priv->head %= ISMT_DESC_ENTRIES; + + return ret; +} + +/** + * ismt_func() - report which i2c commands are supported by this adapter + * @adap: the i2c host adapter + */ +static u32 ismt_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_QUICK | + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_PROC_CALL | + I2C_FUNC_SMBUS_BLOCK_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK | + I2C_FUNC_SMBUS_PEC; +} + +static const struct i2c_algorithm smbus_algorithm = { + .smbus_xfer = ismt_access, + .functionality = ismt_func, +}; + +/** + * ismt_handle_isr() - interrupt handler bottom half + * @priv: iSMT private data + */ +static irqreturn_t ismt_handle_isr(struct ismt_priv *priv) +{ + complete(&priv->cmp); + + return IRQ_HANDLED; +} + +/** + * ismt_do_interrupt() - IRQ interrupt handler + * @vec: interrupt vector + * @data: iSMT private data + */ +static irqreturn_t ismt_do_interrupt(int vec, void *data) +{ + u32 val; + struct ismt_priv *priv = data; + + /* + * check to see it's our interrupt, return IRQ_NONE if not ours + * since we are sharing interrupt + */ + val = readl(priv->smba + ISMT_MSTR_MSTS); + + if (!(val & (ISMT_MSTS_MIS | ISMT_MSTS_MEIS))) + return IRQ_NONE; + else + writel(val | ISMT_MSTS_MIS | ISMT_MSTS_MEIS, + priv->smba + ISMT_MSTR_MSTS); + + return ismt_handle_isr(priv); +} + +/** + * ismt_do_msi_interrupt() - MSI interrupt handler + * @vec: interrupt vector + * @data: iSMT private data + */ +static irqreturn_t ismt_do_msi_interrupt(int vec, void *data) +{ + return ismt_handle_isr(data); +} + +/** + * ismt_hw_init() - initialize the iSMT hardware + * @priv: iSMT private data + */ +static void ismt_hw_init(struct ismt_priv *priv) +{ + u32 val; + struct device *dev = &priv->pci_dev->dev; + + /* initialize the Master Descriptor Base Address (MDBA) */ + writeq(priv->io_rng_dma, priv->smba + ISMT_MSTR_MDBA); + + /* initialize the Master Control Register (MCTRL) */ + writel(ISMT_MCTRL_MEIE, priv->smba + ISMT_MSTR_MCTRL); + + /* initialize the Master Status Register (MSTS) */ + writel(0, priv->smba + ISMT_MSTR_MSTS); + + /* initialize the Master Descriptor Size (MDS) */ + val = readl(priv->smba + ISMT_MSTR_MDS); + writel((val & ~ISMT_MDS_MASK) | (ISMT_DESC_ENTRIES - 1), + priv->smba + ISMT_MSTR_MDS); + + /* + * Set the SMBus speed (could use this for slow HW debuggers) + */ + + val = readl(priv->smba + ISMT_SPGT); + + switch (bus_speed) { + case 0: + break; + + case 80: + dev_dbg(dev, "Setting SMBus clock to 80 kHz\n"); + writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_80K), + priv->smba + ISMT_SPGT); + break; + + case 100: + dev_dbg(dev, "Setting SMBus clock to 100 kHz\n"); + writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_100K), + priv->smba + ISMT_SPGT); + break; + + case 400: + dev_dbg(dev, "Setting SMBus clock to 400 kHz\n"); + writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_400K), + priv->smba + ISMT_SPGT); + break; + + case 1000: + dev_dbg(dev, "Setting SMBus clock to 1000 kHz\n"); + writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_1M), + priv->smba + ISMT_SPGT); + break; + + default: + dev_warn(dev, "Invalid SMBus clock speed, only 0, 80, 100, 400, and 1000 are valid\n"); + break; + } + + val = readl(priv->smba + ISMT_SPGT); + + switch (val & ISMT_SPGT_SPD_MASK) { + case ISMT_SPGT_SPD_80K: + bus_speed = 80; + break; + case ISMT_SPGT_SPD_100K: + bus_speed = 100; + break; + case ISMT_SPGT_SPD_400K: + bus_speed = 400; + break; + case ISMT_SPGT_SPD_1M: + bus_speed = 1000; + break; + } + dev_info(dev, "SMBus clock is running at %d kHz with delay %d us\n", bus_speed, delay); +} + +/** + * ismt_dev_init() - initialize the iSMT data structures + * @priv: iSMT private data + */ +static int ismt_dev_init(struct ismt_priv *priv) +{ + /* allocate memory for the descriptor */ + priv->hw = dmam_alloc_coherent(&priv->pci_dev->dev, + (ISMT_DESC_ENTRIES + * sizeof(struct ismt_desc)), + &priv->io_rng_dma, + GFP_KERNEL); + if (!priv->hw) + return -ENOMEM; + + priv->head = 0; + init_completion(&priv->cmp); + + return 0; +} + +/** + * ismt_int_init() - initialize interrupts + * @priv: iSMT private data + */ +static int ismt_int_init(struct ismt_priv *priv) +{ + int err; + + /* Try using MSI interrupts */ + err = pci_enable_msi(priv->pci_dev); + if (err) + goto intx; + + err = devm_request_irq(&priv->pci_dev->dev, + priv->pci_dev->irq, + ismt_do_msi_interrupt, + 0, + "ismt-msi", + priv); + if (err) { + pci_disable_msi(priv->pci_dev); + goto intx; + } + + return 0; + + /* Try using legacy interrupts */ +intx: + dev_warn(&priv->pci_dev->dev, + "Unable to use MSI interrupts, falling back to legacy\n"); + + err = devm_request_irq(&priv->pci_dev->dev, + priv->pci_dev->irq, + ismt_do_interrupt, + IRQF_SHARED, + "ismt-intx", + priv); + if (err) { + dev_err(&priv->pci_dev->dev, "no usable interrupts\n"); + return err; + } + + return 0; +} + +static struct pci_driver ismt_driver; + +/** + * ismt_probe() - probe for iSMT devices + * @pdev: PCI-Express device + * @id: PCI-Express device ID + */ +static int +ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int err; + struct ismt_priv *priv; + unsigned long start, len; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + pci_set_drvdata(pdev, priv); + + i2c_set_adapdata(&priv->adapter, priv); + priv->adapter.owner = THIS_MODULE; + priv->adapter.class = I2C_CLASS_HWMON; + priv->adapter.algo = &smbus_algorithm; + priv->adapter.dev.parent = &pdev->dev; + ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev)); + priv->adapter.retries = ISMT_MAX_RETRIES; + + priv->pci_dev = pdev; + + err = pcim_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Failed to enable SMBus PCI device (%d)\n", + err); + return err; + } + + /* enable bus mastering */ + pci_set_master(pdev); + + /* Determine the address of the SMBus area */ + start = pci_resource_start(pdev, SMBBAR); + len = pci_resource_len(pdev, SMBBAR); + if (!start || !len) { + dev_err(&pdev->dev, + "SMBus base address uninitialized, upgrade BIOS\n"); + return -ENODEV; + } + + snprintf(priv->adapter.name, sizeof(priv->adapter.name), + "SMBus iSMT adapter at %lx", start); + + dev_dbg(&priv->pci_dev->dev, " start=0x%lX\n", start); + dev_dbg(&priv->pci_dev->dev, " len=0x%lX\n", len); + + err = acpi_check_resource_conflict(&pdev->resource[SMBBAR]); + if (err) { + dev_err(&pdev->dev, "ACPI resource conflict!\n"); + return err; + } + + err = pci_request_region(pdev, SMBBAR, ismt_driver.name); + if (err) { + dev_err(&pdev->dev, + "Failed to request SMBus region 0x%lx-0x%lx\n", + start, start + len); + return err; + } + + priv->smba = pcim_iomap(pdev, SMBBAR, len); + if (!priv->smba) { + dev_err(&pdev->dev, "Unable to ioremap SMBus BAR\n"); + return -ENODEV; + } + + if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) || + (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)) { + if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) || + (pci_set_consistent_dma_mask(pdev, + DMA_BIT_MASK(32)) != 0)) { + dev_err(&pdev->dev, "pci_set_dma_mask fail %p\n", + pdev); + return -ENODEV; + } + } + + err = ismt_dev_init(priv); + if (err) + return err; + + ismt_hw_init(priv); + + err = ismt_int_init(priv); + if (err) + return err; + + err = i2c_add_adapter(&priv->adapter); + if (err) + return -ENODEV; + dev_info(&pdev->dev, "wb-i2c-ismt probe ok.\n"); + return 0; +} + +/** + * ismt_remove() - release driver resources + * @pdev: PCI-Express device + */ +static void ismt_remove(struct pci_dev *pdev) +{ + struct ismt_priv *priv = pci_get_drvdata(pdev); + + i2c_del_adapter(&priv->adapter); +} + +static struct pci_driver ismt_driver = { + .name = "wb_ismt_smbus", + .id_table = ismt_ids, + .probe = ismt_probe, + .remove = ismt_remove, +}; + +module_pci_driver(ismt_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Bill E. Brown "); +MODULE_DESCRIPTION("Intel SMBus Message Transport (iSMT) driver"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.c new file mode 100644 index 000000000000..f318234ae90f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.c @@ -0,0 +1,1332 @@ +/* + * I2C multiplexer + * + * Copyright (c) 2008-2009 Rodolfo Giometti + * Copyright (c) 2008-2009 Eurotech S.p.A. + * + * This module supports the PCA954x series of I2C multiplexer/switch chips + * made by Philips Semiconductors. + * This includes the: + * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547 + * and PCA9548. + * + * These chips are all controlled via the I2C bus itself, and all have a + * single 8-bit register. The upstream "parent" bus fans out to two, + * four, or eight downstream busses or channels; which of these + * are selected is determined by the chip type and register contents. A + * mux can select only one sub-bus at a time; a switch can select any + * combination simultaneously. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_i2c_mux_pca954x.h" + +#define PCA954X_MAX_NCHANS 8 +#define PCA954X_IRQ_OFFSET 4 + +#define I2C_RETRY_TIMES 5 +#define I2C_RETRY_WAIT_TIMES 10 /*delay 10ms*/ + +typedef struct pca9548_cfg_info_s { + uint32_t pca9548_base_nr; + uint32_t pca9548_reset_type; + uint32_t rst_delay_b; /* delay time before reset(us) */ + uint32_t rst_delay; /* reset time(us) */ + uint32_t rst_delay_a; /* delay time after reset(us) */ + union { + i2c_attr_t i2c_attr; + gpio_attr_t gpio_attr; + io_attr_t io_attr; + file_attr_t file_attr; + } attr; + bool select_chan_check; + bool close_chan_force_reset; +} pca9548_cfg_info_t; + +int g_pca954x_debug = 0; +int g_pca954x_error = 0; + +module_param(g_pca954x_debug, int, S_IRUGO | S_IWUSR); +module_param(g_pca954x_error, int, S_IRUGO | S_IWUSR); + +#define PCA954X_DEBUG(fmt, args...) do { \ + if (g_pca954x_debug) { \ + printk(KERN_INFO "[PCA95x][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define PCA954X_ERROR(fmt, args...) do { \ + if (g_pca954x_error) { \ + printk(KERN_ERR "[PCA95x][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +extern int pca9641_setmuxflag(int nr, int flag); +enum pca_type { + pca_9540, + pca_9542, + pca_9543, + pca_9544, + pca_9545, + pca_9546, + pca_9547, + pca_9548, +}; + +struct chip_desc { + u8 nchans; + u8 enable; /* used for muxes only */ + u8 has_irq; + enum muxtype { + pca954x_ismux = 0, + pca954x_isswi + } muxtype; +}; + +struct pca954x { + const struct chip_desc *chip; + u8 last_chan; /* last register value */ + u8 deselect; + struct i2c_client *client; + struct irq_domain *irq; + unsigned int irq_mask; + raw_spinlock_t lock; + pca9548_cfg_info_t pca9548_cfg_info; /* pca9548 reset cfg */ +}; + +/* Provide specs for the PCA954x types we know about */ +static const struct chip_desc chips[] = { + [pca_9540] = { + .nchans = 2, + .enable = 0x4, + .muxtype = pca954x_ismux, + }, + [pca_9542] = { + .nchans = 2, + .enable = 0x4, + .has_irq = 1, + .muxtype = pca954x_ismux, + }, + [pca_9543] = { + .nchans = 2, + .has_irq = 1, + .muxtype = pca954x_isswi, + }, + [pca_9544] = { + .nchans = 4, + .enable = 0x4, + .has_irq = 1, + .muxtype = pca954x_ismux, + }, + [pca_9545] = { + .nchans = 4, + .has_irq = 1, + .muxtype = pca954x_isswi, + }, + [pca_9546] = { + .nchans = 4, + .muxtype = pca954x_isswi, + }, + [pca_9547] = { + .nchans = 8, + .enable = 0x8, + .muxtype = pca954x_ismux, + }, + [pca_9548] = { + .nchans = 8, + .muxtype = pca954x_isswi, + }, +}; + +static const struct i2c_device_id pca954x_id[] = { + { "wb_pca9540", pca_9540 }, + { "wb_pca9542", pca_9542 }, + { "wb_pca9543", pca_9543 }, + { "wb_pca9544", pca_9544 }, + { "wb_pca9545", pca_9545 }, + { "wb_pca9546", pca_9546 }, + { "wb_pca9547", pca_9547 }, + { "wb_pca9548", pca_9548 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pca954x_id); + +#ifdef CONFIG_OF +static const struct of_device_id pca954x_of_match[] = { + { .compatible = "nxp,wb_pca9540", .data = &chips[pca_9540] }, + { .compatible = "nxp,wb_pca9542", .data = &chips[pca_9542] }, + { .compatible = "nxp,wb_pca9543", .data = &chips[pca_9543] }, + { .compatible = "nxp,wb_pca9544", .data = &chips[pca_9544] }, + { .compatible = "nxp,wb_pca9545", .data = &chips[pca_9545] }, + { .compatible = "nxp,wb_pca9546", .data = &chips[pca_9546] }, + { .compatible = "nxp,wb_pca9547", .data = &chips[pca_9547] }, + { .compatible = "nxp,wb_pca9548", .data = &chips[pca_9548] }, + {} +}; +MODULE_DEVICE_TABLE(of, pca954x_of_match); +#endif + +/* 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 pca954x_reg_write(struct i2c_adapter *adap, + struct i2c_client *client, u8 val) +{ + int ret = -ENODEV; + + if (adap->algo->master_xfer) { + struct i2c_msg msg; + char buf[1]; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = 1; + buf[0] = val; + msg.buf = buf; + ret = __i2c_transfer(adap, &msg, 1); + + if (ret >= 0 && ret != 1) + ret = -EREMOTEIO; + } else { + union i2c_smbus_data data; + ret = adap->algo->smbus_xfer(adap, client->addr, + client->flags, + I2C_SMBUS_WRITE, + val, I2C_SMBUS_BYTE, &data); + } + return ret; +} + +static int pca954x_reg_read(struct i2c_adapter *adap, + struct i2c_client *client, u8 *val) +{ + int ret = -ENODEV; + u8 tmp_val; + + if (adap->algo->master_xfer) { + struct i2c_msg msg; + + msg.addr = client->addr; + msg.flags = I2C_M_RD; + msg.len = 1; + msg.buf = &tmp_val; + ret = __i2c_transfer(adap, &msg, 1); + + if (ret >= 0 && ret != 1) { + ret = -EREMOTEIO; + } else { + *val = tmp_val; + } + } else { + union i2c_smbus_data data; + ret = adap->algo->smbus_xfer(adap, client->addr, + client->flags, + I2C_SMBUS_READ, + 0, I2C_SMBUS_BYTE, &data); + + if (!ret) { + tmp_val = data.byte; + *val = tmp_val; + } + } + + return ret; +} + +static int pca954x_setmuxflag(struct i2c_client *client, int flag) +{ + int ret; + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + + ret = pca9641_setmuxflag(adap->nr, flag); + return ret; +} + +static int pca9548_gpio_init(gpio_attr_t *gpio_attr) +{ + int err; + + if (gpio_attr->gpio_init) { + PCA954X_DEBUG("gpio%d already init, do nothing.\n", gpio_attr->gpio); + return 0; + } + + PCA954X_DEBUG("gpio%d init.\n", gpio_attr->gpio); + err = gpio_request(gpio_attr->gpio, "pca9548_reset"); + if (err) { + goto error; + } + err = gpio_direction_output(gpio_attr->gpio, gpio_attr->reset_off); + if (err) { + gpio_free(gpio_attr->gpio); + goto error; + } + gpio_attr->gpio_init = 1; + return 0; +error: + PCA954X_ERROR("pca9548_gpio_init failed, ret:%d.\n", err); + return err; +} + +static void pca9548_gpio_free(gpio_attr_t *gpio_attr) +{ + if (gpio_attr->gpio_init == 1) { + PCA954X_DEBUG("gpio%d release.\n", gpio_attr->gpio); + gpio_free(gpio_attr->gpio); + gpio_attr->gpio_init = 0; + } +} + +static int pca954x_reset_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + filp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(filp)) { + PCA954X_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + ret = kernel_read(filp, val, size, &tmp_pos); + if (ret < 0) { + PCA954X_ERROR("kernel_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int pca954x_reset_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + filp = filp_open(path, O_RDWR, 777); + if (IS_ERR(filp)) { + PCA954X_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + ret = kernel_write(filp, val, size, &tmp_pos); + if (ret < 0) { + PCA954X_ERROR("kernel_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + vfs_fsync(filp, 1); + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int pca954x_reset_i2c_read(uint32_t bus, uint32_t addr, uint32_t offset_addr, + unsigned char *buf, uint32_t size) +{ + struct file *fp; + struct i2c_client client; + char i2c_path[32]; + int i ,j ; + int rv; + + rv = 0; + mem_clear(i2c_path, sizeof(i2c_path)); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); + fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); + if (IS_ERR(fp)) { + PCA954X_ERROR("i2c open fail.\n"); + return -1; + } + memcpy(&client, fp->private_data, sizeof(struct i2c_client)); + client.addr = addr; + for (j = 0 ;j < size ;j++) { + for (i = 0; i < I2C_RETRY_TIMES; i++) { + rv = i2c_smbus_read_byte_data(&client, (offset_addr + j)); + if (rv < 0) { + PCA954X_ERROR("i2c read failed, try again.\n"); + msleep(I2C_RETRY_WAIT_TIMES); + if (i >= (I2C_RETRY_TIMES - 1)) { + goto out; + } + continue; + } + *(buf + j) = (unsigned char)rv; + break; + } + } +out: + filp_close(fp, NULL); + return rv; +} + +static int pca954x_reset_i2c_write(uint32_t bus, uint32_t dev_addr, uint32_t offset_addr, + uint8_t write_buf) +{ + struct file *fp; + struct i2c_client client; + char i2c_path[32]; + int i; + int rv; + + rv = 0; + mem_clear(i2c_path, sizeof(i2c_path)); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); + fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); + if (IS_ERR(fp)) { + PCA954X_ERROR("i2c open fail.\n"); + return -1; + } + memcpy(&client, fp->private_data, sizeof(struct i2c_client)); + client.addr = dev_addr; + for (i = 0; i < I2C_RETRY_TIMES; i++) { + rv = i2c_smbus_write_byte_data(&client, offset_addr, write_buf); + if (rv < 0) { + PCA954X_ERROR("i2c write failed, try again.\n"); + msleep(I2C_RETRY_WAIT_TIMES); + if (i >= (I2C_RETRY_TIMES - 1)) { + goto out; + } + continue; + } + break; + } +out: + filp_close(fp, NULL); + return rv; +} + +static int pca954x_do_file_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout, err; + struct pca954x *data; + pca9548_cfg_info_t *reset_cfg; + file_attr_t *file_attr; + u8 val; + int udelay_cnt; + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9548_cfg_info; + file_attr = &reset_cfg->attr.file_attr; + ret = -1; + + PCA954X_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", + reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); + PCA954X_DEBUG("dev_name:%s, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + file_attr->dev_name, file_attr->offset, file_attr->mask, + file_attr->reset_on, file_attr->reset_off); + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + err = pca954x_reset_file_read(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + val &= ~(file_attr->mask); + val |= file_attr->reset_on; + err = pca954x_reset_file_write(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + val &= ~(file_attr->mask); + val |= file_attr->reset_off; + err = pca954x_reset_file_write(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + err = pca954x_reset_file_read(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + val &= (file_attr->mask); + if (val == file_attr->reset_off) { + ret = 0; + PCA954X_DEBUG("pca954x_do_file_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + if (ret < 0) { + PCA954X_ERROR("pca954x_do_file_reset timeout.\n"); + } +out: + if (err < 0) { + PCA954X_ERROR("pca954x_do_file_reset file rd/wr failed, ret:%d.\n", err); + } + + return ret; +} + +static int pca954x_do_io_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout; + struct pca954x *data; + pca9548_cfg_info_t *reset_cfg; + io_attr_t *io_attr; + u8 val; + int udelay_cnt; + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9548_cfg_info; + io_attr = &reset_cfg->attr.io_attr; + + PCA954X_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", + reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); + PCA954X_DEBUG("io_addr:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + io_attr->io_addr, io_attr->mask, io_attr->reset_on, io_attr->reset_off); + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + val = inb(io_attr->io_addr); + val &= ~(io_attr->mask); + val |= io_attr->reset_on; + outb(val, io_attr->io_addr); + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + val &= ~(io_attr->mask); + val |= io_attr->reset_off; + outb(val, io_attr->io_addr); + + ret = -1; + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + val = inb(io_attr->io_addr); + val &= (io_attr->mask); + if (val == io_attr->reset_off) { + ret = 0; + PCA954X_DEBUG("pca954x_do_io_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + + if (ret < 0) { + PCA954X_ERROR("pca954x_do_io_reset timeout.\n"); + } + + return ret; +} + +static int pca954x_do_gpio_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout; + struct pca954x *data; + pca9548_cfg_info_t *reset_cfg; + gpio_attr_t *gpio_attr; + u8 val; + int udelay_cnt; + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9548_cfg_info; + gpio_attr = &reset_cfg->attr.gpio_attr; + + ret = pca9548_gpio_init(gpio_attr); + if (ret) { + return -1; + } + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + /* reset on */ + __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_on); + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + /* reset off */ + __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_off); + ret = -1; + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + val = __gpio_get_value(gpio_attr->gpio); + if (val == gpio_attr->reset_off) { + ret = 0; + PCA954X_DEBUG("pca954x_do_gpio_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + + if (ret < 0) { + PCA954X_ERROR("pca954x_do_gpio_reset timeout.\n"); + } + + pca9548_gpio_free(gpio_attr); + return ret; +} + +static int pca954x_do_i2c_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout, err; + struct pca954x *data; + pca9548_cfg_info_t *reset_cfg; + i2c_attr_t *i2c_attr; + u8 val; + int udelay_cnt; + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9548_cfg_info; + i2c_attr = &reset_cfg->attr.i2c_attr; + ret = -1; + + PCA954X_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", + reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); + PCA954X_DEBUG("bus:0x%x, addr:0x%x, reg:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + i2c_attr->i2c_bus, i2c_attr->i2c_addr, i2c_attr->reg_offset, + i2c_attr->mask, i2c_attr->reset_on, i2c_attr->reset_off); + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + err = pca954x_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + val &= ~(i2c_attr->mask); + val |= i2c_attr->reset_on; + err = pca954x_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, val); + if (err < 0) { + goto out; + } + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + val &= ~(i2c_attr->mask); + val |= i2c_attr->reset_off; + err = pca954x_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, val); + if (err < 0) { + goto out; + } + + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + err = pca954x_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + val &= (i2c_attr->mask); + if (val == i2c_attr->reset_off) { + ret = 0; + PCA954X_DEBUG("pca954x_do_i2c_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + if (ret < 0) { + PCA954X_ERROR("pca954x_do_i2c_reset timeout.\n"); + } +out: + if (err < 0) { + PCA954X_ERROR("pca954x_do_i2c_reset i2c op failed, ret:%d.\n", err); + } + return ret; +} + +static int pca954x_do_reset(struct i2c_mux_core *muxc) +{ + int ret; + struct pca954x *data; + + data = i2c_mux_priv(muxc); + if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_NONE) { + ret = -1; + PCA954X_DEBUG("Don't need to reset.\n"); + } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_I2C) { + ret = pca954x_do_i2c_reset(muxc); + } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_GPIO) { + ret = pca954x_do_gpio_reset(muxc); + } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_IO) { + ret = pca954x_do_io_reset(muxc); + } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_FILE) { + ret = pca954x_do_file_reset(muxc); + } else { + ret = -1; + PCA954X_ERROR("Unsupport reset type:0x%x.\n", + data->pca9548_cfg_info.pca9548_reset_type); + } + + if (ret < 0) { + PCA954X_ERROR("pca9548_reset_ctrl failed, reset type:%u, ret:%d.\n", + data->pca9548_cfg_info.pca9548_reset_type, ret); + } + return ret; +} + +static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca954x *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + const struct chip_desc *chip = data->chip; + u8 regval; + int ret = 0; + u8 read_val = 0; + int rv; + + /* we make switches look like muxes, not sure how to be smarter */ + if (chip->muxtype == pca954x_ismux) + regval = chan | chip->enable; + else + regval = 1 << chan; + + /* Only select the channel if its different from the last channel */ + if (data->last_chan != regval) { + pca954x_setmuxflag(client, 0); + ret = pca954x_reg_write(muxc->parent, client, regval); + data->last_chan = ret < 0 ? 0 : regval; + } + + if (data->pca9548_cfg_info.select_chan_check) { /* check chan */ + ret = pca954x_reg_read(muxc->parent, client, &read_val); + /* read failed or chan not open, reset pca9548 */ + if ((ret < 0) || (read_val != data->last_chan)) { + dev_warn(&client->dev, "pca954x open channle %u failed, do reset.\n", chan); + PCA954X_DEBUG("ret = %d, read_val = %d, last_chan = %d.\n", ret, read_val, data->last_chan); + rv = pca954x_do_reset(muxc); + if (rv >= 0) { + PCA954X_DEBUG("pca954x_do_reset success, rv = %d.\n", rv); + } else { + PCA954X_DEBUG("pca954x_do_reset failed, rv = %d.\n", rv); + } + if (ret >= 0) { + ret = -EIO; /* chan not match, return IO error */ + } + } + } + + return ret; +} + +static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca954x *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + int ret, rv; + + /* Deselect active channel */ + data->last_chan = 0; + if (data->pca9548_cfg_info.close_chan_force_reset) { + ret = pca954x_do_reset(muxc); + } else { + ret = pca954x_reg_write(muxc->parent, client, data->last_chan); + if (ret < 0 ) { + dev_warn(&client->dev, "pca954x close channel %u failed, do reset.\n", chan); + rv = pca954x_do_reset(muxc); + if (rv == 0) { + ret = 0; + } + } + } + + rv = pca954x_setmuxflag(client, 1); + if (rv == 0) { + PCA954X_DEBUG("match 9641, close 9548 channel to deselect 9641.\n"); + (void)pca954x_reg_write(muxc->parent, client, data->last_chan); + } else { + PCA954X_DEBUG("dismatch 9641, do nothing.\n"); + } + + return ret; + +} + +static irqreturn_t pca954x_irq_handler(int irq, void *dev_id) +{ + struct pca954x *data = dev_id; + unsigned int child_irq; + int ret, i, handled = 0; + + ret = i2c_smbus_read_byte(data->client); + if (ret < 0) + return IRQ_NONE; + + for (i = 0; i < data->chip->nchans; i++) { + if (ret & BIT(PCA954X_IRQ_OFFSET + i)) { + child_irq = irq_linear_revmap(data->irq, i); + handle_nested_irq(child_irq); + handled++; + } + } + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +static void pca954x_irq_mask(struct irq_data *idata) +{ + struct pca954x *data = irq_data_get_irq_chip_data(idata); + unsigned int pos = idata->hwirq; + unsigned long flags; + + raw_spin_lock_irqsave(&data->lock, flags); + + data->irq_mask &= ~BIT(pos); + if (!data->irq_mask) + disable_irq(data->client->irq); + + raw_spin_unlock_irqrestore(&data->lock, flags); +} + +static void pca954x_irq_unmask(struct irq_data *idata) +{ + struct pca954x *data = irq_data_get_irq_chip_data(idata); + unsigned int pos = idata->hwirq; + unsigned long flags; + + raw_spin_lock_irqsave(&data->lock, flags); + + if (!data->irq_mask) + enable_irq(data->client->irq); + data->irq_mask |= BIT(pos); + + raw_spin_unlock_irqrestore(&data->lock, flags); +} + +static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) +{ + if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_LOW) + return -EINVAL; + return 0; +} + +static struct irq_chip pca954x_irq_chip = { + .name = "i2c-mux-pca954x", + .irq_mask = pca954x_irq_mask, + .irq_unmask = pca954x_irq_unmask, + .irq_set_type = pca954x_irq_set_type, +}; + +static int of_pca954x_irq_setup(struct i2c_mux_core *muxc) +{ + struct pca954x *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + int c, err, irq; + + if (!data->chip->has_irq || client->irq <= 0) + return 0; + + raw_spin_lock_init(&data->lock); + + data->irq = irq_domain_add_linear(client->dev.of_node, + data->chip->nchans, + &irq_domain_simple_ops, data); + if (!data->irq) + return -ENODEV; + + for (c = 0; c < data->chip->nchans; c++) { + irq = irq_create_mapping(data->irq, c); + irq_set_chip_data(irq, data); + irq_set_chip_and_handler(irq, &pca954x_irq_chip, + handle_simple_irq); + } + + err = devm_request_threaded_irq(&client->dev, data->client->irq, NULL, + pca954x_irq_handler, + IRQF_ONESHOT | IRQF_SHARED, + "pca954x", data); + if (err) + goto err_req_irq; + + disable_irq(data->client->irq); + + return 0; +err_req_irq: + for (c = 0; c < data->chip->nchans; c++) { + irq = irq_find_mapping(data->irq, c); + irq_dispose_mapping(irq); + } + irq_domain_remove(data->irq); + + return err; +} + +static int pca954x_irq_setup(struct i2c_mux_core *muxc) +{ + return 0; +} + +static int of_pca954x_reset_data_init(struct pca954x *data) +{ + int err; + struct device *dev = &data->client->dev; + pca9548_cfg_info_t *reset_cfg; + + reset_cfg = &data->pca9548_cfg_info; + if (dev == NULL || dev->of_node == NULL) { + PCA954X_DEBUG("dev or dev->of_node is NUll, no reset.\n"); + reset_cfg->pca9548_reset_type = PCA9548_RESET_NONE; + return 0; + } + + reset_cfg->select_chan_check = of_property_read_bool(dev->of_node, "select_chan_check"); + reset_cfg->close_chan_force_reset = of_property_read_bool(dev->of_node, "close_chan_force_reset"); + PCA954X_DEBUG("select_chan_check:%d, close_chan_force_reset:%d.\n", reset_cfg->select_chan_check, + reset_cfg->close_chan_force_reset); + + if (of_property_read_u32(dev->of_node, "pca9548_reset_type", &reset_cfg->pca9548_reset_type)) { + + PCA954X_DEBUG("pca9548_reset_type not found, no reset.\n"); + reset_cfg->pca9548_reset_type = PCA9548_RESET_NONE; + return 0; + } + err = of_property_read_u32(dev->of_node, "rst_delay_b", &reset_cfg->rst_delay_b); + err |= of_property_read_u32(dev->of_node, "rst_delay", &reset_cfg->rst_delay); + err |= of_property_read_u32(dev->of_node, "rst_delay_a", &reset_cfg->rst_delay_a); + + if (err) { + goto dts_config_err; + } + PCA954X_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", + reset_cfg->pca9548_reset_type, reset_cfg->rst_delay_b, + reset_cfg->rst_delay, reset_cfg->rst_delay_a); + + if (reset_cfg->pca9548_reset_type == PCA9548_RESET_I2C) { + + PCA954X_DEBUG("reset by i2c.\n"); + err = of_property_read_u32(dev->of_node, "i2c_bus", &reset_cfg->attr.i2c_attr.i2c_bus); + err |=of_property_read_u32(dev->of_node, "i2c_addr", &reset_cfg->attr.i2c_attr.i2c_addr); + err |=of_property_read_u32(dev->of_node, "reg_offset", &reset_cfg->attr.i2c_attr.reg_offset); + err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.i2c_attr.mask); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.i2c_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.i2c_attr.reset_off); + if (err) { + goto dts_config_err; + } + PCA954X_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, + reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, + reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); + } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_GPIO) { + + PCA954X_DEBUG("reset by gpio.\n"); + err = of_property_read_u32(dev->of_node, "gpio", &reset_cfg->attr.gpio_attr.gpio); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.gpio_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.gpio_attr.reset_off); + if (err) { + goto dts_config_err; + } + PCA954X_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, + reset_cfg->attr.gpio_attr.reset_off); + reset_cfg->attr.gpio_attr.gpio_init = 0; + } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_IO) { + + PCA954X_DEBUG("reset by io.\n"); + err = of_property_read_u32(dev->of_node, "io_addr", &reset_cfg->attr.io_attr.io_addr); + err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.io_attr.mask); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.io_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.io_attr.reset_off); + if (err) { + goto dts_config_err; + } + PCA954X_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, + reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); + } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_FILE) { + + PCA954X_DEBUG("reset by file.\n"); + err = of_property_read_string(dev->of_node, "dev_name", &reset_cfg->attr.file_attr.dev_name); + err |=of_property_read_u32(dev->of_node, "offset", &reset_cfg->attr.file_attr.offset); + err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.file_attr.mask); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.file_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.file_attr.reset_off); + if (err) { + goto dts_config_err; + } + PCA954X_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, + reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off); + } else { + PCA954X_ERROR("Unsupport reset type:%d.\n", reset_cfg->pca9548_reset_type); + goto dts_config_err; + } + return 0; +dts_config_err: + PCA954X_ERROR("dts config error, ret:%d.\n", err); + return -EINVAL; +} + +static int pca954x_reset_data_init(struct pca954x *data) +{ + pca9548_cfg_info_t *reset_cfg; + i2c_mux_pca954x_device_t *i2c_mux_pca954x_device; + + if (data->client->dev.platform_data == NULL) { + PCA954X_DEBUG("pca954x has no reset platform data config.\n"); + return 0; + } + reset_cfg = &data->pca9548_cfg_info; + i2c_mux_pca954x_device = data->client->dev.platform_data; + reset_cfg->select_chan_check = i2c_mux_pca954x_device->select_chan_check; + reset_cfg->close_chan_force_reset = i2c_mux_pca954x_device->close_chan_force_reset; + PCA954X_DEBUG("select_chan_check:%d, close_chan_force_reset:%d.\n", reset_cfg->select_chan_check, + reset_cfg->close_chan_force_reset); + + reset_cfg->pca9548_reset_type = i2c_mux_pca954x_device->pca9548_reset_type; + if (reset_cfg->pca9548_reset_type == PCA9548_RESET_NONE) { + PCA954X_DEBUG("pca9548_reset_type not found, no reset.\n"); + return 0; + } + + reset_cfg->rst_delay_b = i2c_mux_pca954x_device->rst_delay_b; + reset_cfg->rst_delay = i2c_mux_pca954x_device->rst_delay; + reset_cfg->rst_delay_a = i2c_mux_pca954x_device->rst_delay_a; + PCA954X_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", + reset_cfg->pca9548_reset_type, reset_cfg->rst_delay_b, + reset_cfg->rst_delay, reset_cfg->rst_delay_a); + + if (reset_cfg->pca9548_reset_type == PCA9548_RESET_I2C) { + + PCA954X_DEBUG("reset by i2c.\n"); + reset_cfg->attr.i2c_attr.i2c_bus = i2c_mux_pca954x_device->attr.i2c_attr.i2c_bus; + reset_cfg->attr.i2c_attr.i2c_addr = i2c_mux_pca954x_device->attr.i2c_attr.i2c_addr; + reset_cfg->attr.i2c_attr.reg_offset = i2c_mux_pca954x_device->attr.i2c_attr.reg_offset; + reset_cfg->attr.i2c_attr.mask = i2c_mux_pca954x_device->attr.i2c_attr.mask; + reset_cfg->attr.i2c_attr.reset_on = i2c_mux_pca954x_device->attr.i2c_attr.reset_on; + reset_cfg->attr.i2c_attr.reset_off = i2c_mux_pca954x_device->attr.i2c_attr.reset_off; + PCA954X_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, + reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, + reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); + } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_GPIO) { + + PCA954X_DEBUG("reset by gpio.\n"); + reset_cfg->attr.gpio_attr.gpio = i2c_mux_pca954x_device->attr.gpio_attr.gpio; + reset_cfg->attr.gpio_attr.reset_on = i2c_mux_pca954x_device->attr.gpio_attr.reset_on; + reset_cfg->attr.gpio_attr.reset_off = i2c_mux_pca954x_device->attr.gpio_attr.reset_off; + PCA954X_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, + reset_cfg->attr.gpio_attr.reset_off); + reset_cfg->attr.gpio_attr.gpio_init = 0; + } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_IO) { + + PCA954X_DEBUG("reset by io.\n"); + reset_cfg->attr.io_attr.io_addr = i2c_mux_pca954x_device->attr.io_attr.io_addr; + reset_cfg->attr.io_attr.mask = i2c_mux_pca954x_device->attr.io_attr.mask; + reset_cfg->attr.io_attr.reset_on = i2c_mux_pca954x_device->attr.io_attr.reset_on; + reset_cfg->attr.io_attr.reset_off = i2c_mux_pca954x_device->attr.io_attr.reset_off; + PCA954X_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, + reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); + } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_FILE) { + + reset_cfg->attr.file_attr.dev_name = i2c_mux_pca954x_device->attr.file_attr.dev_name; + reset_cfg->attr.file_attr.offset = i2c_mux_pca954x_device->attr.file_attr.offset; + reset_cfg->attr.file_attr.mask = i2c_mux_pca954x_device->attr.file_attr.mask; + reset_cfg->attr.file_attr.reset_on = i2c_mux_pca954x_device->attr.file_attr.reset_on; + reset_cfg->attr.file_attr.reset_off = i2c_mux_pca954x_device->attr.file_attr.reset_off; + PCA954X_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, + reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off); + } else { + PCA954X_ERROR("Unsupport reset type:%d.\n", reset_cfg->pca9548_reset_type); + return -EINVAL; + } + return 0; +} + +/* + * I2C init/probing/exit functions + */ +static int pca954x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + struct device_node *of_node = client->dev.of_node; + bool idle_disconnect_dt; + struct gpio_desc *gpio; + int num, force, class; + struct i2c_mux_core *muxc; + struct pca954x *data; + const struct of_device_id *match; + unsigned int probe_disable; + int ret, dynamic_nr; + i2c_mux_pca954x_device_t *i2c_mux_pca954x_device; + + PCA954X_DEBUG("pca954x_probe, parent bus: %d, 9548 addr:0x%x.\n", adap->nr, client->addr); + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) + return -ENODEV; + + muxc = i2c_mux_alloc(adap, &client->dev, + PCA954X_MAX_NCHANS, sizeof(*data), 0, + pca954x_select_chan, pca954x_deselect_mux); + if (!muxc) + return -ENOMEM; + data = i2c_mux_priv(muxc); + + i2c_set_clientdata(client, muxc); + data->client = client; + + /* Get the mux out of reset if a reset GPIO is specified. */ + gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + + /* check device connection status */ + + if (client->dev.of_node == NULL) { + if (client->dev.platform_data == NULL) { + probe_disable = 1; + PCA954X_DEBUG("has no platform data config, set probe_disable = 1.\n"); + } else { + i2c_mux_pca954x_device = client->dev.platform_data; + probe_disable = i2c_mux_pca954x_device->probe_disable; + } + } else { + probe_disable = of_property_read_bool(of_node, "probe_disable"); + } + + /* Write the mux register at addr to verify + * that the mux is in fact present. This also + * initializes the mux to disconnected state. + */ + if (!probe_disable && (i2c_smbus_write_byte(client, 0) < 0)) { + dev_warn(&client->dev, "probe failed\n"); + return -ENODEV; + } + + match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); + if (match) + data->chip = of_device_get_match_data(&client->dev); + else + data->chip = &chips[id->driver_data]; + + data->last_chan = 0; /* force the first selection */ + + if (client->dev.of_node == NULL) { + idle_disconnect_dt = false; + } else { + idle_disconnect_dt = of_node && + of_property_read_bool(of_node, "i2c-mux-idle-disconnect"); + } + + if (client->dev.of_node) { + ret= of_pca954x_reset_data_init(data); + } else { + ret= pca954x_reset_data_init(data); + } + if (ret < 0) { + dev_err(&client->dev, "pca954x reset config err, ret:%d.\n", ret); + return ret; + } + + if (client->dev.of_node) { + ret = of_pca954x_irq_setup(muxc); + } else { + ret = pca954x_irq_setup(muxc); + } + if (ret) { + goto fail_del_adapters; + } + + if (client->dev.of_node == NULL) { + if (client->dev.platform_data == NULL) { + dynamic_nr = 1; + PCA954X_DEBUG("platform data is NULL, use dynamic adap number.\n"); + } else { + i2c_mux_pca954x_device = client->dev.platform_data; + data->pca9548_cfg_info.pca9548_base_nr = i2c_mux_pca954x_device->pca9548_base_nr; + if (data->pca9548_cfg_info.pca9548_base_nr == 0) { + dynamic_nr = 1; + PCA954X_DEBUG("pca9548_base_nr = 0, use dynamic adap number.\n"); + } else { + dynamic_nr = 0; + PCA954X_DEBUG("pca9548_base_nr:%u.\n", data->pca9548_cfg_info.pca9548_base_nr); + } + } + } else { + if (of_property_read_u32(of_node, "pca9548_base_nr", &data->pca9548_cfg_info.pca9548_base_nr)) { + + dynamic_nr = 1; + PCA954X_DEBUG("pca9548_base_nr not found, use dynamic adap number"); + } else { + dynamic_nr = 0; + PCA954X_DEBUG("pca9548_base_nr:%u.\n", data->pca9548_cfg_info.pca9548_base_nr); + } + } + + /* Now create an adapter for each channel */ + for (num = 0; num < data->chip->nchans; num++) { + bool idle_disconnect_pd = false; + if (dynamic_nr == 1) { + force = 0; /* dynamic adap number */ + } else { + force = data->pca9548_cfg_info.pca9548_base_nr + num; + } + + class = 0; /* no class by default */ + data->deselect |= (idle_disconnect_pd || + idle_disconnect_dt) << num; + + ret = i2c_mux_add_adapter(muxc, force, num, class); + if (ret) + goto fail_del_adapters; + } + + dev_info(&client->dev, + "registered %d multiplexed busses for I2C %s %s\n", + num, data->chip->muxtype == pca954x_ismux + ? "mux" : "switch", client->name); + + return 0; + +fail_del_adapters: + i2c_mux_del_adapters(muxc); + return ret; +} + +static int pca954x_remove(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct pca954x *data = i2c_mux_priv(muxc); + int c, irq; + + if (data->irq) { + for (c = 0; c < data->chip->nchans; c++) { + irq = irq_find_mapping(data->irq, c); + irq_dispose_mapping(irq); + } + irq_domain_remove(data->irq); + } + + i2c_mux_del_adapters(muxc); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int pca954x_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct pca954x *data = i2c_mux_priv(muxc); + + data->last_chan = 0; + return i2c_smbus_write_byte(client, 0); +} +#endif + +static SIMPLE_DEV_PM_OPS(pca954x_pm, NULL, pca954x_resume); + +static struct i2c_driver pca954x_driver = { + .driver = { + .name = "wb_pca954x", + .pm = &pca954x_pm, + .of_match_table = of_match_ptr(pca954x_of_match), + }, + .probe = pca954x_probe, + .remove = pca954x_remove, + .id_table = pca954x_id, +}; + +module_i2c_driver(pca954x_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("PCA954x I2C mux/switch driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.h new file mode 100644 index 000000000000..9cbe162782c5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.h @@ -0,0 +1,67 @@ +#ifndef __WB_I2C_MUX_PCA954X_H__ +#define __WB_I2C_MUX_PCA954X_H__ + +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +typedef enum pca9548_reset_type_s { + PCA9548_RESET_NONE = 0, + PCA9548_RESET_I2C = 1, + PCA9548_RESET_GPIO = 2, + PCA9548_RESET_IO = 3, + PCA9548_RESET_FILE = 4, +} pca9548_reset_type_t; + +typedef struct i2c_attr_s { + uint32_t i2c_bus; + uint32_t i2c_addr; + uint32_t reg_offset; + uint32_t mask; + uint32_t reset_on; + uint32_t reset_off; +} i2c_attr_t; + +typedef struct io_attr_s { + uint32_t io_addr; + uint32_t mask; + uint32_t reset_on; + uint32_t reset_off; +} io_attr_t; + +typedef struct file_attr_s { + const char *dev_name; + uint32_t offset; + uint32_t mask; + uint32_t reset_on; + uint32_t reset_off; +} file_attr_t; + +typedef struct gpio_attr_s { + int gpio_init; + uint32_t gpio; + uint32_t reset_on; + uint32_t reset_off; +} gpio_attr_t; + +typedef struct i2c_mux_pca954x_device_s { + struct i2c_client *client; + uint32_t i2c_bus; + uint32_t i2c_addr; + uint32_t pca9548_base_nr; + uint32_t pca9548_reset_type; + uint32_t rst_delay_b; /* delay time before reset(us) */ + uint32_t rst_delay; /* reset time(us) */ + uint32_t rst_delay_a; /* delay time after reset(us) */ + bool probe_disable; + bool select_chan_check; + bool close_chan_force_reset; + union { + i2c_attr_t i2c_attr; + gpio_attr_t gpio_attr; + io_attr_t io_attr; + file_attr_t file_attr; + } attr; +} i2c_mux_pca954x_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.c new file mode 100644 index 000000000000..c5b6a835ac9f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.c @@ -0,0 +1,1396 @@ +/* + * I2C multiplexer driver for PCA9541 bus master selector + * + * Copyright (c) 2010 Ericsson AB. + * + * Author: Guenter Roeck + * + * Derived from: + * pca954x.c + * + * Copyright (c) 2008-2009 Rodolfo Giometti + * Copyright (c) 2008-2009 Eurotech S.p.A. + * + * 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 +#include +#include + +#include "wb_i2c_mux_pca9641.h" + +/* + * The PCA9541 is a bus master selector. It supports two I2C masters connected + * to a single slave bus. + * + * Before each bus transaction, a master has to acquire bus ownership. After the + * transaction is complete, bus ownership has to be released. This fits well + * into the I2C multiplexer framework, which provides select and release + * functions for this purpose. For this reason, this driver is modeled as + * single-channel I2C bus multiplexer. + * + * This driver assumes that the two bus masters are controlled by two different + * hosts. If a single host controls both masters, platform code has to ensure + * that only one of the masters is instantiated at any given time. + */ + +#define PCA9541_CONTROL 0x01 +#define PCA9541_ISTAT 0x02 + +#define PCA9541_CTL_MYBUS (1 << 0) +#define PCA9541_CTL_NMYBUS (1 << 1) +#define PCA9541_CTL_BUSON (1 << 2) +#define PCA9541_CTL_NBUSON (1 << 3) +#define PCA9541_CTL_BUSINIT (1 << 4) +#define PCA9541_CTL_TESTON (1 << 6) +#define PCA9541_CTL_NTESTON (1 << 7) +#define PCA9541_ISTAT_INTIN (1 << 0) +#define PCA9541_ISTAT_BUSINIT (1 << 1) +#define PCA9541_ISTAT_BUSOK (1 << 2) +#define PCA9541_ISTAT_BUSLOST (1 << 3) +#define PCA9541_ISTAT_MYTEST (1 << 6) +#define PCA9541_ISTAT_NMYTEST (1 << 7) +#define PCA9641_ID 0x00 +#define PCA9641_ID_MAGIC 0x38 +#define PCA9641_CONTROL 0x01 +#define PCA9641_STATUS 0x02 +#define PCA9641_TIME 0x03 +#define PCA9641_CTL_LOCK_REQ BIT(0) +#define PCA9641_CTL_LOCK_GRANT BIT(1) +#define PCA9641_CTL_BUS_CONNECT BIT(2) +#define PCA9641_CTL_BUS_INIT BIT(3) +#define PCA9641_CTL_SMBUS_SWRST BIT(4) +#define PCA9641_CTL_IDLE_TIMER_DIS BIT(5) +#define PCA9641_CTL_SMBUS_DIS BIT(6) +#define PCA9641_CTL_PRIORITY BIT(7) +#define PCA9641_STS_OTHER_LOCK BIT(0) +#define PCA9641_STS_BUS_INIT_FAIL BIT(1) +#define PCA9641_STS_BUS_HUNG BIT(2) +#define PCA9641_STS_MBOX_EMPTY BIT(3) +#define PCA9641_STS_MBOX_FULL BIT(4) +#define PCA9641_STS_TEST_INT BIT(5) +#define PCA9641_STS_SCL_IO BIT(6) +#define PCA9641_STS_SDA_IO BIT(7) +#define PCA9641_RES_TIME 0x03 +#define BUSON (PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON) +#define MYBUS (PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS) +#define mybus(x) (!((x) & MYBUS) || ((x) & MYBUS) == MYBUS) +#define busoff(x) (!((x) & BUSON) || ((x) & BUSON) == BUSON) +#define BUSOFF(x, y) (!((x) & PCA9641_CTL_LOCK_GRANT) && \ + !((y) & PCA9641_STS_OTHER_LOCK)) +#define other_lock(x) ((x) & PCA9641_STS_OTHER_LOCK) +#define lock_grant(x) ((x) & PCA9641_CTL_LOCK_GRANT) + +#define PCA9641_RETRY_TIME (8) +#define PCA9641_RESET_DELAY (150) + +typedef struct i2c_muxs_struct_flag +{ + int nr; + char name[48]; + struct mutex update_lock; + int flag; +}i2c_mux_flag; + +i2c_mux_flag pca_flag = { + .nr = -1, + .flag = -1, +}; + +int pca9641_setmuxflag(int nr, int flag) +{ + if (pca_flag.nr == nr) { + pca_flag.flag = flag; + return 0; + } + return -1; +} +EXPORT_SYMBOL(pca9641_setmuxflag); + +static int g_debug_info = 0; +static int g_debug_err = 0; + +module_param(g_debug_info, int, S_IRUGO | S_IWUSR); +module_param(g_debug_err, int, S_IRUGO | S_IWUSR); + +#define PCA_DEBUG(fmt, args...) do { \ + if (g_debug_info) { \ + printk(KERN_INFO "[pca9641][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define PCA_DEBUG_ERR(fmt, args...) do { \ + if (g_debug_err) { \ + printk(KERN_ERR "[pca9641][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +/* arbitration timeouts, in jiffies */ +#define ARB_TIMEOUT (HZ / 8) /* 125 ms until forcing bus ownership */ +#define ARB2_TIMEOUT (HZ / 4) /* 250 ms until acquisition failure */ + +/* arbitration retry delays, in us */ +#define SELECT_DELAY_SHORT 50 +#define SELECT_DELAY_LONG 1000 +#define I2C_RETRY_TIMES (5) +#define I2C_RETRY_WAIT_TIMES (10) /*delay 10ms*/ + +typedef struct pca9641_cfg_info_s { + uint32_t pca9641_reset_type; + uint32_t rst_delay_b; /* delay time before reset(us) */ + uint32_t rst_delay; /* reset time(us) */ + uint32_t rst_delay_a; /* delay time after reset(us) */ + union { + i2c_attr_t i2c_attr; + gpio_attr_t gpio_attr; + io_attr_t io_attr; + file_attr_t file_attr; + } attr; +} pca9641_cfg_info_t; + +struct pca9541 { + struct i2c_client *client; + unsigned long select_timeout; + unsigned long arb_timeout; + uint32_t pca9641_nr; + pca9641_cfg_info_t pca9641_cfg_info; /* pca9641 reset cfg */ +}; + +static const struct i2c_device_id pca9541_id[] = { + {"wb_pca9541", 0}, + {"wb_pca9641", 1}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, pca9541_id); + +#ifdef CONFIG_OF +static const struct of_device_id pca9541_of_match[] = { + { .compatible = "nxp,wb_pca9541" }, + { .compatible = "nxp,wb_pca9641" }, + {} +}; +MODULE_DEVICE_TABLE(of, pca9541_of_match); +#endif + +static int pca9641_gpio_init(gpio_attr_t *gpio_attr) +{ + int err; + + if (gpio_attr->gpio_init) { + PCA_DEBUG("gpio%d already init, do nothing.\n", gpio_attr->gpio); + return 0; + } + + PCA_DEBUG("gpio%d init.\n", gpio_attr->gpio); + err = gpio_request(gpio_attr->gpio, "pca9641_reset"); + if (err) { + goto error; + } + err = gpio_direction_output(gpio_attr->gpio, gpio_attr->reset_off); + if (err) { + gpio_free(gpio_attr->gpio); + goto error; + } + gpio_attr->gpio_init = 1; + return 0; +error: + PCA_DEBUG_ERR("pca9641_gpio_init failed, ret:%d.\n", err); + return err; +} + +static void pca9641_gpio_free(gpio_attr_t *gpio_attr) +{ + if (gpio_attr->gpio_init == 1) { + PCA_DEBUG("gpio%d release.\n", gpio_attr->gpio); + gpio_free(gpio_attr->gpio); + gpio_attr->gpio_init = 0; + } + return; +} + +static int pca9641_reset_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + filp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(filp)) { + PCA_DEBUG_ERR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + ret = kernel_read(filp, val, size, &tmp_pos); + if (ret < 0) { + PCA_DEBUG_ERR("kernel_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int pca9641_reset_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + + int ret; + struct file *filp; + loff_t tmp_pos; + + filp = filp_open(path, O_RDWR, 777); + if (IS_ERR(filp)) { + PCA_DEBUG_ERR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + ret = kernel_write(filp, val, size, &tmp_pos); + if (ret < 0) { + PCA_DEBUG_ERR("kernel_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + vfs_fsync(filp, 1); + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int pca9641_reset_i2c_read(uint32_t bus, uint32_t addr, uint32_t offset_addr, + unsigned char *buf, uint32_t size) +{ + struct file *fp; + struct i2c_client client; + char i2c_path[32]; + int i, j; + int rv; + + rv = 0; + mem_clear(i2c_path, sizeof(i2c_path)); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); + fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); + if (IS_ERR(fp)) { + PCA_DEBUG_ERR("i2c open fail.\n"); + return -1; + } + memcpy(&client, fp->private_data, sizeof(struct i2c_client)); + client.addr = addr; + for (j = 0; j < size; j++) { + for (i = 0; i < I2C_RETRY_TIMES; i++) { + rv = i2c_smbus_read_byte_data(&client, (offset_addr + j)); + if (rv < 0) { + PCA_DEBUG_ERR("i2c read failed, try again.\n"); + msleep(I2C_RETRY_WAIT_TIMES); + if (i >= (I2C_RETRY_TIMES - 1)) { + goto out; + } + continue; + } + *(buf + j) = (unsigned char)rv; + break; + } + } +out: + filp_close(fp, NULL); + return rv; +} + +static int pca9641_reset_i2c_write(uint32_t bus, uint32_t dev_addr, uint32_t offset_addr, + uint8_t write_buf) +{ + struct file *fp; + struct i2c_client client; + char i2c_path[32]; + int i; + int rv; + + rv = 0; + mem_clear(i2c_path, sizeof(i2c_path)); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); + fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); + if (IS_ERR(fp)) { + PCA_DEBUG_ERR("i2c open fail.\n"); + return -1; + } + memcpy(&client, fp->private_data, sizeof(struct i2c_client)); + client.addr = dev_addr; + for (i = 0; i < I2C_RETRY_TIMES; i++) { + rv = i2c_smbus_write_byte_data(&client, offset_addr, write_buf); + if (rv < 0) { + PCA_DEBUG_ERR("i2c write failed, try again.\n"); + msleep(I2C_RETRY_WAIT_TIMES); + if (i >= (I2C_RETRY_TIMES - 1)) { + goto out; + } + continue; + } + break; + } +out: + filp_close(fp, NULL); + return rv; +} + +static int pca9641_do_file_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout, err; + struct pca9541 *data; + pca9641_cfg_info_t *reset_cfg; + file_attr_t *file_attr; + u8 val; + int udelay_cnt; + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9641_cfg_info; + file_attr = &reset_cfg->attr.file_attr; + ret = -1; + + PCA_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", + reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); + PCA_DEBUG("dev_name:%s, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + file_attr->dev_name, file_attr->offset, file_attr->mask, + file_attr->reset_on, file_attr->reset_off); + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + err = pca9641_reset_file_read(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + + val &= ~(file_attr->mask); + val |= file_attr->reset_on; + err = pca9641_reset_file_write(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + val &= ~(file_attr->mask); + val |= file_attr->reset_off; + err = pca9641_reset_file_write(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + err = pca9641_reset_file_read(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + val &= (file_attr->mask); + if (val == file_attr->reset_off) { + ret = 0; + PCA_DEBUG("pca9641_do_file_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + if (ret < 0) { + PCA_DEBUG_ERR("pca9641_do_file_reset timeout.\n"); + } +out: + if (err < 0) { + PCA_DEBUG_ERR("pca9641_do_file_reset file rd/wr failed, ret:%d.\n", err); + } + + return ret; +} + +static int pca9641_do_io_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout; + struct pca9541 *data; + pca9641_cfg_info_t *reset_cfg; + io_attr_t *io_attr; + u8 val; + int udelay_cnt; + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9641_cfg_info; + io_attr = &reset_cfg->attr.io_attr; + + PCA_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", + reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); + PCA_DEBUG("io_addr:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + io_attr->io_addr, io_attr->mask, io_attr->reset_on, io_attr->reset_off); + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + val = inb(io_attr->io_addr); + val &= ~(io_attr->mask); + val |= io_attr->reset_on; + outb(val, io_attr->io_addr); + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + val &= ~(io_attr->mask); + val |= io_attr->reset_off; + outb(val, io_attr->io_addr); + + ret = -1; + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + val = inb(io_attr->io_addr); + val &= (io_attr->mask); + if (val == io_attr->reset_off) { + ret = 0; + PCA_DEBUG("pca9641_do_io_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + + if (ret < 0) { + PCA_DEBUG_ERR("pca9641_do_io_reset timeout.\n"); + } + + return ret; +} + +static int pca9641_do_gpio_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout; + struct pca9541 *data; + pca9641_cfg_info_t *reset_cfg; + gpio_attr_t *gpio_attr; + u8 val; + int udelay_cnt; + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9641_cfg_info; + gpio_attr = &reset_cfg->attr.gpio_attr; + + ret = pca9641_gpio_init(gpio_attr); + if (ret) { + return -1; + } + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_on); + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_off); + ret = -1; + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + val = __gpio_get_value(gpio_attr->gpio); + if (val == gpio_attr->reset_off) { + ret = 0; + PCA_DEBUG("pca9641_do_gpio_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + + if (ret < 0) { + PCA_DEBUG_ERR("pca9641_do_gpio_reset timeout.\n"); + } + + pca9641_gpio_free(gpio_attr); + return ret; +} + +static int pca9641_do_i2c_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout, err; + struct pca9541 *data; + pca9641_cfg_info_t *reset_cfg; + i2c_attr_t *i2c_attr; + u8 val; + int udelay_cnt; + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9641_cfg_info; + i2c_attr = &reset_cfg->attr.i2c_attr; + ret = -1; + + PCA_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", + reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); + PCA_DEBUG("bus:0x%x, addr:0x%x, reg:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + i2c_attr->i2c_bus, i2c_attr->i2c_addr, i2c_attr->reg_offset, + i2c_attr->mask, i2c_attr->reset_on, i2c_attr->reset_off); + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + err = pca9641_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + + val &= ~(i2c_attr->mask); + val |= i2c_attr->reset_on; + err = pca9641_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, val); + if (err < 0) { + goto out; + } + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + val &= ~(i2c_attr->mask); + val |= i2c_attr->reset_off; + err = pca9641_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, val); + if (err < 0) { + goto out; + } + + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + err = pca9641_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + val &= (i2c_attr->mask); + if (val == i2c_attr->reset_off) { + ret = 0; + PCA_DEBUG("pca9641_do_i2c_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + if (ret < 0) { + PCA_DEBUG_ERR("pca9641_do_i2c_reset timeout.\n"); + } +out: + if (err < 0) { + PCA_DEBUG_ERR("pca9641_do_i2c_reset i2c op failed, ret:%d.\n", err); + } + return ret; +} + +static int pca9641_do_reset(struct i2c_mux_core *muxc) +{ + int ret; + struct pca9541 *data; + + data = i2c_mux_priv(muxc); + if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_NONE) { + ret = -1; + PCA_DEBUG("Don't need to reset.\n"); + } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_I2C) { + ret = pca9641_do_i2c_reset(muxc); + } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_GPIO) { + ret = pca9641_do_gpio_reset(muxc); + } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_IO) { + ret = pca9641_do_io_reset(muxc); + } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_FILE) { + ret = pca9641_do_file_reset(muxc); + } else { + ret = -1; + PCA_DEBUG_ERR("Unsupport reset type:0x%x.\n", + data->pca9641_cfg_info.pca9641_reset_type); + } + + if (ret < 0) { + PCA_DEBUG_ERR("pca9641_reset_ctrl failed, reset type:%u, ret:%d.\n", + data->pca9641_cfg_info.pca9641_reset_type, ret); + } else { + usleep_range(PCA9641_RESET_DELAY, PCA9641_RESET_DELAY + 1); + } + return ret; +} + +/* + * Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer() + * as they will try to lock the adapter a second time. + */ +static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val) +{ + struct i2c_adapter *adap = client->adapter; + int ret; + + if (adap->algo->master_xfer) { + struct i2c_msg msg; + char buf[2]; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = 2; + buf[0] = command; + buf[1] = val; + msg.buf = buf; + ret = __i2c_transfer(adap, &msg, 1); + } else { + union i2c_smbus_data data; + + data.byte = val; + ret = adap->algo->smbus_xfer(adap, client->addr, + client->flags, + I2C_SMBUS_WRITE, + command, + I2C_SMBUS_BYTE_DATA, &data); + } + + return ret; +} + +/* + * Read from chip register. Don't use i2c_transfer()/i2c_smbus_xfer() + * as they will try to lock adapter a second time. + */ +static int pca9541_reg_read(struct i2c_client *client, u8 command) +{ + struct i2c_adapter *adap = client->adapter; + int ret; + u8 val; + + if (adap->algo->master_xfer) { + struct i2c_msg msg[2] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &command + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = &val + } + }; + ret = __i2c_transfer(adap, msg, 2); + if (ret == 2) + ret = val; + else if (ret >= 0) + ret = -EIO; + } else { + union i2c_smbus_data data; + + ret = adap->algo->smbus_xfer(adap, client->addr, + client->flags, + I2C_SMBUS_READ, + command, + I2C_SMBUS_BYTE_DATA, &data); + if (!ret) + ret = data.byte; + } + return ret; +} + +/* + * Arbitration management functions + */ + +/* Release bus. Also reset NTESTON and BUSINIT if it was set. */ +static void pca9541_release_bus(struct i2c_client *client) +{ + int reg; + + reg = pca9541_reg_read(client, PCA9541_CONTROL); + if (reg >= 0 && !busoff(reg) && mybus(reg)) + pca9541_reg_write(client, PCA9541_CONTROL, + (reg & PCA9541_CTL_NBUSON) >> 1); +} + +/* + * Arbitration is defined as a two-step process. A bus master can only activate + * the slave bus if it owns it; otherwise it has to request ownership first. + * This multi-step process ensures that access contention is resolved + * gracefully. + * + * Bus Ownership Other master Action + * state requested access + * ---------------------------------------------------- + * off - yes wait for arbitration timeout or + * for other master to drop request + * off no no take ownership + * off yes no turn on bus + * on yes - done + * on no - wait for arbitration timeout or + * for other master to release bus + * + * The main contention point occurs if the slave bus is off and both masters + * request ownership at the same time. In this case, one master will turn on + * the slave bus, believing that it owns it. The other master will request + * bus ownership. Result is that the bus is turned on, and master which did + * _not_ own the slave bus before ends up owning it. + */ + +/* Control commands per PCA9541 datasheet */ +static const u8 pca9541_control[16] = { + 4, 0, 1, 5, 4, 4, 5, 5, 0, 0, 1, 1, 0, 4, 5, 1 +}; + +/* + * Channel arbitration + * + * Return values: + * <0: error + * 0 : bus not acquired + * 1 : bus acquired + */ +static int pca9541_arbitrate(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct pca9541 *data = i2c_mux_priv(muxc); + int reg; + + reg = pca9541_reg_read(client, PCA9541_CONTROL); + if (reg < 0) + return reg; + + if (busoff(reg)) { + int istat; + /* + * Bus is off. Request ownership or turn it on unless + * other master requested ownership. + */ + istat = pca9541_reg_read(client, PCA9541_ISTAT); + if (!(istat & PCA9541_ISTAT_NMYTEST) + || time_is_before_eq_jiffies(data->arb_timeout)) { + /* + * Other master did not request ownership, + * or arbitration timeout expired. Take the bus. + */ + pca9541_reg_write(client, + PCA9541_CONTROL, + pca9541_control[reg & 0x0f] + | PCA9541_CTL_NTESTON); + data->select_timeout = SELECT_DELAY_SHORT; + } else { + /* + * Other master requested ownership. + * Set extra long timeout to give it time to acquire it. + */ + data->select_timeout = SELECT_DELAY_LONG * 2; + } + } else if (mybus(reg)) { + /* + * Bus is on, and we own it. We are done with acquisition. + * Reset NTESTON and BUSINIT, then return success. + */ + if (reg & (PCA9541_CTL_NTESTON | PCA9541_CTL_BUSINIT)) + pca9541_reg_write(client, + PCA9541_CONTROL, + reg & ~(PCA9541_CTL_NTESTON + | PCA9541_CTL_BUSINIT)); + return 1; + } else { + /* + * Other master owns the bus. + * If arbitration timeout has expired, force ownership. + * Otherwise request it. + */ + data->select_timeout = SELECT_DELAY_LONG; + if (time_is_before_eq_jiffies(data->arb_timeout)) { + /* Time is up, take the bus and reset it. */ + pca9541_reg_write(client, + PCA9541_CONTROL, + pca9541_control[reg & 0x0f] + | PCA9541_CTL_BUSINIT + | PCA9541_CTL_NTESTON); + } else { + /* Request bus ownership if needed */ + if (!(reg & PCA9541_CTL_NTESTON)) + pca9541_reg_write(client, + PCA9541_CONTROL, + reg | PCA9541_CTL_NTESTON); + } + } + return 0; +} + +static int pca9541_select_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca9541 *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + int ret; + unsigned long timeout = jiffies + ARB2_TIMEOUT; + /* give up after this time */ + + data->arb_timeout = jiffies + ARB_TIMEOUT; + /* force bus ownership after this time */ + + do { + ret = pca9541_arbitrate(client); + if (ret) + return ret < 0 ? ret : 0; + + if (data->select_timeout == SELECT_DELAY_SHORT) + udelay(data->select_timeout); + else + msleep(data->select_timeout / 1000); + } while (time_is_after_eq_jiffies(timeout)); + + dev_warn(&client->dev, "pca9541 select channel timeout.\n"); + return -ETIMEDOUT; +} + +static int pca9541_release_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca9541 *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + pca9541_release_bus(client); + return 0; +} + +/* +* Arbitration management functions +*/ +static void pca9641_release_bus(struct i2c_client *client) +{ + pca9541_reg_write(client, PCA9641_CONTROL, 0x80); //master 0x80 +} + +/* +* Channel arbitration +* +* Return values: +* <0: error +* 0 : bus not acquired +* 1 : bus acquired +*/ +static int pca9641_arbitrate(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct pca9541 *data = i2c_mux_priv(muxc); + int reg_ctl, reg_sts; + + reg_ctl = pca9541_reg_read(client, PCA9641_CONTROL); + if (reg_ctl < 0) { + PCA_DEBUG_ERR("pca9641 read control register failed, ret:%d.\n", reg_ctl); + return reg_ctl; + } + + reg_sts = pca9541_reg_read(client, PCA9641_STATUS); + if (reg_sts < 0) { + PCA_DEBUG_ERR("pca9641 read status register failed, ret:%d.\n", reg_sts); + return reg_sts; + } + + if (BUSOFF(reg_ctl, reg_sts)) { + /* + * Bus is off. Request ownership or turn it on unless + * other master requested ownership. + */ + reg_ctl |= PCA9641_CTL_LOCK_REQ; + pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); + reg_ctl = pca9541_reg_read(client, PCA9641_CONTROL); + if (reg_ctl < 0) { + PCA_DEBUG_ERR("Bus is off, but read control register failed, ret:%d.\n", reg_ctl); + return reg_ctl; + } + + if (lock_grant(reg_ctl)) { + /* + * Other master did not request ownership, + * or arbitration timeout expired. Take the bus. + */ + PCA_DEBUG("Bus is off, get pca9641 arbitration success.\n"); + reg_ctl |= PCA9641_CTL_BUS_CONNECT | PCA9641_CTL_LOCK_REQ; + pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); + return 1; + } else { + /* + * Other master requested ownership. + * Set extra long timeout to give it time to acquire it. + */ + PCA_DEBUG("Bus is off, but get pca9641 arbitration failed.\n"); + data->select_timeout = SELECT_DELAY_LONG * 2; + } + } else if (lock_grant(reg_ctl)) { + /* + * Bus is on, and we own it. We are done with acquisition. + */ + PCA_DEBUG("Bus is on, get pca9641 arbitration success.\n"); + reg_ctl |= PCA9641_CTL_BUS_CONNECT | PCA9641_CTL_LOCK_REQ; + pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); + return 1; + } else if (other_lock(reg_sts)) { + /* + * Other master owns the bus. + * If arbitration timeout has expired, force ownership. + * Otherwise request it. + */ + PCA_DEBUG("Other master owns the bus, try to request it.\n"); + data->select_timeout = SELECT_DELAY_LONG; + reg_ctl |= PCA9641_CTL_LOCK_REQ; + pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); + } + return 0; +} + +int pca9641_select_chan_single(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca9541 *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + int ret; + int result; + unsigned long msleep_time; + unsigned long timeout = jiffies + ARB2_TIMEOUT; + /* give up after this time */ + data->arb_timeout = jiffies + ARB_TIMEOUT; + /* force bus ownership after this time */ + for (result = 0 ; result < PCA9641_RETRY_TIME ; result ++) { + do { + ret = pca9641_arbitrate(client); + if (ret) { + return ret < 0 ? -EIO : 0; + } + msleep_time = data->select_timeout / 1000; + if (msleep_time < 1) { + msleep(1); + } else { + msleep(msleep_time); + } + } while (time_is_after_eq_jiffies(timeout)); + timeout = jiffies + ARB2_TIMEOUT; + } + dev_warn(&client->dev, "pca9641 select channel timeout.\n"); + return -ETIMEDOUT; +} + +static int pca9641_select_chan(struct i2c_mux_core *muxc, u32 chan) +{ + int ret, rv; + + ret = pca9641_select_chan_single(muxc, chan); + if (ret < 0) { + PCA_DEBUG_ERR("pca9641 select channel failed, ret:%d, try to reset pca9641.\n", ret); + rv = pca9641_do_reset(muxc); + + if (rv < 0) { + PCA_DEBUG_ERR("pca9641 reset failed, rv:%d.\n", rv); + return ret; + } + + ret = pca9641_select_chan_single(muxc, chan); + if (ret < 0) { + PCA_DEBUG_ERR("after pca9641 reset, select channel still failed, ret:%d.\n", ret); + } + } + return ret; +} + +static int pca9641_release_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca9541 *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + if (pca_flag.flag) { + pca9641_release_bus(client); + } + return 0; +} + +static int pca9641_detect_id(struct i2c_client *client) +{ +#if 0 + int reg; + + reg = pca9541_reg_read(client, PCA9641_ID); + if (reg == PCA9641_ID_MAGIC) + return 1; + else + return 0; +#endif + /* only support pca9641 */ + return 1; +} + +static int pca9641_recordflag(struct i2c_adapter *adap) { + if (pca_flag.flag != -1) { + pr_err(" %s %d has init already!!!", __func__, __LINE__); + return -1 ; + } + pca_flag.nr = adap->nr; + PCA_DEBUG(" adap->nr:%d\n", adap->nr); + snprintf(pca_flag.name, sizeof(pca_flag.name),adap->name); + return 0; +} + +static int of_pca9641_reset_data_init(struct pca9541 *data) +{ + int err; + struct device *dev = &data->client->dev; + pca9641_cfg_info_t *reset_cfg; + + reset_cfg = &data->pca9641_cfg_info; + if (dev == NULL || dev->of_node == NULL) { + PCA_DEBUG("dev or dev->of_node is NUll, no reset.\n"); + reset_cfg->pca9641_reset_type = PCA9641_RESET_NONE; + return 0; + } + + if (of_property_read_u32(dev->of_node, "pca9641_reset_type", &reset_cfg->pca9641_reset_type)) { + + PCA_DEBUG("pca9641_reset_type not found, no reset.\n"); + reset_cfg->pca9641_reset_type = PCA9641_RESET_NONE; + return 0; + } + err = of_property_read_u32(dev->of_node, "rst_delay_b", &reset_cfg->rst_delay_b); + err |= of_property_read_u32(dev->of_node, "rst_delay", &reset_cfg->rst_delay); + err |= of_property_read_u32(dev->of_node, "rst_delay_a", &reset_cfg->rst_delay_a); + + if (err) { + goto dts_config_err; + } + PCA_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", + reset_cfg->pca9641_reset_type, reset_cfg->rst_delay_b, + reset_cfg->rst_delay, reset_cfg->rst_delay_a); + + if (reset_cfg->pca9641_reset_type == PCA9641_RESET_I2C) { + + PCA_DEBUG("reset by i2c.\n"); + err = of_property_read_u32(dev->of_node, "i2c_bus", &reset_cfg->attr.i2c_attr.i2c_bus); + err |=of_property_read_u32(dev->of_node, "i2c_addr", &reset_cfg->attr.i2c_attr.i2c_addr); + err |=of_property_read_u32(dev->of_node, "reg_offset", &reset_cfg->attr.i2c_attr.reg_offset); + err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.i2c_attr.mask); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.i2c_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.i2c_attr.reset_off); + if (err) { + goto dts_config_err; + } + PCA_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, + reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, + reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); + } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_GPIO) { + + PCA_DEBUG("reset by gpio.\n"); + err = of_property_read_u32(dev->of_node, "gpio", &reset_cfg->attr.gpio_attr.gpio); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.gpio_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.gpio_attr.reset_off); + if (err) { + goto dts_config_err; + } + PCA_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, + reset_cfg->attr.gpio_attr.reset_off); + reset_cfg->attr.gpio_attr.gpio_init = 0; + } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_IO) { + + PCA_DEBUG("reset by io.\n"); + err = of_property_read_u32(dev->of_node, "io_addr", &reset_cfg->attr.io_attr.io_addr); + err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.io_attr.mask); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.io_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.io_attr.reset_off); + if (err) { + goto dts_config_err; + } + PCA_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, + reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); + } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_FILE) { + + PCA_DEBUG("reset by file.\n"); + err = of_property_read_string(dev->of_node, "dev_name", &reset_cfg->attr.file_attr.dev_name); + err |=of_property_read_u32(dev->of_node, "offset", &reset_cfg->attr.file_attr.offset); + err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.file_attr.mask); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.file_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.file_attr.reset_off); + if (err) { + goto dts_config_err; + } + PCA_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, + reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off); + } else { + PCA_DEBUG_ERR("Unsupport reset type:%d.\n", reset_cfg->pca9641_reset_type); + goto dts_config_err; + } + return 0; +dts_config_err: + PCA_DEBUG_ERR("dts config error, ret:%d.\n", err); + return -EINVAL; +} + +static int pca9641_reset_data_init(struct pca9541 *data) +{ + pca9641_cfg_info_t *reset_cfg; + i2c_mux_pca9641_device_t *i2c_mux_pca9641_device; + + if (data->client->dev.platform_data == NULL) { + PCA_DEBUG("pca9641 has no reset platform data config.\n"); + return 0; + } + reset_cfg = &data->pca9641_cfg_info; + i2c_mux_pca9641_device = data->client->dev.platform_data; + reset_cfg->pca9641_reset_type = i2c_mux_pca9641_device->pca9641_reset_type; + if (reset_cfg->pca9641_reset_type == PCA9641_RESET_NONE) { + PCA_DEBUG("pca9641 has no reset function.\n"); + return 0; + } + + reset_cfg->rst_delay_b = i2c_mux_pca9641_device->rst_delay_b; + reset_cfg->rst_delay = i2c_mux_pca9641_device->rst_delay; + reset_cfg->rst_delay_a = i2c_mux_pca9641_device->rst_delay_a; + PCA_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", + reset_cfg->pca9641_reset_type, reset_cfg->rst_delay_b, + reset_cfg->rst_delay, reset_cfg->rst_delay_a); + + if (reset_cfg->pca9641_reset_type == PCA9641_RESET_I2C) { + + PCA_DEBUG("reset by i2c.\n"); + reset_cfg->attr.i2c_attr.i2c_bus = i2c_mux_pca9641_device->attr.i2c_attr.i2c_bus; + reset_cfg->attr.i2c_attr.i2c_addr = i2c_mux_pca9641_device->attr.i2c_attr.i2c_addr; + reset_cfg->attr.i2c_attr.reg_offset = i2c_mux_pca9641_device->attr.i2c_attr.reg_offset; + reset_cfg->attr.i2c_attr.mask = i2c_mux_pca9641_device->attr.i2c_attr.mask; + reset_cfg->attr.i2c_attr.reset_on = i2c_mux_pca9641_device->attr.i2c_attr.reset_on; + reset_cfg->attr.i2c_attr.reset_off = i2c_mux_pca9641_device->attr.i2c_attr.reset_off; + PCA_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, + reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, + reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); + } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_GPIO) { + + PCA_DEBUG("reset by gpio.\n"); + reset_cfg->attr.gpio_attr.gpio = i2c_mux_pca9641_device->attr.gpio_attr.gpio; + reset_cfg->attr.gpio_attr.reset_on = i2c_mux_pca9641_device->attr.gpio_attr.reset_on; + reset_cfg->attr.gpio_attr.reset_off = i2c_mux_pca9641_device->attr.gpio_attr.reset_off; + PCA_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, + reset_cfg->attr.gpio_attr.reset_off); + reset_cfg->attr.gpio_attr.gpio_init = 0; + } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_IO) { + + PCA_DEBUG("reset by io.\n"); + reset_cfg->attr.io_attr.io_addr = i2c_mux_pca9641_device->attr.io_attr.io_addr; + reset_cfg->attr.io_attr.mask = i2c_mux_pca9641_device->attr.io_attr.mask; + reset_cfg->attr.io_attr.reset_on = i2c_mux_pca9641_device->attr.io_attr.reset_on; + reset_cfg->attr.io_attr.reset_off = i2c_mux_pca9641_device->attr.io_attr.reset_off; + PCA_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, + reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); + } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_FILE) { + + PCA_DEBUG("reset by file.\n"); + reset_cfg->attr.file_attr.dev_name = i2c_mux_pca9641_device->attr.file_attr.dev_name; + reset_cfg->attr.file_attr.offset = i2c_mux_pca9641_device->attr.file_attr.offset; + reset_cfg->attr.file_attr.mask = i2c_mux_pca9641_device->attr.file_attr.mask; + reset_cfg->attr.file_attr.reset_on = i2c_mux_pca9641_device->attr.file_attr.reset_on; + reset_cfg->attr.file_attr.reset_off = i2c_mux_pca9641_device->attr.file_attr.reset_off; + PCA_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, + reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off); + } else { + PCA_DEBUG_ERR("Unsupport reset type:%d.\n", reset_cfg->pca9641_reset_type); + return -EINVAL; + } + return 0; +} + +/* + * I2C init/probing/exit functions + */ +static int pca9541_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = client->adapter; + struct i2c_mux_core *muxc; + struct pca9541 *data; + int force; + int ret = -ENODEV; + int detect_id; + i2c_mux_pca9641_device_t *i2c_mux_pca9641_device; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + detect_id = pca9641_detect_id(client); + + /* + * I2C accesses are unprotected here. + * We have to lock the adapter before releasing the bus. + */ + if (detect_id == 0) { + i2c_lock_bus(adap, I2C_LOCK_ROOT_ADAPTER); + pca9541_release_bus(client); + i2c_unlock_bus(adap, I2C_LOCK_ROOT_ADAPTER); + } else { + i2c_lock_bus(adap, I2C_LOCK_ROOT_ADAPTER); + pca9641_release_bus(client); + i2c_unlock_bus(adap, I2C_LOCK_ROOT_ADAPTER); + } + + if (detect_id == 0) { /* pca9541 */ + muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), + I2C_MUX_ARBITRATOR, + pca9541_select_chan, pca9541_release_chan); + if (!muxc) + return -ENOMEM; + + data = i2c_mux_priv(muxc); + data->client = client; + + i2c_set_clientdata(client, muxc); + /* Create mux adapter */ + if (of_property_read_u32(client->dev.of_node, "pca9641_nr", &data->pca9641_nr)) { + + force = 0; + PCA_DEBUG("pca9641_nr not found, use dynamic adap number.\n"); + } else { + force = data->pca9641_nr; + PCA_DEBUG("pca9641_nr: %d.\n", force); + } + + ret = i2c_mux_add_adapter(muxc, force, 0, 0); + if (ret) + return ret; + } else { + muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), I2C_MUX_ARBITRATOR, + pca9641_select_chan, pca9641_release_chan); + if (!muxc) { + dev_err(&client->dev, "i2c_mux_alloc failed, out of memory.\n"); + return -ENOMEM; + } + + data = i2c_mux_priv(muxc); + data->client = client; + + i2c_set_clientdata(client, muxc); + + if (client->dev.of_node) { + ret= of_pca9641_reset_data_init(data); + } else { + ret= pca9641_reset_data_init(data); + } + if (ret < 0) { + dev_err(&client->dev, "pca9641 reset config err, ret:%d.\n", ret); + return ret; + } + + if (client->dev.of_node == NULL) { + if (client->dev.platform_data == NULL) { + force = 0; + PCA_DEBUG("platform data is NULL, use dynamic adap number.\n"); + } else { + i2c_mux_pca9641_device = client->dev.platform_data; + data->pca9641_nr = i2c_mux_pca9641_device->pca9641_nr; + if (data->pca9641_nr == 0) { + force = 0; + PCA_DEBUG("pca9641_nr = 0, use dynamic adap number.\n"); + } else { + force = data->pca9641_nr; + PCA_DEBUG("pca9641_nr: %d.\n", force); + } + } + } else { + /* Create mux adapter */ + if (of_property_read_u32(client->dev.of_node, "pca9641_nr", &data->pca9641_nr)) { + + force = 0; + PCA_DEBUG("pca9641_nr not found, use dynamic adap number.\n"); + } else { + force = data->pca9641_nr; + PCA_DEBUG("pca9641_nr: %d.\n", force); + } + } + + ret = i2c_mux_add_adapter(muxc, force, 0, 0); + if (ret) { + dev_err(&client->dev, "Failed to register master selector.\n"); + return ret; + } + } + pca9641_recordflag(muxc->adapter[0]); + + dev_info(&client->dev, "registered master selector for I2C %s\n", client->name); + + return 0; +} + +static int pca9541_remove(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + + i2c_mux_del_adapters(muxc); + return 0; +} + +static struct i2c_driver pca9641_driver = { + .driver = { + .name = "wb_pca9641", + .of_match_table = of_match_ptr(pca9541_of_match), + }, + .probe = pca9541_probe, + .remove = pca9541_remove, + .id_table = pca9541_id, +}; + +module_i2c_driver(pca9641_driver); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("PCA9541 I2C master selector driver"); +MODULE_LICENSE("GPL v2"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.h new file mode 100644 index 000000000000..b87f7585567b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.h @@ -0,0 +1,64 @@ +#ifndef __WB_I2C_MUX_PCA9641_H__ +#define __WB_I2C_MUX_PCA9641_H__ + +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +typedef enum pca9641_reset_type_s { + PCA9641_RESET_NONE = 0, + PCA9641_RESET_I2C = 1, + PCA9641_RESET_GPIO = 2, + PCA9641_RESET_IO = 3, + PCA9641_RESET_FILE = 4, +} pca9641_reset_type_t; + +typedef struct i2c_attr_s { + uint32_t i2c_bus; + uint32_t i2c_addr; + uint32_t reg_offset; + uint32_t mask; + uint32_t reset_on; + uint32_t reset_off; +} i2c_attr_t; + +typedef struct io_attr_s { + uint32_t io_addr; + uint32_t mask; + uint32_t reset_on; + uint32_t reset_off; +} io_attr_t; + +typedef struct file_attr_s { + const char *dev_name; + uint32_t offset; + uint32_t mask; + uint32_t reset_on; + uint32_t reset_off; +} file_attr_t; + +typedef struct gpio_attr_s { + int gpio_init; + uint32_t gpio; + uint32_t reset_on; + uint32_t reset_off; +} gpio_attr_t; + +typedef struct i2c_mux_pca9641_device_s { + struct i2c_client *client; + uint32_t i2c_bus; + uint32_t i2c_addr; + uint32_t pca9641_nr; + uint32_t pca9641_reset_type; + uint32_t rst_delay_b; /* delay time before reset(us) */ + uint32_t rst_delay; /* reset time(us) */ + uint32_t rst_delay_a; /* delay time after reset(us) */ + union { + i2c_attr_t i2c_attr; + gpio_attr_t gpio_attr; + io_attr_t io_attr; + file_attr_t file_attr; + } attr; +} i2c_mux_pca9641_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ina3221.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ina3221.c new file mode 100644 index 000000000000..fba2c4e3a68e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ina3221.c @@ -0,0 +1,1031 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * INA3221 Triple Current/Voltage Monitor + * + * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ + * Andrew F. Davis + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INA3221_DRIVER_NAME "wb_ina3221" + +#define INA3221_CONFIG 0x00 +#define INA3221_SHUNT1 0x01 +#define INA3221_BUS1 0x02 +#define INA3221_SHUNT2 0x03 +#define INA3221_BUS2 0x04 +#define INA3221_SHUNT3 0x05 +#define INA3221_BUS3 0x06 +#define INA3221_CRIT1 0x07 +#define INA3221_WARN1 0x08 +#define INA3221_CRIT2 0x09 +#define INA3221_WARN2 0x0a +#define INA3221_CRIT3 0x0b +#define INA3221_WARN3 0x0c +#define INA3221_SHUNT_SUM 0x0d +#define INA3221_CRIT_SUM 0x0e +#define INA3221_MASK_ENABLE 0x0f + +#define INA3221_CONFIG_MODE_MASK GENMASK(2, 0) +#define INA3221_CONFIG_MODE_POWERDOWN 0 +#define INA3221_CONFIG_MODE_SHUNT BIT(0) +#define INA3221_CONFIG_MODE_BUS BIT(1) +#define INA3221_CONFIG_MODE_CONTINUOUS BIT(2) +#define INA3221_CONFIG_VSH_CT_SHIFT 3 +#define INA3221_CONFIG_VSH_CT_MASK GENMASK(5, 3) +#define INA3221_CONFIG_VSH_CT(x) (((x) & GENMASK(5, 3)) >> 3) +#define INA3221_CONFIG_VBUS_CT_SHIFT 6 +#define INA3221_CONFIG_VBUS_CT_MASK GENMASK(8, 6) +#define INA3221_CONFIG_VBUS_CT(x) (((x) & GENMASK(8, 6)) >> 6) +#define INA3221_CONFIG_AVG_SHIFT 9 +#define INA3221_CONFIG_AVG_MASK GENMASK(11, 9) +#define INA3221_CONFIG_AVG(x) (((x) & GENMASK(11, 9)) >> 9) +#define INA3221_CONFIG_CHs_EN_MASK GENMASK(14, 12) +#define INA3221_CONFIG_CHx_EN(x) BIT(14 - (x)) + +#define INA3221_MASK_ENABLE_SCC_MASK GENMASK(14, 12) + +#define INA3221_CONFIG_DEFAULT 0x7127 +#define INA3221_RSHUNT_DEFAULT 10000 + +enum ina3221_fields { + /* Configuration */ + F_RST, + + /* Status Flags */ + F_CVRF, + + /* Warning Flags */ + F_WF3, F_WF2, F_WF1, + + /* Alert Flags: SF is the summation-alert flag */ + F_SF, F_CF3, F_CF2, F_CF1, + + /* sentinel */ + F_MAX_FIELDS +}; + +static const struct reg_field ina3221_reg_fields[] = { + [F_RST] = REG_FIELD(INA3221_CONFIG, 15, 15), + + [F_CVRF] = REG_FIELD(INA3221_MASK_ENABLE, 0, 0), + [F_WF3] = REG_FIELD(INA3221_MASK_ENABLE, 3, 3), + [F_WF2] = REG_FIELD(INA3221_MASK_ENABLE, 4, 4), + [F_WF1] = REG_FIELD(INA3221_MASK_ENABLE, 5, 5), + [F_SF] = REG_FIELD(INA3221_MASK_ENABLE, 6, 6), + [F_CF3] = REG_FIELD(INA3221_MASK_ENABLE, 7, 7), + [F_CF2] = REG_FIELD(INA3221_MASK_ENABLE, 8, 8), + [F_CF1] = REG_FIELD(INA3221_MASK_ENABLE, 9, 9), +}; + +enum ina3221_channels { + INA3221_CHANNEL1, + INA3221_CHANNEL2, + INA3221_CHANNEL3, + INA3221_NUM_CHANNELS +}; + +/** + * struct ina3221_input - channel input source specific information + * @label: label of channel input source + * @shunt_resistor: shunt resistor value of channel input source + * @disconnected: connection status of channel input source + */ +struct ina3221_input { + const char *label; + int shunt_resistor; + bool disconnected; +}; + +/** + * struct ina3221_data - device specific information + * @pm_dev: Device pointer for pm runtime + * @regmap: Register map of the device + * @fields: Register fields of the device + * @inputs: Array of channel input source specific structures + * @lock: mutex lock to serialize sysfs attribute accesses + * @reg_config: Register value of INA3221_CONFIG + * @summation_shunt_resistor: equivalent shunt resistor value for summation + * @single_shot: running in single-shot operating mode + */ +struct ina3221_data { + struct device *pm_dev; + struct regmap *regmap; + struct regmap_field *fields[F_MAX_FIELDS]; + struct ina3221_input inputs[INA3221_NUM_CHANNELS]; + struct mutex lock; + u32 reg_config; + int summation_shunt_resistor; + + bool single_shot; +}; + +static inline bool ina3221_is_enabled(struct ina3221_data *ina, int channel) +{ + /* Summation channel checks shunt resistor values */ + if (channel > INA3221_CHANNEL3) + return ina->summation_shunt_resistor != 0; + + return pm_runtime_active(ina->pm_dev) && + (ina->reg_config & INA3221_CONFIG_CHx_EN(channel)); +} + +/** + * Helper function to return the resistor value for current summation. + * + * There is a condition to calculate current summation -- all the shunt + * resistor values should be the same, so as to simply fit the formula: + * current summation = shunt voltage summation / shunt resistor + * + * Returns the equivalent shunt resistor value on success or 0 on failure + */ +static inline int ina3221_summation_shunt_resistor(struct ina3221_data *ina) +{ + struct ina3221_input *input = ina->inputs; + int i, shunt_resistor = 0; + + for (i = 0; i < INA3221_NUM_CHANNELS; i++) { + if (input[i].disconnected || !input[i].shunt_resistor) + continue; + if (!shunt_resistor) { + /* Found the reference shunt resistor value */ + shunt_resistor = input[i].shunt_resistor; + } else { + /* No summation if resistor values are different */ + if (shunt_resistor != input[i].shunt_resistor) + return 0; + } + } + + return shunt_resistor; +} + +/* Lookup table for Bus and Shunt conversion times in usec */ +static const u16 ina3221_conv_time[] = { + 140, 204, 332, 588, 1100, 2116, 4156, 8244, +}; + +/* Lookup table for number of samples using in averaging mode */ +static const int ina3221_avg_samples[] = { + 1, 4, 16, 64, 128, 256, 512, 1024, +}; + +/* Converting update_interval in msec to conversion time in usec */ +static inline u32 ina3221_interval_ms_to_conv_time(u16 config, int interval) +{ + u32 channels = hweight16(config & INA3221_CONFIG_CHs_EN_MASK); + u32 samples_idx = INA3221_CONFIG_AVG(config); + u32 samples = ina3221_avg_samples[samples_idx]; + + /* Bisect the result to Bus and Shunt conversion times */ + return DIV_ROUND_CLOSEST(interval * 1000 / 2, channels * samples); +} + +/* Converting CONFIG register value to update_interval in usec */ +static inline u32 ina3221_reg_to_interval_us(u16 config) +{ + u32 channels = hweight16(config & INA3221_CONFIG_CHs_EN_MASK); + u32 vbus_ct_idx = INA3221_CONFIG_VBUS_CT(config); + u32 vsh_ct_idx = INA3221_CONFIG_VSH_CT(config); + u32 samples_idx = INA3221_CONFIG_AVG(config); + u32 samples = ina3221_avg_samples[samples_idx]; + u32 vbus_ct = ina3221_conv_time[vbus_ct_idx]; + u32 vsh_ct = ina3221_conv_time[vsh_ct_idx]; + + /* Calculate total conversion time */ + return channels * (vbus_ct + vsh_ct) * samples; +} + +static inline int ina3221_wait_for_data(struct ina3221_data *ina) +{ + u32 wait, cvrf; + + wait = ina3221_reg_to_interval_us(ina->reg_config); + + /* Polling the CVRF bit to make sure read data is ready */ + return regmap_field_read_poll_timeout(ina->fields[F_CVRF], + cvrf, cvrf, wait, wait * 2); +} + +static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, + int *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(ina->regmap, reg, ®val); + if (ret) + return ret; + + /* + * Shunt Voltage Sum register has 14-bit value with 1-bit shift + * Other Shunt Voltage registers have 12 bits with 3-bit shift + */ + if (reg == INA3221_SHUNT_SUM) + *val = sign_extend32(regval >> 1, 14); + else + *val = sign_extend32(regval >> 3, 12); + + return 0; +} + +static const u8 ina3221_in_reg[] = { + INA3221_BUS1, + INA3221_BUS2, + INA3221_BUS3, + INA3221_SHUNT1, + INA3221_SHUNT2, + INA3221_SHUNT3, + INA3221_SHUNT_SUM, +}; + +static int ina3221_read_chip(struct device *dev, u32 attr, long *val) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int regval; + + switch (attr) { + case hwmon_chip_samples: + regval = INA3221_CONFIG_AVG(ina->reg_config); + *val = ina3221_avg_samples[regval]; + return 0; + case hwmon_chip_update_interval: + /* Return in msec */ + *val = ina3221_reg_to_interval_us(ina->reg_config); + *val = DIV_ROUND_CLOSEST(*val, 1000); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int ina3221_read_in(struct device *dev, u32 attr, int channel, long *val) +{ + const bool is_shunt = channel > INA3221_CHANNEL3; + struct ina3221_data *ina = dev_get_drvdata(dev); + u8 reg = ina3221_in_reg[channel]; + int regval, ret; + + /* + * Translate shunt channel index to sensor channel index except + * the 7th channel (6 since being 0-aligned) is for summation. + */ + if (channel != 6) + channel %= INA3221_NUM_CHANNELS; + + switch (attr) { + case hwmon_in_input: + if (!ina3221_is_enabled(ina, channel)) + return -ENODATA; + + /* Write CONFIG register to trigger a single-shot measurement */ + if (ina->single_shot) + regmap_write(ina->regmap, INA3221_CONFIG, + ina->reg_config); + + ret = ina3221_wait_for_data(ina); + if (ret) + return ret; + + ret = ina3221_read_value(ina, reg, ®val); + if (ret) + return ret; + + /* + * Scale of shunt voltage (uV): LSB is 40uV + * Scale of bus voltage (mV): LSB is 8mV + */ + *val = regval * (is_shunt ? 40 : 8); + return 0; + case hwmon_in_enable: + *val = ina3221_is_enabled(ina, channel); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static const u8 ina3221_curr_reg[][INA3221_NUM_CHANNELS + 1] = { + [hwmon_curr_input] = { INA3221_SHUNT1, INA3221_SHUNT2, + INA3221_SHUNT3, INA3221_SHUNT_SUM }, + [hwmon_curr_max] = { INA3221_WARN1, INA3221_WARN2, INA3221_WARN3, 0 }, + [hwmon_curr_crit] = { INA3221_CRIT1, INA3221_CRIT2, + INA3221_CRIT3, INA3221_CRIT_SUM }, + [hwmon_curr_max_alarm] = { F_WF1, F_WF2, F_WF3, 0 }, + [hwmon_curr_crit_alarm] = { F_CF1, F_CF2, F_CF3, F_SF }, +}; + +static int ina3221_read_curr(struct device *dev, u32 attr, + int channel, long *val) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + struct ina3221_input *input = ina->inputs; + u8 reg = ina3221_curr_reg[attr][channel]; + int resistance_uo, voltage_nv; + int regval, ret; + + if (channel > INA3221_CHANNEL3) + resistance_uo = ina->summation_shunt_resistor; + else + resistance_uo = input[channel].shunt_resistor; + + switch (attr) { + case hwmon_curr_input: + if (!ina3221_is_enabled(ina, channel)) + return -ENODATA; + + /* Write CONFIG register to trigger a single-shot measurement */ + if (ina->single_shot) + regmap_write(ina->regmap, INA3221_CONFIG, + ina->reg_config); + + ret = ina3221_wait_for_data(ina); + if (ret) + return ret; + + fallthrough; + case hwmon_curr_crit: + case hwmon_curr_max: + if (!resistance_uo) + return -ENODATA; + + ret = ina3221_read_value(ina, reg, ®val); + if (ret) + return ret; + + /* Scale of shunt voltage: LSB is 40uV (40000nV) */ + voltage_nv = regval * 40000; + /* Return current in mA */ + *val = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo); + return 0; + case hwmon_curr_crit_alarm: + case hwmon_curr_max_alarm: + /* No actual register read if channel is disabled */ + if (!ina3221_is_enabled(ina, channel)) { + /* Return 0 for alert flags */ + *val = 0; + return 0; + } + ret = regmap_field_read(ina->fields[reg], ®val); + if (ret) + return ret; + *val = regval; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int ina3221_write_chip(struct device *dev, u32 attr, long val) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret, idx; + u32 tmp; + + switch (attr) { + case hwmon_chip_samples: + idx = find_closest(val, ina3221_avg_samples, + ARRAY_SIZE(ina3221_avg_samples)); + + tmp = (ina->reg_config & ~INA3221_CONFIG_AVG_MASK) | + (idx << INA3221_CONFIG_AVG_SHIFT); + ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp); + if (ret) + return ret; + + /* Update reg_config accordingly */ + ina->reg_config = tmp; + return 0; + case hwmon_chip_update_interval: + tmp = ina3221_interval_ms_to_conv_time(ina->reg_config, val); + idx = find_closest(tmp, ina3221_conv_time, + ARRAY_SIZE(ina3221_conv_time)); + + /* Update Bus and Shunt voltage conversion times */ + tmp = INA3221_CONFIG_VBUS_CT_MASK | INA3221_CONFIG_VSH_CT_MASK; + tmp = (ina->reg_config & ~tmp) | + (idx << INA3221_CONFIG_VBUS_CT_SHIFT) | + (idx << INA3221_CONFIG_VSH_CT_SHIFT); + ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp); + if (ret) + return ret; + + /* Update reg_config accordingly */ + ina->reg_config = tmp; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int ina3221_write_curr(struct device *dev, u32 attr, + int channel, long val) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + struct ina3221_input *input = ina->inputs; + u8 reg = ina3221_curr_reg[attr][channel]; + int resistance_uo, current_ma, voltage_uv; + int regval; + + if (channel > INA3221_CHANNEL3) + resistance_uo = ina->summation_shunt_resistor; + else + resistance_uo = input[channel].shunt_resistor; + + if (!resistance_uo) + return -EOPNOTSUPP; + + /* clamp current */ + current_ma = clamp_val(val, + INT_MIN / resistance_uo, + INT_MAX / resistance_uo); + + voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000); + + /* clamp voltage */ + voltage_uv = clamp_val(voltage_uv, -163800, 163800); + + /* + * Formula to convert voltage_uv to register value: + * regval = (voltage_uv / scale) << shift + * Note: + * The scale is 40uV for all shunt voltage registers + * Shunt Voltage Sum register left-shifts 1 bit + * All other Shunt Voltage registers shift 3 bits + * Results: + * SHUNT_SUM: (1 / 40uV) << 1 = 1 / 20uV + * SHUNT[1-3]: (1 / 40uV) << 3 = 1 / 5uV + */ + if (reg == INA3221_SHUNT_SUM) + regval = DIV_ROUND_CLOSEST(voltage_uv, 20) & 0xfffe; + else + regval = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8; + + return regmap_write(ina->regmap, reg, regval); +} + +static int ina3221_write_enable(struct device *dev, int channel, bool enable) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + u16 config, mask = INA3221_CONFIG_CHx_EN(channel); + u16 config_old = ina->reg_config & mask; + u32 tmp; + int ret; + + config = enable ? mask : 0; + + /* Bypass if enable status is not being changed */ + if (config_old == config) + return 0; + + /* For enabling routine, increase refcount and resume() at first */ + if (enable) { + ret = pm_runtime_resume_and_get(ina->pm_dev); + if (ret < 0) { + dev_err(dev, "Failed to get PM runtime\n"); + return ret; + } + } + + /* Enable or disable the channel */ + tmp = (ina->reg_config & ~mask) | (config & mask); + ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp); + if (ret) + goto fail; + + /* Cache the latest config register value */ + ina->reg_config = tmp; + + /* For disabling routine, decrease refcount or suspend() at last */ + if (!enable) + pm_runtime_put_sync(ina->pm_dev); + + return 0; + +fail: + if (enable) { + dev_err(dev, "Failed to enable channel %d: error %d\n", + channel, ret); + pm_runtime_put_sync(ina->pm_dev); + } + + return ret; +} + +static int ina3221_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret; + + mutex_lock(&ina->lock); + + switch (type) { + case hwmon_chip: + ret = ina3221_read_chip(dev, attr, val); + break; + case hwmon_in: + /* 0-align channel ID */ + ret = ina3221_read_in(dev, attr, channel - 1, val); + break; + case hwmon_curr: + ret = ina3221_read_curr(dev, attr, channel, val); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + mutex_unlock(&ina->lock); + + return ret; +} + +static int ina3221_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret; + + mutex_lock(&ina->lock); + + switch (type) { + case hwmon_chip: + ret = ina3221_write_chip(dev, attr, val); + break; + case hwmon_in: + /* 0-align channel ID */ + ret = ina3221_write_enable(dev, channel - 1, val); + break; + case hwmon_curr: + ret = ina3221_write_curr(dev, attr, channel, val); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + mutex_unlock(&ina->lock); + + return ret; +} + +static int ina3221_read_string(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int index = channel - 1; + + if (channel == 7) + *str = "sum of shunt voltages"; + else + *str = ina->inputs[index].label; + + return 0; +} + +static umode_t ina3221_is_visible(const void *drvdata, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct ina3221_data *ina = drvdata; + const struct ina3221_input *input = NULL; + + switch (type) { + case hwmon_chip: + switch (attr) { + case hwmon_chip_samples: + case hwmon_chip_update_interval: + return 0644; + default: + return 0; + } + case hwmon_in: + /* Ignore in0_ */ + if (channel == 0) + return 0; + + switch (attr) { + case hwmon_in_label: + if (channel - 1 <= INA3221_CHANNEL3) + input = &ina->inputs[channel - 1]; + else if (channel == 7) + return 0444; + /* Hide label node if label is not provided */ + return (input && input->label) ? 0444 : 0; + case hwmon_in_input: + return 0444; + case hwmon_in_enable: + return 0644; + default: + return 0; + } + case hwmon_curr: + switch (attr) { + case hwmon_curr_input: + case hwmon_curr_crit_alarm: + case hwmon_curr_max_alarm: + return 0444; + case hwmon_curr_crit: + case hwmon_curr_max: + return 0644; + default: + return 0; + } + default: + return 0; + } +} + +#define INA3221_HWMON_CURR_CONFIG (HWMON_C_INPUT | \ + HWMON_C_CRIT | HWMON_C_CRIT_ALARM | \ + HWMON_C_MAX | HWMON_C_MAX_ALARM) + +static const struct hwmon_channel_info *ina3221_info[] = { + HWMON_CHANNEL_INFO(chip, + HWMON_C_SAMPLES, + HWMON_C_UPDATE_INTERVAL), + HWMON_CHANNEL_INFO(in, + /* 0: dummy, skipped in is_visible */ + HWMON_I_INPUT, + /* 1-3: input voltage Channels */ + HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, + /* 4-6: shunt voltage Channels */ + HWMON_I_INPUT, + HWMON_I_INPUT, + HWMON_I_INPUT, + /* 7: summation of shunt voltage channels */ + HWMON_I_INPUT | HWMON_I_LABEL), + HWMON_CHANNEL_INFO(curr, + /* 1-3: current channels*/ + INA3221_HWMON_CURR_CONFIG, + INA3221_HWMON_CURR_CONFIG, + INA3221_HWMON_CURR_CONFIG, + /* 4: summation of current channels */ + HWMON_C_INPUT | HWMON_C_CRIT | HWMON_C_CRIT_ALARM), + NULL +}; + +static const struct hwmon_ops ina3221_hwmon_ops = { + .is_visible = ina3221_is_visible, + .read_string = ina3221_read_string, + .read = ina3221_read, + .write = ina3221_write, +}; + +static const struct hwmon_chip_info ina3221_chip_info = { + .ops = &ina3221_hwmon_ops, + .info = ina3221_info, +}; + +/* Extra attribute groups */ +static ssize_t ina3221_shunt_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int channel = sd_attr->index; + struct ina3221_input *input = &ina->inputs[channel]; + + return snprintf(buf, PAGE_SIZE, "%d\n", input->shunt_resistor); +} + +static ssize_t ina3221_shunt_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int channel = sd_attr->index; + struct ina3221_input *input = &ina->inputs[channel]; + int val; + int ret; + + ret = kstrtoint(buf, 0, &val); + if (ret) + return ret; + + val = clamp_val(val, 1, INT_MAX); + + input->shunt_resistor = val; + + /* Update summation_shunt_resistor for summation channel */ + ina->summation_shunt_resistor = ina3221_summation_shunt_resistor(ina); + + return count; +} + +/* shunt resistance */ +static SENSOR_DEVICE_ATTR_RW(shunt1_resistor, ina3221_shunt, INA3221_CHANNEL1); +static SENSOR_DEVICE_ATTR_RW(shunt2_resistor, ina3221_shunt, INA3221_CHANNEL2); +static SENSOR_DEVICE_ATTR_RW(shunt3_resistor, ina3221_shunt, INA3221_CHANNEL3); + +static struct attribute *ina3221_attrs[] = { + &sensor_dev_attr_shunt1_resistor.dev_attr.attr, + &sensor_dev_attr_shunt2_resistor.dev_attr.attr, + &sensor_dev_attr_shunt3_resistor.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(ina3221); + +static const struct regmap_range ina3221_yes_ranges[] = { + regmap_reg_range(INA3221_CONFIG, INA3221_BUS3), + regmap_reg_range(INA3221_SHUNT_SUM, INA3221_SHUNT_SUM), + regmap_reg_range(INA3221_MASK_ENABLE, INA3221_MASK_ENABLE), +}; + +static const struct regmap_access_table ina3221_volatile_table = { + .yes_ranges = ina3221_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(ina3221_yes_ranges), +}; + +static const struct regmap_config ina3221_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + + .cache_type = REGCACHE_RBTREE, + .volatile_table = &ina3221_volatile_table, +}; + +static int ina3221_probe_child_from_dt(struct device *dev, + struct device_node *child, + struct ina3221_data *ina) +{ + struct ina3221_input *input; + u32 val; + int ret; + + ret = of_property_read_u32(child, "reg", &val); + if (ret) { + dev_err(dev, "missing reg property of %pOFn\n", child); + return ret; + } else if (val > INA3221_CHANNEL3) { + dev_err(dev, "invalid reg %d of %pOFn\n", val, child); + return ret; + } + + input = &ina->inputs[val]; + + /* Log the disconnected channel input */ + if (!of_device_is_available(child)) { + input->disconnected = true; + return 0; + } + + /* Save the connected input label if available */ + of_property_read_string(child, "label", &input->label); + + /* Overwrite default shunt resistor value optionally */ + if (!of_property_read_u32(child, "shunt-resistor-micro-ohms", &val)) { + if (val < 1 || val > INT_MAX) { + dev_err(dev, "invalid shunt resistor value %u of %pOFn\n", + val, child); + return -EINVAL; + } + input->shunt_resistor = val; + } + + return 0; +} + +static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina) +{ + const struct device_node *np = dev->of_node; + struct device_node *child; + int ret; + + /* Compatible with non-DT platforms */ + if (!np) + return 0; + + ina->single_shot = of_property_read_bool(np, "ti,single-shot"); + + for_each_child_of_node(np, child) { + ret = ina3221_probe_child_from_dt(dev, child, ina); + if (ret) { + of_node_put(child); + return ret; + } + } + + return 0; +} + +static int ina3221_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct ina3221_data *ina; + struct device *hwmon_dev; + int i, ret; + + ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL); + if (!ina) + return -ENOMEM; + + ina->regmap = devm_regmap_init_i2c(client, &ina3221_regmap_config); + if (IS_ERR(ina->regmap)) { + dev_err(dev, "Unable to allocate register map\n"); + return PTR_ERR(ina->regmap); + } + + for (i = 0; i < F_MAX_FIELDS; i++) { + ina->fields[i] = devm_regmap_field_alloc(dev, + ina->regmap, + ina3221_reg_fields[i]); + if (IS_ERR(ina->fields[i])) { + dev_err(dev, "Unable to allocate regmap fields\n"); + return PTR_ERR(ina->fields[i]); + } + } + + for (i = 0; i < INA3221_NUM_CHANNELS; i++) + ina->inputs[i].shunt_resistor = INA3221_RSHUNT_DEFAULT; + + ret = ina3221_probe_from_dt(dev, ina); + if (ret) { + dev_err(dev, "Unable to probe from device tree\n"); + return ret; + } + + /* The driver will be reset, so use reset value */ + ina->reg_config = INA3221_CONFIG_DEFAULT; + + /* Clear continuous bit to use single-shot mode */ + if (ina->single_shot) + ina->reg_config &= ~INA3221_CONFIG_MODE_CONTINUOUS; + + /* Disable channels if their inputs are disconnected */ + for (i = 0; i < INA3221_NUM_CHANNELS; i++) { + if (ina->inputs[i].disconnected) + ina->reg_config &= ~INA3221_CONFIG_CHx_EN(i); + } + + /* Initialize summation_shunt_resistor for summation channel control */ + ina->summation_shunt_resistor = ina3221_summation_shunt_resistor(ina); + + ina->pm_dev = dev; + mutex_init(&ina->lock); + dev_set_drvdata(dev, ina); + + /* Enable PM runtime -- status is suspended by default */ + pm_runtime_enable(ina->pm_dev); + + /* Initialize (resume) the device */ + for (i = 0; i < INA3221_NUM_CHANNELS; i++) { + if (ina->inputs[i].disconnected) + continue; + /* Match the refcount with number of enabled channels */ + ret = pm_runtime_get_sync(ina->pm_dev); + if (ret < 0) + goto fail; + } + + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ina, + &ina3221_chip_info, + ina3221_groups); + if (IS_ERR(hwmon_dev)) { + dev_err(dev, "Unable to register hwmon device\n"); + ret = PTR_ERR(hwmon_dev); + goto fail; + } + + return 0; + +fail: + pm_runtime_disable(ina->pm_dev); + pm_runtime_set_suspended(ina->pm_dev); + /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */ + for (i = 0; i < INA3221_NUM_CHANNELS; i++) + pm_runtime_put_noidle(ina->pm_dev); + mutex_destroy(&ina->lock); + + return ret; +} + +static int ina3221_remove(struct i2c_client *client) +{ + struct ina3221_data *ina = dev_get_drvdata(&client->dev); + int i; + + pm_runtime_disable(ina->pm_dev); + pm_runtime_set_suspended(ina->pm_dev); + + /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */ + for (i = 0; i < INA3221_NUM_CHANNELS; i++) + pm_runtime_put_noidle(ina->pm_dev); + + mutex_destroy(&ina->lock); + + return 0; +} + +static int __maybe_unused ina3221_suspend(struct device *dev) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret; + + /* Save config register value and enable cache-only */ + ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); + if (ret) + return ret; + + /* Set to power-down mode for power saving */ + ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, + INA3221_CONFIG_MODE_MASK, + INA3221_CONFIG_MODE_POWERDOWN); + if (ret) + return ret; + + regcache_cache_only(ina->regmap, true); + regcache_mark_dirty(ina->regmap); + + return 0; +} + +static int __maybe_unused ina3221_resume(struct device *dev) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret; + + regcache_cache_only(ina->regmap, false); + + /* Software reset the chip */ + ret = regmap_field_write(ina->fields[F_RST], true); + if (ret) { + dev_err(dev, "Unable to reset device\n"); + return ret; + } + + /* Restore cached register values to hardware */ + ret = regcache_sync(ina->regmap); + if (ret) + return ret; + + /* Restore config register value to hardware */ + ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config); + if (ret) + return ret; + + /* Initialize summation channel control */ + if (ina->summation_shunt_resistor) { + /* + * Take all three channels into summation by default + * Shunt measurements of disconnected channels should + * be 0, so it does not matter for summation. + */ + ret = regmap_update_bits(ina->regmap, INA3221_MASK_ENABLE, + INA3221_MASK_ENABLE_SCC_MASK, + INA3221_MASK_ENABLE_SCC_MASK); + if (ret) { + dev_err(dev, "Unable to control summation channel\n"); + return ret; + } + } + + return 0; +} + +static const struct dev_pm_ops ina3221_pm = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(ina3221_suspend, ina3221_resume, NULL) +}; + +static const struct of_device_id ina3221_of_match_table[] = { + { .compatible = "ti,wb_ina3221", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ina3221_of_match_table); + +static const struct i2c_device_id ina3221_ids[] = { + { "wb_ina3221", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, ina3221_ids); + +static struct i2c_driver ina3221_i2c_driver = { + .probe_new = ina3221_probe, + .remove = ina3221_remove, + .driver = { + .name = INA3221_DRIVER_NAME, + .of_match_table = ina3221_of_match_table, + .pm = &ina3221_pm, + }, + .id_table = ina3221_ids, +}; +module_i2c_driver(ina3221_i2c_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("Texas Instruments INA3221 HWMon Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_isl68137.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_isl68137.c new file mode 100644 index 000000000000..5b3b54d92180 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_isl68137.c @@ -0,0 +1,572 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Hardware monitoring driver for Renesas Digital Multiphase Voltage Regulators + * + * Copyright (c) 2017 Google Inc + * Copyright (c) 2020 Renesas Electronics America + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_pmbus.h" + +#define ISL68137_VOUT_AVS (0x30) +#define RAA_DMPVR2_READ_VMON (0xc8) +#define WRITE_PROTECT_CLOSE (0x00) +#define WRITE_PROTECT_OPEN (0x40) + +static int g_wb_isl68137_debug = 0; +static int g_wb_isl68137_error = 0; + +module_param(g_wb_isl68137_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_isl68137_error, int, S_IRUGO | S_IWUSR); + +#define WB_ISL68137_VERBOSE(fmt, args...) do { \ + if (g_wb_isl68137_debug) { \ + printk(KERN_INFO "[WB_ISL68137][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_ISL68137_ERROR(fmt, args...) do { \ + if (g_wb_isl68137_error) { \ + printk(KERN_ERR "[WB_ISL68137][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +enum chips { + isl68137, + isl68220, + isl68221, + isl68222, + isl68223, + isl68224, + isl68225, + isl68226, + isl68227, + isl68229, + isl68233, + isl68239, + isl69222, + isl69223, + isl69224, + isl69225, + isl69227, + isl69228, + isl69234, + isl69236, + isl69239, + isl69242, + isl69243, + isl69247, + isl69248, + isl69254, + isl69255, + isl69256, + isl69259, + isl69260, + isl69268, + isl69269, + isl69298, + raa228000, + raa228004, + raa228006, + raa228228, + raa229001, + raa229004, +}; + +enum variants { + raa_dmpvr1_2rail, + raa_dmpvr2_1rail, + raa_dmpvr2_2rail, + raa_dmpvr2_2rail_nontc, + raa_dmpvr2_3rail, + raa_dmpvr2_hv, +}; + +static const struct i2c_device_id raa_dmpvr_id[]; + +static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client, + int page, + char *buf) +{ + int val = wb_pmbus_read_byte_data(client, page, PMBUS_OPERATION); + + return sprintf(buf, "%d\n", + (val & ISL68137_VOUT_AVS) == ISL68137_VOUT_AVS ? 1 : 0); +} + +static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client, + int page, + const char *buf, size_t count) +{ + int rc, op_val; + bool result; + + rc = kstrtobool(buf, &result); + if (rc) + return rc; + + op_val = result ? ISL68137_VOUT_AVS : 0; + + /* + * Writes to VOUT setpoint over AVSBus will persist after the VRM is + * switched to PMBus control. Switching back to AVSBus control + * restores this persisted setpoint rather than re-initializing to + * PMBus VOUT_COMMAND. Writing VOUT_COMMAND first over PMBus before + * enabling AVS control is the workaround. + */ + if (op_val == ISL68137_VOUT_AVS) { + rc = wb_pmbus_read_word_data(client, page, 0xff, + PMBUS_VOUT_COMMAND); + if (rc < 0) + return rc; + + rc = wb_pmbus_write_word_data(client, page, PMBUS_VOUT_COMMAND, + rc); + if (rc < 0) + return rc; + } + + rc = wb_pmbus_update_byte_data(client, page, PMBUS_OPERATION, + ISL68137_VOUT_AVS, op_val); + + return (rc < 0) ? rc : count; +} + +static ssize_t isl68137_avs_enable_show(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + return isl68137_avs_enable_show_page(client, attr->index, buf); +} + +static ssize_t isl68137_avs_enable_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + return isl68137_avs_enable_store_page(client, attr->index, buf, count); +} + +static ssize_t isl68137_avs_vout_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int vout_cmd, vout; + + mutex_lock(&data->update_lock); + vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); + if (vout_cmd < 0) { + WB_ISL68137_ERROR("%d-%04x: read page%d vout command reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd); + mutex_unlock(&data->update_lock); + return vout_cmd; + } + vout = vout_cmd * 1000; + WB_ISL68137_VERBOSE("%d-%04x: page%d, vout: %d, vout_cmd: 0x%x\n", client->adapter->nr, + client->addr, attr->index, vout, vout_cmd); + mutex_unlock(&data->update_lock); + return snprintf(buf, PAGE_SIZE, "%d\n", vout); +} + +static ssize_t isl68137_avs_vout_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int vout, vout_max, vout_min; + int ret, vout_cmd, vout_cmd_set; + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + ret = kstrtoint(buf, 0, &vout); + if (ret) { + WB_ISL68137_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + vout_max = data->vout_max[attr->index]; + vout_min = data->vout_min[attr->index]; + if ((vout > vout_max) || (vout < vout_min)) { + WB_ISL68137_ERROR("%d-%04x: vout value: %d, out of range [%d, %d] \n", client->adapter->nr, + client->addr, vout, vout_min, vout_max); + return -EINVAL; + } + + /* calc VOUT_COMMAND set value */ + vout_cmd_set = vout / 1000; + if (vout_cmd_set > 0xffff) { + WB_ISL68137_ERROR("%d-%04x: invalid value, vout %d, vout_cmd_set: 0x%x\n", + client->adapter->nr, client->addr, vout, vout_cmd_set); + return -EINVAL; + } + + mutex_lock(&data->update_lock); + + /* close write protect */ + ret = wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, WRITE_PROTECT_CLOSE); + if (ret < 0) { + WB_ISL68137_ERROR("%d-%04x: close page%d write protect failed, ret: %d\n", client->adapter->nr, + client->addr, attr->index, ret); + mutex_unlock(&data->update_lock); + return ret; + } + + /* set VOUT_COMMAND */ + ret = wb_pmbus_write_word_data(client, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set); + if (ret < 0) { + WB_ISL68137_ERROR("%d-%04x: set page%d vout cmd reg: 0x%x, value: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set, ret); + goto error; + } + + /* read back VOUT_COMMAND */ + vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); + if (vout_cmd < 0) { + ret = vout_cmd; + WB_ISL68137_ERROR("%d-%04x: read page%d vout command reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, ret); + goto error; + } + + /* compare vout_cmd and vout_cmd_set */ + if (vout_cmd != vout_cmd_set) { + ret = -EIO; + WB_ISL68137_ERROR("%d-%04x: vout cmd value check error, vout cmd read: 0x%x, vout cmd set: 0x%x\n", + client->adapter->nr, client->addr, vout_cmd, vout_cmd_set); + goto error; + } + + /* open write protect */ + wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, WRITE_PROTECT_OPEN); + mutex_unlock(&data->update_lock); + WB_ISL68137_VERBOSE("%d-%04x: set page%d vout cmd success, vout %d, vout_cmd_set: 0x%x\n", + client->adapter->nr, client->addr, attr->index, vout, vout_cmd_set); + return count; +error: + wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, WRITE_PROTECT_OPEN); + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t isl68137_avs_vout_max_store(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int ret, vout_threshold; + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + ret = kstrtoint(buf, 0, &vout_threshold); + if (ret) { + WB_ISL68137_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + WB_ISL68137_VERBOSE("%d-%04x: vout%d max threshold: %d", client->adapter->nr, client->addr, + attr->index, vout_threshold); + + data->vout_max[attr->index] = vout_threshold; + return count; +} + +static ssize_t isl68137_avs_vout_max_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_max[attr->index]); +} + +static ssize_t isl68137_avs_vout_min_store(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int ret, vout_threshold; + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + ret = kstrtoint(buf, 0, &vout_threshold); + if (ret) { + WB_ISL68137_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + WB_ISL68137_VERBOSE("%d-%04x: vout%d min threshold: %d", client->adapter->nr, client->addr, + attr->index, vout_threshold); + + data->vout_min[attr->index] = vout_threshold; + return count; +} + +static ssize_t isl68137_avs_vout_min_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_min[attr->index]); +} + +static SENSOR_DEVICE_ATTR_RW(avs0_enable, isl68137_avs_enable, 0); +static SENSOR_DEVICE_ATTR_RW(avs1_enable, isl68137_avs_enable, 1); + +static SENSOR_DEVICE_ATTR_RW(avs0_vout, isl68137_avs_vout, 0); +static SENSOR_DEVICE_ATTR_RW(avs1_vout, isl68137_avs_vout, 1); +static SENSOR_DEVICE_ATTR_RW(avs0_vout_max, isl68137_avs_vout_max, 0); +static SENSOR_DEVICE_ATTR_RW(avs0_vout_min, isl68137_avs_vout_min, 0); +static SENSOR_DEVICE_ATTR_RW(avs1_vout_max, isl68137_avs_vout_max, 1); +static SENSOR_DEVICE_ATTR_RW(avs1_vout_min, isl68137_avs_vout_min, 1); + +static struct attribute *enable_attrs[] = { + &sensor_dev_attr_avs0_enable.dev_attr.attr, + &sensor_dev_attr_avs1_enable.dev_attr.attr, + NULL, +}; + +static struct attribute *avs_ctrl_attrs[] = { + &sensor_dev_attr_avs0_vout.dev_attr.attr, + &sensor_dev_attr_avs1_vout.dev_attr.attr, + &sensor_dev_attr_avs0_vout_max.dev_attr.attr, + &sensor_dev_attr_avs0_vout_min.dev_attr.attr, + &sensor_dev_attr_avs1_vout_max.dev_attr.attr, + &sensor_dev_attr_avs1_vout_min.dev_attr.attr, + NULL, +}; + +static const struct attribute_group enable_group = { + .attrs = enable_attrs, +}; + +static const struct attribute_group avs_ctrl_group = { + .attrs = avs_ctrl_attrs, +}; + +static const struct attribute_group *isl68137_attribute_groups[] = { + &enable_group, + &avs_ctrl_group, + NULL, +}; + +static int raa_dmpvr2_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + int ret; + + switch (reg) { + case PMBUS_VIRT_READ_VMON: + ret = wb_pmbus_read_word_data(client, page, phase, + RAA_DMPVR2_READ_VMON); + break; + default: + ret = -ENODATA; + break; + } + + return ret; +} + +static struct pmbus_driver_info raa_dmpvr_info = { + .pages = 3, + .format[PSC_VOLTAGE_IN] = direct, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_CURRENT_IN] = direct, + .format[PSC_CURRENT_OUT] = direct, + .format[PSC_POWER] = direct, + .format[PSC_TEMPERATURE] = direct, + .m[PSC_VOLTAGE_IN] = 1, + .b[PSC_VOLTAGE_IN] = 0, + .R[PSC_VOLTAGE_IN] = 2, + .m[PSC_VOLTAGE_OUT] = 1, + .b[PSC_VOLTAGE_OUT] = 0, + .R[PSC_VOLTAGE_OUT] = 3, + .m[PSC_CURRENT_IN] = 1, + .b[PSC_CURRENT_IN] = 0, + .R[PSC_CURRENT_IN] = 2, + .m[PSC_CURRENT_OUT] = 1, + .b[PSC_CURRENT_OUT] = 0, + .R[PSC_CURRENT_OUT] = 1, + .m[PSC_POWER] = 1, + .b[PSC_POWER] = 0, + .R[PSC_POWER] = 0, + .m[PSC_TEMPERATURE] = 1, + .b[PSC_TEMPERATURE] = 0, + .R[PSC_TEMPERATURE] = 0, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN + | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 + | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT + | PMBUS_HAVE_VMON, + .func[1] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT + | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, + .func[2] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT + | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, +}; + +static int isl68137_probe(struct i2c_client *client) +{ + struct pmbus_driver_info *info; + + info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + memcpy(info, &raa_dmpvr_info, sizeof(*info)); + + switch (i2c_match_id(raa_dmpvr_id, client)->driver_data) { + case raa_dmpvr1_2rail: + info->pages = 2; + info->R[PSC_VOLTAGE_IN] = 3; + info->func[0] &= ~PMBUS_HAVE_VMON; + info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_POUT; + info->groups = isl68137_attribute_groups; + break; + case raa_dmpvr2_1rail: + info->pages = 1; + info->read_word_data = raa_dmpvr2_read_word_data; + break; + case raa_dmpvr2_2rail_nontc: + info->func[0] &= ~PMBUS_HAVE_TEMP3; + info->func[1] &= ~PMBUS_HAVE_TEMP3; + fallthrough; + case raa_dmpvr2_2rail: + info->pages = 2; + info->read_word_data = raa_dmpvr2_read_word_data; + break; + case raa_dmpvr2_3rail: + info->read_word_data = raa_dmpvr2_read_word_data; + break; + case raa_dmpvr2_hv: + info->pages = 1; + info->R[PSC_VOLTAGE_IN] = 1; + info->m[PSC_VOLTAGE_OUT] = 2; + info->R[PSC_VOLTAGE_OUT] = 2; + info->m[PSC_CURRENT_IN] = 2; + info->m[PSC_POWER] = 2; + info->R[PSC_POWER] = -1; + info->read_word_data = raa_dmpvr2_read_word_data; + break; + default: + return -ENODEV; + } + + return wb_pmbus_do_probe(client, info); +} + +static const struct i2c_device_id raa_dmpvr_id[] = { + {"wb_isl68127", raa_dmpvr1_2rail}, + {"wb_isl68137", raa_dmpvr1_2rail}, + {"wb_isl68220", raa_dmpvr2_2rail}, + {"wb_isl68221", raa_dmpvr2_3rail}, + {"wb_isl68222", raa_dmpvr2_2rail}, + {"wb_isl68223", raa_dmpvr2_2rail}, + {"wb_isl68224", raa_dmpvr2_3rail}, + {"wb_isl68225", raa_dmpvr2_2rail}, + {"wb_isl68226", raa_dmpvr2_3rail}, + {"wb_isl68227", raa_dmpvr2_1rail}, + {"wb_isl68229", raa_dmpvr2_3rail}, + {"wb_isl68233", raa_dmpvr2_2rail}, + {"wb_isl68239", raa_dmpvr2_3rail}, + + {"wb_isl69222", raa_dmpvr2_2rail}, + {"wb_isl69223", raa_dmpvr2_3rail}, + {"wb_isl69224", raa_dmpvr2_2rail}, + {"wb_isl69225", raa_dmpvr2_2rail}, + {"wb_isl69227", raa_dmpvr2_3rail}, + {"wb_isl69228", raa_dmpvr2_3rail}, + {"wb_isl69234", raa_dmpvr2_2rail}, + {"wb_isl69236", raa_dmpvr2_2rail}, + {"wb_isl69239", raa_dmpvr2_3rail}, + {"wb_isl69242", raa_dmpvr2_2rail}, + {"wb_isl69243", raa_dmpvr2_1rail}, + {"wb_isl69247", raa_dmpvr2_2rail}, + {"wb_isl69248", raa_dmpvr2_2rail}, + {"wb_isl69254", raa_dmpvr2_2rail}, + {"wb_isl69255", raa_dmpvr2_2rail}, + {"wb_isl69256", raa_dmpvr2_2rail}, + {"wb_isl69259", raa_dmpvr2_2rail}, + {"wb_isl69260", raa_dmpvr2_2rail}, + {"wb_isl69268", raa_dmpvr2_2rail}, + {"wb_isl69269", raa_dmpvr2_3rail}, + {"wb_isl69298", raa_dmpvr2_2rail}, + + {"wb_raa228000", raa_dmpvr2_hv}, + {"wb_raa228004", raa_dmpvr2_hv}, + {"wb_raa228006", raa_dmpvr2_hv}, + {"wb_raa228228", raa_dmpvr2_2rail_nontc}, + {"wb_raa229001", raa_dmpvr2_2rail}, + {"wb_raa229004", raa_dmpvr2_2rail}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, raa_dmpvr_id); + +/* This is the driver that will be inserted */ +static struct i2c_driver isl68137_driver = { + .driver = { + .name = "wb_isl68137", + }, + .probe_new = isl68137_probe, + .remove = wb_pmbus_do_remove, + .id_table = raa_dmpvr_id, +}; + +module_i2c_driver(isl68137_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("PMBus driver for Renesas digital multiphase voltage regulators"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.c new file mode 100644 index 000000000000..0386cfb0b61d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.c @@ -0,0 +1,992 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * lm75.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (c) 1998, 1999 Frodo Looijaard + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wb_lm75.h" + +/* + * This driver handles the LM75 and compatible digital temperature sensors. + */ + +enum lm75_type { /* keep sorted in alphabetical order */ + adt75, + ds1775, + ds75, + ds7505, + g751, + lm75, + lm75a, + lm75b, + max6625, + max6626, + max31725, + mcp980x, + pct2075, + stds75, + stlm75, + tcn75, + tmp100, + tmp101, + tmp105, + tmp112, + tmp175, + tmp275, + tmp75, + tmp75b, + tmp75c, +}; + +/** + * struct lm75_params - lm75 configuration parameters. + * @set_mask: Bits to set in configuration register when configuring + * the chip. + * @clr_mask: Bits to clear in configuration register when configuring + * the chip. + * @default_resolution: Default number of bits to represent the temperature + * value. + * @resolution_limits: Limit register resolution. Optional. Should be set if + * the resolution of limit registers does not match the + * resolution of the temperature register. + * @resolutions: List of resolutions associated with sample times. + * Optional. Should be set if num_sample_times is larger + * than 1, and if the resolution changes with sample times. + * If set, number of entries must match num_sample_times. + * @default_sample_time:Sample time to be set by default. + * @num_sample_times: Number of possible sample times to be set. Optional. + * Should be set if the number of sample times is larger + * than one. + * @sample_times: All the possible sample times to be set. Mandatory if + * num_sample_times is larger than 1. If set, number of + * entries must match num_sample_times. + */ + +struct lm75_params { + u8 set_mask; + u8 clr_mask; + u8 default_resolution; + u8 resolution_limits; + const u8 *resolutions; + unsigned int default_sample_time; + u8 num_sample_times; + const unsigned int *sample_times; +}; +#if 0 +/* Addresses scanned */ +static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; +#endif +/* The LM75 registers */ +#define LM75_REG_TEMP 0x00 +#define LM75_REG_CONF 0x01 +#define LM75_REG_HYST 0x02 +#define LM75_REG_MAX 0x03 +#define PCT2075_REG_IDLE 0x04 +#define LM75_TEMP_INVALID_RETRY_TIMES (3) + +/* Each client has this additional data */ +struct lm75_data { + struct i2c_client *client; + struct regmap *regmap; + struct regulator *vs; + u8 orig_conf; + u8 current_conf; + u8 resolution; /* In bits, 9 to 16 */ + unsigned int sample_time; /* In ms */ + enum lm75_type kind; + const struct lm75_params *params; +}; + +/*-----------------------------------------------------------------------*/ + +static const u8 lm75_sample_set_masks[] = { 0 << 5, 1 << 5, 2 << 5, 3 << 5 }; + +#define LM75_SAMPLE_CLEAR_MASK (3 << 5) + +/* The structure below stores the configuration values of the supported devices. + * In case of being supported multiple configurations, the default one must + * always be the first element of the array + */ +static const struct lm75_params device_params[] = { + [adt75] = { + .clr_mask = 1 << 5, /* not one-shot mode */ + .default_resolution = 12, + .default_sample_time = MSEC_PER_SEC / 10, + }, + [ds1775] = { + .clr_mask = 3 << 5, + .set_mask = 2 << 5, /* 11-bit mode */ + .default_resolution = 11, + .default_sample_time = 500, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 125, 250, 500, 1000 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [ds75] = { + .clr_mask = 3 << 5, + .set_mask = 2 << 5, /* 11-bit mode */ + .default_resolution = 11, + .default_sample_time = 600, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 150, 300, 600, 1200 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [stds75] = { + .clr_mask = 3 << 5, + .set_mask = 2 << 5, /* 11-bit mode */ + .default_resolution = 11, + .default_sample_time = 600, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 150, 300, 600, 1200 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [stlm75] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 6, + }, + [ds7505] = { + .set_mask = 3 << 5, /* 12-bit mode*/ + .default_resolution = 12, + .default_sample_time = 200, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 25, 50, 100, 200 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [g751] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 10, + }, + [lm75] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 10, + }, + [lm75a] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 10, + }, + [lm75b] = { + .default_resolution = 11, + .default_sample_time = MSEC_PER_SEC / 10, + }, + [max6625] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 7, + }, + [max6626] = { + .default_resolution = 12, + .default_sample_time = MSEC_PER_SEC / 7, + .resolution_limits = 9, + }, + [max31725] = { + .default_resolution = 16, + .default_sample_time = MSEC_PER_SEC / 20, + }, + [tcn75] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 18, + }, + [pct2075] = { + .default_resolution = 11, + .default_sample_time = MSEC_PER_SEC / 10, + .num_sample_times = 31, + .sample_times = (unsigned int []){ 100, 200, 300, 400, 500, 600, + 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, + 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, + 2800, 2900, 3000, 3100 }, + }, + [mcp980x] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode */ + .default_resolution = 12, + .resolution_limits = 9, + .default_sample_time = 240, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 30, 60, 120, 240 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp100] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode */ + .default_resolution = 12, + .default_sample_time = 320, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 40, 80, 160, 320 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp101] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode */ + .default_resolution = 12, + .default_sample_time = 320, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 40, 80, 160, 320 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp105] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode*/ + .default_resolution = 12, + .default_sample_time = 220, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 28, 55, 110, 220 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp112] = { + .set_mask = 3 << 5, /* 8 samples / second */ + .clr_mask = 1 << 7, /* no one-shot mode*/ + .default_resolution = 12, + .default_sample_time = 125, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 125, 250, 1000, 4000 }, + }, + [tmp175] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode*/ + .default_resolution = 12, + .default_sample_time = 220, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 28, 55, 110, 220 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp275] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode*/ + .default_resolution = 12, + .default_sample_time = 220, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 28, 55, 110, 220 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp75] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode*/ + .default_resolution = 12, + .default_sample_time = 220, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 28, 55, 110, 220 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp75b] = { /* not one-shot mode, Conversion rate 37Hz */ + .clr_mask = 1 << 7 | 3 << 5, + .default_resolution = 12, + .default_sample_time = MSEC_PER_SEC / 37, + .sample_times = (unsigned int []){ MSEC_PER_SEC / 37, + MSEC_PER_SEC / 18, + MSEC_PER_SEC / 9, MSEC_PER_SEC / 4 }, + .num_sample_times = 4, + }, + [tmp75c] = { + .clr_mask = 1 << 5, /*not one-shot mode*/ + .default_resolution = 12, + .default_sample_time = MSEC_PER_SEC / 12, + } +}; + +/* input temp threshold check */ +typedef struct lm75_temp_threshold_s { + int chip_type; + int temp_max; + int temp_min; +} lm75_temp_threshold_t; + +static lm75_temp_threshold_t g_lm75_temp_threshold_info[] = { + { + .chip_type = lm75, + .temp_max = 125000, + .temp_min = -55000, + }, + { + .chip_type = tmp275, + .temp_max = 125000, + .temp_min = -40000, + }, +}; + +/*-----------------------------------------------------------------------*/ +static int lm75_input_temp_check(struct lm75_data *data, int input_val) +{ + int i, size; + + size = ARRAY_SIZE(g_lm75_temp_threshold_info); + + for (i = 0; i < size; i++) { + if (g_lm75_temp_threshold_info[i].chip_type == data->kind) { + if ((input_val > g_lm75_temp_threshold_info[i].temp_max) + || (input_val < g_lm75_temp_threshold_info[i].temp_min)) { + dev_dbg(&data->client->dev, "input temp: %d not in range[%d, %d]\n", + input_val, g_lm75_temp_threshold_info[i].temp_min, + g_lm75_temp_threshold_info[i].temp_max); + return -EINVAL; + } + dev_dbg(&data->client->dev, "input temp: %d in range[%d, %d]", input_val, + g_lm75_temp_threshold_info[i].temp_min, g_lm75_temp_threshold_info[i].temp_max); + return 0; + } + } + return 0; +} + +static inline long lm75_reg_to_mc(s16 temp, u8 resolution) +{ + return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8); +} + +static int lm75_write_config(struct lm75_data *data, u8 set_mask, + u8 clr_mask) +{ + u8 value; + + clr_mask |= LM75_SHUTDOWN; + value = data->current_conf & ~clr_mask; + value |= set_mask; + + if (data->current_conf != value) { + s32 err; + + err = i2c_smbus_write_byte_data(data->client, LM75_REG_CONF, + value); + if (err) + return err; + data->current_conf = value; + } + return 0; +} + +static int lm75_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, + long *val) +{ + struct lm75_data *data = dev_get_drvdata(dev); + unsigned int regval; + int err, reg, i, ret; + + switch (type) { + case hwmon_chip: + switch (attr) { + case hwmon_chip_update_interval: + *val = data->sample_time; + break; + default: + return -EINVAL; + } + break; + case hwmon_temp: + switch (attr) { + case hwmon_temp_input: + reg = LM75_REG_TEMP; + break; + case hwmon_temp_max: + reg = LM75_REG_MAX; + break; + case hwmon_temp_max_hyst: + reg = LM75_REG_HYST; + break; + default: + return -EINVAL; + } + for (i = 0; i < LM75_TEMP_INVALID_RETRY_TIMES; i++) { + err = regmap_read(data->regmap, reg, ®val); + if (err < 0) { + return err; + } + *val = lm75_reg_to_mc(regval, data->resolution); + if (reg != LM75_REG_TEMP) { + return 0; + } + /* do input_temp_check */ + ret = lm75_input_temp_check(data, *val); + if (ret == 0) { /* input temp check ok */ + return 0; + } + if ((i + 1) < LM75_TEMP_INVALID_RETRY_TIMES) { + msleep(data->sample_time); + } + } + dev_info(&data->client->dev, "temp_input value: %ld invalid\n", *val); + return -EINVAL; + default: + return -EINVAL; + } + return 0; +} + +static int lm75_write_temp(struct device *dev, u32 attr, long temp) +{ + struct lm75_data *data = dev_get_drvdata(dev); + u8 resolution; + int reg; + + switch (attr) { + case hwmon_temp_max: + reg = LM75_REG_MAX; + break; + case hwmon_temp_max_hyst: + reg = LM75_REG_HYST; + break; + default: + return -EINVAL; + } + + /* + * Resolution of limit registers is assumed to be the same as the + * temperature input register resolution unless given explicitly. + */ + if (data->params->resolution_limits) + resolution = data->params->resolution_limits; + else + resolution = data->resolution; + + temp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); + temp = DIV_ROUND_CLOSEST(temp << (resolution - 8), + 1000) << (16 - resolution); + + return regmap_write(data->regmap, reg, (u16)temp); +} + +static int lm75_update_interval(struct device *dev, long val) +{ + struct lm75_data *data = dev_get_drvdata(dev); + unsigned int reg; + u8 index; + s32 err; + + index = find_closest(val, data->params->sample_times, + (int)data->params->num_sample_times); + + switch (data->kind) { + default: + err = lm75_write_config(data, lm75_sample_set_masks[index], + LM75_SAMPLE_CLEAR_MASK); + if (err) + return err; + + data->sample_time = data->params->sample_times[index]; + if (data->params->resolutions) + data->resolution = data->params->resolutions[index]; + break; + case tmp112: + err = regmap_read(data->regmap, LM75_REG_CONF, ®); + if (err < 0) + return err; + reg &= ~0x00c0; + reg |= (3 - index) << 6; + err = regmap_write(data->regmap, LM75_REG_CONF, reg); + if (err < 0) + return err; + data->sample_time = data->params->sample_times[index]; + break; + case pct2075: + err = i2c_smbus_write_byte_data(data->client, PCT2075_REG_IDLE, + index + 1); + if (err) + return err; + data->sample_time = data->params->sample_times[index]; + break; + } + return 0; +} + +static int lm75_write_chip(struct device *dev, u32 attr, long val) +{ + switch (attr) { + case hwmon_chip_update_interval: + return lm75_update_interval(dev, val); + default: + return -EINVAL; + } + return 0; +} + +static int lm75_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_chip: + return lm75_write_chip(dev, attr, val); + case hwmon_temp: + return lm75_write_temp(dev, attr, val); + default: + return -EINVAL; + } + return 0; +} + +static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct lm75_data *config_data = data; + + switch (type) { + case hwmon_chip: + switch (attr) { + case hwmon_chip_update_interval: + if (config_data->params->num_sample_times > 1) + return 0644; + return 0444; + } + break; + case hwmon_temp: + switch (attr) { + case hwmon_temp_input: + return 0444; + case hwmon_temp_max: + case hwmon_temp_max_hyst: + return 0644; + } + break; + default: + break; + } + return 0; +} + +static const struct hwmon_channel_info *lm75_info[] = { + HWMON_CHANNEL_INFO(chip, + HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL), + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST), + NULL +}; + +static const struct hwmon_ops lm75_hwmon_ops = { + .is_visible = lm75_is_visible, + .read = lm75_read, + .write = lm75_write, +}; + +static const struct hwmon_chip_info lm75_chip_info = { + .ops = &lm75_hwmon_ops, + .info = lm75_info, +}; + +static bool lm75_is_writeable_reg(struct device *dev, unsigned int reg) +{ + return reg != LM75_REG_TEMP; +} + +static bool lm75_is_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg == LM75_REG_TEMP || reg == LM75_REG_CONF; +} + +static const struct regmap_config lm75_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .max_register = PCT2075_REG_IDLE, + .writeable_reg = lm75_is_writeable_reg, + .volatile_reg = lm75_is_volatile_reg, + .val_format_endian = REGMAP_ENDIAN_BIG, + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static void lm75_disable_regulator(void *data) +{ + struct lm75_data *lm75 = data; + + regulator_disable(lm75->vs); +} + +static void lm75_remove(void *data) +{ + struct lm75_data *lm75 = data; + struct i2c_client *client = lm75->client; + + i2c_smbus_write_byte_data(client, LM75_REG_CONF, lm75->orig_conf); +} + +static const struct i2c_device_id lm75_ids[]; + +static int lm75_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct device *hwmon_dev; + struct lm75_data *data; + int status, err; + enum lm75_type kind; + + if (client->dev.of_node) + kind = (enum lm75_type)of_device_get_match_data(&client->dev); + else + kind = i2c_match_id(lm75_ids, client)->driver_data; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) + return -EIO; + + data = devm_kzalloc(dev, sizeof(struct lm75_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->client = client; + data->kind = kind; + + data->vs = devm_regulator_get(dev, "vs"); + if (IS_ERR(data->vs)) + return PTR_ERR(data->vs); + + data->regmap = devm_regmap_init_i2c(client, &lm75_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + + /* Set to LM75 resolution (9 bits, 1/2 degree C) and range. + * Then tweak to be more precise when appropriate. + */ + + data->params = &device_params[data->kind]; + + /* Save default sample time and resolution*/ + data->sample_time = data->params->default_sample_time; + data->resolution = data->params->default_resolution; + + /* Enable the power */ + err = regulator_enable(data->vs); + if (err) { + dev_err(dev, "failed to enable regulator: %d\n", err); + return err; + } + + err = devm_add_action_or_reset(dev, lm75_disable_regulator, data); + if (err) + return err; + + /* Cache original configuration */ + status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); + if (status < 0) { + dev_dbg(dev, "Can't read config? %d\n", status); + return status; + } + data->orig_conf = status; + data->current_conf = status; + + err = lm75_write_config(data, data->params->set_mask, + data->params->clr_mask); + if (err) + return err; + + err = devm_add_action_or_reset(dev, lm75_remove, data); + if (err) + return err; + + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, + data, &lm75_chip_info, + NULL); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); + + dev_info(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), client->name); + + return 0; +} + +static const struct i2c_device_id lm75_ids[] = { + { "wb_adt75", adt75, }, + { "wb_ds1775", ds1775, }, + { "wb_ds75", ds75, }, + { "wb_ds7505", ds7505, }, + { "wb_g751", g751, }, + { "wb_lm75", lm75, }, + { "wb_lm75a", lm75a, }, + { "wb_lm75b", lm75b, }, + { "wb_max6625", max6625, }, + { "wb_max6626", max6626, }, + { "wb_max31725", max31725, }, + { "wb_max31726", max31725, }, + { "wb_mcp980x", mcp980x, }, + { "wb_pct2075", pct2075, }, + { "wb_stds75", stds75, }, + { "wb_stlm75", stlm75, }, + { "wb_tcn75", tcn75, }, + { "wb_tmp100", tmp100, }, + { "wb_tmp101", tmp101, }, + { "wb_tmp105", tmp105, }, + { "wb_tmp112", tmp112, }, + { "wb_tmp175", tmp175, }, + { "wb_tmp275", tmp275, }, + { "wb_tmp75", tmp75, }, + { "wb_tmp75b", tmp75b, }, + { "wb_tmp75c", tmp75c, }, + { /* LIST END */ } +}; +MODULE_DEVICE_TABLE(i2c, lm75_ids); + +static const struct of_device_id __maybe_unused lm75_of_match[] = { + { + .compatible = "adi,adt75", + .data = (void *)adt75 + }, + { + .compatible = "dallas,ds1775", + .data = (void *)ds1775 + }, + { + .compatible = "dallas,ds75", + .data = (void *)ds75 + }, + { + .compatible = "dallas,ds7505", + .data = (void *)ds7505 + }, + { + .compatible = "gmt,g751", + .data = (void *)g751 + }, + { + .compatible = "national,lm75", + .data = (void *)lm75 + }, + { + .compatible = "national,lm75a", + .data = (void *)lm75a + }, + { + .compatible = "national,lm75b", + .data = (void *)lm75b + }, + { + .compatible = "maxim,max6625", + .data = (void *)max6625 + }, + { + .compatible = "maxim,max6626", + .data = (void *)max6626 + }, + { + .compatible = "maxim,max31725", + .data = (void *)max31725 + }, + { + .compatible = "maxim,max31726", + .data = (void *)max31725 + }, + { + .compatible = "maxim,mcp980x", + .data = (void *)mcp980x + }, + { + .compatible = "nxp,pct2075", + .data = (void *)pct2075 + }, + { + .compatible = "st,stds75", + .data = (void *)stds75 + }, + { + .compatible = "st,stlm75", + .data = (void *)stlm75 + }, + { + .compatible = "microchip,tcn75", + .data = (void *)tcn75 + }, + { + .compatible = "ti,tmp100", + .data = (void *)tmp100 + }, + { + .compatible = "ti,tmp101", + .data = (void *)tmp101 + }, + { + .compatible = "ti,tmp105", + .data = (void *)tmp105 + }, + { + .compatible = "ti,tmp112", + .data = (void *)tmp112 + }, + { + .compatible = "ti,tmp175", + .data = (void *)tmp175 + }, + { + .compatible = "ti,tmp275", + .data = (void *)tmp275 + }, + { + .compatible = "ti,tmp75", + .data = (void *)tmp75 + }, + { + .compatible = "ti,tmp75b", + .data = (void *)tmp75b + }, + { + .compatible = "ti,tmp75c", + .data = (void *)tmp75c + }, + { }, +}; +MODULE_DEVICE_TABLE(of, lm75_of_match); + +#define LM75A_ID 0xA1 +#if 0 +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int lm75_detect(struct i2c_client *new_client, + struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = new_client->adapter; + int i; + int conf, hyst, os; + bool is_lm75a = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + /* + * Now, we do the remaining detection. There is no identification- + * dedicated register so we have to rely on several tricks: + * unused bits, registers cycling over 8-address boundaries, + * addresses 0x04-0x07 returning the last read value. + * The cycling+unused addresses combination is not tested, + * since it would significantly slow the detection down and would + * hardly add any value. + * + * The National Semiconductor LM75A is different than earlier + * LM75s. It has an ID byte of 0xaX (where X is the chip + * revision, with 1 being the only revision in existence) in + * register 7, and unused registers return 0xff rather than the + * last read value. + * + * Note that this function only detects the original National + * Semiconductor LM75 and the LM75A. Clones from other vendors + * aren't detected, on purpose, because they are typically never + * found on PC hardware. They are found on embedded designs where + * they can be instantiated explicitly so detection is not needed. + * The absence of identification registers on all these clones + * would make their exhaustive detection very difficult and weak, + * and odds are that the driver would bind to unsupported devices. + */ + + /* Unused bits */ + conf = i2c_smbus_read_byte_data(new_client, 1); + if (conf & 0xe0) + return -ENODEV; + + /* First check for LM75A */ + if (i2c_smbus_read_byte_data(new_client, 7) == LM75A_ID) { + /* + * LM75A returns 0xff on unused registers so + * just to be sure we check for that too. + */ + if (i2c_smbus_read_byte_data(new_client, 4) != 0xff + || i2c_smbus_read_byte_data(new_client, 5) != 0xff + || i2c_smbus_read_byte_data(new_client, 6) != 0xff) + return -ENODEV; + is_lm75a = 1; + hyst = i2c_smbus_read_byte_data(new_client, 2); + os = i2c_smbus_read_byte_data(new_client, 3); + } else { /* Traditional style LM75 detection */ + /* Unused addresses */ + hyst = i2c_smbus_read_byte_data(new_client, 2); + if (i2c_smbus_read_byte_data(new_client, 4) != hyst + || i2c_smbus_read_byte_data(new_client, 5) != hyst + || i2c_smbus_read_byte_data(new_client, 6) != hyst + || i2c_smbus_read_byte_data(new_client, 7) != hyst) + return -ENODEV; + os = i2c_smbus_read_byte_data(new_client, 3); + if (i2c_smbus_read_byte_data(new_client, 4) != os + || i2c_smbus_read_byte_data(new_client, 5) != os + || i2c_smbus_read_byte_data(new_client, 6) != os + || i2c_smbus_read_byte_data(new_client, 7) != os) + return -ENODEV; + } + /* + * It is very unlikely that this is a LM75 if both + * hysteresis and temperature limit registers are 0. + */ + if (hyst == 0 && os == 0) + return -ENODEV; + + /* Addresses cycling */ + for (i = 8; i <= 248; i += 40) { + if (i2c_smbus_read_byte_data(new_client, i + 1) != conf + || i2c_smbus_read_byte_data(new_client, i + 2) != hyst + || i2c_smbus_read_byte_data(new_client, i + 3) != os) + return -ENODEV; + if (is_lm75a && i2c_smbus_read_byte_data(new_client, i + 7) + != LM75A_ID) + return -ENODEV; + } + + strlcpy(info->type, is_lm75a ? "lm75a" : "lm75", I2C_NAME_SIZE); + + return 0; +} +#endif + +#ifdef CONFIG_PM +static int lm75_suspend(struct device *dev) +{ + int status; + struct i2c_client *client = to_i2c_client(dev); + + status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); + if (status < 0) { + dev_dbg(&client->dev, "Can't read config? %d\n", status); + return status; + } + status = status | LM75_SHUTDOWN; + i2c_smbus_write_byte_data(client, LM75_REG_CONF, status); + return 0; +} + +static int lm75_resume(struct device *dev) +{ + int status; + struct i2c_client *client = to_i2c_client(dev); + + status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); + if (status < 0) { + dev_dbg(&client->dev, "Can't read config? %d\n", status); + return status; + } + status = status & ~LM75_SHUTDOWN; + i2c_smbus_write_byte_data(client, LM75_REG_CONF, status); + return 0; +} + +static const struct dev_pm_ops lm75_dev_pm_ops = { + .suspend = lm75_suspend, + .resume = lm75_resume, +}; +#define LM75_DEV_PM_OPS (&lm75_dev_pm_ops) +#else +#define LM75_DEV_PM_OPS NULL +#endif /* CONFIG_PM */ + +static struct i2c_driver lm75_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "wb_lm75", + .of_match_table = of_match_ptr(lm75_of_match), + .pm = LM75_DEV_PM_OPS, + }, + .probe_new = lm75_probe, + .id_table = lm75_ids, + /* .detect = lm75_detect, */ + /* .address_list = normal_i2c, */ +}; + +module_i2c_driver(lm75_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("LM75 driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.h new file mode 100644 index 000000000000..a398171162a8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * lm75.h - Part of lm_sensors, Linux kernel modules for hardware monitoring + * Copyright (c) 2003 Mark M. Hoffman + */ + +/* + * This file contains common code for encoding/decoding LM75 type + * temperature readings, which are emulated by many of the chips + * we support. As the user is unlikely to load more than one driver + * which contains this code, we don't worry about the wasted space. + */ + +#include + +/* straight from the datasheet */ +#define LM75_TEMP_MIN (-55000) +#define LM75_TEMP_MAX 125000 +#define LM75_SHUTDOWN 0x01 + +/* + * TEMP: 0.001C/bit (-55C to +125C) + * REG: (0.5C/bit, two's complement) << 7 + */ +static inline u16 LM75_TEMP_TO_REG(long temp) +{ + int ntemp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); + + ntemp += (ntemp < 0 ? -250 : 250); + return (u16)((ntemp / 500) << 7); +} + +static inline int LM75_TEMP_FROM_REG(u16 reg) +{ + /* + * use integer division instead of equivalent right shift to + * guarantee arithmetic shift and preserve the sign + */ + return ((s16)reg / 128) * 500; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus.h new file mode 100644 index 000000000000..9fb2c9017ae6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus.h @@ -0,0 +1,535 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * wb_pmbus.h - Common defines and structures for PMBus devices + * + * Copyright (c) 2010, 2011 Ericsson AB. + * Copyright (c) 2012 Guenter Roeck + */ + +#ifndef WB_PMBUS_H +#define WB_PMBUS_H + +#include +#include +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +/* + * Registers + */ +enum pmbus_regs { + PMBUS_PAGE = 0x00, + PMBUS_OPERATION = 0x01, + PMBUS_ON_OFF_CONFIG = 0x02, + PMBUS_CLEAR_FAULTS = 0x03, + PMBUS_PHASE = 0x04, + + PMBUS_WRITE_PROTECT = 0x10, + + PMBUS_CAPABILITY = 0x19, + PMBUS_QUERY = 0x1A, + + PMBUS_VOUT_MODE = 0x20, + PMBUS_VOUT_COMMAND = 0x21, + PMBUS_VOUT_TRIM = 0x22, + PMBUS_VOUT_CAL_OFFSET = 0x23, + PMBUS_VOUT_MAX = 0x24, + PMBUS_VOUT_MARGIN_HIGH = 0x25, + PMBUS_VOUT_MARGIN_LOW = 0x26, + PMBUS_VOUT_TRANSITION_RATE = 0x27, + PMBUS_VOUT_DROOP = 0x28, + PMBUS_VOUT_SCALE_LOOP = 0x29, + PMBUS_VOUT_SCALE_MONITOR = 0x2A, + + PMBUS_COEFFICIENTS = 0x30, + PMBUS_POUT_MAX = 0x31, + + PMBUS_FAN_CONFIG_12 = 0x3A, + PMBUS_FAN_COMMAND_1 = 0x3B, + PMBUS_FAN_COMMAND_2 = 0x3C, + PMBUS_FAN_CONFIG_34 = 0x3D, + PMBUS_FAN_COMMAND_3 = 0x3E, + PMBUS_FAN_COMMAND_4 = 0x3F, + + PMBUS_VOUT_OV_FAULT_LIMIT = 0x40, + PMBUS_VOUT_OV_FAULT_RESPONSE = 0x41, + PMBUS_VOUT_OV_WARN_LIMIT = 0x42, + PMBUS_VOUT_UV_WARN_LIMIT = 0x43, + PMBUS_VOUT_UV_FAULT_LIMIT = 0x44, + PMBUS_VOUT_UV_FAULT_RESPONSE = 0x45, + PMBUS_IOUT_OC_FAULT_LIMIT = 0x46, + PMBUS_IOUT_OC_FAULT_RESPONSE = 0x47, + PMBUS_IOUT_OC_LV_FAULT_LIMIT = 0x48, + PMBUS_IOUT_OC_LV_FAULT_RESPONSE = 0x49, + PMBUS_IOUT_OC_WARN_LIMIT = 0x4A, + PMBUS_IOUT_UC_FAULT_LIMIT = 0x4B, + PMBUS_IOUT_UC_FAULT_RESPONSE = 0x4C, + + PMBUS_OT_FAULT_LIMIT = 0x4F, + PMBUS_OT_FAULT_RESPONSE = 0x50, + PMBUS_OT_WARN_LIMIT = 0x51, + PMBUS_UT_WARN_LIMIT = 0x52, + PMBUS_UT_FAULT_LIMIT = 0x53, + PMBUS_UT_FAULT_RESPONSE = 0x54, + PMBUS_VIN_OV_FAULT_LIMIT = 0x55, + PMBUS_VIN_OV_FAULT_RESPONSE = 0x56, + PMBUS_VIN_OV_WARN_LIMIT = 0x57, + PMBUS_VIN_UV_WARN_LIMIT = 0x58, + PMBUS_VIN_UV_FAULT_LIMIT = 0x59, + + PMBUS_IIN_OC_FAULT_LIMIT = 0x5B, + PMBUS_IIN_OC_WARN_LIMIT = 0x5D, + + PMBUS_POUT_OP_FAULT_LIMIT = 0x68, + PMBUS_POUT_OP_WARN_LIMIT = 0x6A, + PMBUS_PIN_OP_WARN_LIMIT = 0x6B, + + PMBUS_STATUS_BYTE = 0x78, + PMBUS_STATUS_WORD = 0x79, + PMBUS_STATUS_VOUT = 0x7A, + PMBUS_STATUS_IOUT = 0x7B, + PMBUS_STATUS_INPUT = 0x7C, + PMBUS_STATUS_TEMPERATURE = 0x7D, + PMBUS_STATUS_CML = 0x7E, + PMBUS_STATUS_OTHER = 0x7F, + PMBUS_STATUS_MFR_SPECIFIC = 0x80, + PMBUS_STATUS_FAN_12 = 0x81, + PMBUS_STATUS_FAN_34 = 0x82, + + PMBUS_READ_VIN = 0x88, + PMBUS_READ_IIN = 0x89, + PMBUS_READ_VCAP = 0x8A, + PMBUS_READ_VOUT = 0x8B, + PMBUS_READ_IOUT = 0x8C, + PMBUS_READ_TEMPERATURE_1 = 0x8D, + PMBUS_READ_TEMPERATURE_2 = 0x8E, + PMBUS_READ_TEMPERATURE_3 = 0x8F, + PMBUS_READ_FAN_SPEED_1 = 0x90, + PMBUS_READ_FAN_SPEED_2 = 0x91, + PMBUS_READ_FAN_SPEED_3 = 0x92, + PMBUS_READ_FAN_SPEED_4 = 0x93, + PMBUS_READ_DUTY_CYCLE = 0x94, + PMBUS_READ_FREQUENCY = 0x95, + PMBUS_READ_POUT = 0x96, + PMBUS_READ_PIN = 0x97, + + PMBUS_REVISION = 0x98, + PMBUS_MFR_ID = 0x99, + PMBUS_MFR_MODEL = 0x9A, + PMBUS_MFR_REVISION = 0x9B, + PMBUS_MFR_LOCATION = 0x9C, + PMBUS_MFR_DATE = 0x9D, + PMBUS_MFR_SERIAL = 0x9E, + + PMBUS_MFR_VIN_MIN = 0xA0, + PMBUS_MFR_VIN_MAX = 0xA1, + PMBUS_MFR_IIN_MAX = 0xA2, + PMBUS_MFR_PIN_MAX = 0xA3, + PMBUS_MFR_VOUT_MIN = 0xA4, + PMBUS_MFR_VOUT_MAX = 0xA5, + PMBUS_MFR_IOUT_MAX = 0xA6, + PMBUS_MFR_POUT_MAX = 0xA7, + + PMBUS_IC_DEVICE_ID = 0xAD, + PMBUS_IC_DEVICE_REV = 0xAE, + + PMBUS_MFR_MAX_TEMP_1 = 0xC0, + PMBUS_MFR_MAX_TEMP_2 = 0xC1, + PMBUS_MFR_MAX_TEMP_3 = 0xC2, + +/* + * Virtual registers. + * Useful to support attributes which are not supported by standard PMBus + * registers but exist as manufacturer specific registers on individual chips. + * Must be mapped to real registers in device specific code. + * + * Semantics: + * Virtual registers are all word size. + * READ registers are read-only; writes are either ignored or return an error. + * RESET registers are read/write. Reading reset registers returns zero + * (used for detection), writing any value causes the associated history to be + * reset. + * Virtual registers have to be handled in device specific driver code. Chip + * driver code returns non-negative register values if a virtual register is + * supported, or a negative error code if not. The chip driver may return + * -ENODATA or any other error code in this case, though an error code other + * than -ENODATA is handled more efficiently and thus preferred. Either case, + * the calling PMBus core code will abort if the chip driver returns an error + * code when reading or writing virtual registers. + */ + PMBUS_VIRT_BASE = 0x100, + PMBUS_VIRT_READ_TEMP_AVG, + PMBUS_VIRT_READ_TEMP_MIN, + PMBUS_VIRT_READ_TEMP_MAX, + PMBUS_VIRT_RESET_TEMP_HISTORY, + PMBUS_VIRT_READ_VIN_AVG, + PMBUS_VIRT_READ_VIN_MIN, + PMBUS_VIRT_READ_VIN_MAX, + PMBUS_VIRT_RESET_VIN_HISTORY, + PMBUS_VIRT_READ_IIN_AVG, + PMBUS_VIRT_READ_IIN_MIN, + PMBUS_VIRT_READ_IIN_MAX, + PMBUS_VIRT_RESET_IIN_HISTORY, + PMBUS_VIRT_READ_PIN_AVG, + PMBUS_VIRT_READ_PIN_MIN, + PMBUS_VIRT_READ_PIN_MAX, + PMBUS_VIRT_RESET_PIN_HISTORY, + PMBUS_VIRT_READ_POUT_AVG, + PMBUS_VIRT_READ_POUT_MIN, + PMBUS_VIRT_READ_POUT_MAX, + PMBUS_VIRT_RESET_POUT_HISTORY, + PMBUS_VIRT_READ_VOUT_AVG, + PMBUS_VIRT_READ_VOUT_MIN, + PMBUS_VIRT_READ_VOUT_MAX, + PMBUS_VIRT_RESET_VOUT_HISTORY, + PMBUS_VIRT_READ_IOUT_AVG, + PMBUS_VIRT_READ_IOUT_MIN, + PMBUS_VIRT_READ_IOUT_MAX, + PMBUS_VIRT_RESET_IOUT_HISTORY, + PMBUS_VIRT_READ_TEMP2_AVG, + PMBUS_VIRT_READ_TEMP2_MIN, + PMBUS_VIRT_READ_TEMP2_MAX, + PMBUS_VIRT_RESET_TEMP2_HISTORY, + + PMBUS_VIRT_READ_VMON, + PMBUS_VIRT_VMON_UV_WARN_LIMIT, + PMBUS_VIRT_VMON_OV_WARN_LIMIT, + PMBUS_VIRT_VMON_UV_FAULT_LIMIT, + PMBUS_VIRT_VMON_OV_FAULT_LIMIT, + PMBUS_VIRT_STATUS_VMON, + + /* + * RPM and PWM Fan control + * + * Drivers wanting to expose PWM control must define the behaviour of + * PMBUS_VIRT_PWM_[1-4] and PMBUS_VIRT_PWM_ENABLE_[1-4] in the + * {read,write}_word_data callback. + * + * pmbus core provides a default implementation for + * PMBUS_VIRT_FAN_TARGET_[1-4]. + * + * TARGET, PWM and PWM_ENABLE members must be defined sequentially; + * pmbus core uses the difference between the provided register and + * it's _1 counterpart to calculate the FAN/PWM ID. + */ + PMBUS_VIRT_FAN_TARGET_1, + PMBUS_VIRT_FAN_TARGET_2, + PMBUS_VIRT_FAN_TARGET_3, + PMBUS_VIRT_FAN_TARGET_4, + PMBUS_VIRT_PWM_1, + PMBUS_VIRT_PWM_2, + PMBUS_VIRT_PWM_3, + PMBUS_VIRT_PWM_4, + PMBUS_VIRT_PWM_ENABLE_1, + PMBUS_VIRT_PWM_ENABLE_2, + PMBUS_VIRT_PWM_ENABLE_3, + PMBUS_VIRT_PWM_ENABLE_4, + + /* Samples for average + * + * Drivers wanting to expose functionality for changing the number of + * samples used for average values should implement support in + * {read,write}_word_data callback for either PMBUS_VIRT_SAMPLES if it + * applies to all types of measurements, or any number of specific + * PMBUS_VIRT_*_SAMPLES registers to allow for individual control. + */ + PMBUS_VIRT_SAMPLES, + PMBUS_VIRT_IN_SAMPLES, + PMBUS_VIRT_CURR_SAMPLES, + PMBUS_VIRT_POWER_SAMPLES, + PMBUS_VIRT_TEMP_SAMPLES, +}; + +/* + * OPERATION + */ +#define PB_OPERATION_CONTROL_ON BIT(7) + +/* + * WRITE_PROTECT + */ +#define PB_WP_ALL BIT(7) /* all but WRITE_PROTECT */ +#define PB_WP_OP BIT(6) /* all but WP, OPERATION, PAGE */ +#define PB_WP_VOUT BIT(5) /* all but WP, OPERATION, PAGE, VOUT, ON_OFF */ + +#define PB_WP_ANY (PB_WP_ALL | PB_WP_OP | PB_WP_VOUT) + +/* + * CAPABILITY + */ +#define PB_CAPABILITY_SMBALERT BIT(4) +#define PB_CAPABILITY_ERROR_CHECK BIT(7) + +/* + * VOUT_MODE + */ +#define PB_VOUT_MODE_MODE_MASK 0xe0 +#define PB_VOUT_MODE_PARAM_MASK 0x1f + +#define PB_VOUT_MODE_LINEAR 0x00 +#define PB_VOUT_MODE_VID 0x20 +#define PB_VOUT_MODE_DIRECT 0x40 + +/* + * Fan configuration + */ +#define PB_FAN_2_PULSE_MASK (BIT(0) | BIT(1)) +#define PB_FAN_2_RPM BIT(2) +#define PB_FAN_2_INSTALLED BIT(3) +#define PB_FAN_1_PULSE_MASK (BIT(4) | BIT(5)) +#define PB_FAN_1_RPM BIT(6) +#define PB_FAN_1_INSTALLED BIT(7) + +enum pmbus_fan_mode { percent = 0, rpm }; + +/* + * STATUS_BYTE, STATUS_WORD (lower) + */ +#define PB_STATUS_NONE_ABOVE BIT(0) +#define PB_STATUS_CML BIT(1) +#define PB_STATUS_TEMPERATURE BIT(2) +#define PB_STATUS_VIN_UV BIT(3) +#define PB_STATUS_IOUT_OC BIT(4) +#define PB_STATUS_VOUT_OV BIT(5) +#define PB_STATUS_OFF BIT(6) +#define PB_STATUS_BUSY BIT(7) + +/* + * STATUS_WORD (upper) + */ +#define PB_STATUS_UNKNOWN BIT(8) +#define PB_STATUS_OTHER BIT(9) +#define PB_STATUS_FANS BIT(10) +#define PB_STATUS_POWER_GOOD_N BIT(11) +#define PB_STATUS_WORD_MFR BIT(12) +#define PB_STATUS_INPUT BIT(13) +#define PB_STATUS_IOUT_POUT BIT(14) +#define PB_STATUS_VOUT BIT(15) + +/* + * STATUS_IOUT + */ +#define PB_POUT_OP_WARNING BIT(0) +#define PB_POUT_OP_FAULT BIT(1) +#define PB_POWER_LIMITING BIT(2) +#define PB_CURRENT_SHARE_FAULT BIT(3) +#define PB_IOUT_UC_FAULT BIT(4) +#define PB_IOUT_OC_WARNING BIT(5) +#define PB_IOUT_OC_LV_FAULT BIT(6) +#define PB_IOUT_OC_FAULT BIT(7) + +/* + * STATUS_VOUT, STATUS_INPUT + */ +#define PB_VOLTAGE_UV_FAULT BIT(4) +#define PB_VOLTAGE_UV_WARNING BIT(5) +#define PB_VOLTAGE_OV_WARNING BIT(6) +#define PB_VOLTAGE_OV_FAULT BIT(7) + +/* + * STATUS_INPUT + */ +#define PB_PIN_OP_WARNING BIT(0) +#define PB_IIN_OC_WARNING BIT(1) +#define PB_IIN_OC_FAULT BIT(2) + +/* + * STATUS_TEMPERATURE + */ +#define PB_TEMP_UT_FAULT BIT(4) +#define PB_TEMP_UT_WARNING BIT(5) +#define PB_TEMP_OT_WARNING BIT(6) +#define PB_TEMP_OT_FAULT BIT(7) + +/* + * STATUS_FAN + */ +#define PB_FAN_AIRFLOW_WARNING BIT(0) +#define PB_FAN_AIRFLOW_FAULT BIT(1) +#define PB_FAN_FAN2_SPEED_OVERRIDE BIT(2) +#define PB_FAN_FAN1_SPEED_OVERRIDE BIT(3) +#define PB_FAN_FAN2_WARNING BIT(4) +#define PB_FAN_FAN1_WARNING BIT(5) +#define PB_FAN_FAN2_FAULT BIT(6) +#define PB_FAN_FAN1_FAULT BIT(7) + +/* + * CML_FAULT_STATUS + */ +#define PB_CML_FAULT_OTHER_MEM_LOGIC BIT(0) +#define PB_CML_FAULT_OTHER_COMM BIT(1) +#define PB_CML_FAULT_PROCESSOR BIT(3) +#define PB_CML_FAULT_MEMORY BIT(4) +#define PB_CML_FAULT_PACKET_ERROR BIT(5) +#define PB_CML_FAULT_INVALID_DATA BIT(6) +#define PB_CML_FAULT_INVALID_COMMAND BIT(7) + +enum pmbus_sensor_classes { + PSC_VOLTAGE_IN = 0, + PSC_VOLTAGE_OUT, + PSC_CURRENT_IN, + PSC_CURRENT_OUT, + PSC_POWER, + PSC_TEMPERATURE, + PSC_FAN, + PSC_PWM, + PSC_NUM_CLASSES /* Number of power sensor classes */ +}; + +#define PMBUS_PAGES 32 /* Per PMBus specification */ +#define PMBUS_PHASES 8 /* Maximum number of phases per page */ + +/* Functionality bit mask */ +#define PMBUS_HAVE_VIN BIT(0) +#define PMBUS_HAVE_VCAP BIT(1) +#define PMBUS_HAVE_VOUT BIT(2) +#define PMBUS_HAVE_IIN BIT(3) +#define PMBUS_HAVE_IOUT BIT(4) +#define PMBUS_HAVE_PIN BIT(5) +#define PMBUS_HAVE_POUT BIT(6) +#define PMBUS_HAVE_FAN12 BIT(7) +#define PMBUS_HAVE_FAN34 BIT(8) +#define PMBUS_HAVE_TEMP BIT(9) +#define PMBUS_HAVE_TEMP2 BIT(10) +#define PMBUS_HAVE_TEMP3 BIT(11) +#define PMBUS_HAVE_STATUS_VOUT BIT(12) +#define PMBUS_HAVE_STATUS_IOUT BIT(13) +#define PMBUS_HAVE_STATUS_INPUT BIT(14) +#define PMBUS_HAVE_STATUS_TEMP BIT(15) +#define PMBUS_HAVE_STATUS_FAN12 BIT(16) +#define PMBUS_HAVE_STATUS_FAN34 BIT(17) +#define PMBUS_HAVE_VMON BIT(18) +#define PMBUS_HAVE_STATUS_VMON BIT(19) +#define PMBUS_HAVE_PWM12 BIT(20) +#define PMBUS_HAVE_PWM34 BIT(21) +#define PMBUS_HAVE_SAMPLES BIT(22) + +#define PMBUS_PHASE_VIRTUAL BIT(30) /* Phases on this page are virtual */ +#define PMBUS_PAGE_VIRTUAL BIT(31) /* Page is virtual */ + +enum pmbus_data_format { linear = 0, direct, vid }; +enum vrm_version { vr11 = 0, vr12, vr13, imvp9, amd625mv }; + +struct pmbus_driver_info { + int pages; /* Total number of pages */ + u8 phases[PMBUS_PAGES]; /* Number of phases per page */ + enum pmbus_data_format format[PSC_NUM_CLASSES]; + enum vrm_version vrm_version[PMBUS_PAGES]; /* vrm version per page */ + /* + * Support one set of coefficients for each sensor type + * Used for chips providing data in direct mode. + */ + int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */ + int b[PSC_NUM_CLASSES]; /* offset */ + int R[PSC_NUM_CLASSES]; /* exponent */ + + u32 func[PMBUS_PAGES]; /* Functionality, per page */ + u32 pfunc[PMBUS_PHASES];/* Functionality, per phase */ + /* + * The following functions map manufacturing specific register values + * to PMBus standard register values. Specify only if mapping is + * necessary. + * Functions return the register value (read) or zero (write) if + * successful. A return value of -ENODATA indicates that there is no + * manufacturer specific register, but that a standard PMBus register + * may exist. Any other negative return value indicates that the + * register does not exist, and that no attempt should be made to read + * the standard register. + */ + int (*read_byte_data)(struct i2c_client *client, int page, int reg); + int (*read_word_data)(struct i2c_client *client, int page, int phase, + int reg); + int (*write_word_data)(struct i2c_client *client, int page, int reg, + u16 word); + int (*write_byte)(struct i2c_client *client, int page, u8 value); + /* + * The identify function determines supported PMBus functionality. + * This function is only necessary if a chip driver supports multiple + * chips, and the chip functionality is not pre-determined. + */ + int (*identify)(struct i2c_client *client, + struct pmbus_driver_info *info); + + /* Regulator functionality, if supported by this chip driver. */ + int num_regulators; + const struct regulator_desc *reg_desc; + + /* custom attributes */ + const struct attribute_group **groups; +}; + +/* Regulator ops */ + +extern const struct regulator_ops wb_pmbus_regulator_ops; + +/* Macro for filling in array of struct regulator_desc */ +#define PMBUS_REGULATOR(_name, _id) \ + [_id] = { \ + .name = (_name # _id), \ + .id = (_id), \ + .of_match = of_match_ptr(_name # _id), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = &wb_pmbus_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + } + +struct pmbus_data { + struct device *dev; + struct device *hwmon_dev; + + u32 flags; /* from platform data */ + + int exponent[PMBUS_PAGES]; /* linear mode: exponent for output voltages */ + + const struct pmbus_driver_info *info; + + int max_attributes; + int num_attributes; + struct attribute_group group; + const struct attribute_group **groups; + struct dentry *debugfs; /* debugfs device directory */ + + struct pmbus_sensor *sensors; + + struct mutex update_lock; + + bool has_status_word; /* device uses STATUS_WORD register */ + int (*read_status)(struct i2c_client *client, int page); + + s16 currpage; /* current page, -1 for unknown/unset */ + s16 currphase; /* current phase, 0xff for all, -1 for unknown/unset */ + int vout_max[PMBUS_PAGES]; /* pmbus maximum output voltage */ + int vout_min[PMBUS_PAGES]; /* pmbus minimum output voltage */ +}; + +/* Function declarations */ +void wb_pmbus_clear_cache(struct i2c_client *client); +int wb_pmbus_set_page(struct i2c_client *client, int page, int phase); +int wb_pmbus_read_word_data(struct i2c_client *client, int page, int phase, + u8 reg); +int wb_pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, + u16 word); +int wb_pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg); +int wb_pmbus_write_byte(struct i2c_client *client, int page, u8 value); +int wb_pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, + u8 value); +int wb_pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, + u8 mask, u8 value); +void wb_pmbus_clear_faults(struct i2c_client *client); +bool wb_pmbus_check_byte_register(struct i2c_client *client, int page, int reg); +bool wb_pmbus_check_word_register(struct i2c_client *client, int page, int reg); +int wb_pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info); +int wb_pmbus_do_remove(struct i2c_client *client); +const struct pmbus_driver_info *wb_pmbus_get_driver_info(struct i2c_client + *client); +int wb_pmbus_get_fan_rate_device(struct i2c_client *client, int page, int id, + enum pmbus_fan_mode mode); +int wb_pmbus_get_fan_rate_cached(struct i2c_client *client, int page, int id, + enum pmbus_fan_mode mode); +int wb_pmbus_update_fan(struct i2c_client *client, int page, int id, + u8 config, u8 mask, u16 command); +struct dentry *wb_pmbus_get_debugfs_dir(struct i2c_client *client); + +#endif /* WB_PMBUS_H */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus_core.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus_core.c new file mode 100644 index 000000000000..343aea446b9f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus_core.c @@ -0,0 +1,2780 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for PMBus devices + * + * Copyright (c) 2010, 2011 Ericsson AB. + * Copyright (c) 2012 Guenter Roeck + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wb_pmbus.h" + +/* + * Number of additional attribute pointers to allocate + * with each call to krealloc + */ +#define PMBUS_ATTR_ALLOC_SIZE (32) +#define PMBUS_NAME_SIZE (24) +#define PMBUS_RETRY_SLEEP_TIME (10000) /* 10ms */ +#define PMBUS_RETRY_TIME (3) + +struct pmbus_sensor { + struct pmbus_sensor *next; + char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */ + struct device_attribute attribute; + u8 page; /* page number */ + u8 phase; /* phase number, 0xff for all phases */ + u16 reg; /* register */ + enum pmbus_sensor_classes class; /* sensor class */ + bool update; /* runtime sensor update needed */ + bool convert; /* Whether or not to apply linear/vid/direct */ + int data; /* Sensor data. + Negative if there was a read error */ +}; +#define to_pmbus_sensor(_attr) \ + container_of(_attr, struct pmbus_sensor, attribute) + +struct pmbus_boolean { + char name[PMBUS_NAME_SIZE]; /* sysfs boolean name */ + struct sensor_device_attribute attribute; + struct pmbus_sensor *s1; + struct pmbus_sensor *s2; +}; +#define to_pmbus_boolean(_attr) \ + container_of(_attr, struct pmbus_boolean, attribute) + +struct pmbus_label { + char name[PMBUS_NAME_SIZE]; /* sysfs label name */ + struct device_attribute attribute; + char label[PMBUS_NAME_SIZE]; /* label */ +}; +#define to_pmbus_label(_attr) \ + container_of(_attr, struct pmbus_label, attribute) + +/* Macros for converting between sensor index and register/page/status mask */ + +#define PB_STATUS_MASK 0xffff +#define PB_REG_SHIFT 16 +#define PB_REG_MASK 0x3ff +#define PB_PAGE_SHIFT 26 +#define PB_PAGE_MASK 0x3f + +#define pb_reg_to_index(page, reg, mask) (((page) << PB_PAGE_SHIFT) | \ + ((reg) << PB_REG_SHIFT) | (mask)) + +#define pb_index_to_page(index) (((index) >> PB_PAGE_SHIFT) & PB_PAGE_MASK) +#define pb_index_to_reg(index) (((index) >> PB_REG_SHIFT) & PB_REG_MASK) +#define pb_index_to_mask(index) ((index) & PB_STATUS_MASK) + +struct pmbus_debugfs_entry { + struct i2c_client *client; + u8 page; + u8 reg; +}; + +static const int pmbus_fan_rpm_mask[] = { + PB_FAN_1_RPM, + PB_FAN_2_RPM, + PB_FAN_1_RPM, + PB_FAN_2_RPM, +}; + +static const int pmbus_fan_config_registers[] = { + PMBUS_FAN_CONFIG_12, + PMBUS_FAN_CONFIG_12, + PMBUS_FAN_CONFIG_34, + PMBUS_FAN_CONFIG_34 +}; + +static const int pmbus_fan_command_registers[] = { + PMBUS_FAN_COMMAND_1, + PMBUS_FAN_COMMAND_2, + PMBUS_FAN_COMMAND_3, + PMBUS_FAN_COMMAND_4, +}; + +void wb_pmbus_clear_cache(struct i2c_client *client) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + struct pmbus_sensor *sensor; + + for (sensor = data->sensors; sensor; sensor = sensor->next) + sensor->data = -ENODATA; +} +EXPORT_SYMBOL_GPL(wb_pmbus_clear_cache); + +static int wb_pmbus_set_page_tmp(struct i2c_client *client, int page, int phase) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + int rv; + + if (page < 0) + return 0; + + if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL) && + data->info->pages > 1 && page != data->currpage) { + rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); + if (rv < 0) + return rv; + + rv = i2c_smbus_read_byte_data(client, PMBUS_PAGE); + if (rv < 0) + return rv; + + if (rv != page) + return -EIO; + } + data->currpage = page; + + if (data->info->phases[page] && data->currphase != phase && + !(data->info->func[page] & PMBUS_PHASE_VIRTUAL)) { + rv = i2c_smbus_write_byte_data(client, PMBUS_PHASE, + phase); + if (rv) + return rv; + } + data->currphase = phase; + + return 0; +} + +int wb_pmbus_set_page(struct i2c_client *client, int page, int phase) +{ + int rv, i; + struct device *dev = &client->dev; + + for (i = 0; i < PMBUS_RETRY_TIME; i++) { + rv = wb_pmbus_set_page_tmp(client, page, phase); + if(rv >= 0){ + return rv; + } + if ((i + 1) < PMBUS_RETRY_TIME) { + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + } + dev_dbg(dev, "wb_pmbus_set_page failed, page=%d, phase=%d, rv=%d\n", + page, phase, rv); + return rv; +} +EXPORT_SYMBOL_GPL(wb_pmbus_set_page); + +static int wb_pmbus_write_byte_tmp(struct i2c_client *client, int page, u8 value) +{ + int rv; + + rv = wb_pmbus_set_page(client, page, 0xff); + if (rv < 0) + return rv; + + return i2c_smbus_write_byte(client, value); +} + +int wb_pmbus_write_byte(struct i2c_client *client, int page, u8 value) +{ + int rv, i; + struct device *dev = &client->dev; + + for (i = 0; i < PMBUS_RETRY_TIME; i++) { + rv = wb_pmbus_write_byte_tmp(client, page, value); + if(rv >= 0){ + return rv; + } + if ((i + 1) < PMBUS_RETRY_TIME) { + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + } + dev_dbg(dev, "wb_pmbus_write_byte failed, page=%d, value=0x%x, rv: %d\n", + page, value, rv); + return rv; +} + +EXPORT_SYMBOL_GPL(wb_pmbus_write_byte); + +/* + * _pmbus_write_byte() is similar to pmbus_write_byte(), but checks if + * a device specific mapping function exists and calls it if necessary. + */ +static int _pmbus_write_byte(struct i2c_client *client, int page, u8 value) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + const struct pmbus_driver_info *info = data->info; + int status; + + if (info->write_byte) { + status = info->write_byte(client, page, value); + if (status != -ENODATA) + return status; + } + return wb_pmbus_write_byte(client, page, value); +} + +static int wb_pmbus_write_word_data_tmp(struct i2c_client *client, int page, u8 reg, + u16 word) +{ + int rv; + + rv = wb_pmbus_set_page(client, page, 0xff); + if (rv < 0) + return rv; + + return i2c_smbus_write_word_data(client, reg, word); +} + +int wb_pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, + u16 word) +{ + int rv, i; + struct device *dev = &client->dev; + + for (i = 0; i < PMBUS_RETRY_TIME; i++) { + rv = wb_pmbus_write_word_data_tmp(client, page, reg, word); + if(rv >= 0){ + return rv; + } + if ((i + 1) < PMBUS_RETRY_TIME) { + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + } + dev_dbg(dev, "wb_pmbus_write_word_data failed, page: %d, reg: 0x%x, value: 0x%x, rv: %d\n", + page, reg, word, rv); + return rv; + +} +EXPORT_SYMBOL_GPL(wb_pmbus_write_word_data); + +static int pmbus_write_virt_reg(struct i2c_client *client, int page, int reg, + u16 word) +{ + int bit; + int id; + int rv; + + switch (reg) { + case PMBUS_VIRT_FAN_TARGET_1 ... PMBUS_VIRT_FAN_TARGET_4: + id = reg - PMBUS_VIRT_FAN_TARGET_1; + bit = pmbus_fan_rpm_mask[id]; + rv = wb_pmbus_update_fan(client, page, id, bit, bit, word); + break; + default: + rv = -ENXIO; + break; + } + + return rv; +} + +/* + * _pmbus_write_word_data() is similar to pmbus_write_word_data(), but checks if + * a device specific mapping function exists and calls it if necessary. + */ +static int _pmbus_write_word_data(struct i2c_client *client, int page, int reg, + u16 word) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + const struct pmbus_driver_info *info = data->info; + int status; + + if (info->write_word_data) { + status = info->write_word_data(client, page, reg, word); + if (status != -ENODATA) + return status; + } + + if (reg >= PMBUS_VIRT_BASE) + return pmbus_write_virt_reg(client, page, reg, word); + + return wb_pmbus_write_word_data(client, page, reg, word); +} + +int wb_pmbus_update_fan(struct i2c_client *client, int page, int id, + u8 config, u8 mask, u16 command) +{ + int from; + int rv; + u8 to; + + from = wb_pmbus_read_byte_data(client, page, + pmbus_fan_config_registers[id]); + if (from < 0) + return from; + + to = (from & ~mask) | (config & mask); + if (to != from) { + rv = wb_pmbus_write_byte_data(client, page, + pmbus_fan_config_registers[id], to); + if (rv < 0) + return rv; + } + + return _pmbus_write_word_data(client, page, + pmbus_fan_command_registers[id], command); +} +EXPORT_SYMBOL_GPL(wb_pmbus_update_fan); + +static int wb_pmbus_read_word_data_tmp(struct i2c_client *client, int page, int phase, u8 reg) +{ + int rv; + + rv = wb_pmbus_set_page(client, page, phase); + if (rv < 0) + return rv; + + return i2c_smbus_read_word_data(client, reg); +} + +int wb_pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg) +{ + int rv, i; + struct device *dev = &client->dev; + + for (i = 0; i < PMBUS_RETRY_TIME; i++) { + rv = wb_pmbus_read_word_data_tmp(client, page, phase, reg); + if(rv >= 0){ + return rv; + } + if ((i + 1) < PMBUS_RETRY_TIME) { + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + } + dev_dbg(dev, "wb_pmbus_read_word_data failed, page: %d, phase: %d, reg: 0x%x, rv: %d\n", + page, phase, reg, rv); + return rv; +} +EXPORT_SYMBOL_GPL(wb_pmbus_read_word_data); + +static int pmbus_read_virt_reg(struct i2c_client *client, int page, int reg) +{ + int rv; + int id; + + switch (reg) { + case PMBUS_VIRT_FAN_TARGET_1 ... PMBUS_VIRT_FAN_TARGET_4: + id = reg - PMBUS_VIRT_FAN_TARGET_1; + rv = wb_pmbus_get_fan_rate_device(client, page, id, rpm); + break; + default: + rv = -ENXIO; + break; + } + + return rv; +} + +/* + * _pmbus_read_word_data() is similar to wb_pmbus_read_word_data(), but checks if + * a device specific mapping function exists and calls it if necessary. + */ +static int _pmbus_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + const struct pmbus_driver_info *info = data->info; + int status; + + if (info->read_word_data) { + status = info->read_word_data(client, page, phase, reg); + if (status != -ENODATA) + return status; + } + + if (reg >= PMBUS_VIRT_BASE) + return pmbus_read_virt_reg(client, page, reg); + + return wb_pmbus_read_word_data(client, page, phase, reg); +} + +/* Same as above, but without phase parameter, for use in check functions */ +static int __pmbus_read_word_data(struct i2c_client *client, int page, int reg) +{ + return _pmbus_read_word_data(client, page, 0xff, reg); +} + +static int wb_pmbus_read_byte_data_tmp(struct i2c_client *client, int page, u8 reg) +{ + int rv; + + rv = wb_pmbus_set_page(client, page, 0xff); + if (rv < 0) + return rv; + + return i2c_smbus_read_byte_data(client, reg); +} + +int wb_pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg) +{ + int rv, i; + struct device *dev = &client->dev; + + for (i = 0; i < PMBUS_RETRY_TIME; i++) { + rv = wb_pmbus_read_byte_data_tmp(client, page, reg); + if(rv >= 0){ + return rv; + } + if ((i + 1) < PMBUS_RETRY_TIME) { + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + } + dev_dbg(dev, "wb_pmbus_read_byte_data failed, page: %d, reg: 0x%x, rv: %d\n", + page, reg, rv); + return rv; +} +EXPORT_SYMBOL_GPL(wb_pmbus_read_byte_data); + +static int wb_pmbus_write_byte_data_tmp(struct i2c_client *client, int page, u8 reg, u8 value) +{ + int rv; + + rv = wb_pmbus_set_page(client, page, 0xff); + if (rv < 0) + return rv; + + return i2c_smbus_write_byte_data(client, reg, value); +} + +int wb_pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value) +{ + int rv, i; + struct device *dev = &client->dev; + + for (i = 0; i < PMBUS_RETRY_TIME; i++) { + rv = wb_pmbus_write_byte_data_tmp(client, page, reg, value); + if(rv >= 0){ + return rv; + } + if ((i + 1) < PMBUS_RETRY_TIME) { + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + } + dev_dbg(dev, "wb_pmbus_write_byte_data failed, page: %d, reg: 0x%x, value: 0x%x, rv: %d\n", + page, reg, value, rv); + return rv; +} +EXPORT_SYMBOL_GPL(wb_pmbus_write_byte_data); + +int wb_pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, + u8 mask, u8 value) +{ + unsigned int tmp; + int rv; + + rv = wb_pmbus_read_byte_data(client, page, reg); + if (rv < 0) + return rv; + + tmp = (rv & ~mask) | (value & mask); + + if (tmp != rv) + rv = wb_pmbus_write_byte_data(client, page, reg, tmp); + + return rv; +} +EXPORT_SYMBOL_GPL(wb_pmbus_update_byte_data); + +/* + * _pmbus_read_byte_data() is similar to wb_pmbus_read_byte_data(), but checks if + * a device specific mapping function exists and calls it if necessary. + */ +static int _pmbus_read_byte_data(struct i2c_client *client, int page, int reg) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + const struct pmbus_driver_info *info = data->info; + int status; + + if (info->read_byte_data) { + status = info->read_byte_data(client, page, reg); + if (status != -ENODATA) + return status; + } + return wb_pmbus_read_byte_data(client, page, reg); +} + +static struct pmbus_sensor *pmbus_find_sensor(struct pmbus_data *data, int page, + int reg) +{ + struct pmbus_sensor *sensor; + + for (sensor = data->sensors; sensor; sensor = sensor->next) { + if (sensor->page == page && sensor->reg == reg) + return sensor; + } + + return ERR_PTR(-EINVAL); +} + +static int pmbus_get_fan_rate(struct i2c_client *client, int page, int id, + enum pmbus_fan_mode mode, + bool from_cache) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + bool want_rpm, have_rpm; + struct pmbus_sensor *s; + int config; + int reg; + + want_rpm = (mode == rpm); + + if (from_cache) { + reg = want_rpm ? PMBUS_VIRT_FAN_TARGET_1 : PMBUS_VIRT_PWM_1; + s = pmbus_find_sensor(data, page, reg + id); + if (IS_ERR(s)) + return PTR_ERR(s); + + return s->data; + } + + config = wb_pmbus_read_byte_data(client, page, + pmbus_fan_config_registers[id]); + if (config < 0) + return config; + + have_rpm = !!(config & pmbus_fan_rpm_mask[id]); + if (want_rpm == have_rpm) + return wb_pmbus_read_word_data(client, page, 0xff, + pmbus_fan_command_registers[id]); + + /* Can't sensibly map between RPM and PWM, just return zero */ + return 0; +} + +int wb_pmbus_get_fan_rate_device(struct i2c_client *client, int page, int id, + enum pmbus_fan_mode mode) +{ + return pmbus_get_fan_rate(client, page, id, mode, false); +} +EXPORT_SYMBOL_GPL(wb_pmbus_get_fan_rate_device); + +int wb_pmbus_get_fan_rate_cached(struct i2c_client *client, int page, int id, + enum pmbus_fan_mode mode) +{ + return pmbus_get_fan_rate(client, page, id, mode, true); +} +EXPORT_SYMBOL_GPL(wb_pmbus_get_fan_rate_cached); + +static void pmbus_clear_fault_page(struct i2c_client *client, int page) +{ + _pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); +} + +void wb_pmbus_clear_faults(struct i2c_client *client) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + int i; + + for (i = 0; i < data->info->pages; i++) + pmbus_clear_fault_page(client, i); +} +EXPORT_SYMBOL_GPL(wb_pmbus_clear_faults); + +static int pmbus_check_status_cml(struct i2c_client *client) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + int status, status2; + + status = data->read_status(client, -1); + if (status < 0 || (status & PB_STATUS_CML)) { + status2 = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML); + if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND)) + return -EIO; + } + return 0; +} + +static bool pmbus_check_register(struct i2c_client *client, + int (*func)(struct i2c_client *client, + int page, int reg), + int page, int reg) +{ + int rv; + struct pmbus_data *data = i2c_get_clientdata(client); + + rv = func(client, page, reg); + if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK)) + rv = pmbus_check_status_cml(client); + pmbus_clear_fault_page(client, -1); + return rv >= 0; +} + +static bool pmbus_check_status_register(struct i2c_client *client, int page) +{ + int status; + struct pmbus_data *data = i2c_get_clientdata(client); + + status = data->read_status(client, page); + if (status >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK) && + (status & PB_STATUS_CML)) { + status = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML); + if (status < 0 || (status & PB_CML_FAULT_INVALID_COMMAND)) + status = -EIO; + } + + pmbus_clear_fault_page(client, -1); + return status >= 0; +} + +bool wb_pmbus_check_byte_register(struct i2c_client *client, int page, int reg) +{ + return pmbus_check_register(client, _pmbus_read_byte_data, page, reg); +} +EXPORT_SYMBOL_GPL(wb_pmbus_check_byte_register); + +bool wb_pmbus_check_word_register(struct i2c_client *client, int page, int reg) +{ + return pmbus_check_register(client, __pmbus_read_word_data, page, reg); +} +EXPORT_SYMBOL_GPL(wb_pmbus_check_word_register); + +const struct pmbus_driver_info *wb_pmbus_get_driver_info(struct i2c_client *client) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + + return data->info; +} +EXPORT_SYMBOL_GPL(wb_pmbus_get_driver_info); + +static int pmbus_read_status_byte(struct i2c_client *client, int page) +{ + return _pmbus_read_byte_data(client, page, PMBUS_STATUS_BYTE); +} + +static int pmbus_read_status_word(struct i2c_client *client, int page) +{ + return _pmbus_read_word_data(client, page, 0xff, PMBUS_STATUS_WORD); +} + +static int pmbus_get_status(struct i2c_client *client, int page, int reg) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + int status; + + switch (reg) { + case PMBUS_STATUS_WORD: + status = data->read_status(client, page); + if ((status < 0) || (data->has_status_word && (status == 0xffff)) + || (!data->has_status_word && (status == 0xff))) { + if (data->has_status_word) { + data->read_status = pmbus_read_status_byte; + } else { + data->read_status = pmbus_read_status_word; + } + data->has_status_word = !data->has_status_word; + status = data->read_status(client, page); + } + break; + default: + status = _pmbus_read_byte_data(client, page, reg); + break; + } + if (status < 0) + wb_pmbus_clear_faults(client); + return status; +} + +static void pmbus_update_sensor_data(struct i2c_client *client, struct pmbus_sensor *sensor) +{ + if (sensor->data < 0 || sensor->update) + sensor->data = _pmbus_read_word_data(client, sensor->page, + sensor->phase, sensor->reg); +} + +/* + * Convert linear sensor values to milli- or micro-units + * depending on sensor type. + */ +static s64 pmbus_reg2data_linear(struct pmbus_data *data, + struct pmbus_sensor *sensor) +{ + s16 exponent; + s32 mantissa; + s64 val; + + if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */ + exponent = data->exponent[sensor->page]; + mantissa = (u16) sensor->data; + } else { /* LINEAR11 */ + exponent = ((s16)sensor->data) >> 11; + mantissa = ((s16)((sensor->data & 0x7ff) << 5)) >> 5; + } + + val = mantissa; + + /* scale result to milli-units for all sensors except fans */ + if (sensor->class != PSC_FAN) + val = val * 1000LL; + + /* scale result to micro-units for power sensors */ + if (sensor->class == PSC_POWER) + val = val * 1000LL; + + if (exponent >= 0) + val <<= exponent; + else + val >>= -exponent; + + return val; +} + +/* + * Convert direct sensor values to milli- or micro-units + * depending on sensor type. + */ +static s64 pmbus_reg2data_direct(struct pmbus_data *data, + struct pmbus_sensor *sensor) +{ + s64 b, val = (s16)sensor->data; + s32 m, R; + + m = data->info->m[sensor->class]; + b = data->info->b[sensor->class]; + R = data->info->R[sensor->class]; + + if (m == 0) + return 0; + + /* X = 1/m * (Y * 10^-R - b) */ + R = -R; + /* scale result to milli-units for everything but fans */ + if (!(sensor->class == PSC_FAN || sensor->class == PSC_PWM)) { + R += 3; + b *= 1000; + } + + /* scale result to micro-units for power sensors */ + if (sensor->class == PSC_POWER) { + R += 3; + b *= 1000; + } + + while (R > 0) { + val *= 10; + R--; + } + while (R < 0) { + val = div_s64(val + 5LL, 10L); /* round closest */ + R++; + } + + val = div_s64(val - b, m); + return val; +} + +/* + * Convert VID sensor values to milli- or micro-units + * depending on sensor type. + */ +static s64 pmbus_reg2data_vid(struct pmbus_data *data, + struct pmbus_sensor *sensor) +{ + long val = sensor->data; + long rv = 0; + + switch (data->info->vrm_version[sensor->page]) { + case vr11: + if (val >= 0x02 && val <= 0xb2) + rv = DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); + break; + case vr12: + if (val >= 0x01) + rv = 250 + (val - 1) * 5; + break; + case vr13: + if (val >= 0x01) + rv = 500 + (val - 1) * 10; + break; + case imvp9: + if (val >= 0x01) + rv = 200 + (val - 1) * 10; + break; + case amd625mv: + if (val >= 0x0 && val <= 0xd8) + rv = DIV_ROUND_CLOSEST(155000 - val * 625, 100); + break; + } + return rv; +} + +static s64 pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) +{ + s64 val; + + if (!sensor->convert) + return sensor->data; + + switch (data->info->format[sensor->class]) { + case direct: + val = pmbus_reg2data_direct(data, sensor); + break; + case vid: + val = pmbus_reg2data_vid(data, sensor); + break; + case linear: + default: + val = pmbus_reg2data_linear(data, sensor); + break; + } + return val; +} + +#define MAX_MANTISSA (1023 * 1000) +#define MIN_MANTISSA (511 * 1000) + +static u16 pmbus_data2reg_linear(struct pmbus_data *data, + struct pmbus_sensor *sensor, s64 val) +{ + s16 exponent = 0, mantissa; + bool negative = false; + + /* simple case */ + if (val == 0) + return 0; + + if (sensor->class == PSC_VOLTAGE_OUT) { + /* LINEAR16 does not support negative voltages */ + if (val < 0) + return 0; + + /* + * For a static exponents, we don't have a choice + * but to adjust the value to it. + */ + if (data->exponent[sensor->page] < 0) + val <<= -data->exponent[sensor->page]; + else + val >>= data->exponent[sensor->page]; + val = DIV_ROUND_CLOSEST_ULL(val, 1000); + return clamp_val(val, 0, 0xffff); + } + + if (val < 0) { + negative = true; + val = -val; + } + + /* Power is in uW. Convert to mW before converting. */ + if (sensor->class == PSC_POWER) + val = DIV_ROUND_CLOSEST_ULL(val, 1000); + + /* + * For simplicity, convert fan data to milli-units + * before calculating the exponent. + */ + if (sensor->class == PSC_FAN) + val = val * 1000LL; + + /* Reduce large mantissa until it fits into 10 bit */ + while (val >= MAX_MANTISSA && exponent < 15) { + exponent++; + val >>= 1; + } + /* Increase small mantissa to improve precision */ + while (val < MIN_MANTISSA && exponent > -15) { + exponent--; + val <<= 1; + } + + /* Convert mantissa from milli-units to units */ + mantissa = clamp_val(DIV_ROUND_CLOSEST_ULL(val, 1000), 0, 0x3ff); + + /* restore sign */ + if (negative) + mantissa = -mantissa; + + /* Convert to 5 bit exponent, 11 bit mantissa */ + return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800); +} + +static u16 pmbus_data2reg_direct(struct pmbus_data *data, + struct pmbus_sensor *sensor, s64 val) +{ + s64 b; + s32 m, R; + + m = data->info->m[sensor->class]; + b = data->info->b[sensor->class]; + R = data->info->R[sensor->class]; + + /* Power is in uW. Adjust R and b. */ + if (sensor->class == PSC_POWER) { + R -= 3; + b *= 1000; + } + + /* Calculate Y = (m * X + b) * 10^R */ + if (!(sensor->class == PSC_FAN || sensor->class == PSC_PWM)) { + R -= 3; /* Adjust R and b for data in milli-units */ + b *= 1000; + } + val = val * m + b; + + while (R > 0) { + val *= 10; + R--; + } + while (R < 0) { + val = div_s64(val + 5LL, 10L); /* round closest */ + R++; + } + + return (u16)clamp_val(val, S16_MIN, S16_MAX); +} + +static u16 pmbus_data2reg_vid(struct pmbus_data *data, + struct pmbus_sensor *sensor, s64 val) +{ + val = clamp_val(val, 500, 1600); + + return 2 + DIV_ROUND_CLOSEST_ULL((1600LL - val) * 100LL, 625); +} + +static u16 pmbus_data2reg(struct pmbus_data *data, + struct pmbus_sensor *sensor, s64 val) +{ + u16 regval; + + if (!sensor->convert) + return val; + + switch (data->info->format[sensor->class]) { + case direct: + regval = pmbus_data2reg_direct(data, sensor, val); + break; + case vid: + regval = pmbus_data2reg_vid(data, sensor, val); + break; + case linear: + default: + regval = pmbus_data2reg_linear(data, sensor, val); + break; + } + return regval; +} + +/* + * Return boolean calculated from converted data. + * defines a status register index and mask. + * The mask is in the lower 8 bits, the register index is in bits 8..23. + * + * The associated pmbus_boolean structure contains optional pointers to two + * sensor attributes. If specified, those attributes are compared against each + * other to determine if a limit has been exceeded. + * + * If the sensor attribute pointers are NULL, the function returns true if + * (status[reg] & mask) is true. + * + * If sensor attribute pointers are provided, a comparison against a specified + * limit has to be performed to determine the boolean result. + * In this case, the function returns true if v1 >= v2 (where v1 and v2 are + * sensor values referenced by sensor attribute pointers s1 and s2). + * + * To determine if an object exceeds upper limits, specify = . + * To determine if an object exceeds lower limits, specify = . + * + * If a negative value is stored in any of the referenced registers, this value + * reflects an error code which will be returned. + */ +static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b, + int index) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + struct pmbus_sensor *s1 = b->s1; + struct pmbus_sensor *s2 = b->s2; + u16 mask = pb_index_to_mask(index); + u8 page = pb_index_to_page(index); + u16 reg = pb_index_to_reg(index); + int ret, status; + u16 regval; + + mutex_lock(&data->update_lock); + status = pmbus_get_status(client, page, reg); + if (status < 0) { + ret = status; + goto unlock; + } + + if (s1) + pmbus_update_sensor_data(client, s1); + if (s2) + pmbus_update_sensor_data(client, s2); + + regval = status & mask; + if (s1 && s2) { + s64 v1, v2; + + if (s1->data < 0) { + ret = s1->data; + goto unlock; + } + if (s2->data < 0) { + ret = s2->data; + goto unlock; + } + + v1 = pmbus_reg2data(data, s1); + v2 = pmbus_reg2data(data, s2); + ret = !!(regval && v1 >= v2); + } else { + ret = !!regval; + } +unlock: + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t pmbus_show_boolean(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct pmbus_boolean *boolean = to_pmbus_boolean(attr); + struct i2c_client *client = to_i2c_client(dev->parent); + int val; + + val = pmbus_get_boolean(client, boolean, attr->index); + if (val < 0) + return val; + return snprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t pmbus_show_sensor(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + ssize_t ret; + + mutex_lock(&data->update_lock); + pmbus_update_sensor_data(client, sensor); + if (sensor->data < 0) + ret = sensor->data; + else + ret = snprintf(buf, PAGE_SIZE, "%lld\n", pmbus_reg2data(data, sensor)); + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t pmbus_set_sensor(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct pmbus_data *data = i2c_get_clientdata(client); + struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); + ssize_t rv = count; + s64 val; + int ret; + u16 regval; + + if (kstrtos64(buf, 10, &val) < 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + regval = pmbus_data2reg(data, sensor, val); + ret = _pmbus_write_word_data(client, sensor->page, sensor->reg, regval); + if (ret < 0) + rv = ret; + else + sensor->data = regval; + mutex_unlock(&data->update_lock); + return rv; +} + +static ssize_t pmbus_show_label(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct pmbus_label *label = to_pmbus_label(da); + + return snprintf(buf, PAGE_SIZE, "%s\n", label->label); +} + +static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr) +{ + if (data->num_attributes >= data->max_attributes - 1) { + int new_max_attrs = data->max_attributes + PMBUS_ATTR_ALLOC_SIZE; + void *new_attrs = devm_krealloc(data->dev, data->group.attrs, + new_max_attrs * sizeof(void *), + GFP_KERNEL); + if (!new_attrs) + return -ENOMEM; + data->group.attrs = new_attrs; + data->max_attributes = new_max_attrs; + } + + data->group.attrs[data->num_attributes++] = attr; + data->group.attrs[data->num_attributes] = NULL; + return 0; +} + +static void pmbus_dev_attr_init(struct device_attribute *dev_attr, + const char *name, + umode_t mode, + ssize_t (*show)(struct device *dev, + struct device_attribute *attr, + char *buf), + ssize_t (*store)(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count)) +{ + sysfs_attr_init(&dev_attr->attr); + dev_attr->attr.name = name; + dev_attr->attr.mode = mode; + dev_attr->show = show; + dev_attr->store = store; +} + +static void pmbus_attr_init(struct sensor_device_attribute *a, + const char *name, + umode_t mode, + ssize_t (*show)(struct device *dev, + struct device_attribute *attr, + char *buf), + ssize_t (*store)(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count), + int idx) +{ + pmbus_dev_attr_init(&a->dev_attr, name, mode, show, store); + a->index = idx; +} + +static int pmbus_add_boolean(struct pmbus_data *data, + const char *name, const char *type, int seq, + struct pmbus_sensor *s1, + struct pmbus_sensor *s2, + u8 page, u16 reg, u16 mask) +{ + struct pmbus_boolean *boolean; + struct sensor_device_attribute *a; + + if (WARN((s1 && !s2) || (!s1 && s2), "Bad s1/s2 parameters\n")) + return -EINVAL; + + boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL); + if (!boolean) + return -ENOMEM; + + a = &boolean->attribute; + + snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s", + name, seq, type); + boolean->s1 = s1; + boolean->s2 = s2; + pmbus_attr_init(a, boolean->name, 0444, pmbus_show_boolean, NULL, + pb_reg_to_index(page, reg, mask)); + + return pmbus_add_attribute(data, &a->dev_attr.attr); +} + +static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, + const char *name, const char *type, + int seq, int page, int phase, + int reg, + enum pmbus_sensor_classes class, + bool update, bool readonly, + bool convert) +{ + struct pmbus_sensor *sensor; + struct device_attribute *a; + + sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return NULL; + a = &sensor->attribute; + + if (type) + snprintf(sensor->name, sizeof(sensor->name), "%s%d_%s", + name, seq, type); + else + snprintf(sensor->name, sizeof(sensor->name), "%s%d", + name, seq); + + if (data->flags & PMBUS_WRITE_PROTECTED) + readonly = true; + + sensor->page = page; + sensor->phase = phase; + sensor->reg = reg; + sensor->class = class; + sensor->update = update; + sensor->convert = convert; + sensor->data = -ENODATA; + pmbus_dev_attr_init(a, sensor->name, + readonly ? 0444 : 0644, + pmbus_show_sensor, pmbus_set_sensor); + + if (pmbus_add_attribute(data, &a->attr)) + return NULL; + + sensor->next = data->sensors; + data->sensors = sensor; + + return sensor; +} + +static int pmbus_add_label(struct pmbus_data *data, + const char *name, int seq, + const char *lstring, int index, int phase) +{ + struct pmbus_label *label; + struct device_attribute *a; + + label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL); + if (!label) + return -ENOMEM; + + a = &label->attribute; + + snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq); + if (!index) { + if (phase == 0xff) + strncpy(label->label, lstring, + sizeof(label->label) - 1); + else + snprintf(label->label, sizeof(label->label), "%s.%d", + lstring, phase); + } else { + if (phase == 0xff) + snprintf(label->label, sizeof(label->label), "%s%d", + lstring, index); + else + snprintf(label->label, sizeof(label->label), "%s%d.%d", + lstring, index, phase); + } + + pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL); + return pmbus_add_attribute(data, &a->attr); +} + +/* + * Search for attributes. Allocate sensors, booleans, and labels as needed. + */ + +/* + * The pmbus_limit_attr structure describes a single limit attribute + * and its associated alarm attribute. + */ +struct pmbus_limit_attr { + u16 reg; /* Limit register */ + u16 sbit; /* Alarm attribute status bit */ + bool update; /* True if register needs updates */ + bool low; /* True if low limit; for limits with compare + functions only */ + const char *attr; /* Attribute name */ + const char *alarm; /* Alarm attribute name */ +}; + +/* + * The pmbus_sensor_attr structure describes one sensor attribute. This + * description includes a reference to the associated limit attributes. + */ +struct pmbus_sensor_attr { + u16 reg; /* sensor register */ + u16 gbit; /* generic status bit */ + u8 nlimit; /* # of limit registers */ + enum pmbus_sensor_classes class;/* sensor class */ + const char *label; /* sensor label */ + bool paged; /* true if paged sensor */ + bool update; /* true if update needed */ + bool compare; /* true if compare function needed */ + u32 func; /* sensor mask */ + u32 sfunc; /* sensor status mask */ + int sreg; /* status register */ + const struct pmbus_limit_attr *limit;/* limit registers */ +}; + +/* + * Add a set of limit attributes and, if supported, the associated + * alarm attributes. + * returns 0 if no alarm register found, 1 if an alarm register was found, + * < 0 on errors. + */ +static int pmbus_add_limit_attrs(struct i2c_client *client, + struct pmbus_data *data, + const struct pmbus_driver_info *info, + const char *name, int index, int page, + struct pmbus_sensor *base, + const struct pmbus_sensor_attr *attr) +{ + const struct pmbus_limit_attr *l = attr->limit; + int nlimit = attr->nlimit; + int have_alarm = 0; + int i, ret; + struct pmbus_sensor *curr; + + for (i = 0; i < nlimit; i++) { + if (wb_pmbus_check_word_register(client, page, l->reg)) { + curr = pmbus_add_sensor(data, name, l->attr, index, + page, 0xff, l->reg, attr->class, + attr->update || l->update, + false, true); + if (!curr) + return -ENOMEM; + if (l->sbit && (info->func[page] & attr->sfunc)) { + ret = pmbus_add_boolean(data, name, + l->alarm, index, + attr->compare ? l->low ? curr : base + : NULL, + attr->compare ? l->low ? base : curr + : NULL, + page, attr->sreg, l->sbit); + if (ret) + return ret; + have_alarm = 1; + } + } + l++; + } + return have_alarm; +} + +static int pmbus_add_sensor_attrs_one(struct i2c_client *client, + struct pmbus_data *data, + const struct pmbus_driver_info *info, + const char *name, + int index, int page, int phase, + const struct pmbus_sensor_attr *attr, + bool paged) +{ + struct pmbus_sensor *base; + bool upper = !!(attr->gbit & 0xff00); /* need to check STATUS_WORD */ + int ret; + + if (attr->label) { + ret = pmbus_add_label(data, name, index, attr->label, + paged ? page + 1 : 0, phase); + if (ret) + return ret; + } + base = pmbus_add_sensor(data, name, "input", index, page, phase, + attr->reg, attr->class, true, true, true); + if (!base) + return -ENOMEM; + /* No limit and alarm attributes for phase specific sensors */ + if (attr->sfunc && phase == 0xff) { + ret = pmbus_add_limit_attrs(client, data, info, name, + index, page, base, attr); + if (ret < 0) + return ret; + /* + * Add generic alarm attribute only if there are no individual + * alarm attributes, if there is a global alarm bit, and if + * the generic status register (word or byte, depending on + * which global bit is set) for this page is accessible. + */ + if (!ret && attr->gbit && + (!upper || (upper && data->has_status_word)) && + pmbus_check_status_register(client, page)) { + ret = pmbus_add_boolean(data, name, "alarm", index, + NULL, NULL, + page, PMBUS_STATUS_WORD, + attr->gbit); + if (ret) + return ret; + } + } + return 0; +} + +static bool pmbus_sensor_is_paged(const struct pmbus_driver_info *info, + const struct pmbus_sensor_attr *attr) +{ + int p; + + if (attr->paged) + return true; + + /* + * Some attributes may be present on more than one page despite + * not being marked with the paged attribute. If that is the case, + * then treat the sensor as being paged and add the page suffix to the + * attribute name. + * We don't just add the paged attribute to all such attributes, in + * order to maintain the un-suffixed labels in the case where the + * attribute is only on page 0. + */ + for (p = 1; p < info->pages; p++) { + if (info->func[p] & attr->func) + return true; + } + return false; +} + +static int pmbus_add_sensor_attrs(struct i2c_client *client, + struct pmbus_data *data, + const char *name, + const struct pmbus_sensor_attr *attrs, + int nattrs) +{ + const struct pmbus_driver_info *info = data->info; + int index, i; + int ret; + + index = 1; + for (i = 0; i < nattrs; i++) { + int page, pages; + bool paged = pmbus_sensor_is_paged(info, attrs); + + pages = paged ? info->pages : 1; + for (page = 0; page < pages; page++) { + if (!(info->func[page] & attrs->func)) + continue; + ret = pmbus_add_sensor_attrs_one(client, data, info, + name, index, page, + 0xff, attrs, paged); + if (ret) + return ret; + index++; + if (info->phases[page]) { + int phase; + + for (phase = 0; phase < info->phases[page]; + phase++) { + if (!(info->pfunc[phase] & attrs->func)) + continue; + ret = pmbus_add_sensor_attrs_one(client, + data, info, name, index, page, + phase, attrs, paged); + if (ret) + return ret; + index++; + } + } + } + attrs++; + } + return 0; +} + +static const struct pmbus_limit_attr vin_limit_attrs[] = { + { + .reg = PMBUS_VIN_UV_WARN_LIMIT, + .attr = "min", + .alarm = "min_alarm", + .sbit = PB_VOLTAGE_UV_WARNING, + }, { + .reg = PMBUS_VIN_UV_FAULT_LIMIT, + .attr = "lcrit", + .alarm = "lcrit_alarm", + .sbit = PB_VOLTAGE_UV_FAULT, + }, { + .reg = PMBUS_VIN_OV_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_VOLTAGE_OV_WARNING, + }, { + .reg = PMBUS_VIN_OV_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_VOLTAGE_OV_FAULT, + }, { + .reg = PMBUS_VIRT_READ_VIN_AVG, + .update = true, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_VIN_MIN, + .update = true, + .attr = "lowest", + }, { + .reg = PMBUS_VIRT_READ_VIN_MAX, + .update = true, + .attr = "highest", + }, { + .reg = PMBUS_VIRT_RESET_VIN_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_VIN_MIN, + .attr = "rated_min", + }, { + .reg = PMBUS_MFR_VIN_MAX, + .attr = "rated_max", + }, +}; + +static const struct pmbus_limit_attr vmon_limit_attrs[] = { + { + .reg = PMBUS_VIRT_VMON_UV_WARN_LIMIT, + .attr = "min", + .alarm = "min_alarm", + .sbit = PB_VOLTAGE_UV_WARNING, + }, { + .reg = PMBUS_VIRT_VMON_UV_FAULT_LIMIT, + .attr = "lcrit", + .alarm = "lcrit_alarm", + .sbit = PB_VOLTAGE_UV_FAULT, + }, { + .reg = PMBUS_VIRT_VMON_OV_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_VOLTAGE_OV_WARNING, + }, { + .reg = PMBUS_VIRT_VMON_OV_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_VOLTAGE_OV_FAULT, + } +}; + +static const struct pmbus_limit_attr vout_limit_attrs[] = { + { + .reg = PMBUS_VOUT_UV_WARN_LIMIT, + .attr = "min", + .alarm = "min_alarm", + .sbit = PB_VOLTAGE_UV_WARNING, + }, { + .reg = PMBUS_VOUT_UV_FAULT_LIMIT, + .attr = "lcrit", + .alarm = "lcrit_alarm", + .sbit = PB_VOLTAGE_UV_FAULT, + }, { + .reg = PMBUS_VOUT_OV_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_VOLTAGE_OV_WARNING, + }, { + .reg = PMBUS_VOUT_OV_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_VOLTAGE_OV_FAULT, + }, { + .reg = PMBUS_VIRT_READ_VOUT_AVG, + .update = true, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_VOUT_MIN, + .update = true, + .attr = "lowest", + }, { + .reg = PMBUS_VIRT_READ_VOUT_MAX, + .update = true, + .attr = "highest", + }, { + .reg = PMBUS_VIRT_RESET_VOUT_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_VOUT_MIN, + .attr = "rated_min", + }, { + .reg = PMBUS_MFR_VOUT_MAX, + .attr = "rated_max", + }, +}; + +static const struct pmbus_sensor_attr voltage_attributes[] = { + { + .reg = PMBUS_READ_VIN, + .class = PSC_VOLTAGE_IN, + .label = "vin", + .func = PMBUS_HAVE_VIN, + .sfunc = PMBUS_HAVE_STATUS_INPUT, + .sreg = PMBUS_STATUS_INPUT, + .gbit = PB_STATUS_VIN_UV, + .limit = vin_limit_attrs, + .nlimit = 0, + }, { + .reg = PMBUS_VIRT_READ_VMON, + .class = PSC_VOLTAGE_IN, + .label = "vmon", + .func = PMBUS_HAVE_VMON, + .sfunc = PMBUS_HAVE_STATUS_VMON, + .sreg = PMBUS_VIRT_STATUS_VMON, + .limit = vmon_limit_attrs, + .nlimit = 0, + }, { + .reg = PMBUS_READ_VCAP, + .class = PSC_VOLTAGE_IN, + .label = "vcap", + .func = PMBUS_HAVE_VCAP, + }, { + .reg = PMBUS_READ_VOUT, + .class = PSC_VOLTAGE_OUT, + .label = "vout", + .paged = true, + .func = PMBUS_HAVE_VOUT, + .sfunc = PMBUS_HAVE_STATUS_VOUT, + .sreg = PMBUS_STATUS_VOUT, + .gbit = PB_STATUS_VOUT_OV, + .limit = vout_limit_attrs, + .nlimit = 0, + } +}; + +/* Current attributes */ + +static const struct pmbus_limit_attr iin_limit_attrs[] = { + { + .reg = PMBUS_IIN_OC_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_IIN_OC_WARNING, + }, { + .reg = PMBUS_IIN_OC_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_IIN_OC_FAULT, + }, { + .reg = PMBUS_VIRT_READ_IIN_AVG, + .update = true, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_IIN_MIN, + .update = true, + .attr = "lowest", + }, { + .reg = PMBUS_VIRT_READ_IIN_MAX, + .update = true, + .attr = "highest", + }, { + .reg = PMBUS_VIRT_RESET_IIN_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_IIN_MAX, + .attr = "rated_max", + }, +}; + +static const struct pmbus_limit_attr iout_limit_attrs[] = { + { + .reg = PMBUS_IOUT_OC_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_IOUT_OC_WARNING, + }, { + .reg = PMBUS_IOUT_UC_FAULT_LIMIT, + .attr = "lcrit", + .alarm = "lcrit_alarm", + .sbit = PB_IOUT_UC_FAULT, + }, { + .reg = PMBUS_IOUT_OC_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_IOUT_OC_FAULT, + }, { + .reg = PMBUS_VIRT_READ_IOUT_AVG, + .update = true, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_IOUT_MIN, + .update = true, + .attr = "lowest", + }, { + .reg = PMBUS_VIRT_READ_IOUT_MAX, + .update = true, + .attr = "highest", + }, { + .reg = PMBUS_VIRT_RESET_IOUT_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_IOUT_MAX, + .attr = "rated_max", + }, +}; + +static const struct pmbus_sensor_attr current_attributes[] = { + { + .reg = PMBUS_READ_IIN, + .class = PSC_CURRENT_IN, + .label = "iin", + .func = PMBUS_HAVE_IIN, + .sfunc = PMBUS_HAVE_STATUS_INPUT, + .sreg = PMBUS_STATUS_INPUT, + .gbit = PB_STATUS_INPUT, + .limit = iin_limit_attrs, + .nlimit = 0, + }, { + .reg = PMBUS_READ_IOUT, + .class = PSC_CURRENT_OUT, + .label = "iout", + .paged = true, + .func = PMBUS_HAVE_IOUT, + .sfunc = PMBUS_HAVE_STATUS_IOUT, + .sreg = PMBUS_STATUS_IOUT, + .gbit = PB_STATUS_IOUT_OC, + .limit = iout_limit_attrs, + .nlimit = 0, + } +}; + +/* Power attributes */ + +static const struct pmbus_limit_attr pin_limit_attrs[] = { + { + .reg = PMBUS_PIN_OP_WARN_LIMIT, + .attr = "max", + .alarm = "alarm", + .sbit = PB_PIN_OP_WARNING, + }, { + .reg = PMBUS_VIRT_READ_PIN_AVG, + .update = true, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_PIN_MIN, + .update = true, + .attr = "input_lowest", + }, { + .reg = PMBUS_VIRT_READ_PIN_MAX, + .update = true, + .attr = "input_highest", + }, { + .reg = PMBUS_VIRT_RESET_PIN_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_PIN_MAX, + .attr = "rated_max", + }, +}; + +static const struct pmbus_limit_attr pout_limit_attrs[] = { + { + .reg = PMBUS_POUT_MAX, + .attr = "cap", + .alarm = "cap_alarm", + .sbit = PB_POWER_LIMITING, + }, { + .reg = PMBUS_POUT_OP_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_POUT_OP_WARNING, + }, { + .reg = PMBUS_POUT_OP_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_POUT_OP_FAULT, + }, { + .reg = PMBUS_VIRT_READ_POUT_AVG, + .update = true, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_POUT_MIN, + .update = true, + .attr = "input_lowest", + }, { + .reg = PMBUS_VIRT_READ_POUT_MAX, + .update = true, + .attr = "input_highest", + }, { + .reg = PMBUS_VIRT_RESET_POUT_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_POUT_MAX, + .attr = "rated_max", + }, +}; + +static const struct pmbus_sensor_attr power_attributes[] = { + { + .reg = PMBUS_READ_PIN, + .class = PSC_POWER, + .label = "pin", + .func = PMBUS_HAVE_PIN, + .sfunc = PMBUS_HAVE_STATUS_INPUT, + .sreg = PMBUS_STATUS_INPUT, + .gbit = PB_STATUS_INPUT, + .limit = pin_limit_attrs, + .nlimit = 0, + }, { + .reg = PMBUS_READ_POUT, + .class = PSC_POWER, + .label = "pout", + .paged = true, + .func = PMBUS_HAVE_POUT, + .sfunc = PMBUS_HAVE_STATUS_IOUT, + .sreg = PMBUS_STATUS_IOUT, + .limit = pout_limit_attrs, + .nlimit = 0, + } +}; + +/* Temperature atributes */ + +static const struct pmbus_limit_attr temp_limit_attrs[] = { + { + .reg = PMBUS_UT_WARN_LIMIT, + .low = true, + .attr = "min", + .alarm = "min_alarm", + .sbit = PB_TEMP_UT_WARNING, + }, { + .reg = PMBUS_UT_FAULT_LIMIT, + .low = true, + .attr = "lcrit", + .alarm = "lcrit_alarm", + .sbit = PB_TEMP_UT_FAULT, + }, { + .reg = PMBUS_OT_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_TEMP_OT_WARNING, + }, { + .reg = PMBUS_OT_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_TEMP_OT_FAULT, + }, { + .reg = PMBUS_VIRT_READ_TEMP_MIN, + .attr = "lowest", + }, { + .reg = PMBUS_VIRT_READ_TEMP_AVG, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_TEMP_MAX, + .attr = "highest", + }, { + .reg = PMBUS_VIRT_RESET_TEMP_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_MAX_TEMP_1, + .attr = "rated_max", + }, +}; + +static const struct pmbus_limit_attr temp_limit_attrs2[] = { + { + .reg = PMBUS_UT_WARN_LIMIT, + .low = true, + .attr = "min", + .alarm = "min_alarm", + .sbit = PB_TEMP_UT_WARNING, + }, { + .reg = PMBUS_UT_FAULT_LIMIT, + .low = true, + .attr = "lcrit", + .alarm = "lcrit_alarm", + .sbit = PB_TEMP_UT_FAULT, + }, { + .reg = PMBUS_OT_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_TEMP_OT_WARNING, + }, { + .reg = PMBUS_OT_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_TEMP_OT_FAULT, + }, { + .reg = PMBUS_VIRT_READ_TEMP2_MIN, + .attr = "lowest", + }, { + .reg = PMBUS_VIRT_READ_TEMP2_AVG, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_TEMP2_MAX, + .attr = "highest", + }, { + .reg = PMBUS_VIRT_RESET_TEMP2_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_MAX_TEMP_2, + .attr = "rated_max", + }, +}; + +static const struct pmbus_limit_attr temp_limit_attrs3[] = { + { + .reg = PMBUS_UT_WARN_LIMIT, + .low = true, + .attr = "min", + .alarm = "min_alarm", + .sbit = PB_TEMP_UT_WARNING, + }, { + .reg = PMBUS_UT_FAULT_LIMIT, + .low = true, + .attr = "lcrit", + .alarm = "lcrit_alarm", + .sbit = PB_TEMP_UT_FAULT, + }, { + .reg = PMBUS_OT_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_TEMP_OT_WARNING, + }, { + .reg = PMBUS_OT_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_TEMP_OT_FAULT, + }, { + .reg = PMBUS_MFR_MAX_TEMP_3, + .attr = "rated_max", + }, +}; + +static const struct pmbus_sensor_attr temp_attributes[] = { + { + .reg = PMBUS_READ_TEMPERATURE_1, + .class = PSC_TEMPERATURE, + .paged = true, + .update = true, + .compare = true, + .func = PMBUS_HAVE_TEMP, + .sfunc = PMBUS_HAVE_STATUS_TEMP, + .sreg = PMBUS_STATUS_TEMPERATURE, + .gbit = PB_STATUS_TEMPERATURE, + .limit = temp_limit_attrs, + .nlimit = 0, + }, { + .reg = PMBUS_READ_TEMPERATURE_2, + .class = PSC_TEMPERATURE, + .paged = true, + .update = true, + .compare = true, + .func = PMBUS_HAVE_TEMP2, + .sfunc = PMBUS_HAVE_STATUS_TEMP, + .sreg = PMBUS_STATUS_TEMPERATURE, + .gbit = PB_STATUS_TEMPERATURE, + .limit = temp_limit_attrs2, + .nlimit = 0, + }, { + .reg = PMBUS_READ_TEMPERATURE_3, + .class = PSC_TEMPERATURE, + .paged = true, + .update = true, + .compare = true, + .func = PMBUS_HAVE_TEMP3, + .sfunc = PMBUS_HAVE_STATUS_TEMP, + .sreg = PMBUS_STATUS_TEMPERATURE, + .gbit = PB_STATUS_TEMPERATURE, + .limit = temp_limit_attrs3, + .nlimit = 0, + } +}; + +static const int pmbus_fan_registers[] = { + PMBUS_READ_FAN_SPEED_1, + PMBUS_READ_FAN_SPEED_2, + PMBUS_READ_FAN_SPEED_3, + PMBUS_READ_FAN_SPEED_4 +}; + +static const int pmbus_fan_status_registers[] = { + PMBUS_STATUS_FAN_12, + PMBUS_STATUS_FAN_12, + PMBUS_STATUS_FAN_34, + PMBUS_STATUS_FAN_34 +}; + +static const u32 pmbus_fan_flags[] = { + PMBUS_HAVE_FAN12, + PMBUS_HAVE_FAN12, + PMBUS_HAVE_FAN34, + PMBUS_HAVE_FAN34 +}; + +static const u32 pmbus_fan_status_flags[] = { + PMBUS_HAVE_STATUS_FAN12, + PMBUS_HAVE_STATUS_FAN12, + PMBUS_HAVE_STATUS_FAN34, + PMBUS_HAVE_STATUS_FAN34 +}; + +/* Fans */ + +/* Precondition: FAN_CONFIG_x_y and FAN_COMMAND_x must exist for the fan ID */ +static int pmbus_add_fan_ctrl(struct i2c_client *client, + struct pmbus_data *data, int index, int page, int id, + u8 config) +{ + struct pmbus_sensor *sensor; + + sensor = pmbus_add_sensor(data, "fan", "target", index, page, + 0xff, PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN, + false, false, true); + + if (!sensor) + return -ENOMEM; + + if (!((data->info->func[page] & PMBUS_HAVE_PWM12) || + (data->info->func[page] & PMBUS_HAVE_PWM34))) + return 0; + + sensor = pmbus_add_sensor(data, "pwm", NULL, index, page, + 0xff, PMBUS_VIRT_PWM_1 + id, PSC_PWM, + false, false, true); + + if (!sensor) + return -ENOMEM; + + sensor = pmbus_add_sensor(data, "pwm", "enable", index, page, + 0xff, PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM, + true, false, false); + + if (!sensor) + return -ENOMEM; + + return 0; +} + +static int pmbus_add_fan_attributes(struct i2c_client *client, + struct pmbus_data *data) +{ + const struct pmbus_driver_info *info = data->info; + int index = 1; + int page; + int ret; + + for (page = 0; page < info->pages; page++) { + int f; + + for (f = 0; f < ARRAY_SIZE(pmbus_fan_registers); f++) { + int regval; + + if (!(info->func[page] & pmbus_fan_flags[f])) + break; + + if (!wb_pmbus_check_word_register(client, page, + pmbus_fan_registers[f])) + break; + + /* + * Skip fan if not installed. + * Each fan configuration register covers multiple fans, + * so we have to do some magic. + */ + regval = _pmbus_read_byte_data(client, page, + pmbus_fan_config_registers[f]); + if (regval < 0 || + (!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4))))) + continue; + + if (pmbus_add_sensor(data, "fan", "input", index, + page, 0xff, pmbus_fan_registers[f], + PSC_FAN, true, true, true) == NULL) + return -ENOMEM; + + /* Fan control */ + if (wb_pmbus_check_word_register(client, page, + pmbus_fan_command_registers[f])) { + ret = pmbus_add_fan_ctrl(client, data, index, + page, f, regval); + if (ret < 0) + return ret; + } + + /* + * Each fan status register covers multiple fans, + * so we have to do some magic. + */ + if ((info->func[page] & pmbus_fan_status_flags[f]) && + wb_pmbus_check_byte_register(client, + page, pmbus_fan_status_registers[f])) { + int reg; + + if (f > 1) /* fan 3, 4 */ + reg = PMBUS_STATUS_FAN_34; + else + reg = PMBUS_STATUS_FAN_12; + ret = pmbus_add_boolean(data, "fan", + "alarm", index, NULL, NULL, page, reg, + PB_FAN_FAN1_WARNING >> (f & 1)); + if (ret) + return ret; + ret = pmbus_add_boolean(data, "fan", + "fault", index, NULL, NULL, page, reg, + PB_FAN_FAN1_FAULT >> (f & 1)); + if (ret) + return ret; + } + index++; + } + } + return 0; +} + +struct pmbus_samples_attr { + int reg; + char *name; +}; + +struct pmbus_samples_reg { + int page; + struct pmbus_samples_attr *attr; + struct device_attribute dev_attr; +}; + +static struct pmbus_samples_attr pmbus_samples_registers[] = { + { + .reg = PMBUS_VIRT_SAMPLES, + .name = "samples", + }, { + .reg = PMBUS_VIRT_IN_SAMPLES, + .name = "in_samples", + }, { + .reg = PMBUS_VIRT_CURR_SAMPLES, + .name = "curr_samples", + }, { + .reg = PMBUS_VIRT_POWER_SAMPLES, + .name = "power_samples", + }, { + .reg = PMBUS_VIRT_TEMP_SAMPLES, + .name = "temp_samples", + } +}; + +#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, dev_attr) + +static ssize_t pmbus_show_samples(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int val; + struct i2c_client *client = to_i2c_client(dev->parent); + struct pmbus_samples_reg *reg = to_samples_reg(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg); + mutex_unlock(&data->update_lock); + if (val < 0) + return val; + + return snprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t pmbus_set_samples(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + int ret; + long val; + struct i2c_client *client = to_i2c_client(dev->parent); + struct pmbus_samples_reg *reg = to_samples_reg(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + + if (kstrtol(buf, 0, &val) < 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + ret = _pmbus_write_word_data(client, reg->page, reg->attr->reg, val); + mutex_unlock(&data->update_lock); + + return ret ? : count; +} + +static int pmbus_add_samples_attr(struct pmbus_data *data, int page, + struct pmbus_samples_attr *attr) +{ + struct pmbus_samples_reg *reg; + + reg = devm_kzalloc(data->dev, sizeof(*reg), GFP_KERNEL); + if (!reg) + return -ENOMEM; + + reg->attr = attr; + reg->page = page; + + pmbus_dev_attr_init(®->dev_attr, attr->name, 0644, + pmbus_show_samples, pmbus_set_samples); + + return pmbus_add_attribute(data, ®->dev_attr.attr); +} + +static int pmbus_add_samples_attributes(struct i2c_client *client, + struct pmbus_data *data) +{ + const struct pmbus_driver_info *info = data->info; + int s; + + if (!(info->func[0] & PMBUS_HAVE_SAMPLES)) + return 0; + + for (s = 0; s < ARRAY_SIZE(pmbus_samples_registers); s++) { + struct pmbus_samples_attr *attr; + int ret; + + attr = &pmbus_samples_registers[s]; + if (!wb_pmbus_check_word_register(client, 0, attr->reg)) + continue; + + ret = pmbus_add_samples_attr(data, 0, attr); + if (ret) + return ret; + } + + return 0; +} + +static int pmbus_find_attributes(struct i2c_client *client, + struct pmbus_data *data) +{ + int ret; + + /* Voltage sensors */ + ret = pmbus_add_sensor_attrs(client, data, "in", voltage_attributes, + ARRAY_SIZE(voltage_attributes)); + if (ret) + return ret; + + /* Current sensors */ + ret = pmbus_add_sensor_attrs(client, data, "curr", current_attributes, + ARRAY_SIZE(current_attributes)); + if (ret) + return ret; + + /* Power sensors */ + ret = pmbus_add_sensor_attrs(client, data, "power", power_attributes, + ARRAY_SIZE(power_attributes)); + if (ret) + return ret; + + /* Temperature sensors */ + ret = pmbus_add_sensor_attrs(client, data, "temp", temp_attributes, + ARRAY_SIZE(temp_attributes)); + if (ret) + return ret; + + /* Fans */ + ret = pmbus_add_fan_attributes(client, data); + if (ret) + return ret; + + ret = pmbus_add_samples_attributes(client, data); + return ret; +} + +/* + * Identify chip parameters. + * This function is called for all chips. + */ +static int pmbus_identify_common(struct i2c_client *client, + struct pmbus_data *data, int page) +{ + int vout_mode = -1; + + if (wb_pmbus_check_byte_register(client, page, PMBUS_VOUT_MODE)) + vout_mode = _pmbus_read_byte_data(client, page, + PMBUS_VOUT_MODE); + if (vout_mode >= 0 && vout_mode != 0xff) { + /* + * Not all chips support the VOUT_MODE command, + * so a failure to read it is not an error. + */ + switch (vout_mode >> 5) { + case 0: /* linear mode */ + if (data->info->format[PSC_VOLTAGE_OUT] != linear) + return -ENODEV; + + data->exponent[page] = ((s8)(vout_mode << 3)) >> 3; + break; + case 1: /* VID mode */ + if (data->info->format[PSC_VOLTAGE_OUT] != vid) + return -ENODEV; + break; + case 2: /* direct mode */ + if (data->info->format[PSC_VOLTAGE_OUT] != direct) + return -ENODEV; + break; + default: + return -ENODEV; + } + } + + pmbus_clear_fault_page(client, page); + return 0; +} + +static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, + struct pmbus_driver_info *info) +{ + struct device *dev = &client->dev; + int page, ret, i; + + /* + * Some PMBus chips don't support PMBUS_STATUS_WORD, so try + * to use PMBUS_STATUS_BYTE instead if that is the case. + * Bail out if both registers are not supported. + */ + for(i = 0; i < PMBUS_RETRY_TIME; i++) { + data->read_status = pmbus_read_status_word; + ret = i2c_smbus_read_word_data(client, PMBUS_STATUS_WORD); + if (ret < 0 || ret == 0xffff) { + data->read_status = pmbus_read_status_byte; + ret = i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE); + if (ret < 0 || ret == 0xff) { + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + continue; + } + } else { + data->has_status_word = true; + } + break; + } + + if(i == PMBUS_RETRY_TIME) { + dev_err(dev, "PMBus status register not found\n"); + return -ENODEV; + } + + /* Enable PEC if the controller supports it */ + for(i = 0; i < PMBUS_RETRY_TIME; i++) { + ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); + if (ret >= 0) { + break; + } + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + + if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) + client->flags |= I2C_CLIENT_PEC; + + /* + * Check if the chip is write protected. If it is, we can not clear + * faults, and we should not try it. Also, in that case, writes into + * limit registers need to be disabled. + */ + for(i = 0; i < PMBUS_RETRY_TIME; i++) { + ret = i2c_smbus_read_byte_data(client, PMBUS_WRITE_PROTECT); + if (ret >= 0) { + break; + } + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + + if (ret > 0 && (ret & PB_WP_ANY)) + data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK; + + if (data->info->pages) + wb_pmbus_clear_faults(client); + else + pmbus_clear_fault_page(client, -1); + + if (info->identify) { + ret = (*info->identify)(client, info); + if (ret < 0) { + dev_err(dev, "Chip identification failed\n"); + return ret; + } + } + + if (info->pages <= 0 || info->pages > PMBUS_PAGES) { + dev_err(dev, "Bad number of PMBus pages: %d\n", info->pages); + return -ENODEV; + } + + for (page = 0; page < info->pages; page++) { + ret = pmbus_identify_common(client, data, page); + if (ret < 0) { + dev_err(dev, "Failed to identify chip capabilities\n"); + return ret; + } + } + return 0; +} + +#if IS_ENABLED(CONFIG_REGULATOR) +static int pmbus_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct device *dev = rdev_get_dev(rdev); + struct i2c_client *client = to_i2c_client(dev->parent); + u8 page = rdev_get_id(rdev); + int ret; + + ret = wb_pmbus_read_byte_data(client, page, PMBUS_OPERATION); + if (ret < 0) + return ret; + + return !!(ret & PB_OPERATION_CONTROL_ON); +} + +static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable) +{ + struct device *dev = rdev_get_dev(rdev); + struct i2c_client *client = to_i2c_client(dev->parent); + u8 page = rdev_get_id(rdev); + + return wb_pmbus_update_byte_data(client, page, PMBUS_OPERATION, + PB_OPERATION_CONTROL_ON, + enable ? PB_OPERATION_CONTROL_ON : 0); +} + +static int pmbus_regulator_enable(struct regulator_dev *rdev) +{ + return _pmbus_regulator_on_off(rdev, 1); +} + +static int pmbus_regulator_disable(struct regulator_dev *rdev) +{ + return _pmbus_regulator_on_off(rdev, 0); +} + +const struct regulator_ops wb_pmbus_regulator_ops = { + .enable = pmbus_regulator_enable, + .disable = pmbus_regulator_disable, + .is_enabled = pmbus_regulator_is_enabled, +}; +EXPORT_SYMBOL_GPL(wb_pmbus_regulator_ops); + +static int pmbus_regulator_register(struct pmbus_data *data) +{ + struct device *dev = data->dev; + const struct pmbus_driver_info *info = data->info; + const struct pmbus_platform_data *pdata = dev_get_platdata(dev); + struct regulator_dev *rdev; + int i; + + for (i = 0; i < info->num_regulators; i++) { + struct regulator_config config = { }; + + config.dev = dev; + config.driver_data = data; + + if (pdata && pdata->reg_init_data) + config.init_data = &pdata->reg_init_data[i]; + + rdev = devm_regulator_register(dev, &info->reg_desc[i], + &config); + if (IS_ERR(rdev)) { + dev_err(dev, "Failed to register %s regulator\n", + info->reg_desc[i].name); + return PTR_ERR(rdev); + } + } + + return 0; +} +#else +static int pmbus_regulator_register(struct pmbus_data *data) +{ + return 0; +} +#endif + +static struct dentry *pmbus_debugfs_dir; /* pmbus debugfs directory */ + +#if IS_ENABLED(CONFIG_DEBUG_FS) +static int pmbus_debugfs_get(void *data, u64 *val) +{ + int rc; + struct pmbus_debugfs_entry *entry = data; + + rc = _pmbus_read_byte_data(entry->client, entry->page, entry->reg); + if (rc < 0) + return rc; + + *val = rc; + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops, pmbus_debugfs_get, NULL, + "0x%02llx\n"); + +static int pmbus_debugfs_get_status(void *data, u64 *val) +{ + int rc; + struct pmbus_debugfs_entry *entry = data; + struct pmbus_data *pdata = i2c_get_clientdata(entry->client); + + rc = pdata->read_status(entry->client, entry->page); + if (rc < 0) + return rc; + + *val = rc; + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_status, pmbus_debugfs_get_status, + NULL, "0x%04llx\n"); + +static int pmbus_debugfs_get_pec(void *data, u64 *val) +{ + struct i2c_client *client = data; + + *val = !!(client->flags & I2C_CLIENT_PEC); + + return 0; +} + +static int pmbus_debugfs_set_pec(void *data, u64 val) +{ + int rc; + struct i2c_client *client = data; + + if (!val) { + client->flags &= ~I2C_CLIENT_PEC; + return 0; + } + + if (val != 1) + return -EINVAL; + + rc = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); + if (rc < 0) + return rc; + + if (!(rc & PB_CAPABILITY_ERROR_CHECK)) + return -EOPNOTSUPP; + + client->flags |= I2C_CLIENT_PEC; + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_pec, pmbus_debugfs_get_pec, + pmbus_debugfs_set_pec, "%llu\n"); + +static int pmbus_init_debugfs(struct i2c_client *client, + struct pmbus_data *data) +{ + int i, idx = 0; + char name[PMBUS_NAME_SIZE]; + struct pmbus_debugfs_entry *entries; + + if (!pmbus_debugfs_dir) + return -ENODEV; + + /* + * Create the debugfs directory for this device. Use the hwmon device + * name to avoid conflicts (hwmon numbers are globally unique). + */ + data->debugfs = debugfs_create_dir(dev_name(data->hwmon_dev), + pmbus_debugfs_dir); + if (IS_ERR_OR_NULL(data->debugfs)) { + data->debugfs = NULL; + return -ENODEV; + } + + /* Allocate the max possible entries we need. */ + entries = devm_kcalloc(data->dev, + data->info->pages * 10, sizeof(*entries), + GFP_KERNEL); + if (!entries) + return -ENOMEM; + + debugfs_create_file("pec", 0664, data->debugfs, client, + &pmbus_debugfs_ops_pec); + + for (i = 0; i < data->info->pages; ++i) { + /* Check accessibility of status register if it's not page 0 */ + if (!i || pmbus_check_status_register(client, i)) { + /* No need to set reg as we have special read op. */ + entries[idx].client = client; + entries[idx].page = i; + scnprintf(name, PMBUS_NAME_SIZE, "status%d", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops_status); + } + + if (data->info->func[i] & PMBUS_HAVE_STATUS_VOUT) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_VOUT; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_vout", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (data->info->func[i] & PMBUS_HAVE_STATUS_IOUT) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_IOUT; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_iout", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (data->info->func[i] & PMBUS_HAVE_STATUS_INPUT) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_INPUT; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_input", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (data->info->func[i] & PMBUS_HAVE_STATUS_TEMP) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_TEMPERATURE; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_temp", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (wb_pmbus_check_byte_register(client, i, PMBUS_STATUS_CML)) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_CML; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_cml", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (wb_pmbus_check_byte_register(client, i, PMBUS_STATUS_OTHER)) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_OTHER; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_other", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (wb_pmbus_check_byte_register(client, i, + PMBUS_STATUS_MFR_SPECIFIC)) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_MFR_SPECIFIC; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_mfr", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (data->info->func[i] & PMBUS_HAVE_STATUS_FAN12) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_FAN_12; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_fan12", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (data->info->func[i] & PMBUS_HAVE_STATUS_FAN34) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_FAN_34; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_fan34", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + } + + return 0; +} +#else +static int pmbus_init_debugfs(struct i2c_client *client, + struct pmbus_data *data) +{ + return 0; +} +#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */ + +int wb_pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info) +{ + struct device *dev = &client->dev; + const struct pmbus_platform_data *pdata = dev_get_platdata(dev); + struct pmbus_data *data; + size_t groups_num = 0; + int ret; + + if (!info) + return -ENODEV; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE + | I2C_FUNC_SMBUS_BYTE_DATA + | I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + if (info->groups) + while (info->groups[groups_num]) + groups_num++; + + data->groups = devm_kcalloc(dev, groups_num + 2, sizeof(void *), + GFP_KERNEL); + if (!data->groups) + return -ENOMEM; + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->dev = dev; + + if (pdata) + data->flags = pdata->flags; + data->info = info; + data->currpage = -1; + data->currphase = -1; + + ret = pmbus_init_common(client, data, info); + if (ret < 0) + return ret; + + ret = pmbus_find_attributes(client, data); + if (ret) + return ret; + + /* + * If there are no attributes, something is wrong. + * Bail out instead of trying to register nothing. + */ + if (!data->num_attributes) { + dev_err(dev, "No attributes found\n"); + return -ENODEV; + } + + data->groups[0] = &data->group; + memcpy(data->groups + 1, info->groups, sizeof(void *) * groups_num); + data->hwmon_dev = devm_hwmon_device_register_with_groups(dev, + client->name, data, data->groups); + if (IS_ERR(data->hwmon_dev)) { + dev_err(dev, "Failed to register hwmon device\n"); + return PTR_ERR(data->hwmon_dev); + } + + ret = pmbus_regulator_register(data); + if (ret) + return ret; + + ret = pmbus_init_debugfs(client, data); + if (ret) + dev_warn(dev, "Failed to register debugfs\n"); + + return 0; +} +EXPORT_SYMBOL_GPL(wb_pmbus_do_probe); + +int wb_pmbus_do_remove(struct i2c_client *client) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + + debugfs_remove_recursive(data->debugfs); + + return 0; +} +EXPORT_SYMBOL_GPL(wb_pmbus_do_remove); + +struct dentry *wb_pmbus_get_debugfs_dir(struct i2c_client *client) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + + return data->debugfs; +} +EXPORT_SYMBOL_GPL(wb_pmbus_get_debugfs_dir); + +static int __init pmbus_core_init(void) +{ + pmbus_debugfs_dir = debugfs_create_dir("pmbus", NULL); + if (IS_ERR(pmbus_debugfs_dir)) + pmbus_debugfs_dir = NULL; + + return 0; +} + +static void __exit pmbus_core_exit(void) +{ + debugfs_remove_recursive(pmbus_debugfs_dir); +} + +module_init(pmbus_core_init); +module_exit(pmbus_core_exit); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("PMBus core driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tmp401.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tmp401.c new file mode 100644 index 000000000000..b8d3a024f624 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tmp401.c @@ -0,0 +1,1010 @@ +/* tmp401.c + * + * Copyright (C) 2007,2008 Hans de Goede + * Preliminary tmp411 support by: + * Gabriel Konat, Sander Leget, Wouter Willems + * Copyright (C) 2009 Andre Prendel + * + * Cleanup and support for TMP431 and TMP432 by Guenter Roeck + * Copyright (c) 2013 Guenter Roeck + * + * 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. + */ + +/* + * Driver for the Texas Instruments TMP401 SMBUS temperature sensor IC. + * + * Note this IC is in some aspect similar to the LM90, but it has quite a + * few differences too, for example the local temp has a higher resolution + * and thus has 16 bits registers for its value and limit instead of 8 bits. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +/* static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c, 0x4d, + 0x4e, 0x4f, I2C_CLIENT_END }; */ + +enum chips { tmp401, tmp411, tmp431, tmp432, tmp435, tmp461 }; + +/* + * The TMP401 registers, note some registers have different addresses for + * reading and writing + */ +#define TMP401_STATUS (0x02) +#define TMP401_CONFIG_READ (0x03) +#define TMP401_CONFIG_WRITE (0x09) +#define TMP401_CONVERSION_RATE_READ (0x04) +#define TMP401_CONVERSION_RATE_WRITE (0x0A) +#define TMP401_TEMP_CRIT_HYST (0x21) +#define TMP401_MANUFACTURER_ID_REG (0xFE) +#define TMP401_DEVICE_ID_REG (0xFF) +#define TMP401_DEVICE_CAR_REG (0x22) /* Consecutive Alert Register */ + +static const u8 TMP401_TEMP_MSB_READ[7][2] = { + { 0x00, 0x01 }, /* temp */ + { 0x06, 0x08 }, /* low limit */ + { 0x05, 0x07 }, /* high limit */ + { 0x20, 0x19 }, /* therm (crit) limit */ + { 0x30, 0x34 }, /* lowest */ + { 0x32, 0x36 }, /* highest */ + { 0, 0x11 }, /* offset */ +}; + +static const u8 TMP401_TEMP_MSB_WRITE[7][2] = { + { 0, 0 }, /* temp (unused) */ + { 0x0C, 0x0E }, /* low limit */ + { 0x0B, 0x0D }, /* high limit */ + { 0x20, 0x19 }, /* therm (crit) limit */ + { 0x30, 0x34 }, /* lowest */ + { 0x32, 0x36 }, /* highest */ + { 0, 0x11 }, /* offset */ +}; + +static const u8 TMP401_TEMP_LSB[7][2] = { + { 0x15, 0x10 }, /* temp */ + { 0x17, 0x14 }, /* low limit */ + { 0x16, 0x13 }, /* high limit */ + { 0, 0 }, /* therm (crit) limit (unused) */ + { 0x31, 0x35 }, /* lowest */ + { 0x33, 0x37 }, /* highest */ + { 0, 0x12 }, /* offset */ +}; + +static const u8 TMP432_TEMP_MSB_READ[4][3] = { + { 0x00, 0x01, 0x23 }, /* temp */ + { 0x06, 0x08, 0x16 }, /* low limit */ + { 0x05, 0x07, 0x15 }, /* high limit */ + { 0x20, 0x19, 0x1A }, /* therm (crit) limit */ +}; + +static const u8 TMP432_TEMP_MSB_WRITE[4][3] = { + { 0, 0, 0 }, /* temp - unused */ + { 0x0C, 0x0E, 0x16 }, /* low limit */ + { 0x0B, 0x0D, 0x15 }, /* high limit */ + { 0x20, 0x19, 0x1A }, /* therm (crit) limit */ +}; + +static const u8 TMP432_TEMP_LSB[3][3] = { + { 0x29, 0x10, 0x24 }, /* temp */ + { 0x3E, 0x14, 0x18 }, /* low limit */ + { 0x3D, 0x13, 0x17 }, /* high limit */ +}; + +/* [0] = fault, [1] = low, [2] = high, [3] = therm/crit */ +static const u8 TMP432_STATUS_REG[] = { + 0x1b, 0x36, 0x35, 0x37 }; + +/* Flags */ +#define TMP401_CONFIG_RANGE BIT(2) +#define TMP401_CONFIG_SHUTDOWN BIT(6) +#define TMP401_STATUS_LOCAL_CRIT BIT(0) +#define TMP401_STATUS_REMOTE_CRIT BIT(1) +#define TMP401_STATUS_REMOTE_OPEN BIT(2) +#define TMP401_STATUS_REMOTE_LOW BIT(3) +#define TMP401_STATUS_REMOTE_HIGH BIT(4) +#define TMP401_STATUS_LOCAL_LOW BIT(5) +#define TMP401_STATUS_LOCAL_HIGH BIT(6) + +/* On TMP432, each status has its own register */ +#define TMP432_STATUS_LOCAL BIT(0) +#define TMP432_STATUS_REMOTE1 BIT(1) +#define TMP432_STATUS_REMOTE2 BIT(2) + +/* Manufacturer / Device ID's */ +#define TMP401_MANUFACTURER_ID (0x55) +#define TMP401_DEVICE_ID (0x11) +#define TMP411A_DEVICE_ID (0x12) +#define TMP411B_DEVICE_ID (0x13) +#define TMP411C_DEVICE_ID (0x10) +#define TMP431_DEVICE_ID (0x31) +#define TMP432_DEVICE_ID (0x32) +#define TMP435_DEVICE_ID (0x35) + +/* Timeout function bit */ +#define TIMEOUT_STATE_BIT (7) /* 1:enable 0:disable */ +#define TIMEOUT_STATE_EN (1) /* 1:enable */ +#define TIMEOUT_STATE_IEN (0) /* 0:disable */ +#define TIMEOUT_STATE_NA "NA" +#define TMP401_TEMP_INVALID_RETRY_TIMES (3) + +/* input temp threshold check */ +typedef struct tmp401_temp_threshold_s { + int chip_type; + int temp_max; + int temp_min; +} tmp401_temp_threshold_t; + +static tmp401_temp_threshold_t g_tmp401_input_threshold_info[] = { + { + .chip_type = tmp411, + .temp_max = 127000, + .temp_min = -55000, + }, +}; + +/* + * Driver data (common to all clients) + */ + +static const struct i2c_device_id tmp401_id[] = { + { "wb_tmp401", tmp401 }, + { "wb_tmp411", tmp411 }, + { "wb_tmp431", tmp431 }, + { "wb_tmp432", tmp432 }, + { "wb_tmp435", tmp435 }, + { "wb_tmp461", tmp461 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tmp401_id); + +/* + * Client data (each client gets its own) + */ + +struct tmp401_data { + struct i2c_client *client; + const struct attribute_group *groups[3]; + struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + enum chips kind; + + unsigned int update_interval; /* in milliseconds */ + + /* register values */ + u8 status[4]; + u8 config; + u16 temp[7][3]; + u8 temp_crit_hyst; +}; + +/* + * Sysfs attr show / store functions + */ + +static int tmp401_register_to_temp(u16 reg, u8 config) +{ + int temp = reg; + + if (config & TMP401_CONFIG_RANGE) + temp -= 64 * 256; + + return DIV_ROUND_CLOSEST(temp * 125, 32); +} + +static u16 tmp401_temp_to_register(long temp, u8 config, int zbits) +{ + if (config & TMP401_CONFIG_RANGE) { + temp = clamp_val(temp, -64000, 191000); + temp += 64000; + } else + temp = clamp_val(temp, 0, 127000); + + return DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits; +} + +static int tmp401_update_device_reg16(struct i2c_client *client, + struct tmp401_data *data) +{ + int i, j, val; + int num_regs = data->kind == tmp411 ? 6 : 4; + int num_sensors = data->kind == tmp432 ? 3 : 2; + + for (i = 0; i < num_sensors; i++) { /* local / r1 / r2 */ + for (j = 0; j < num_regs; j++) { /* temp / low / ... */ + u8 regaddr; + /* + * High byte must be read first immediately followed + * by the low byte + */ + regaddr = data->kind == tmp432 ? + TMP432_TEMP_MSB_READ[j][i] : + TMP401_TEMP_MSB_READ[j][i]; + val = i2c_smbus_read_byte_data(client, regaddr); + if (val < 0) + return val; + data->temp[j][i] = val << 8; + if (j == 3) /* crit is msb only */ + continue; + regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[j][i] + : TMP401_TEMP_LSB[j][i]; + val = i2c_smbus_read_byte_data(client, regaddr); + if (val < 0) + return val; + data->temp[j][i] |= val; + } + } + return 0; +} + +static struct tmp401_data *tmp401_update_device(struct device *dev) +{ + struct tmp401_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + struct tmp401_data *ret = data; + int i, val; + unsigned long next_update; + + mutex_lock(&data->update_lock); + + next_update = data->last_updated + + msecs_to_jiffies(data->update_interval); + if (time_after(jiffies, next_update) || !data->valid) { + if (data->kind != tmp432) { + /* + * The driver uses the TMP432 status format internally. + * Convert status to TMP432 format for other chips. + */ + val = i2c_smbus_read_byte_data(client, TMP401_STATUS); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + data->status[0] = + (val & TMP401_STATUS_REMOTE_OPEN) >> 1; + data->status[1] = + ((val & TMP401_STATUS_REMOTE_LOW) >> 2) | + ((val & TMP401_STATUS_LOCAL_LOW) >> 5); + data->status[2] = + ((val & TMP401_STATUS_REMOTE_HIGH) >> 3) | + ((val & TMP401_STATUS_LOCAL_HIGH) >> 6); + data->status[3] = val & (TMP401_STATUS_LOCAL_CRIT + | TMP401_STATUS_REMOTE_CRIT); + } else { + for (i = 0; i < ARRAY_SIZE(data->status); i++) { + val = i2c_smbus_read_byte_data(client, + TMP432_STATUS_REG[i]); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + data->status[i] = val; + } + } + + val = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + data->config = val; + val = tmp401_update_device_reg16(client, data); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + val = i2c_smbus_read_byte_data(client, TMP401_TEMP_CRIT_HYST); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + data->temp_crit_hyst = val; + + data->last_updated = jiffies; + data->valid = 1; + } + +abort: + mutex_unlock(&data->update_lock); + return ret; +} + +static int tmp401_input_temp_check(struct tmp401_data *data, int input_val) +{ + int i, size; + + size = ARRAY_SIZE(g_tmp401_input_threshold_info); + + for (i = 0; i < size; i++) { + if (g_tmp401_input_threshold_info[i].chip_type == data->kind) { + if ((input_val > g_tmp401_input_threshold_info[i].temp_max) + || (input_val < g_tmp401_input_threshold_info[i].temp_min)) { + dev_dbg(&data->client->dev, "input temp: %d not in range[%d, %d]\n", + input_val, g_tmp401_input_threshold_info[i].temp_min, + g_tmp401_input_threshold_info[i].temp_max); + return -EINVAL; + } + dev_dbg(&data->client->dev, "input temp: %d in range[%d, %d]", input_val, + g_tmp401_input_threshold_info[i].temp_min, g_tmp401_input_threshold_info[i].temp_max); + return 0; + } + } + return 0; +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr, index, i, value, ret; + struct tmp401_data *data; + struct i2c_client *client; + + data = dev_get_drvdata(dev); + client = data->client; + + nr = to_sensor_dev_attr_2(devattr)->nr; + index = to_sensor_dev_attr_2(devattr)->index; + + for (i = 0; i < TMP401_TEMP_INVALID_RETRY_TIMES; i++) { + data = tmp401_update_device(dev); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + value = tmp401_register_to_temp(data->temp[nr][index], data->config); + if (nr != 0) { /* not input temp, return value */ + return sprintf(buf, "%d\n", value); + } + /* nr == 0 is temp input, do input_temp_check */ + ret = tmp401_input_temp_check(data, value); + if (ret == 0) { /* input temp check ok */ + return sprintf(buf, "%d\n", value); + } + if ((i + 1) < TMP401_TEMP_INVALID_RETRY_TIMES) { + msleep(data->update_interval); + } + } + dev_info(&client->dev, "temp%d_input value: %d invalid\n", index + 1, value); + return -EINVAL; +} + +static ssize_t show_temp_crit_hyst(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int temp, index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + mutex_lock(&data->update_lock); + temp = tmp401_register_to_temp(data->temp[3][index], data->config); + temp -= data->temp_crit_hyst * 1000; + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", temp); +} + +static ssize_t show_status(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr_2(devattr)->nr; + int mask = to_sensor_dev_attr_2(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%d\n", !!(data->status[nr] & mask)); +} + +static ssize_t store_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr_2(devattr)->nr; + int index = to_sensor_dev_attr_2(devattr)->index; + struct tmp401_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + long val; + u16 reg; + u8 regaddr; + + if (kstrtol(buf, 10, &val)) + return -EINVAL; + + reg = tmp401_temp_to_register(val, data->config, nr == 3 ? 8 : 4); + + mutex_lock(&data->update_lock); + + regaddr = data->kind == tmp432 ? TMP432_TEMP_MSB_WRITE[nr][index] + : TMP401_TEMP_MSB_WRITE[nr][index]; + i2c_smbus_write_byte_data(client, regaddr, reg >> 8); + if (nr != 3) { + regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[nr][index] + : TMP401_TEMP_LSB[nr][index]; + i2c_smbus_write_byte_data(client, regaddr, reg & 0xFF); + } + data->temp[nr][index] = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int temp, index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + long val; + u8 reg; + + if (IS_ERR(data)) + return PTR_ERR(data); + + if (kstrtol(buf, 10, &val)) + return -EINVAL; + + if (data->config & TMP401_CONFIG_RANGE) + val = clamp_val(val, -64000, 191000); + else + val = clamp_val(val, 0, 127000); + + mutex_lock(&data->update_lock); + temp = tmp401_register_to_temp(data->temp[3][index], data->config); + val = clamp_val(val, temp - 255000, temp); + reg = ((temp - val) + 500) / 1000; + + i2c_smbus_write_byte_data(data->client, TMP401_TEMP_CRIT_HYST, + reg); + + data->temp_crit_hyst = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +/* + * Resets the historical measurements of minimum and maximum temperatures. + * This is done by writing any value to any of the minimum/maximum registers + * (0x30-0x37). + */ +static ssize_t reset_temp_history(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct tmp401_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + long val; + + if (kstrtol(buf, 10, &val)) + return -EINVAL; + + if (val != 1) { + dev_err(dev, + "temp_reset_history value %ld not supported. Use 1 to reset the history!\n", + val); + return -EINVAL; + } + mutex_lock(&data->update_lock); + i2c_smbus_write_byte_data(client, TMP401_TEMP_MSB_WRITE[5][0], val); + data->valid = 0; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_update_interval(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tmp401_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", data->update_interval); +} + +static ssize_t set_update_interval(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct tmp401_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + unsigned long val; + int err, rate; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + /* + * For valid rates, interval can be calculated as + * interval = (1 << (7 - rate)) * 125; + * Rounded rate is therefore + * rate = 7 - __fls(interval * 4 / (125 * 3)); + * Use clamp_val() to avoid overflows, and to ensure valid input + * for __fls. + */ + val = clamp_val(val, 125, 16000); + rate = 7 - __fls(val * 4 / (125 * 3)); + mutex_lock(&data->update_lock); + i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, rate); + data->update_interval = (1 << (7 - rate)) * 125; + mutex_unlock(&data->update_lock); + + return count; +} + +/* + * Enable/disable the state of the timeout function + * @dev: device info + * @state: 1:enable 0:disable + */ +static int timeout_cfg(struct device *dev, int state) +{ + int rv, chip_type; + u8 reg_value; + struct tmp401_data *data; + struct i2c_client *client; + + data = dev_get_drvdata(dev); + client = data->client; + + /* get chip type */ + chip_type = data->kind; + dev_dbg(&client->dev, "set timeout. chip:%d, state:%d\n", chip_type, state); + + /* chip type check */ + if(chip_type != tmp401 && chip_type != tmp411) { + dev_info(&client->dev, + "Chip type: %d, not support timeout config.!\n", chip_type); + return -EPERM; + } + + /* parameter check */ + if(state != TIMEOUT_STATE_EN && state != TIMEOUT_STATE_IEN) { + dev_err(&client->dev, + "Parameter check error. state: %d not supported.!\n", state); + return -EINVAL; + } + + mutex_lock(&data->update_lock); + /* read the Consecutive alert register */ + reg_value = i2c_smbus_read_byte_data(client, TMP401_DEVICE_CAR_REG); + if (reg_value < 0) { + dev_err(&client->dev, "Failed to read. reg:0x%0x, value:%d\n", TMP401_DEVICE_CAR_REG, reg_value); + mutex_unlock(&data->update_lock); + return -EIO; + } + dev_dbg(&client->dev, "get register value. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); + + /* same value case, do not write */ + if((u8)state == (reg_value >> TIMEOUT_STATE_BIT)) { + mutex_unlock(&data->update_lock); + dev_info(&client->dev, "timeout config has been set and the current state is %d.\n", state); + return 0; + } + + /* calculate the register value */ + reg_value = (reg_value & ~(1 << TIMEOUT_STATE_BIT)) | (state << TIMEOUT_STATE_BIT); + + /* set the Consecutive alert register */ + dev_dbg(&client->dev, "set register value. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); + rv = i2c_smbus_write_byte_data(client, TMP401_DEVICE_CAR_REG, reg_value); + if (rv < 0) { + dev_err(&client->dev, + "set the register Error. reg:0x%0x, value:%d\n", TMP401_DEVICE_CAR_REG, reg_value); + mutex_unlock(&data->update_lock); + return -EIO; + } + mutex_unlock(&data->update_lock); + + dev_info(&client->dev, "set bus timeout success. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); + + return 0; +} + +static ssize_t set_timeout_en(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int val, err; + struct i2c_client *client; + struct tmp401_data *data; + + data = dev_get_drvdata(dev); + client = data->client; + + err = kstrtoint(buf, 0, &val); + if (err) { + dev_err(&client->dev, + "kstrtoint error: %d.\n", err); + return err; + } + + err = timeout_cfg(dev, val); + if(err < 0) { + dev_err(&client->dev, + "set bus timeout error: %d. value:%d!\n", err, val); + return err; + } + + return count; +} + +static ssize_t show_timeout_en(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int chip_type; + u8 reg_value; + struct tmp401_data *data; + struct i2c_client *client; + + data = dev_get_drvdata(dev); + client = data->client; + + /* get chip type */ + chip_type = data->kind; + dev_dbg(&client->dev, "get timeout. chip:%d\n", chip_type); + + /* chip type check */ + if(chip_type != tmp401 && chip_type != tmp411) { + dev_info(&client->dev, + "Chip type: %d, not support timeout config.!\n", chip_type); + /* not support, return NA */ + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", TIMEOUT_STATE_NA); + } + + /* read the Consecutive alert register */ + reg_value = i2c_smbus_read_byte_data(client, TMP401_DEVICE_CAR_REG); + if (reg_value < 0) { + dev_err(&client->dev, "Failed to read. reg:0x%0x, value:%d\n", TMP401_DEVICE_CAR_REG, reg_value); + return -EIO; + } + dev_dbg(&client->dev, "get register value. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); + + /* decode the register value */ + reg_value = reg_value >> TIMEOUT_STATE_BIT; + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", reg_value); +} + +static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0); +static SENSOR_DEVICE_ATTR_2(temp1_min, S_IWUSR | S_IRUGO, show_temp, + store_temp, 1, 0); +static SENSOR_DEVICE_ATTR_2(temp1_max, S_IWUSR | S_IRUGO, show_temp, + store_temp, 2, 0); +static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IWUSR | S_IRUGO, show_temp, + store_temp, 3, 0); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, + show_temp_crit_hyst, store_temp_crit_hyst, 0); +static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO, show_status, NULL, + 1, TMP432_STATUS_LOCAL); +static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_status, NULL, + 2, TMP432_STATUS_LOCAL); +static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_status, NULL, + 3, TMP432_STATUS_LOCAL); +static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1); +static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp, + store_temp, 1, 1); +static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp, + store_temp, 2, 1); +static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IWUSR | S_IRUGO, show_temp, + store_temp, 3, 1); +static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, + NULL, 1); +static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_status, NULL, + 0, TMP432_STATUS_REMOTE1); +static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_status, NULL, + 1, TMP432_STATUS_REMOTE1); +static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_status, NULL, + 2, TMP432_STATUS_REMOTE1); +static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_status, NULL, + 3, TMP432_STATUS_REMOTE1); + +static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval, + set_update_interval); +static DEVICE_ATTR(timeout_en, S_IRUGO | S_IWUSR, show_timeout_en, set_timeout_en); + +static struct attribute *tmp401_attributes[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_crit.dev_attr.attr, + &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, + &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, + + &dev_attr_update_interval.attr, + &dev_attr_timeout_en.attr, + + NULL +}; + +static const struct attribute_group tmp401_group = { + .attrs = tmp401_attributes, +}; + +/* + * Additional features of the TMP411 chip. + * The TMP411 stores the minimum and maximum + * temperature measured since power-on, chip-reset, or + * minimum and maximum register reset for both the local + * and remote channels. + */ +static SENSOR_DEVICE_ATTR_2(temp1_lowest, S_IRUGO, show_temp, NULL, 4, 0); +static SENSOR_DEVICE_ATTR_2(temp1_highest, S_IRUGO, show_temp, NULL, 5, 0); +static SENSOR_DEVICE_ATTR_2(temp2_lowest, S_IRUGO, show_temp, NULL, 4, 1); +static SENSOR_DEVICE_ATTR_2(temp2_highest, S_IRUGO, show_temp, NULL, 5, 1); +static SENSOR_DEVICE_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history, + 0); + +static struct attribute *tmp411_attributes[] = { + &sensor_dev_attr_temp1_highest.dev_attr.attr, + &sensor_dev_attr_temp1_lowest.dev_attr.attr, + &sensor_dev_attr_temp2_highest.dev_attr.attr, + &sensor_dev_attr_temp2_lowest.dev_attr.attr, + &sensor_dev_attr_temp_reset_history.dev_attr.attr, + NULL +}; + +static const struct attribute_group tmp411_group = { + .attrs = tmp411_attributes, +}; + +static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2); +static SENSOR_DEVICE_ATTR_2(temp3_min, S_IWUSR | S_IRUGO, show_temp, + store_temp, 1, 2); +static SENSOR_DEVICE_ATTR_2(temp3_max, S_IWUSR | S_IRUGO, show_temp, + store_temp, 2, 2); +static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IWUSR | S_IRUGO, show_temp, + store_temp, 3, 2); +static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, + NULL, 2); +static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_status, NULL, + 0, TMP432_STATUS_REMOTE2); +static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_status, NULL, + 1, TMP432_STATUS_REMOTE2); +static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_status, NULL, + 2, TMP432_STATUS_REMOTE2); +static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_status, NULL, + 3, TMP432_STATUS_REMOTE2); + +static struct attribute *tmp432_attributes[] = { + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp3_crit.dev_attr.attr, + &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, + &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, + + NULL +}; + +static const struct attribute_group tmp432_group = { + .attrs = tmp432_attributes, +}; + +/* + * Additional features of the TMP461 chip. + * The TMP461 temperature offset for the remote channel. + */ +static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IWUSR | S_IRUGO, show_temp, + store_temp, 6, 1); + +static struct attribute *tmp461_attributes[] = { + &sensor_dev_attr_temp2_offset.dev_attr.attr, + NULL +}; + +static const struct attribute_group tmp461_group = { + .attrs = tmp461_attributes, +}; + +/* + * Begin non sysfs callback code (aka Real code) + */ + +static int tmp401_init_client(struct tmp401_data *data, + struct i2c_client *client) +{ + int config, config_orig, status = 0; + + /* Set the conversion rate to 2 Hz */ + i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5); + data->update_interval = 500; + + /* Start conversions (disable shutdown if necessary) */ + config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); + if (config < 0) + return config; + + config_orig = config; + config &= ~TMP401_CONFIG_SHUTDOWN; + + if (config != config_orig) + status = i2c_smbus_write_byte_data(client, + TMP401_CONFIG_WRITE, + config); + + return status; +} + +#if 0 +static int tmp401_detect(struct i2c_client *client, + struct i2c_board_info *info) +{ + enum chips kind; + struct i2c_adapter *adapter = client->adapter; + u8 reg; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + /* Detect and identify the chip */ + reg = i2c_smbus_read_byte_data(client, TMP401_MANUFACTURER_ID_REG); + if (reg != TMP401_MANUFACTURER_ID) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, TMP401_DEVICE_ID_REG); + + switch (reg) { + case TMP401_DEVICE_ID: + if (client->addr != 0x4c) + return -ENODEV; + kind = tmp401; + break; + case TMP411A_DEVICE_ID: + if (client->addr != 0x4c) + return -ENODEV; + kind = tmp411; + break; + case TMP411B_DEVICE_ID: + if (client->addr != 0x4d) + return -ENODEV; + kind = tmp411; + break; + case TMP411C_DEVICE_ID: + if (client->addr != 0x4e) + return -ENODEV; + kind = tmp411; + break; + case TMP431_DEVICE_ID: + if (client->addr != 0x4c && client->addr != 0x4d) + return -ENODEV; + kind = tmp431; + break; + case TMP432_DEVICE_ID: + if (client->addr != 0x4c && client->addr != 0x4d) + return -ENODEV; + kind = tmp432; + break; + case TMP435_DEVICE_ID: + kind = tmp435; + break; + default: + return -ENODEV; + } + + reg = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); + if (reg & 0x1b) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, TMP401_CONVERSION_RATE_READ); + /* Datasheet says: 0x1-0x6 */ + if (reg > 15) + return -ENODEV; + + strlcpy(info->type, tmp401_id[kind].name, I2C_NAME_SIZE); + + return 0; +} +#endif + +static int tmp401_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + static const char * const names[] = { + "TMP401", "TMP411", "TMP431", "TMP432", "TMP435", "TMP461" + }; + struct device *dev = &client->dev; + struct device *hwmon_dev; + struct tmp401_data *data; + int groups = 0, status; + + data = devm_kzalloc(dev, sizeof(struct tmp401_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->client = client; + mutex_init(&data->update_lock); + data->kind = id->driver_data; + + /* Initialize the TMP401 chip */ + status = tmp401_init_client(data, client); + if (status < 0) + return status; + + /* Register sysfs hooks */ + data->groups[groups++] = &tmp401_group; + + /* Register additional tmp411 sysfs hooks */ + if (data->kind == tmp411) + data->groups[groups++] = &tmp411_group; + + /* Register additional tmp432 sysfs hooks */ + if (data->kind == tmp432) + data->groups[groups++] = &tmp432_group; + + if (data->kind == tmp461) + data->groups[groups++] = &tmp461_group; + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, data->groups); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); + + /* disable the timeout function */ + status = timeout_cfg(hwmon_dev, TIMEOUT_STATE_IEN); + if((status < 0) && (status != -EPERM)) { + dev_err(dev, + "set bus timeout error when probing: %d.!\n", status); + /* here, no need call devm_hwmon_device_unregister, device managed. */ + return status; + } + + dev_info(dev, "Detected TI %s chip\n", names[data->kind]); + + return 0; +} + +static struct i2c_driver tmp401_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "wb_tmp401", + }, + .probe = tmp401_probe, + .id_table = tmp401_id, + /* .detect = tmp401_detect, */ + /* .address_list = normal_i2c, */ +}; + +module_i2c_driver(tmp401_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("Texas Instruments TMP401 temperature sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tps53622.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tps53622.c new file mode 100644 index 000000000000..b68196d9f57c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tps53622.c @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for Texas Instruments TPS53679 + * + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Vadim Pasternak + */ + +#include +#include +#include +#include +#include +#include +#include +#include "wb_pmbus.h" + +enum chips { + tps53647, tps53667, tps53679, tps53681, tps53688, tps53622 +}; + +#define TPS53647_PAGE_NUM 1 + +#define TPS53679_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */ +#define TPS53679_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */ +#define TPS53679_PROT_VR13_10MV 0x04 /* VR13.0 mode, 10-mV DAC */ +#define TPS53679_PROT_IMVP8_5MV 0x05 /* IMVP8 mode, 5-mV DAC */ +#define TPS53679_PROT_VR13_5MV 0x07 /* VR13.0 mode, 5-mV DAC */ +#define TPS53679_PAGE_NUM 2 + +#define TPS53681_DEVICE_ID 0x81 + +#define TPS53681_PMBUS_REVISION 0x33 + +#define TPS53681_MFR_SPECIFIC_20 0xe4 /* Number of phases, per page */ + +static const struct i2c_device_id tps53679_id[]; + +static int tps53679_identify_mode(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + u8 vout_params; + int i, ret; + + for (i = 0; i < info->pages; i++) { + /* Read the register with VOUT scaling value.*/ + ret = wb_pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); + if (ret < 0) + return ret; + + vout_params = ret & GENMASK(4, 0); + + switch (vout_params) { + case TPS53679_PROT_VR13_10MV: + case TPS53679_PROT_VR12_5_10MV: + info->vrm_version[i] = vr13; + break; + case TPS53679_PROT_VR13_5MV: + case TPS53679_PROT_VR12_5MV: + case TPS53679_PROT_IMVP8_5MV: + info->vrm_version[i] = vr12; + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static int tps53679_identify_phases(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + int ret; + + /* On TPS53681, only channel A provides per-phase output current */ + ret = wb_pmbus_read_byte_data(client, 0, TPS53681_MFR_SPECIFIC_20); + if (ret < 0) + return ret; + info->phases[0] = (ret & 0x07) + 1; + + return 0; +} + +static int tps53679_identify_chip(struct i2c_client *client, + u8 revision, u16 id) +{ + u8 buf[I2C_SMBUS_BLOCK_MAX]; + int ret; + + ret = wb_pmbus_read_byte_data(client, 0, PMBUS_REVISION); + if (ret < 0) + return ret; + if (ret != revision) { + dev_err(&client->dev, "Unexpected PMBus revision 0x%x\n", ret); + return -ENODEV; + } + + ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf); + if (ret < 0) + return ret; + if (ret != 1 || buf[0] != id) { + dev_err(&client->dev, "Unexpected device ID 0x%x\n", buf[0]); + return -ENODEV; + } + return 0; +} + +/* + * Common identification function for chips with multi-phase support. + * Since those chips have special configuration registers, we want to have + * some level of reassurance that we are really talking with the chip + * being probed. Check PMBus revision and chip ID. + */ +static int tps53679_identify_multiphase(struct i2c_client *client, + struct pmbus_driver_info *info, + int pmbus_rev, int device_id) +{ + int ret; + + ret = tps53679_identify_chip(client, pmbus_rev, device_id); + if (ret < 0) + return ret; + + ret = tps53679_identify_mode(client, info); + if (ret < 0) + return ret; + + return tps53679_identify_phases(client, info); +} + +static int tps53679_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + return tps53679_identify_mode(client, info); +} + +static int tps53681_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + return tps53679_identify_multiphase(client, info, + TPS53681_PMBUS_REVISION, + TPS53681_DEVICE_ID); +} + +static int tps53681_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + /* + * For reading the total output current (READ_IOUT) for all phases, + * the chip datasheet is a bit vague. It says "PHASE must be set to + * FFh to access all phases simultaneously. PHASE may also be set to + * 80h readack (!) the total phase current". + * Experiments show that the command does _not_ report the total + * current for all phases if the phase is set to 0xff. Instead, it + * appears to report the current of one of the phases. Override phase + * parameter with 0x80 when reading the total output current on page 0. + */ + if (reg == PMBUS_READ_IOUT && page == 0 && phase == 0xff) + return wb_pmbus_read_word_data(client, page, 0x80, reg); + return -ENODATA; +} + +static struct pmbus_driver_info tps53679_info = { + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = vid, + .format[PSC_TEMPERATURE] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | + PMBUS_HAVE_STATUS_INPUT | + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_POUT, + .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_POUT, + .pfunc[0] = PMBUS_HAVE_IOUT, + .pfunc[1] = PMBUS_HAVE_IOUT, + .pfunc[2] = PMBUS_HAVE_IOUT, + .pfunc[3] = PMBUS_HAVE_IOUT, + .pfunc[4] = PMBUS_HAVE_IOUT, + .pfunc[5] = PMBUS_HAVE_IOUT, +}; + +static int tps53679_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct pmbus_driver_info *info; + enum chips chip_id; + + if (dev->of_node) + chip_id = (enum chips)of_device_get_match_data(dev); + else + chip_id = i2c_match_id(tps53679_id, client)->driver_data; + + info = devm_kmemdup(dev, &tps53679_info, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + switch (chip_id) { + case tps53647: + case tps53667: + info->pages = TPS53647_PAGE_NUM; + info->identify = tps53679_identify; + break; + case tps53679: + case tps53688: + case tps53622: + info->pages = TPS53679_PAGE_NUM; + info->identify = tps53679_identify; + break; + case tps53681: + info->pages = TPS53679_PAGE_NUM; + info->phases[0] = 6; + info->identify = tps53681_identify; + info->read_word_data = tps53681_read_word_data; + break; + default: + return -ENODEV; + } + + return wb_pmbus_do_probe(client, info); +} + +static const struct i2c_device_id tps53679_id[] = { + {"wb_tps53647", tps53647}, + {"wb_tps53667", tps53667}, + {"wb_tps53679", tps53679}, + {"wb_tps53681", tps53681}, + {"wb_tps53688", tps53688}, + {"wb_tps53622", tps53622}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, tps53679_id); + +static const struct of_device_id __maybe_unused tps53679_of_match[] = { + {.compatible = "ti,wb_tps53647", .data = (void *)tps53647}, + {.compatible = "ti,wb_tps53667", .data = (void *)tps53667}, + {.compatible = "ti,wb_tps53679", .data = (void *)tps53679}, + {.compatible = "ti,wb_tps53681", .data = (void *)tps53681}, + {.compatible = "ti,wb_tps53688", .data = (void *)tps53688}, + {.compatible = "ti,wb_tps53622", .data = (void *)tps53622}, + {} +}; +MODULE_DEVICE_TABLE(of, tps53679_of_match); + +static struct i2c_driver tps53679_driver = { + .driver = { + .name = "wb_tps53622", + .of_match_table = of_match_ptr(tps53679_of_match), + }, + .probe_new = tps53679_probe, + .remove = wb_pmbus_do_remove, + .id_table = tps53679_id, +}; + +module_i2c_driver(tps53679_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("PMBus driver for Texas Instruments TPS53679"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ucd9000.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ucd9000.c new file mode 100644 index 000000000000..5c3d125afb6d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ucd9000.c @@ -0,0 +1,676 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for UCD90xxx Sequencer and System Health + * Controller series + * + * Copyright (C) 2011 Ericsson AB. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wb_pmbus.h" + +enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd90320, ucd9090, + ucd90910 }; + +#define UCD9000_MONITOR_CONFIG 0xd5 +#define UCD9000_NUM_PAGES 0xd6 +#define UCD9000_FAN_CONFIG_INDEX 0xe7 +#define UCD9000_FAN_CONFIG 0xe8 +#define UCD9000_MFR_STATUS 0xf3 +#define UCD9000_GPIO_SELECT 0xfa +#define UCD9000_GPIO_CONFIG 0xfb +#define UCD9000_DEVICE_ID 0xfd + +/* GPIO CONFIG bits */ +#define UCD9000_GPIO_CONFIG_ENABLE BIT(0) +#define UCD9000_GPIO_CONFIG_OUT_ENABLE BIT(1) +#define UCD9000_GPIO_CONFIG_OUT_VALUE BIT(2) +#define UCD9000_GPIO_CONFIG_STATUS BIT(3) +#define UCD9000_GPIO_INPUT 0 +#define UCD9000_GPIO_OUTPUT 1 + +#define UCD9000_MON_TYPE(x) (((x) >> 5) & 0x07) +#define UCD9000_MON_PAGE(x) ((x) & 0x1f) + +#define UCD9000_MON_VOLTAGE 1 +#define UCD9000_MON_TEMPERATURE 2 +#define UCD9000_MON_CURRENT 3 +#define UCD9000_MON_VOLTAGE_HW 4 + +#define UCD9000_NUM_FAN 4 + +#define UCD9000_GPIO_NAME_LEN 16 +#define UCD9090_NUM_GPIOS 23 +#define UCD901XX_NUM_GPIOS 26 +#define UCD90320_NUM_GPIOS 84 +#define UCD90910_NUM_GPIOS 26 + +#define UCD9000_DEBUGFS_NAME_LEN 24 +#define UCD9000_GPI_COUNT 8 +#define UCD90320_GPI_COUNT 32 + +#define UCD9000_RETRY_SLEEP_TIME (10000) /* 10ms */ +#define UCD9000_RETRY_TIME (3) +#define WB_DEV_NAME_MAX_LEN (64) + +static int g_wb_ucd9000_debug = 0; +static int g_wb_ucd9000_error = 0; + +module_param(g_wb_ucd9000_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_ucd9000_error, int, S_IRUGO | S_IWUSR); + +#define WB_UDC9000_VERBOSE(fmt, args...) do { \ + if (g_wb_ucd9000_debug) { \ + printk(KERN_INFO "[WB_UCD9000][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_UDC9000_ERROR(fmt, args...) do { \ + if (g_wb_ucd9000_error) { \ + printk(KERN_ERR "[WB_UCD9000][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +struct ucd9000_data { + u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX]; + struct pmbus_driver_info info; +#ifdef CONFIG_GPIOLIB + struct gpio_chip gpio; +#endif + struct dentry *debugfs; +}; +#define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info) + +struct ucd9000_debugfs_entry { + struct i2c_client *client; + u8 index; +}; + +static int wb_i2c_smbus_read_block_data(const struct i2c_client *client, u8 command, u8 *values) +{ + int rv, i; + + for(i = 0; i < UCD9000_RETRY_TIME; i++) { + rv = i2c_smbus_read_block_data(client, command, values); + if(rv >= 0){ + return rv; + } + usleep_range(UCD9000_RETRY_SLEEP_TIME, UCD9000_RETRY_SLEEP_TIME + 1); + } + WB_UDC9000_ERROR("read_block_data failed. nr:%d, addr:0x%x, reg:0x%x, rv:%d.", + client->adapter->nr, client->addr, command, rv); + return rv; +} + +static int ucd9000_get_fan_config(struct i2c_client *client, int fan) +{ + int fan_config = 0; + struct ucd9000_data *data + = to_ucd9000_data(wb_pmbus_get_driver_info(client)); + + if (data->fan_data[fan][3] & 1) + fan_config |= PB_FAN_2_INSTALLED; /* Use lower bit position */ + + /* Pulses/revolution */ + fan_config |= (data->fan_data[fan][3] & 0x06) >> 1; + + return fan_config; +} + +static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg) +{ + int ret = 0; + int fan_config; + + switch (reg) { + case PMBUS_FAN_CONFIG_12: + if (page > 0) + return -ENXIO; + + ret = ucd9000_get_fan_config(client, 0); + if (ret < 0) + return ret; + fan_config = ret << 4; + ret = ucd9000_get_fan_config(client, 1); + if (ret < 0) + return ret; + fan_config |= ret; + ret = fan_config; + break; + case PMBUS_FAN_CONFIG_34: + if (page > 0) + return -ENXIO; + + ret = ucd9000_get_fan_config(client, 2); + if (ret < 0) + return ret; + fan_config = ret << 4; + ret = ucd9000_get_fan_config(client, 3); + if (ret < 0) + return ret; + fan_config |= ret; + ret = fan_config; + break; + default: + ret = -ENODATA; + break; + } + return ret; +} + +static const struct i2c_device_id ucd9000_id[] = { + {"wb_ucd9000", ucd9000}, + {"wb_ucd90120", ucd90120}, + {"wb_ucd90124", ucd90124}, + {"wb_ucd90160", ucd90160}, + {"wb_ucd90320", ucd90320}, + {"wb_ucd9090", ucd9090}, + {"wb_ucd90910", ucd90910}, + {} +}; +MODULE_DEVICE_TABLE(i2c, ucd9000_id); + +static const struct of_device_id __maybe_unused ucd9000_of_match[] = { + { + .compatible = "ti,wb_ucd9000", + .data = (void *)ucd9000 + }, + { + .compatible = "ti,wb_ucd90120", + .data = (void *)ucd90120 + }, + { + .compatible = "ti,wb_ucd90124", + .data = (void *)ucd90124 + }, + { + .compatible = "ti,wb_ucd90160", + .data = (void *)ucd90160 + }, + { + .compatible = "ti,wb_ucd90320", + .data = (void *)ucd90320 + }, + { + .compatible = "ti,wb_ucd9090", + .data = (void *)ucd9090 + }, + { + .compatible = "ti,wb_ucd90910", + .data = (void *)ucd90910 + }, + { }, +}; +MODULE_DEVICE_TABLE(of, ucd9000_of_match); + +#ifdef CONFIG_GPIOLIB +static int ucd9000_gpio_read_config(struct i2c_client *client, + unsigned int offset) +{ + int ret; + + /* No page set required */ + ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_SELECT, offset); + if (ret < 0) + return ret; + + return i2c_smbus_read_byte_data(client, UCD9000_GPIO_CONFIG); +} + +static int ucd9000_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct i2c_client *client = gpiochip_get_data(gc); + int ret; + + ret = ucd9000_gpio_read_config(client, offset); + if (ret < 0) + return ret; + + return !!(ret & UCD9000_GPIO_CONFIG_STATUS); +} + +static void ucd9000_gpio_set(struct gpio_chip *gc, unsigned int offset, + int value) +{ + struct i2c_client *client = gpiochip_get_data(gc); + int ret; + + ret = ucd9000_gpio_read_config(client, offset); + if (ret < 0) { + dev_dbg(&client->dev, "failed to read GPIO %d config: %d\n", + offset, ret); + return; + } + + if (value) { + if (ret & UCD9000_GPIO_CONFIG_STATUS) + return; + + ret |= UCD9000_GPIO_CONFIG_STATUS; + } else { + if (!(ret & UCD9000_GPIO_CONFIG_STATUS)) + return; + + ret &= ~UCD9000_GPIO_CONFIG_STATUS; + } + + ret |= UCD9000_GPIO_CONFIG_ENABLE; + + /* Page set not required */ + ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, ret); + if (ret < 0) { + dev_dbg(&client->dev, "Failed to write GPIO %d config: %d\n", + offset, ret); + return; + } + + ret &= ~UCD9000_GPIO_CONFIG_ENABLE; + + ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, ret); + if (ret < 0) + dev_dbg(&client->dev, "Failed to write GPIO %d config: %d\n", + offset, ret); +} + +static int ucd9000_gpio_get_direction(struct gpio_chip *gc, + unsigned int offset) +{ + struct i2c_client *client = gpiochip_get_data(gc); + int ret; + + ret = ucd9000_gpio_read_config(client, offset); + if (ret < 0) + return ret; + + return !(ret & UCD9000_GPIO_CONFIG_OUT_ENABLE); +} + +static int ucd9000_gpio_set_direction(struct gpio_chip *gc, + unsigned int offset, bool direction_out, + int requested_out) +{ + struct i2c_client *client = gpiochip_get_data(gc); + int ret, config, out_val; + + ret = ucd9000_gpio_read_config(client, offset); + if (ret < 0) + return ret; + + if (direction_out) { + out_val = requested_out ? UCD9000_GPIO_CONFIG_OUT_VALUE : 0; + + if (ret & UCD9000_GPIO_CONFIG_OUT_ENABLE) { + if ((ret & UCD9000_GPIO_CONFIG_OUT_VALUE) == out_val) + return 0; + } else { + ret |= UCD9000_GPIO_CONFIG_OUT_ENABLE; + } + + if (out_val) + ret |= UCD9000_GPIO_CONFIG_OUT_VALUE; + else + ret &= ~UCD9000_GPIO_CONFIG_OUT_VALUE; + + } else { + if (!(ret & UCD9000_GPIO_CONFIG_OUT_ENABLE)) + return 0; + + ret &= ~UCD9000_GPIO_CONFIG_OUT_ENABLE; + } + + ret |= UCD9000_GPIO_CONFIG_ENABLE; + config = ret; + + /* Page set not required */ + ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, config); + if (ret < 0) + return ret; + + config &= ~UCD9000_GPIO_CONFIG_ENABLE; + + return i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, config); +} + +static int ucd9000_gpio_direction_input(struct gpio_chip *gc, + unsigned int offset) +{ + return ucd9000_gpio_set_direction(gc, offset, UCD9000_GPIO_INPUT, 0); +} + +static int ucd9000_gpio_direction_output(struct gpio_chip *gc, + unsigned int offset, int val) +{ + return ucd9000_gpio_set_direction(gc, offset, UCD9000_GPIO_OUTPUT, + val); +} + +static void ucd9000_probe_gpio(struct i2c_client *client, + const struct i2c_device_id *mid, + struct ucd9000_data *data) +{ + int rc; + + switch (mid->driver_data) { + case ucd9090: + data->gpio.ngpio = UCD9090_NUM_GPIOS; + break; + case ucd90120: + case ucd90124: + case ucd90160: + data->gpio.ngpio = UCD901XX_NUM_GPIOS; + break; + case ucd90320: + data->gpio.ngpio = UCD90320_NUM_GPIOS; + break; + case ucd90910: + data->gpio.ngpio = UCD90910_NUM_GPIOS; + break; + default: + return; /* GPIO support is optional. */ + } + + /* + * Pinmux support has not been added to the new gpio_chip. + * This support should be added when possible given the mux + * behavior of these IO devices. + */ + data->gpio.label = client->name; + data->gpio.get_direction = ucd9000_gpio_get_direction; + data->gpio.direction_input = ucd9000_gpio_direction_input; + data->gpio.direction_output = ucd9000_gpio_direction_output; + data->gpio.get = ucd9000_gpio_get; + data->gpio.set = ucd9000_gpio_set; + data->gpio.can_sleep = true; + data->gpio.base = -1; + data->gpio.parent = &client->dev; + + rc = devm_gpiochip_add_data(&client->dev, &data->gpio, client); + if (rc) + dev_warn(&client->dev, "Could not add gpiochip: %d\n", rc); +} +#else +static void ucd9000_probe_gpio(struct i2c_client *client, + const struct i2c_device_id *mid, + struct ucd9000_data *data) +{ +} +#endif /* CONFIG_GPIOLIB */ + +#ifdef CONFIG_DEBUG_FS +static int ucd9000_get_mfr_status(struct i2c_client *client, u8 *buffer) +{ + int ret = wb_pmbus_set_page(client, 0, 0xff); + + if (ret < 0) + return ret; + + return wb_i2c_smbus_read_block_data(client, UCD9000_MFR_STATUS, buffer); +} + +static int ucd9000_debugfs_show_mfr_status_bit(void *data, u64 *val) +{ + struct ucd9000_debugfs_entry *entry = data; + struct i2c_client *client = entry->client; + u8 buffer[I2C_SMBUS_BLOCK_MAX]; + int ret, i; + + ret = ucd9000_get_mfr_status(client, buffer); + if (ret < 0) + return ret; + + /* + * GPI fault bits are in sets of 8, two bytes from end of response. + */ + i = ret - 3 - entry->index / 8; + if (i >= 0) + *val = !!(buffer[i] & BIT(entry->index % 8)); + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(ucd9000_debugfs_mfr_status_bit, + ucd9000_debugfs_show_mfr_status_bit, NULL, "%1lld\n"); + +static ssize_t ucd9000_debugfs_read_mfr_status(struct file *file, + char __user *buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *client = file->private_data; + u8 buffer[I2C_SMBUS_BLOCK_MAX]; + char str[(I2C_SMBUS_BLOCK_MAX * 2) + 2]; + char *res; + int rc; + + rc = ucd9000_get_mfr_status(client, buffer); + if (rc < 0) + return rc; + + res = bin2hex(str, buffer, min(rc, I2C_SMBUS_BLOCK_MAX)); + *res++ = '\n'; + *res = 0; + + return simple_read_from_buffer(buf, count, ppos, str, res - str); +} + +static const struct file_operations ucd9000_debugfs_show_mfr_status_fops = { + .llseek = noop_llseek, + .read = ucd9000_debugfs_read_mfr_status, + .open = simple_open, +}; + +static int ucd9000_init_debugfs(struct i2c_client *client, + const struct i2c_device_id *mid, + struct ucd9000_data *data) +{ + struct dentry *debugfs; + struct ucd9000_debugfs_entry *entries; + int i, gpi_count; + char name[UCD9000_DEBUGFS_NAME_LEN]; + + debugfs = wb_pmbus_get_debugfs_dir(client); + if (!debugfs) + return -ENOENT; + + data->debugfs = debugfs_create_dir(client->name, debugfs); + if (!data->debugfs) + return -ENOENT; + + /* + * Of the chips this driver supports, only the UCD9090, UCD90160, + * UCD90320, and UCD90910 report GPI faults in their MFR_STATUS + * register, so only create the GPI fault debugfs attributes for those + * chips. + */ + if (mid->driver_data == ucd9090 || mid->driver_data == ucd90160 || + mid->driver_data == ucd90320 || mid->driver_data == ucd90910) { + gpi_count = mid->driver_data == ucd90320 ? UCD90320_GPI_COUNT + : UCD9000_GPI_COUNT; + entries = devm_kcalloc(&client->dev, + gpi_count, sizeof(*entries), + GFP_KERNEL); + if (!entries) + return -ENOMEM; + + for (i = 0; i < gpi_count; i++) { + entries[i].client = client; + entries[i].index = i; + scnprintf(name, UCD9000_DEBUGFS_NAME_LEN, + "gpi%d_alarm", i + 1); + debugfs_create_file(name, 0444, data->debugfs, + &entries[i], + &ucd9000_debugfs_mfr_status_bit); + } + } + + scnprintf(name, UCD9000_DEBUGFS_NAME_LEN, "mfr_status"); + debugfs_create_file(name, 0444, data->debugfs, client, + &ucd9000_debugfs_show_mfr_status_fops); + + return 0; +} +#else +static int ucd9000_init_debugfs(struct i2c_client *client, + const struct i2c_device_id *mid, + struct ucd9000_data *data) +{ + return 0; +} +#endif /* CONFIG_DEBUG_FS */ + +static int ucd9000_probe(struct i2c_client *client) +{ + u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; + char wb_device_name[WB_DEV_NAME_MAX_LEN]; + struct ucd9000_data *data; + struct pmbus_driver_info *info; + const struct i2c_device_id *mid; + enum chips chip; + int i, ret; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA)) + return -ENODEV; + + ret = wb_i2c_smbus_read_block_data(client, UCD9000_DEVICE_ID, + block_buffer); + if (ret < 0) { + dev_err(&client->dev, "Failed to read device ID\n"); + return ret; + } + block_buffer[ret] = '\0'; + dev_info(&client->dev, "Device ID %s\n", block_buffer); + + mem_clear(wb_device_name, sizeof(wb_device_name)); + snprintf(wb_device_name, sizeof(wb_device_name), "wb_%s", block_buffer); + + for (mid = ucd9000_id; mid->name[0]; mid++) { + if (!strncasecmp(mid->name, wb_device_name, strlen(mid->name))) + break; + } + if (!mid->name[0]) { + dev_err(&client->dev, "Unsupported device\n"); + return -ENODEV; + } + + if (client->dev.of_node) + chip = (enum chips)of_device_get_match_data(&client->dev); + else + chip = mid->driver_data; + + if (chip != ucd9000 && strcmp(client->name, mid->name) != 0) + dev_notice(&client->dev, + "Device mismatch: Configured %s, detected %s\n", + client->name, mid->name); + + data = devm_kzalloc(&client->dev, sizeof(struct ucd9000_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + info = &data->info; + + ret = i2c_smbus_read_byte_data(client, UCD9000_NUM_PAGES); + if (ret < 0) { + dev_err(&client->dev, + "Failed to read number of active pages\n"); + return ret; + } + info->pages = ret; + if (!info->pages) { + dev_err(&client->dev, "No pages configured\n"); + return -ENODEV; + } + + /* The internal temperature sensor is always active */ + /* ucd90160 have no temperature */ + /* info->func[0] = PMBUS_HAVE_TEMP; */ + + /* Everything else is configurable */ + ret = wb_i2c_smbus_read_block_data(client, UCD9000_MONITOR_CONFIG, + block_buffer); + if (ret <= 0) { + dev_err(&client->dev, "Failed to read configuration data\n"); + return -ENODEV; + } + for (i = 0; i < ret; i++) { + int page = UCD9000_MON_PAGE(block_buffer[i]); + + if (page >= info->pages) + continue; + + switch (UCD9000_MON_TYPE(block_buffer[i])) { + case UCD9000_MON_VOLTAGE: + case UCD9000_MON_VOLTAGE_HW: + info->func[page] |= PMBUS_HAVE_VOUT + | PMBUS_HAVE_STATUS_VOUT; + break; + case UCD9000_MON_TEMPERATURE: + info->func[page] |= PMBUS_HAVE_TEMP2 + | PMBUS_HAVE_STATUS_TEMP; + break; + case UCD9000_MON_CURRENT: + info->func[page] |= PMBUS_HAVE_IOUT + | PMBUS_HAVE_STATUS_IOUT; + break; + default: + break; + } + } + + /* Fan configuration */ + if (mid->driver_data == ucd90124) { + for (i = 0; i < UCD9000_NUM_FAN; i++) { + i2c_smbus_write_byte_data(client, + UCD9000_FAN_CONFIG_INDEX, i); + ret = wb_i2c_smbus_read_block_data(client, + UCD9000_FAN_CONFIG, + data->fan_data[i]); + if (ret < 0) + return ret; + } + i2c_smbus_write_byte_data(client, UCD9000_FAN_CONFIG_INDEX, 0); + + info->read_byte_data = ucd9000_read_byte_data; + info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 + | PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34; + } + + ucd9000_probe_gpio(client, mid, data); + + ret = wb_pmbus_do_probe(client, info); + if (ret) + return ret; + + ret = ucd9000_init_debugfs(client, mid, data); + if (ret) + dev_warn(&client->dev, "Failed to register debugfs: %d\n", + ret); + + return 0; +} + +/* This is the driver that will be inserted */ +static struct i2c_driver ucd9000_driver = { + .driver = { + .name = "wb_ucd9000", + .of_match_table = of_match_ptr(ucd9000_of_match), + }, + .probe_new = ucd9000_probe, + .remove = wb_pmbus_do_remove, + .id_table = ucd9000_id, +}; + +module_i2c_driver(ucd9000_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe12284.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe12284.c new file mode 100644 index 000000000000..404c349f51f0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe12284.c @@ -0,0 +1,495 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for Infineon Multi-phase Digital VR Controllers + * + * Copyright (c) 2020 Mellanox Technologies. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "wb_pmbus.h" + +#define XDPE122_PROT_VR12_5MV (0x01) /* VR12.0 mode, 5-mV DAC */ +#define XDPE122_PROT_VR12_5_10MV (0x02) /* VR12.5 mode, 10-mV DAC */ +#define XDPE122_PROT_IMVP9_10MV (0x03) /* IMVP9 mode, 10-mV DAC */ +#define XDPE122_AMD_625MV (0x10) /* AMD mode 6.25mV */ +#define XDPE122_PAGE_NUM (2) +#define XDPE122_WRITE_PROTECT_CLOSE (0x00) +#define XDPE122_WRITE_PROTECT_OPEN (0x40) + +static int g_wb_xdpe122_debug = 0; +static int g_wb_xdpe122_error = 0; + +module_param(g_wb_xdpe122_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_xdpe122_error, int, S_IRUGO | S_IWUSR); + +#define WB_XDPE122_VERBOSE(fmt, args...) do { \ + if (g_wb_xdpe122_debug) { \ + printk(KERN_INFO "[WB_XDPE122][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_XDPE122_ERROR(fmt, args...) do { \ + if (g_wb_xdpe122_error) { \ + printk(KERN_ERR "[WB_XDPE122][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static int xdpe122_data2reg_vid(struct pmbus_data *data, int page, long val) +{ + int vrm_version; + + vrm_version = data->info->vrm_version[page]; + WB_XDPE122_VERBOSE("page%d, vrm_version: %d, data_val: %ld\n", + page, vrm_version, val); + /* Convert data to VID register. */ + switch (vrm_version) { + case vr13: + if (val >= 500) { + return 1 + DIV_ROUND_CLOSEST(val - 500, 10); + } + return 0; + case vr12: + if (val >= 250) { + return 1 + DIV_ROUND_CLOSEST(val - 250, 5); + } + return 0; + case imvp9: + if (val >= 200) { + return 1 + DIV_ROUND_CLOSEST(val - 200, 10); + } + return 0; + case amd625mv: + if (val >= 200 && val <= 1550) { + return DIV_ROUND_CLOSEST((1550 - val) * 100, 625); + } + return 0; + default: + WB_XDPE122_ERROR("Unsupport vrm_version, page%d, vrm_version: %d\n", + page, vrm_version); + return -EINVAL; + } + return 0; +} + + +/* + * Convert VID sensor values to milli- or micro-units + * depending on sensor type. + */ +static s64 xdpe122_reg2data_vid(struct pmbus_data *data, int page, long val) +{ + + long rv; + int vrm_version; + + rv = 0; + vrm_version = data->info->vrm_version[page]; + switch (vrm_version) { + case vr11: + if (val >= 0x02 && val <= 0xb2) + rv = DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); + break; + case vr12: + if (val >= 0x01) + rv = 250 + (val - 1) * 5; + break; + case vr13: + if (val >= 0x01) + rv = 500 + (val - 1) * 10; + break; + case imvp9: + if (val >= 0x01) + rv = 200 + (val - 1) * 10; + break; + case amd625mv: + if (val >= 0x0 && val <= 0xd8) + rv = DIV_ROUND_CLOSEST(155000 - val * 625, 100); + break; + } + WB_XDPE122_VERBOSE("page%d, vrm_version: %d, reg_val: 0x%lx, data_val: %ld\n", + page, vrm_version, val, rv); + return rv; +} + +static ssize_t xdpe122_avs_vout_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int vout_cmd, vout; + + mutex_lock(&data->update_lock); + vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); + if (vout_cmd < 0) { + WB_XDPE122_ERROR("%d-%04x: read page%d, vout command reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd); + mutex_unlock(&data->update_lock); + return vout_cmd; + } + + vout = xdpe122_reg2data_vid(data, attr->index, vout_cmd); + vout = vout * 1000; + WB_XDPE122_VERBOSE("%d-%04x: page%d, vout command reg_val: 0x%x, vout: %d uV\n", + client->adapter->nr, client->addr, attr->index, vout_cmd, vout); + + mutex_unlock(&data->update_lock); + return snprintf(buf, PAGE_SIZE, "%d\n", vout); +} + +static ssize_t xdpe122_avs_vout_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int vout, vout_max, vout_min, vout_mv; + int ret, vout_cmd, vout_cmd_set; + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + ret = kstrtoint(buf, 0, &vout); + if (ret) { + WB_XDPE122_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + vout_max = data->vout_max[attr->index]; + vout_min = data->vout_min[attr->index]; + if ((vout > vout_max) || (vout < vout_min)) { + WB_XDPE122_ERROR("%d-%04x: vout value: %d, out of range [%d, %d] \n", client->adapter->nr, + client->addr, vout, vout_min, vout_max); + return -EINVAL; + } + + /* calc VOUT_COMMAND set value Unit must be mV*/ + vout_mv = vout / 1000; + vout_cmd_set = xdpe122_data2reg_vid(data, attr->index, vout_mv); + if ((vout_cmd_set < 0) || (vout_cmd_set > 0xffff)) { + WB_XDPE122_ERROR("%d-%04x: invalid value, vout %d uV, vout_cmd_set: %d\n", + client->adapter->nr, client->addr, vout, vout_cmd_set); + return -EINVAL; + } + + mutex_lock(&data->update_lock); + + /* close write protect */ + ret = wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, XDPE122_WRITE_PROTECT_CLOSE); + if (ret < 0) { + WB_XDPE122_ERROR("%d-%04x: close page%d write protect failed, ret: %d\n", client->adapter->nr, + client->addr, attr->index, ret); + mutex_unlock(&data->update_lock); + return ret; + } + + /* set VOUT_COMMAND */ + ret = wb_pmbus_write_word_data(client, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set); + if (ret < 0) { + WB_XDPE122_ERROR("%d-%04x: set page%d vout cmd reg: 0x%x, value: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set, ret); + goto error; + } + + /* read back VOUT_COMMAND */ + vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); + if (vout_cmd < 0) { + ret = vout_cmd; + WB_XDPE122_ERROR("%d-%04x: read page%d vout command reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, ret); + goto error; + } + + /* compare vout_cmd and vout_cmd_set */ + if (vout_cmd != vout_cmd_set) { + ret = -EIO; + WB_XDPE122_ERROR("%d-%04x: vout cmd value check error, vout cmd read: 0x%x, vout cmd set: 0x%x\n", + client->adapter->nr, client->addr, vout_cmd, vout_cmd_set); + goto error; + } + + /* open write protect */ + wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, XDPE122_WRITE_PROTECT_OPEN); + mutex_unlock(&data->update_lock); + WB_XDPE122_VERBOSE("%d-%04x: set page%d vout cmd success, vout %d uV, vout_cmd_set: 0x%x\n", + client->adapter->nr, client->addr, attr->index, vout, vout_cmd_set); + return count; +error: + wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, XDPE122_WRITE_PROTECT_OPEN); + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t xdpe122_avs_vout_max_store(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int ret, vout_threshold; + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + ret = kstrtoint(buf, 0, &vout_threshold); + if (ret) { + WB_XDPE122_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + WB_XDPE122_VERBOSE("%d-%04x: vout%d max threshold: %d", client->adapter->nr, client->addr, + attr->index, vout_threshold); + + data->vout_max[attr->index] = vout_threshold; + return count; +} + +static ssize_t xdpe122_avs_vout_max_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_max[attr->index]); +} + +static ssize_t xdpe122_avs_vout_min_store(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int ret, vout_threshold; + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + ret = kstrtoint(buf, 0, &vout_threshold); + if (ret) { + WB_XDPE122_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + WB_XDPE122_VERBOSE("%d-%04x: vout%d min threshold: %d", client->adapter->nr, client->addr, + attr->index, vout_threshold); + + data->vout_min[attr->index] = vout_threshold; + return count; +} + +static ssize_t xdpe122_avs_vout_min_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_min[attr->index]); +} + +static SENSOR_DEVICE_ATTR_RW(avs0_vout, xdpe122_avs_vout, 0); +static SENSOR_DEVICE_ATTR_RW(avs1_vout, xdpe122_avs_vout, 1); +static SENSOR_DEVICE_ATTR_RW(avs0_vout_max, xdpe122_avs_vout_max, 0); +static SENSOR_DEVICE_ATTR_RW(avs0_vout_min, xdpe122_avs_vout_min, 0); +static SENSOR_DEVICE_ATTR_RW(avs1_vout_max, xdpe122_avs_vout_max, 1); +static SENSOR_DEVICE_ATTR_RW(avs1_vout_min, xdpe122_avs_vout_min, 1); + +static struct attribute *avs_ctrl_attrs[] = { + &sensor_dev_attr_avs0_vout.dev_attr.attr, + &sensor_dev_attr_avs1_vout.dev_attr.attr, + &sensor_dev_attr_avs0_vout_max.dev_attr.attr, + &sensor_dev_attr_avs0_vout_min.dev_attr.attr, + &sensor_dev_attr_avs1_vout_max.dev_attr.attr, + &sensor_dev_attr_avs1_vout_min.dev_attr.attr, + NULL, +}; + +static const struct attribute_group avs_ctrl_group = { + .attrs = avs_ctrl_attrs, +}; + +static const struct attribute_group *xdpe122_attribute_groups[] = { + &avs_ctrl_group, + NULL, +}; + +static int xdpe122_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + const struct pmbus_driver_info *info = wb_pmbus_get_driver_info(client); + long val; + s16 exponent; + s32 mantissa; + int ret; + + switch (reg) { + case PMBUS_VOUT_OV_FAULT_LIMIT: + case PMBUS_VOUT_UV_FAULT_LIMIT: + ret = wb_pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + + /* Convert register value to LINEAR11 data. */ + exponent = ((s16)ret) >> 11; + mantissa = ((s16)((ret & GENMASK(10, 0)) << 5)) >> 5; + val = mantissa * 1000L; + if (exponent >= 0) + val <<= exponent; + else + val >>= -exponent; + + /* Convert data to VID register. */ + switch (info->vrm_version[page]) { + case vr13: + if (val >= 500) + return 1 + DIV_ROUND_CLOSEST(val - 500, 10); + return 0; + case vr12: + if (val >= 250) + return 1 + DIV_ROUND_CLOSEST(val - 250, 5); + return 0; + case imvp9: + if (val >= 200) + return 1 + DIV_ROUND_CLOSEST(val - 200, 10); + return 0; + case amd625mv: + if (val >= 200 && val <= 1550) + return DIV_ROUND_CLOSEST((1550 - val) * 100, + 625); + return 0; + default: + return -EINVAL; + } + default: + return -ENODATA; + } + + return 0; +} + +static int xdpe122_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + u8 vout_params; + int i, ret; + + for (i = 0; i < XDPE122_PAGE_NUM; i++) { + /* Read the register with VOUT scaling value.*/ + ret = wb_pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); + if (ret < 0) + return ret; + + vout_params = ret & GENMASK(4, 0); + + switch (vout_params) { + case XDPE122_PROT_VR12_5_10MV: + info->vrm_version[i] = vr13; + break; + case XDPE122_PROT_VR12_5MV: + info->vrm_version[i] = vr12; + break; + case XDPE122_PROT_IMVP9_10MV: + info->vrm_version[i] = imvp9; + break; + case XDPE122_AMD_625MV: + info->vrm_version[i] = amd625mv; + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static struct pmbus_driver_info xdpe122_info = { + .pages = XDPE122_PAGE_NUM, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = vid, + .format[PSC_TEMPERATURE] = linear, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT, + .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT, + .groups = xdpe122_attribute_groups, + .identify = xdpe122_identify, + .read_word_data = xdpe122_read_word_data, +}; + +static int xdpe122_probe(struct i2c_client *client) +{ + struct pmbus_driver_info *info; + + info = devm_kmemdup(&client->dev, &xdpe122_info, sizeof(*info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + return wb_pmbus_do_probe(client, info); +} + +static const struct i2c_device_id xdpe122_id[] = { + {"wb_xdpe12254", 0}, + {"wb_xdpe12284", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, xdpe122_id); + +static const struct of_device_id __maybe_unused xdpe122_of_match[] = { + {.compatible = "infineon,wb_xdpe12254"}, + {.compatible = "infineon,wb_xdpe12284"}, + {} +}; +MODULE_DEVICE_TABLE(of, xdpe122_of_match); + +static struct i2c_driver xdpe122_driver = { + .driver = { + .name = "wb_xdpe12284", + .of_match_table = of_match_ptr(xdpe122_of_match), + }, + .probe_new = xdpe122_probe, + .remove = wb_pmbus_do_remove, + .id_table = xdpe122_id, +}; + +module_i2c_driver(xdpe122_driver); + +MODULE_AUTHOR("Vadim Pasternak "); +MODULE_DESCRIPTION("PMBus driver for Infineon XDPE122 family"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe132g5c_pmbus.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe132g5c_pmbus.c new file mode 100644 index 000000000000..c0c3d2bc79f9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe132g5c_pmbus.c @@ -0,0 +1,277 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wb_pmbus.h" + +typedef enum { + DBG_START, + DBG_VERBOSE, + DBG_KEY, + DBG_WARN, + DBG_ERROR, + DBG_END, +} dbg_level_t; + +static int debuglevel = 0; +module_param(debuglevel, int, S_IRUGO); + +#define DBG_DEBUG(fmt, arg...) do { \ + if ( debuglevel > DBG_START && debuglevel < DBG_ERROR) { \ + printk(KERN_INFO "[DEBUG]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ + } else if ( debuglevel >= DBG_ERROR ) { \ + printk(KERN_ERR "[DEBUG]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ + } else { } \ +} while (0) + +#define DBG_ERROR(fmt, arg...) do { \ + if ( debuglevel > DBG_START) { \ + printk(KERN_ERR "[ERROR]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ + } \ +} while (0) + +#define BUF_SIZE (256) +#define XDPE132G5C_PAGE_NUM (2) +#define XDPE132G5C_PROT_VR12_5MV (0x01) /* VR12.0 mode, 5-mV DAC */ +#define XDPE132G5C_PROT_VR12_5_10MV (0x02) /* VR12.5 mode, 10-mV DAC */ +#define XDPE132G5C_PROT_IMVP9_10MV (0x03) /* IMVP9 mode, 10-mV DAC */ +#define XDPE132G5C_PROT_VR13_10MV (0x04) /* VR13.0 mode, 10-mV DAC */ +#define XDPE132G5C_PROT_IMVP8_5MV (0x05) /* IMVP8 mode, 5-mV DAC */ +#define XDPE132G5C_PROT_VR13_5MV (0x07) /* VR13.0 mode, 5-mV DAC */ +#define RETRY_TIME (15) + +static ssize_t set_xdpe132g5c_avs(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + int ret; + unsigned long val; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct pmbus_data *data; + + data = i2c_get_clientdata(client); + ret = kstrtoul(buf, 0, &val); + if (ret){ + return ret; + } + mutex_lock(&data->update_lock); + /* set value */ + ret = wb_pmbus_write_word_data(client, attr->index, PMBUS_VOUT_COMMAND, (u16)val); + if (ret < 0) { + DBG_ERROR("set pmbus_vout_command fail\n"); + goto finish_set; + } +finish_set: + wb_pmbus_clear_faults(client); + mutex_unlock(&data->update_lock); + return (ret < 0) ? ret : count; + +} + +static ssize_t show_xdpe132g5c_avs(struct device *dev, struct device_attribute *da, char *buf) +{ + int val; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct pmbus_data *data; + + data = i2c_get_clientdata(client); + mutex_lock(&data->update_lock); + val = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); + if (val < 0) { + DBG_ERROR("fail val = %d\n", val); + goto finish_show; + } +finish_show: + wb_pmbus_clear_faults(client); + mutex_unlock(&data->update_lock); + return snprintf(buf, BUF_SIZE, "0x%04x\n", val); +} + +static SENSOR_DEVICE_ATTR(avs0_vout_command, S_IRUGO | S_IWUSR, show_xdpe132g5c_avs, set_xdpe132g5c_avs, 0); +static SENSOR_DEVICE_ATTR(avs1_vout_command, S_IRUGO | S_IWUSR, show_xdpe132g5c_avs, set_xdpe132g5c_avs, 1); + +static struct attribute *xdpe132g5c_sysfs_attrs[] = { + &sensor_dev_attr_avs0_vout_command.dev_attr.attr, + &sensor_dev_attr_avs1_vout_command.dev_attr.attr, + NULL, +}; + +static const struct attribute_group xdpe132g5c_sysfs_attrs_group = { + .attrs = xdpe132g5c_sysfs_attrs, +}; + +static int xdpe132g5c_read_word_data(struct i2c_client *client, int page, int phase, int reg) +{ + int rv; + int retry; + int value; + + rv = wb_pmbus_set_page(client, page, 0xff); + if (rv < 0) { + return rv; + } + + retry = 3; + while (retry--) { + value = i2c_smbus_read_word_data(client, reg); + if ((value == 0xffff) || (value < 0)) { + continue; + } + } + return value; +} + +static int xdpe132g5c_identify(struct i2c_client *client, struct pmbus_driver_info *info) +{ + u8 vout_params; + int ret, i, retry; + + /* Read the register with VOUT scaling value.*/ + for (i = 0; i < XDPE132G5C_PAGE_NUM; i++) { + for (retry = 0; retry < RETRY_TIME; retry++) { + ret = wb_pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); + if (ret < 0 || ret == 0xff) { + msleep(5); + continue; + } else { + break; + } + } + if (ret < 0) { + return ret; + } + + switch (ret >> 5) { + case 0: /* linear mode */ + if (info->format[PSC_VOLTAGE_OUT] != linear) { + return -ENODEV; + } + break; + case 1: /* VID mode */ + if (info->format[PSC_VOLTAGE_OUT] != vid) { + return -ENODEV; + } + vout_params = ret & GENMASK(4, 0); + switch (vout_params) { + case XDPE132G5C_PROT_VR13_10MV: + case XDPE132G5C_PROT_VR12_5_10MV: + info->vrm_version[i] = vr13; + break; + case XDPE132G5C_PROT_VR13_5MV: + case XDPE132G5C_PROT_VR12_5MV: + case XDPE132G5C_PROT_IMVP8_5MV: + info->vrm_version[i] = vr12; + break; + case XDPE132G5C_PROT_IMVP9_10MV: + info->vrm_version[i] = imvp9; + break; + default: + return -EINVAL; + } + break; + case 2: /* direct mode */ + if (info->format[PSC_VOLTAGE_OUT] != direct) { + return -ENODEV; + } + break; + default: + return -ENODEV; + } + } + + return 0; +} + +static struct pmbus_driver_info xdpe132g5c_info = { + .pages = XDPE132G5C_PAGE_NUM, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = linear, + .format[PSC_TEMPERATURE] = linear, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN + | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP + | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, + .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN + | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, + .identify = xdpe132g5c_identify, + .read_word_data = xdpe132g5c_read_word_data, +}; + +static int xdpe132g5c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int status; + struct pmbus_driver_info *info; + + info = devm_kmemdup(&client->dev, &xdpe132g5c_info, sizeof(*info), GFP_KERNEL); + if (!info) { + return -ENOMEM; + } + + status = wb_pmbus_do_probe(client, &xdpe132g5c_info); + if (status != 0) { + DBG_ERROR("pmbus probe error %d\n", status); + return status; + } + + status = sysfs_create_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); + if (status != 0) { + DBG_ERROR("sysfs_create_group error %d\n", status); + return status; + } + + return status; +} + +static int xdpe132g5c_remove(struct i2c_client *client) +{ + int ret; + + sysfs_remove_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); + ret = wb_pmbus_do_remove(client); + if (ret != 0){ + DBG_ERROR("fail remove xdpe132g5c %d\n", ret); + } + return ret; +} + +static const struct i2c_device_id xdpe132g5c_id[] = { + {"wb_xdpe132g5c_pmbus", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, xdpe132g5c_id); + +static const struct of_device_id __maybe_unused xdpe132g5c_of_match[] = { + {.compatible = "infineon,wb_xdpe132g5c_pmbus"}, + {} +}; +MODULE_DEVICE_TABLE(of, xdpe132g5c_of_match); + +static struct i2c_driver xdpe132g5c_driver = { + .driver = { + .name = "wb_xdpe132g5c_pmbus", + .of_match_table = of_match_ptr(xdpe132g5c_of_match), + }, + .probe = xdpe132g5c_probe, + .remove = xdpe132g5c_remove, + .id_table = xdpe132g5c_id, +}; + +module_i2c_driver(xdpe132g5c_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("PMBus driver for Infineon XDPE132 family"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/Makefile new file mode 100644 index 000000000000..4d5f8d5358d9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/Makefile @@ -0,0 +1,23 @@ +PWD = $(shell pwd) + +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall + +ifndef CONFIG_MDIO_BITBANG +obj-m += mdio_bitbang.o +endif + +ifndef CONFIG_MDIO_GPIO +obj-m += mdio_gpio.o +endif + +obj-m += wb_mdio_gpio_device.o + +all: + $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules + @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi + cp -p $(PWD)/*.ko $(module_out_put_dir) +clean: + rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/*.mod + rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order + rm -rf $(PWD)/.tmp_versions diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_bitbang.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_bitbang.c new file mode 100644 index 000000000000..5136275c8e73 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_bitbang.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Bitbanged MDIO support. + * + * Author: Scott Wood + * Copyright (c) 2007 Freescale Semiconductor + * + * Based on CPM2 MDIO code which is: + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + */ + +#include +#include +#include +#include + +#define MDIO_READ 2 +#define MDIO_WRITE 1 + +#define MDIO_C45 (1<<15) +#define MDIO_C45_ADDR (MDIO_C45 | 0) +#define MDIO_C45_READ (MDIO_C45 | 3) +#define MDIO_C45_WRITE (MDIO_C45 | 1) + +#define MDIO_SETUP_TIME 10 +#define MDIO_HOLD_TIME 10 + +/* Minimum MDC period is 400 ns, plus some margin for error. MDIO_DELAY + * is done twice per period. + */ +#define MDIO_DELAY 250 + +/* The PHY may take up to 300 ns to produce data, plus some margin + * for error. + */ +#define MDIO_READ_DELAY 350 + +/* MDIO must already be configured as output. */ +static void mdiobb_send_bit(struct mdiobb_ctrl *ctrl, int val) +{ + const struct mdiobb_ops *ops = ctrl->ops; + + ops->set_mdio_data(ctrl, val); + ndelay(MDIO_DELAY); + ops->set_mdc(ctrl, 1); + ndelay(MDIO_DELAY); + ops->set_mdc(ctrl, 0); +} + +/* MDIO must already be configured as input. */ +static int mdiobb_get_bit(struct mdiobb_ctrl *ctrl) +{ + const struct mdiobb_ops *ops = ctrl->ops; + + ndelay(MDIO_DELAY); + ops->set_mdc(ctrl, 1); + ndelay(MDIO_READ_DELAY); + ops->set_mdc(ctrl, 0); + + return ops->get_mdio_data(ctrl); +} + +/* MDIO must already be configured as output. */ +static void mdiobb_send_num(struct mdiobb_ctrl *ctrl, u16 val, int bits) +{ + int i; + + for (i = bits - 1; i >= 0; i--) + mdiobb_send_bit(ctrl, (val >> i) & 1); +} + +/* MDIO must already be configured as input. */ +static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits) +{ + int i; + u16 ret = 0; + + for (i = bits - 1; i >= 0; i--) { + ret <<= 1; + ret |= mdiobb_get_bit(ctrl); + } + + return ret; +} + +/* Utility to send the preamble, address, and + * register (common to read and write). + */ +static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int op, u8 phy, u8 reg) +{ + const struct mdiobb_ops *ops = ctrl->ops; + int i; + + ops->set_mdio_dir(ctrl, 1); + + /* + * Send a 32 bit preamble ('1's) with an extra '1' bit for good + * measure. The IEEE spec says this is a PHY optional + * requirement. The AMD 79C874 requires one after power up and + * one after a MII communications error. This means that we are + * doing more preambles than we need, but it is safer and will be + * much more robust. + */ + + for (i = 0; i < 32; i++) + mdiobb_send_bit(ctrl, 1); + + /* send the start bit (01) and the read opcode (10) or write (01). + Clause 45 operation uses 00 for the start and 11, 10 for + read/write */ + mdiobb_send_bit(ctrl, 0); + if (op & MDIO_C45) + mdiobb_send_bit(ctrl, 0); + else + mdiobb_send_bit(ctrl, 1); + mdiobb_send_bit(ctrl, (op >> 1) & 1); + mdiobb_send_bit(ctrl, (op >> 0) & 1); + + mdiobb_send_num(ctrl, phy, 5); + mdiobb_send_num(ctrl, reg, 5); +} + +/* In clause 45 mode all commands are prefixed by MDIO_ADDR to specify the + lower 16 bits of the 21 bit address. This transfer is done identically to a + MDIO_WRITE except for a different code. To enable clause 45 mode or + MII_ADDR_C45 into the address. Theoretically clause 45 and normal devices + can exist on the same bus. Normal devices should ignore the MDIO_ADDR + phase. */ +static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr) +{ + unsigned int dev_addr = (addr >> 16) & 0x1F; + unsigned int reg = addr & 0xFFFF; + mdiobb_cmd(ctrl, MDIO_C45_ADDR, phy, dev_addr); + + /* send the turnaround (10) */ + mdiobb_send_bit(ctrl, 1); + mdiobb_send_bit(ctrl, 0); + + mdiobb_send_num(ctrl, reg, 16); + + ctrl->ops->set_mdio_dir(ctrl, 0); + mdiobb_get_bit(ctrl); + + return dev_addr; +} + +static int mdiobb_read(struct mii_bus *bus, int phy, int reg) +{ + struct mdiobb_ctrl *ctrl = bus->priv; + int ret, i; + + if (reg & MII_ADDR_C45) { + reg = mdiobb_cmd_addr(ctrl, phy, reg); + mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg); + } else + mdiobb_cmd(ctrl, MDIO_READ, phy, reg); + + ctrl->ops->set_mdio_dir(ctrl, 0); + + /* check the turnaround bit: the PHY should be driving it to zero, if this + * PHY is listed in phy_ignore_ta_mask as having broken TA, skip that + */ + if (mdiobb_get_bit(ctrl) != 0 && + !(bus->phy_ignore_ta_mask & (1 << phy))) { + /* PHY didn't drive TA low -- flush any bits it + * may be trying to send. + */ + for (i = 0; i < 32; i++) + mdiobb_get_bit(ctrl); + + return 0xffff; + } + + ret = mdiobb_get_num(ctrl, 16); + mdiobb_get_bit(ctrl); + return ret; +} + +static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val) +{ + struct mdiobb_ctrl *ctrl = bus->priv; + + if (reg & MII_ADDR_C45) { + reg = mdiobb_cmd_addr(ctrl, phy, reg); + mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg); + } else + mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg); + + /* send the turnaround (10) */ + mdiobb_send_bit(ctrl, 1); + mdiobb_send_bit(ctrl, 0); + + mdiobb_send_num(ctrl, val, 16); + + ctrl->ops->set_mdio_dir(ctrl, 0); + mdiobb_get_bit(ctrl); + return 0; +} + +struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) +{ + struct mii_bus *bus; + + bus = mdiobus_alloc(); + if (!bus) + return NULL; + + __module_get(ctrl->ops->owner); + + bus->read = mdiobb_read; + bus->write = mdiobb_write; + bus->priv = ctrl; + + return bus; +} +EXPORT_SYMBOL(alloc_mdio_bitbang); + +void free_mdio_bitbang(struct mii_bus *bus) +{ + struct mdiobb_ctrl *ctrl = bus->priv; + + module_put(ctrl->ops->owner); + mdiobus_free(bus); +} +EXPORT_SYMBOL(free_mdio_bitbang); + +MODULE_LICENSE("GPL v2"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_gpio.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_gpio.c new file mode 100644 index 000000000000..1b00235d7dc5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_gpio.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * GPIO based MDIO bitbang driver. + * Supports OpenFirmware. + * + * Copyright (c) 2008 CSE Semaphore Belgium. + * by Laurent Pinchart + * + * Copyright (C) 2008, Paulius Zaleckas + * + * Based on earlier work by + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct mdio_gpio_info { + struct mdiobb_ctrl ctrl; + struct gpio_desc *mdc, *mdio, *mdo; +}; + +static int mdio_gpio_get_data(struct device *dev, + struct mdio_gpio_info *bitbang) +{ + bitbang->mdc = devm_gpiod_get_index(dev, NULL, MDIO_GPIO_MDC, + GPIOD_OUT_LOW); + if (IS_ERR(bitbang->mdc)) + return PTR_ERR(bitbang->mdc); + + bitbang->mdio = devm_gpiod_get_index(dev, NULL, MDIO_GPIO_MDIO, + GPIOD_IN); + if (IS_ERR(bitbang->mdio)) + return PTR_ERR(bitbang->mdio); + + bitbang->mdo = devm_gpiod_get_index_optional(dev, NULL, MDIO_GPIO_MDO, + GPIOD_OUT_LOW); + return PTR_ERR_OR_ZERO(bitbang->mdo); +} + +static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + if (bitbang->mdo) { + /* Separate output pin. Always set its value to high + * when changing direction. If direction is input, + * assume the pin serves as pull-up. If direction is + * output, the default value is high. + */ + gpiod_set_value_cansleep(bitbang->mdo, 1); + return; + } + + if (dir) + gpiod_direction_output(bitbang->mdio, 1); + else + gpiod_direction_input(bitbang->mdio); +} + +static int mdio_get(struct mdiobb_ctrl *ctrl) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + return gpiod_get_value_cansleep(bitbang->mdio); +} + +static void mdio_set(struct mdiobb_ctrl *ctrl, int what) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + if (bitbang->mdo) + gpiod_set_value_cansleep(bitbang->mdo, what); + else + gpiod_set_value_cansleep(bitbang->mdio, what); +} + +static void mdc_set(struct mdiobb_ctrl *ctrl, int what) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + gpiod_set_value_cansleep(bitbang->mdc, what); +} + +static const struct mdiobb_ops mdio_gpio_ops = { + .owner = THIS_MODULE, + .set_mdc = mdc_set, + .set_mdio_dir = mdio_dir, + .set_mdio_data = mdio_set, + .get_mdio_data = mdio_get, +}; + +static struct mii_bus *mdio_gpio_bus_init(struct device *dev, + struct mdio_gpio_info *bitbang, + int bus_id) +{ + struct mdio_gpio_platform_data *pdata = dev_get_platdata(dev); + struct mii_bus *new_bus; + + bitbang->ctrl.ops = &mdio_gpio_ops; + + new_bus = alloc_mdio_bitbang(&bitbang->ctrl); + if (!new_bus) + return NULL; + + new_bus->name = "GPIO Bitbanged MDIO"; + new_bus->parent = dev; + + if (bus_id != -1) + snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id); + else + strncpy(new_bus->id, "gpio", MII_BUS_ID_SIZE); + + if (pdata) { + new_bus->phy_mask = pdata->phy_mask; + new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask; + } + + dev_set_drvdata(dev, new_bus); + + return new_bus; +} + +static void mdio_gpio_bus_deinit(struct device *dev) +{ + struct mii_bus *bus = dev_get_drvdata(dev); + + free_mdio_bitbang(bus); +} + +static void mdio_gpio_bus_destroy(struct device *dev) +{ + struct mii_bus *bus = dev_get_drvdata(dev); + + mdiobus_unregister(bus); + mdio_gpio_bus_deinit(dev); +} + +static int mdio_gpio_probe(struct platform_device *pdev) +{ + struct mdio_gpio_info *bitbang; + struct mii_bus *new_bus; + int ret, bus_id; + + bitbang = devm_kzalloc(&pdev->dev, sizeof(*bitbang), GFP_KERNEL); + if (!bitbang) + return -ENOMEM; + + ret = mdio_gpio_get_data(&pdev->dev, bitbang); + if (ret) + return ret; + + if (pdev->dev.of_node) { + bus_id = of_alias_get_id(pdev->dev.of_node, "mdio-gpio"); + if (bus_id < 0) { + dev_warn(&pdev->dev, "failed to get alias id\n"); + bus_id = 0; + } + } else { + bus_id = pdev->id; + } + + new_bus = mdio_gpio_bus_init(&pdev->dev, bitbang, bus_id); + if (!new_bus) + return -ENODEV; + + ret = of_mdiobus_register(new_bus, pdev->dev.of_node); + if (ret) + mdio_gpio_bus_deinit(&pdev->dev); + + return ret; +} + +static int mdio_gpio_remove(struct platform_device *pdev) +{ + mdio_gpio_bus_destroy(&pdev->dev); + + return 0; +} + +static const struct of_device_id mdio_gpio_of_match[] = { + { .compatible = "virtual,mdio-gpio", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mdio_gpio_of_match); + +static struct platform_driver mdio_gpio_driver = { + .probe = mdio_gpio_probe, + .remove = mdio_gpio_remove, + .driver = { + .name = "mdio-gpio", + .of_match_table = mdio_gpio_of_match, + }, +}; + +module_platform_driver(mdio_gpio_driver); + +MODULE_ALIAS("platform:mdio-gpio"); +MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/wb_mdio_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/wb_mdio_gpio_device.c new file mode 100644 index 000000000000..e3198b378a20 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/wb_mdio_gpio_device.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int gpio_mdc = 44; +module_param(gpio_mdc, int, S_IRUGO | S_IWUSR); + +static int gpio_mdio = 45; +module_param(gpio_mdio, int, S_IRUGO | S_IWUSR); + +static char *gpio_chip_name = NULL; +module_param(gpio_chip_name, charp, 0644); +MODULE_PARM_DESC(str_var, "A string variable for GPIO controller"); + +static int g_wb_mdio_gpio_device_debug = 0; +static int g_wb_mdio_gpio_device_error = 0; + +module_param(g_wb_mdio_gpio_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_mdio_gpio_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_MIDO_GPIO_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_mdio_gpio_device_debug) { \ + printk(KERN_INFO "[WB_MDIO_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_MIDO_GPIO_DEVICE_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_mdio_gpio_device_error) { \ + printk(KERN_ERR "[WB_MDIO_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +struct mdio_gpio_platform_data mdio_gpio_device_data = { + .phy_mask = 0, + .phy_ignore_ta_mask = 0, +}; + +static void wb_mdio_gpio_device_release(struct device *dev) +{ + return; +} + +static struct platform_device mdio_gpio_device = { + .name = "mdio-gpio", + .num_resources = 0, + .id = -1, + .dev = { + .platform_data = &mdio_gpio_device_data, + .release = wb_mdio_gpio_device_release, + }, +}; + +static struct gpiod_lookup_table wb_mdio_gpio_table = { + .dev_id = "mdio-gpio", + .table = { + GPIO_LOOKUP_IDX("wb_gpio_d1500", 44, NULL, MDIO_GPIO_MDC, + GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("wb_gpio_d1500", 45, NULL, MDIO_GPIO_MDIO, + GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static int __init wb_mdio_gpio_device_init(void) +{ + int err; + + WB_MIDO_GPIO_DEVICE_DEBUG_VERBOSE("wb_mdio_gpio_device_init enter!\n"); + wb_mdio_gpio_table.table[0].chip_hwnum = gpio_mdc; + wb_mdio_gpio_table.table[1].chip_hwnum = gpio_mdio; + + if (gpio_chip_name) { + wb_mdio_gpio_table.table[0].key = gpio_chip_name; + wb_mdio_gpio_table.table[1].key = gpio_chip_name; + } + + gpiod_add_lookup_table(&wb_mdio_gpio_table); + + err = platform_device_register(&mdio_gpio_device); + if (err < 0) { + printk(KERN_ERR "register mdio gpio device fail(%d). \n", err); + gpiod_remove_lookup_table(&wb_mdio_gpio_table); + return -1; + } + return 0; + +} + +static void __exit wb_mdio_gpio_device_exit(void) +{ + WB_MIDO_GPIO_DEVICE_DEBUG_VERBOSE("wb_mdio_gpio_device_exit enter!\n"); + platform_device_unregister(&mdio_gpio_device); + gpiod_remove_lookup_table(&wb_mdio_gpio_table); +} + +module_init(wb_mdio_gpio_device_init); +module_exit(wb_mdio_gpio_device_exit); +MODULE_DESCRIPTION("WB MDIO GPIO Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/Makefile new file mode 100644 index 000000000000..295934ca4a29 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/Makefile @@ -0,0 +1,17 @@ +PWD = $(shell pwd) + +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall + +obj-m := wb_pinctrl_intel.o +obj-m += wb_gpio_c3000.o +obj-m += wb_gpio_c3000_device.o + +all: + $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules + @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi + cp -p $(PWD)/*.ko $(module_out_put_dir) +clean: + rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/*.mod + rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order + rm -rf $(PWD)/.tmp_versions diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/core.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/core.h new file mode 100644 index 000000000000..840103c40c14 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/core.h @@ -0,0 +1,249 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Core private header for the pin control subsystem + * + * Copyright (C) 2011 ST-Ericsson SA + * Written on behalf of Linaro for ST-Ericsson + * + * Author: Linus Walleij + */ + +#include +#include +#include +#include +#include + +struct pinctrl_gpio_range; + +/** + * struct pinctrl_dev - pin control class device + * @node: node to include this pin controller in the global pin controller list + * @desc: the pin controller descriptor supplied when initializing this pin + * controller + * @pin_desc_tree: each pin descriptor for this pin controller is stored in + * this radix tree + * @pin_group_tree: optionally each pin group can be stored in this radix tree + * @num_groups: optionally number of groups can be kept here + * @pin_function_tree: optionally each function can be stored in this radix tree + * @num_functions: optionally number of functions can be kept here + * @gpio_ranges: a list of GPIO ranges that is handled by this pin controller, + * ranges are added to this list at runtime + * @dev: the device entry for this pin controller + * @owner: module providing the pin controller, used for refcounting + * @driver_data: driver data for drivers registering to the pin controller + * subsystem + * @p: result of pinctrl_get() for this device + * @hog_default: default state for pins hogged by this device + * @hog_sleep: sleep state for pins hogged by this device + * @mutex: mutex taken on each pin controller specific action + * @device_root: debugfs root for this device + */ +struct pinctrl_dev { + struct list_head node; + struct pinctrl_desc *desc; + struct radix_tree_root pin_desc_tree; +#ifdef CONFIG_GENERIC_PINCTRL_GROUPS + struct radix_tree_root pin_group_tree; + unsigned int num_groups; +#endif +#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS + struct radix_tree_root pin_function_tree; + unsigned int num_functions; +#endif + struct list_head gpio_ranges; + struct device *dev; + struct module *owner; + void *driver_data; + struct pinctrl *p; + struct pinctrl_state *hog_default; + struct pinctrl_state *hog_sleep; + struct mutex mutex; +#ifdef CONFIG_DEBUG_FS + struct dentry *device_root; +#endif +}; + +/** + * struct pinctrl - per-device pin control state holder + * @node: global list node + * @dev: the device using this pin control handle + * @states: a list of states for this device + * @state: the current state + * @dt_maps: the mapping table chunks dynamically parsed from device tree for + * this device, if any + * @users: reference count + */ +struct pinctrl { + struct list_head node; + struct device *dev; + struct list_head states; + struct pinctrl_state *state; + struct list_head dt_maps; + struct kref users; +}; + +/** + * struct pinctrl_state - a pinctrl state for a device + * @node: list node for struct pinctrl's @states field + * @name: the name of this state + * @settings: a list of settings for this state + */ +struct pinctrl_state { + struct list_head node; + const char *name; + struct list_head settings; +}; + +/** + * struct pinctrl_setting_mux - setting data for MAP_TYPE_MUX_GROUP + * @group: the group selector to program + * @func: the function selector to program + */ +struct pinctrl_setting_mux { + unsigned group; + unsigned func; +}; + +/** + * struct pinctrl_setting_configs - setting data for MAP_TYPE_CONFIGS_* + * @group_or_pin: the group selector or pin ID to program + * @configs: a pointer to an array of config parameters/values to program into + * hardware. Each individual pin controller defines the format and meaning + * of config parameters. + * @num_configs: the number of entries in array @configs + */ +struct pinctrl_setting_configs { + unsigned group_or_pin; + unsigned long *configs; + unsigned num_configs; +}; + +/** + * struct pinctrl_setting - an individual mux or config setting + * @node: list node for struct pinctrl_settings's @settings field + * @type: the type of setting + * @pctldev: pin control device handling to be programmed. Not used for + * PIN_MAP_TYPE_DUMMY_STATE. + * @dev_name: the name of the device using this state + * @data: Data specific to the setting type + */ +struct pinctrl_setting { + struct list_head node; + enum pinctrl_map_type type; + struct pinctrl_dev *pctldev; + const char *dev_name; + union { + struct pinctrl_setting_mux mux; + struct pinctrl_setting_configs configs; + } data; +}; + +/** + * struct pin_desc - pin descriptor for each physical pin in the arch + * @pctldev: corresponding pin control device + * @name: a name for the pin, e.g. the name of the pin/pad/finger on a + * datasheet or such + * @dynamic_name: if the name of this pin was dynamically allocated + * @drv_data: driver-defined per-pin data. pinctrl core does not touch this + * @mux_usecount: If zero, the pin is not claimed, and @owner should be NULL. + * If non-zero, this pin is claimed by @owner. This field is an integer + * rather than a boolean, since pinctrl_get() might process multiple + * mapping table entries that refer to, and hence claim, the same group + * or pin, and each of these will increment the @usecount. + * @mux_owner: The name of device that called pinctrl_get(). + * @mux_setting: The most recent selected mux setting for this pin, if any. + * @gpio_owner: If pinctrl_gpio_request() was called for this pin, this is + * the name of the GPIO that "owns" this pin. + */ +struct pin_desc { + struct pinctrl_dev *pctldev; + const char *name; + bool dynamic_name; + void *drv_data; + /* These fields only added when supporting pinmux drivers */ +#ifdef CONFIG_PINMUX + unsigned mux_usecount; + const char *mux_owner; + const struct pinctrl_setting_mux *mux_setting; + const char *gpio_owner; +#endif +}; + +/** + * struct pinctrl_maps - a list item containing part of the mapping table + * @node: mapping table list node + * @maps: array of mapping table entries + * @num_maps: the number of entries in @maps + */ +struct pinctrl_maps { + struct list_head node; + const struct pinctrl_map *maps; + unsigned num_maps; +}; + +#ifdef CONFIG_GENERIC_PINCTRL_GROUPS + +/** + * struct group_desc - generic pin group descriptor + * @name: name of the pin group + * @pins: array of pins that belong to the group + * @num_pins: number of pins in the group + * @data: pin controller driver specific data + */ +struct group_desc { + const char *name; + int *pins; + int num_pins; + void *data; +}; + +int pinctrl_generic_get_group_count(struct pinctrl_dev *pctldev); + +const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group_selector); + +int pinctrl_generic_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int group_selector, + const unsigned int **pins, + unsigned int *npins); + +struct group_desc *pinctrl_generic_get_group(struct pinctrl_dev *pctldev, + unsigned int group_selector); + +int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name, + int *gpins, int ngpins, void *data); + +int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev, + unsigned int group_selector); + +#endif /* CONFIG_GENERIC_PINCTRL_GROUPS */ + +struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name); +struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np); +int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name); +const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin); +int pinctrl_get_group_selector(struct pinctrl_dev *pctldev, + const char *pin_group); + +static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev, + unsigned int pin) +{ + return radix_tree_lookup(&pctldev->pin_desc_tree, pin); +} + +extern struct pinctrl_gpio_range * +pinctrl_find_gpio_range_from_pin_nolock(struct pinctrl_dev *pctldev, + unsigned int pin); + +extern int pinctrl_force_sleep(struct pinctrl_dev *pctldev); +extern int pinctrl_force_default(struct pinctrl_dev *pctldev); + +extern struct mutex pinctrl_maps_mutex; +extern struct list_head pinctrl_maps; + +#define for_each_maps(_maps_node_, _i_, _map_) \ + list_for_each_entry(_maps_node_, &pinctrl_maps, node) \ + for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \ + _i_ < _maps_node_->num_maps; \ + _i_++, _map_ = &_maps_node_->maps[_i_]) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000.c new file mode 100644 index 000000000000..753c8a061a86 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000.c @@ -0,0 +1,452 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel Denverton SoC pinctrl/GPIO driver + * + * Copyright (C) 2017, Intel Corporation + * Author: Mika Westerberg + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_pinctrl_intel.h" + +static int g_c3000_gpio_debug = 0; +static int g_c3000_gpio_error = 0; +module_param(g_c3000_gpio_debug, int, S_IRUGO | S_IWUSR); +module_param(g_c3000_gpio_error, int, S_IRUGO | S_IWUSR); + +#define C3000_GPIO_VERBOSE(fmt, args...) do { \ + if (g_c3000_gpio_debug) { \ + printk(KERN_INFO "[GPIO_PCIE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define C3000_GPIO_ERROR(fmt, args...) do { \ + if (g_c3000_gpio_error) { \ + printk(KERN_ERR "[GPIO_PCIE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define DNV_PAD_OWN 0x020 +#define DNV_PADCFGLOCK 0x090 +#define DNV_HOSTSW_OWN 0x0C0 +#define DNV_GPI_IS 0x100 +#define DNV_GPI_IE 0x120 + +#define DNV_GPP(n, s, e) \ + { \ + .reg_num = (n), \ + .base = (s), \ + .size = ((e) - (s) + 1), \ + } + +#define DNV_COMMUNITY(b, s, e, g, d) \ + { \ + .barno = (b), \ + .padown_offset = DNV_PAD_OWN, \ + .padcfglock_offset = DNV_PADCFGLOCK, \ + .hostown_offset = DNV_HOSTSW_OWN, \ + .is_offset = DNV_GPI_IS, \ + .ie_offset = DNV_GPI_IE, \ + .pin_base = (s), \ + .npins = ((e) - (s) + 1), \ + .gpps = (g), \ + .ngpps = ARRAY_SIZE(g), \ + .dw_base = (d), \ + } + +/* Denverton */ +static const struct pinctrl_pin_desc dnv_pins[] = { + /* North ALL */ + PINCTRL_PIN(0, "GBE0_SDP0"), + PINCTRL_PIN(1, "GBE1_SDP0"), + PINCTRL_PIN(2, "GBE0_SDP1"), + PINCTRL_PIN(3, "GBE1_SDP1"), + PINCTRL_PIN(4, "GBE0_SDP2"), + PINCTRL_PIN(5, "GBE1_SDP2"), + PINCTRL_PIN(6, "GBE0_SDP3"), + PINCTRL_PIN(7, "GBE1_SDP3"), + PINCTRL_PIN(8, "GBE2_LED0"), + PINCTRL_PIN(9, "GBE2_LED1"), + PINCTRL_PIN(10, "GBE0_I2C_CLK"), + PINCTRL_PIN(11, "GBE0_I2C_DATA"), + PINCTRL_PIN(12, "GBE1_I2C_CLK"), + PINCTRL_PIN(13, "GBE1_I2C_DATA"), + PINCTRL_PIN(14, "NCSI_RXD0"), + PINCTRL_PIN(15, "NCSI_CLK_IN"), + PINCTRL_PIN(16, "NCSI_RXD1"), + PINCTRL_PIN(17, "NCSI_CRS_DV"), + PINCTRL_PIN(18, "NCSI_ARB_IN"), + PINCTRL_PIN(19, "NCSI_TX_EN"), + PINCTRL_PIN(20, "NCSI_TXD0"), + PINCTRL_PIN(21, "NCSI_TXD1"), + PINCTRL_PIN(22, "NCSI_ARB_OUT"), + PINCTRL_PIN(23, "GBE0_LED0"), + PINCTRL_PIN(24, "GBE0_LED1"), + PINCTRL_PIN(25, "GBE1_LED0"), + PINCTRL_PIN(26, "GBE1_LED1"), + PINCTRL_PIN(27, "GPIO0"), + PINCTRL_PIN(28, "PCIE_CLKREQ0_N"), + PINCTRL_PIN(29, "PCIE_CLKREQ1_N"), + PINCTRL_PIN(30, "PCIE_CLKREQ2_N"), + PINCTRL_PIN(31, "PCIE_CLKREQ3_N"), + PINCTRL_PIN(32, "PCIE_CLKREQ4_N"), + PINCTRL_PIN(33, "GPIO1"), + PINCTRL_PIN(34, "GPIO2"), + PINCTRL_PIN(35, "SVID_ALERT_N"), + PINCTRL_PIN(36, "SVID_DATA"), + PINCTRL_PIN(37, "SVID_CLK"), + PINCTRL_PIN(38, "THERMTRIP_N"), + PINCTRL_PIN(39, "PROCHOT_N"), + PINCTRL_PIN(40, "MEMHOT_N"), + /* South DFX */ + PINCTRL_PIN(41, "DFX_PORT_CLK0"), + PINCTRL_PIN(42, "DFX_PORT_CLK1"), + PINCTRL_PIN(43, "DFX_PORT0"), + PINCTRL_PIN(44, "DFX_PORT1"), + PINCTRL_PIN(45, "DFX_PORT2"), + PINCTRL_PIN(46, "DFX_PORT3"), + PINCTRL_PIN(47, "DFX_PORT4"), + PINCTRL_PIN(48, "DFX_PORT5"), + PINCTRL_PIN(49, "DFX_PORT6"), + PINCTRL_PIN(50, "DFX_PORT7"), + PINCTRL_PIN(51, "DFX_PORT8"), + PINCTRL_PIN(52, "DFX_PORT9"), + PINCTRL_PIN(53, "DFX_PORT10"), + PINCTRL_PIN(54, "DFX_PORT11"), + PINCTRL_PIN(55, "DFX_PORT12"), + PINCTRL_PIN(56, "DFX_PORT13"), + PINCTRL_PIN(57, "DFX_PORT14"), + PINCTRL_PIN(58, "DFX_PORT15"), + /* South GPP0 */ + PINCTRL_PIN(59, "GPIO12"), + PINCTRL_PIN(60, "SMB5_GBE_ALRT_N"), + PINCTRL_PIN(61, "PCIE_CLKREQ5_N"), + PINCTRL_PIN(62, "PCIE_CLKREQ6_N"), + PINCTRL_PIN(63, "PCIE_CLKREQ7_N"), + PINCTRL_PIN(64, "UART0_RXD"), + PINCTRL_PIN(65, "UART0_TXD"), + PINCTRL_PIN(66, "SMB5_GBE_CLK"), + PINCTRL_PIN(67, "SMB5_GBE_DATA"), + PINCTRL_PIN(68, "ERROR2_N"), + PINCTRL_PIN(69, "ERROR1_N"), + PINCTRL_PIN(70, "ERROR0_N"), + PINCTRL_PIN(71, "IERR_N"), + PINCTRL_PIN(72, "MCERR_N"), + PINCTRL_PIN(73, "SMB0_LEG_CLK"), + PINCTRL_PIN(74, "SMB0_LEG_DATA"), + PINCTRL_PIN(75, "SMB0_LEG_ALRT_N"), + PINCTRL_PIN(76, "SMB1_HOST_DATA"), + PINCTRL_PIN(77, "SMB1_HOST_CLK"), + PINCTRL_PIN(78, "SMB2_PECI_DATA"), + PINCTRL_PIN(79, "SMB2_PECI_CLK"), + PINCTRL_PIN(80, "SMB4_CSME0_DATA"), + PINCTRL_PIN(81, "SMB4_CSME0_CLK"), + PINCTRL_PIN(82, "SMB4_CSME0_ALRT_N"), + PINCTRL_PIN(83, "USB_OC0_N"), + PINCTRL_PIN(84, "FLEX_CLK_SE0"), + PINCTRL_PIN(85, "FLEX_CLK_SE1"), + PINCTRL_PIN(86, "GPIO4"), + PINCTRL_PIN(87, "GPIO5"), + PINCTRL_PIN(88, "GPIO6"), + PINCTRL_PIN(89, "GPIO7"), + PINCTRL_PIN(90, "SATA0_LED_N"), + PINCTRL_PIN(91, "SATA1_LED_N"), + PINCTRL_PIN(92, "SATA_PDETECT0"), + PINCTRL_PIN(93, "SATA_PDETECT1"), + PINCTRL_PIN(94, "SATA0_SDOUT"), + PINCTRL_PIN(95, "SATA1_SDOUT"), + PINCTRL_PIN(96, "UART1_RXD"), + PINCTRL_PIN(97, "UART1_TXD"), + PINCTRL_PIN(98, "GPIO8"), + PINCTRL_PIN(99, "GPIO9"), + PINCTRL_PIN(100, "TCK"), + PINCTRL_PIN(101, "TRST_N"), + PINCTRL_PIN(102, "TMS"), + PINCTRL_PIN(103, "TDI"), + PINCTRL_PIN(104, "TDO"), + PINCTRL_PIN(105, "CX_PRDY_N"), + PINCTRL_PIN(106, "CX_PREQ_N"), + PINCTRL_PIN(107, "CTBTRIGINOUT"), + PINCTRL_PIN(108, "CTBTRIGOUT"), + PINCTRL_PIN(109, "DFX_SPARE2"), + PINCTRL_PIN(110, "DFX_SPARE3"), + PINCTRL_PIN(111, "DFX_SPARE4"), + /* South GPP1 */ + PINCTRL_PIN(112, "SUSPWRDNACK"), + PINCTRL_PIN(113, "PMU_SUSCLK"), + PINCTRL_PIN(114, "ADR_TRIGGER"), + PINCTRL_PIN(115, "PMU_SLP_S45_N"), + PINCTRL_PIN(116, "PMU_SLP_S3_N"), + PINCTRL_PIN(117, "PMU_WAKE_N"), + PINCTRL_PIN(118, "PMU_PWRBTN_N"), + PINCTRL_PIN(119, "PMU_RESETBUTTON_N"), + PINCTRL_PIN(120, "PMU_PLTRST_N"), + PINCTRL_PIN(121, "SUS_STAT_N"), + PINCTRL_PIN(122, "SLP_S0IX_N"), + PINCTRL_PIN(123, "SPI_CS0_N"), + PINCTRL_PIN(124, "SPI_CS1_N"), + PINCTRL_PIN(125, "SPI_MOSI_IO0"), + PINCTRL_PIN(126, "SPI_MISO_IO1"), + PINCTRL_PIN(127, "SPI_IO2"), + PINCTRL_PIN(128, "SPI_IO3"), + PINCTRL_PIN(129, "SPI_CLK"), + PINCTRL_PIN(130, "SPI_CLK_LOOPBK"), + PINCTRL_PIN(131, "ESPI_IO0"), + PINCTRL_PIN(132, "ESPI_IO1"), + PINCTRL_PIN(133, "ESPI_IO2"), + PINCTRL_PIN(134, "ESPI_IO3"), + PINCTRL_PIN(135, "ESPI_CS0_N"), + PINCTRL_PIN(136, "ESPI_CLK"), + PINCTRL_PIN(137, "ESPI_RST_N"), + PINCTRL_PIN(138, "ESPI_ALRT0_N"), + PINCTRL_PIN(139, "GPIO10"), + PINCTRL_PIN(140, "GPIO11"), + PINCTRL_PIN(141, "ESPI_CLK_LOOPBK"), + PINCTRL_PIN(142, "EMMC_CMD"), + PINCTRL_PIN(143, "EMMC_STROBE"), + PINCTRL_PIN(144, "EMMC_CLK"), + PINCTRL_PIN(145, "EMMC_D0"), + PINCTRL_PIN(146, "EMMC_D1"), + PINCTRL_PIN(147, "EMMC_D2"), + PINCTRL_PIN(148, "EMMC_D3"), + PINCTRL_PIN(149, "EMMC_D4"), + PINCTRL_PIN(150, "EMMC_D5"), + PINCTRL_PIN(151, "EMMC_D6"), + PINCTRL_PIN(152, "EMMC_D7"), + PINCTRL_PIN(153, "GPIO3"), +}; + +static const unsigned int dnv_uart0_pins[] = { 60, 61, 64, 65 }; +static const unsigned int dnv_uart0_modes[] = { 2, 3, 1, 1 }; +static const unsigned int dnv_uart1_pins[] = { 94, 95, 96, 97 }; +static const unsigned int dnv_uart2_pins[] = { 60, 61, 62, 63 }; +static const unsigned int dnv_uart2_modes[] = { 1, 2, 2, 2 }; +static const unsigned int dnv_emmc_pins[] = { + 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, +}; + +static const struct intel_pingroup dnv_groups[] = { + PIN_GROUP("uart0_grp", dnv_uart0_pins, dnv_uart0_modes), + PIN_GROUP("uart1_grp", dnv_uart1_pins, 1), + PIN_GROUP("uart2_grp", dnv_uart2_pins, dnv_uart2_modes), + PIN_GROUP("emmc_grp", dnv_emmc_pins, 1), +}; + +static const char * const dnv_uart0_groups[] = { "uart0_grp" }; +static const char * const dnv_uart1_groups[] = { "uart1_grp" }; +static const char * const dnv_uart2_groups[] = { "uart2_grp" }; +static const char * const dnv_emmc_groups[] = { "emmc_grp" }; + +static const struct intel_function dnv_functions[] = { + FUNCTION("uart0", dnv_uart0_groups), + FUNCTION("uart1", dnv_uart1_groups), + FUNCTION("uart2", dnv_uart2_groups), + FUNCTION("emmc", dnv_emmc_groups), +}; + +static const struct intel_padgroup dnv_north_gpps[] = { + DNV_GPP(0, 0, 31), /* North ALL_0 */ + DNV_GPP(1, 32, 40), /* North ALL_1 */ +}; + +static const struct intel_padgroup dnv_south_gpps[] = { + DNV_GPP(0, 41, 58), /* South DFX */ + DNV_GPP(1, 59, 90), /* South GPP0_0 */ + DNV_GPP(2, 91, 111), /* South GPP0_1 */ + DNV_GPP(3, 112, 143), /* South GPP1_0 */ + DNV_GPP(4, 144, 153), /* South GPP1_1 */ +}; + +static const struct intel_community dnv_communities[] = { + DNV_COMMUNITY(0, 0, 40, dnv_north_gpps, 0xc20000), + DNV_COMMUNITY(1, 41, 153, dnv_south_gpps, 0xc50000), +}; + +static const struct intel_pinctrl_soc_data dnv_soc_data = { + .pins = dnv_pins, + .npins = ARRAY_SIZE(dnv_pins), + .groups = dnv_groups, + .ngroups = ARRAY_SIZE(dnv_groups), + .functions = dnv_functions, + .nfunctions = ARRAY_SIZE(dnv_functions), + .communities = dnv_communities, + .ncommunities = ARRAY_SIZE(dnv_communities), +}; + +static INTEL_PINCTRL_PM_OPS(dnv_pinctrl_pm_ops); + +static int pci_dev_init(wb_gpio_data_t *wb_gpio_data, struct pci_dev *pci_dev) +{ + int err, i; + void __iomem *base; + + C3000_GPIO_VERBOSE("Enter vendor 0x%x, device 0x%x.\n", + pci_dev->vendor, pci_dev->device); + + C3000_GPIO_VERBOSE("start pci_enable_device!\n"); + err = pci_enable_device(pci_dev); + if (err) { + dev_err(&pci_dev->dev, "Failed to enable pci device, ret:%d.\n", err); + return err; + } + + err = pci_request_region(pci_dev, 0, "P2SB"); + if (err) { + dev_err(&pci_dev->dev, "Requesting C3000 P2SB BAR0 region failed, ret: %d\n", err); + goto err_disable; + } + + C3000_GPIO_VERBOSE("start pci_set_master!\n"); + pci_set_master(pci_dev); + + base = pci_iomap(pci_dev, wb_gpio_data->pci_bar, 0); + if (!base) { + dev_err(&pci_dev->dev, "pci_iomap bar: %d failed\n", wb_gpio_data->pci_bar); + err = -ENOMEM; + goto err_release; + } + wb_gpio_data->pci_mem_base = base; + + for (i = 0; i < dnv_soc_data.ncommunities; i++) { + wb_gpio_data->res[i] = base + dnv_soc_data.communities[i].dw_base; + } + return 0; +err_release: + pci_release_region(pci_dev, wb_gpio_data->pci_bar); +err_disable: + pci_disable_device(pci_dev); + return err; +} + +static void pci_dev_release(wb_gpio_data_t *wb_gpio_data) +{ + struct pci_dev *pci_dev; + + pci_dev = wb_gpio_data->pci_dev; + if (wb_gpio_data->pci_mem_base) { + pci_iounmap(pci_dev, wb_gpio_data->pci_mem_base); + } + pci_release_region(pci_dev, wb_gpio_data->pci_bar); + pci_disable_device(pci_dev); + return; +} + +static int wb_gpio_driver_probe(struct platform_device *plat_dev) +{ + int ret, devfn; + wb_gpio_data_t *wb_gpio_data; + wb_gpio_data_t *c3000_gpio_device; + struct pci_dev *pci_dev; + + if (dnv_soc_data.ncommunities > GPIO_RES_MAX) { + dev_err(&plat_dev->dev, "GPIO ncommunities %lu is more than GPIO resource number: %d\n", + dnv_soc_data.ncommunities, GPIO_RES_MAX); + return -EINVAL; + } + + wb_gpio_data = devm_kzalloc(&plat_dev->dev, sizeof(wb_gpio_data_t), GFP_KERNEL); + if (!wb_gpio_data) { + dev_err(&plat_dev->dev, "devm_kzalloc failed.\n"); + ret = -ENOMEM; + return ret; + } + + if (plat_dev->dev.of_node) { + ret = 0; + ret += of_property_read_u32(plat_dev->dev.of_node, "pci_domain", &wb_gpio_data->pci_domain); + ret += of_property_read_u32(plat_dev->dev.of_node, "pci_bus", &wb_gpio_data->pci_bus); + ret += of_property_read_u32(plat_dev->dev.of_node, "pci_slot", &wb_gpio_data->pci_slot); + ret += of_property_read_u32(plat_dev->dev.of_node, "pci_fn", &wb_gpio_data->pci_fn); + ret += of_property_read_u32(plat_dev->dev.of_node, "pci_bar", &wb_gpio_data->pci_bar); + ret += of_property_read_u32(plat_dev->dev.of_node, "irq", &wb_gpio_data->irq); + if (ret != 0) { + dev_err(&plat_dev->dev, "Failed to get dts config, ret:%d.\n", ret); + return -ENXIO; + } + } else { + if (plat_dev->dev.platform_data == NULL) { + dev_err(&plat_dev->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + c3000_gpio_device = plat_dev->dev.platform_data; + wb_gpio_data->pci_domain = c3000_gpio_device->pci_domain; + wb_gpio_data->pci_bus = c3000_gpio_device->pci_bus; + wb_gpio_data->pci_slot = c3000_gpio_device->pci_slot; + wb_gpio_data->pci_fn = c3000_gpio_device->pci_fn; + wb_gpio_data->pci_bar = c3000_gpio_device->pci_bar; + wb_gpio_data->irq = c3000_gpio_device->irq; + } + + C3000_GPIO_VERBOSE("domain:0x%04x, bus:0x%02x, slot:0x%02x, fn:%u, bar:%u, irq: %d\n", + wb_gpio_data->pci_domain, wb_gpio_data->pci_bus, wb_gpio_data->pci_slot, wb_gpio_data->pci_fn, + wb_gpio_data->pci_bar, wb_gpio_data->irq); + + devfn = PCI_DEVFN(wb_gpio_data->pci_slot, wb_gpio_data->pci_fn); + pci_dev = pci_get_domain_bus_and_slot(wb_gpio_data->pci_domain, wb_gpio_data->pci_bus, devfn); + if (pci_dev == NULL) { + dev_err(&plat_dev->dev, "Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", + wb_gpio_data->pci_domain, wb_gpio_data->pci_bus, devfn); + return -ENXIO; + } + wb_gpio_data->pci_dev = pci_dev; + ret = pci_dev_init(wb_gpio_data, pci_dev); + if (ret != 0) { + dev_err(&plat_dev->dev, "Failed to get pci bar address.\n"); + return ret; + } + C3000_GPIO_VERBOSE("pci_dev_init success, pci_mem_bae: 0x%pK, res0: 0x%pK, res1: 0x%pK\n", + wb_gpio_data->pci_mem_base, wb_gpio_data->res[0], wb_gpio_data->res[1]); + + platform_set_drvdata(plat_dev, wb_gpio_data); + + ret = wb_pinctrl_probe(plat_dev, &dnv_soc_data); + if (ret) { + dev_err(&plat_dev->dev, "C3000 gpio pinctrl probe failed, ret:%d\n", ret); + pci_dev_release(wb_gpio_data); + return ret; + } + dev_info(&plat_dev->dev, "C3000 gpio pinctrl probe success.\n"); + return 0; +} + +static int wb_gpio_driver_remove(struct platform_device *plat_dev) +{ + wb_gpio_data_t *wb_gpio_data; + + C3000_GPIO_VERBOSE("c3000_gpio_pcie_remove.\n"); + + wb_gpio_data = platform_get_drvdata(plat_dev); + pci_dev_release(wb_gpio_data); + return 0; +} + +static const struct of_device_id gpio_c3000_match[] = { + { + .compatible = "wb_gpio_c3000", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, gpio_c3000_match); + +static struct platform_driver wb_gpio_c3000_driver = { + .driver = { + .name = "wb_gpio_c3000", + .of_match_table = gpio_c3000_match, + }, + .probe = wb_gpio_driver_probe, + .remove = wb_gpio_driver_remove, +}; + +module_platform_driver(wb_gpio_c3000_driver); + +MODULE_DESCRIPTION("C3000 GPIO Controller driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000_device.c new file mode 100644 index 000000000000..33ab19a5ac44 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000_device.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include + +#include "wb_pinctrl_intel.h" + +static int g_wb_c300_gpio_device_debug = 0; +static int g_wb_c300_gpio_device_error = 0; + +module_param(g_wb_c300_gpio_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_c300_gpio_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_C3000_GPIO_DEVICE_DEBUG(fmt, args...) do { \ + if (g_wb_c300_gpio_device_debug) { \ + printk(KERN_INFO "[WB_C3000_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_C3000_GPIO_DEVICE_ERROR(fmt, args...) do { \ + if (g_wb_c300_gpio_device_error) { \ + printk(KERN_ERR "[WB_C3000_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static wb_gpio_data_t c3000_gpio_device_data = { + .irq = 15, + .pci_domain = 0x0000, + .pci_bus = 0x00, + .pci_slot = 0x1f, + .pci_fn = 1, + .pci_bar = 0, +}; + +static void wb_c3000_gpio_device_release(struct device *dev) +{ + return; +} + +static struct platform_device c3000_gpio_device = { + .name = "wb_gpio_c3000", + .id = -1, + .dev = { + .platform_data = &c3000_gpio_device_data, + .release = wb_c3000_gpio_device_release, + }, +}; + +static int __init wb_c3000_gpio_device_init(void) +{ + WB_C3000_GPIO_DEVICE_DEBUG("wb_c3000_gpio_device_init enter!\n"); + return platform_device_register(&c3000_gpio_device); + +} + +static void __exit wb_c3000_gpio_device_exit(void) +{ + + WB_C3000_GPIO_DEVICE_DEBUG("wb_c3000_gpio_device_exit enter!\n"); + platform_device_unregister(&c3000_gpio_device); + return; +} + +module_init(wb_c3000_gpio_device_init); +module_exit(wb_c3000_gpio_device_exit); +MODULE_DESCRIPTION("C3000 GPIO Controller device"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.c new file mode 100644 index 000000000000..7a52f17ac8f9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.c @@ -0,0 +1,1829 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel pinctrl/GPIO core driver. + * + * Copyright (C) 2015, Intel Corporation + * Authors: Mathias Nyman + * Mika Westerberg + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "core.h" +#include "wb_pinctrl_intel.h" + +/* Offset from regs */ +#define REVID 0x000 +#define REVID_SHIFT 16 +#define REVID_MASK GENMASK(31, 16) + +#define PADBAR 0x00c + +#define PADOWN_BITS 4 +#define PADOWN_SHIFT(p) ((p) % 8 * PADOWN_BITS) +#define PADOWN_MASK(p) (GENMASK(3, 0) << PADOWN_SHIFT(p)) +#define PADOWN_GPP(p) ((p) / 8) + +/* Offset from pad_regs */ +#define PADCFG0 0x000 +#define PADCFG0_RXEVCFG_SHIFT 25 +#define PADCFG0_RXEVCFG_MASK GENMASK(26, 25) +#define PADCFG0_RXEVCFG_LEVEL 0 +#define PADCFG0_RXEVCFG_EDGE 1 +#define PADCFG0_RXEVCFG_DISABLED 2 +#define PADCFG0_RXEVCFG_EDGE_BOTH 3 +#define PADCFG0_PREGFRXSEL BIT(24) +#define PADCFG0_RXINV BIT(23) +#define PADCFG0_GPIROUTIOXAPIC BIT(20) +#define PADCFG0_GPIROUTSCI BIT(19) +#define PADCFG0_GPIROUTSMI BIT(18) +#define PADCFG0_GPIROUTNMI BIT(17) +#define PADCFG0_PMODE_SHIFT 10 +#define PADCFG0_PMODE_MASK GENMASK(13, 10) +#define PADCFG0_PMODE_GPIO 0 +#define PADCFG0_GPIORXDIS BIT(9) +#define PADCFG0_GPIOTXDIS BIT(8) +#define PADCFG0_GPIORXSTATE BIT(1) +#define PADCFG0_GPIOTXSTATE BIT(0) + +#define PADCFG1 0x004 +#define PADCFG1_TERM_UP BIT(13) +#define PADCFG1_TERM_SHIFT 10 +#define PADCFG1_TERM_MASK GENMASK(12, 10) +#define PADCFG1_TERM_20K BIT(2) +#define PADCFG1_TERM_5K BIT(1) +#define PADCFG1_TERM_1K BIT(0) +#define PADCFG1_TERM_833 (BIT(1) | BIT(0)) + +#define PADCFG2 0x008 +#define PADCFG2_DEBEN BIT(0) +#define PADCFG2_DEBOUNCE_SHIFT 1 +#define PADCFG2_DEBOUNCE_MASK GENMASK(4, 1) + +#define DEBOUNCE_PERIOD_NSEC 31250 + +struct intel_pad_context { + u32 padcfg0; + u32 padcfg1; + u32 padcfg2; +}; + +struct intel_community_context { + u32 *intmask; + u32 *hostown; +}; + +#define pin_to_padno(c, p) ((p) - (c)->pin_base) +#define padgroup_offset(g, p) ((p) - (g)->base) + +static struct intel_community *intel_get_community(struct intel_pinctrl *pctrl, + unsigned int pin) +{ + struct intel_community *community; + int i; + + for (i = 0; i < pctrl->ncommunities; i++) { + community = &pctrl->communities[i]; + if (pin >= community->pin_base && + pin < community->pin_base + community->npins) + return community; + } + + dev_warn(pctrl->dev, "failed to find community for pin %u\n", pin); + return NULL; +} + +static const struct intel_padgroup * +intel_community_get_padgroup(const struct intel_community *community, + unsigned int pin) +{ + int i; + + for (i = 0; i < community->ngpps; i++) { + const struct intel_padgroup *padgrp = &community->gpps[i]; + + if (pin >= padgrp->base && pin < padgrp->base + padgrp->size) + return padgrp; + } + + return NULL; +} + +static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl, + unsigned int pin, unsigned int reg) +{ + const struct intel_community *community; + unsigned int padno; + size_t nregs; + + community = intel_get_community(pctrl, pin); + if (!community) + return NULL; + + padno = pin_to_padno(community, pin); + nregs = (community->features & PINCTRL_FEATURE_DEBOUNCE) ? 4 : 2; + + if (reg >= nregs * 4) + return NULL; + + return community->pad_regs + reg + padno * nregs * 4; +} + +static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned int pin) +{ + const struct intel_community *community; + const struct intel_padgroup *padgrp; + unsigned int gpp, offset, gpp_offset; + void __iomem *padown; + + community = intel_get_community(pctrl, pin); + if (!community) + return false; + if (!community->padown_offset) + return true; + + padgrp = intel_community_get_padgroup(community, pin); + if (!padgrp) + return false; + + gpp_offset = padgroup_offset(padgrp, pin); + gpp = PADOWN_GPP(gpp_offset); + offset = community->padown_offset + padgrp->padown_num * 4 + gpp * 4; + padown = community->regs + offset; + + return !(readl(padown) & PADOWN_MASK(gpp_offset)); +} + +static bool intel_pad_set_acpi_mode(struct intel_pinctrl *pctrl, + unsigned pin, bool acpi_mode) +{ + const struct intel_community *community; + const struct intel_padgroup *padgrp; + unsigned int offset, gpp_offset; + void __iomem *hostown; + uint32_t value; + + community = intel_get_community(pctrl, pin); + if (!community) + return true; + if (!community->hostown_offset) + return false; + + padgrp = intel_community_get_padgroup(community, pin); + if (!padgrp) + return true; + + gpp_offset = padgroup_offset(padgrp, pin); + offset = community->hostown_offset + padgrp->reg_num * 4; + hostown = community->regs + offset; + + value = readl(hostown); + if (acpi_mode) { + /* ACPI mode */ + value &= ~BIT(gpp_offset); + } else { + /* GPIO mode */ + value |= BIT(gpp_offset); + } + + writel(value, hostown); + + return !(readl(hostown) & BIT(gpp_offset)); +} + +static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned int pin) +{ + const struct intel_community *community; + const struct intel_padgroup *padgrp; + unsigned int offset, gpp_offset; + void __iomem *hostown; + + community = intel_get_community(pctrl, pin); + if (!community) + return true; + if (!community->hostown_offset) + return false; + + padgrp = intel_community_get_padgroup(community, pin); + if (!padgrp) + return true; + + gpp_offset = padgroup_offset(padgrp, pin); + offset = community->hostown_offset + padgrp->reg_num * 4; + hostown = community->regs + offset; + + return !(readl(hostown) & BIT(gpp_offset)); +} + +/** + * enum - Locking variants of the pad configuration + * + * @PAD_UNLOCKED: pad is fully controlled by the configuration registers + * @PAD_LOCKED: pad configuration registers, except TX state, are locked + * @PAD_LOCKED_TX: pad configuration TX state is locked + * @PAD_LOCKED_FULL: pad configuration registers are locked completely + * + * Locking is considered as read-only mode for corresponding registers and + * their respective fields. That said, TX state bit is locked separately from + * the main locking scheme. + */ +enum { + PAD_UNLOCKED = 0, + PAD_LOCKED = 1, + PAD_LOCKED_TX = 2, + PAD_LOCKED_FULL = PAD_LOCKED | PAD_LOCKED_TX, +}; + +static int intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin) +{ + struct intel_community *community; + const struct intel_padgroup *padgrp; + unsigned int offset, gpp_offset; + u32 value; + int ret = PAD_UNLOCKED; + + community = intel_get_community(pctrl, pin); + if (!community) + return PAD_LOCKED_FULL; + if (!community->padcfglock_offset) + return PAD_UNLOCKED; + + padgrp = intel_community_get_padgroup(community, pin); + if (!padgrp) + return PAD_LOCKED_FULL; + + gpp_offset = padgroup_offset(padgrp, pin); + + /* + * If PADCFGLOCK and PADCFGLOCKTX bits are both clear for this pad, + * the pad is considered unlocked. Any other case means that it is + * either fully or partially locked. + */ + offset = community->padcfglock_offset + 0 + padgrp->reg_num * 8; + value = readl(community->regs + offset); + if (value & BIT(gpp_offset)) + ret |= PAD_LOCKED; + + offset = community->padcfglock_offset + 4 + padgrp->reg_num * 8; + value = readl(community->regs + offset); + if (value & BIT(gpp_offset)) + ret |= PAD_LOCKED_TX; + + return ret; +} + +static bool intel_pad_is_unlocked(struct intel_pinctrl *pctrl, unsigned int pin) +{ + return (intel_pad_locked(pctrl, pin) & PAD_LOCKED) == PAD_UNLOCKED; +} + +static bool intel_pad_usable(struct intel_pinctrl *pctrl, unsigned int pin) +{ + return intel_pad_owned_by_host(pctrl, pin) && intel_pad_is_unlocked(pctrl, pin); +} + +static int intel_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->soc->ngroups; +} + +static const char *intel_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->soc->groups[group].name; +} + +static int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group, + const unsigned int **pins, unsigned int *npins) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *pins = pctrl->soc->groups[group].pins; + *npins = pctrl->soc->groups[group].npins; + return 0; +} + +static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned int pin) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + void __iomem *padcfg; + u32 cfg0, cfg1, mode; + int locked; + bool acpi; + + if (!intel_pad_owned_by_host(pctrl, pin)) { + seq_puts(s, "not available"); + return; + } + + cfg0 = readl(intel_get_padcfg(pctrl, pin, PADCFG0)); + cfg1 = readl(intel_get_padcfg(pctrl, pin, PADCFG1)); + + mode = (cfg0 & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT; + if (mode == PADCFG0_PMODE_GPIO) + seq_puts(s, "GPIO "); + else + seq_printf(s, "mode %d ", mode); + + seq_printf(s, "0x%08x 0x%08x", cfg0, cfg1); + + /* Dump the additional PADCFG registers if available */ + padcfg = intel_get_padcfg(pctrl, pin, PADCFG2); + if (padcfg) + seq_printf(s, " 0x%08x", readl(padcfg)); + + locked = intel_pad_locked(pctrl, pin); + acpi = intel_pad_acpi_mode(pctrl, pin); + + if (locked || acpi) { + seq_puts(s, " ["); + if (locked) + seq_puts(s, "LOCKED"); + if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_TX) + seq_puts(s, " tx"); + else if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_FULL) + seq_puts(s, " full"); + + if (locked && acpi) + seq_puts(s, ", "); + + if (acpi) + seq_puts(s, "ACPI"); + seq_puts(s, "]"); + } +} + +static const struct pinctrl_ops intel_pinctrl_ops = { + .get_groups_count = intel_get_groups_count, + .get_group_name = intel_get_group_name, + .get_group_pins = intel_get_group_pins, + .pin_dbg_show = intel_pin_dbg_show, +}; + +static int intel_get_functions_count(struct pinctrl_dev *pctldev) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->soc->nfunctions; +} + +static const char *intel_get_function_name(struct pinctrl_dev *pctldev, + unsigned int function) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->soc->functions[function].name; +} + +static int intel_get_function_groups(struct pinctrl_dev *pctldev, + unsigned int function, + const char * const **groups, + unsigned int * const ngroups) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *groups = pctrl->soc->functions[function].groups; + *ngroups = pctrl->soc->functions[function].ngroups; + return 0; +} + +static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned int function, unsigned int group) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct intel_pingroup *grp = &pctrl->soc->groups[group]; + unsigned long flags; + int i; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + + /* + * All pins in the groups needs to be accessible and writable + * before we can enable the mux for this group. + */ + for (i = 0; i < grp->npins; i++) { + if (!intel_pad_usable(pctrl, grp->pins[i])) { + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + return -EBUSY; + } + } + + /* Now enable the mux setting for each pin in the group */ + for (i = 0; i < grp->npins; i++) { + void __iomem *padcfg0; + u32 value; + + padcfg0 = intel_get_padcfg(pctrl, grp->pins[i], PADCFG0); + value = readl(padcfg0); + + value &= ~PADCFG0_PMODE_MASK; + + if (grp->modes) + value |= grp->modes[i] << PADCFG0_PMODE_SHIFT; + else + value |= grp->mode << PADCFG0_PMODE_SHIFT; + + writel(value, padcfg0); + } + + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input) +{ + u32 value; + + value = readl(padcfg0); + if (input) { + value &= ~PADCFG0_GPIORXDIS; + value |= PADCFG0_GPIOTXDIS; + } else { + value &= ~PADCFG0_GPIOTXDIS; + value |= PADCFG0_GPIORXDIS; + } + writel(value, padcfg0); +} + +static int intel_gpio_get_gpio_mode(void __iomem *padcfg0) +{ + return (readl(padcfg0) & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT; +} + +static void intel_gpio_set_gpio_mode(void __iomem *padcfg0) +{ + u32 value; + + value = readl(padcfg0); + + /* Put the pad into GPIO mode */ + value &= ~PADCFG0_PMODE_MASK; + value |= PADCFG0_PMODE_GPIO; + + /* Disable input and output buffers */ + value |= PADCFG0_GPIORXDIS; + value |= PADCFG0_GPIOTXDIS; + + /* Disable SCI/SMI/NMI generation */ + value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI); + value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI); + + writel(value, padcfg0); +} + +static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + void __iomem *padcfg0; + unsigned long flags; + + padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); + + raw_spin_lock_irqsave(&pctrl->lock, flags); + + if (!intel_pad_owned_by_host(pctrl, pin)) { + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + return -EBUSY; + } + + if (!intel_pad_is_unlocked(pctrl, pin)) { + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + return 0; + } + + /* + * If pin is already configured in GPIO mode, we assume that + * firmware provides correct settings. In such case we avoid + * potential glitches on the pin. Otherwise, for the pin in + * alternative mode, consumer has to supply respective flags. + */ + if (intel_gpio_get_gpio_mode(padcfg0) == PADCFG0_PMODE_GPIO) { + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + return 0; + } + + intel_gpio_set_gpio_mode(padcfg0); + + /* Disable TX buffer and enable RX (this will be input) */ + __intel_gpio_set_direction(padcfg0, true); + + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static int intel_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin, bool input) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + void __iomem *padcfg0; + unsigned long flags; + + padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); + + raw_spin_lock_irqsave(&pctrl->lock, flags); + __intel_gpio_set_direction(padcfg0, input); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static const struct pinmux_ops intel_pinmux_ops = { + .get_functions_count = intel_get_functions_count, + .get_function_name = intel_get_function_name, + .get_function_groups = intel_get_function_groups, + .set_mux = intel_pinmux_set_mux, + .gpio_request_enable = intel_gpio_request_enable, + .gpio_set_direction = intel_gpio_set_direction, +}; + +static int intel_config_get_pull(struct intel_pinctrl *pctrl, unsigned int pin, + enum pin_config_param param, u32 *arg) +{ + const struct intel_community *community; + void __iomem *padcfg1; + unsigned long flags; + u32 value, term; + + community = intel_get_community(pctrl, pin); + padcfg1 = intel_get_padcfg(pctrl, pin, PADCFG1); + + raw_spin_lock_irqsave(&pctrl->lock, flags); + value = readl(padcfg1); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + term = (value & PADCFG1_TERM_MASK) >> PADCFG1_TERM_SHIFT; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + if (term) + return -EINVAL; + break; + + case PIN_CONFIG_BIAS_PULL_UP: + if (!term || !(value & PADCFG1_TERM_UP)) + return -EINVAL; + + switch (term) { + case PADCFG1_TERM_833: + *arg = 833; + break; + case PADCFG1_TERM_1K: + *arg = 1000; + break; + case PADCFG1_TERM_5K: + *arg = 5000; + break; + case PADCFG1_TERM_20K: + *arg = 20000; + break; + } + + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + if (!term || value & PADCFG1_TERM_UP) + return -EINVAL; + + switch (term) { + case PADCFG1_TERM_833: + if (!(community->features & PINCTRL_FEATURE_1K_PD)) + return -EINVAL; + *arg = 833; + break; + case PADCFG1_TERM_1K: + if (!(community->features & PINCTRL_FEATURE_1K_PD)) + return -EINVAL; + *arg = 1000; + break; + case PADCFG1_TERM_5K: + *arg = 5000; + break; + case PADCFG1_TERM_20K: + *arg = 20000; + break; + } + + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int intel_config_get_debounce(struct intel_pinctrl *pctrl, unsigned int pin, + enum pin_config_param param, u32 *arg) +{ + void __iomem *padcfg2; + unsigned long flags; + unsigned long v; + u32 value2; + + padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2); + if (!padcfg2) + return -ENOTSUPP; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + value2 = readl(padcfg2); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + if (!(value2 & PADCFG2_DEBEN)) + return -EINVAL; + + v = (value2 & PADCFG2_DEBOUNCE_MASK) >> PADCFG2_DEBOUNCE_SHIFT; + *arg = BIT(v) * DEBOUNCE_PERIOD_NSEC / NSEC_PER_USEC; + + return 0; +} + +static int intel_config_get(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *config) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param = pinconf_to_config_param(*config); + u32 arg = 0; + int ret; + + if (!intel_pad_owned_by_host(pctrl, pin)) + return -ENOTSUPP; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = intel_config_get_pull(pctrl, pin, param, &arg); + if (ret) + return ret; + break; + + case PIN_CONFIG_INPUT_DEBOUNCE: + ret = intel_config_get_debounce(pctrl, pin, param, &arg); + if (ret) + return ret; + break; + + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + return 0; +} + +static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin, + unsigned long config) +{ + unsigned int param = pinconf_to_config_param(config); + unsigned int arg = pinconf_to_config_argument(config); + const struct intel_community *community; + void __iomem *padcfg1; + unsigned long flags; + int ret = 0; + u32 value; + + community = intel_get_community(pctrl, pin); + padcfg1 = intel_get_padcfg(pctrl, pin, PADCFG1); + + raw_spin_lock_irqsave(&pctrl->lock, flags); + + value = readl(padcfg1); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + value &= ~(PADCFG1_TERM_MASK | PADCFG1_TERM_UP); + break; + + case PIN_CONFIG_BIAS_PULL_UP: + value &= ~PADCFG1_TERM_MASK; + + value |= PADCFG1_TERM_UP; + + /* Set default strength value in case none is given */ + if (arg == 1) + arg = 5000; + + switch (arg) { + case 20000: + value |= PADCFG1_TERM_20K << PADCFG1_TERM_SHIFT; + break; + case 5000: + value |= PADCFG1_TERM_5K << PADCFG1_TERM_SHIFT; + break; + case 1000: + value |= PADCFG1_TERM_1K << PADCFG1_TERM_SHIFT; + break; + case 833: + value |= PADCFG1_TERM_833 << PADCFG1_TERM_SHIFT; + break; + default: + ret = -EINVAL; + } + + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + value &= ~(PADCFG1_TERM_UP | PADCFG1_TERM_MASK); + + /* Set default strength value in case none is given */ + if (arg == 1) + arg = 5000; + + switch (arg) { + case 20000: + value |= PADCFG1_TERM_20K << PADCFG1_TERM_SHIFT; + break; + case 5000: + value |= PADCFG1_TERM_5K << PADCFG1_TERM_SHIFT; + break; + case 1000: + if (!(community->features & PINCTRL_FEATURE_1K_PD)) { + ret = -EINVAL; + break; + } + value |= PADCFG1_TERM_1K << PADCFG1_TERM_SHIFT; + break; + case 833: + if (!(community->features & PINCTRL_FEATURE_1K_PD)) { + ret = -EINVAL; + break; + } + value |= PADCFG1_TERM_833 << PADCFG1_TERM_SHIFT; + break; + default: + ret = -EINVAL; + } + + break; + } + + if (!ret) + writel(value, padcfg1); + + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + return ret; +} + +static int intel_config_set_debounce(struct intel_pinctrl *pctrl, + unsigned int pin, unsigned int debounce) +{ + void __iomem *padcfg0, *padcfg2; + unsigned long flags; + u32 value0, value2; + + padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2); + if (!padcfg2) + return -ENOTSUPP; + + padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); + + raw_spin_lock_irqsave(&pctrl->lock, flags); + + value0 = readl(padcfg0); + value2 = readl(padcfg2); + + /* Disable glitch filter and debouncer */ + value0 &= ~PADCFG0_PREGFRXSEL; + value2 &= ~(PADCFG2_DEBEN | PADCFG2_DEBOUNCE_MASK); + + if (debounce) { + unsigned long v; + + v = order_base_2(debounce * NSEC_PER_USEC / DEBOUNCE_PERIOD_NSEC); + if (v < 3 || v > 15) { + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + return -EINVAL; + } + + /* Enable glitch filter and debouncer */ + value0 |= PADCFG0_PREGFRXSEL; + value2 |= v << PADCFG2_DEBOUNCE_SHIFT; + value2 |= PADCFG2_DEBEN; + } + + writel(value0, padcfg0); + writel(value2, padcfg2); + + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static int intel_config_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int nconfigs) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + int i, ret; + + if (!intel_pad_usable(pctrl, pin)) + return -ENOTSUPP; + + for (i = 0; i < nconfigs; i++) { + switch (pinconf_to_config_param(configs[i])) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = intel_config_set_pull(pctrl, pin, configs[i]); + if (ret) + return ret; + break; + + case PIN_CONFIG_INPUT_DEBOUNCE: + ret = intel_config_set_debounce(pctrl, pin, + pinconf_to_config_argument(configs[i])); + if (ret) + return ret; + break; + + default: + return -ENOTSUPP; + } + } + + return 0; +} + +static const struct pinconf_ops intel_pinconf_ops = { + .is_generic = true, + .pin_config_get = intel_config_get, + .pin_config_set = intel_config_set, +}; + +static const struct pinctrl_desc intel_pinctrl_desc = { + .pctlops = &intel_pinctrl_ops, + .pmxops = &intel_pinmux_ops, + .confops = &intel_pinconf_ops, + .owner = THIS_MODULE, +}; + +/** + * intel_gpio_to_pin() - Translate from GPIO offset to pin number + * @pctrl: Pinctrl structure + * @offset: GPIO offset from gpiolib + * @community: Community is filled here if not %NULL + * @padgrp: Pad group is filled here if not %NULL + * + * When coming through gpiolib irqchip, the GPIO offset is not + * automatically translated to pinctrl pin number. This function can be + * used to find out the corresponding pinctrl pin. + */ +static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned int offset, + const struct intel_community **community, + const struct intel_padgroup **padgrp) +{ + int i; + + for (i = 0; i < pctrl->ncommunities; i++) { + const struct intel_community *comm = &pctrl->communities[i]; + int j; + + for (j = 0; j < comm->ngpps; j++) { + const struct intel_padgroup *pgrp = &comm->gpps[j]; + + if (pgrp->gpio_base == INTEL_GPIO_BASE_NOMAP) + continue; + + if (offset >= pgrp->gpio_base && + offset < pgrp->gpio_base + pgrp->size) { + int pin; + + pin = pgrp->base + offset - pgrp->gpio_base; + if (community) + *community = comm; + if (padgrp) + *padgrp = pgrp; + + return pin; + } + } + } + + return -EINVAL; +} + +/** + * intel_pin_to_gpio() - Translate from pin number to GPIO offset + * @pctrl: Pinctrl structure + * @pin: pin number + * + * Translate the pin number of pinctrl to GPIO offset + */ +static __maybe_unused int intel_pin_to_gpio(struct intel_pinctrl *pctrl, int pin) +{ + const struct intel_community *community; + const struct intel_padgroup *padgrp; + + community = intel_get_community(pctrl, pin); + if (!community) + return -EINVAL; + + padgrp = intel_community_get_padgroup(community, pin); + if (!padgrp) + return -EINVAL; + + return pin - padgrp->base + padgrp->gpio_base; +} + +static int intel_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct intel_pinctrl *pctrl = gpiochip_get_data(chip); + void __iomem *reg; + u32 padcfg0; + int pin; + + pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL); + if (pin < 0) + return -EINVAL; + + reg = intel_get_padcfg(pctrl, pin, PADCFG0); + if (!reg) + return -EINVAL; + + padcfg0 = readl(reg); + if (!(padcfg0 & PADCFG0_GPIOTXDIS)) + return !!(padcfg0 & PADCFG0_GPIOTXSTATE); + + return !!(padcfg0 & PADCFG0_GPIORXSTATE); +} + +static void intel_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct intel_pinctrl *pctrl = gpiochip_get_data(chip); + unsigned long flags; + void __iomem *reg; + u32 padcfg0; + int pin; + + pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL); + if (pin < 0) + return; + + reg = intel_get_padcfg(pctrl, pin, PADCFG0); + if (!reg) + return; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + padcfg0 = readl(reg); + if (value) + padcfg0 |= PADCFG0_GPIOTXSTATE; + else + padcfg0 &= ~PADCFG0_GPIOTXSTATE; + writel(padcfg0, reg); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); +} + +static int intel_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + struct intel_pinctrl *pctrl = gpiochip_get_data(chip); + unsigned long flags; + void __iomem *reg; + u32 padcfg0; + int pin; + + pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL); + if (pin < 0) + return -EINVAL; + + reg = intel_get_padcfg(pctrl, pin, PADCFG0); + if (!reg) + return -EINVAL; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + padcfg0 = readl(reg); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + if (padcfg0 & PADCFG0_PMODE_MASK) + return -EINVAL; + + if (padcfg0 & PADCFG0_GPIOTXDIS) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; +} + +static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) +{ + return pinctrl_gpio_direction_input(chip->base + offset); +} + +static int intel_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, + int value) +{ + intel_gpio_set(chip, offset, value); + return pinctrl_gpio_direction_output(chip->base + offset); +} + +static const struct gpio_chip intel_gpio_chip = { + .owner = THIS_MODULE, + .request = gpiochip_generic_request, + .free = gpiochip_generic_free, + .get_direction = intel_gpio_get_direction, + .direction_input = intel_gpio_direction_input, + .direction_output = intel_gpio_direction_output, + .get = intel_gpio_get, + .set = intel_gpio_set, + .set_config = gpiochip_generic_config, +}; + +static void intel_gpio_irq_ack(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct intel_pinctrl *pctrl = gpiochip_get_data(gc); + const struct intel_community *community; + const struct intel_padgroup *padgrp; + int pin; + + pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); + if (pin >= 0) { + unsigned int gpp, gpp_offset, is_offset; + + gpp = padgrp->reg_num; + gpp_offset = padgroup_offset(padgrp, pin); + is_offset = community->is_offset + gpp * 4; + + raw_spin_lock(&pctrl->lock); + writel(BIT(gpp_offset), community->regs + is_offset); + raw_spin_unlock(&pctrl->lock); + } +} + +static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct intel_pinctrl *pctrl = gpiochip_get_data(gc); + const struct intel_community *community; + const struct intel_padgroup *padgrp; + int pin; + + pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); + if (pin >= 0) { + unsigned int gpp, gpp_offset; + unsigned long flags; + void __iomem *reg, *is; + u32 value; + + gpp = padgrp->reg_num; + gpp_offset = padgroup_offset(padgrp, pin); + + reg = community->regs + community->ie_offset + gpp * 4; + is = community->regs + community->is_offset + gpp * 4; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + + /* Clear interrupt status first to avoid unexpected interrupt */ + writel(BIT(gpp_offset), is); + + value = readl(reg); + if (mask) + value &= ~BIT(gpp_offset); + else + value |= BIT(gpp_offset); + writel(value, reg); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + } +} + +static void intel_gpio_irq_mask(struct irq_data *d) +{ + intel_gpio_irq_mask_unmask(d, true); +} + +static void intel_gpio_irq_unmask(struct irq_data *d) +{ + intel_gpio_irq_mask_unmask(d, false); +} + +static int intel_gpio_irq_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct intel_pinctrl *pctrl = gpiochip_get_data(gc); + unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); + unsigned long flags; + void __iomem *reg; + u32 value; + + reg = intel_get_padcfg(pctrl, pin, PADCFG0); + if (!reg) + return -EINVAL; + + /* set not ACPI mode */ + intel_pad_set_acpi_mode(pctrl, pin, false); + + /* + * If the pin is in ACPI mode it is still usable as a GPIO but it + * cannot be used as IRQ because GPI_IS status bit will not be + * updated by the host controller hardware. + */ + if (intel_pad_acpi_mode(pctrl, pin)) { + dev_warn(pctrl->dev, "pin %u cannot be used as IRQ\n", pin); + return -EPERM; + } + + raw_spin_lock_irqsave(&pctrl->lock, flags); + + intel_gpio_set_gpio_mode(reg); + + /* Disable TX buffer and enable RX (this will be input) */ + __intel_gpio_set_direction(reg, true); + + value = readl(reg); + + value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV); + + if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { + value |= PADCFG0_RXEVCFG_EDGE_BOTH << PADCFG0_RXEVCFG_SHIFT; + } else if (type & IRQ_TYPE_EDGE_FALLING) { + value |= PADCFG0_RXEVCFG_EDGE << PADCFG0_RXEVCFG_SHIFT; + value |= PADCFG0_RXINV; + } else if (type & IRQ_TYPE_EDGE_RISING) { + value |= PADCFG0_RXEVCFG_EDGE << PADCFG0_RXEVCFG_SHIFT; + } else if (type & IRQ_TYPE_LEVEL_MASK) { + if (type & IRQ_TYPE_LEVEL_LOW) + value |= PADCFG0_RXINV; + } else { + value |= PADCFG0_RXEVCFG_DISABLED << PADCFG0_RXEVCFG_SHIFT; + } + + writel(value, reg); + + if (type & IRQ_TYPE_EDGE_BOTH) + irq_set_handler_locked(d, handle_edge_irq); + else if (type & IRQ_TYPE_LEVEL_MASK) + irq_set_handler_locked(d, handle_level_irq); + + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct intel_pinctrl *pctrl = gpiochip_get_data(gc); + unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); + + if (on) + enable_irq_wake(pctrl->irq); + else + disable_irq_wake(pctrl->irq); + + dev_dbg(pctrl->dev, "%sable wake for pin %u\n", on ? "en" : "dis", pin); + return 0; +} + +static int intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl, + const struct intel_community *community) +{ + struct gpio_chip *gc = &pctrl->chip; + unsigned int gpp; + int ret = 0; + + for (gpp = 0; gpp < community->ngpps; gpp++) { + const struct intel_padgroup *padgrp = &community->gpps[gpp]; + unsigned long pending, enabled, gpp_offset; + unsigned long flags; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + + pending = readl(community->regs + community->is_offset + + padgrp->reg_num * 4); + enabled = readl(community->regs + community->ie_offset + + padgrp->reg_num * 4); + + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + /* Only interrupts that are enabled */ + pending &= enabled; + + for_each_set_bit(gpp_offset, &pending, padgrp->size) { + unsigned int irq; + + irq = irq_find_mapping(gc->irq.domain, + padgrp->gpio_base + gpp_offset); + generic_handle_irq(irq); + } + + ret += pending ? 1 : 0; + } + + return ret; +} + +static irqreturn_t intel_gpio_irq(int irq, void *data) +{ + const struct intel_community *community; + struct intel_pinctrl *pctrl = data; + unsigned int i; + int ret = 0; + + /* Need to check all communities for pending interrupts */ + for (i = 0; i < pctrl->ncommunities; i++) { + community = &pctrl->communities[i]; + ret += intel_gpio_community_irq_handler(pctrl, community); + } + + return IRQ_RETVAL(ret); +} + +static int intel_gpio_add_community_ranges(struct intel_pinctrl *pctrl, + const struct intel_community *community) +{ + int ret = 0, i; + + for (i = 0; i < community->ngpps; i++) { + const struct intel_padgroup *gpp = &community->gpps[i]; + + if (gpp->gpio_base == INTEL_GPIO_BASE_NOMAP) + continue; + + ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), + gpp->gpio_base, gpp->base, + gpp->size); + if (ret) + return ret; + } + + return ret; +} + +static int intel_gpio_add_pin_ranges(struct gpio_chip *gc) +{ + struct intel_pinctrl *pctrl = gpiochip_get_data(gc); + int ret, i; + + for (i = 0; i < pctrl->ncommunities; i++) { + struct intel_community *community = &pctrl->communities[i]; + + ret = intel_gpio_add_community_ranges(pctrl, community); + if (ret) { + dev_err(pctrl->dev, "failed to add GPIO pin range\n"); + return ret; + } + } + + return 0; +} + +static unsigned int intel_gpio_ngpio(const struct intel_pinctrl *pctrl) +{ + const struct intel_community *community; + unsigned int ngpio = 0; + int i, j; + + for (i = 0; i < pctrl->ncommunities; i++) { + community = &pctrl->communities[i]; + for (j = 0; j < community->ngpps; j++) { + const struct intel_padgroup *gpp = &community->gpps[j]; + + if (gpp->gpio_base == INTEL_GPIO_BASE_NOMAP) + continue; + + if (gpp->gpio_base + gpp->size > ngpio) + ngpio = gpp->gpio_base + gpp->size; + } + } + + return ngpio; +} + +static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq) +{ + int ret; + struct gpio_irq_chip *girq; + + pctrl->chip = intel_gpio_chip; + + /* Setup GPIO chip */ + pctrl->chip.ngpio = intel_gpio_ngpio(pctrl); + pctrl->chip.label = dev_name(pctrl->dev); + pctrl->chip.parent = pctrl->dev; + pctrl->chip.base = 0; + pctrl->chip.add_pin_ranges = intel_gpio_add_pin_ranges; + pctrl->irq = irq; + + /* Setup IRQ chip */ + pctrl->irqchip.name = dev_name(pctrl->dev); + pctrl->irqchip.irq_ack = intel_gpio_irq_ack; + pctrl->irqchip.irq_mask = intel_gpio_irq_mask; + pctrl->irqchip.irq_unmask = intel_gpio_irq_unmask; + pctrl->irqchip.irq_set_type = intel_gpio_irq_type; + pctrl->irqchip.irq_set_wake = intel_gpio_irq_wake; + pctrl->irqchip.flags = IRQCHIP_MASK_ON_SUSPEND; + + /* + * On some platforms several GPIO controllers share the same interrupt + * line. + */ + ret = devm_request_irq(pctrl->dev, irq, intel_gpio_irq, + IRQF_SHARED | IRQF_NO_THREAD, + dev_name(pctrl->dev), pctrl); + if (ret) { + dev_err(pctrl->dev, "failed to request interrupt\n"); + return ret; + } + + girq = &pctrl->chip.irq; + girq->chip = &pctrl->irqchip; + /* This will let us handle the IRQ in the driver */ + girq->parent_handler = NULL; + girq->num_parents = 0; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + + ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl); + if (ret) { + dev_err(pctrl->dev, "failed to register gpiochip\n"); + return ret; + } + + return 0; +} + +static int intel_pinctrl_add_padgroups(struct intel_pinctrl *pctrl, + struct intel_community *community) +{ + struct intel_padgroup *gpps; + unsigned int npins = community->npins; + unsigned int padown_num = 0; + size_t ngpps, i; + + if (community->gpps) + ngpps = community->ngpps; + else + ngpps = DIV_ROUND_UP(community->npins, community->gpp_size); + + gpps = devm_kcalloc(pctrl->dev, ngpps, sizeof(*gpps), GFP_KERNEL); + if (!gpps) + return -ENOMEM; + + for (i = 0; i < ngpps; i++) { + if (community->gpps) { + gpps[i] = community->gpps[i]; + } else { + unsigned int gpp_size = community->gpp_size; + + gpps[i].reg_num = i; + gpps[i].base = community->pin_base + i * gpp_size; + gpps[i].size = min(gpp_size, npins); + npins -= gpps[i].size; + } + + if (gpps[i].size > 32) + return -EINVAL; + + /* Special treatment for GPIO base */ + switch (gpps[i].gpio_base) { + case INTEL_GPIO_BASE_MATCH: + gpps[i].gpio_base = gpps[i].base; + break; + case INTEL_GPIO_BASE_ZERO: + gpps[i].gpio_base = 0; + break; + case INTEL_GPIO_BASE_NOMAP: + default: + break; + } + + gpps[i].padown_num = padown_num; + + /* + * In older hardware the number of padown registers per + * group is fixed regardless of the group size. + */ + if (community->gpp_num_padown_regs) + padown_num += community->gpp_num_padown_regs; + else + padown_num += DIV_ROUND_UP(gpps[i].size * 4, 32); + } + + community->ngpps = ngpps; + community->gpps = gpps; + + return 0; +} + +static int intel_pinctrl_pm_init(struct intel_pinctrl *pctrl) +{ +#ifdef CONFIG_PM_SLEEP + const struct intel_pinctrl_soc_data *soc = pctrl->soc; + struct intel_community_context *communities; + struct intel_pad_context *pads; + int i; + + pads = devm_kcalloc(pctrl->dev, soc->npins, sizeof(*pads), GFP_KERNEL); + if (!pads) + return -ENOMEM; + + communities = devm_kcalloc(pctrl->dev, pctrl->ncommunities, + sizeof(*communities), GFP_KERNEL); + if (!communities) + return -ENOMEM; + + for (i = 0; i < pctrl->ncommunities; i++) { + struct intel_community *community = &pctrl->communities[i]; + u32 *intmask, *hostown; + + intmask = devm_kcalloc(pctrl->dev, community->ngpps, + sizeof(*intmask), GFP_KERNEL); + if (!intmask) + return -ENOMEM; + + communities[i].intmask = intmask; + + hostown = devm_kcalloc(pctrl->dev, community->ngpps, + sizeof(*hostown), GFP_KERNEL); + if (!hostown) + return -ENOMEM; + + communities[i].hostown = hostown; + } + + pctrl->context.pads = pads; + pctrl->context.communities = communities; +#endif + + return 0; +} + +int wb_pinctrl_probe(struct platform_device *pdev, + const struct intel_pinctrl_soc_data *soc_data) +{ + struct intel_pinctrl *pctrl; + struct intel_community *community; + wb_gpio_data_t *wb_gpio_data; + void __iomem *regs; + int i, ret; + u32 padbar, rev; + + if (!soc_data) { + dev_err(&pdev->dev, "soc_data is null\n"); + return -EINVAL; + } + + wb_gpio_data = platform_get_drvdata(pdev); + pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) { + dev_err(&pdev->dev, "pctrl kzalloc failed\n"); + return -ENOMEM; + } + + /* check resource */ + if (soc_data->ncommunities > GPIO_RES_MAX) { + dev_err(&pdev->dev, "GPIO ncommunities %lu is more than GPIO resource number: %d\n", + soc_data->ncommunities, GPIO_RES_MAX); + return -EINVAL; + } + + pctrl->dev = &pdev->dev; + pctrl->soc = soc_data; + pctrl->irq = wb_gpio_data->irq; + raw_spin_lock_init(&pctrl->lock); + + /* + * Make a copy of the communities which we can use to hold pointers + * to the registers. + */ + pctrl->ncommunities = pctrl->soc->ncommunities; + pctrl->communities = devm_kcalloc(&pdev->dev, pctrl->ncommunities, + sizeof(*pctrl->communities), GFP_KERNEL); + if (!pctrl->communities) { + dev_err(&pdev->dev, "devm_kcalloc communities failed. ret:%d\n", ret); + return -ENOMEM; + } + + for (i = 0; i < pctrl->ncommunities; i++) { + community = &pctrl->communities[i]; + *community = pctrl->soc->communities[i]; + + regs = wb_gpio_data->res[i]; + + /* + * Determine community features based on the revision if + * not specified already. + */ + if (!community->features) { + rev = (readl(regs + REVID) & REVID_MASK) >> REVID_SHIFT; + if (rev >= 0x94) { + community->features |= PINCTRL_FEATURE_DEBOUNCE; + community->features |= PINCTRL_FEATURE_1K_PD; + } + } + + /* Read offset of the pad configuration registers */ + padbar = readl(regs + PADBAR); + + community->regs = regs; + community->pad_regs = regs + padbar; + + ret = intel_pinctrl_add_padgroups(pctrl, community); + if (ret) { + dev_err(&pdev->dev, "intel_pinctrl_add_padgroups failed. ret:%d\n", ret); + return ret; + } + } + + ret = intel_pinctrl_pm_init(pctrl); + if (ret) { + dev_err(&pdev->dev, "intel_pinctrl_pm_init failed. ret:%d\n", ret); + return ret; + } + + pctrl->pctldesc = intel_pinctrl_desc; + pctrl->pctldesc.name = dev_name(&pdev->dev); + pctrl->pctldesc.pins = pctrl->soc->pins; + pctrl->pctldesc.npins = pctrl->soc->npins; + + pctrl->pctldev = devm_pinctrl_register(&pdev->dev, &pctrl->pctldesc, + pctrl); + if (IS_ERR(pctrl->pctldev)) { + dev_err(&pdev->dev, "failed to register pinctrl driver\n"); + return PTR_ERR(pctrl->pctldev); + } + + ret = intel_gpio_probe(pctrl, pctrl->irq); + if (ret) { + dev_err(&pdev->dev, "intel_gpio_probe failed. ret:%d\n", ret); + return ret; + } + return 0; +} +EXPORT_SYMBOL_GPL(wb_pinctrl_probe); + +#if 0 +int intel_pinctrl_probe_by_hid(struct platform_device *pdev) +{ + const struct intel_pinctrl_soc_data *data; + + data = device_get_match_data(&pdev->dev); + if (!data) + return -ENODATA; + + return intel_pinctrl_probe(pdev, data); +} +EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_hid); + +int intel_pinctrl_probe_by_uid(struct platform_device *pdev) +{ + const struct intel_pinctrl_soc_data *data; + + data = intel_pinctrl_get_soc_data(pdev); + if (IS_ERR(data)) + return PTR_ERR(data); + + return intel_pinctrl_probe(pdev, data); +} +EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_uid); + +const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_device *pdev) +{ + const struct intel_pinctrl_soc_data *data = NULL; + const struct intel_pinctrl_soc_data **table; + struct acpi_device *adev; + unsigned int i; + + adev = ACPI_COMPANION(&pdev->dev); + if (adev) { + const void *match = device_get_match_data(&pdev->dev); + + table = (const struct intel_pinctrl_soc_data **)match; + for (i = 0; table[i]; i++) { + if (!strcmp(adev->pnp.unique_id, table[i]->uid)) { + data = table[i]; + break; + } + } + } else { + const struct platform_device_id *id; + + id = platform_get_device_id(pdev); + if (!id) + return ERR_PTR(-ENODEV); + + table = (const struct intel_pinctrl_soc_data **)id->driver_data; + data = table[pdev->id]; + } + + return data ?: ERR_PTR(-ENODATA); +} +EXPORT_SYMBOL_GPL(intel_pinctrl_get_soc_data); +#endif + +#ifdef CONFIG_PM_SLEEP +static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int pin) +{ + const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin); + + if (!pd || !intel_pad_usable(pctrl, pin)) + return false; + + /* + * Only restore the pin if it is actually in use by the kernel (or + * by userspace). It is possible that some pins are used by the + * BIOS during resume and those are not always locked down so leave + * them alone. + */ + if (pd->mux_owner || pd->gpio_owner || + gpiochip_line_is_irq(&pctrl->chip, intel_pin_to_gpio(pctrl, pin))) + return true; + + return false; +} + +int wb_intel_pinctrl_suspend_noirq(struct device *dev) +{ + struct intel_pinctrl *pctrl = dev_get_drvdata(dev); + struct intel_community_context *communities; + struct intel_pad_context *pads; + int i; + + pads = pctrl->context.pads; + for (i = 0; i < pctrl->soc->npins; i++) { + const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i]; + void __iomem *padcfg; + u32 val; + + if (!intel_pinctrl_should_save(pctrl, desc->number)) + continue; + + val = readl(intel_get_padcfg(pctrl, desc->number, PADCFG0)); + pads[i].padcfg0 = val & ~PADCFG0_GPIORXSTATE; + val = readl(intel_get_padcfg(pctrl, desc->number, PADCFG1)); + pads[i].padcfg1 = val; + + padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG2); + if (padcfg) + pads[i].padcfg2 = readl(padcfg); + } + + communities = pctrl->context.communities; + for (i = 0; i < pctrl->ncommunities; i++) { + struct intel_community *community = &pctrl->communities[i]; + void __iomem *base; + unsigned int gpp; + + base = community->regs + community->ie_offset; + for (gpp = 0; gpp < community->ngpps; gpp++) + communities[i].intmask[gpp] = readl(base + gpp * 4); + + base = community->regs + community->hostown_offset; + for (gpp = 0; gpp < community->ngpps; gpp++) + communities[i].hostown[gpp] = readl(base + gpp * 4); + } + + return 0; +} +EXPORT_SYMBOL_GPL(wb_intel_pinctrl_suspend_noirq); + +static void intel_gpio_irq_init(struct intel_pinctrl *pctrl) +{ + size_t i; + + for (i = 0; i < pctrl->ncommunities; i++) { + const struct intel_community *community; + void __iomem *base; + unsigned int gpp; + + community = &pctrl->communities[i]; + base = community->regs; + + for (gpp = 0; gpp < community->ngpps; gpp++) { + /* Mask and clear all interrupts */ + writel(0, base + community->ie_offset + gpp * 4); + writel(0xffff, base + community->is_offset + gpp * 4); + } + } +} + +static bool intel_gpio_update_reg(void __iomem *reg, u32 mask, u32 value) +{ + u32 curr, updated; + + curr = readl(reg); + + updated = (curr & ~mask) | (value & mask); + if (curr == updated) + return false; + + writel(updated, reg); + return true; +} + +static void intel_restore_hostown(struct intel_pinctrl *pctrl, unsigned int c, + void __iomem *base, unsigned int gpp, u32 saved) +{ + const struct intel_community *community = &pctrl->communities[c]; + const struct intel_padgroup *padgrp = &community->gpps[gpp]; + struct device *dev = pctrl->dev; + const char *dummy; + u32 requested = 0; + unsigned int i; + + if (padgrp->gpio_base == INTEL_GPIO_BASE_NOMAP) + return; + + for_each_requested_gpio_in_range(&pctrl->chip, i, padgrp->gpio_base, padgrp->size, dummy) + requested |= BIT(i); + + if (!intel_gpio_update_reg(base + gpp * 4, requested, saved)) + return; + + dev_dbg(dev, "restored hostown %u/%u %#08x\n", c, gpp, readl(base + gpp * 4)); +} + +static void intel_restore_intmask(struct intel_pinctrl *pctrl, unsigned int c, + void __iomem *base, unsigned int gpp, u32 saved) +{ + struct device *dev = pctrl->dev; + + if (!intel_gpio_update_reg(base + gpp * 4, ~0U, saved)) + return; + + dev_dbg(dev, "restored mask %u/%u %#08x\n", c, gpp, readl(base + gpp * 4)); +} + +static void intel_restore_padcfg(struct intel_pinctrl *pctrl, unsigned int pin, + unsigned int reg, u32 saved) +{ + u32 mask = (reg == PADCFG0) ? PADCFG0_GPIORXSTATE : 0; + unsigned int n = reg / sizeof(u32); + struct device *dev = pctrl->dev; + void __iomem *padcfg; + + padcfg = intel_get_padcfg(pctrl, pin, reg); + if (!padcfg) + return; + + if (!intel_gpio_update_reg(padcfg, ~mask, saved)) + return; + + dev_dbg(dev, "restored pin %u padcfg%u %#08x\n", pin, n, readl(padcfg)); +} + +int wb_intel_pinctrl_resume_noirq(struct device *dev) +{ + struct intel_pinctrl *pctrl = dev_get_drvdata(dev); + const struct intel_community_context *communities; + const struct intel_pad_context *pads; + int i; + + /* Mask all interrupts */ + intel_gpio_irq_init(pctrl); + + pads = pctrl->context.pads; + for (i = 0; i < pctrl->soc->npins; i++) { + const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i]; + + if (!intel_pinctrl_should_save(pctrl, desc->number)) + continue; + + intel_restore_padcfg(pctrl, desc->number, PADCFG0, pads[i].padcfg0); + intel_restore_padcfg(pctrl, desc->number, PADCFG1, pads[i].padcfg1); + intel_restore_padcfg(pctrl, desc->number, PADCFG2, pads[i].padcfg2); + } + + communities = pctrl->context.communities; + for (i = 0; i < pctrl->ncommunities; i++) { + struct intel_community *community = &pctrl->communities[i]; + void __iomem *base; + unsigned int gpp; + + base = community->regs + community->ie_offset; + for (gpp = 0; gpp < community->ngpps; gpp++) + intel_restore_intmask(pctrl, i, base, gpp, communities[i].intmask[gpp]); + + base = community->regs + community->hostown_offset; + for (gpp = 0; gpp < community->ngpps; gpp++) + intel_restore_hostown(pctrl, i, base, gpp, communities[i].hostown[gpp]); + } + + return 0; +} +EXPORT_SYMBOL_GPL(wb_intel_pinctrl_resume_noirq); +#endif + +MODULE_AUTHOR("Mathias Nyman "); +MODULE_AUTHOR("Mika Westerberg "); +MODULE_DESCRIPTION("Intel pinctrl/GPIO core driver"); +MODULE_LICENSE("GPL v2"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.h new file mode 100644 index 000000000000..5ed0cc0651a5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.h @@ -0,0 +1,275 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Core pinctrl/GPIO driver for Intel GPIO controllers + * + * Copyright (C) 2015, Intel Corporation + * Authors: Mathias Nyman + * Mika Westerberg + */ + +#ifndef PINCTRL_INTEL_H +#define PINCTRL_INTEL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +struct platform_device; +struct device; + +#define GPIO_RES_MAX (2) + +typedef struct wb_gpio_data_s { + int irq; + void __iomem *res[GPIO_RES_MAX]; + unsigned int pci_domain; + unsigned int pci_bus; + unsigned int pci_slot; + unsigned int pci_fn; + unsigned int pci_bar; + struct pci_dev *pci_dev; + void __iomem *pci_mem_base; +} wb_gpio_data_t; + +/** + * struct intel_pingroup - Description about group of pins + * @name: Name of the groups + * @pins: All pins in this group + * @npins: Number of pins in this groups + * @mode: Native mode in which the group is muxed out @pins. Used if @modes + * is %NULL. + * @modes: If not %NULL this will hold mode for each pin in @pins + */ +struct intel_pingroup { + const char *name; + const unsigned int *pins; + size_t npins; + unsigned short mode; + const unsigned int *modes; +}; + +/** + * struct intel_function - Description about a function + * @name: Name of the function + * @groups: An array of groups for this function + * @ngroups: Number of groups in @groups + */ +struct intel_function { + const char *name; + const char * const *groups; + size_t ngroups; +}; + +/** + * struct intel_padgroup - Hardware pad group information + * @reg_num: GPI_IS register number + * @base: Starting pin of this group + * @size: Size of this group (maximum is 32). + * @gpio_base: Starting GPIO base of this group + * @padown_num: PAD_OWN register number (assigned by the core driver) + * + * If pad groups of a community are not the same size, use this structure + * to specify them. + */ +struct intel_padgroup { + unsigned int reg_num; + unsigned int base; + unsigned int size; + int gpio_base; + unsigned int padown_num; +}; + +/** + * enum - Special treatment for GPIO base in pad group + * + * @INTEL_GPIO_BASE_ZERO: force GPIO base to be 0 + * @INTEL_GPIO_BASE_NOMAP: no GPIO mapping should be created + * @INTEL_GPIO_BASE_MATCH: matches with starting pin number + */ +enum { + INTEL_GPIO_BASE_ZERO = -2, + INTEL_GPIO_BASE_NOMAP = -1, + INTEL_GPIO_BASE_MATCH = 0, +}; + +/** + * struct intel_community - Intel pin community description + * @barno: MMIO BAR number where registers for this community reside + * @padown_offset: Register offset of PAD_OWN register from @regs. If %0 + * then there is no support for owner. + * @padcfglock_offset: Register offset of PADCFGLOCK from @regs. If %0 then + * locking is not supported. + * @hostown_offset: Register offset of HOSTSW_OWN from @regs. If %0 then it + * is assumed that the host owns the pin (rather than + * ACPI). + * @is_offset: Register offset of GPI_IS from @regs. + * @ie_offset: Register offset of GPI_IE from @regs. + * @features: Additional features supported by the hardware + * @pin_base: Starting pin of pins in this community + * @npins: Number of pins in this community + * @gpp_size: Maximum number of pads in each group, such as PADCFGLOCK, + * HOSTSW_OWN, GPI_IS, GPI_IE. Used when @gpps is %NULL. + * @gpp_num_padown_regs: Number of pad registers each pad group consumes at + * minimum. Use %0 if the number of registers can be + * determined by the size of the group. + * @gpps: Pad groups if the controller has variable size pad groups + * @ngpps: Number of pad groups in this community + * @pad_map: Optional non-linear mapping of the pads + * @nirqs: Optional total number of IRQs this community can generate + * @acpi_space_id: Optional address space ID for ACPI OpRegion handler + * @regs: Community specific common registers (reserved for core driver) + * @pad_regs: Community specific pad registers (reserved for core driver) + * + * In some of Intel GPIO host controllers this driver supports each pad group + * is of equal size (except the last one). In that case the driver can just + * fill in @gpp_size field and let the core driver to handle the rest. If + * the controller has pad groups of variable size the client driver can + * pass custom @gpps and @ngpps instead. + */ +struct intel_community { + unsigned int barno; + unsigned int padown_offset; + unsigned int padcfglock_offset; + unsigned int hostown_offset; + unsigned int is_offset; + unsigned int ie_offset; + unsigned int features; + unsigned int pin_base; + size_t npins; + unsigned int gpp_size; + unsigned int gpp_num_padown_regs; + const struct intel_padgroup *gpps; + size_t ngpps; + const unsigned int *pad_map; + unsigned short nirqs; + unsigned short acpi_space_id; + + /* Reserved for the core driver */ + void __iomem *regs; + void __iomem *pad_regs; + u32 dw_base; +}; + +/* Additional features supported by the hardware */ +#define PINCTRL_FEATURE_DEBOUNCE BIT(0) +#define PINCTRL_FEATURE_1K_PD BIT(1) + +/** + * PIN_GROUP - Declare a pin group + * @n: Name of the group + * @p: An array of pins this group consists + * @m: Mode which the pins are put when this group is active. Can be either + * a single integer or an array of integers in which case mode is per + * pin. + */ +#define PIN_GROUP(n, p, m) \ + { \ + .name = (n), \ + .pins = (p), \ + .npins = ARRAY_SIZE((p)), \ + .mode = __builtin_choose_expr( \ + __builtin_constant_p((m)), (m), 0), \ + .modes = __builtin_choose_expr( \ + __builtin_constant_p((m)), NULL, (m)), \ + } + +#define FUNCTION(n, g) \ + { \ + .name = (n), \ + .groups = (g), \ + .ngroups = ARRAY_SIZE((g)), \ + } + +/** + * struct intel_pinctrl_soc_data - Intel pin controller per-SoC configuration + * @uid: ACPI _UID for the probe driver use if needed + * @pins: Array if pins this pinctrl controls + * @npins: Number of pins in the array + * @groups: Array of pin groups + * @ngroups: Number of groups in the array + * @functions: Array of functions + * @nfunctions: Number of functions in the array + * @communities: Array of communities this pinctrl handles + * @ncommunities: Number of communities in the array + * + * The @communities is used as a template by the core driver. It will make + * copy of all communities and fill in rest of the information. + */ +struct intel_pinctrl_soc_data { + const char *uid; + const struct pinctrl_pin_desc *pins; + size_t npins; + const struct intel_pingroup *groups; + size_t ngroups; + const struct intel_function *functions; + size_t nfunctions; + const struct intel_community *communities; + size_t ncommunities; +}; + +struct intel_pad_context; +struct intel_community_context; + +/** + * struct intel_pinctrl_context - context to be saved during suspend-resume + * @pads: Opaque context per pad (driver dependent) + * @communities: Opaque context per community (driver dependent) + */ +struct intel_pinctrl_context { + struct intel_pad_context *pads; + struct intel_community_context *communities; +}; + +/** + * struct intel_pinctrl - Intel pinctrl private structure + * @dev: Pointer to the device structure + * @lock: Lock to serialize register access + * @pctldesc: Pin controller description + * @pctldev: Pointer to the pin controller device + * @chip: GPIO chip in this pin controller + * @irqchip: IRQ chip in this pin controller + * @soc: SoC/PCH specific pin configuration data + * @communities: All communities in this pin controller + * @ncommunities: Number of communities in this pin controller + * @context: Configuration saved over system sleep + * @irq: pinctrl/GPIO chip irq number + */ +struct intel_pinctrl { + struct device *dev; + raw_spinlock_t lock; + struct pinctrl_desc pctldesc; + struct pinctrl_dev *pctldev; + struct gpio_chip chip; + struct irq_chip irqchip; + const struct intel_pinctrl_soc_data *soc; + struct intel_community *communities; + size_t ncommunities; + struct intel_pinctrl_context context; + int irq; +}; + +int wb_pinctrl_probe(struct platform_device *pdev, const struct intel_pinctrl_soc_data *soc_data); + +#if 0 +const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_device *pdev); +int intel_pinctrl_probe_by_hid(struct platform_device *pdev); +int intel_pinctrl_probe_by_uid(struct platform_device *pdev); +#endif + +#ifdef CONFIG_PM_SLEEP +int wb_intel_pinctrl_suspend_noirq(struct device *dev); +int wb_intel_pinctrl_resume_noirq(struct device *dev); +#endif + +#define INTEL_PINCTRL_PM_OPS(_name) \ +const struct dev_pm_ops _name = { \ + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(wb_intel_pinctrl_suspend_noirq, \ + wb_intel_pinctrl_resume_noirq) \ +} + +#endif /* PINCTRL_INTEL_H */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/Makefile new file mode 100644 index 000000000000..369b64605dd3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/Makefile @@ -0,0 +1,20 @@ +pes_parent_dir:=$(shell pwd)/$(lastword $(MAKEFILE_LIST)) +pes_parent_dir:=$(shell dirname $(pes_parent_dir)) + +SUBDIRS=$(shell ls -l | grep ^d | awk '{if($$9 != "build") print $$9}') +INC = -I./inc + +all : CHECK $(SUBDIRS) +CHECK : + @echo $(pes_parent_dir) + +$(SUBDIRS):ECHO + #@echo $@ + make -C $@ + +ECHO: + @echo $(SUBDIRS) + +.PHONY : clean +clean : + -rm -rf $(SYSFS_OUT_PUT) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/Makefile new file mode 100644 index 000000000000..e516b70b3d92 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/Makefile @@ -0,0 +1,25 @@ +PWD = $(shell pwd) + +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall +SUBDIR_CFG = cfg +plat_dfd-objs := dfd_module.o dfd_fan_driver.o \ +dfd_slot_driver.o \ +dfd_sensors_driver.o \ +dfd_psu_driver.o \ +dfd_sff_driver.o \ +$(SUBDIR_CFG)/dfd_cfg.o \ +$(SUBDIR_CFG)/dfd_cfg_adapter.o \ +$(SUBDIR_CFG)/dfd_cfg_file.o \ +$(SUBDIR_CFG)/dfd_cfg_info.o \ +$(SUBDIR_CFG)/dfd_cfg_listnode.o \ + +obj-m := plat_dfd.o +all: + $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules + @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi + cp -p $(PWD)/*.ko $(module_out_put_dir) +clean: + rm -f $(PWD)/*.o $(PWD)/$(SUBDIR_CFG)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/$(SUBDIR_CFG)/.*.cmd $(PWD)/*.mod + rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order + rm -rf $(PWD)/.tmp_versions diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c new file mode 100644 index 000000000000..3d05621ef031 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c @@ -0,0 +1,815 @@ +#include +#include +#include +#include +#include +#include + +#include "../include/dfd_module.h" +#include "../include/dfd_cfg_file.h" +#include "../include/dfd_cfg_listnode.h" +#include "../include/dfd_cfg_info.h" +#include "../include/dfd_cfg_adapter.h" +#include "../include/dfd_cfg.h" +#include "../../dev_sysfs/include/sysfs_common.h" + +#ifdef DFD_CFG_ITEM +#undef DFD_CFG_ITEM +#endif +#define DFD_CFG_ITEM(_id, _name, _index_min, _index_max) _name, +static char *dfd_cfg_item_name[] = { + DFD_CFG_ITEM_ALL +}; + +#ifdef DFD_CFG_ITEM +#undef DFD_CFG_ITEM +#endif +#define DFD_CFG_ITEM(_id, _name, _index_min, _index_max) {_index_min, _index_max}, +static index_range_t dfd_cfg_item_index_range[] = { + DFD_CFG_ITEM_ALL +}; + +static lnode_root_t dfd_ko_cfg_list_root; + +static void dfd_ko_cfg_del_space_lf_cr(char *str) +{ + int i, j; + int len; + + len = strlen(str); + for (i = 0; i < len; i++) { + if (str[i] == '\r' || str[i] == '\n' || str[i] == ' ') { + for (j = i; j < len - 1; j++) { + str[j] = str[j + 1]; + } + str[j] = '\0'; + len--; + i--; + } + } +} + +static int dfd_ko_cfg_get_value_from_char(char *value_str, int32_t *value, int line_num) +{ + int value_tmp = 0; + + if (strlen(value_str) == 0) { + DBG_DEBUG(DBG_WARN, "line%d: value str is empty\n", line_num); + *value = DFD_CFG_EMPTY_VALUE; + return 0; + } + + if ((strlen(value_str) > 2) && (value_str[0] == '0') + && (value_str[1] == 'x' || value_str[1] == 'X')) { + value_tmp = (int32_t)simple_strtol(value_str, NULL, 16); + } else { + value_tmp = (int32_t)simple_strtol(value_str, NULL, 10); + } + + *value = value_tmp; + return 0; +} + +static int dfd_ko_cfg_analyse_index(char *index_str, int *index1, int *index2, int line_num) +{ + int rv; + char *index1_begin_char, *index2_begin_char; + + if (index_str[0] != '_') { + DBG_DEBUG(DBG_ERROR, "line%d: no '-' between name and index1\n", line_num); + return -1; + } + + index1_begin_char = index_str; + rv = dfd_ko_cfg_get_value_from_char(++index1_begin_char, index1, line_num); + if (rv < 0) { + return -1; + } + + if (index2 == NULL) { + return 0; + } + + index2_begin_char = strchr(index1_begin_char, '_'); + if (index2_begin_char == NULL) { + DBG_DEBUG(DBG_ERROR, "line%d: no '-' between index1 and index2\n", line_num); + return -1; + } else { + rv = dfd_ko_cfg_get_value_from_char(++index2_begin_char, index2, line_num); + if (rv < 0) { + return -1; + } + } + + return 0; +} + +static int dfd_ko_cfg_check_array_index(index_range_t *index_range, int *index1, int *index2, + int line_num) +{ + + if ((*index1 < 0) || (*index1 > index_range->index1_max)) { + DBG_DEBUG(DBG_ERROR, "line%d: index1[%d] invalid, max=%d\n", line_num, *index1, + index_range->index1_max); + return -1; + } + + if (index2 == NULL) { + return 0; + } + + if ((*index2 < 0) || (*index2 > index_range->index2_max)) { + DBG_DEBUG(DBG_ERROR, "line%d: index2[%d] invalid, max=%d\n", line_num, *index2, + index_range->index2_max); + return -1; + } + + return 0; +} + +static int dfd_ko_cfg_get_index(char *index_str, index_range_t *index_range, int *index1, + int *index2, int line_num) +{ + int rv; + + if (index_range->index2_max == INDEX_NOT_EXIST) { + index2 = NULL; + } + + rv = dfd_ko_cfg_analyse_index(index_str, index1, index2, line_num); + if (rv < 0) { + return -1; + } + + rv = dfd_ko_cfg_check_array_index(index_range, index1, index2, line_num); + if (rv < 0) { + return -1; + } + + return 0; +} + +static int dfd_ko_cfg_add_int_item(int key, int value, int line_num) +{ + int rv; + int *int_cfg; + + int_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); + if (int_cfg == NULL) { + + int_cfg = (int *)kmalloc(sizeof(int), GFP_KERNEL); + if (int_cfg == NULL) { + DBG_DEBUG(DBG_ERROR, "line%d: kmalloc int fail\n", line_num); + return -1; + } + + *int_cfg = value; + rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, int_cfg); + if (rv == 0) { + DBG_DEBUG(DBG_VERBOSE, "line%d: add int item[%d] success, key=0x%08x\n", line_num, value, key); + } else { + kfree(int_cfg); + int_cfg = NULL; + DBG_DEBUG(DBG_ERROR, "line%d: add int item[%d] fail, key=0x%08x rv=%d \n", line_num, value, key, rv); + return -1; + } + } else { + + DBG_DEBUG(DBG_WARN, "line%d: replace int item[%d->%d], key=0x%08x\n", line_num, *int_cfg, value, key); + *int_cfg = value; + } + + return 0; +} + +static int dfd_ko_cfg_analyse_int_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, char *arg_value, + char *cfg_pre, index_range_t *index_range, int line_num) +{ + int rv; + int index1 = 0, index2 = 0; + int value, key; + char *arg_name_tmp; + + if (index_range->index1_max != INDEX_NOT_EXIST) { + arg_name_tmp = arg_name + strlen(cfg_pre); + rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); + if (rv < 0) { + return -1; + } + } + + rv = dfd_ko_cfg_get_value_from_char(arg_value, &value, line_num); + if (rv < 0) { + return -1; + } + + key = DFD_CFG_KEY(cfg_item_id, index1, index2); + rv = dfd_ko_cfg_add_int_item(key, value, line_num); + if (rv < 0) { + return -1; + } + + return 0; +} + +static int dfd_ko_cfg_add_str_item(int key, char *str, int line_num) +{ + int rv; + char *str_cfg; + + str_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); + if (str_cfg == NULL) { + + str_cfg = (char *)kmalloc(DFD_CFG_STR_MAX_LEN, GFP_KERNEL); + if (str_cfg == NULL) { + DBG_DEBUG(DBG_ERROR, "line%d: kmalloc str[%lu] fail\n", line_num, strlen(str)); + return -1; + } + mem_clear(str_cfg, DFD_CFG_STR_MAX_LEN); + strncpy(str_cfg, str, DFD_CFG_STR_MAX_LEN - 1); + + rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, str_cfg); + if (rv == 0) { + DBG_DEBUG(DBG_VERBOSE, "line%d: add string item[%s] success, key=0x%08x\n", line_num, str_cfg, key); + } else { + kfree(str_cfg); + str_cfg = NULL; + DBG_DEBUG(DBG_ERROR, "line%d: add string item[%s] fail, key=0x%08x rv=%d \n", line_num, str_cfg, key, rv); + return -1; + } + } else { + DBG_DEBUG(DBG_WARN, "line%d: replace string item[%s->%s], key=0x%08x\n", line_num, str_cfg, str, key); + mem_clear(str_cfg, DFD_CFG_STR_MAX_LEN); + strncpy(str_cfg, str, DFD_CFG_STR_MAX_LEN - 1); + } + + return 0; +} + +static int dfd_ko_cfg_analyse_str_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, char *arg_value, + char *cfg_pre, index_range_t *index_range, int line_num) +{ + int rv; + int index1 = 0, index2 = 0; + int btree_key; + char *arg_name_tmp; + + if (index_range->index1_max != INDEX_NOT_EXIST) { + arg_name_tmp = arg_name + strlen(cfg_pre); + rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); + if (rv < 0) { + return -1; + } + } + + if (strlen(arg_value) >= DFD_CFG_STR_MAX_LEN) { + DBG_DEBUG(DBG_ERROR, "line%d: string item[%s] is too long \n", line_num, arg_value); + return -1; + } + + btree_key = DFD_CFG_KEY(cfg_item_id, index1, index2); + rv = dfd_ko_cfg_add_str_item(btree_key, arg_value, line_num); + if (rv < 0) { + return -1; + } + + return 0; +} + +static int dfd_ko_cfg_get_i2c_dev_member(char *member_str, dfd_i2c_dev_mem_t *member, int line_num) +{ + dfd_i2c_dev_mem_t mem_index; + + for (mem_index = DFD_I2C_DEV_MEM_BUS; mem_index < DFD_I2C_DEV_MEM_END; mem_index++) { + if (memcmp(member_str, g_dfd_i2c_dev_mem_str[mem_index], + strlen(g_dfd_i2c_dev_mem_str[mem_index])) == 0) { + *member = mem_index; + return 0; + } + } + + DBG_DEBUG(DBG_ERROR, "line%d: i2c dev member[%s] invalid\n", line_num, member_str); + return -1; +} + +static void dfd_ko_cfg_set_i2c_dev_mem_value(dfd_i2c_dev_t *i2c_dev, dfd_i2c_dev_mem_t member, + int value) +{ + switch (member) { + case DFD_I2C_DEV_MEM_BUS: + i2c_dev->bus = value; + break; + case DFD_I2C_DEV_MEM_ADDR: + i2c_dev->addr = value; + break; + default: + break; + } +} + +static int dfd_ko_cfg_add_i2c_dev_item(int key, dfd_i2c_dev_mem_t member, int value, int line_num) +{ + int rv; + dfd_i2c_dev_t *i2c_dev_cfg; + + i2c_dev_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); + if (i2c_dev_cfg == NULL) { + + i2c_dev_cfg = (dfd_i2c_dev_t *)kmalloc(sizeof(dfd_i2c_dev_t), GFP_KERNEL); + if (i2c_dev_cfg == NULL) { + DBG_DEBUG(DBG_ERROR, "line%d: kmalloc i2c_dev fail\n", line_num); + return -1; + } + mem_clear(i2c_dev_cfg, sizeof(dfd_i2c_dev_t)); + + dfd_ko_cfg_set_i2c_dev_mem_value(i2c_dev_cfg, member, value); + rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, i2c_dev_cfg); + if (rv == 0) { + DBG_DEBUG(DBG_VERBOSE, "line%d: add i2c_dev item[%s=%d] success, key=0x%08x\n", line_num, + g_dfd_i2c_dev_mem_str[member], value, key); + } else { + kfree(i2c_dev_cfg); + i2c_dev_cfg = NULL; + DBG_DEBUG(DBG_ERROR, "line%d: add i2c_dev item[%s=%d] fail, key=0x%08x rv=%d\n", line_num, + g_dfd_i2c_dev_mem_str[member], value, key, rv); + return -1; + } + } else { + + DBG_DEBUG(DBG_VERBOSE, "line%d: replace i2c_dev item[%s=%d], key=0x%08x\n", line_num, + g_dfd_i2c_dev_mem_str[member], value, key); + dfd_ko_cfg_set_i2c_dev_mem_value(i2c_dev_cfg, member, value); + } + + return 0; +} + +static int dfd_ko_cfg_analyse_i2c_dev_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, + char *arg_value, char *cfg_pre, index_range_t *index_range, int line_num) +{ + int rv; + int index1 = 0, index2 = 0; + int value, key; + char *arg_name_tmp; + dfd_i2c_dev_mem_t member; + + arg_name_tmp = arg_name + strlen(cfg_pre); + rv = dfd_ko_cfg_get_i2c_dev_member(arg_name_tmp, &member, line_num); + if (rv < 0) { + return -1; + } + + if (index_range->index1_max != INDEX_NOT_EXIST) { + arg_name_tmp += strlen(g_dfd_i2c_dev_mem_str[member]); + rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); + if (rv < 0) { + return -1; + } + } + + rv = dfd_ko_cfg_get_value_from_char(arg_value, &value, line_num); + if (rv < 0) { + return -1; + } + + key = DFD_CFG_KEY(cfg_item_id, index1, index2); + rv = dfd_ko_cfg_add_i2c_dev_item(key, member, value, line_num); + if (rv < 0) { + return -1; + } + + return 0; +} + +static int dfd_ko_cfg_get_enum_value_by_str(char *enum_val_str[], int enum_val_end, char *buf) +{ + int i; + int enum_val; + + enum_val = DFD_CFG_INVALID_VALUE; + for (i = 0; i < enum_val_end; i++) { + if (memcmp(buf, enum_val_str[i], strlen(enum_val_str[i])) == 0) { + enum_val = i; + break; + } + } + + return enum_val; +} + +static int dfd_ko_cfg_get_info_ctrl_member(char *member_str, info_ctrl_mem_t *member, int line_num) +{ + info_ctrl_mem_t mem_index; + + for (mem_index = INFO_CTRL_MEM_MODE; mem_index < INFO_CTRL_MEM_END; mem_index++) { + if (memcmp(member_str, g_info_ctrl_mem_str[mem_index], + strlen(g_info_ctrl_mem_str[mem_index])) == 0) { + *member = mem_index; + return 0; + } + } + + DBG_DEBUG(DBG_ERROR, "line%d: info ctrl member[%s] invalid\n", line_num, member_str); + return -1; +} + +static void dfd_ko_cfg_set_info_ctrl_mem_value(info_ctrl_t *info_ctrl, info_ctrl_mem_t member, + char *buf_val, int line_num) +{ + switch (member) { + case INFO_CTRL_MEM_MODE: + info_ctrl->mode = dfd_ko_cfg_get_enum_value_by_str(g_info_ctrl_mode_str, INFO_CTRL_MODE_END, buf_val);; + break; + case INFO_CTRL_MEM_INT_CONS: + dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_cons), line_num); + break; + case INFO_CTRL_MEM_SRC: + info_ctrl->src = dfd_ko_cfg_get_enum_value_by_str(g_info_src_str, INFO_SRC_END, buf_val); + break; + case INFO_CTRL_MEM_FRMT: + info_ctrl->frmt = dfd_ko_cfg_get_enum_value_by_str(g_info_frmt_str, INFO_FRMT_END, buf_val); + break; + case INFO_CTRL_MEM_POLA: + info_ctrl->pola = dfd_ko_cfg_get_enum_value_by_str(g_info_pola_str, INFO_POLA_END, buf_val); + break; + case INFO_CTRL_MEM_FPATH: + mem_clear(info_ctrl->fpath, sizeof(info_ctrl->fpath)); + strncpy(info_ctrl->fpath, buf_val, sizeof(info_ctrl->fpath) - 1); + break; + case INFO_CTRL_MEM_ADDR: + dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->addr), line_num); + break; + case INFO_CTRL_MEM_LEN: + dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->len), line_num); + break; + case INFO_CTRL_MEM_BIT_OFFSET: + dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->bit_offset), line_num); + break; + case INFO_CTRL_MEM_STR_CONS: + mem_clear(info_ctrl->str_cons, sizeof(info_ctrl->str_cons)); + strncpy(info_ctrl->str_cons, buf_val, sizeof(info_ctrl->str_cons) - 1); + break; + case INFO_CTRL_MEM_INT_EXTRA1: + dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_extra1), line_num); + break; + case INFO_CTRL_MEM_INT_EXTRA2: + dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_extra2), line_num); + break; + case INFO_CTRL_MEM_INT_EXTRA3: + dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_extra3), line_num); + break; + default: + break; + } +} + +static int dfd_ko_cfg_add_info_ctrl_item(int key, info_ctrl_mem_t member, char *buf_val, + int line_num) +{ + int rv; + info_ctrl_t *info_ctrl_cfg; + + info_ctrl_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); + if (info_ctrl_cfg == NULL) { + + info_ctrl_cfg = (info_ctrl_t *)kmalloc(sizeof(info_ctrl_t), GFP_KERNEL); + if (info_ctrl_cfg == NULL) { + DBG_DEBUG(DBG_ERROR, "line%d: kmalloc info_ctrl fail\n", line_num); + return -1; + } + mem_clear(info_ctrl_cfg, sizeof(info_ctrl_t)); + + dfd_ko_cfg_set_info_ctrl_mem_value(info_ctrl_cfg, member, buf_val, line_num); + rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, info_ctrl_cfg); + if (rv == 0) { + DBG_DEBUG(DBG_VERBOSE, "line%d: add info_ctrl item[%s=%s] success, key=0x%08x\n", line_num, + g_info_ctrl_mem_str[member], buf_val, key); + } else { + kfree(info_ctrl_cfg); + info_ctrl_cfg = NULL; + DBG_DEBUG(DBG_ERROR, "line%d: add info_ctrl item[%s=%s] fail, key=0x%08x rv=%d\n", line_num, + g_info_ctrl_mem_str[member], buf_val, key, rv); + return -1; + } + } else { + + DBG_DEBUG(DBG_VERBOSE, "line%d: replace info_ctrl item[%s=%s], key=0x%08x\n", line_num, + g_info_ctrl_mem_str[member], buf_val, key); + dfd_ko_cfg_set_info_ctrl_mem_value(info_ctrl_cfg, member, buf_val, line_num); + } + + return 0; +} + +static int dfd_ko_cfg_analyse_info_ctrl_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, + char *arg_value, char *cfg_pre, index_range_t *index_range, int line_num) +{ + int rv; + int index1 = 0, index2 = 0; + int key; + char *arg_name_tmp; + info_ctrl_mem_t member; + + arg_name_tmp = arg_name + strlen(cfg_pre); + rv = dfd_ko_cfg_get_info_ctrl_member(arg_name_tmp, &member, line_num); + if (rv < 0) { + return -1; + } + + if (index_range->index1_max != INDEX_NOT_EXIST) { + arg_name_tmp += strlen(g_info_ctrl_mem_str[member]); + rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); + if (rv < 0) { + return -1; + } + } + + key = DFD_CFG_KEY(cfg_item_id, index1, index2); + rv = dfd_ko_cfg_add_info_ctrl_item(key, member, arg_value, line_num); + if (rv < 0) { + return -1; + } + + return 0; +} + +static int dfd_ko_cfg_analyse_config(char *arg_name, char*arg_value, int line_num) +{ + int i, rv = 0; + int cfg_item_num; + + cfg_item_num = sizeof(dfd_cfg_item_name) / sizeof(dfd_cfg_item_name[0]); + for (i = 0; i < cfg_item_num; i++) { + if (memcmp(arg_name, dfd_cfg_item_name[i], strlen(dfd_cfg_item_name[i])) == 0){ + if (DFD_CFG_ITEM_IS_INT(i)) { + rv = dfd_ko_cfg_analyse_int_item(i, arg_name, arg_value, dfd_cfg_item_name[i], + &(dfd_cfg_item_index_range[i]), line_num); + } else if (DFD_CFG_ITEM_IS_STRING(i)) { + rv = dfd_ko_cfg_analyse_str_item(i, arg_name, arg_value, dfd_cfg_item_name[i], + &(dfd_cfg_item_index_range[i]), line_num); + } else if (DFD_CFG_ITEM_IS_I2C_DEV(i)) { + rv = dfd_ko_cfg_analyse_i2c_dev_item(i, arg_name, arg_value, dfd_cfg_item_name[i], + &(dfd_cfg_item_index_range[i]), line_num); + } else if (DFD_CFG_ITEM_IS_INFO_CTRL(i)) { + rv = dfd_ko_cfg_analyse_info_ctrl_item(i, arg_name, arg_value, dfd_cfg_item_name[i], + &(dfd_cfg_item_index_range[i]), line_num); + } else { + rv = -1; + } + break; + } + } + + return rv; +} + +static int dfd_ko_cfg_cut_config_line(char *config_line, char *arg_name, char *arg_value) +{ + int i, j = 0, k = 0; + int len, name_value_flag = 0; + + len = strlen(config_line); + for (i = 0; i < len; i++) { + if (config_line[i] == '=') { + name_value_flag = 1; + continue; + } + + if (name_value_flag == 0) { + arg_name[j++] = config_line[i]; + } else { + arg_value[k++] = config_line[i]; + } + } + + if (name_value_flag == 0) { + return -1; + } else { + return 0; + } +} + +static int dfd_ko_cfg_analyse_config_line(char *config_line, int line_num) +{ + int rv; + char arg_name[DFD_CFG_NAME_MAX_LEN] = {0}; + char arg_value[DFD_CFG_VALUE_MAX_LEN] = {0}; + + dfd_ko_cfg_del_space_lf_cr(config_line); + + if (strlen(config_line) == 0) { + DBG_DEBUG(DBG_VERBOSE, "line%d: space line\n", line_num); + return 0; + } + + if (config_line[0] == '#') { + DBG_DEBUG(DBG_VERBOSE, "line%d: comment line[%s]\n", line_num, config_line); + return 0; + } + + rv = dfd_ko_cfg_cut_config_line(config_line, arg_name, arg_value); + if (rv < 0) { + DBG_DEBUG(DBG_VERBOSE, "line%d: [%s]no '=' between name and value\n", line_num, config_line); + return -1; + } + + DBG_DEBUG(DBG_VERBOSE, "line%d: config_line[%s] name[%s] value[%s]\n", line_num, config_line, arg_name, arg_value); + return dfd_ko_cfg_analyse_config(arg_name, arg_value, line_num); +} + +static int dfd_ko_cfg_analyse_config_file(char *fpath) +{ + int rv; + int line_num = 1; + kfile_ctrl_t kfile_ctrl; + char config_line[DFD_CFG_CMDLINE_MAX_LEN] = {0}; + + rv = kfile_open(fpath, &kfile_ctrl); + if (rv != KFILE_RV_OK) { + DBG_DEBUG(DBG_ERROR, "open config file[%s] fail, rv=%d\n", fpath, rv); + return -1; + } + + while(kfile_gets(config_line, sizeof(config_line), &kfile_ctrl) > 0){ + rv = dfd_ko_cfg_analyse_config_line(config_line, line_num++); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "!!!!file[%s] config line[%d %s] analyse fail\n", fpath, line_num - 1, + config_line); + break; + } + + (void)mem_clear(config_line, sizeof(config_line)); + + } + kfile_close(&kfile_ctrl); + + return rv; +} + +void *dfd_ko_cfg_get_item(int key) +{ + return lnode_find_node(&dfd_ko_cfg_list_root, key); +} + +static void dfd_ko_cfg_print_item(int key, const void *cfg) +{ + int item_id; + dfd_i2c_dev_t *i2c_dev; + info_ctrl_t *info_ctrl; + + if (cfg == NULL) { + DBG_DEBUG(DBG_ERROR, "input arguments error\n"); + return; + } + printk(KERN_INFO "**************************\n"); + printk(KERN_INFO "key=0x%08x\n", key); + + item_id = DFD_CFG_ITEM_ID(key); + if (DFD_CFG_ITEM_IS_INT(item_id)) { + printk(KERN_INFO "int=%d\n", *((int *)cfg)); + } else if (DFD_CFG_ITEM_IS_I2C_DEV(item_id)) { + i2c_dev = (dfd_i2c_dev_t *)cfg; + printk(KERN_INFO ".bus=0x%02x\n", i2c_dev->bus); + printk(KERN_INFO ".addr=0x%02x\n", i2c_dev->addr); + } else if (DFD_CFG_ITEM_IS_INFO_CTRL(item_id)) { + info_ctrl = (info_ctrl_t *)cfg; + printk(KERN_INFO ".mode=%s\n", g_info_ctrl_mode_str[info_ctrl->mode]); + printk(KERN_INFO ".int_cons=%d\n", info_ctrl->int_cons); + printk(KERN_INFO ".src=%s\n", g_info_src_str[info_ctrl->src]); + printk(KERN_INFO ".frmt=%s\n", g_info_frmt_str[info_ctrl->frmt]); + printk(KERN_INFO ".pola=%s\n", g_info_pola_str[info_ctrl->pola]); + printk(KERN_INFO ".fpath=%s\n", info_ctrl->fpath); + printk(KERN_INFO ".addr=0x%02x\n", info_ctrl->addr); + printk(KERN_INFO ".len=%d\n", info_ctrl->len); + printk(KERN_INFO ".bit_offset=%d\n", info_ctrl->bit_offset); + } else { + printk(KERN_INFO "item[%d] error!\n", item_id); + } +} + +void dfd_ko_cfg_show_item(int key) +{ + void *cfg; + + cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); + if (cfg == 0) { + printk(KERN_INFO "item[0x%08x] not exist\n", key); + return; + } + + dfd_ko_cfg_print_item(key, cfg); +} + +static int dfd_get_my_dev_type_by_file(void) +{ + struct file *fp; + loff_t pos; + int card_type; + char buf[DFD_PID_BUF_LEN]; + int ret; + + fp= filp_open(DFD_PUB_CARDTYPE_FILE, O_RDONLY, 0); + if (IS_ERR(fp)) { + DBG_DEBUG(DBG_VERBOSE, "open file fail!\n"); + return -1; + } + mem_clear(buf, DFD_PID_BUF_LEN); + pos = 0; + ret = kernel_read(fp, buf, DFD_PRODUCT_ID_LENGTH + 1, &pos); + if (ret < 0) { + DBG_DEBUG(DBG_VERBOSE, "kernel_read failed, path=%s, addr=0, size=%d, ret=%d\n", + DFD_PUB_CARDTYPE_FILE, DFD_PRODUCT_ID_LENGTH + 1, ret); + filp_close(fp, NULL); + return -1; + } + + card_type = simple_strtoul(buf, NULL, 10); + DBG_DEBUG(DBG_VERBOSE, "card_type 0x%x.\n", card_type); + + filp_close(fp, NULL); + return card_type; +} + +static int drv_get_my_dev_type(void) +{ + static int type = -1; + + if (type > 0) { + return type; + } + type = dfd_get_my_dev_type_by_file(); + DBG_DEBUG(DBG_VERBOSE, "ko board type %d\n", type); + return type; +} + +static int dfd_ko_cfg_init(void) +{ + int rv; + int card_type; + char file_name[32] = {0}; + char fpath[128] = {0}; + kfile_ctrl_t kfile_ctrl; + + rv = lnode_init_root(&dfd_ko_cfg_list_root); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "init list root fail, rv=%d\n", rv); + return -1; + } + + card_type = drv_get_my_dev_type(); + if (card_type > 0) { + snprintf(fpath, sizeof(fpath), "%s0x%x", DFD_KO_CFG_FILE_DIR, card_type); + rv = kfile_open(fpath, &kfile_ctrl); + if (rv != KFILE_RV_OK) { + DBG_DEBUG(DBG_VERBOSE, "open config file[%s] fail, rv=%d, maybe not exist\n", + fpath, rv); + + rv = kfile_open(DFD_KO_CFG_FILE_NAME, &kfile_ctrl); + if (rv != KFILE_RV_OK) { + DBG_DEBUG(DBG_ERROR, "open config file[%s] fail, rv=%d\n", DFD_KO_CFG_FILE_NAME, + rv); + return -1; + } + DBG_DEBUG(DBG_ERROR, "get config file from: %s, success.\n", DFD_KO_CFG_FILE_NAME); + } else { + DBG_DEBUG(DBG_VERBOSE, "get config file from: %s, success.\n", fpath); + } + } else { + DBG_DEBUG(DBG_VERBOSE, "get board id failed, try to get config file from: %s\n", + DFD_KO_CFG_FILE_NAME); + + rv = kfile_open(DFD_KO_CFG_FILE_NAME, &kfile_ctrl); + if (rv != KFILE_RV_OK) { + DBG_DEBUG(DBG_ERROR, "open config file[%s] fail, rv=%d\n", DFD_KO_CFG_FILE_NAME, rv); + return -1; + } + DBG_DEBUG(DBG_ERROR, "get config file from: %s, success.\n", DFD_KO_CFG_FILE_NAME); + } + + while (kfile_gets(file_name, sizeof(file_name), &kfile_ctrl) > 0) { + + dfd_ko_cfg_del_space_lf_cr(file_name); + mem_clear(fpath, sizeof(fpath)); + snprintf(fpath, sizeof(fpath), "%s%s.cfg", DFD_KO_CFG_FILE_DIR, file_name); + DBG_DEBUG(DBG_VERBOSE, ">>>>start parsing config file[%s]\n", fpath); + + rv = dfd_ko_cfg_analyse_config_file(fpath); + if (rv < 0) { + break; + } + } + kfile_close(&kfile_ctrl); + + return 0; +} + +int32_t dfd_dev_cfg_init(void) +{ + return dfd_ko_cfg_init(); +} + +void dfd_dev_cfg_exit(void) +{ + lnode_free_list(&dfd_ko_cfg_list_root); + return; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c new file mode 100644 index 000000000000..1d5ca7072f8f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c @@ -0,0 +1,351 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "../include/dfd_module.h" +#include "../include/dfd_cfg_file.h" +#include "../include/dfd_cfg.h" +#include "../include/dfd_cfg_adapter.h" +#include "../../dev_sysfs/include/sysfs_common.h" + +char *g_dfd_i2c_dev_mem_str[DFD_I2C_DEV_MEM_END] = { + ".bus", + ".addr", +}; + +static dfd_i2c_dev_t* dfd_ko_get_cpld_i2c_dev(int sub_slot, int cpld_id) +{ + int key; + dfd_i2c_dev_t *i2c_dev; + + key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_I2C_DEV, sub_slot, cpld_id); + i2c_dev = dfd_ko_cfg_get_item(key); + if (i2c_dev == NULL) { + DBG_DEBUG(DBG_ERROR, "get cpld[%d] i2c dev config fail, key=0x%08x\n", cpld_id, key); + return NULL; + } + + return i2c_dev; +} + +static int32_t dfd_ko_i2c_smbus_transfer(int read_write, int bus, int addr, int offset, uint8_t *buf, uint32_t size) +{ + int rv; + struct i2c_adapter *i2c_adap; + union i2c_smbus_data data; + + i2c_adap = i2c_get_adapter(bus); + if (i2c_adap == NULL) { + DBG_DEBUG(DBG_ERROR, "get i2c bus[%d] adapter fail\n", bus); + return -DFD_RV_DEV_FAIL; + } + + if (read_write == I2C_SMBUS_WRITE) { + data.byte = *buf; + } else { + data.byte = 0; + } + rv = i2c_smbus_xfer(i2c_adap, addr, 0, read_write, offset, I2C_SMBUS_BYTE_DATA, &data); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "i2c dev[bus=%d addr=0x%x offset=0x%x size=%d rw=%d] transfer fail, rv=%d\n", + bus, addr, offset, size, read_write, rv); + rv = -DFD_RV_DEV_FAIL; + } else { + DBG_DEBUG(DBG_VERBOSE, "i2c dev[bus=%d addr=0x%x offset=0x%x size=%d rw=%d] transfer success\n", + bus, addr, offset, size, read_write); + rv = DFD_RV_OK; + } + + if (read_write == I2C_SMBUS_READ) { + if (rv == DFD_RV_OK) { + *buf = data.byte; + } else { + *buf = 0; + } + } + + i2c_put_adapter(i2c_adap); + return rv; +} + +static int32_t dfd_ko_i2c_read_data(int bus, int addr, int offset, uint8_t *buf, uint32_t size) +{ + int i, rv; + for (i = 0; i < DFD_KO_CPLD_I2C_RETRY_TIMES; i++) { + rv = dfd_ko_i2c_smbus_transfer(I2C_SMBUS_READ, bus, addr, offset, buf, size); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "[%d]cpld read[offset=0x%x] fail, rv %d\n", i, addr, rv); + msleep(DFD_KO_CPLD_I2C_RETRY_SLEEP); + } else { + DBG_DEBUG(DBG_VERBOSE, "[%d]cpld read[offset=0x%x] success, value=0x%x\n", + i, addr, *buf); + break; + } + } + return rv; +} + +static int32_t dfd_ko_i2c_write_data(int bus, int addr, int offset, uint8_t data, uint32_t size) +{ + int i, rv; + for (i = 0; i < DFD_KO_CPLD_I2C_RETRY_TIMES; i++) { + rv = dfd_ko_i2c_smbus_transfer(I2C_SMBUS_WRITE, bus, addr, offset, &data, size); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "[%d]cpld write[offset=0x%x] fail, rv=%d\n", i, addr, rv); + msleep(DFD_KO_CPLD_I2C_RETRY_SLEEP); + } else { + DBG_DEBUG(DBG_VERBOSE, "[%d]cpld write[offset=0x%x, data=%d] success\n", i, addr, data); + break; + } + } + + return rv; +} + +static int32_t dfd_ko_cpld_i2c_read(int32_t addr, uint8_t *buf) +{ + int rv; + int sub_slot, cpld_id, cpld_addr; + dfd_i2c_dev_t *i2c_dev; + + if (buf == NULL) { + DBG_DEBUG(DBG_ERROR, "input arguments error\n"); + return -DFD_RV_INDEX_INVALID; + } + + sub_slot = DFD_KO_CPLD_GET_SLOT(addr); + cpld_id = DFD_KO_CPLD_GET_ID(addr); + cpld_addr = DFD_KO_CPLD_GET_INDEX(addr); + + i2c_dev = dfd_ko_get_cpld_i2c_dev(sub_slot, cpld_id); + if (i2c_dev == NULL) { + return -DFD_RV_DEV_NOTSUPPORT; + } + rv = dfd_ko_i2c_read_data(i2c_dev->bus, i2c_dev->addr, cpld_addr, buf, sizeof(uint8_t)); + + return rv; +} + +static int32_t dfd_ko_cpld_i2c_write(int32_t addr, uint8_t data) +{ + int rv; + int sub_slot, cpld_id, cpld_addr; + dfd_i2c_dev_t *i2c_dev; + + sub_slot = DFD_KO_CPLD_GET_SLOT(addr); + cpld_id = DFD_KO_CPLD_GET_ID(addr); + cpld_addr = DFD_KO_CPLD_GET_INDEX(addr); + + i2c_dev = dfd_ko_get_cpld_i2c_dev(sub_slot, cpld_id); + if (i2c_dev == NULL) { + return -DFD_RV_DEV_NOTSUPPORT; + } + + rv = dfd_ko_i2c_write_data(i2c_dev->bus, i2c_dev->addr, cpld_addr, data, sizeof(uint8_t)); + + return rv; +} + +static int32_t dfd_ko_cpld_io_read(int32_t addr, uint8_t *buf) +{ + int cpld_id, sub_slot, offset; + int key; + int *tmp; + uint16_t io_port; + + sub_slot = DFD_KO_CPLD_GET_SLOT(addr); + cpld_id = DFD_KO_CPLD_GET_ID(addr); + offset = DFD_KO_CPLD_GET_INDEX(addr); + + key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_LPC_DEV, sub_slot, cpld_id); + tmp = dfd_ko_cfg_get_item(key); + if (tmp == NULL) { + DBG_DEBUG(DBG_ERROR,"get cpld io base config fail, key=0x%08x\n", key); + return -1; + } + + io_port = (u16)(*tmp) + offset; + *buf = inb(io_port); + DBG_DEBUG(DBG_VERBOSE, "read cpld io port addr 0x%x, data 0x%x\n", io_port, *buf); + + return DFD_RV_OK; + +} + +static int32_t dfd_ko_cpld_io_write(int32_t addr, uint8_t data) +{ + int cpld_id, sub_slot, offset; + int key; + int *tmp; + uint16_t io_port; + + sub_slot = DFD_KO_CPLD_GET_SLOT(addr); + cpld_id = DFD_KO_CPLD_GET_ID(addr); + offset = DFD_KO_CPLD_GET_INDEX(addr); + + key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_LPC_DEV, sub_slot, cpld_id); + tmp = dfd_ko_cfg_get_item(key); + if (tmp == NULL) { + DBG_DEBUG(DBG_ERROR, "get cpld io base config fail, key=0x%08x\n", key); + return -1; + } + + io_port = (u16)(*tmp) + offset; + DBG_DEBUG(DBG_VERBOSE, "write cpld io port addr 0x%x, data 0x%x\n", io_port, data); + outb(data, (u16)io_port); + + return DFD_RV_OK; +} + +static int dfd_cfg_get_cpld_mode(int sub_slot, int cpld_id, int *mode) +{ + int key; + char *name; + + if (mode == NULL) { + DBG_DEBUG(DBG_ERROR, "input arguments error\n"); + return -DFD_RV_TYPE_ERR; + } + + key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_MODE, sub_slot, cpld_id); + name = dfd_ko_cfg_get_item(key); + if (name == NULL) { + DBG_DEBUG(DBG_ERROR, "get cpld[%d] mode info ctrl fail, key=0x%08x\n", cpld_id, key); + return -DFD_RV_NODE_FAIL; + } + + DBG_DEBUG(DBG_VERBOSE, "cpld_id %d mode_name %s.\n", cpld_id, name); + if (!strncmp(name, DFD_KO_CPLD_MODE_I2C_STRING, strlen(DFD_KO_CPLD_MODE_I2C_STRING))) { + *mode = DFD_CPLD_MODE_I2C; + } else if (!strncmp(name, DFD_KO_CPLD_MODE_LPC_STRING, strlen(DFD_KO_CPLD_MODE_LPC_STRING))) { + *mode = DFD_CPLD_MODE_LPC; + } else { + + *mode = DFD_CPLD_MODE_I2C; + } + + DBG_DEBUG(DBG_VERBOSE, "cpld_id %d mode %d.\n", cpld_id, *mode); + return 0; +} + +int32_t dfd_ko_cpld_read(int32_t addr, uint8_t *buf) +{ + int ret; + int sub_slot, cpld_id; + int cpld_mode; + + sub_slot = DFD_KO_CPLD_GET_SLOT(addr); + cpld_id = DFD_KO_CPLD_GET_ID(addr); + + ret = dfd_cfg_get_cpld_mode(sub_slot, cpld_id, &cpld_mode); + if (ret) { + DBG_DEBUG(DBG_WARN, "drv_get_cpld_mode sub_slot %d cpldid %d faile, set default i2c mode.\n", sub_slot, cpld_id); + cpld_mode = DFD_CPLD_MODE_I2C; + } + + if (cpld_mode == DFD_CPLD_MODE_I2C) { + ret = dfd_ko_cpld_i2c_read(addr, buf); + } else if (cpld_mode == DFD_CPLD_MODE_LPC) { + ret = dfd_ko_cpld_io_read(addr, buf); + } else { + DBG_DEBUG(DBG_ERROR, "cpld_mode %d invalid.\n", cpld_mode); + ret = -DFD_RV_DEV_NOTSUPPORT; + } + + DBG_DEBUG(DBG_VERBOSE, "addr 0x%x val 0x%x ret %d\n", addr, *buf, ret); + return ret; +} + +int32_t dfd_ko_cpld_write(int32_t addr, uint8_t val) +{ + int ret; + int sub_slot, cpld_id, cpld_mode; + + sub_slot = DFD_KO_CPLD_GET_SLOT(addr); + cpld_id = DFD_KO_CPLD_GET_ID(addr); + + ret = dfd_cfg_get_cpld_mode(sub_slot, cpld_id, &cpld_mode); + if (ret) { + DBG_DEBUG(DBG_ERROR, "drv_get_cpld_mode sub_slot %d cpldid %d faile, set default local_bus mode.\n", sub_slot, cpld_id); + cpld_mode = DFD_CPLD_MODE_I2C; + } + + if (cpld_mode == DFD_CPLD_MODE_I2C) { + ret = dfd_ko_cpld_i2c_write(addr, val); + } else if (cpld_mode == DFD_CPLD_MODE_LPC) { + ret = dfd_ko_cpld_io_write(addr, val); + } else { + DBG_DEBUG(DBG_ERROR, "cpld_mode %d invalid.\n", cpld_mode); + ret = -DFD_RV_DEV_NOTSUPPORT; + } + + DBG_DEBUG(DBG_VERBOSE, "addr 0x%x val 0x%x ret %d\n", addr, val, ret); + return ret; +} + +int32_t dfd_ko_i2c_read(int bus, int addr, int offset, uint8_t *buf, uint32_t size) +{ + int i, rv; + + for (i = 0; i < size; i++) { + rv = dfd_ko_i2c_read_data(bus, addr, offset, &buf[i], sizeof(uint8_t)); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "dfd_ko_i2c_read[bus=%d addr=0x%x offset=0x%x]fail, rv=%d\n", + bus, addr, offset, rv); + return rv; + } + offset++; + } + + return size; +} + +int32_t dfd_ko_i2c_write(int bus, int addr, int offset, uint8_t *buf, uint32_t size) +{ + int i, rv; + + for (i = 0; i < size; i++) { + rv = dfd_ko_i2c_write_data(bus, addr, offset, buf[i], sizeof(uint8_t)); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "dfd_ko_i2c_write[bus=%d addr=0x%x offset=0x%x]fail, rv=%d\n", + bus, addr, offset, rv); + return rv; + } + offset++; + } + + return size; + +} + +int32_t dfd_ko_read_file(char *fpath, int32_t addr, uint8_t *val, int32_t read_bytes) +{ + int32_t ret; + struct file *filp; + loff_t pos; + + if ((fpath == NULL) || (val == NULL) || (addr < 0) || (read_bytes < 0)) { + DBG_DEBUG(DBG_ERROR, "input arguments error, addr=%d read_bytes=%d\n", addr, read_bytes); + return -DFD_RV_INDEX_INVALID; + } + + filp = filp_open(fpath, O_RDONLY, 0); + if (IS_ERR(filp)){ + DBG_DEBUG(DBG_ERROR, "open file[%s] fail\n", fpath); + return -DFD_RV_DEV_FAIL; + } + + pos = addr; + ret = kernel_read(filp, val, read_bytes, &pos); + if (ret < 0) { + DBG_DEBUG(DBG_ERROR, "kernel_read failed, path=%s, addr=%d, size=%d, ret=%d\n", fpath, addr, read_bytes, ret); + ret = -DFD_RV_DEV_FAIL; + } + + filp_close(filp, NULL); + return ret; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c new file mode 100644 index 000000000000..8d77759ba7e0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c @@ -0,0 +1,236 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/dfd_cfg_file.h" +#include "../include/dfd_module.h" +#include "../../dev_sysfs/include/sysfs_common.h" + +struct getdents_callback { + struct dir_context ctx; + const char *obj_name; + char *match_name; + int dir_len; + int found; +}; + +int kfile_open(char *fname, kfile_ctrl_t *kfile_ctrl) +{ + int ret; + struct file *filp; + loff_t pos; + + if ((fname == NULL) || (kfile_ctrl == NULL)) { + return KFILE_RV_INPUT_ERR; + } + + filp = filp_open(fname, O_RDONLY, 0); + if (IS_ERR(filp)){ + return KFILE_RV_OPEN_FAIL; + } + + kfile_ctrl->size = filp->f_inode->i_size; + + kfile_ctrl->buf = kmalloc(kfile_ctrl->size, GFP_KERNEL); + if (kfile_ctrl->buf == NULL) { + ret = KFILE_RV_MALLOC_FAIL; + goto close_fp; + } + mem_clear(kfile_ctrl->buf, kfile_ctrl->size); + + pos = 0; + ret = kernel_read(filp, kfile_ctrl->buf, kfile_ctrl->size, &pos); + if (ret < 0) { + ret = KFILE_RV_RD_FAIL; + goto free_buf; + } + + kfile_ctrl->pos = 0; + + ret = KFILE_RV_OK; + goto close_fp; + +free_buf: + kfree(kfile_ctrl->buf); + kfile_ctrl->buf = NULL; + +close_fp: + filp_close(filp, NULL); + return ret; +} + +void kfile_close(kfile_ctrl_t *kfile_ctrl) +{ + if (kfile_ctrl == NULL) { + return; + } + + kfile_ctrl->size = 0; + kfile_ctrl->pos = 0; + if (kfile_ctrl->buf) { + kfree(kfile_ctrl->buf); + kfile_ctrl->buf = NULL; + } +} + +int kfile_gets(char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl) +{ + int i; + int has_cr = 0; + + if ((buf == NULL) || (buf_size <= 0) || (kfile_ctrl == NULL) || (kfile_ctrl->buf == NULL) + || (kfile_ctrl->size <= 0)) { + return KFILE_RV_INPUT_ERR; + } + + mem_clear(buf, buf_size); + for (i = 0; i < buf_size; i++) { + + if (kfile_ctrl->pos >= kfile_ctrl->size) { + break; + } + + if (has_cr) { + break; + } + + if (IS_CR(kfile_ctrl->buf[kfile_ctrl->pos])) { + has_cr = 1; + } + + buf[i] = kfile_ctrl->buf[kfile_ctrl->pos]; + kfile_ctrl->pos++; + } + + return i; +} + +int kfile_read(int32_t addr, char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl) +{ + int i; + + if ((buf == NULL) || (buf_size <= 0) || (kfile_ctrl == NULL) || (kfile_ctrl->buf == NULL) + || (kfile_ctrl->size <= 0)) { + return KFILE_RV_INPUT_ERR; + } + + if ((addr < 0) || (addr >= kfile_ctrl->size)) { + return KFILE_RV_ADDR_ERR; + } + + mem_clear(buf, buf_size); + + kfile_ctrl->pos = addr; + for (i = 0; i < buf_size; i++) { + + if (kfile_ctrl->pos >= kfile_ctrl->size) { + break; + } + + buf[i] = kfile_ctrl->buf[kfile_ctrl->pos]; + kfile_ctrl->pos++; + } + + return i; +} + +static int kfile_filldir_one(struct dir_context *ctx, const char * name, int len, + loff_t pos, u64 ino, unsigned int d_type) +{ + struct getdents_callback *buf ; + int result; + buf = container_of(ctx, struct getdents_callback, ctx); + result = 0; + if (strncmp(buf->obj_name, name, strlen(buf->obj_name)) == 0) { + if (buf->dir_len < len) { + DBG_DEBUG(DBG_ERROR, "match ok. dir name:%s, but buf_len %d small than dir len %d.\n", + name, buf->dir_len, len); + buf->found = 0; + return -1; + } + mem_clear(buf->match_name, buf->dir_len); + memcpy(buf->match_name, name, len); + buf->found = 1; + result = -1; + } + return result; +} + +int kfile_iterate_dir(const char *dir_path, const char *obj_name, char *match_name, int len) +{ + int ret; + struct file *dir; + struct getdents_callback buffer = { + .ctx.actor = kfile_filldir_one, + }; + + if(!dir_path || !obj_name || !match_name) { + DBG_DEBUG(DBG_ERROR, "params error. \n"); + return KFILE_RV_INPUT_ERR; + } + buffer.obj_name = obj_name; + buffer.match_name = match_name; + buffer.dir_len = len; + buffer.found = 0; + + dir = filp_open(dir_path, O_RDONLY, 0); + if (IS_ERR(dir)) { + DBG_DEBUG(DBG_ERROR, "filp_open error, dir path:%s\n", dir_path); + return KFILE_RV_OPEN_FAIL; + } + ret = iterate_dir(dir, &buffer.ctx); + if (buffer.found) { + DBG_DEBUG(DBG_VERBOSE, "match ok, dir name:%s\n", match_name); + filp_close(dir, NULL); + return DFD_RV_OK; + } + filp_close(dir, NULL); + return -DFD_RV_NODE_FAIL; +} + +#if 0 + +int kfile_write(char *fpath, int32_t addr, char *buf, int buf_size) +{ + int ret = KFILE_RV_OK; + struct file *filp; + mm_segment_t old_fs; + int wlen; + + if ((fpath == NULL) || (buf == NULL) || (buf_size <= 0)) { + return KFILE_RV_INPUT_ERR; + } + + if (addr < 0) { + return KFILE_RV_ADDR_ERR; + } + + filp = filp_open(fpath, O_RDWR, 0); + if (IS_ERR(filp)){ + return KFILE_RV_OPEN_FAIL; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + filp->f_op->llseek(filp,0,0); + filp->f_pos = addr; + + wlen = filp->f_op->write(filp, buf, buf_size, &(filp->f_pos)); + if (wlen < 0) { + ret = KFILE_RV_WR_FAIL; + } + + filp->f_op->llseek(filp,0,0); + set_fs(old_fs); + filp_close(filp, NULL); + + return ret; +} +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c new file mode 100644 index 000000000000..f8d64dcacbe3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c @@ -0,0 +1,771 @@ +#include +#include +#include + +#include "../include/dfd_module.h" +#include "../include/dfd_cfg_adapter.h" +#include "../include/dfd_cfg.h" +#include "../include/dfd_cfg_info.h" +#include "../include/dfd_cfg_file.h" +#include "../../dev_sysfs/include/sysfs_common.h" + +#define DFD_HWMON_NAME "hwmon" +/* CPLD_VOLATGE_VALUE_MODE1 */ +#define DFD_GET_CPLD_VOLATGE_CODE_VALUE(value) ((value >> 4)& 0xfff) +/* ((code_val * 16 * 33 * k) / ((65536 - 5000) * 10)) = ((code_val * 33 * k) / 37835) */ +#define DFD_GET_CPLD_VOLATGE_REAL_VALUE(code_val, k) ((code_val * 33 * k) / 37835) + + +/* CPLD_VOLATGE_VALUE_MODE2 */ +/* high 8 bit + low 4 bit(bit0-bit3) */ +#define DFD_GET_CPLD_VOLATGE_CODE_VALUE2(value) (((value & 0xff00) >> 4) + (value & 0xf)) +#define DFD_GET_CPLD_VOLATGE_REAL_VALUE2(code_val, k) ((code_val * 33 * k) / 40950) + +typedef enum cpld_volatge_value_s { + CPLD_VOLATGE_VALUE_MODE1, + CPLD_VOLATGE_VALUE_MODE2, +} cpld_volatge_value_t; + +char *g_info_ctrl_mem_str[INFO_CTRL_MEM_END] = { + ".mode", + ".int_cons", + ".src", + ".frmt", + ".pola", + ".fpath", + ".addr", + ".len", + ".bit_offset", + ".str_cons", + ".int_extra1", + ".int_extra2", + ".int_extra3", +}; + +char *g_info_ctrl_mode_str[INFO_CTRL_MODE_END] = { + "none", + "config", + "constant", + "tlv", + "str_constant", +}; + +char *g_info_src_str[INFO_SRC_END] = { + "none", + "cpld", + "fpga", + "other_i2c", + "file", +}; + +char *g_info_frmt_str[INFO_FRMT_END] = { + "none", + "bit", + "byte", + "num_bytes", + "num_str", + "num_buf", + "buf", +}; + +char *g_info_pola_str[INFO_POLA_END] = { + "none", + "positive", + "negative", +}; + +static int dfd_read_info_from_cpld(int32_t addr, int read_bytes, uint8_t *val) +{ + int i, rv; + + for (i = 0; i < read_bytes; i++) { + rv = dfd_ko_cpld_read(addr, &(val[i])); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "read info[addr=0x%x read_bytes=%d] from cpld fail, reading_byte=%d rv=%d\n", + addr, read_bytes, i, rv); + return rv; + } + addr++; + } + + return read_bytes; +} + +static int dfd_write_info_to_cpld(int32_t addr, int write_bytes, uint8_t *val, uint8_t bit_mask) +{ + int rv; + uint8_t val_tmp; + + if (bit_mask != 0xff) { + rv = dfd_ko_cpld_read(addr, &val_tmp); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "read original info[addr=0x%x] from cpld fail, rv=%d\n", addr, rv); + return -1; + } + + val_tmp = (val_tmp & (~bit_mask)) | (val[0] & bit_mask); + } else { + val_tmp = val[0]; + } + + rv = dfd_ko_cpld_write(addr, val_tmp); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "write info[addr=0x%x val=0x%x] to cpld fail, rv=%d\n", addr, val_tmp, rv); + return -1; + } + + return 0; +} + +static int dfd_read_info(info_src_t src, char *fpath, int32_t addr, int read_bytes, uint8_t *val) +{ + int rv = 0; + + switch (src) { + case INFO_SRC_CPLD: + rv = dfd_read_info_from_cpld(addr, read_bytes, val); + break; + case INFO_SRC_FPGA: + rv = -1; + DBG_DEBUG(DBG_ERROR, "not support read info from fpga\n"); + break; + case INFO_SRC_OTHER_I2C: + rv = -1; + DBG_DEBUG(DBG_ERROR, "not support read info from other i2c\n"); + break; + case INFO_SRC_FILE: + rv = dfd_ko_read_file(fpath, addr, val, read_bytes); + break; + default: + rv = -1; + DBG_DEBUG(DBG_ERROR, "info src[%d] error\n", src); + break; + } + + return rv; +} + +static int dfd_write_info(info_src_t src, char *fpath, int32_t addr, int write_bytes, uint8_t *val, uint8_t bit_mask) +{ + int rv = 0; + + switch (src) { + case INFO_SRC_CPLD: + rv = dfd_write_info_to_cpld(addr, write_bytes, val, bit_mask); + break; + case INFO_SRC_FPGA: + rv = -1; + DBG_DEBUG(DBG_ERROR, "not support write info to fpga\n"); + break; + case INFO_SRC_OTHER_I2C: + rv = -1; + DBG_DEBUG(DBG_ERROR, "not support write info to other i2c\n"); + break; + case INFO_SRC_FILE: + rv = -1; + DBG_DEBUG(DBG_ERROR, "not support write info to file\n"); + break; + default: + rv = -1; + DBG_DEBUG(DBG_ERROR, "info src[%d] error\n", src); + break; + } + + return rv; +} + +static int dfd_get_info_value(info_ctrl_t *info_ctrl, int *ret, info_num_buf_to_value_f pfun) +{ + int i, rv; + int read_bytes, readed_bytes, int_tmp; + uint8_t byte_tmp, val[INFO_INT_MAX_LEN + 1] = {0}; + + if (info_ctrl->mode == INFO_CTRL_MODE_CONS) { + *ret = info_ctrl->int_cons; + return DFD_RV_OK; + } + if (info_ctrl->mode == INFO_CTRL_MODE_TLV) { + return INFO_CTRL_MODE_TLV; + } + + if (IS_INFO_FRMT_BIT(info_ctrl->frmt)) { + if (!INFO_BIT_OFFSET_VALID(info_ctrl->bit_offset)) { + DBG_DEBUG(DBG_ERROR, "info ctrl bit_offsest[%d] invalid\n", + info_ctrl->bit_offset); + return -DFD_RV_TYPE_ERR; + } + read_bytes = 1; + } else if (IS_INFO_FRMT_BYTE(info_ctrl->frmt) || IS_INFO_FRMT_NUM_STR(info_ctrl->frmt) + || IS_INFO_FRMT_NUM_BUF(info_ctrl->frmt)) { + if (!INFO_INT_LEN_VALAID(info_ctrl->len)) { + DBG_DEBUG(DBG_ERROR, "info ctrl len[%d] invalid\n", info_ctrl->len); + return -DFD_RV_TYPE_ERR; + } + read_bytes = info_ctrl->len; + } else { + DBG_DEBUG(DBG_ERROR, "info ctrl info format[%d] error\n", info_ctrl->frmt); + return -DFD_RV_TYPE_ERR; + } + + readed_bytes = dfd_read_info(info_ctrl->src, info_ctrl->fpath, info_ctrl->addr, read_bytes, &(val[0])); + if (readed_bytes <= 0) { + DBG_DEBUG(DBG_ERROR, "read int info[src=%s frmt=%s fpath=%s addr=0x%x read_bytes=%d] fail, rv=%d\n", + g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], info_ctrl->fpath, + info_ctrl->addr, read_bytes, readed_bytes); + return -DFD_RV_DEV_FAIL; + } + + if (IS_INFO_FRMT_BIT(info_ctrl->frmt)) { + if (info_ctrl->pola == INFO_POLA_NEGA) { + val[0] = ~val[0]; + } + byte_tmp = (val[0] >> info_ctrl->bit_offset) & (~(0xff << info_ctrl->len)); + if (pfun) { + rv = pfun(&byte_tmp, sizeof(byte_tmp), &int_tmp); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "info ctrl bit process fail, rv=%d\n", rv); + return rv; + } + } else { + int_tmp = (int)byte_tmp; + } + } else if (IS_INFO_FRMT_BYTE(info_ctrl->frmt)) { + int_tmp = 0; + for (i = 0; i < info_ctrl->len; i++) { + if (info_ctrl->pola == INFO_POLA_NEGA) { + int_tmp |= val[info_ctrl->len - i - 1]; + } else { + int_tmp |= val[i]; + } + if (i != (info_ctrl->len - 1)) { + int_tmp <<= 8; + } + } + } else if (IS_INFO_FRMT_NUM_STR(info_ctrl->frmt)) { + val[readed_bytes] = '\0'; + int_tmp = simple_strtol((char *)(&(val[0])), NULL, 10); + } else { + if (pfun == NULL) { + DBG_DEBUG(DBG_ERROR, "info ctrl number buf process function is null\n"); + return -DFD_RV_INDEX_INVALID; + } + rv = pfun(val, readed_bytes, &int_tmp); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "info ctrl number buf process fail, rv=%d\n", rv); + return rv; + } + } + + *ret = int_tmp; + DBG_DEBUG(DBG_VERBOSE, "read int info[src=%s frmt=%s pola=%s fpath=%s addr=0x%x len=%d bit_offset=%d] success, ret=%d\n", + g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], g_info_pola_str[info_ctrl->pola], + info_ctrl->fpath, info_ctrl->addr, info_ctrl->len, info_ctrl->bit_offset, *ret); + return DFD_RV_OK; +} + +int dfd_info_get_int(int key, int *ret, info_num_buf_to_value_f pfun) +{ + int rv; + info_ctrl_t *info_ctrl; + + if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key)) || (ret == NULL)) { + DBG_DEBUG(DBG_ERROR, "input arguments error, key=0x%08x\n", key); + return -DFD_RV_INDEX_INVALID; + } + + info_ctrl = dfd_ko_cfg_get_item(key); + if (info_ctrl == NULL) { + DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + + DBG_DEBUG(DBG_VERBOSE, "get info ctrl value, key=0x%08x\n", key); + rv = dfd_get_info_value(info_ctrl, ret, pfun); + return rv; +} + +int dfd_info_get_buf(int key, uint8_t *buf, int buf_len, info_buf_to_buf_f pfun) +{ + int rv; + int read_bytes, buf_real_len; + uint8_t buf_tmp[INFO_BUF_MAX_LEN]; + info_ctrl_t *info_ctrl; + + if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key)) || (buf == NULL)) { + DBG_DEBUG(DBG_ERROR, "input arguments error, key=0x%08x\n", key); + return -DFD_RV_INDEX_INVALID; + } + + info_ctrl = dfd_ko_cfg_get_item(key); + if (info_ctrl == NULL) { + DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + + if (info_ctrl->mode != INFO_CTRL_MODE_CFG) { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] mode[%d] invalid\n", key, info_ctrl->mode); + return -DFD_RV_TYPE_ERR; + } + + if (!IS_INFO_FRMT_BUF(info_ctrl->frmt) || !INFO_BUF_LEN_VALAID(info_ctrl->len) + || (buf_len <= info_ctrl->len)) { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] format=%d or len=%d invlaid, buf_len=%d\n", + key, info_ctrl->frmt, info_ctrl->len, buf_len); + return -DFD_RV_TYPE_ERR; + } + + read_bytes = dfd_read_info(info_ctrl->src, info_ctrl->fpath, info_ctrl->addr, info_ctrl->len, buf_tmp); + if (read_bytes <= 0) { + DBG_DEBUG(DBG_ERROR, "read buf info[key=0x%08x src=%s frmt=%s fpath=%s addr=0x%x len=%d] fail, rv=%d\n", + key, g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], info_ctrl->fpath, + info_ctrl->addr, info_ctrl->len, read_bytes); + return -DFD_RV_DEV_FAIL; + } + + if (pfun) { + buf_real_len = buf_len; + rv = pfun(buf_tmp, read_bytes, buf, &buf_real_len); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] buf process fail, rv=%d\n", key, rv); + return -DFD_RV_DEV_NOTSUPPORT; + } + } else { + buf_real_len = read_bytes; + memcpy(buf, buf_tmp, read_bytes); + } + + return buf_real_len; +} + +static int dfd_2key_info_get_buf(info_ctrl_t *info_ctrl, uint8_t *buf, int buf_len, info_hwmon_buf_f pfun) +{ + int rv; + int read_bytes, buf_real_len; + uint8_t buf_tmp[INFO_BUF_MAX_LEN]; + char temp_fpath[INFO_FPATH_MAX_LEN]; + + if (!IS_INFO_FRMT_BUF(info_ctrl->frmt) || !INFO_BUF_LEN_VALAID(info_ctrl->len) + || (buf_len <= info_ctrl->len)) { + DBG_DEBUG(DBG_ERROR, "key_path info ctrl format=%d or len=%d invlaid, buf_len=%d\n", + info_ctrl->frmt, info_ctrl->len, buf_len); + return -DFD_RV_TYPE_ERR; + } + + mem_clear(buf_tmp, sizeof(buf_tmp)); + rv = kfile_iterate_dir(info_ctrl->fpath, DFD_HWMON_NAME, buf_tmp, INFO_BUF_MAX_LEN); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "dir patch:%s ,can find name %s dir \n", + info_ctrl->fpath, DFD_HWMON_NAME); + return -DFD_RV_NO_NODE; + } + mem_clear(temp_fpath, sizeof(temp_fpath)); + snprintf(temp_fpath, sizeof(temp_fpath), "%s%s/%s", + info_ctrl->fpath, buf_tmp, info_ctrl->str_cons); + DBG_DEBUG(DBG_VERBOSE, "match ok path = %s \n", temp_fpath); + + mem_clear(buf_tmp, sizeof(buf_tmp)); + + read_bytes = dfd_read_info(info_ctrl->src, temp_fpath, info_ctrl->addr, info_ctrl->len, buf_tmp); + if (read_bytes <= 0) { + DBG_DEBUG(DBG_ERROR, "read buf info[src=%s frmt=%s fpath=%s addr=0x%x len=%d] fail, rv=%d\n", + g_info_src_str[info_ctrl->src], g_info_src_str[info_ctrl->frmt], temp_fpath, + info_ctrl->addr, info_ctrl->len, read_bytes); + return -DFD_RV_DEV_FAIL; + } + + if (pfun) { + buf_real_len = buf_len; + rv = pfun(buf_tmp, read_bytes, buf, &buf_real_len, info_ctrl); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "info ctrl buf process fail, rv=%d\n", rv); + return -DFD_RV_DEV_NOTSUPPORT; + } + } else { + buf_real_len = read_bytes; + memcpy(buf, buf_tmp, buf_real_len); + } + return buf_real_len; +} + +int dfd_info_set_int(int key, int val) +{ + int rv; + int write_bytes; + uint8_t byte_tmp, bit_mask; + info_ctrl_t *info_ctrl; + + if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key))) { + DBG_DEBUG(DBG_ERROR, "input arguments error, key=0x%08x\n", key); + return -DFD_RV_INDEX_INVALID; + } + + info_ctrl = dfd_ko_cfg_get_item(key); + if (info_ctrl == NULL) { + DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + + if (info_ctrl->mode != INFO_CTRL_MODE_CFG) { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] mode[%d] warnning\n", key, info_ctrl->mode); + return -DFD_RV_TYPE_ERR; + } + + if (IS_INFO_FRMT_BIT(info_ctrl->frmt)) { + + if (!INFO_BIT_OFFSET_VALID(info_ctrl->bit_offset)) { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] bit_offsest[%d] invalid\n", + key, info_ctrl->bit_offset); + return -DFD_RV_TYPE_ERR; + } + + write_bytes = 1; + + byte_tmp = (uint8_t)(val & 0xff); + byte_tmp <<= info_ctrl->bit_offset; + if (info_ctrl->pola == INFO_POLA_NEGA) { + byte_tmp = ~byte_tmp; + } + + bit_mask = (~(0xff << info_ctrl->len)) << info_ctrl->bit_offset; + } else if (IS_INFO_FRMT_BYTE(info_ctrl->frmt)) { + + if (!INFO_INT_LEN_VALAID(info_ctrl->len)) { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] len[%d] invalid\n", key, info_ctrl->len); + return -DFD_RV_TYPE_ERR; + } + + write_bytes = 1; + + byte_tmp = (uint8_t)(val & 0xff); + + bit_mask = 0xff; + } else if (IS_INFO_FRMT_NUM_STR(info_ctrl->frmt)) { + + DBG_DEBUG(DBG_ERROR, "not support str int set\n"); + return -1; + } else if (IS_INFO_FRMT_NUM_BUF(info_ctrl->frmt)) { + + if (!INFO_INT_LEN_VALAID(info_ctrl->len)) { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] len[%d] invalid\n", key, info_ctrl->len); + return -DFD_RV_TYPE_ERR; + } + + write_bytes = 1; + + byte_tmp = (uint8_t)(val & 0xff); + + bit_mask = 0xff; + } else { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] format[%d] error\n", key, info_ctrl->frmt); + return -DFD_RV_TYPE_ERR; + } + + rv = dfd_write_info(info_ctrl->src, info_ctrl->fpath, info_ctrl->addr, write_bytes, + &byte_tmp, bit_mask); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "write int info[src=%s frmt=%s fpath=%s addr=0x%x len=%d val=%d] fail, rv=%d\n", + g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], info_ctrl->fpath, + info_ctrl->addr, info_ctrl->len, val, rv); + return -DFD_RV_DEV_FAIL; + } + + DBG_DEBUG(DBG_VERBOSE, "write int info[src=%s frmt=%s pola=%s fpath=%s addr=0x%x len=%d bit_offset=%d val=%d] success\n", + g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], g_info_pola_str[info_ctrl->pola], + info_ctrl->fpath, info_ctrl->addr, info_ctrl->len, info_ctrl->bit_offset, val); + return DFD_RV_OK; +} + +static int dfd_info_reg2data_linear(int key, int data, int *temp_value) +{ + s16 exponent; + s32 mantissa; + int val; + info_ctrl_t *info_ctrl; + + info_ctrl = dfd_ko_cfg_get_item(key); + if (info_ctrl == NULL) { + DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=%d\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + + switch (info_ctrl->int_extra1) { + case LINEAR11: + exponent = ((s16)data) >> 11; + mantissa = ((s16)((data & 0x7ff) << 5)) >> 5; + val = mantissa; + val = val * 1000L; + break; + case LINEAR16: + break; + default: + break; + } + + if (DFD_CFG_ITEM_ID(key) == DFD_CFG_ITEM_HWMON_POWER) { + val = val * 1000L; + } + + if (exponent >= 0) { + val <<= exponent; + } else { + val >>= -exponent; + } + *temp_value = val; + + return DFD_RV_OK; +} + +static int dfd_info_reg2data_tmp464(int data, int *temp_value) +{ + s16 tmp_val; + int val; + + DBG_DEBUG(DBG_VERBOSE, "reg2data_tmp464, data=%d\n", data); + + if (data >= 0) { + val = data*625/80; + } else { + tmp_val = ~(data & 0x7ff) + 1; + val = tmp_val*625/80; + } + *temp_value = val; + + return DFD_RV_OK; +} + +static int dfd_info_reg2data_mac_th5(int data, int *temp_value) +{ + int tmp_val; + int val; + + DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_th5, data=%d\n", data); + + tmp_val = data >> 4; + val = 476359 - (((tmp_val - 2) * 317704) / 2000); + + DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_th5, val=%d\n", val); + *temp_value = val; + + return DFD_RV_OK; +} + +static int dfd_info_reg2data_mac_td3(int data, int *temp_value) +{ + int val; + + if (data == 0) { + DBG_DEBUG(DBG_ERROR,"invalid cpld data=%d\n", data); + *temp_value = -READ_TEMP_FAIL; + return DFD_RV_OK; + } + + DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_td3, data=%d\n", data); + val = 434100 - (12500000 / (data * 100 - 1) *535); + if ((val / 1000 < -70) || (val / 1000 > 200)) { + DBG_DEBUG(DBG_ERROR,"out of range cpld val=%d\n", val); + *temp_value = -READ_TEMP_FAIL; + return DFD_RV_OK; + } + DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_td3, val=%d\n", val); + *temp_value = val; + + return DFD_RV_OK; +} + +static int dfd_info_get_cpld_voltage(int key, uint32_t *value) +{ + int rv; + uint32_t vol_ref_tmp, vol_ref; + uint32_t vol_curr_tmp, vol_curr; + info_ctrl_t *info_ctrl; + info_ctrl_t info_ctrl_tmp; + uint32_t vol_coefficient; + + info_ctrl = dfd_ko_cfg_get_item(key); + if (info_ctrl == NULL) { + DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + + vol_coefficient = (uint32_t)info_ctrl->int_extra2; + + rv = dfd_get_info_value(info_ctrl, &vol_curr_tmp, NULL); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "get cpld current voltage error, addr:0x%x, rv = %d\n", info_ctrl->addr, rv); + return rv; + } + if (info_ctrl->int_extra3 == CPLD_VOLATGE_VALUE_MODE2) { + vol_curr_tmp = DFD_GET_CPLD_VOLATGE_CODE_VALUE2(vol_curr_tmp); + vol_curr = DFD_GET_CPLD_VOLATGE_REAL_VALUE2(vol_curr_tmp, vol_coefficient); + DBG_DEBUG(DBG_VERBOSE, "vol_curr_tmp = 0x%x, vol_curr = 0x%x, is same.\n", vol_curr_tmp, vol_curr); + } else { + vol_curr_tmp = DFD_GET_CPLD_VOLATGE_CODE_VALUE(vol_curr_tmp); + if (info_ctrl->addr == info_ctrl->int_extra1) { + vol_curr = DFD_GET_CPLD_VOLATGE_REAL_VALUE(vol_curr_tmp, vol_coefficient); + DBG_DEBUG(DBG_VERBOSE, "current voltage is reference voltage, vol_curr_tmp: 0x%x, coefficient: %u, vol_curr: %u\n", + vol_curr_tmp, vol_coefficient, vol_curr); + } else { + memcpy(&info_ctrl_tmp, info_ctrl, sizeof(info_ctrl_t)); + info_ctrl_tmp.addr = info_ctrl->int_extra1; + rv = dfd_get_info_value(&info_ctrl_tmp, &vol_ref_tmp, NULL); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "get cpld reference voltage error, addr: 0x%x, rv: %d\n", info_ctrl_tmp.addr, rv); + return rv; + } + vol_ref = DFD_GET_CPLD_VOLATGE_CODE_VALUE(vol_ref_tmp); + DBG_DEBUG(DBG_VERBOSE, "vol_ref_tmp: 0x%x, vol_ref: 0x%x\n", vol_ref_tmp, vol_ref); + vol_curr = (vol_curr_tmp * vol_coefficient) / vol_ref; + DBG_DEBUG(DBG_VERBOSE, "vol_curr_tmp: 0x%x, vol_ref: 0x%x, coefficient: %u, vol_curr: %u\n", + vol_curr_tmp, vol_ref, vol_coefficient, vol_curr); + } + } + *value = vol_curr; + return DFD_RV_OK; +} + +static int dfd_info_get_cpld_temperature(int key, int *value) +{ + int rv; + int temp_reg; + int temp_value; + info_ctrl_t *info_ctrl; + + info_ctrl = dfd_ko_cfg_get_item(key); + if (info_ctrl == NULL) { + DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + + rv = dfd_info_get_int(key, &temp_reg, NULL); + if(rv < 0) { + DBG_DEBUG(DBG_ERROR, "get cpld current temperature error, addr:0x%x, rv =%d\n", info_ctrl->addr, rv); + return rv; + } + DBG_DEBUG(DBG_VERBOSE, "get cpld temp:0x%08x, extra1 0x%x\n", temp_reg, info_ctrl->int_extra1); + + switch (info_ctrl->int_extra1) { + case LINEAR11: + rv = dfd_info_reg2data_linear(key, temp_reg, &temp_value); + break; + case TMP464: + rv = dfd_info_reg2data_tmp464(temp_reg, &temp_value); + break; + case MAC_TH5: + rv = dfd_info_reg2data_mac_th5(temp_reg, &temp_value); + break; + case MAC_TD3: + rv = dfd_info_reg2data_mac_td3(temp_reg, &temp_value); + break; + default: + temp_value = temp_reg; + rv = DFD_RV_OK; + break; + } + + DBG_DEBUG(DBG_VERBOSE, "calc temp:%d \n", temp_value); + *value = temp_value; + + return rv; +} + +static int dfd_info_get_sensor_value(int key, uint8_t *buf, int buf_len, info_hwmon_buf_f pfun) +{ + int rv, buf_real_len; + uint32_t value; + uint8_t buf_tmp[INFO_BUF_MAX_LEN]; + info_ctrl_t *info_ctrl; + + info_ctrl = dfd_ko_cfg_get_item(key); + if (info_ctrl == NULL) { + DBG_DEBUG(DBG_ERROR, "get info ctrl fail, key=0x%08x\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + + if ( DFD_CFG_ITEM_ID(key) == DFD_CFG_ITEM_HWMON_IN && info_ctrl->src == INFO_SRC_CPLD) { + rv = dfd_info_get_cpld_voltage(key, &value); + if(rv < 0) { + DBG_DEBUG(DBG_ERROR, "get cpld voltage failed.key=0x%08x, rv:%d\n", key, rv); + return -DFD_RV_DEV_NOTSUPPORT; + } + DBG_DEBUG(DBG_VERBOSE, "get cpld voltage ok, value:%u\n", value); + mem_clear(buf_tmp, sizeof(buf_tmp)); + snprintf(buf_tmp, sizeof(buf_tmp), "%u\n", value); + buf_real_len = strlen(buf_tmp); + if(buf_len <= buf_real_len) { + DBG_DEBUG(DBG_ERROR, "length not enough.buf_len:%d,need length:%d\n", buf_len, buf_real_len); + return -DFD_RV_DEV_FAIL; + } + if (pfun) { + buf_real_len = buf_len; + rv = pfun(buf_tmp, strlen(buf_tmp), buf, &buf_real_len, info_ctrl); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "deal date error.org value:%s, buf_len:%d, rv=%d\n", + buf_tmp, buf_len, rv); + return -DFD_RV_DEV_NOTSUPPORT; + } + } else { + memcpy(buf, buf_tmp, buf_real_len); + } + return buf_real_len; + } else if ( DFD_CFG_ITEM_ID(key) == DFD_CFG_ITEM_HWMON_TEMP && info_ctrl->src == INFO_SRC_CPLD ) { + rv = dfd_info_get_cpld_temperature(key, &value); + if(rv < 0) { + DBG_DEBUG(DBG_ERROR, "get cpld temperature failed.key=0x%08x, rv:%d\n", key, rv); + return -DFD_RV_DEV_NOTSUPPORT; + } + DBG_DEBUG(DBG_VERBOSE, "get cpld temperature ok, value:%d buf_len %d\n", value, buf_len); + mem_clear(buf_tmp, sizeof(buf_tmp)); + snprintf(buf_tmp, sizeof(buf_tmp), "%d\n", value); + buf_real_len = strlen(buf_tmp); + if(buf_len <= buf_real_len) { + DBG_DEBUG(DBG_ERROR, "length not enough.buf_len:%d,need length:%d\n", buf_len, buf_real_len); + return -DFD_RV_DEV_FAIL; + } + DBG_DEBUG(DBG_VERBOSE, "buf_real_len %d\n", buf_real_len); + memcpy(buf, buf_tmp, buf_real_len); + return buf_real_len; + } + + DBG_DEBUG(DBG_ERROR, "not support mode. key:0x%08x\n", key); + return -DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_info_get_sensor(uint32_t key, char *buf, int buf_len, info_hwmon_buf_f pfun) +{ + info_ctrl_t *key_info_ctrl; + int rv; + + if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key)) || + (buf == NULL) || buf_len <= 0) { + DBG_DEBUG(DBG_ERROR, "input arguments error, key_path=0x%08x, buf_len:%d.\n", + key, buf_len); + return -DFD_RV_INVALID_VALUE; + } + + key_info_ctrl = dfd_ko_cfg_get_item(key); + if (key_info_ctrl == NULL) { + DBG_DEBUG(DBG_ERROR, "key_path info error, key=0x%08x\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + mem_clear(buf, buf_len); + + if (key_info_ctrl->mode == INFO_CTRL_MODE_SRT_CONS) { + snprintf(buf, buf_len, "%s\n", key_info_ctrl->str_cons); + DBG_DEBUG(DBG_VERBOSE, "get sensor value through string config, key=0x%08x, value:%s\n", key, buf); + return strlen(buf); + } + + if (key_info_ctrl->mode == INFO_CTRL_MODE_CFG && key_info_ctrl->src == INFO_SRC_FILE) { + DBG_DEBUG(DBG_VERBOSE, "get sensor value through hwmon, key:0x%08x\n", key); + rv = dfd_2key_info_get_buf(key_info_ctrl, buf, buf_len, pfun); + if (rv < 0) { + DBG_DEBUG(DBG_VERBOSE, "get sensor value through hwmon failed, key:0x%08x, rv:%d\n", key, rv); + } + return rv; + } + rv = dfd_info_get_sensor_value(key, buf, buf_len, pfun); + if( rv < 0) { + DBG_DEBUG(DBG_ERROR, "get sensor value failed, key=0x%08x, rv:%d.\n", key, rv); + } + return rv; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c new file mode 100644 index 000000000000..d6fd7e104c9f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c @@ -0,0 +1,82 @@ +#include +#include + +#include "../include/dfd_cfg_listnode.h" +#include "../../dev_sysfs/include/sysfs_common.h" + +void *lnode_find_node(lnode_root_t *root, int key) +{ + lnode_node_t *lnode; + + if (root == NULL){ + return NULL; + } + + list_for_each_entry(lnode, &(root->root), lst) { + if (lnode->key == key) { + return lnode->data; + } + } + + return NULL; +} + +int lnode_insert_node(lnode_root_t *root, int key, void *data) +{ + lnode_node_t *lnode; + void *data_tmp; + + if ((root == NULL) || (data == NULL)) { + return LNODE_RV_INPUT_ERR; + } + + data_tmp = lnode_find_node(root, key); + if (data_tmp != NULL) { + return LNODE_RV_NODE_EXIST; + } + + lnode = kmalloc(sizeof(lnode_node_t), GFP_KERNEL); + if (lnode == NULL) { + return LNODE_RV_NOMEM; + } + + lnode->key = key; + lnode->data = data; + list_add_tail(&(lnode->lst), &(root->root)); + + return LNODE_RV_OK; +} + +int lnode_init_root(lnode_root_t *root) +{ + if (root == NULL) { + return LNODE_RV_INPUT_ERR; + } + + INIT_LIST_HEAD(&(root->root)); + + return LNODE_RV_OK; +} + +void lnode_free_list(lnode_root_t *root) +{ + lnode_node_t *lnode, *lnode_next; + + if (root == NULL){ + return ; + } + + list_for_each_entry_safe(lnode, lnode_next, &(root->root), lst) { + if ( lnode->data ) { + kfree(lnode->data); + lnode->data = NULL; + lnode->key = 0; + } + list_del(&lnode->lst); + kfree(lnode); + lnode = NULL; + } + + return ; + +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_fan_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_fan_driver.c new file mode 100644 index 000000000000..d8965d75c9c0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_fan_driver.c @@ -0,0 +1,201 @@ +#include +#include + +#include "./include/dfd_module.h" +#include "./include/dfd_cfg.h" +#include "./include/dfd_cfg_adapter.h" +#include "./include/dfd_cfg_info.h" +#include "../dev_sysfs/include/sysfs_common.h" + +#define FAN_SIZE (256) + +int g_dfd_fan_dbg_level = 0; +module_param(g_dfd_fan_dbg_level, int, S_IRUGO | S_IWUSR); + +typedef enum fan_speed_format_mem_s { + LINEAR120 = 1, +} fan_speed_format_mem_t; + +int dfd_get_fan_roll_status(unsigned int fan_index, unsigned int motor_index) +{ + int key, ret; + int status; + + key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_ROLL_STATUS, fan_index, motor_index); + ret = dfd_info_get_int(key, &status, NULL); + if (ret < 0) { + DFD_FAN_DEBUG(DBG_ERROR, "get fan roll status error, fan:%d,motor:%d\n", + fan_index, motor_index); + return ret; + } + + DFD_FAN_DEBUG(DBG_VERBOSE, "fan%u motor%u get fan roll status success, status:%d.\n", + fan_index, motor_index, status); + return status; +} + +int dfd_get_fan_present_status(unsigned int fan_index) +{ + int key, ret; + int status; + + key = DFD_CFG_KEY(DFD_CFG_ITEM_DEV_PRESENT_STATUS, WB_MAIN_DEV_FAN, fan_index); + ret = dfd_info_get_int(key, &status, NULL); + if (ret < 0) { + DFD_FAN_DEBUG(DBG_ERROR, "fan%u get present status error, key:0x%x\n", fan_index, key); + return ret; + } + + DFD_FAN_DEBUG(DBG_VERBOSE, "fan%u get present status success, status:%d.\n", fan_index, status); + return status; +} + +static int dfd_get_fan_speed_linear120(int origin_data, int *speed) +{ + *speed = origin_data * 120; + DFD_FAN_DEBUG(DBG_VERBOSE, "get fan speed by linear120 origin_data: %d, speed: %d\n", + origin_data, *speed); + return 0; +} + +static int dfd_get_fan_speed_default(int origin_data, int *speed) +{ + if (origin_data == 0 || origin_data == 0xffff) { + *speed = 0; + } else { + *speed = 15000000 / origin_data; + } + DFD_FAN_DEBUG(DBG_VERBOSE, "get fan speed by default origin_data: %d, speed: %d\n", + origin_data, *speed); + return 0; +} + +ssize_t dfd_get_fan_speed(unsigned int fan_index, unsigned int motor_index,unsigned int *speed) +{ + int key, ret, speed_tmp; + info_ctrl_t *info_ctrl; + + if (speed == NULL) { + DFD_FAN_DEBUG(DBG_ERROR, "param error. fan index:%d, motor index:%d.\n", + fan_index, motor_index); + return -DFD_RV_INVALID_VALUE; + } + + key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_SPEED, fan_index, motor_index); + ret = dfd_info_get_int(key, &speed_tmp, NULL); + if (ret < 0) { + DFD_FAN_DEBUG(DBG_ERROR, "get fan speed error, key:0x%x,ret:%d\n",key, ret); + return ret; + } + DFD_FAN_DEBUG(DBG_VERBOSE, "get fan origin data: 0x%x\n", speed_tmp); + + info_ctrl = dfd_ko_cfg_get_item(key); + switch (info_ctrl->int_extra1) { + case LINEAR120: + ret = dfd_get_fan_speed_linear120(speed_tmp, speed); + break; + default: + ret = dfd_get_fan_speed_default(speed_tmp, speed); + break; + } + + return ret; +} + +int dfd_set_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int level) +{ + int key, ret; + + if (level < 0 || level > 0xff) { + DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, can not set fan speed level: %d.\n", + fan_index, motor_index, level); + return -DFD_RV_INVALID_VALUE; + } + + key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_RATIO, fan_index, motor_index); + ret = dfd_info_set_int(key, level); + if (ret < 0) { + DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, set fan level 0x%02x error, key:0x%x,ret:%d\n", + fan_index, motor_index, level, key, ret); + return ret; + } + + DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, set fan speed level 0x%02x success.\n", + fan_index, motor_index, level); + return DFD_RV_OK; +} + +int dfd_set_fan_pwm(unsigned int fan_index, unsigned int motor_index, int pwm) +{ + int ret, data; + + if (pwm < 0 || pwm > 100) { + DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, can't set pwm: %d.\n", + fan_index, motor_index, pwm); + return -DFD_RV_INVALID_VALUE; + } + + data = pwm * 255 / 100; + ret = dfd_set_fan_speed_level(fan_index, motor_index, data); + if (ret < 0) { + DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, set fan ratio:%d error, ret:%d\n", + fan_index, motor_index, data, ret); + return ret; + } + + DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, set fan ratio %d success.\n", + fan_index, motor_index, data); + return DFD_RV_OK; +} + +int dfd_get_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int *level) +{ + int key, ret, speed_level; + + if (level == NULL) { + DFD_FAN_DEBUG(DBG_ERROR, "param error. fan index:%d, motor index:%d.\n", + fan_index, motor_index); + return -DFD_RV_INVALID_VALUE; + } + + key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_RATIO, fan_index, motor_index); + ret = dfd_info_get_int(key, &speed_level, NULL); + if (ret < 0) { + DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, get fan speed level error, key:0x%x,ret:%d\n", + fan_index, motor_index, key, ret); + return ret; + } + + DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, get fan speed level success, value:0x%02x.\n", + fan_index, motor_index, speed_level); + *level = speed_level; + return DFD_RV_OK; +} + +int dfd_get_fan_pwm(unsigned int fan_index, unsigned int motor_index, int *pwm) +{ + int ret, level; + + if (pwm == NULL) { + DFD_FAN_DEBUG(DBG_ERROR, "param error. fan index:%d, motor index:%d.\n", + fan_index, motor_index); + return -DFD_RV_INVALID_VALUE; + } + + ret = dfd_get_fan_speed_level(fan_index, motor_index, &level); + if (ret < 0) { + DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, get fan pwm error, ret:%d\n", + fan_index, motor_index, ret); + return ret; + } + + if ((level * 100) % 255 > 0) { + *pwm = level * 100 / 255 + 1; + } else { + *pwm = level * 100 / 255; + } + + DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, get fan pwm success, value:%d.\n", + fan_index, motor_index, *pwm); + return DFD_RV_OK; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_module.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_module.c new file mode 100644 index 000000000000..9e5b00b795de --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_module.c @@ -0,0 +1,95 @@ +#include + +#include "../dev_sysfs/include/sysfs_common.h" +#include "./include/dfd_module.h" +#include "./include/dfd_cfg.h" +#include "./include/dfd_fan_driver.h" +#include "./include/dfd_slot_driver.h" +#include "./include/dfd_sensors_driver.h" +#include "./include/dfd_psu_driver.h" +#include "./include/dfd_sff_driver.h" + +typedef enum dfd_dev_init_fail_s { + DFD_KO_INIT_CPLD_FAIL = 1, + DFD_KO_INIT_FPGA_FAIL = 2, + DFD_KO_INIT_IRQ_FAIL = 3, + DFD_KO_INIT_CFG_FAIL = 4, + DFD_KO_INIT_DATA_FAIL = 5, +} dfd_dev_init_fail_t; + +int g_dfd_dbg_level = 0; + +int dfd_get_dev_number(unsigned int main_dev_id, unsigned int minor_dev_id) +{ + int key,dev_num; + int *p_dev_num; + + key = DFD_CFG_KEY(DFD_CFG_ITEM_DEV_NUM, main_dev_id, minor_dev_id); + p_dev_num = dfd_ko_cfg_get_item(key); + if (p_dev_num == NULL) { + DBG_DEBUG(DBG_ERROR, "get device number failed, key:0x%x\n",key); + return -DFD_RV_DEV_NOTSUPPORT; + } + dev_num = *p_dev_num; + DBG_DEBUG(DBG_VERBOSE, "get device number ok, number:%d\n",dev_num); + return dev_num; +} + +static struct switch_drivers_t switch_drivers= { + .get_dev_number = dfd_get_dev_number, + /* fan */ + .get_fan_speed = dfd_get_fan_speed, + .get_fan_pwm = dfd_get_fan_pwm, + .set_fan_pwm = dfd_set_fan_pwm, + .get_fan_present_status = dfd_get_fan_present_status, + .get_fan_roll_status = dfd_get_fan_roll_status, + .get_fan_speed_level = dfd_get_fan_speed_level, + .set_fan_speed_level = dfd_set_fan_speed_level, + /* slot */ + .get_slot_present_status = dfd_get_slot_present_status, + /* sensors */ + .get_temp_info = dfd_get_temp_info, + .get_voltage_info = dfd_get_voltage_info, + /* psu */ + .get_psu_present_status = dfd_get_psu_present_status, + .get_psu_output_status = dfd_get_psu_output_status, + .get_psu_alert_status = dfd_get_psu_alert_status, + /* sff */ + .get_sff_cpld_info = dfd_get_sff_cpld_info, + .get_sff_dir_name = dfd_get_sff_dir_name, +}; + +struct switch_drivers_t * dfd_plat_driver_get(void) { + return &switch_drivers; +} + +static int32_t __init dfd_dev_init(void) +{ + int ret; + + DBG_DEBUG(DBG_VERBOSE, "Enter.\n"); + + ret = dfd_dev_cfg_init(); + if (ret != 0) { + DBG_DEBUG(DBG_ERROR, "dfd_dev_cfg_init failed ret %d.\n", ret); + ret = -DFD_KO_INIT_CFG_FAIL; + return ret; + } + + DBG_DEBUG(DBG_VERBOSE, "success.\n"); + return 0; +} + +static void __exit dfd_dev_exit(void) +{ + DBG_DEBUG(DBG_VERBOSE, "dfd_dev_exit.\n"); + dfd_dev_cfg_exit(); + return ; +} + +module_init(dfd_dev_init); +module_exit(dfd_dev_exit); +module_param(g_dfd_dbg_level, int, S_IRUGO | S_IWUSR); +EXPORT_SYMBOL(dfd_plat_driver_get); +MODULE_AUTHOR("support"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_psu_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_psu_driver.c new file mode 100644 index 000000000000..55e2e4339ae7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_psu_driver.c @@ -0,0 +1,70 @@ +#include +#include + +#include "./include/dfd_module.h" +#include "./include/dfd_cfg.h" +#include "./include/dfd_cfg_adapter.h" +#include "./include/dfd_cfg_info.h" +#include "../dev_sysfs/include/sysfs_common.h" + +#define PSU_SIZE (256) + +typedef enum dfd_psu_status_e { + DFD_PSU_PRESENT_STATUS = 0, + DFD_PSU_OUTPUT_STATUS = 1, + DFD_PSU_ALERT_STATUS = 2, +} dfd_psu_status_t; + +int g_dfd_psu_dbg_level = 0; +module_param(g_dfd_psu_dbg_level, int, S_IRUGO | S_IWUSR); + +int dfd_get_psu_present_status(unsigned int psu_index) +{ + int ret, present_key, present_status; + + present_key = DFD_CFG_KEY(DFD_CFG_ITEM_PSU_STATUS, psu_index, DFD_PSU_PRESENT_STATUS); + ret = dfd_info_get_int(present_key, &present_status, NULL); + if (ret < 0) { + DFD_PSU_DEBUG(DBG_ERROR, "dfd_get_psu_present_status error. psu_index:%d, ret:%d\n", + psu_index, ret); + return ret; + } + + DFD_PSU_DEBUG(DBG_VERBOSE, "dfd_get_psu_present_status success. psu_index:%d, status:%d\n", + psu_index, present_status); + return present_status; +} + +int dfd_get_psu_output_status(unsigned int psu_index) +{ + int ret, output_key, output_status; + + output_key = DFD_CFG_KEY(DFD_CFG_ITEM_PSU_STATUS, psu_index, DFD_PSU_OUTPUT_STATUS); + ret = dfd_info_get_int(output_key, &output_status, NULL); + if (ret < 0) { + DFD_PSU_DEBUG(DBG_ERROR, "dfd_get_psu_output_status error. psu_index:%d, ret:%d\n", + psu_index, ret); + return ret; + } + + DFD_PSU_DEBUG(DBG_VERBOSE, "dfd_get_psu_output_status success. psu_index:%d, status:%d\n", + psu_index, output_status); + return output_status; +} + +int dfd_get_psu_alert_status(unsigned int psu_index) +{ + int ret, alert_key, alert_status; + + alert_key = DFD_CFG_KEY(DFD_CFG_ITEM_PSU_STATUS, psu_index, DFD_PSU_ALERT_STATUS); + ret = dfd_info_get_int(alert_key, &alert_status, NULL); + if (ret < 0) { + DFD_PSU_DEBUG(DBG_ERROR, "dfd_get_psu_alert_status error. psu_index:%d, ret:%d\n", + psu_index, ret); + return ret; + } + + DFD_PSU_DEBUG(DBG_VERBOSE, "dfd_get_psu_alert_status success. psu_index:%d, status:%d\n", + psu_index, alert_status); + return alert_status; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sensors_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sensors_driver.c new file mode 100644 index 000000000000..bfca20290efb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sensors_driver.c @@ -0,0 +1,149 @@ +#include +#include + +#include "./include/dfd_module.h" +#include "./include/dfd_cfg.h" +#include "./include/dfd_cfg_adapter.h" +#include "./include/dfd_cfg_info.h" +#include "./include/dfd_cfg_file.h" +#include "../dev_sysfs/include/sysfs_common.h" + +#define DFD_GET_TEMP_SENSOR_KEY1(dev_index, temp_index) \ + (((dev_index & 0xff) << 8) | (temp_index & 0xff)) +#define DFD_GET_TEMP_SENSOR_KEY2(main_dev_id, temp_type) \ + (((main_dev_id & 0x0f) << 4) | (temp_type & 0x0f)) +#define DFD_FORMAT_STR_MAX_LEN (32) + +int g_dfd_sensor_dbg_level = 0; +module_param(g_dfd_sensor_dbg_level, int, S_IRUGO | S_IWUSR); + +static int dfd_deal_hwmon_buf(uint8_t *buf, int buf_len, uint8_t *buf_new, int *buf_len_new, info_ctrl_t *info_ctrl) +{ + int i, tmp_len; + int exp, decimal, divisor; + int org_value, tmp_value; + int div_result, div_mod; + char fmt_str[DFD_FORMAT_STR_MAX_LEN]; + + exp = info_ctrl->int_cons; + decimal = info_ctrl->bit_offset; + + if (exp <= 0) { + DBG_DEBUG(DBG_VERBOSE, "exponent %d, don't need transform. buf_len:%d, buf_len_new:%d\n", + exp, buf_len, *buf_len_new); + snprintf(buf_new, *buf_len_new, "%s", buf); + *buf_len_new = strlen(buf_new); + return DFD_RV_OK; + } + divisor = 1; + for (i = 0; i < exp; i++) { + divisor *= 10; + } + org_value = simple_strtol(buf, NULL, 10); + if (org_value < 0) { + tmp_value = 0 - org_value; + } else { + tmp_value = org_value; + } + div_result = tmp_value / divisor; + div_mod = tmp_value % divisor; + DBG_DEBUG(DBG_VERBOSE, "exp:%d, decimal:%d, original value:%d, divisor:%d, result :%d, mod:%d\n", + exp, decimal, org_value, divisor, div_result, div_mod); + + mem_clear(fmt_str, sizeof(fmt_str)); + if (org_value < 0) { + snprintf(fmt_str, sizeof(fmt_str), "-%%d.%%0%dd\n",exp); + } else { + snprintf(fmt_str, sizeof(fmt_str), "%%d.%%0%dd\n",exp); + } + DBG_DEBUG(DBG_VERBOSE, "format string:%s",fmt_str); + snprintf(buf_new, *buf_len_new, fmt_str, div_result, div_mod); + *buf_len_new = strlen(buf_new); + tmp_len = *buf_len_new; + + if ( decimal > 0) { + for(i = 0; i < *buf_len_new; i++) { + if (buf_new[i] == '.') { + if( i + decimal + 2 <= *buf_len_new ) { + buf_new[i + decimal + 1 ] = '\n'; + buf_new[i + decimal + 2 ] = '\0'; + *buf_len_new = strlen(buf_new); + DBG_DEBUG(DBG_VERBOSE, "deal decimal[%d] ok, str len:%d, value:%s\n", + decimal, *buf_len_new, buf_new); + } + break; + } + } + if (tmp_len == *buf_len_new) { + DBG_DEBUG(DBG_WARN, "deal decimal[%d] failed, use original value:%s\n", decimal, buf_new); + } + } + return DFD_RV_OK; +} + +static int dfd_get_sensor_info(uint8_t main_dev_id, uint8_t dev_index, uint8_t sensor_type, + uint8_t sensor_index, uint8_t sensor_attr, char *buf) +{ + uint32_t key; + uint16_t key_index1; + uint8_t key_index2; + int rv; + info_hwmon_buf_f pfunc; + + key_index1 = DFD_GET_TEMP_SENSOR_KEY1(dev_index, sensor_index); + key_index2 = DFD_GET_TEMP_SENSOR_KEY2(main_dev_id, sensor_attr); + if (sensor_type == WB_MINOR_DEV_TEMP ) { + key = DFD_CFG_KEY(DFD_CFG_ITEM_HWMON_TEMP, key_index1, key_index2); + } else if (sensor_type == WB_MINOR_DEV_IN) { + key = DFD_CFG_KEY(DFD_CFG_ITEM_HWMON_IN, key_index1, key_index2); + } else { + DFD_SENSOR_DEBUG(DBG_ERROR, "unknow sensor type:%d.\n",sensor_type); + return -DFD_RV_INVALID_VALUE; + } + + DFD_SENSOR_DEBUG(DBG_VERBOSE, "get sensor info.main_dev_id:%d, dev_index:0x%x, sensor_index:0x%x, sensor_attr:0x%x, key:0x%x,\n", + main_dev_id, dev_index, sensor_index, sensor_attr, key); + + pfunc = dfd_deal_hwmon_buf; + mem_clear(buf, PAGE_SIZE); + rv = dfd_info_get_sensor(key, buf, PAGE_SIZE, pfunc); + return rv; +} + +ssize_t dfd_get_temp_info(uint8_t main_dev_id, uint8_t dev_index, + uint8_t temp_index, uint8_t temp_attr, char *buf) +{ + int rv; + + if (buf == NULL) { + DFD_SENSOR_DEBUG(DBG_ERROR, "param error. buf is NULL.\n"); + return -DFD_RV_INVALID_VALUE; + } + + rv = dfd_get_sensor_info(main_dev_id, dev_index, WB_MINOR_DEV_TEMP, temp_index, temp_attr, buf); + if (rv < 0) { + DFD_SENSOR_DEBUG(DBG_ERROR, "get temp info error. rv:%d\n", rv); + } else { + DFD_SENSOR_DEBUG(DBG_VERBOSE, "get temp info ok.value:%s\n", buf); + } + return rv; +} + +ssize_t dfd_get_voltage_info(uint8_t main_dev_id, uint8_t dev_index, + uint8_t in_index, uint8_t in_attr, char *buf) +{ + int rv; + + if (buf == NULL) { + DFD_SENSOR_DEBUG(DBG_ERROR, "param error. buf is NULL.\n"); + return -DFD_RV_INVALID_VALUE; + } + + rv = dfd_get_sensor_info(main_dev_id, dev_index, WB_MINOR_DEV_IN, in_index, in_attr, buf); + if (rv < 0) { + DFD_SENSOR_DEBUG(DBG_ERROR, "get voltage info error. rv:%d\n", rv); + } else { + DFD_SENSOR_DEBUG(DBG_VERBOSE, "get voltage info ok.value:%s\n", buf); + } + return rv; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sff_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sff_driver.c new file mode 100644 index 000000000000..5c1faff975b1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sff_driver.c @@ -0,0 +1,56 @@ +#include + +#include "./include/dfd_module.h" +#include "./include/dfd_cfg.h" +#include "./include/dfd_cfg_info.h" +#include "./include/dfd_cfg_adapter.h" +#include "../dev_sysfs/include/sysfs_common.h" + +int g_dfd_sff_dbg_level = 0; +module_param(g_dfd_sff_dbg_level, int, S_IRUGO | S_IWUSR); + +ssize_t dfd_get_sff_cpld_info(unsigned int sff_index, int cpld_reg_type, char *buf, int len) +{ + int key, ret, value; + + if(buf == NULL) { + DFD_SFF_DEBUG(DBG_ERROR, "param error, buf is NULL. sff_index:%d, cpld_reg_type:%d.\n", + sff_index, cpld_reg_type); + return -DFD_RV_INVALID_VALUE; + } + + key = DFD_CFG_KEY(DFD_CFG_ITEM_SFF_CPLD_REG, sff_index, cpld_reg_type); + ret = dfd_info_get_int(key, &value, NULL); + if (ret < 0) { + DFD_SFF_DEBUG(DBG_ERROR, "get sff cpld reg error, key:0x%x,ret:%d.\n", key, ret); + return ret; + } + + mem_clear(buf, len); + return (ssize_t)snprintf(buf, len, "%d\n", value); +} + +ssize_t dfd_get_sff_dir_name(unsigned int sff_index, char *buf, int buf_len) +{ + int key; + char *sff_dir_name; + + if (buf == NULL) { + DFD_SFF_DEBUG(DBG_ERROR, "param error. buf is NULL.sff index:%d", sff_index); + return -DFD_RV_INVALID_VALUE; + } + + mem_clear(buf, buf_len); + + key = DFD_CFG_KEY(DFD_CFG_ITEM_SFF_DIR_NAME, sff_index, 0); + sff_dir_name = dfd_ko_cfg_get_item(key); + if (sff_dir_name == NULL) { + DFD_SFF_DEBUG(DBG_ERROR, "sff dir name config error, key=0x%08x\n", key); + return -DFD_RV_NODE_FAIL; + } + + DFD_SFF_DEBUG(DBG_VERBOSE, "%s\n", sff_dir_name); + snprintf(buf, buf_len, "%s", sff_dir_name); + return strlen(buf); + +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_slot_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_slot_driver.c new file mode 100644 index 000000000000..69c82adabef0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_slot_driver.c @@ -0,0 +1,27 @@ +#include +#include + +#include "./include/dfd_module.h" +#include "./include/dfd_cfg.h" +#include "./include/dfd_cfg_adapter.h" +#include "./include/dfd_cfg_info.h" +#include "../dev_sysfs/include/sysfs_common.h" + +#define SLOT_SIZE (256) + +int g_dfd_slot_dbg_level = 0; +module_param(g_dfd_slot_dbg_level, int, S_IRUGO | S_IWUSR); + +int dfd_get_slot_present_status(unsigned int slot_index) +{ + int key, ret; + int status; + + key = DFD_CFG_KEY(DFD_CFG_ITEM_DEV_PRESENT_STATUS, WB_MAIN_DEV_SLOT, slot_index); + ret = dfd_info_get_int(key, &status, NULL); + if (ret < 0) { + DFD_SLOT_DEBUG(DBG_ERROR, "get slot status error, key:0x%x\n",key); + return ret; + } + return status; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg.h new file mode 100644 index 000000000000..af3de1ca9938 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg.h @@ -0,0 +1,99 @@ +#ifndef __DFD_CFG_H__ +#define __DFD_CFG_H__ + +#include + +#define DFD_KO_CFG_FILE_NAME "/etc/plat_sysfs_cfg/cfg_file_name" +#define DFD_KO_CFG_FILE_DIR "/etc/plat_sysfs_cfg/" +#define DFD_PUB_CARDTYPE_FILE "/sys/module/platform_common/parameters/dfd_my_type" + +#define DFD_CFG_CMDLINE_MAX_LEN (256) +#define DFD_CFG_NAME_MAX_LEN (256) +#define DFD_CFG_VALUE_MAX_LEN (256) +#define DFD_CFG_STR_MAX_LEN (64) +#define DFD_CFG_CPLD_NUM_MAX (16) +#define DFD_PRODUCT_ID_LENGTH (8) +#define DFD_PID_BUF_LEN (32) +#define DFD_TEMP_NAME_BUF_LEN (32) + +#define DFD_CFG_EMPTY_VALUE (-1) +#define DFD_CFG_INVALID_VALUE (0) + +#define DFD_CFG_KEY(item, index1, index2) \ + ((((item) & 0xff) << 24) | (((index1) & 0xffff) << 8) | ((index2) & 0xff)) +#define DFD_CFG_ITEM_ID(key) (((key) >> 24) & 0xff) +#define DFD_CFG_INDEX1(key) (((key) >> 8) & 0xffff) +#define DFD_CFG_INDEX2(key) ((key)& 0xff) + +#define INDEX_NOT_EXIST (-1) +#define INDEX1_MAX (0xffff) +#define INDEX2_MAX (0xff) +#define READ_TEMP_FAIL 1000000 + +#define DFD_CFG_ITEM_ALL \ + DFD_CFG_ITEM(DFD_CFG_ITEM_NONE, "none", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_DEV_NUM, "dev_num", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_CPLD_LPC_DEV, "cpld_lpc_dev", INDEX1_MAX, DFD_CFG_CPLD_NUM_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_INT_END, "end_int", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ + \ + DFD_CFG_ITEM(DFD_CFG_ITEM_CPLD_MODE, "mode_cpld", INDEX1_MAX, DFD_CFG_CPLD_NUM_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_SFF_DIR_NAME, "sff_dir_name", INDEX1_MAX, INDEX_NOT_EXIST) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_STRING_END, "end_string", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ + \ + DFD_CFG_ITEM(DFD_CFG_ITEM_CPLD_I2C_DEV, "cpld_i2c_dev", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_OTHER_I2C_DEV, "other_i2c_dev", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_I2C_DEV_END, "end_i2c_dev", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ + \ + DFD_CFG_ITEM(DFD_CFG_ITEM_FAN_ROLL_STATUS, "fan_roll_status", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_FAN_SPEED, "fan_speed", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_FAN_RATIO, "fan_ratio", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_DEV_PRESENT_STATUS, "dev_present_status", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_PSU_STATUS, "psu_status", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_HWMON_TEMP, "hwmon_temp", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_HWMON_IN, "hwmon_in", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_SFF_CPLD_REG, "sff_cpld_reg", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_INFO_CTRL_END, "end_info_ctrl", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_HWMON_POWER, "hwmon_power", INDEX1_MAX, INDEX2_MAX) \ + +#ifdef DFD_CFG_ITEM +#undef DFD_CFG_ITEM +#endif +#define DFD_CFG_ITEM(_id, _name, _index_min, _index_max) _id, +typedef enum dfd_cfg_item_id_s { + DFD_CFG_ITEM_ALL +} dfd_cfg_item_id_t; + +#define DFD_CFG_ITEM_IS_INT(item_id) \ + (((item_id) > DFD_CFG_ITEM_NONE) && ((item_id) < DFD_CFG_ITEM_INT_END)) + +#define DFD_CFG_ITEM_IS_STRING(item_id) \ + (((item_id) > DFD_CFG_ITEM_INT_END) && ((item_id) < DFD_CFG_ITEM_STRING_END)) + +#define DFD_CFG_ITEM_IS_I2C_DEV(item_id) \ + (((item_id) > DFD_CFG_ITEM_STRING_END) && ((item_id) < DFD_CFG_ITEM_I2C_DEV_END)) + +#define DFD_CFG_ITEM_IS_INFO_CTRL(item_id) \ + (((item_id) > DFD_CFG_ITEM_I2C_DEV_END) && ((item_id) < DFD_CFG_ITEM_INFO_CTRL_END)) + +typedef struct index_range_s { + int index1_max; + int index2_max; +} index_range_t; + +typedef struct val_convert_node_s { + struct list_head lst; + int int_val; + char str_val[DFD_CFG_STR_MAX_LEN]; + int index1; + int index2; +} val_convert_node_t; + +void *dfd_ko_cfg_get_item(int key); + +void dfd_ko_cfg_show_item(int key); + +int32_t dfd_dev_cfg_init(void); + +void dfd_dev_cfg_exit(void); + +#endif /* __DFD_CFG_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_adapter.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_adapter.h new file mode 100644 index 000000000000..70d8b536c437 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_adapter.h @@ -0,0 +1,46 @@ +#ifndef __DFD_CFG_ADAPTER_H__ +#define __DFD_CFG_ADAPTER_H__ + +#define DFD_KO_CPLD_I2C_RETRY_SLEEP (10) /* ms */ +#define DFD_KO_CPLD_I2C_RETRY_TIMES (50 / DFD_KO_CPLD_I2C_RETRY_SLEEP) + +#define DFD_KO_CPLD_GET_SLOT(addr) ((addr >> 24) & 0xff) +#define DFD_KO_CPLD_GET_ID(addr) ((addr >> 16) & 0xff) +#define DFD_KO_CPLD_GET_INDEX(addr) (addr & 0xffff) +#define DFD_KO_CPLD_MODE_I2C_STRING "i2c" +#define DFD_KO_CPLD_MODE_LPC_STRING "lpc" + +typedef struct dfd_i2c_dev_s { + int bus; + int addr; +} dfd_i2c_dev_t; + +typedef enum dfd_i2c_dev_mem_s { + DFD_I2C_DEV_MEM_BUS, + DFD_I2C_DEV_MEM_ADDR, + DFD_I2C_DEV_MEM_END +} dfd_i2c_dev_mem_t; + +typedef enum cpld_mode_e { + DFD_CPLD_MODE_I2C, + DFD_CPLD_MODE_LPC, +} cpld_mode_t; + +typedef enum i2c_mode_e { + DFD_I2C_MODE_NORMAL_I2C, + DFD_I2C_MODE_SMBUS, +} i2c_mode_t; + +extern char *g_dfd_i2c_dev_mem_str[DFD_I2C_DEV_MEM_END]; + +int32_t dfd_ko_cpld_read(int32_t addr, uint8_t *buf); + +int32_t dfd_ko_cpld_write(int32_t addr, uint8_t val); + +int32_t dfd_ko_i2c_read(int bus, int addr, int offset, uint8_t *buf, uint32_t size); + +int32_t dfd_ko_i2c_write(int bus, int addr, int offset, uint8_t *buf, uint32_t size); + +int32_t dfd_ko_read_file(char *fpath, int32_t addr, uint8_t *val, int32_t read_bytes); + +#endif /* __DFD_CFG_ADAPTER_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_file.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_file.h new file mode 100644 index 000000000000..50d7a42d5564 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_file.h @@ -0,0 +1,37 @@ +#ifndef __DFD_CFG_FILE_H__ +#define __DFD_CFG_FILE_H__ + +#include + +#define KFILE_RV_OK (0) +#define KFILE_RV_INPUT_ERR (-1) +#define KFILE_RV_STAT_FAIL (-2) +#define KFILE_RV_OPEN_FAIL (-3) +#define KFILE_RV_MALLOC_FAIL (-4) +#define KFILE_RV_RD_FAIL (-5) +#define KFILE_RV_ADDR_ERR (-6) +#define KFILE_RV_WR_FAIL (-7) + +#define IS_CR(c) ((c) == '\n') + +typedef struct kfile_ctrl_s { + int32_t size; + int32_t pos; + char *buf; +} kfile_ctrl_t; + +int kfile_open(char *fname, kfile_ctrl_t *kfile_ctrl); + +void kfile_close(kfile_ctrl_t *kfile_ctrl); + +int kfile_gets(char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl); + +int kfile_read(int32_t addr, char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl); + +int kfile_iterate_dir(const char *dir_path, const char *obj_name, char *match_name, int len); + +#if 0 + +int kfile_write(char *fpath, int32_t addr, char *buf, int buf_size); +#endif +#endif /* __DFD_CFG_FILE_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_info.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_info.h new file mode 100644 index 000000000000..88e8f92c10fe --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_info.h @@ -0,0 +1,119 @@ +#ifndef __DFD_CFG_INFO_H__ +#define __DFD_CFG_INFO_H__ + +#include + +typedef int (*info_num_buf_to_value_f)(uint8_t *num_buf, int buf_len, int *num_val); + +typedef int (*info_buf_to_buf_f)(uint8_t *buf, int buf_len, uint8_t *buf_new, int *buf_len_new); + +#define IS_INFO_FRMT_BIT(frmt) ((frmt) == INFO_FRMT_BIT) +#define IS_INFO_FRMT_BYTE(frmt) (((frmt) == INFO_FRMT_BYTE) || ((frmt) == INFO_FRMT_NUM_BYTES)) +#define IS_INFO_FRMT_NUM_STR(frmt) ((frmt) == INFO_FRMT_NUM_STR) +#define IS_INFO_FRMT_NUM_BUF(frmt) ((frmt) == INFO_FRMT_NUM_BUF) +#define IS_INFO_FRMT_BUF(frmt) ((frmt) == INFO_FRMT_BUF) + +#define INFO_INT_MAX_LEN (32) +#define INFO_INT_LEN_VALAID(len) (((len) > 0) && ((len) < INFO_INT_MAX_LEN)) + +#define INFO_BUF_MAX_LEN (128) +#define INFO_BUF_LEN_VALAID(len) (((len) > 0) && ((len) < INFO_BUF_MAX_LEN)) + +#define INFO_BIT_OFFSET_VALID(bit_offset) (((bit_offset) >= 0) && ((bit_offset) < 8)) + +typedef enum info_ctrl_mode_e { + INFO_CTRL_MODE_NONE, + INFO_CTRL_MODE_CFG, + INFO_CTRL_MODE_CONS, + INFO_CTRL_MODE_TLV, + INFO_CTRL_MODE_SRT_CONS, + INFO_CTRL_MODE_END +} info_ctrl_mode_t; + +typedef enum info_frmt_e { + INFO_FRMT_NONE, + INFO_FRMT_BIT, + INFO_FRMT_BYTE, + INFO_FRMT_NUM_BYTES, + INFO_FRMT_NUM_STR, + INFO_FRMT_NUM_BUF, + INFO_FRMT_BUF, + INFO_FRMT_END +} info_frmt_t; + +typedef enum info_src_e { + INFO_SRC_NONE, + INFO_SRC_CPLD, + INFO_SRC_FPGA, + INFO_SRC_OTHER_I2C, + INFO_SRC_FILE, + INFO_SRC_END +} info_src_t; + +typedef enum info_pola_e { + INFO_POLA_NONE, + INFO_POLA_POSI, + INFO_POLA_NEGA, + INFO_POLA_END +} info_pola_t; + +#define INFO_FPATH_MAX_LEN (128) +#define INFO_STR_CONS_MAX_LEN (64) +typedef struct info_ctrl_s { + info_ctrl_mode_t mode; + int32_t int_cons; + info_src_t src; + info_frmt_t frmt; + info_pola_t pola; + char fpath[INFO_FPATH_MAX_LEN]; + int32_t addr; + int32_t len; + int32_t bit_offset; + char str_cons[INFO_STR_CONS_MAX_LEN]; + int32_t int_extra1; + int32_t int_extra2; + int32_t int_extra3; /* cpld voltage mode */ +} info_ctrl_t; + +typedef enum info_ctrl_mem_s { + INFO_CTRL_MEM_MODE, + INFO_CTRL_MEM_INT_CONS, + INFO_CTRL_MEM_SRC, + INFO_CTRL_MEM_FRMT, + INFO_CTRL_MEM_POLA, + INFO_CTRL_MEM_FPATH, + INFO_CTRL_MEM_ADDR, + INFO_CTRL_MEM_LEN, + INFO_CTRL_MEM_BIT_OFFSET, + INFO_CTRL_MEM_STR_CONS, + INFO_CTRL_MEM_INT_EXTRA1, + INFO_CTRL_MEM_INT_EXTRA2, + INFO_CTRL_MEM_INT_EXTRA3, + INFO_CTRL_MEM_END +} info_ctrl_mem_t; + +typedef enum sensor_format_mem_s { + LINEAR11 = 1, + LINEAR16, + TMP464, + MAC_TH5, + MAC_TD3 +} sensor_format_mem_t; + +typedef int (*info_hwmon_buf_f)(uint8_t *buf, int buf_len, uint8_t *buf_new, int *buf_len_new, info_ctrl_t *info_ctrl); + +extern char *g_info_ctrl_mem_str[INFO_CTRL_MEM_END]; +extern char *g_info_src_str[INFO_SRC_END]; +extern char *g_info_frmt_str[INFO_FRMT_END]; +extern char *g_info_pola_str[INFO_POLA_END]; +extern char *g_info_ctrl_mode_str[INFO_CTRL_MODE_END]; + +int dfd_info_get_int(int key, int *ret, info_num_buf_to_value_f pfun); + +int dfd_info_get_buf(int key, uint8_t *buf, int buf_len, info_buf_to_buf_f pfun); + +int dfd_info_set_int(int key, int val); + +int dfd_info_get_sensor(uint32_t key, char *buf, int buf_len, info_hwmon_buf_f pfun); + +#endif /* __DFD_CFG_INFO_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_listnode.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_listnode.h new file mode 100644 index 000000000000..955dfa96e42e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_listnode.h @@ -0,0 +1,30 @@ +#ifndef __DFD_CFG_LISTNODE_H__ +#define __DFD_CFG_LISTNODE_H__ + +#include + +#define LNODE_RV_OK (0) +#define LNODE_RV_INPUT_ERR (-1) +#define LNODE_RV_NODE_EXIST (-2) +#define LNODE_RV_NOMEM (-3) + +typedef struct lnode_root_s { + struct list_head root; +} lnode_root_t; + +typedef struct lnode_node_s { + struct list_head lst; + + int key; + void *data; +} lnode_node_t; + +void *lnode_find_node(lnode_root_t *root, int key); + +int lnode_insert_node(lnode_root_t *root, int key, void *data); + +int lnode_init_root(lnode_root_t *root); + +void lnode_free_list(lnode_root_t *root); + +#endif /* __DFD_CFG_LISTNODE_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_fan_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_fan_driver.h new file mode 100644 index 000000000000..1065fd9eed3f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_fan_driver.h @@ -0,0 +1,18 @@ +#ifndef _DFD_FAN_DRIVER_H_ +#define _DFD_FAN_DRIVER_H_ + +ssize_t dfd_get_fan_speed(unsigned int fan_index, unsigned int motor_index,unsigned int *speed); + +int dfd_set_fan_pwm(unsigned int fan_index, unsigned int motor_index, int pwm); + +int dfd_get_fan_pwm(unsigned int fan_index, unsigned int motor_index, int *pwm); + +int dfd_get_fan_present_status(unsigned int fan_index); + +int dfd_get_fan_roll_status(unsigned int fan_index, unsigned int motor_index); + +int dfd_get_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int *level); + +int dfd_set_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int level); + +#endif /* _DFD_FAN_DRIVER_H_ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_module.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_module.h new file mode 100644 index 000000000000..a547255cf3ab --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_module.h @@ -0,0 +1,96 @@ +#ifndef __DFD_MODULE_H__ +#define __DFD_MODULE_H__ + +typedef enum dfd_rv_s { + DFD_RV_OK = 0, + DFD_RV_INIT_ERR = 1, + DFD_RV_SLOT_INVALID = 2, + DFD_RV_MODE_INVALID = 3, + DFD_RV_MODE_NOTSUPPORT = 4, + DFD_RV_TYPE_ERR = 5, + DFD_RV_DEV_NOTSUPPORT = 6, + DFD_RV_DEV_FAIL = 7, + DFD_RV_INDEX_INVALID = 8, + DFD_RV_NO_INTF = 9, + DFD_RV_NO_NODE = 10, + DFD_RV_NODE_FAIL = 11, + DFD_RV_INVALID_VALUE = 12, + DFD_RV_NO_MEMORY = 13, +} dfd_rv_t; + +typedef enum { + DBG_VERBOSE = 0x01, + DBG_WARN = 0x02, + DBG_ERROR = 0x04, +} dbg_level_t; + +extern int g_dfd_dbg_level; +extern int g_dfd_fan_dbg_level; +extern int g_dfd_slot_dbg_level; +extern int g_dfd_sensor_dbg_level; +extern int g_dfd_psu_dbg_level; +extern int g_dfd_sff_dbg_level; + +#define DBG_DEBUG(level, fmt, arg...) do { \ + if (g_dfd_dbg_level & level) { \ + if(level >= DBG_ERROR) { \ + printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } else { \ + printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } \ + } \ +} while (0) + +#define DFD_FAN_DEBUG(level, fmt, arg...) do { \ + if (g_dfd_fan_dbg_level & level) { \ + if(level >= DBG_ERROR) { \ + printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } else { \ + printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } \ + } \ +} while (0) + +#define DFD_SLOT_DEBUG(level, fmt, arg...) do { \ + if (g_dfd_slot_dbg_level & level) { \ + if(level >= DBG_ERROR) { \ + printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } else { \ + printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } \ + } \ +} while (0) + +#define DFD_SENSOR_DEBUG(level, fmt, arg...) do { \ + if (g_dfd_sensor_dbg_level & level) { \ + if(level >= DBG_ERROR) { \ + printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } else { \ + printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } \ + } \ +} while (0) + +#define DFD_PSU_DEBUG(level, fmt, arg...) do { \ + if (g_dfd_psu_dbg_level & level) { \ + if(level >= DBG_ERROR) { \ + printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } else { \ + printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } \ + } \ +} while (0) + +#define DFD_SFF_DEBUG(level, fmt, arg...) do { \ + if (g_dfd_sff_dbg_level & level) { \ + if(level >= DBG_ERROR) { \ + printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } else { \ + printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } \ + } \ +} while (0) + +int dfd_get_dev_number(unsigned int main_dev_id, unsigned int minor_dev_id); + +#endif /* __DFD_MODULE_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_psu_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_psu_driver.h new file mode 100644 index 000000000000..ce7199660557 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_psu_driver.h @@ -0,0 +1,10 @@ +#ifndef _DFD_PSU_DRIVER_H_ +#define _DFD_PSU_DRIVER_H_ + +int dfd_get_psu_present_status(unsigned int psu_index); + +int dfd_get_psu_output_status(unsigned int psu_index); + +int dfd_get_psu_alert_status(unsigned int psu_index); + +#endif /* _DFD_PSU_DRIVER_H_ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sensors_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sensors_driver.h new file mode 100644 index 000000000000..16733b26029f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sensors_driver.h @@ -0,0 +1,10 @@ +#ifndef _DFD_SENSORS_DRIVER_H_ +#define _DFD_SENSORS_DRIVER_H_ + +ssize_t dfd_get_temp_info(uint8_t main_dev_id, uint8_t dev_index, + uint8_t temp_index, uint8_t temp_attr, char *buf); + +ssize_t dfd_get_voltage_info(uint8_t main_dev_id, uint8_t dev_index, + uint8_t in_index, uint8_t in_attr, char *buf); + +#endif /* _DFD_SENSORS_DRIVER_H_ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sff_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sff_driver.h new file mode 100644 index 000000000000..7107b72ee4b2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sff_driver.h @@ -0,0 +1,8 @@ +#ifndef _DFD_SFF_DRIVER_H_ +#define _DFD_SFF_DRIVER_H_ + +ssize_t dfd_get_sff_cpld_info(unsigned int sff_index, int cpld_reg_type, char *buf, int len); + +ssize_t dfd_get_sff_dir_name(unsigned int sff_index, char *buf, int buf_len); + +#endif /* _DFD_SFF_DRIVER_H_ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_slot_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_slot_driver.h new file mode 100644 index 000000000000..c68caecd2e66 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_slot_driver.h @@ -0,0 +1,6 @@ +#ifndef _DFD_SLOT_DRIVER_H_ +#define _DFD_SLOT_DRIVER_H_ + +int dfd_get_slot_present_status(unsigned int slot_index); + +#endif /* _DFD_SLOT_DRIVER_H_ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/Makefile new file mode 100644 index 000000000000..1a1044bb1fe8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/Makefile @@ -0,0 +1,21 @@ +PWD = $(shell pwd) + +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall +KBUILD_EXTRA_SYMBOLS += $(PLAT_SYSFS_DIR)/dev_cfg/Module.symvers + +obj-m := plat_switch.o +obj-m += plat_fan.o +obj-m += plat_psu.o +obj-m += plat_sff.o +obj-m += plat_sensor.o +obj-m += plat_slot.o + +all: + $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules + @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi + cp -p $(PWD)/*.ko $(module_out_put_dir) +clean: + rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/*.mod + rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order + rm -rf $(PWD)/.tmp_versions diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/plat_switch.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/plat_switch.h new file mode 100644 index 000000000000..bbd813e87114 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/plat_switch.h @@ -0,0 +1,86 @@ +#ifndef _PLAT_SWITCH_H_ +#define _PLAT_SWITCH_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +enum LOG_LEVEL{ + INFO = 0x1, + ERR = 0x2, + DBG = 0x4, + ALL = 0xf +}; + +#define LOG_INFO(_prefix, fmt, args...) \ + do { \ + if (g_loglevel & INFO) \ + { \ + printk( KERN_INFO _prefix "%s "fmt, __FUNCTION__, ##args); \ + } \ + } while (0) + +#define LOG_ERR(_prefix, fmt, args...) \ + do { \ + if (g_loglevel & ERR) \ + { \ + printk( KERN_ERR _prefix "%s "fmt, __FUNCTION__, ##args); \ + } \ + } while (0) + +#define LOG_DBG(_prefix, fmt, args...) \ + do { \ + if (g_loglevel & DBG) \ + { \ + printk( KERN_DEBUG _prefix "%s "fmt, __FUNCTION__, ##args); \ + } \ + } while (0) + +#define check_pfun(p) \ + do { \ + if (p == NULL) { \ + printk( KERN_ERR "%s, %s = NULL.\n", __FUNCTION__, #p); \ + return -ENOSYS; \ + } \ + }while(0) + +#define check_p(p) check_pfun(p) + +#define to_switch_obj(x) container_of(x, struct switch_obj, kobj) +#define to_switch_attr(x) container_of(x, struct switch_attribute, attr) +#define to_switch_device_attr(x) container_of(x, struct switch_device_attribute, switch_attr) + +#define SWITCH_ATTR(_name, _mode, _show, _store, _type) \ + { .switch_attr = __ATTR(_name, _mode, _show, _store), \ + .type = _type } + +#define SWITCH_DEVICE_ATTR(_name, _mode, _show, _store, _type) \ +struct switch_device_attribute switch_dev_attr_##_name \ + = SWITCH_ATTR(_name, _mode, _show, _store, _type) + +struct switch_obj { + struct kobject kobj; + unsigned int index; +}; + +/* a custom attribute that works just for a struct switch_obj. */ +struct switch_attribute { + struct attribute attr; + ssize_t (*show)(struct switch_obj *foo, struct switch_attribute *attr, char *buf); + ssize_t (*store)(struct switch_obj *foo, struct switch_attribute *attr, const char *buf, size_t count); +}; + +struct switch_device_attribute { + struct switch_attribute switch_attr; + int type; +}; + +extern struct switch_obj *wb_plat_kobject_create(const char *name, struct kobject *parent); +extern void wb_plat_kobject_delete(struct switch_obj **obj); + +#endif /* _PLAT_SWITCH_H_ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/sysfs_common.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/sysfs_common.h new file mode 100644 index 000000000000..5b73731e1fbf --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/sysfs_common.h @@ -0,0 +1,90 @@ +#ifndef _SYSFS_COMMON_H_ +#define _SYSFS_COMMON_H_ + +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +#define DIR_NAME_MAX_LEN (64) + +#define WB_SYSFS_DEV_ERROR "NA" +/* sysfs directory name */ +#define FAN_SYSFS_NAME "fan" +#define PSU_SYSFS_NAME "psu" +#define SLOT_SYSFS_NAME "slot" +#define VOLTAGE_SYSFS_NAME "in" +#define TEMP_SYSFS_NAME "temp" +#define SFF_SYSFS_NAME "sff" + +typedef enum wb_main_dev_type_e { + WB_MAIN_DEV_MAINBOARD = 0, + WB_MAIN_DEV_FAN = 1, + WB_MAIN_DEV_PSU = 2, + WB_MAIN_DEV_SFF = 3, + WB_MAIN_DEV_CPLD = 4, + WB_MAIN_DEV_SLOT = 5, +} wb_main_dev_type_t; + +typedef enum wb_minor_dev_type_e { + WB_MINOR_DEV_NONE = 0, /* None */ + WB_MINOR_DEV_TEMP = 1, + WB_MINOR_DEV_IN = 2, + WB_MINOR_DEV_CURR = 3, + WB_MINOR_DEV_POWER = 4, + WB_MINOR_DEV_MOTOR = 5, + WB_MINOR_DEV_PSU = 6, +} wb_minor_dev_type_t; + +typedef enum wb_sensor_type_e { + WB_SENSOR_INPUT = 0, + WB_SENSOR_ALIAS = 1, + WB_SENSOR_TYPE = 2, + WB_SENSOR_MAX = 3, + WB_SENSOR_MAX_HYST = 4, + WB_SENSOR_MIN = 5, + WB_SENSOR_CRIT = 6, +} wb_sensor_type_t; + +typedef enum wb_sff_cpld_attr_e { + WB_SFF_POWER_ON = 0x01, + WB_SFF_TX_FAULT, + WB_SFF_TX_DIS, + WB_SFF_PRE_N, + WB_SFF_RX_LOS, + WB_SFF_RESET, + WB_SFF_LPMODE, + WB_SFF_MODULE_PRESENT, + WB_SFF_INTERRUPT, +} wb_sff_cpld_attr_t; + +struct switch_drivers_t{ + /* device */ + int (*get_dev_number) (unsigned int main_dev_id, unsigned int minor_dev_id); + /* fan */ + int (*get_fan_number) (void); + ssize_t (*get_fan_speed) (unsigned int fan_index, unsigned int motor_index, unsigned int *speed); + int (*get_fan_pwm) (unsigned int fan_index, unsigned int motor_index, int *pwm); + int (*set_fan_pwm) (unsigned int fan_index, unsigned int motor_index, int pwm); + int (*get_fan_present_status)(unsigned int fan_index); + int (*get_fan_roll_status)(unsigned int fan_index, unsigned int motor_index); + int (*get_fan_speed_level)(unsigned int fan_index, unsigned int motor_index, int *level); + int (*set_fan_speed_level)(unsigned int fan_index, unsigned int motor_index, int level); + /* slot */ + int (*get_slot_present_status) (unsigned int slot_index); + /* sensors */ + ssize_t (*get_temp_info)( uint8_t main_dev_id, uint8_t dev_index, + uint8_t temp_index, uint8_t temp_attr, char *buf); + ssize_t (*get_voltage_info)( uint8_t main_dev_id, uint8_t dev_index, + uint8_t in_index, uint8_t in_attr, char *buf); + /* psu */ + int (*get_psu_present_status)(unsigned int psu_index); + int (*get_psu_output_status)(unsigned int psu_index); + int (*get_psu_alert_status)(unsigned int psu_index); + /* sff */ + ssize_t (*get_sff_cpld_info)( unsigned int sff_index, int cpld_reg_type, char *buf, int len); + ssize_t (*get_sff_dir_name)(unsigned int sff_index, char *buf, int buf_len); +}; + +extern struct switch_drivers_t * dfd_plat_driver_get(void); + +#endif /*_SYSFS_COMMON_H_ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_fan.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_fan.c new file mode 100644 index 000000000000..931c7c243a21 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_fan.c @@ -0,0 +1,501 @@ +/* + * plat_fan.c + * + * This module create fan kobjects and attributes in /sys/wb_plat/fan + * + */ + +#include + +#include "./include/plat_switch.h" +#include "./include/sysfs_common.h" + +#define FAN_INFO(fmt, args...) LOG_INFO("fan: ", fmt, ##args) +#define FAN_ERR(fmt, args...) LOG_ERR("fan: ", fmt, ##args) +#define FAN_DBG(fmt, args...) LOG_DBG("fan: ", fmt, ##args) + +struct motor_obj_t{ + struct switch_obj *obj; +}; + +struct fan_obj_t{ + unsigned int motor_number; + struct motor_obj_t *motor; + struct switch_obj *obj; +}; + +struct fan_t{ + unsigned int fan_number; + struct fan_obj_t *fan; +}; + +static int g_loglevel = 0; +static struct fan_t g_fan; +static struct switch_obj *g_fan_obj = NULL; +static struct switch_drivers_t *g_drv = NULL; + +static ssize_t fan_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_fan.fan_number); +} + +static ssize_t fan_motor_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int index; + + index = obj->index; + FAN_DBG("fan_motor_number_show,fan index:%d\n",index); + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_fan.fan[index-1].motor_number); +} + +static ssize_t fan_roll_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int fan_index, motor_index; + struct switch_obj *p_obj; + int ret; + + check_p(g_drv); + check_p(g_drv->get_fan_roll_status); + + p_obj = to_switch_obj(obj->kobj.parent); + check_p(p_obj); + + fan_index = p_obj->index; + motor_index = obj->index; + + ret = g_drv->get_fan_roll_status(fan_index, motor_index); + if (ret < 0 ) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t fan_present_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int fan_index; + int ret; + + fan_index = obj->index; + FAN_DBG("fan_present_status_show, fan index:%d\n",fan_index); + check_p(g_drv); + check_p(g_drv->get_fan_present_status); + + ret = g_drv->get_fan_present_status(fan_index); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t fan_speed_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int fan_index, motor_index, speed; + int ret; + struct switch_obj *p_obj; + + check_p(g_drv); + check_p(g_drv->get_fan_speed); + + p_obj = to_switch_obj(obj->kobj.parent); + check_p(p_obj); + + fan_index = p_obj->index; + motor_index = obj->index; + + ret = g_drv->get_fan_speed(fan_index, motor_index, &speed); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", speed); +} + +static ssize_t fan_motor_ratio_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int fan_index, motor_index; + struct switch_obj *p_obj; + int ret, pwm; + + check_p(g_drv); + check_p(g_drv->get_fan_pwm); + + p_obj = to_switch_obj(obj->kobj.parent); + check_p(p_obj); + fan_index = p_obj->index; + motor_index = obj->index; + ret = g_drv->get_fan_pwm(fan_index, motor_index, &pwm); + + if (ret < 0 ) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", pwm); +} + +static ssize_t fan_motor_ratio_store(struct switch_obj *obj, struct switch_attribute *attr, + const char* buf, size_t count) +{ + unsigned int fan_index, motor_index; + struct switch_obj *p_obj; + int ret, pwm; + + check_p(g_drv); + check_p(g_drv->set_fan_pwm); + + p_obj = to_switch_obj(obj->kobj.parent); + check_p(p_obj); + + fan_index = p_obj->index; + motor_index = obj->index; + sscanf(buf, "%d", &pwm); + + if (pwm < 0 || pwm > 100) { + FAN_ERR("can not set pwm = %d.\n", pwm); + return -EINVAL; + } + ret = g_drv->set_fan_pwm(fan_index, motor_index, pwm); + if (ret < 0) { + FAN_ERR("can not set pwm = %d.\n", pwm); + return -EIO; + } + return count; +} + +/************************************fan dir and attrs*******************************************/ +static struct switch_attribute fan_number_att = __ATTR(num_fans, S_IRUGO, fan_number_show, NULL); + +static struct attribute *fan_dir_attrs[] = { + &fan_number_att.attr, + NULL, +}; + +static struct attribute_group fan_root_attr_group = { + .attrs = fan_dir_attrs, +}; + +/*******************************fan1 fan2 dir and attrs*******************************************/ +static struct switch_attribute fan_num_motors_att = __ATTR(num_motors, S_IRUGO, fan_motor_number_show, NULL); +static struct switch_attribute fan_present_att = __ATTR(present, S_IRUGO, fan_present_status_show, NULL); + +static struct attribute *fan_attrs[] = { + &fan_num_motors_att.attr, + &fan_present_att.attr, + NULL, +}; + +static struct attribute_group fan_attr_group = { + .attrs = fan_attrs, +}; + +/*******************************motor0 motor1 dir and attrs*******************************************/ +static struct switch_attribute motor_speed_att = __ATTR(speed, S_IRUGO, fan_speed_show, NULL); +static struct switch_attribute motor_status_att = __ATTR(status, S_IRUGO, fan_roll_status_show, NULL); +static struct switch_attribute motor_ratio_att = __ATTR(ratio, S_IRUGO | S_IWUSR, fan_motor_ratio_show, fan_motor_ratio_store); + +static struct attribute *motor_attrs[] = { + &motor_speed_att.attr, + &motor_status_att.attr, + &motor_ratio_att.attr, + NULL, +}; + +static struct attribute_group motor_attr_group = { + .attrs = motor_attrs, +}; + +static void fanindex_single_motor_remove_kobj_and_attrs(struct fan_obj_t * curr_fan, unsigned int motor_index) +{ + struct motor_obj_t *curr_motor; /* point to motor0 motor1...*/ + + curr_motor = &curr_fan->motor[motor_index]; + if (curr_motor->obj) { + sysfs_remove_group(&curr_motor->obj->kobj, &motor_attr_group); + wb_plat_kobject_delete(&curr_motor->obj); + FAN_DBG("delete fan:%d motor%d.\n", curr_fan->obj->index, motor_index); + } + return; +} + +static int fanindex_single_motor_create_kobj_and_attrs(struct fan_obj_t * curr_fan, unsigned int motor_index) +{ + char name[DIR_NAME_MAX_LEN]; + struct motor_obj_t *curr_motor; /* point to motor0 motor1...*/ + + FAN_DBG("create fan_index:%d, motor%d ...\n", curr_fan->obj->index, motor_index); + + curr_motor = &curr_fan->motor[motor_index]; + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "motor%d", motor_index); + curr_motor->obj = wb_plat_kobject_create(name, &curr_fan->obj->kobj); + if (!curr_motor->obj) { + FAN_ERR("create fan_index:%d, motor%d object error!\n", curr_fan->obj->index, motor_index); + return -EBADRQC; + } + curr_motor->obj->index = motor_index; + if (sysfs_create_group(&curr_motor->obj->kobj, &motor_attr_group) != 0) { + FAN_ERR("create fan_index:%d, motor%d attrs error.\n", curr_fan->obj->index, motor_index); + wb_plat_kobject_delete(&curr_motor->obj); + return -EBADRQC; + } + FAN_DBG("create fan_index:%d, motor%d ok.\n", curr_fan->obj->index, motor_index); + return 0; +} + +static int fanindex_motor_create_kobj_and_attrs(struct fan_obj_t * curr_fan, int motor_num) +{ + int motor_index, i; + + curr_fan->motor = kzalloc(sizeof(struct motor_obj_t) * motor_num, GFP_KERNEL); + if (!curr_fan->motor) { + FAN_ERR("kzalloc motor error, fan index = %d, motor number = %d.\n", curr_fan->obj->index, motor_num); + return -ENOMEM; + } + curr_fan->motor_number = motor_num; + for (motor_index = 0; motor_index < motor_num; motor_index++) { + if (fanindex_single_motor_create_kobj_and_attrs(curr_fan, motor_index) != 0) { + goto motor_error; + } + } + return 0; +motor_error: + for(i = motor_index - 1; i >= 0; i--) { + fanindex_single_motor_remove_kobj_and_attrs(curr_fan, i); + } + if(curr_fan->motor) { + kfree(curr_fan->motor); + curr_fan->motor = NULL; + } + return -EBADRQC; +} + +static void fanindex_motor_remove_kobj_and_attrs(struct fan_obj_t *curr_fan, int motor_num) +{ + int motor_index; + + for (motor_index = motor_num - 1; motor_index >= 0; motor_index--) { + fanindex_single_motor_remove_kobj_and_attrs(curr_fan, motor_index); + } + return; +} + +static int fan_motor_create(void) +{ + int fan_num, motor_num; + unsigned int fan_index, i; + struct fan_obj_t *curr_fan; /* point to fan1 fan2...*/ + + check_p(g_drv->get_dev_number); + + motor_num = g_drv->get_dev_number(WB_MAIN_DEV_FAN, WB_MINOR_DEV_MOTOR); + if (motor_num <= 0) { + FAN_ERR("get fan motor number error, motor_num:%d error.\n", motor_num); + return -ENODEV; + } + + fan_num = g_fan.fan_number; + for (fan_index = 1; fan_index <= fan_num; fan_index++) { + curr_fan = &g_fan.fan[fan_index - 1]; + if (fanindex_motor_create_kobj_and_attrs(curr_fan, motor_num) != 0) { + goto error; + } + } + return 0; +error: + for (i = fan_index - 1; i > 0; i--) { + curr_fan = &g_fan.fan[i - 1]; + motor_num = curr_fan->motor_number; + fanindex_motor_remove_kobj_and_attrs(curr_fan, motor_num); + } + return -EBADRQC; +} + +static void fan_motor_remove(void) +{ + unsigned int fan_index; + struct fan_obj_t *curr_fan; + + if (g_fan.fan) { + for (fan_index = g_fan.fan_number; fan_index > 0; fan_index--) { + curr_fan = &g_fan.fan[fan_index - 1]; + if (curr_fan->motor) { + fanindex_motor_remove_kobj_and_attrs(curr_fan, curr_fan->motor_number); + kfree(curr_fan->motor); + curr_fan->motor = NULL; + curr_fan->motor_number = 0; + } + } + } + return; +} + +static void fan_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct fan_obj_t *curr_fan; + + curr_fan = &g_fan.fan[index - 1]; + if (curr_fan->obj) { + sysfs_remove_group(&curr_fan->obj->kobj, &fan_attr_group); + wb_plat_kobject_delete(&curr_fan->obj); + FAN_DBG("delete fan%d.\n", index); + } + return; +} + +static int fan_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) +{ + char name[DIR_NAME_MAX_LEN]; + struct fan_obj_t *curr_fan; + + curr_fan = &g_fan.fan[index - 1]; + FAN_DBG("create fan%d ...\n", index); + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "fan%d", index); + curr_fan->obj = wb_plat_kobject_create(name, parent); + if (!curr_fan->obj) { + FAN_ERR("create fan%d object error!\n", index); + return -EBADRQC; + } + curr_fan->obj->index = index; + if (sysfs_create_group(&curr_fan->obj->kobj, &fan_attr_group) != 0) { + FAN_ERR("create fan%d attrs error.\n", index); + wb_plat_kobject_delete(&curr_fan->obj); + return -EBADRQC; + } + FAN_DBG("create fan%d ok.\n", index); + return 0; +} + +static int fan_sub_create_kobj_and_attrs(struct kobject *parent, int fan_num) +{ + unsigned int fan_index, i; + + g_fan.fan = kzalloc(sizeof(struct fan_obj_t) * fan_num, GFP_KERNEL); + if (!g_fan.fan) { + FAN_ERR("kzalloc fan.fan error, fan number = %d.\n", fan_num); + return -ENOMEM; + } + + for (fan_index = 1; fan_index <= fan_num; fan_index++) { + if(fan_sub_single_create_kobj_and_attrs(parent, fan_index) != 0 ) { + goto error; + } + } + return 0; +error: + for (i = fan_index - 1; i > 0; i--) { + fan_sub_single_remove_kobj_and_attrs(i); + } + if (g_fan.fan) { + kfree(g_fan.fan); + g_fan.fan = NULL; + } + return -EBADRQC; +} + +static int fan_sub_create(void) +{ + int ret, fan_num; + + check_p(g_drv->get_dev_number); + fan_num = g_drv->get_dev_number(WB_MAIN_DEV_FAN, WB_MINOR_DEV_NONE); + if (fan_num < 0) { + FAN_ERR("fan number = %d error.\n", fan_num); + return -EINVAL; + } + g_fan.fan_number = fan_num; + ret = fan_sub_create_kobj_and_attrs(&g_fan_obj->kobj, fan_num); + return ret; +} + +static void fan_sub_remove(void) +{ + unsigned int fan_index; + + if (g_fan.fan) { + for (fan_index = g_fan.fan_number; fan_index > 0; fan_index--) { + fan_sub_single_remove_kobj_and_attrs(fan_index); + } + kfree(g_fan.fan); + } + mem_clear(&g_fan, sizeof(struct fan_t)); + return; +} + +static int fan_root_create(void) +{ + g_fan_obj = wb_plat_kobject_create("fan", NULL); + if (!g_fan_obj) { + FAN_ERR("wb_plat_kobject_create fan error!\n"); + return -ENOMEM; + } + + if (sysfs_create_group(&g_fan_obj->kobj, &fan_root_attr_group) != 0) { + wb_plat_kobject_delete(&g_fan_obj); + FAN_ERR("create fan dir attrs error!\n"); + return -EBADRQC; + } + FAN_DBG("wb_plat_kobject_create fan directory and attribute success.\n"); + return 0; +} + +static void fan_root_remove(void) +{ + if (g_fan_obj) { + sysfs_remove_group(&g_fan_obj->kobj, &fan_root_attr_group); + wb_plat_kobject_delete(&g_fan_obj); + FAN_DBG("delete fan root success\n"); + } + + return; +} + +static int fan_init(void) +{ + int ret; + + FAN_INFO("fan_init...\n"); + g_drv = dfd_plat_driver_get(); + check_p(g_drv); + + ret = fan_root_create(); + if (ret < 0) { + goto fan_root_error; + } + + ret = fan_sub_create(); + if (ret < 0) { + goto fan_sub_error; + } + + ret = fan_motor_create(); + if (ret < 0) { + goto fan_motor_error; + } + + FAN_INFO("fan_init ok.\n"); + return 0; +fan_motor_error: + fan_sub_remove(); +fan_sub_error: + fan_root_remove(); +fan_root_error: + return ret; +} + +static void fan_exit(void) +{ + fan_motor_remove(); + fan_sub_remove(); + fan_root_remove(); + FAN_INFO("fan_exit ok.\n"); + return ; +} + +module_init(fan_init); +module_exit(fan_exit); +module_param(g_loglevel, int, 0644); +MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("fan sysfs driver"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_psu.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_psu.c new file mode 100644 index 000000000000..197f94b64991 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_psu.c @@ -0,0 +1,426 @@ +/* + * plat_psu.c + * + * This module create psu kobjects and attributes in /sys/wb_plat/psu + * + */ + +#include + +#include "./include/plat_switch.h" +#include "./include/sysfs_common.h" + +#define PSU_INFO(fmt, args...) LOG_INFO("psu: ", fmt, ##args) +#define PSU_ERR(fmt, args...) LOG_ERR("psu: ", fmt, ##args) +#define PSU_DBG(fmt, args...) LOG_DBG("psu: ", fmt, ##args) + +struct temp_obj_t{ + struct switch_obj *obj; +}; + +struct psu_obj_t{ + unsigned int temp_number; + struct temp_obj_t *temp; + struct switch_obj *obj; +}; + +struct psu_t{ + unsigned int psu_number; + struct psu_obj_t *psu; +}; + +static int g_loglevel = 0; +static struct psu_t g_psu; +static struct switch_obj *g_psu_obj = NULL; +static struct switch_drivers_t *g_drv = NULL; + +static ssize_t psu_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_psu.psu_number); +} + +static ssize_t psu_present_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int psu_index; + int ret; + + psu_index = obj->index; + PSU_DBG("psu_present_status_show, psu index:%d\n",psu_index); + check_p(g_drv); + check_p(g_drv->get_psu_present_status); + + ret = g_drv->get_psu_present_status(psu_index); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t psu_output_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int psu_index; + int ret; + + psu_index = obj->index; + PSU_DBG("psu_output_status_show, psu index:%d\n",psu_index); + check_p(g_drv); + check_p(g_drv->get_psu_output_status); + + ret = g_drv->get_psu_output_status(psu_index); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t psu_alert_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int psu_index; + int ret; + + psu_index = obj->index; + PSU_DBG("psu_alert_status_show, psu index:%d\n",psu_index); + check_p(g_drv); + check_p(g_drv->get_psu_alert_status); + + ret = g_drv->get_psu_alert_status(psu_index); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +/************************************psu dir and attrs*******************************************/ +static struct switch_attribute psu_number_att = __ATTR(num_psus, S_IRUGO, psu_number_show, NULL); + +static struct attribute *psu_dir_attrs[] = { + &psu_number_att.attr, + NULL, +}; + +static struct attribute_group psu_root_attr_group = { + .attrs = psu_dir_attrs, +}; + +/*******************************psu1 psu2 dir and attrs*******************************************/ +static struct switch_attribute psu_present_status_att = __ATTR(present, S_IRUGO, psu_present_status_show, NULL); +static struct switch_attribute psu_output_status_att = __ATTR(output, S_IRUGO, psu_output_status_show, NULL); +static struct switch_attribute psu_alert_status_att = __ATTR(alert, S_IRUGO, psu_alert_status_show, NULL); + +static struct attribute *psu_attrs[] = { + &psu_present_status_att.attr, + &psu_output_status_att.attr, + &psu_alert_status_att.attr, + NULL, +}; + +static struct attribute_group psu_attr_group = { + .attrs = psu_attrs, +}; + +/*******************************psu temp0 temp1 dir and attrs*******************************************/ +static struct attribute *psu_temp_attrs[] = { + NULL, +}; + +static struct attribute_group psu_temp_attr_group = { + .attrs = psu_temp_attrs, +}; + +static void psuindex_single_temp_remove_kobj_and_attrs(struct psu_obj_t * curr_psu, unsigned int temp_index) +{ + + struct temp_obj_t *curr_temp; /* point to temp0 temp1...*/ + + curr_temp = &curr_psu->temp[temp_index]; + if (curr_temp->obj) { + sysfs_remove_group(&curr_temp->obj->kobj, &psu_temp_attr_group); + wb_plat_kobject_delete(&curr_temp->obj); + PSU_DBG("delete psu:%d temp%d.\n", curr_psu->obj->index, temp_index); + } + return; +} + +static int psuindex_single_temp_create_kobj_and_attrs(struct psu_obj_t * curr_psu, unsigned int temp_index) +{ + char name[DIR_NAME_MAX_LEN]; + struct temp_obj_t *curr_temp; /* point to temp0 temp1...*/ + + PSU_DBG("create psu_index:%d, temp%d ...\n", curr_psu->obj->index, temp_index); + + curr_temp = &curr_psu->temp[temp_index]; + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "temp%d", temp_index); + curr_temp->obj = wb_plat_kobject_create(name, &curr_psu->obj->kobj); + if (!curr_temp->obj) { + PSU_ERR("create psu_index:%d, temp%d object error!\n", curr_psu->obj->index, temp_index); + return -EBADRQC; + } + curr_temp->obj->index = temp_index; + if (sysfs_create_group(&curr_temp->obj->kobj, &psu_temp_attr_group) != 0) { + PSU_ERR("create psu_index:%d, temp%d attrs error.\n", curr_psu->obj->index, temp_index); + wb_plat_kobject_delete(&curr_temp->obj); + return -EBADRQC; + } + PSU_DBG("create psu_index:%d, temp%d ok.\n", curr_psu->obj->index, temp_index); + return 0; +} + +static int psuindex_temp_create_kobj_and_attrs(struct psu_obj_t * curr_psu, int temp_num) +{ + int temp_index, i; + + curr_psu->temp = kzalloc(sizeof(struct temp_obj_t) * temp_num, GFP_KERNEL); + if (!curr_psu->temp) { + PSU_ERR("kzalloc temp error, psu index = %d, temp number = %d.\n", curr_psu->obj->index, temp_num); + return -ENOMEM; + } + curr_psu->temp_number = temp_num; + for (temp_index = 0; temp_index < temp_num; temp_index++) { + if (psuindex_single_temp_create_kobj_and_attrs(curr_psu, temp_index) != 0) { + goto temp_error; + } + } + return 0; +temp_error: + for (i = temp_index - 1; i >= 0; i--) { + psuindex_single_temp_remove_kobj_and_attrs(curr_psu, i); + } + if (curr_psu->temp) { + kfree(curr_psu->temp); + curr_psu->temp = NULL; + } + return -EBADRQC; +} + +static void psuindex_temp_remove_kobj_and_attrs(struct psu_obj_t * curr_psu, int temp_num) +{ + unsigned int temp_index; + + for (temp_index = temp_num - 1; temp_index >= 0; temp_index--) { + psuindex_single_temp_remove_kobj_and_attrs(curr_psu, temp_index); + } + return; +} + +static int psu_temp_create(void) +{ + int psu_num, temp_num; + unsigned int psu_index, i; + struct psu_obj_t *curr_psu; /* point to psu1 psu2...*/ + + check_p(g_drv->get_dev_number); + temp_num = g_drv->get_dev_number(WB_MAIN_DEV_PSU, WB_MINOR_DEV_TEMP); + if (temp_num <= 0) { + PSU_INFO("psu temp_num:%d, don't need creat temp directory.\n", temp_num); + return 0; + } + + psu_num = g_psu.psu_number; + for(psu_index = 1; psu_index <= psu_num; psu_index++) { + curr_psu = &g_psu.psu[psu_index - 1]; + if(psuindex_temp_create_kobj_and_attrs(curr_psu, temp_num) != 0) { + goto error; + } + } + return 0; +error: + for(i = psu_index - 1; i > 0; i--) { + curr_psu = &g_psu.psu[i - 1]; + temp_num = curr_psu->temp_number; + psuindex_temp_remove_kobj_and_attrs(curr_psu, temp_num); + } + return -EBADRQC; +} + +static void psu_temp_remove(void) +{ + unsigned int psu_index; + struct psu_obj_t *curr_psu; + + if (g_psu.psu) { + for (psu_index = g_psu.psu_number; psu_index > 0; psu_index--) { + curr_psu = &g_psu.psu[psu_index - 1]; + if (curr_psu->temp) { + psuindex_temp_remove_kobj_and_attrs(curr_psu,curr_psu->temp_number); + kfree(curr_psu->temp); + curr_psu->temp = NULL; + curr_psu->temp_number = 0; + } + } + } + return; +} + +static void psu_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct psu_obj_t *curr_psu; + + curr_psu = &g_psu.psu[index - 1]; + if (curr_psu->obj) { + sysfs_remove_group(&curr_psu->obj->kobj, &psu_attr_group); + wb_plat_kobject_delete(&curr_psu->obj); + PSU_DBG("delete psu%d.\n", index); + } + return; +} + +static int psu_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) +{ + char name[DIR_NAME_MAX_LEN]; + struct psu_obj_t *curr_psu; + + curr_psu = &g_psu.psu[index-1]; + PSU_DBG("create psu%d ...\n", index); + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "%s%d",PSU_SYSFS_NAME, index); + curr_psu->obj = wb_plat_kobject_create(name, parent); + if (!curr_psu->obj) { + PSU_ERR("create psu%d object error!\n", index); + return -EBADRQC; + } + curr_psu->obj->index = index; + if (sysfs_create_group(&curr_psu->obj->kobj, &psu_attr_group) != 0) { + PSU_ERR("create psu%d attrs error.\n", index); + wb_plat_kobject_delete(&curr_psu->obj); + return -EBADRQC; + } + PSU_DBG("create psu%d ok.\n", index); + return 0; +} + +static int psu_sub_create_kobj_and_attrs(struct kobject *parent, int psu_num) +{ + unsigned int psu_index, i; + + g_psu.psu = kzalloc(sizeof(struct psu_obj_t) * psu_num, GFP_KERNEL); + if (!g_psu.psu) { + PSU_ERR("kzalloc psu.psu error, psu number = %d.\n", psu_num); + return -ENOMEM; + } + + for (psu_index = 1; psu_index <= psu_num; psu_index++) { + if (psu_sub_single_create_kobj_and_attrs(parent, psu_index) != 0) { + goto error; + } + } + return 0; +error: + for(i = psu_index - 1; i > 0; i--) { + psu_sub_single_remove_kobj_and_attrs(i); + } + if(g_psu.psu) { + kfree(g_psu.psu); + g_psu.psu = NULL; + } + return -EBADRQC; +} + +static int psu_sub_create(void) +{ + int ret, psu_num; + + check_p(g_drv->get_dev_number); + psu_num = g_drv->get_dev_number(WB_MAIN_DEV_PSU, WB_MINOR_DEV_NONE); + if (psu_num < 0) { + PSU_ERR("psu number = %d error.\n", psu_num); + return -EINVAL; + } + g_psu.psu_number = psu_num; + ret = psu_sub_create_kobj_and_attrs(&g_psu_obj->kobj, psu_num); + return ret; +} + +static void psu_sub_remove(void) +{ + unsigned int psu_index; + + if (g_psu.psu) { + for (psu_index = g_psu.psu_number; psu_index > 0; psu_index--) { + psu_sub_single_remove_kobj_and_attrs(psu_index); + } + kfree(g_psu.psu); + } + mem_clear(&g_psu, sizeof(struct psu_t)); + return ; +} + +static int psu_root_create(void) +{ + g_psu_obj = wb_plat_kobject_create(PSU_SYSFS_NAME, NULL); + if (!g_psu_obj) { + PSU_ERR("wb_plat_kobject_create psu error!\n"); + return -ENOMEM; + } + + if (sysfs_create_group(&g_psu_obj->kobj, &psu_root_attr_group) != 0) { + wb_plat_kobject_delete(&g_psu_obj); + PSU_ERR("create psu dir attrs error!\n"); + return -EBADRQC; + } + PSU_DBG("wb_plat_kobject_create psu directory and attribute success.\n"); + return 0; +} + +static void psu_root_remove(void) +{ + if (g_psu_obj) { + sysfs_remove_group(&g_psu_obj->kobj, &psu_root_attr_group); + wb_plat_kobject_delete(&g_psu_obj); + PSU_DBG("delete psu root success\n"); + } + return; +} + +static int wb_psu_init(void) +{ + int ret; + + PSU_INFO("wb_psu_init...\n"); + g_drv = dfd_plat_driver_get(); + check_p(g_drv); + + ret = psu_root_create(); + if (ret < 0) { + goto psu_root_error; + } + + ret = psu_sub_create(); + if (ret < 0) { + goto psu_sub_error; + } + + ret = psu_temp_create(); + if (ret < 0) { + goto psu_temp_error; + } + + PSU_INFO("wb_psu_init ok.\n"); + return 0; +psu_temp_error: + psu_sub_remove(); +psu_sub_error: + psu_root_remove(); +psu_root_error: + return ret; +} + +static void wb_psu_exit(void) +{ + psu_temp_remove(); + psu_sub_remove(); + psu_root_remove(); + PSU_INFO("wb_psu_exit ok.\n"); + return ; +} + +module_init(wb_psu_init); +module_exit(wb_psu_exit); +module_param(g_loglevel, int, 0644); +MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("psu sysfs driver"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sensor.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sensor.c new file mode 100644 index 000000000000..aaf62f4c1a3c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sensor.c @@ -0,0 +1,452 @@ +/* + * plat_sensor.c + * + * This module create sensor kobjects and attributes in /sys/wb_plat/sensor + */ + +#include + +#include "./include/plat_switch.h" +#include "./include/sysfs_common.h" + +#define SENSOR_INFO(fmt, args...) LOG_INFO("sensor: ", fmt, ##args) +#define SENSOR_ERR(fmt, args...) LOG_ERR("sensor: ", fmt, ##args) +#define SENSOR_DBG(fmt, args...) LOG_DBG("sensor: ", fmt, ##args) + +struct sensor_t { + unsigned int in_number; + unsigned int temp_number; + struct sensor_in_t *in; + struct sensor_temp_t *temp; +}; + +struct sensor_temp_t { + struct switch_obj *obj; +}; + +struct sensor_in_t { + struct switch_obj *obj; +}; + +static int g_loglevel = 0; +static struct switch_drivers_t *g_drv = NULL; +static struct sensor_t g_sensor; +static struct switch_obj *g_sensor_obj = NULL; + +static ssize_t sensor_temp_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_sensor.temp_number); +} + +static ssize_t sensor_in_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_sensor.in_number); +} + +static ssize_t sensor_voltage_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int in_index; + int ret; + struct switch_device_attribute *in_attr; + + check_p(g_drv); + check_p(g_drv->get_voltage_info); + in_index = obj->index; + + in_attr = to_switch_device_attr(attr); + check_p(in_attr); + SENSOR_DBG("sensor_in_show, in index:0x%x, in type:0x%x\n",in_index, in_attr->type); + ret = g_drv->get_voltage_info(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_NONE, in_index, in_attr->type, buf); + if (ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + return ret; +} + +static ssize_t sensor_temp_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int temp_index; + int ret; + struct switch_device_attribute *temp_attr; + + check_p(g_drv); + check_p(g_drv->get_temp_info); + temp_index = obj->index; + + temp_attr = to_switch_device_attr(attr); + check_p(temp_attr); + SENSOR_DBG("sensor_temp_show, temp index:0x%x, temp type:0x%x\n", temp_index, temp_attr->type); + ret = g_drv->get_temp_info(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_NONE, temp_index, temp_attr->type, buf); + if (ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + return ret; +} + +/************************************sensor dir and attrs*******************************************/ +static struct switch_attribute num_temp_att = __ATTR(num_temp_sensors, S_IRUGO, sensor_temp_number_show, NULL); +static struct switch_attribute num_in_att = __ATTR(num_in_sensors, S_IRUGO, sensor_in_number_show, NULL); + +static struct attribute *sensor_dir_attrs[] = { + &num_temp_att.attr, + &num_in_att.attr, + NULL, +}; + +static struct attribute_group sensor_root_attr_group = { + .attrs = sensor_dir_attrs, +}; + +/*******************************temp0 temp1 dir and attrs*******************************************/ +static SWITCH_DEVICE_ATTR(temp_input, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_INPUT); +static SWITCH_DEVICE_ATTR(temp_alias, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_ALIAS); +static SWITCH_DEVICE_ATTR(temp_type, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_TYPE); +static SWITCH_DEVICE_ATTR(temp_max, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_MAX); +static SWITCH_DEVICE_ATTR(temp_max_hyst, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_MAX_HYST); +static SWITCH_DEVICE_ATTR(temp_min, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_MIN); + +static struct attribute *sensor_temp_attrs[] = { + &switch_dev_attr_temp_input.switch_attr.attr, + &switch_dev_attr_temp_alias.switch_attr.attr, + &switch_dev_attr_temp_type.switch_attr.attr, + &switch_dev_attr_temp_max.switch_attr.attr, + &switch_dev_attr_temp_max_hyst.switch_attr.attr, + &switch_dev_attr_temp_min.switch_attr.attr, + NULL, +}; + +static struct attribute_group sensor_temp_attr_group = { + .attrs = sensor_temp_attrs, +}; + +/*******************************in0 in1 dir and attrs*******************************************/ +static SWITCH_DEVICE_ATTR(in_input, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_INPUT); +static SWITCH_DEVICE_ATTR(in_alias, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_ALIAS); +static SWITCH_DEVICE_ATTR(in_type, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_TYPE); +static SWITCH_DEVICE_ATTR(in_max, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_MAX); +static SWITCH_DEVICE_ATTR(in_min, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_MIN); +static SWITCH_DEVICE_ATTR(in_crit, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_CRIT); + +static struct attribute *sensor_in_attrs[] = { + &switch_dev_attr_in_input.switch_attr.attr, + &switch_dev_attr_in_alias.switch_attr.attr, + &switch_dev_attr_in_type.switch_attr.attr, + &switch_dev_attr_in_max.switch_attr.attr, + &switch_dev_attr_in_min.switch_attr.attr, + &switch_dev_attr_in_crit.switch_attr.attr, + NULL, +}; + +static struct attribute_group sensor_in_attr_group = { + .attrs = sensor_in_attrs, +}; + +static int sensor_in_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) +{ + char name[DIR_NAME_MAX_LEN]; + struct sensor_in_t *curr_sensor; + + curr_sensor = &g_sensor.in[index - 1]; + SENSOR_DBG("create sensor in%d ...\n", index); + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "in%d", index); + curr_sensor->obj = wb_plat_kobject_create(name, parent); + if (!curr_sensor->obj) { + SENSOR_ERR("create sensor in%d object error!\n", index); + return -EBADRQC; + } + curr_sensor->obj->index = index; + if (sysfs_create_group(&curr_sensor->obj->kobj, &sensor_in_attr_group) != 0) { + SENSOR_ERR("create sensor in%d attrs error.\n", index); + wb_plat_kobject_delete(&curr_sensor->obj); + return -EBADRQC; + } + SENSOR_DBG("create sensor in%d ok.\n", index); + return 0; + +} + +static void sensor_in_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct sensor_in_t *curr_in; + + curr_in = &g_sensor.in[index - 1]; + if (curr_in->obj) { + sysfs_remove_group(&curr_in->obj->kobj, &sensor_in_attr_group); + wb_plat_kobject_delete(&curr_in->obj); + SENSOR_DBG("delete in%d.\n", index); + } + return; +} + +static int sensor_temp_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) +{ + char name[DIR_NAME_MAX_LEN]; + struct sensor_temp_t *curr_sensor; + + curr_sensor = &g_sensor.temp[index - 1]; + SENSOR_DBG("create sensor temp%d ...\n", index); + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "temp%d", index); + curr_sensor->obj = wb_plat_kobject_create(name, parent); + if (!curr_sensor->obj) { + SENSOR_ERR("create sensor temp%d object error!\n", index); + return -EBADRQC; + } + curr_sensor->obj->index = index; + if (sysfs_create_group(&curr_sensor->obj->kobj, &sensor_temp_attr_group) != 0) { + SENSOR_ERR("create sensor temp%d attrs error.\n", index); + wb_plat_kobject_delete(&curr_sensor->obj); + return -EBADRQC; + } + SENSOR_DBG("create sensor temp%d ok.\n", index); + return 0; + +} + +static void sensor_temp_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct sensor_temp_t *curr_temp; + + curr_temp = &g_sensor.temp[index - 1]; + if (curr_temp->obj) { + sysfs_remove_group(&curr_temp->obj->kobj, &sensor_temp_attr_group); + wb_plat_kobject_delete(&curr_temp->obj); + SENSOR_DBG("delete temp%d.\n", index); + } + return; +} + +static int sensor_temp_sub_create_kobj_and_attrs(struct kobject *parent, int temp_num) +{ + unsigned int temp_index, i; + + g_sensor.temp = kzalloc(sizeof(struct sensor_temp_t) * temp_num, GFP_KERNEL); + if (!g_sensor.temp ) { + SENSOR_ERR("kzalloc g_sensor.temp error, temp number = %d.\n", temp_num); + return -ENOMEM; + } + for (temp_index = 1; temp_index <= temp_num; temp_index++) { + if (sensor_temp_sub_single_create_kobj_and_attrs(parent, temp_index) != 0 ) { + goto error; + } + } + return 0; +error: + for (i = temp_index - 1; i > 0; i--) { + sensor_temp_sub_single_remove_kobj_and_attrs(i); + } + + if (g_sensor.temp) { + kfree(g_sensor.temp); + g_sensor.temp = NULL; + } + return -EBADRQC; +} + +static int sensor_in_sub_create_kobj_and_attrs(struct kobject *parent, int in_num) +{ + unsigned int in_index, i; + + g_sensor.in = kzalloc(sizeof(struct sensor_in_t) * in_num, GFP_KERNEL); + if (!g_sensor.in) { + SENSOR_ERR("kzalloc g_sensor.in error, in number = %d.\n", in_num); + return -ENOMEM; + } + + for (in_index = 1; in_index <= in_num; in_index++) { + if (sensor_in_sub_single_create_kobj_and_attrs(parent, in_index) != 0 ) { + goto error; + } + } + return 0; +error: + for (i = in_index - 1; i > 0; i--) { + sensor_in_sub_single_remove_kobj_and_attrs(i); + } + + if (g_sensor.in) { + kfree(g_sensor.in); + g_sensor.in = NULL; + } + return -EBADRQC; +} + +static int sensor_temp_sub_create(void) +{ + int ret, temp_num; + + check_p(g_drv->get_dev_number); + temp_num = g_drv->get_dev_number(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_TEMP); + g_sensor.temp_number = temp_num; + if (temp_num <= 0) { + SENSOR_DBG("Warning:sensor temp number = %d \n", temp_num); + return 0; + } + ret = sensor_temp_sub_create_kobj_and_attrs(&g_sensor_obj->kobj, temp_num); + return ret; +} + +static int sensor_in_sub_create(void) +{ + int ret, in_num; + + check_p(g_drv->get_dev_number); + in_num = g_drv->get_dev_number(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_IN); + g_sensor.in_number = in_num; + + if (in_num <= 0) { + SENSOR_DBG("Warning:sensor in number = %d \n", in_num); + return 0; + } + ret = sensor_in_sub_create_kobj_and_attrs(&g_sensor_obj->kobj, in_num); + return ret; +} + +static void temp_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct sensor_temp_t * curr_temp; + + curr_temp = &g_sensor.temp[index - 1]; + if (curr_temp->obj) { + sysfs_remove_group(&curr_temp->obj->kobj, &sensor_temp_attr_group); + wb_plat_kobject_delete(&curr_temp->obj); + SENSOR_DBG("delete sensor temp%d.\n", index); + } + return; +} + +static void in_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct sensor_in_t * curr_in; + + curr_in = &g_sensor.in[index - 1]; + if (curr_in->obj) { + sysfs_remove_group(&curr_in->obj->kobj, &sensor_in_attr_group); + wb_plat_kobject_delete(&curr_in->obj); + SENSOR_DBG("delete sensor in%d.\n", index); + } + return; +} + +static void sensor_temp_sub_remove(void) +{ + unsigned int temp_index; + + if (g_sensor.temp) { + for (temp_index = g_sensor.temp_number; temp_index > 0; temp_index--) { + temp_sub_single_remove_kobj_and_attrs(temp_index); + } + kfree(g_sensor.temp); + g_sensor.temp = NULL; + } + return; +} + +static void sensor_in_sub_remove(void) +{ + unsigned int in_index; + + if (g_sensor.in) { + for (in_index = g_sensor.in_number; in_index > 0; in_index--) { + in_sub_single_remove_kobj_and_attrs(in_index); + } + kfree(g_sensor.in); + g_sensor.in = NULL; + } + return; +} + +static void sensor_sub_remove(void) +{ + sensor_temp_sub_remove(); + sensor_in_sub_remove(); +} + +static int sensor_sub_create(void) +{ + int ret; + /* temp creat */ + ret = sensor_temp_sub_create(); + if (ret < 0) { + goto temp_err; + } + /* Voltage creat */ + ret = sensor_in_sub_create(); + if (ret < 0) { + goto in_err; + } + return 0; +in_err: + sensor_temp_sub_remove(); +temp_err: + return ret; +} +static void sensor_root_remove(void) +{ + if (g_sensor_obj) { + sysfs_remove_group(&g_sensor_obj->kobj, &sensor_root_attr_group); + wb_plat_kobject_delete(&g_sensor_obj); + SENSOR_DBG("delete sensor root success\n"); + } + + return; +} + +static int sensor_root_create(void) +{ + g_sensor_obj = wb_plat_kobject_create("sensor", NULL); + if (!g_sensor_obj) { + SENSOR_ERR("wb_plat_kobject_create sensor error!\n"); + return -ENOMEM; + } + + if (sysfs_create_group(&g_sensor_obj->kobj, &sensor_root_attr_group) != 0) { + wb_plat_kobject_delete(&g_sensor_obj); + SENSOR_ERR("create sensor dir attrs error!\n"); + return -EBADRQC; + } + SENSOR_DBG("wb_plat_kobject_create sensor directory and attribute success.\n"); + return 0; +} + +static int wb_sensor_init(void) +{ + int ret; + + SENSOR_INFO("wb_sensor_init...\n"); + g_drv = dfd_plat_driver_get(); + check_p(g_drv); + + ret = sensor_root_create(); + if (ret < 0) { + goto sensor_root_error; + } + + ret = sensor_sub_create(); + if (ret < 0) { + goto sensor_sub_error; + } + SENSOR_INFO("sensor_init ok.\n"); + return 0; +sensor_sub_error: + sensor_root_remove(); +sensor_root_error: + return ret; +} + +static void wb_sensor_exit(void) +{ + sensor_sub_remove(); + sensor_root_remove(); + SENSOR_INFO("sensor_exit ok.\n"); + return; +} + +module_init(wb_sensor_init); +module_exit(wb_sensor_exit); +module_param(g_loglevel, int, 0644); +MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("sensors sysfs driver"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sff.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sff.c new file mode 100644 index 000000000000..50c0f78aede9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sff.c @@ -0,0 +1,287 @@ +/* + * plat_sff.c + * + * This module create sff kobjects and attributes in /sys/wb_plat/sff + * + */ + +#include + +#include "./include/plat_switch.h" +#include "./include/sysfs_common.h" + +#define SFF_INFO(fmt, args...) LOG_INFO("sff: ", fmt, ##args) +#define SFF_ERR(fmt, args...) LOG_ERR("sff: ", fmt, ##args) +#define SFF_DBG(fmt, args...) LOG_DBG("sff: ", fmt, ##args) + +struct sff_obj_t{ + struct switch_obj *sff_obj; + struct bin_attribute bin; + int sff_creat_bin_flag; +}; + +struct sff_t{ + unsigned int sff_number; + struct sff_obj_t *sff; +}; + +static int g_loglevel = 0; +static struct sff_t g_sff; +static struct switch_obj *g_sff_obj = NULL; +static struct switch_drivers_t *g_drv = NULL; + +static ssize_t sff_cpld_info_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int sff_index; + int ret; + struct switch_device_attribute *sff_cpld_attr; + + check_p(g_drv); + check_p(g_drv->get_sff_cpld_info); + + sff_index = obj->index; + sff_cpld_attr = to_switch_device_attr(attr); + check_p(sff_cpld_attr); + SFF_DBG("sff_cpld_info_show, sff index:0x%x, sff cpld attr type:0x%x\n", sff_index, sff_cpld_attr->type); + ret = g_drv->get_sff_cpld_info(sff_index, sff_cpld_attr->type, buf, PAGE_SIZE); + if(ret < 0) { + SFF_ERR("sff_cpld_info_show error. sff index:0x%x, sff cpld attr type:0x%x, ret:%d\n", + sff_index, sff_cpld_attr->type,ret ); + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + SFF_DBG("sff_cpld_info_show ok. sff index:0x%x, sff cpld attr type:0x%x, ret:%d\n", sff_index, sff_cpld_attr->type, ret); + return ret; +} + +static ssize_t sff_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_sff.sff_number); +} + +/************************************sff attrs*******************************************/ +static struct switch_attribute sff_number_att = __ATTR(num_sffs, S_IRUGO, sff_number_show, NULL); +static SWITCH_DEVICE_ATTR(present, S_IRUGO, sff_cpld_info_show, NULL, WB_SFF_MODULE_PRESENT); + +/*******************************xcvr dir and attrs*******************************************/ +static struct attribute *xcvr_dir_attrs[] = { + &sff_number_att.attr, + NULL, +}; + +static struct attribute_group sff_xcvr_attr_group = { + .attrs = xcvr_dir_attrs, +}; + +/*******************************sff dir and attrs*******************************************/ +static struct attribute *sff_attrs[] = { + &switch_dev_attr_present.switch_attr.attr, + NULL, +}; + +static struct attribute_group sff_attr_group = { + .attrs = sff_attrs, +}; + +static int sff_sub_single_create_attrs(unsigned int index) +{ + struct sff_obj_t *curr_sff; + + curr_sff = &g_sff.sff[index-1]; + if (sysfs_create_group(&curr_sff->sff_obj->kobj, &sff_attr_group) != 0) { + SFF_ERR("create sff%d dir attrs error!\n", index); + wb_plat_kobject_delete(&curr_sff->sff_obj); + return -EBADRQC; + } + SFF_DBG("create sff%d dir attrs ok!\n", index); + return 0; +} + +static int sff_sub_single_create_kobj(struct kobject *parent, unsigned int index) +{ + struct sff_obj_t *curr_sff; + char sff_dir_name[DIR_NAME_MAX_LEN]; + int ret; + + check_p(g_drv->get_sff_dir_name); + ret = g_drv->get_sff_dir_name(index, sff_dir_name, sizeof(sff_dir_name)); + if (ret < 0) { + SFF_ERR("sff index:%d, get sff dir name error. please check sff config.\n", index); + return -ENOSYS; + } + + curr_sff = &g_sff.sff[index - 1]; + + curr_sff->sff_obj = wb_plat_kobject_create(sff_dir_name, parent); + if (!curr_sff->sff_obj) { + SFF_ERR("sff index:%d, create %s object error! \n", index, sff_dir_name); + return -EBADRQC; + } + + SFF_DBG("create sff kobj ok. sff index:%d, dir name:%s\n",index, sff_dir_name); + curr_sff->sff_obj->index = index; + + return 0; +} + +static void sff_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct sff_obj_t *curr_sff; + + curr_sff = &g_sff.sff[index - 1]; + /* remove sff dir and attr */ + if (curr_sff->sff_obj) { + SFF_DBG("delete sff%d attrs.\n", curr_sff->sff_obj->index); + curr_sff->sff_obj->index = 0; + sysfs_remove_group(&curr_sff->sff_obj->kobj, &sff_attr_group); + wb_plat_kobject_delete(&curr_sff->sff_obj); + } + + return; +} + +static int sff_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) +{ + int ret; + + ret = sff_sub_single_create_kobj(parent, index); + if (ret < 0) { + SFF_ERR("sff index:%d, create sff dir error.\n", index); + return ret; + } + + ret = sff_sub_single_create_attrs(index); + if (ret < 0) { + SFF_ERR("sff index:%d, create sff attr error.\n", index); + return ret; + } + return 0; +} + +static int sff_sub_create_kobj_and_attrs(struct kobject *parent, int sff_num) +{ + unsigned int sff_index, i; + + g_sff.sff = kzalloc(sizeof(struct sff_obj_t) * sff_num, GFP_KERNEL); + if (!g_sff.sff) { + SFF_ERR("kzalloc g_sff.sff error, sff number = %d.\n", sff_num); + return -ENOMEM; + } + + for (sff_index = 1; sff_index <= sff_num; sff_index++) { + if (sff_sub_single_create_kobj_and_attrs(parent, sff_index) != 0 ) { + goto error; + } + } + return 0; +error: + for (i = sff_index - 1; i > 0; i--) { + sff_sub_single_remove_kobj_and_attrs(i); + } + if (g_sff.sff) { + kfree(g_sff.sff); + g_sff.sff = NULL; + } + return -EBADRQC; +} + +static int sff_sub_create(void) +{ + int ret, sff_num; + + check_p(g_drv->get_dev_number); + sff_num = g_drv->get_dev_number(WB_MAIN_DEV_SFF, WB_MINOR_DEV_NONE); + g_sff.sff_number = sff_num; + if (sff_num <= 0) { + SFF_ERR("ERROR. port number:%d\n", sff_num); + return -EINVAL; + } + + ret = sff_sub_create_kobj_and_attrs(&g_sff_obj->kobj, sff_num); + + return ret; +} + +static void sff_sub_remove(void) +{ + unsigned int sff_index; + + if (g_sff.sff) { + for (sff_index = g_sff.sff_number; sff_index > 0; sff_index--) { + sff_sub_single_remove_kobj_and_attrs(sff_index); + } + kfree(g_sff.sff); + } + mem_clear(&g_sff, sizeof(struct sff_t)); + return ; +} + +static int sff_xcvr_create(void) +{ + g_sff_obj = wb_plat_kobject_create(SFF_SYSFS_NAME, NULL); + if (!g_sff_obj) { + SFF_ERR("wb_plat_kobject_create sff error!\n"); + return -ENOMEM; + } + + g_sff_obj->index = 0; + if (sysfs_create_group(&g_sff_obj->kobj, &sff_xcvr_attr_group) != 0) { + wb_plat_kobject_delete(&g_sff_obj); + SFF_ERR("create sff dir attrs error!\n"); + return -EBADRQC; + } + SFF_DBG("wb_plat_kobject_create sff directory and attribute success.\n"); + return 0; +} + +static void sff_xcvr_remove(void) +{ + if (g_sff_obj) { + sysfs_remove_group(&g_sff_obj->kobj, &sff_xcvr_attr_group); + wb_plat_kobject_delete(&g_sff_obj); + SFF_DBG("delete sff root success\n"); + } + + return; +} + +static int wb_sff_init(void) +{ + int ret; + + SFF_INFO("wb_sff_init...\n"); + g_drv = dfd_plat_driver_get(); + check_p(g_drv); + + ret = sff_xcvr_create(); + if (ret < 0) { + goto sff_root_error; + } + + ret = sff_sub_create(); + if (ret < 0) { + goto sff_sub_error; + } + SFF_INFO("wb_sff_init ok.\n"); + return 0; + +sff_sub_error: + sff_xcvr_remove(); +sff_root_error: + return ret; +} + +static void wb_sff_exit(void) +{ + sff_sub_remove(); + sff_xcvr_remove(); + SFF_INFO("wb_sff_exit ok.\n"); + return ; +} + +module_init(wb_sff_init); +module_exit(wb_sff_exit); +module_param(g_loglevel, int, 0644); +MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("sff sysfs driver"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_slot.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_slot.c new file mode 100644 index 000000000000..7c50f283bd06 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_slot.c @@ -0,0 +1,663 @@ +/* + * plat_slot.c + * + * This module create sff kobjects and attributes in /sys/wb_plat/slot + * + */ + +#include + +#include "./include/plat_switch.h" +#include "./include/sysfs_common.h" + +#define SLOT_INFO(fmt, args...) LOG_INFO("slot: ", fmt, ##args) +#define SLOT_ERR(fmt, args...) LOG_ERR("slot: ", fmt, ##args) +#define SLOT_DBG(fmt, args...) LOG_DBG("slot: ", fmt, ##args) + +struct slot_temp_obj_t{ + struct switch_obj *obj; +}; + +struct slot_in_obj_t{ + struct switch_obj *obj; +}; + +struct slot_obj_t{ + unsigned int temp_number; + unsigned int in_number; + struct slot_temp_obj_t *temp; + struct slot_in_obj_t *in; + struct switch_obj *obj; +}; + +struct slot_t{ + unsigned int slot_number; + struct slot_obj_t *slot; +}; + +static int g_loglevel = 0; +static struct slot_t g_slot; +static struct switch_obj *g_slot_obj = NULL; +static struct switch_drivers_t *g_drv = NULL; + +static ssize_t slot_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_slot.slot_number); +} + +static ssize_t slot_temp_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int index; + + index = obj->index; + SLOT_DBG("slot_temp_number_show,slot index:%d\n",index); + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_slot.slot[index-1].temp_number); +} + +static ssize_t slot_in_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int index; + + index = obj->index; + SLOT_DBG("slot_in_number_show,slot index:%d\n",index); + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_slot.slot[index-1].in_number); +} + +static ssize_t slot_present_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int slot_index; + int ret; + + slot_index = obj->index; + SLOT_DBG("slot_present_status_show, slot index:%d\n",slot_index); + check_p(g_drv); + check_p(g_drv->get_slot_present_status); + + ret = g_drv->get_slot_present_status(slot_index); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t slot_voltage_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int slot_index, in_index; + int ret; + struct switch_obj *p_obj; + struct switch_device_attribute *in_attr; + + check_p(g_drv); + check_p(g_drv->get_voltage_info); + + p_obj = to_switch_obj(obj->kobj.parent); + check_p(p_obj); + + slot_index = p_obj->index; + in_index = obj->index; + + in_attr = to_switch_device_attr(attr); + check_p(in_attr); + SLOT_DBG("slot_voltage_show, slot index:0x%x, temp index:0x%x, temp type:0x%x\n",slot_index, in_index, in_attr->type); + ret = g_drv->get_voltage_info(WB_MAIN_DEV_SLOT, slot_index, in_index, in_attr->type, buf); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + return ret; +} + +static ssize_t slot_temp_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int slot_index, temp_index; + int ret; + struct switch_obj *p_obj; + struct switch_device_attribute *temp_attr; + + check_p(g_drv); + check_p(g_drv->get_temp_info); + + p_obj = to_switch_obj(obj->kobj.parent); + check_p(p_obj); + + slot_index = p_obj->index; + temp_index = obj->index; + + temp_attr = to_switch_device_attr(attr); + check_p(temp_attr); + SLOT_DBG("slot_temp_show, slot index:0x%x, temp index:0x%x, temp type:0x%x\n",slot_index, temp_index, temp_attr->type); + ret = g_drv->get_temp_info(WB_MAIN_DEV_SLOT, slot_index, temp_index, temp_attr->type, buf); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + return ret; +} + +/************************************slot dir and attrs*******************************************/ +static struct switch_attribute slot_number_att = __ATTR(num_slots, S_IRUGO, slot_number_show, NULL); + +static struct attribute *slot_dir_attrs[] = { + &slot_number_att.attr, + NULL, +}; + +static struct attribute_group slot_root_attr_group = { + .attrs = slot_dir_attrs, +}; + +/*******************************slot1 slot2 dir and attrs*******************************************/ +static struct switch_attribute num_temp_sensors_att = __ATTR(num_temp_sensors, S_IRUGO, slot_temp_number_show, NULL); +static struct switch_attribute num_in_sensors_att = __ATTR(num_in_sensors, S_IRUGO, slot_in_number_show, NULL); +static struct switch_attribute slot_present_status_att = __ATTR(present, S_IRUGO, slot_present_status_show, NULL); + +static struct attribute *slot_attrs[] = { + &num_temp_sensors_att.attr, + &num_in_sensors_att.attr, + &slot_present_status_att.attr, + NULL, +}; + +static struct attribute_group slot_attr_group = { + .attrs = slot_attrs, +}; + +/*******************************temp dir and attrs*******************************************/ +static SWITCH_DEVICE_ATTR(temp_alias, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_ALIAS); +static SWITCH_DEVICE_ATTR(temp_type, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_TYPE); +static SWITCH_DEVICE_ATTR(temp_max, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_MAX); +static SWITCH_DEVICE_ATTR(temp_max_hyst, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_MAX_HYST); +static SWITCH_DEVICE_ATTR(temp_min, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_MIN); +static SWITCH_DEVICE_ATTR(temp_input, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_INPUT); + +static struct attribute *temp_attrs[] = { + &switch_dev_attr_temp_alias.switch_attr.attr, + &switch_dev_attr_temp_type.switch_attr.attr, + &switch_dev_attr_temp_max.switch_attr.attr, + &switch_dev_attr_temp_max_hyst.switch_attr.attr, + &switch_dev_attr_temp_min.switch_attr.attr, + &switch_dev_attr_temp_input.switch_attr.attr, + NULL, +}; + +static struct attribute_group temp_attr_group = { + .attrs = temp_attrs, +}; + +/*******************************Voltage dir and attrs*******************************************/ +static SWITCH_DEVICE_ATTR(in_alias, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_ALIAS); +static SWITCH_DEVICE_ATTR(in_type, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_TYPE); +static SWITCH_DEVICE_ATTR(in_max, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_MAX); +static SWITCH_DEVICE_ATTR(in_crit, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_CRIT); +static SWITCH_DEVICE_ATTR(in_min, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_MIN); +static SWITCH_DEVICE_ATTR(in_input, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_INPUT); + +static struct attribute *in_attrs[] = { + &switch_dev_attr_in_alias.switch_attr.attr, + &switch_dev_attr_in_type.switch_attr.attr, + &switch_dev_attr_in_max.switch_attr.attr, + &switch_dev_attr_in_crit.switch_attr.attr, + &switch_dev_attr_in_min.switch_attr.attr, + &switch_dev_attr_in_input.switch_attr.attr, + NULL, +}; + +static struct attribute_group in_attr_group = { + .attrs = in_attrs, +}; + +static void slotindex_single_temp_remove_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int temp_index) +{ + + struct slot_temp_obj_t *curr_temp; /* point to temp1 temp2...*/ + + curr_temp = &curr_slot->temp[temp_index - 1]; + if (curr_temp->obj) { + sysfs_remove_group(&curr_temp->obj->kobj, &temp_attr_group); + wb_plat_kobject_delete(&curr_temp->obj); + SLOT_DBG("delete slot:%d temp%d.\n", curr_slot->obj->index, temp_index); + } + return; +} + +static int slotindex_single_temp_create_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int temp_index) +{ + char name[DIR_NAME_MAX_LEN]; + struct slot_temp_obj_t *curr_temp; /* point to temp1 temp2...*/ + + curr_temp = &curr_slot->temp[temp_index - 1]; + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "%s%d", TEMP_SYSFS_NAME, temp_index); + + curr_temp->obj = wb_plat_kobject_create(name, &curr_slot->obj->kobj); + if (!curr_temp->obj) { + SLOT_ERR("create slot_index:%d, temp%d object error!\n", curr_slot->obj->index, temp_index); + return -EBADRQC; + } + curr_temp->obj->index = temp_index; + if (sysfs_create_group(&curr_temp->obj->kobj, &temp_attr_group) != 0) { + SLOT_ERR("create slot_index:%d, temp%d attrs error.\n", curr_slot->obj->index, temp_index); + wb_plat_kobject_delete(&curr_temp->obj); + return -EBADRQC; + } + SLOT_DBG("create slot_index:%d, temp%d ok.\n", curr_slot->obj->index, temp_index); + return 0; +} + +static void slotindex_temp_remove_kobj_and_attrs(struct slot_obj_t * curr_slot) +{ + int temp_index; + + for(temp_index = curr_slot->temp_number; temp_index > 0; temp_index--) { + slotindex_single_temp_remove_kobj_and_attrs(curr_slot, temp_index); + } + + if(curr_slot->temp) { + kfree(curr_slot->temp); + curr_slot->temp = NULL; + curr_slot->temp_number = 0; + } + return; +} + +static int slotindex_temp_create_kobj_and_attrs(struct slot_obj_t * curr_slot, int temp_num) +{ + int temp_index, i; + + curr_slot->temp_number = temp_num; + curr_slot->temp = kzalloc(sizeof(struct slot_temp_obj_t) * temp_num, GFP_KERNEL); + if (!curr_slot->temp) { + SLOT_ERR("kzalloc slot temp error, slot index = %d, temp number = %d.\n", curr_slot->obj->index, temp_num); + return -ENOMEM; + } + + for (temp_index = 1; temp_index <= temp_num; temp_index++) { + if (slotindex_single_temp_create_kobj_and_attrs(curr_slot, temp_index) != 0) { + goto error; + } + } + return 0; +error: + for (i = temp_index - 1; i > 0; i--) { + slotindex_single_temp_remove_kobj_and_attrs(curr_slot, i); + } + + if (curr_slot->temp) { + kfree(curr_slot->temp); + curr_slot->temp = NULL; + curr_slot->temp_number = 0; + } + return -EBADRQC; +} + +static void slotindex_single_in_remove_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int in_index) +{ + + struct slot_in_obj_t *curr_in; /* point to in1 in2...*/ + + curr_in = &curr_slot->in[in_index - 1]; + if (curr_in->obj) { + sysfs_remove_group(&curr_in->obj->kobj, &in_attr_group); + wb_plat_kobject_delete(&curr_in->obj); + SLOT_DBG("delete slot:%d in%d.\n", curr_slot->obj->index, in_index); + } + return; +} + +static int slotindex_single_in_create_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int in_index) +{ + char name[DIR_NAME_MAX_LEN]; + struct slot_in_obj_t *curr_in; /* point to in1 in2...*/ + + curr_in = &curr_slot->in[in_index - 1]; + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "%s%d", VOLTAGE_SYSFS_NAME, in_index); + curr_in->obj = wb_plat_kobject_create(name, &curr_slot->obj->kobj); + if (!curr_in->obj) { + SLOT_ERR("create slot_index:%d, in%d object error!\n", curr_slot->obj->index, in_index); + return -EBADRQC; + } + curr_in->obj->index = in_index; + if (sysfs_create_group(&curr_in->obj->kobj, &in_attr_group) != 0) { + SLOT_ERR("create slot_index:%d, in%d attrs error.\n", curr_slot->obj->index, in_index); + wb_plat_kobject_delete(&curr_in->obj); + return -EBADRQC; + } + SLOT_DBG("create slot_index:%d, in%d ok.\n", curr_slot->obj->index, in_index); + return 0; +} + +static void slotindex_in_remove_kobj_and_attrs(struct slot_obj_t * curr_slot) +{ + int in_index; + + for(in_index = curr_slot->in_number; in_index > 0; in_index--) { + slotindex_single_in_remove_kobj_and_attrs(curr_slot, in_index); + } + + if(curr_slot->in) { + kfree(curr_slot->in); + curr_slot->in = NULL; + curr_slot->in_number = 0; + } + return; +} + +static int slotindex_in_create_kobj_and_attrs(struct slot_obj_t * curr_slot, int in_num) +{ + int in_index, i; + + curr_slot->in_number = in_num; + curr_slot->in = kzalloc(sizeof(struct slot_in_obj_t) * in_num, GFP_KERNEL); + if (!curr_slot->in) { + SLOT_ERR("kzalloc slot Voltage error, slot index = %d, Voltage number = %d.\n", curr_slot->obj->index, in_num); + return -ENOMEM; + } + + for (in_index = 1; in_index <= in_num; in_index++) { + if (slotindex_single_in_create_kobj_and_attrs(curr_slot, in_index) != 0 ) { + goto error; + } + } + return 0; +error: + for (i = in_index - 1; i > 0; i++) { + slotindex_single_in_remove_kobj_and_attrs(curr_slot, i); + } + + if (curr_slot->in) { + kfree(curr_slot->in); + curr_slot->in = NULL; + curr_slot->in_number = 0; + } + return -EBADRQC; +} + +static void slotindex_obj_remove_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int obj_id) +{ + switch (obj_id) { + case WB_MINOR_DEV_TEMP: + slotindex_temp_remove_kobj_and_attrs(curr_slot); + break; + case WB_MINOR_DEV_IN: + slotindex_in_remove_kobj_and_attrs(curr_slot); + break; + default: + SLOT_ERR("Unknow obj id:%d\n", obj_id); + } + return ; +} + +static int slotindex_obj_create_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int obj_id, int obj_num) +{ + int ret; + + switch (obj_id) { + case WB_MINOR_DEV_TEMP: + ret = slotindex_temp_create_kobj_and_attrs(curr_slot, obj_num); + break; + case WB_MINOR_DEV_IN: + ret = slotindex_in_create_kobj_and_attrs(curr_slot, obj_num); + break; + default: + SLOT_ERR("Unknow obj id:%d\n", obj_id); + ret = -EINVAL; + } + return ret; +} + +static void slot_child_obj_remove_by_id(unsigned int obj_id) +{ + int slot_num; + unsigned int slot_index; + struct slot_obj_t *curr_slot; /* point to slot1 slot2...*/ + + slot_num = g_slot.slot_number; + if (slot_num <= 0 || !g_slot.slot) { + SLOT_DBG("Warning:slot number = %d\n", slot_num); + return; + } + + for(slot_index = slot_num; slot_index > 0; slot_index--) { + curr_slot = &g_slot.slot[slot_index - 1]; + slotindex_obj_remove_kobj_and_attrs(curr_slot, obj_id); + } + return; +} + +static int slot_child_obj_create_by_id(unsigned int obj_id) +{ + int slot_num, obj_num; + unsigned int slot_index, i; + struct slot_obj_t *curr_slot; /* point to slot1 slot2...*/ + + check_p(g_drv->get_dev_number); + obj_num = g_drv->get_dev_number(WB_MAIN_DEV_SLOT,obj_id); + slot_num = g_slot.slot_number; + if (obj_num <= 0 || slot_num <= 0 || !g_slot.slot) { + SLOT_DBG("Warning:slot number = %d, object number:%d.obj_id:%d\n", slot_num, obj_num, obj_id); + return 0; + } + + for (slot_index = 1; slot_index <= slot_num; slot_index++) { + curr_slot = &g_slot.slot[slot_index - 1]; + if (slotindex_obj_create_kobj_and_attrs(curr_slot, obj_id, obj_num) != 0) { + goto error; + } + } + return 0; +error: + for(i = slot_index - 1; i > 0; i++) { + curr_slot = &g_slot.slot[i - 1]; + slotindex_obj_remove_kobj_and_attrs(curr_slot, obj_id); + } + return -EBADRQC; +} + +static void slot_child_obj_remove(void) +{ + /* temp remove */ + slot_child_obj_remove_by_id(WB_MINOR_DEV_TEMP); + + /* in creat */ + slot_child_obj_remove_by_id(WB_MINOR_DEV_IN); + return; +} + +static int slot_child_obj_create(void) +{ + int ret; + + /* temp creat */ + ret = slot_child_obj_create_by_id(WB_MINOR_DEV_TEMP); + if (ret < 0) { + goto temp_err; + } + /* Voltage creat */ + ret = slot_child_obj_create_by_id(WB_MINOR_DEV_IN); + if(ret < 0) { + goto in_err; + } + return 0; +in_err: + slot_child_obj_remove_by_id(WB_MINOR_DEV_TEMP); +temp_err: + return ret; +} + +static void slot_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct slot_obj_t *curr_slot; + + curr_slot = &g_slot.slot[index - 1]; + if (curr_slot->obj) { + sysfs_remove_group(&curr_slot->obj->kobj, &slot_attr_group); + wb_plat_kobject_delete(&curr_slot->obj); + SLOT_DBG("delete slot%d.\n", index); + } + return; +} + +static int slot_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) +{ + char name[DIR_NAME_MAX_LEN]; + struct slot_obj_t *curr_slot; + + curr_slot = &g_slot.slot[index - 1]; + SLOT_DBG("create %s%d ...\n", SLOT_SYSFS_NAME, index); + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "%s%d", SLOT_SYSFS_NAME, index); + curr_slot->obj = wb_plat_kobject_create(name, parent); + if (!curr_slot->obj) { + SLOT_ERR("create slot%d object error!\n", index); + return -EBADRQC; + } + curr_slot->obj->index = index; + if (sysfs_create_group(&curr_slot->obj->kobj, &slot_attr_group) != 0) { + SLOT_ERR("create slot%d attrs error.\n", index); + wb_plat_kobject_delete(&curr_slot->obj); + return -EBADRQC; + } + SLOT_DBG("create slot%d ok.\n", index); + return 0; +} + +static int slot_sub_create_kobj_and_attrs(struct kobject *parent, int slot_num) +{ + unsigned int slot_index, i; + + g_slot.slot = kzalloc(sizeof(struct slot_obj_t) * slot_num, GFP_KERNEL); + if (!g_slot.slot) { + SLOT_ERR("kzalloc slot.slot error, slot number = %d.\n", slot_num); + return -ENOMEM; + } + + for (slot_index = 1; slot_index <= slot_num; slot_index++) { + if (slot_sub_single_create_kobj_and_attrs(parent, slot_index) != 0) { + goto error; + } + } + return 0; +error: + for (i = slot_index - 1; i > 0; i--) { + slot_sub_single_remove_kobj_and_attrs(i); + } + if (g_slot.slot) { + kfree(g_slot.slot); + g_slot.slot = NULL; + } + return -EBADRQC; +} + +/* create slot1 slot2...dir and attrs */ +static int slot_sub_create(void) +{ + int ret, slot_num; + + check_p(g_drv->get_dev_number); + slot_num = g_drv->get_dev_number(WB_MAIN_DEV_SLOT, WB_MINOR_DEV_NONE); + g_slot.slot_number = slot_num; + if (slot_num <= 0) { + SLOT_DBG("Warning:slot number = %d \n", slot_num); + return 0; + } + ret = slot_sub_create_kobj_and_attrs(&g_slot_obj->kobj, slot_num); + return ret; +} + +/** + * slot_sub_remove - delete slot1 slot2...dir and attrs + */ +static void slot_sub_remove(void) +{ + unsigned int slot_index; + + if (g_slot.slot) { + for (slot_index = g_slot.slot_number; slot_index > 0; slot_index--) { + slot_sub_single_remove_kobj_and_attrs(slot_index); + } + kfree(g_slot.slot); + } + mem_clear(&g_slot, sizeof(struct slot_t)); + return ; +} + +/* create slot dir and num_slots attr */ +static int slot_root_create(void) +{ + g_slot_obj = wb_plat_kobject_create(SLOT_SYSFS_NAME, NULL); + if (!g_slot_obj) { + SLOT_ERR("wb_plat_kobject_create slot error!\n"); + return -ENOMEM; + } + + if (sysfs_create_group(&g_slot_obj->kobj, &slot_root_attr_group) != 0) { + wb_plat_kobject_delete(&g_slot_obj); + SLOT_ERR("create slot dir attrs error!\n"); + return -EBADRQC; + } + SLOT_DBG("wb_plat_kobject_create slot directory and attribute success.\n"); + return 0; +} + +static void slot_root_remove(void) +{ + if (g_slot_obj) { + sysfs_remove_group(&g_slot_obj->kobj, &slot_root_attr_group); + wb_plat_kobject_delete(&g_slot_obj); + SLOT_DBG("delete slot root success\n"); + } + + return; +} + +static int wb_slot_init(void) +{ + int ret; + + SLOT_INFO("wb_slot_init...\n"); + g_drv = dfd_plat_driver_get(); + check_p(g_drv); + + ret = slot_root_create(); + if (ret < 0) { + goto slot_root_error; + } + + ret = slot_sub_create(); + if (ret < 0) { + goto slot_sub_error; + } + + ret = slot_child_obj_create(); + if (ret < 0) { + goto slot_child_obj_error; + } + + SLOT_INFO("wb_slot_init ok.\n"); + return 0; +slot_child_obj_error: + slot_sub_remove(); +slot_sub_error: + slot_root_remove(); +slot_root_error: + return ret; +} + +static void wb_slot_exit(void) +{ + slot_child_obj_remove(); + slot_sub_remove(); + slot_root_remove(); + SLOT_INFO("wb_slot_exit ok.\n"); + return ; +} + +module_init(wb_slot_init); +module_exit(wb_slot_exit); +module_param(g_loglevel, int, 0644); +MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("slot sysfs driver"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_switch.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_switch.c new file mode 100644 index 000000000000..9563260f32b4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_switch.c @@ -0,0 +1,131 @@ +/* + * plat_switch.c + * + * This module create a kset in sysfs called /sys/wb_plat + * Then other switch kobjects are created and assigned to this kset, + * such as "board", "cpld", "fan", "psu", "sff", ... + * + */ +#include "./include/plat_switch.h" + +#define SWITCH_INFO(fmt, args...) LOG_INFO("switch: ", fmt, ##args) +#define SWITCH_ERR(fmt, args...) LOG_ERR("switch: ", fmt, ##args) +#define SWITCH_DBG(fmt, args...) LOG_DBG("switch: ", fmt, ##args) + +static int g_loglevel = 0; + +static ssize_t switch_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct switch_attribute *attribute; + struct switch_obj *device; + + attribute = to_switch_attr(attr); + device = to_switch_obj(kobj); + + if (!attribute->show) + return -ENOSYS; + + return attribute->show(device, attribute, buf); +} + +static ssize_t switch_attr_store(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t len) +{ + struct switch_attribute *attribute; + struct switch_obj *obj; + + attribute = to_switch_attr(attr); + obj = to_switch_obj(kobj); + + if (!attribute->store) + return -ENOSYS; + + return attribute->store(obj, attribute, buf, len); +} + +static const struct sysfs_ops switch_sysfs_ops = { + .show = switch_attr_show, + .store = switch_attr_store, +}; + +static void switch_obj_release(struct kobject *kobj) +{ + struct switch_obj *obj; + + obj = to_switch_obj(kobj); + kfree(obj); +} + +static struct kobj_type switch_ktype = { + .sysfs_ops = &switch_sysfs_ops, + .release = switch_obj_release, + .default_attrs = NULL, +}; + +static struct kset *switch_kset; + +struct switch_obj *wb_plat_kobject_create(const char *name, struct kobject *parent) +{ + struct switch_obj *obj = NULL; + int ret = 0; + + obj = kzalloc(sizeof(*obj), GFP_KERNEL); + if (!obj) { + SWITCH_DBG("wb_plat_kobject_create %s kzalloc error", name); + return NULL; + } + + obj->kobj.kset = switch_kset; + + ret = kobject_init_and_add(&obj->kobj, &switch_ktype, parent, "%s", name); + if (ret) { + kobject_put(&obj->kobj); + SWITCH_DBG("kobject_init_and_add %s error", name); + return NULL; + } + + return obj; +} + +void wb_plat_kobject_delete(struct switch_obj **obj) +{ + if (*obj) { + SWITCH_DBG("%s delete %s.\n", (*obj)->kobj.parent->name, (*obj)->kobj.name); + kobject_put(&((*obj)->kobj)); + *obj = NULL; + } +} + +static int __init switch_init(void) +{ + SWITCH_INFO("...\n"); + + switch_kset = kset_create_and_add("wb_plat", NULL, NULL); + if (!switch_kset) { + SWITCH_ERR("create switch_kset error.\n"); + return -ENOMEM; + } + + SWITCH_INFO("ok.\n"); + return 0; +} + +static void __exit switch_exit(void) +{ + if (switch_kset) { + kset_unregister(switch_kset); + } + + SWITCH_INFO("ok.\n"); +} + +module_init(switch_init); +module_exit(switch_exit); +EXPORT_SYMBOL(wb_plat_kobject_create); +EXPORT_SYMBOL(wb_plat_kobject_delete); +module_param(g_loglevel, int, 0644); +MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("Switch driver"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common.h new file mode 100644 index 000000000000..9e4a4fae00c1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common.h @@ -0,0 +1,74 @@ +#ifndef __PLATFORM_COMMON_H__ +#define __PLATFORM_COMMON_H__ + +#include +#include +#include +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +typedef enum { + DBG_START, + DBG_VERBOSE, + DBG_KEY, + DBG_WARN, + DBG_ERROR, + DBG_END, +} dbg_level_t; + + typedef struct dfd_i2c_dev_s { + int bus; + int addr; + } dfd_i2c_dev_t; + +typedef struct dfd_dev_head_info_s { + uint8_t ver; + uint8_t flag; + uint8_t hw_ver; + uint8_t type; + int16_t tlv_len; +} dfd_dev_head_info_t; + +typedef struct dfd_dev_tlv_info_s { + uint8_t type; + uint8_t len; + uint8_t data[0]; +} dfd_dev_tlv_info_t; + +typedef enum dfd_dev_info_type_e { + DFD_DEV_INFO_TYPE_MAC = 1, + DFD_DEV_INFO_TYPE_NAME = 2, + DFD_DEV_INFO_TYPE_SN = 3, + DFD_DEV_INFO_TYPE_PWR_CONS = 4, + DFD_DEV_INFO_TYPE_HW_INFO = 5, + DFD_DEV_INFO_TYPE_DEV_TYPE = 6, +} dfd_dev_tlv_type_t; + +extern int debuglevel; +extern s32 platform_i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command); +extern s32 platform_i2c_smbus_read_i2c_block_data(const struct i2c_client *client, + u8 command, u8 length, u8 *values); +extern s32 platform_i2c_smbus_read_word_data(const struct i2c_client *client, u8 command); + +#define DBG_DEBUG(fmt, arg...) do { \ + if ( debuglevel > DBG_START && debuglevel < DBG_ERROR) { \ + printk(KERN_INFO "[DEBUG]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ + } else if ( debuglevel >= DBG_ERROR ) { \ + printk(KERN_ERR "[DEBUG]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ + } else { } \ +} while (0) + +#define DBG_INFO(fmt, arg...) do { \ + if ( debuglevel > DBG_KEY) { \ + printk(KERN_INFO "[INFO]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ + } \ + } while (0) + +#define DBG_ERROR(fmt, arg...) do { \ + if ( debuglevel > DBG_START) { \ + printk(KERN_ERR "[ERROR]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ + } \ + } while (0) + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common_module.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common_module.c new file mode 100644 index 000000000000..189a3aa056b2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common_module.c @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,152) +#include +#else +#include +#endif +#include +#include +#include +#include +#include "platform_common.h" +#include "dfd_tlveeprom.h" + +#define PLATFORM_I2C_RETRY_TIMES 3 + +#define DFD_TLVEEPROM_I2C_BUS (0) +#define DFD_TLVEEPROM_I2C_ADDR (0x56) +#define DFD_E2PROM_MAX_LEN (256) +#define DFD_CARDTYPE_EXT_TLVLEN (4) + +#define PLATFORM_CARDTYPE_RETRY_CNT (10) +#define PLATFORM_CARDTYPE_RETRY_TIMES (1000) + +int debuglevel = 0; +module_param(debuglevel, int, S_IRUGO | S_IWUSR); + +static int dfd_my_type = 0; +module_param(dfd_my_type, int, S_IRUGO | S_IWUSR); + +int g_common_debug_error = 0; +module_param(g_common_debug_error, int, S_IRUGO | S_IWUSR); + +int g_common_debug_verbose = 0; +module_param(g_common_debug_verbose, int, S_IRUGO | S_IWUSR); + +uint32_t dfd_my_type_i2c_bus = 0; +module_param(dfd_my_type_i2c_bus, int, S_IRUGO | S_IWUSR); + +uint32_t dfd_my_type_i2c_addr = 0; +module_param(dfd_my_type_i2c_addr, int, S_IRUGO | S_IWUSR); + +#define PLATFORM_COMMON_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_common_debug_verbose) { \ + printk(KERN_ERR "[PLATFORM_COMMON][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define PLATFORM_COMMON_DEBUG_ERROR(fmt, args...) do { \ + if (g_common_debug_error) { \ + printk(KERN_ERR "[PLATFORM_COMMON][ERROR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static int32_t dfd_i2c_read(char *dev, uint32_t addr, uint32_t offset_addr, unsigned char * +buf, int32_t size) +{ + struct file *fp; + struct i2c_client client; + int i ,j; + int rv; + s32 val_t; + + val_t = -1; + rv = 0; + fp = filp_open(dev, O_RDWR, S_IRUSR | S_IWUSR); + if (IS_ERR(fp)) { + DBG_ERROR("i2c open fail.\n"); + PLATFORM_COMMON_DEBUG_ERROR("i2c open fail.\n"); + return -1; + } + memcpy(&client, fp->private_data, sizeof(struct i2c_client)); + client.addr = addr; + for (j = 0 ;j < size ;j++){ + for (i = 0; i < PLATFORM_I2C_RETRY_TIMES; i++) { + if ((val_t = i2c_smbus_read_byte_data(&client, (offset_addr + j)))< 0) { + DBG_DEBUG("read try(%d)time offset_addr:%x \n", i, offset_addr); + continue; + } else { + * (buf + j) = val_t; + break; + } + } + if (val_t < 0) { + rv = -1; + break; + } + } + filp_close(fp, NULL); + return rv; +} + +static int dfd_tlvinfo_get_cardtype(void) +{ + char i2c_path[16] = {0}; + int ret; + int cardtype; + u_int8_t eeprom[DFD_E2PROM_MAX_LEN]; + dfd_i2c_dev_t i2c_dev; + uint8_t buf[DFD_CARDTYPE_EXT_TLVLEN]; + uint8_t len; + dfd_tlv_type_t tlv_type; + + if (dfd_my_type_i2c_bus != 0) { + i2c_dev.bus = dfd_my_type_i2c_bus; + } else { + i2c_dev.bus = DFD_TLVEEPROM_I2C_BUS; + } + + if (dfd_my_type_i2c_addr != 0) { + i2c_dev.addr = dfd_my_type_i2c_addr; + } else { + i2c_dev.addr = DFD_TLVEEPROM_I2C_ADDR; + } + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_dev.bus); + PLATFORM_COMMON_DEBUG_VERBOSE("Read device eeprom info:(dev:%s, addr:%02x).\n", i2c_path, i2c_dev.addr); + + ret = dfd_i2c_read(i2c_path, i2c_dev.addr, 0, eeprom, DFD_E2PROM_MAX_LEN); + if (ret != 0) { + DBG_ERROR("Read eeprom info error(dev: %s, addr: %02x).\n", i2c_path, i2c_dev.addr); + PLATFORM_COMMON_DEBUG_ERROR("Read eeprom info error(dev: %s, addr: %02x).\n", i2c_path, i2c_dev.addr); + return ret; + } + + tlv_type.main_type = TLV_CODE_VENDOR_EXT; + tlv_type.ext_type = DFD_TLVINFO_EXT_TLV_TYPE_DEV_TYPE; + len = sizeof(buf); + mem_clear(buf, len); + ret = dfd_tlvinfo_get_e2prom_info(eeprom, DFD_E2PROM_MAX_LEN, &tlv_type, buf, &len); + if (ret) { + DBG_ERROR("dfd_tlvinfo_get_e2prom_info failed ret %d.\n", ret); + return -1; + } + for (ret = 0; ret < 4; ret++) { + DBG_DEBUG("buf 0x%02x.\n", buf[ret]); + } + + cardtype = ntohl(*((uint32_t *)buf)); + DBG_DEBUG("cardtype 0x%x.\n", cardtype); + return cardtype; +} + +static int __dfd_get_my_card_type(void) +{ + return dfd_tlvinfo_get_cardtype(); +} + +int dfd_get_my_card_type(void) +{ + int type; + int cnt; + + if (dfd_my_type != 0) { + DBG_DEBUG("my_type = 0x%x\r\n", dfd_my_type); + return dfd_my_type; + } + + cnt = PLATFORM_CARDTYPE_RETRY_CNT; + while (cnt--) { + type = __dfd_get_my_card_type(); + if (type < 0) { + PLATFORM_COMMON_DEBUG_ERROR("__dfd_get_my_card_type fail cnt %d, ret %d.\n", cnt, type); + msleep(PLATFORM_CARDTYPE_RETRY_TIMES); + continue; + } + PLATFORM_COMMON_DEBUG_VERBOSE("success to get type 0x%x.\n", type); + break; + } + + dfd_my_type = type; + return dfd_my_type; +} +EXPORT_SYMBOL(dfd_get_my_card_type); + +static int __init platform_common_init(void) +{ + int ret; + + PLATFORM_COMMON_DEBUG_VERBOSE("Enter.\n"); + ret = dfd_get_my_card_type(); + if (ret <= 0) { + PLATFORM_COMMON_DEBUG_ERROR("dfd_get_my_card_type failed, ret %d.\n", ret); + printk(KERN_ERR "Warning: Device type get failed, please check the TLV-EEPROM!\n"); + return -1; + } + + PLATFORM_COMMON_DEBUG_VERBOSE("Leave success type 0x%x.\n", ret); + return 0; +} + +static void __exit platform_common_exit(void) +{ + PLATFORM_COMMON_DEBUG_VERBOSE("Exit.\n"); +} + +module_init(platform_common_init); +module_exit(platform_common_exit); + +MODULE_DESCRIPTION("Platform Support"); +MODULE_AUTHOR("support"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/Makefile new file mode 100644 index 000000000000..6831a03a60fd --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/Makefile @@ -0,0 +1,18 @@ +PWD = $(shell pwd) + +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall + +sdhci_pci-objs := sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \ + sdhci-pci-dwc-mshc.o sdhci-pci-gli.o +obj-m += sdhci_pci.o + + +all: + $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules + @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi + @if [ -f $(PWD)/*.ko ]; then cp -p $(PWD)/*.ko $(module_out_put_dir);fi +clean: + rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd + rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order + rm -rf $(PWD)/.tmp_versions \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/cqhci.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/cqhci.h new file mode 100644 index 000000000000..89bf6adbce8c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/cqhci.h @@ -0,0 +1,242 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + */ +#ifndef LINUX_MMC_CQHCI_H +#define LINUX_MMC_CQHCI_H + +#include +#include +#include +#include +#include +#include +#include +#include + +/* registers */ +/* version */ +#define CQHCI_VER 0x00 +#define CQHCI_VER_MAJOR(x) (((x) & GENMASK(11, 8)) >> 8) +#define CQHCI_VER_MINOR1(x) (((x) & GENMASK(7, 4)) >> 4) +#define CQHCI_VER_MINOR2(x) ((x) & GENMASK(3, 0)) + +/* capabilities */ +#define CQHCI_CAP 0x04 +/* configuration */ +#define CQHCI_CFG 0x08 +#define CQHCI_DCMD 0x00001000 +#define CQHCI_TASK_DESC_SZ 0x00000100 +#define CQHCI_ENABLE 0x00000001 + +/* control */ +#define CQHCI_CTL 0x0C +#define CQHCI_CLEAR_ALL_TASKS 0x00000100 +#define CQHCI_HALT 0x00000001 + +/* interrupt status */ +#define CQHCI_IS 0x10 +#define CQHCI_IS_HAC BIT(0) +#define CQHCI_IS_TCC BIT(1) +#define CQHCI_IS_RED BIT(2) +#define CQHCI_IS_TCL BIT(3) + +#define CQHCI_IS_MASK (CQHCI_IS_TCC | CQHCI_IS_RED) + +/* interrupt status enable */ +#define CQHCI_ISTE 0x14 + +/* interrupt signal enable */ +#define CQHCI_ISGE 0x18 + +/* interrupt coalescing */ +#define CQHCI_IC 0x1C +#define CQHCI_IC_ENABLE BIT(31) +#define CQHCI_IC_RESET BIT(16) +#define CQHCI_IC_ICCTHWEN BIT(15) +#define CQHCI_IC_ICCTH(x) (((x) & 0x1F) << 8) +#define CQHCI_IC_ICTOVALWEN BIT(7) +#define CQHCI_IC_ICTOVAL(x) ((x) & 0x7F) + +/* task list base address */ +#define CQHCI_TDLBA 0x20 + +/* task list base address upper */ +#define CQHCI_TDLBAU 0x24 + +/* door-bell */ +#define CQHCI_TDBR 0x28 + +/* task completion notification */ +#define CQHCI_TCN 0x2C + +/* device queue status */ +#define CQHCI_DQS 0x30 + +/* device pending tasks */ +#define CQHCI_DPT 0x34 + +/* task clear */ +#define CQHCI_TCLR 0x38 + +/* send status config 1 */ +#define CQHCI_SSC1 0x40 +#define CQHCI_SSC1_CBC_MASK GENMASK(19, 16) + +/* send status config 2 */ +#define CQHCI_SSC2 0x44 + +/* response for dcmd */ +#define CQHCI_CRDCT 0x48 + +/* response mode error mask */ +#define CQHCI_RMEM 0x50 + +/* task error info */ +#define CQHCI_TERRI 0x54 + +#define CQHCI_TERRI_C_INDEX(x) ((x) & GENMASK(5, 0)) +#define CQHCI_TERRI_C_TASK(x) (((x) & GENMASK(12, 8)) >> 8) +#define CQHCI_TERRI_C_VALID(x) ((x) & BIT(15)) +#define CQHCI_TERRI_D_INDEX(x) (((x) & GENMASK(21, 16)) >> 16) +#define CQHCI_TERRI_D_TASK(x) (((x) & GENMASK(28, 24)) >> 24) +#define CQHCI_TERRI_D_VALID(x) ((x) & BIT(31)) + +/* command response index */ +#define CQHCI_CRI 0x58 + +/* command response argument */ +#define CQHCI_CRA 0x5C + +#define CQHCI_INT_ALL 0xF +#define CQHCI_IC_DEFAULT_ICCTH 31 +#define CQHCI_IC_DEFAULT_ICTOVAL 1 + +/* attribute fields */ +#define CQHCI_VALID(x) (((x) & 1) << 0) +#define CQHCI_END(x) (((x) & 1) << 1) +#define CQHCI_INT(x) (((x) & 1) << 2) +#define CQHCI_ACT(x) (((x) & 0x7) << 3) + +/* data command task descriptor fields */ +#define CQHCI_FORCED_PROG(x) (((x) & 1) << 6) +#define CQHCI_CONTEXT(x) (((x) & 0xF) << 7) +#define CQHCI_DATA_TAG(x) (((x) & 1) << 11) +#define CQHCI_DATA_DIR(x) (((x) & 1) << 12) +#define CQHCI_PRIORITY(x) (((x) & 1) << 13) +#define CQHCI_QBAR(x) (((x) & 1) << 14) +#define CQHCI_REL_WRITE(x) (((x) & 1) << 15) +#define CQHCI_BLK_COUNT(x) (((x) & 0xFFFF) << 16) +#define CQHCI_BLK_ADDR(x) (((x) & 0xFFFFFFFF) << 32) + +/* direct command task descriptor fields */ +#define CQHCI_CMD_INDEX(x) (((x) & 0x3F) << 16) +#define CQHCI_CMD_TIMING(x) (((x) & 1) << 22) +#define CQHCI_RESP_TYPE(x) (((x) & 0x3) << 23) + +/* transfer descriptor fields */ +#define CQHCI_DAT_LENGTH(x) (((x) & 0xFFFF) << 16) +#define CQHCI_DAT_ADDR_LO(x) (((x) & 0xFFFFFFFF) << 32) +#define CQHCI_DAT_ADDR_HI(x) (((x) & 0xFFFFFFFF) << 0) + +struct cqhci_host_ops; +struct mmc_host; +struct mmc_request; +struct cqhci_slot; + +struct cqhci_host { + const struct cqhci_host_ops *ops; + void __iomem *mmio; + struct mmc_host *mmc; + + spinlock_t lock; + + /* relative card address of device */ + unsigned int rca; + + /* 64 bit DMA */ + bool dma64; + int num_slots; + int qcnt; + + u32 dcmd_slot; + u32 caps; +#define CQHCI_TASK_DESC_SZ_128 0x1 + + u32 quirks; +#define CQHCI_QUIRK_SHORT_TXFR_DESC_SZ 0x1 + + bool enabled; + bool halted; + bool init_done; + bool activated; + bool waiting_for_idle; + bool recovery_halt; + + size_t desc_size; + size_t data_size; + + u8 *desc_base; + + /* total descriptor size */ + u8 slot_sz; + + /* 64/128 bit depends on CQHCI_CFG */ + u8 task_desc_len; + + /* 64 bit on 32-bit arch, 128 bit on 64-bit */ + u8 link_desc_len; + + u8 *trans_desc_base; + /* same length as transfer descriptor */ + u8 trans_desc_len; + + dma_addr_t desc_dma_base; + dma_addr_t trans_desc_dma_base; + + struct completion halt_comp; + wait_queue_head_t wait_queue; + struct cqhci_slot *slot; +}; + +struct cqhci_host_ops { + void (*dumpregs)(struct mmc_host *mmc); + void (*write_l)(struct cqhci_host *host, u32 val, int reg); + u32 (*read_l)(struct cqhci_host *host, int reg); + void (*enable)(struct mmc_host *mmc); + void (*disable)(struct mmc_host *mmc, bool recovery); + void (*update_dcmd_desc)(struct mmc_host *mmc, struct mmc_request *mrq, + u64 *data); + void (*pre_enable)(struct mmc_host *mmc); + void (*post_disable)(struct mmc_host *mmc); +}; + +static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg) +{ + if (unlikely(host->ops->write_l)) + host->ops->write_l(host, val, reg); + else + writel_relaxed(val, host->mmio + reg); +} + +static inline u32 cqhci_readl(struct cqhci_host *host, int reg) +{ + if (unlikely(host->ops->read_l)) + return host->ops->read_l(host, reg); + else + return readl_relaxed(host->mmio + reg); +} + +struct platform_device; + +irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error, + int data_error); +int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc, bool dma64); +struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev); +int cqhci_deactivate(struct mmc_host *mmc); +static inline int cqhci_suspend(struct mmc_host *mmc) +{ + return cqhci_deactivate(mmc); +} +int cqhci_resume(struct mmc_host *mmc); + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-arasan.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-arasan.c new file mode 100644 index 000000000000..499f3205ec5c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-arasan.c @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * sdhci-pci-arasan.c - Driver for Arasan PCI Controller with + * integrated phy. + * + * Copyright (C) 2017 Arasan Chip Systems Inc. + * + * Author: Atul Garg + */ + +#include +#include + +#include "sdhci.h" +#include "sdhci-pci.h" + +/* Extra registers for Arasan SD/SDIO/MMC Host Controller with PHY */ +#define PHY_ADDR_REG 0x300 +#define PHY_DAT_REG 0x304 + +#define PHY_WRITE BIT(8) +#define PHY_BUSY BIT(9) +#define DATA_MASK 0xFF + +/* PHY Specific Registers */ +#define DLL_STATUS 0x00 +#define IPAD_CTRL1 0x01 +#define IPAD_CTRL2 0x02 +#define IPAD_STS 0x03 +#define IOREN_CTRL1 0x06 +#define IOREN_CTRL2 0x07 +#define IOPU_CTRL1 0x08 +#define IOPU_CTRL2 0x09 +#define ITAP_DELAY 0x0C +#define OTAP_DELAY 0x0D +#define STRB_SEL 0x0E +#define CLKBUF_SEL 0x0F +#define MODE_CTRL 0x11 +#define DLL_TRIM 0x12 +#define CMD_CTRL 0x20 +#define DATA_CTRL 0x21 +#define STRB_CTRL 0x22 +#define CLK_CTRL 0x23 +#define PHY_CTRL 0x24 + +#define DLL_ENBL BIT(3) +#define RTRIM_EN BIT(1) +#define PDB_ENBL BIT(1) +#define RETB_ENBL BIT(6) +#define ODEN_CMD BIT(1) +#define ODEN_DAT 0xFF +#define REN_STRB BIT(0) +#define REN_CMND BIT(1) +#define REN_DATA 0xFF +#define PU_CMD BIT(1) +#define PU_DAT 0xFF +#define ITAPDLY_EN BIT(0) +#define OTAPDLY_EN BIT(0) +#define OD_REL_CMD BIT(1) +#define OD_REL_DAT 0xFF +#define DLLTRM_ICP 0x8 +#define PDB_CMND BIT(0) +#define PDB_DATA 0xFF +#define PDB_STRB BIT(0) +#define PDB_CLOCK BIT(0) +#define CALDONE_MASK 0x10 +#define DLL_RDY_MASK 0x10 +#define MAX_CLK_BUF 0x7 + +/* Mode Controls */ +#define ENHSTRB_MODE BIT(0) +#define HS400_MODE BIT(1) +#define LEGACY_MODE BIT(2) +#define DDR50_MODE BIT(3) + +/* + * Controller has no specific bits for HS200/HS. + * Used BIT(4), BIT(5) for software programming. + */ +#define HS200_MODE BIT(4) +#define HISPD_MODE BIT(5) + +#define OTAPDLY(x) (((x) << 1) | OTAPDLY_EN) +#define ITAPDLY(x) (((x) << 1) | ITAPDLY_EN) +#define FREQSEL(x) (((x) << 5) | DLL_ENBL) +#define IOPAD(x, y) ((x) | ((y) << 2)) + +/* Arasan private data */ +struct arasan_host { + u32 chg_clk; +}; + +static int arasan_phy_addr_poll(struct sdhci_host *host, u32 offset, u32 mask) +{ + ktime_t timeout = ktime_add_us(ktime_get(), 100); + bool failed; + u8 val = 0; + + while (1) { + failed = ktime_after(ktime_get(), timeout); + val = sdhci_readw(host, PHY_ADDR_REG); + if (!(val & mask)) + return 0; + if (failed) + return -EBUSY; + } +} + +static int arasan_phy_write(struct sdhci_host *host, u8 data, u8 offset) +{ + sdhci_writew(host, data, PHY_DAT_REG); + sdhci_writew(host, (PHY_WRITE | offset), PHY_ADDR_REG); + return arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY); +} + +static int arasan_phy_read(struct sdhci_host *host, u8 offset, u8 *data) +{ + int ret; + + sdhci_writew(host, 0, PHY_DAT_REG); + sdhci_writew(host, offset, PHY_ADDR_REG); + ret = arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY); + + /* Masking valid data bits */ + *data = sdhci_readw(host, PHY_DAT_REG) & DATA_MASK; + return ret; +} + +static int arasan_phy_sts_poll(struct sdhci_host *host, u32 offset, u32 mask) +{ + int ret; + ktime_t timeout = ktime_add_us(ktime_get(), 100); + bool failed; + u8 val = 0; + + while (1) { + failed = ktime_after(ktime_get(), timeout); + ret = arasan_phy_read(host, offset, &val); + if (ret) + return -EBUSY; + else if (val & mask) + return 0; + if (failed) + return -EBUSY; + } +} + +/* Initialize the Arasan PHY */ +static int arasan_phy_init(struct sdhci_host *host) +{ + int ret; + u8 val; + + /* Program IOPADs and wait for calibration to be done */ + if (arasan_phy_read(host, IPAD_CTRL1, &val) || + arasan_phy_write(host, val | RETB_ENBL | PDB_ENBL, IPAD_CTRL1) || + arasan_phy_read(host, IPAD_CTRL2, &val) || + arasan_phy_write(host, val | RTRIM_EN, IPAD_CTRL2)) + return -EBUSY; + ret = arasan_phy_sts_poll(host, IPAD_STS, CALDONE_MASK); + if (ret) + return -EBUSY; + + /* Program CMD/Data lines */ + if (arasan_phy_read(host, IOREN_CTRL1, &val) || + arasan_phy_write(host, val | REN_CMND | REN_STRB, IOREN_CTRL1) || + arasan_phy_read(host, IOPU_CTRL1, &val) || + arasan_phy_write(host, val | PU_CMD, IOPU_CTRL1) || + arasan_phy_read(host, CMD_CTRL, &val) || + arasan_phy_write(host, val | PDB_CMND, CMD_CTRL) || + arasan_phy_read(host, IOREN_CTRL2, &val) || + arasan_phy_write(host, val | REN_DATA, IOREN_CTRL2) || + arasan_phy_read(host, IOPU_CTRL2, &val) || + arasan_phy_write(host, val | PU_DAT, IOPU_CTRL2) || + arasan_phy_read(host, DATA_CTRL, &val) || + arasan_phy_write(host, val | PDB_DATA, DATA_CTRL) || + arasan_phy_read(host, STRB_CTRL, &val) || + arasan_phy_write(host, val | PDB_STRB, STRB_CTRL) || + arasan_phy_read(host, CLK_CTRL, &val) || + arasan_phy_write(host, val | PDB_CLOCK, CLK_CTRL) || + arasan_phy_read(host, CLKBUF_SEL, &val) || + arasan_phy_write(host, val | MAX_CLK_BUF, CLKBUF_SEL) || + arasan_phy_write(host, LEGACY_MODE, MODE_CTRL)) + return -EBUSY; + return 0; +} + +/* Set Arasan PHY for different modes */ +static int arasan_phy_set(struct sdhci_host *host, u8 mode, u8 otap, + u8 drv_type, u8 itap, u8 trim, u8 clk) +{ + u8 val; + int ret; + + if (mode == HISPD_MODE || mode == HS200_MODE) + ret = arasan_phy_write(host, 0x0, MODE_CTRL); + else + ret = arasan_phy_write(host, mode, MODE_CTRL); + if (ret) + return ret; + if (mode == HS400_MODE || mode == HS200_MODE) { + ret = arasan_phy_read(host, IPAD_CTRL1, &val); + if (ret) + return ret; + ret = arasan_phy_write(host, IOPAD(val, drv_type), IPAD_CTRL1); + if (ret) + return ret; + } + if (mode == LEGACY_MODE) { + ret = arasan_phy_write(host, 0x0, OTAP_DELAY); + if (ret) + return ret; + ret = arasan_phy_write(host, 0x0, ITAP_DELAY); + } else { + ret = arasan_phy_write(host, OTAPDLY(otap), OTAP_DELAY); + if (ret) + return ret; + if (mode != HS200_MODE) + ret = arasan_phy_write(host, ITAPDLY(itap), ITAP_DELAY); + else + ret = arasan_phy_write(host, 0x0, ITAP_DELAY); + } + if (ret) + return ret; + if (mode != LEGACY_MODE) { + ret = arasan_phy_write(host, trim, DLL_TRIM); + if (ret) + return ret; + } + ret = arasan_phy_write(host, 0, DLL_STATUS); + if (ret) + return ret; + if (mode != LEGACY_MODE) { + ret = arasan_phy_write(host, FREQSEL(clk), DLL_STATUS); + if (ret) + return ret; + ret = arasan_phy_sts_poll(host, DLL_STATUS, DLL_RDY_MASK); + if (ret) + return -EBUSY; + } + return 0; +} + +static int arasan_select_phy_clock(struct sdhci_host *host) +{ + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct arasan_host *arasan_host = sdhci_pci_priv(slot); + u8 clk; + + if (arasan_host->chg_clk == host->mmc->ios.clock) + return 0; + + arasan_host->chg_clk = host->mmc->ios.clock; + if (host->mmc->ios.clock == 200000000) + clk = 0x0; + else if (host->mmc->ios.clock == 100000000) + clk = 0x2; + else if (host->mmc->ios.clock == 50000000) + clk = 0x1; + else + clk = 0x0; + + if (host->mmc_host_ops.hs400_enhanced_strobe) { + arasan_phy_set(host, ENHSTRB_MODE, 1, 0x0, 0x0, + DLLTRM_ICP, clk); + } else { + switch (host->mmc->ios.timing) { + case MMC_TIMING_LEGACY: + arasan_phy_set(host, LEGACY_MODE, 0x0, 0x0, 0x0, + 0x0, 0x0); + break; + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + arasan_phy_set(host, HISPD_MODE, 0x3, 0x0, 0x2, + DLLTRM_ICP, clk); + break; + case MMC_TIMING_MMC_HS200: + case MMC_TIMING_UHS_SDR104: + arasan_phy_set(host, HS200_MODE, 0x2, + host->mmc->ios.drv_type, 0x0, + DLLTRM_ICP, clk); + break; + case MMC_TIMING_MMC_DDR52: + case MMC_TIMING_UHS_DDR50: + arasan_phy_set(host, DDR50_MODE, 0x1, 0x0, + 0x0, DLLTRM_ICP, clk); + break; + case MMC_TIMING_MMC_HS400: + arasan_phy_set(host, HS400_MODE, 0x1, + host->mmc->ios.drv_type, 0xa, + DLLTRM_ICP, clk); + break; + default: + break; + } + } + return 0; +} + +static int arasan_pci_probe_slot(struct sdhci_pci_slot *slot) +{ + int err; + + slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | MMC_CAP_8_BIT_DATA; + err = arasan_phy_init(slot->host); + if (err) + return -ENODEV; + return 0; +} + +static void arasan_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) +{ + sdhci_set_clock(host, clock); + + /* Change phy settings for the new clock */ + arasan_select_phy_clock(host); +} + +static const struct sdhci_ops arasan_sdhci_pci_ops = { + .set_clock = arasan_sdhci_set_clock, + .enable_dma = sdhci_pci_enable_dma, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +const struct sdhci_pci_fixes sdhci_arasan = { + .probe_slot = arasan_pci_probe_slot, + .ops = &arasan_sdhci_pci_ops, + .priv_size = sizeof(struct arasan_host), +}; diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-core.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-core.c new file mode 100644 index 000000000000..5fe00b537df6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-core.c @@ -0,0 +1,2566 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* linux/drivers/mmc/host/sdhci-pci.c - SDHCI on PCI bus interface + * + * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. + * + * Thanks to the following companies for their support: + * + * - JMicron (hardware and technical support) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_X86 +#include +#endif + +#include "cqhci.h" + +#include "sdhci.h" +#include "sdhci-pci.h" + +#define mem_clear(data, size) memset((data), 0, (size)) + +static int wb_sdhci_pci = 0; +module_param(wb_sdhci_pci, int, S_IRUGO); + +static void sdhci_pci_hw_reset(struct sdhci_host *host); + +#ifdef CONFIG_PM_SLEEP +static int sdhci_pci_init_wakeup(struct sdhci_pci_chip *chip) +{ + mmc_pm_flag_t pm_flags = 0; + bool cap_cd_wake = false; + int i; + + for (i = 0; i < chip->num_slots; i++) { + struct sdhci_pci_slot *slot = chip->slots[i]; + + if (slot) { + pm_flags |= slot->host->mmc->pm_flags; + if (slot->host->mmc->caps & MMC_CAP_CD_WAKE) + cap_cd_wake = true; + } + } + + if ((pm_flags & MMC_PM_KEEP_POWER) && (pm_flags & MMC_PM_WAKE_SDIO_IRQ)) + return device_wakeup_enable(&chip->pdev->dev); + else if (!cap_cd_wake) + return device_wakeup_disable(&chip->pdev->dev); + + return 0; +} + +static int sdhci_pci_suspend_host(struct sdhci_pci_chip *chip) +{ + int i, ret; + + sdhci_pci_init_wakeup(chip); + + for (i = 0; i < chip->num_slots; i++) { + struct sdhci_pci_slot *slot = chip->slots[i]; + struct sdhci_host *host; + + if (!slot) + continue; + + host = slot->host; + + if (chip->pm_retune && host->tuning_mode != SDHCI_TUNING_MODE_3) + mmc_retune_needed(host->mmc); + + ret = sdhci_suspend_host(host); + if (ret) + goto err_pci_suspend; + + if (device_may_wakeup(&chip->pdev->dev)) + mmc_gpio_set_cd_wake(host->mmc, true); + } + + return 0; + +err_pci_suspend: + while (--i >= 0) + sdhci_resume_host(chip->slots[i]->host); + return ret; +} + +int sdhci_pci_resume_host(struct sdhci_pci_chip *chip) +{ + struct sdhci_pci_slot *slot; + int i, ret; + + for (i = 0; i < chip->num_slots; i++) { + slot = chip->slots[i]; + if (!slot) + continue; + + ret = sdhci_resume_host(slot->host); + if (ret) + return ret; + + mmc_gpio_set_cd_wake(slot->host->mmc, false); + } + + return 0; +} + +static int sdhci_cqhci_suspend(struct sdhci_pci_chip *chip) +{ + int ret; + + ret = cqhci_suspend(chip->slots[0]->host->mmc); + if (ret) + return ret; + + return sdhci_pci_suspend_host(chip); +} + +static int sdhci_cqhci_resume(struct sdhci_pci_chip *chip) +{ + int ret; + + ret = sdhci_pci_resume_host(chip); + if (ret) + return ret; + + return cqhci_resume(chip->slots[0]->host->mmc); +} +#endif + +#ifdef CONFIG_PM +static int sdhci_pci_runtime_suspend_host(struct sdhci_pci_chip *chip) +{ + struct sdhci_pci_slot *slot; + struct sdhci_host *host; + int i, ret; + + for (i = 0; i < chip->num_slots; i++) { + slot = chip->slots[i]; + if (!slot) + continue; + + host = slot->host; + + ret = sdhci_runtime_suspend_host(host); + if (ret) + goto err_pci_runtime_suspend; + + if (chip->rpm_retune && + host->tuning_mode != SDHCI_TUNING_MODE_3) + mmc_retune_needed(host->mmc); + } + + return 0; + +err_pci_runtime_suspend: + while (--i >= 0) + sdhci_runtime_resume_host(chip->slots[i]->host, 0); + return ret; +} + +static int sdhci_pci_runtime_resume_host(struct sdhci_pci_chip *chip) +{ + struct sdhci_pci_slot *slot; + int i, ret; + + for (i = 0; i < chip->num_slots; i++) { + slot = chip->slots[i]; + if (!slot) + continue; + + ret = sdhci_runtime_resume_host(slot->host, 0); + if (ret) + return ret; + } + + return 0; +} + +static int sdhci_cqhci_runtime_suspend(struct sdhci_pci_chip *chip) +{ + int ret; + + ret = cqhci_suspend(chip->slots[0]->host->mmc); + if (ret) + return ret; + + return sdhci_pci_runtime_suspend_host(chip); +} + +static int sdhci_cqhci_runtime_resume(struct sdhci_pci_chip *chip) +{ + int ret; + + ret = sdhci_pci_runtime_resume_host(chip); + if (ret) + return ret; + + return cqhci_resume(chip->slots[0]->host->mmc); +} +#endif + +static u32 sdhci_cqhci_irq(struct sdhci_host *host, u32 intmask) +{ + int cmd_error = 0; + int data_error = 0; + + if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) + return intmask; + + cqhci_irq(host->mmc, intmask, cmd_error, data_error); + + return 0; +} + +static void sdhci_pci_dumpregs(struct mmc_host *mmc) +{ + sdhci_dumpregs(mmc_priv(mmc)); +} + +static void sdhci_cqhci_reset(struct sdhci_host *host, u8 mask) +{ + if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) && + host->mmc->cqe_private) + cqhci_deactivate(host->mmc); + sdhci_reset(host, mask); +} + +/*****************************************************************************\ + * * + * Hardware specific quirk handling * + * * +\*****************************************************************************/ + +static int ricoh_probe(struct sdhci_pci_chip *chip) +{ + if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG || + chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SONY) + chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET; + return 0; +} + +static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot) +{ + slot->host->caps = + FIELD_PREP(SDHCI_TIMEOUT_CLK_MASK, 0x21) | + FIELD_PREP(SDHCI_CLOCK_BASE_MASK, 0x21) | + SDHCI_TIMEOUT_CLK_UNIT | + SDHCI_CAN_VDD_330 | + SDHCI_CAN_DO_HISPD | + SDHCI_CAN_DO_SDMA; + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int ricoh_mmc_resume(struct sdhci_pci_chip *chip) +{ + /* Apply a delay to allow controller to settle */ + /* Otherwise it becomes confused if card state changed + during suspend */ + msleep(500); + return sdhci_pci_resume_host(chip); +} +#endif + +static const struct sdhci_pci_fixes sdhci_ricoh = { + .probe = ricoh_probe, + .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | + SDHCI_QUIRK_FORCE_DMA | + SDHCI_QUIRK_CLOCK_BEFORE_RESET, +}; + +static const struct sdhci_pci_fixes sdhci_ricoh_mmc = { + .probe_slot = ricoh_mmc_probe_slot, +#ifdef CONFIG_PM_SLEEP + .resume = ricoh_mmc_resume, +#endif + .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | + SDHCI_QUIRK_CLOCK_BEFORE_RESET | + SDHCI_QUIRK_NO_CARD_NO_RESET | + SDHCI_QUIRK_MISSING_CAPS +}; + +static const struct sdhci_pci_fixes sdhci_ene_712 = { + .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE | + SDHCI_QUIRK_BROKEN_DMA, +}; + +static const struct sdhci_pci_fixes sdhci_ene_714 = { + .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE | + SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS | + SDHCI_QUIRK_BROKEN_DMA, +}; + +static const struct sdhci_pci_fixes sdhci_cafe = { + .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | + SDHCI_QUIRK_NO_BUSY_IRQ | + SDHCI_QUIRK_BROKEN_CARD_DETECTION | + SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, +}; + +static const struct sdhci_pci_fixes sdhci_intel_qrk = { + .quirks = SDHCI_QUIRK_NO_HISPD_BIT, +}; + +static int mrst_hc_probe_slot(struct sdhci_pci_slot *slot) +{ + slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; + return 0; +} + +/* + * ADMA operation is disabled for Moorestown platform due to + * hardware bugs. + */ +static int mrst_hc_probe(struct sdhci_pci_chip *chip) +{ + /* + * slots number is fixed here for MRST as SDIO3/5 are never used and + * have hardware bugs. + */ + chip->num_slots = 1; + return 0; +} + +static int pch_hc_probe_slot(struct sdhci_pci_slot *slot) +{ + slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; + return 0; +} + +#ifdef CONFIG_PM + +static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id) +{ + struct sdhci_pci_slot *slot = dev_id; + struct sdhci_host *host = slot->host; + + mmc_detect_change(host->mmc, msecs_to_jiffies(200)); + return IRQ_HANDLED; +} + +static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) +{ + int err, irq, gpio = slot->cd_gpio; + + slot->cd_gpio = -EINVAL; + slot->cd_irq = -EINVAL; + + if (!gpio_is_valid(gpio)) + return; + + err = devm_gpio_request(&slot->chip->pdev->dev, gpio, "sd_cd"); + if (err < 0) + goto out; + + err = gpio_direction_input(gpio); + if (err < 0) + goto out_free; + + irq = gpio_to_irq(gpio); + if (irq < 0) + goto out_free; + + err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING, "sd_cd", slot); + if (err) + goto out_free; + + slot->cd_gpio = gpio; + slot->cd_irq = irq; + + return; + +out_free: + devm_gpio_free(&slot->chip->pdev->dev, gpio); +out: + dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n"); +} + +static void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) +{ + if (slot->cd_irq >= 0) + free_irq(slot->cd_irq, slot); +} + +#else + +static inline void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) +{ +} + +static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) +{ +} + +#endif + +static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) +{ + slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE; + slot->host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC; + return 0; +} + +static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot) +{ + slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE; + return 0; +} + +static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = { + .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, + .probe_slot = mrst_hc_probe_slot, +}; + +static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = { + .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, + .probe = mrst_hc_probe, +}; + +static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .allow_runtime_pm = true, + .own_cd_for_runtime_pm = true, +}; + +static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, + .allow_runtime_pm = true, + .probe_slot = mfd_sdio_probe_slot, +}; + +static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = { + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .allow_runtime_pm = true, + .probe_slot = mfd_emmc_probe_slot, +}; + +static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = { + .quirks = SDHCI_QUIRK_BROKEN_ADMA, + .probe_slot = pch_hc_probe_slot, +}; + +#ifdef CONFIG_X86 + +#define BYT_IOSF_SCCEP 0x63 +#define BYT_IOSF_OCP_NETCTRL0 0x1078 +#define BYT_IOSF_OCP_TIMEOUT_BASE GENMASK(10, 8) + +static void byt_ocp_setting(struct pci_dev *pdev) +{ + u32 val = 0; + + if (pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC && + pdev->device != PCI_DEVICE_ID_INTEL_BYT_SDIO && + pdev->device != PCI_DEVICE_ID_INTEL_BYT_SD && + pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC2) + return; + + if (iosf_mbi_read(BYT_IOSF_SCCEP, MBI_CR_READ, BYT_IOSF_OCP_NETCTRL0, + &val)) { + dev_err(&pdev->dev, "%s read error\n", __func__); + return; + } + + if (!(val & BYT_IOSF_OCP_TIMEOUT_BASE)) + return; + + val &= ~BYT_IOSF_OCP_TIMEOUT_BASE; + + if (iosf_mbi_write(BYT_IOSF_SCCEP, MBI_CR_WRITE, BYT_IOSF_OCP_NETCTRL0, + val)) { + dev_err(&pdev->dev, "%s write error\n", __func__); + return; + } + + dev_dbg(&pdev->dev, "%s completed\n", __func__); +} + +#else + +static inline void byt_ocp_setting(struct pci_dev *pdev) +{ +} + +#endif + +enum { + INTEL_DSM_FNS = 0, + INTEL_DSM_V18_SWITCH = 3, + INTEL_DSM_V33_SWITCH = 4, + INTEL_DSM_DRV_STRENGTH = 9, + INTEL_DSM_D3_RETUNE = 10, +}; + +struct intel_host { + u32 dsm_fns; + int drv_strength; + bool d3_retune; + bool rpm_retune_ok; + bool needs_pwr_off; + u32 glk_rx_ctrl1; + u32 glk_tun_val; + u32 active_ltr; + u32 idle_ltr; +}; + +static const guid_t intel_dsm_guid = + GUID_INIT(0xF6C13EA5, 0x65CD, 0x461F, + 0xAB, 0x7A, 0x29, 0xF7, 0xE8, 0xD5, 0xBD, 0x61); + +static int __intel_dsm(struct intel_host *intel_host, struct device *dev, + unsigned int fn, u32 *result) +{ + union acpi_object *obj; + int err = 0; + size_t len; + + obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &intel_dsm_guid, 0, fn, NULL); + if (!obj) + return -EOPNOTSUPP; + + if (obj->type != ACPI_TYPE_BUFFER || obj->buffer.length < 1) { + err = -EINVAL; + goto out; + } + + len = min_t(size_t, obj->buffer.length, 4); + + *result = 0; + memcpy(result, obj->buffer.pointer, len); +out: + ACPI_FREE(obj); + + return err; +} + +static int intel_dsm(struct intel_host *intel_host, struct device *dev, + unsigned int fn, u32 *result) +{ + if (fn > 31 || !(intel_host->dsm_fns & (1 << fn))) + return -EOPNOTSUPP; + + return __intel_dsm(intel_host, dev, fn, result); +} + +static void intel_dsm_init(struct intel_host *intel_host, struct device *dev, + struct mmc_host *mmc) +{ + int err; + u32 val; + + intel_host->d3_retune = true; + + err = __intel_dsm(intel_host, dev, INTEL_DSM_FNS, &intel_host->dsm_fns); + if (err) { + pr_debug("%s: DSM not supported, error %d\n", + mmc_hostname(mmc), err); + return; + } + + pr_debug("%s: DSM function mask %#x\n", + mmc_hostname(mmc), intel_host->dsm_fns); + + err = intel_dsm(intel_host, dev, INTEL_DSM_DRV_STRENGTH, &val); + intel_host->drv_strength = err ? 0 : val; + + err = intel_dsm(intel_host, dev, INTEL_DSM_D3_RETUNE, &val); + intel_host->d3_retune = err ? true : !!val; +} + +static void sdhci_pci_int_hw_reset(struct sdhci_host *host) +{ + u8 reg; + + reg = sdhci_readb(host, SDHCI_POWER_CONTROL); + reg |= 0x10; + sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); + /* For eMMC, minimum is 1us but give it 9us for good measure */ + udelay(9); + reg &= ~0x10; + sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); + /* For eMMC, minimum is 200us but give it 300us for good measure */ + usleep_range(300, 1000); +} + +static int intel_select_drive_strength(struct mmc_card *card, + unsigned int max_dtr, int host_drv, + int card_drv, int *drv_type) +{ + struct sdhci_host *host = mmc_priv(card->host); + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct intel_host *intel_host = sdhci_pci_priv(slot); + + if (!(mmc_driver_type_mask(intel_host->drv_strength) & card_drv)) + return 0; + + return intel_host->drv_strength; +} + +static int bxt_get_cd(struct mmc_host *mmc) +{ + int gpio_cd = mmc_gpio_get_cd(mmc); + struct sdhci_host *host = mmc_priv(mmc); + unsigned long flags; + int ret = 0; + + if (!gpio_cd) + return 0; + + spin_lock_irqsave(&host->lock, flags); + + if (host->flags & SDHCI_DEVICE_DEAD) + goto out; + + ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); +out: + spin_unlock_irqrestore(&host->lock, flags); + + return ret; +} + +#define SDHCI_INTEL_PWR_TIMEOUT_CNT 20 +#define SDHCI_INTEL_PWR_TIMEOUT_UDELAY 100 + +static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode, + unsigned short vdd) +{ + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct intel_host *intel_host = sdhci_pci_priv(slot); + int cntr; + u8 reg; + + /* + * Bus power may control card power, but a full reset still may not + * reset the power, whereas a direct write to SDHCI_POWER_CONTROL can. + * That might be needed to initialize correctly, if the card was left + * powered on previously. + */ + if (intel_host->needs_pwr_off) { + intel_host->needs_pwr_off = false; + if (mode != MMC_POWER_OFF) { + sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); + usleep_range(10000, 12500); + } + } + + sdhci_set_power(host, mode, vdd); + + if (mode == MMC_POWER_OFF) + return; + + /* + * Bus power might not enable after D3 -> D0 transition due to the + * present state not yet having propagated. Retry for up to 2ms. + */ + for (cntr = 0; cntr < SDHCI_INTEL_PWR_TIMEOUT_CNT; cntr++) { + reg = sdhci_readb(host, SDHCI_POWER_CONTROL); + if (reg & SDHCI_POWER_ON) + break; + udelay(SDHCI_INTEL_PWR_TIMEOUT_UDELAY); + reg |= SDHCI_POWER_ON; + sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); + } +} + +static void sdhci_intel_set_uhs_signaling(struct sdhci_host *host, + unsigned int timing) +{ + /* Set UHS timing to SDR25 for High Speed mode */ + if (timing == MMC_TIMING_MMC_HS || timing == MMC_TIMING_SD_HS) + timing = MMC_TIMING_UHS_SDR25; + sdhci_set_uhs_signaling(host, timing); +} + +#define INTEL_HS400_ES_REG 0x78 +#define INTEL_HS400_ES_BIT BIT(0) + +static void intel_hs400_enhanced_strobe(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + u32 val; + + val = sdhci_readl(host, INTEL_HS400_ES_REG); + if (ios->enhanced_strobe) + val |= INTEL_HS400_ES_BIT; + else + val &= ~INTEL_HS400_ES_BIT; + sdhci_writel(host, val, INTEL_HS400_ES_REG); +} + +static int intel_start_signal_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + struct device *dev = mmc_dev(mmc); + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct intel_host *intel_host = sdhci_pci_priv(slot); + unsigned int fn; + u32 result = 0; + int err; + + err = sdhci_start_signal_voltage_switch(mmc, ios); + if (err) + return err; + + switch (ios->signal_voltage) { + case MMC_SIGNAL_VOLTAGE_330: + fn = INTEL_DSM_V33_SWITCH; + break; + case MMC_SIGNAL_VOLTAGE_180: + fn = INTEL_DSM_V18_SWITCH; + break; + default: + return 0; + } + + err = intel_dsm(intel_host, dev, fn, &result); + pr_debug("%s: %s DSM fn %u error %d result %u\n", + mmc_hostname(mmc), __func__, fn, err, result); + + return 0; +} + +static const struct sdhci_ops sdhci_intel_byt_ops = { + .set_clock = sdhci_set_clock, + .set_power = sdhci_intel_set_power, + .enable_dma = sdhci_pci_enable_dma, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_intel_set_uhs_signaling, + .hw_reset = sdhci_pci_hw_reset, +}; + +static const struct sdhci_ops sdhci_intel_glk_ops = { + .set_clock = sdhci_set_clock, + .set_power = sdhci_intel_set_power, + .enable_dma = sdhci_pci_enable_dma, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_cqhci_reset, + .set_uhs_signaling = sdhci_intel_set_uhs_signaling, + .hw_reset = sdhci_pci_hw_reset, + .irq = sdhci_cqhci_irq, +}; + +static void byt_read_dsm(struct sdhci_pci_slot *slot) +{ + struct intel_host *intel_host = sdhci_pci_priv(slot); + struct device *dev = &slot->chip->pdev->dev; + struct mmc_host *mmc = slot->host->mmc; + + intel_dsm_init(intel_host, dev, mmc); + slot->chip->rpm_retune = intel_host->d3_retune; +} + +static int intel_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + int err = sdhci_execute_tuning(mmc, opcode); + struct sdhci_host *host = mmc_priv(mmc); + + if (err) + return err; + + /* + * Tuning can leave the IP in an active state (Buffer Read Enable bit + * set) which prevents the entry to low power states (i.e. S0i3). Data + * reset will clear it. + */ + sdhci_reset(host, SDHCI_RESET_DATA); + + return 0; +} + +#define INTEL_ACTIVELTR 0x804 +#define INTEL_IDLELTR 0x808 + +#define INTEL_LTR_REQ BIT(15) +#define INTEL_LTR_SCALE_MASK GENMASK(11, 10) +#define INTEL_LTR_SCALE_1US (2 << 10) +#define INTEL_LTR_SCALE_32US (3 << 10) +#define INTEL_LTR_VALUE_MASK GENMASK(9, 0) + +static void intel_cache_ltr(struct sdhci_pci_slot *slot) +{ + struct intel_host *intel_host = sdhci_pci_priv(slot); + struct sdhci_host *host = slot->host; + + intel_host->active_ltr = readl(host->ioaddr + INTEL_ACTIVELTR); + intel_host->idle_ltr = readl(host->ioaddr + INTEL_IDLELTR); +} + +static void intel_ltr_set(struct device *dev, s32 val) +{ + struct sdhci_pci_chip *chip = dev_get_drvdata(dev); + struct sdhci_pci_slot *slot = chip->slots[0]; + struct intel_host *intel_host = sdhci_pci_priv(slot); + struct sdhci_host *host = slot->host; + u32 ltr; + + pm_runtime_get_sync(dev); + + /* + * Program latency tolerance (LTR) accordingly what has been asked + * by the PM QoS layer or disable it in case we were passed + * negative value or PM_QOS_LATENCY_ANY. + */ + ltr = readl(host->ioaddr + INTEL_ACTIVELTR); + + if (val == PM_QOS_LATENCY_ANY || val < 0) { + ltr &= ~INTEL_LTR_REQ; + } else { + ltr |= INTEL_LTR_REQ; + ltr &= ~INTEL_LTR_SCALE_MASK; + ltr &= ~INTEL_LTR_VALUE_MASK; + + if (val > INTEL_LTR_VALUE_MASK) { + val >>= 5; + if (val > INTEL_LTR_VALUE_MASK) + val = INTEL_LTR_VALUE_MASK; + ltr |= INTEL_LTR_SCALE_32US | val; + } else { + ltr |= INTEL_LTR_SCALE_1US | val; + } + } + + if (ltr == intel_host->active_ltr) + goto out; + + writel(ltr, host->ioaddr + INTEL_ACTIVELTR); + writel(ltr, host->ioaddr + INTEL_IDLELTR); + + /* Cache the values into lpss structure */ + intel_cache_ltr(slot); +out: + pm_runtime_put_autosuspend(dev); +} + +static bool intel_use_ltr(struct sdhci_pci_chip *chip) +{ + switch (chip->pdev->device) { + case PCI_DEVICE_ID_INTEL_BYT_EMMC: + case PCI_DEVICE_ID_INTEL_BYT_EMMC2: + case PCI_DEVICE_ID_INTEL_BYT_SDIO: + case PCI_DEVICE_ID_INTEL_BYT_SD: + case PCI_DEVICE_ID_INTEL_BSW_EMMC: + case PCI_DEVICE_ID_INTEL_BSW_SDIO: + case PCI_DEVICE_ID_INTEL_BSW_SD: + return false; + default: + return true; + } +} + +static void intel_ltr_expose(struct sdhci_pci_chip *chip) +{ + struct device *dev = &chip->pdev->dev; + + if (!intel_use_ltr(chip)) + return; + + dev->power.set_latency_tolerance = intel_ltr_set; + dev_pm_qos_expose_latency_tolerance(dev); +} + +static void intel_ltr_hide(struct sdhci_pci_chip *chip) +{ + struct device *dev = &chip->pdev->dev; + + if (!intel_use_ltr(chip)) + return; + + dev_pm_qos_hide_latency_tolerance(dev); + dev->power.set_latency_tolerance = NULL; +} + +static void byt_probe_slot(struct sdhci_pci_slot *slot) +{ + struct mmc_host_ops *ops = &slot->host->mmc_host_ops; + struct device *dev = &slot->chip->pdev->dev; + struct mmc_host *mmc = slot->host->mmc; + + byt_read_dsm(slot); + + byt_ocp_setting(slot->chip->pdev); + + ops->execute_tuning = intel_execute_tuning; + ops->start_signal_voltage_switch = intel_start_signal_voltage_switch; + + device_property_read_u32(dev, "max-frequency", &mmc->f_max); + + if (!mmc->slotno) { + slot->chip->slots[mmc->slotno] = slot; + intel_ltr_expose(slot->chip); + } +} + +static void byt_add_debugfs(struct sdhci_pci_slot *slot) +{ + struct intel_host *intel_host = sdhci_pci_priv(slot); + struct mmc_host *mmc = slot->host->mmc; + struct dentry *dir = mmc->debugfs_root; + + if (!intel_use_ltr(slot->chip)) + return; + + debugfs_create_x32("active_ltr", 0444, dir, &intel_host->active_ltr); + debugfs_create_x32("idle_ltr", 0444, dir, &intel_host->idle_ltr); + + intel_cache_ltr(slot); +} + +static int byt_add_host(struct sdhci_pci_slot *slot) +{ + int ret = sdhci_add_host(slot->host); + + if (!ret) + byt_add_debugfs(slot); + return ret; +} + +static void byt_remove_slot(struct sdhci_pci_slot *slot, int dead) +{ + struct mmc_host *mmc = slot->host->mmc; + + if (!mmc->slotno) + intel_ltr_hide(slot->chip); +} + +static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) +{ + byt_probe_slot(slot); + slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | + MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR | + MMC_CAP_CMD_DURING_TFR | + MMC_CAP_WAIT_WHILE_BUSY; + slot->hw_reset = sdhci_pci_int_hw_reset; + if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BSW_EMMC) + slot->host->timeout_clk = 1000; /* 1000 kHz i.e. 1 MHz */ + slot->host->mmc_host_ops.select_drive_strength = + intel_select_drive_strength; + return 0; +} + +static int dnv_emmc_hs_probe_slot(struct sdhci_pci_slot *slot) +{ + /* Remove 1.8V capability, if 1.8V is supported, it will be negotiated to DDR mode */ + slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | + MMC_CAP_HW_RESET | + MMC_CAP_CMD_DURING_TFR | + MMC_CAP_WAIT_WHILE_BUSY; + slot->hw_reset = sdhci_pci_int_hw_reset; + return 0; +} + +static bool glk_broken_cqhci(struct sdhci_pci_slot *slot) +{ + return slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC && + (dmi_match(DMI_BIOS_VENDOR, "LENOVO") || + dmi_match(DMI_SYS_VENDOR, "IRBIS")); +} + +static int glk_emmc_probe_slot(struct sdhci_pci_slot *slot) +{ + int ret = byt_emmc_probe_slot(slot); + + if (!glk_broken_cqhci(slot)) + slot->host->mmc->caps2 |= MMC_CAP2_CQE; + + if (slot->chip->pdev->device != PCI_DEVICE_ID_INTEL_GLK_EMMC) { + slot->host->mmc->caps2 |= MMC_CAP2_HS400_ES, + slot->host->mmc_host_ops.hs400_enhanced_strobe = + intel_hs400_enhanced_strobe; + slot->host->mmc->caps2 |= MMC_CAP2_CQE_DCMD; + } + + return ret; +} + +static const struct cqhci_host_ops glk_cqhci_ops = { + .enable = sdhci_cqe_enable, + .disable = sdhci_cqe_disable, + .dumpregs = sdhci_pci_dumpregs, +}; + +static int glk_emmc_add_host(struct sdhci_pci_slot *slot) +{ + struct device *dev = &slot->chip->pdev->dev; + struct sdhci_host *host = slot->host; + struct cqhci_host *cq_host; + bool dma64; + int ret; + + ret = sdhci_setup_host(host); + if (ret) + return ret; + + cq_host = devm_kzalloc(dev, sizeof(*cq_host), GFP_KERNEL); + if (!cq_host) { + ret = -ENOMEM; + goto cleanup; + } + + cq_host->mmio = host->ioaddr + 0x200; + cq_host->quirks |= CQHCI_QUIRK_SHORT_TXFR_DESC_SZ; + cq_host->ops = &glk_cqhci_ops; + + dma64 = host->flags & SDHCI_USE_64_BIT_DMA; + if (dma64) + cq_host->caps |= CQHCI_TASK_DESC_SZ_128; + + ret = cqhci_init(cq_host, host->mmc, dma64); + if (ret) + goto cleanup; + + ret = __sdhci_add_host(host); + if (ret) + goto cleanup; + + byt_add_debugfs(slot); + + return 0; + +cleanup: + sdhci_cleanup_host(host); + return ret; +} + +#ifdef CONFIG_PM +#define GLK_RX_CTRL1 0x834 +#define GLK_TUN_VAL 0x840 +#define GLK_PATH_PLL GENMASK(13, 8) +#define GLK_DLY GENMASK(6, 0) +/* Workaround firmware failing to restore the tuning value */ +static void glk_rpm_retune_wa(struct sdhci_pci_chip *chip, bool susp) +{ + struct sdhci_pci_slot *slot = chip->slots[0]; + struct intel_host *intel_host = sdhci_pci_priv(slot); + struct sdhci_host *host = slot->host; + u32 glk_rx_ctrl1; + u32 glk_tun_val; + u32 dly; + + if (intel_host->rpm_retune_ok || !mmc_can_retune(host->mmc)) + return; + + glk_rx_ctrl1 = sdhci_readl(host, GLK_RX_CTRL1); + glk_tun_val = sdhci_readl(host, GLK_TUN_VAL); + + if (susp) { + intel_host->glk_rx_ctrl1 = glk_rx_ctrl1; + intel_host->glk_tun_val = glk_tun_val; + return; + } + + if (!intel_host->glk_tun_val) + return; + + if (glk_rx_ctrl1 != intel_host->glk_rx_ctrl1) { + intel_host->rpm_retune_ok = true; + return; + } + + dly = FIELD_PREP(GLK_DLY, FIELD_GET(GLK_PATH_PLL, glk_rx_ctrl1) + + (intel_host->glk_tun_val << 1)); + if (dly == FIELD_GET(GLK_DLY, glk_rx_ctrl1)) + return; + + glk_rx_ctrl1 = (glk_rx_ctrl1 & ~GLK_DLY) | dly; + sdhci_writel(host, glk_rx_ctrl1, GLK_RX_CTRL1); + + intel_host->rpm_retune_ok = true; + chip->rpm_retune = true; + mmc_retune_needed(host->mmc); + pr_info("%s: Requiring re-tune after rpm resume", mmc_hostname(host->mmc)); +} + +static void glk_rpm_retune_chk(struct sdhci_pci_chip *chip, bool susp) +{ + if (chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC && + !chip->rpm_retune) + glk_rpm_retune_wa(chip, susp); +} + +static int glk_runtime_suspend(struct sdhci_pci_chip *chip) +{ + glk_rpm_retune_chk(chip, true); + + return sdhci_cqhci_runtime_suspend(chip); +} + +static int glk_runtime_resume(struct sdhci_pci_chip *chip) +{ + glk_rpm_retune_chk(chip, false); + + return sdhci_cqhci_runtime_resume(chip); +} +#endif + +#ifdef CONFIG_ACPI +static int ni_set_max_freq(struct sdhci_pci_slot *slot) +{ + acpi_status status; + unsigned long long max_freq; + + status = acpi_evaluate_integer(ACPI_HANDLE(&slot->chip->pdev->dev), + "MXFQ", NULL, &max_freq); + if (ACPI_FAILURE(status)) { + dev_err(&slot->chip->pdev->dev, + "MXFQ not found in acpi table\n"); + return -EINVAL; + } + + slot->host->mmc->f_max = max_freq * 1000000; + + return 0; +} +#else +static inline int ni_set_max_freq(struct sdhci_pci_slot *slot) +{ + return 0; +} +#endif + +static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot) +{ + int err; + + byt_probe_slot(slot); + + err = ni_set_max_freq(slot); + if (err) + return err; + + slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE | + MMC_CAP_WAIT_WHILE_BUSY; + return 0; +} + +static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot) +{ + byt_probe_slot(slot); + slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE | + MMC_CAP_WAIT_WHILE_BUSY; + return 0; +} + +static void byt_needs_pwr_off(struct sdhci_pci_slot *slot) +{ + struct intel_host *intel_host = sdhci_pci_priv(slot); + u8 reg = sdhci_readb(slot->host, SDHCI_POWER_CONTROL); + + intel_host->needs_pwr_off = reg & SDHCI_POWER_ON; +} + +static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) +{ + byt_probe_slot(slot); + slot->host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | + MMC_CAP_AGGRESSIVE_PM | MMC_CAP_CD_WAKE; + slot->cd_idx = 0; + slot->cd_override_level = true; + if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXT_SD || + slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXTM_SD || + slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_APL_SD || + slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_SD) + slot->host->mmc_host_ops.get_cd = bxt_get_cd; + + if (slot->chip->pdev->subsystem_vendor == PCI_VENDOR_ID_NI && + slot->chip->pdev->subsystem_device == PCI_SUBDEVICE_ID_NI_78E3) + slot->host->mmc->caps2 |= MMC_CAP2_AVOID_3_3V; + + byt_needs_pwr_off(slot); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP + +static int byt_resume(struct sdhci_pci_chip *chip) +{ + byt_ocp_setting(chip->pdev); + + return sdhci_pci_resume_host(chip); +} + +#endif + +#ifdef CONFIG_PM + +static int byt_runtime_resume(struct sdhci_pci_chip *chip) +{ + byt_ocp_setting(chip->pdev); + + return sdhci_pci_runtime_resume_host(chip); +} + +#endif + +static struct sdhci_pci_fixes sdhci_intel_dnv_emmc = { +#ifdef CONFIG_PM_SLEEP + .resume = byt_resume, +#endif +#ifdef CONFIG_PM + .runtime_resume = byt_runtime_resume, +#endif + .allow_runtime_pm = true, + .probe_slot = byt_emmc_probe_slot, + .add_host = byt_add_host, + .remove_slot = byt_remove_slot, + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | + SDHCI_QUIRK_NO_LED, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_STOP_WITH_TC, + .ops = &sdhci_intel_byt_ops, + .priv_size = sizeof(struct intel_host), +}; + +static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = { +#ifdef CONFIG_PM_SLEEP + .resume = byt_resume, +#endif +#ifdef CONFIG_PM + .runtime_resume = byt_runtime_resume, +#endif + .allow_runtime_pm = true, + .probe_slot = byt_emmc_probe_slot, + .add_host = byt_add_host, + .remove_slot = byt_remove_slot, + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | + SDHCI_QUIRK_NO_LED, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 | + SDHCI_QUIRK2_STOP_WITH_TC, + .ops = &sdhci_intel_byt_ops, + .priv_size = sizeof(struct intel_host), +}; + +static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = { + .allow_runtime_pm = true, + .probe_slot = glk_emmc_probe_slot, + .add_host = glk_emmc_add_host, + .remove_slot = byt_remove_slot, +#ifdef CONFIG_PM_SLEEP + .suspend = sdhci_cqhci_suspend, + .resume = sdhci_cqhci_resume, +#endif +#ifdef CONFIG_PM + .runtime_suspend = glk_runtime_suspend, + .runtime_resume = glk_runtime_resume, +#endif + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | + SDHCI_QUIRK_NO_LED, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 | + SDHCI_QUIRK2_STOP_WITH_TC, + .ops = &sdhci_intel_glk_ops, + .priv_size = sizeof(struct intel_host), +}; + +static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = { +#ifdef CONFIG_PM_SLEEP + .resume = byt_resume, +#endif +#ifdef CONFIG_PM + .runtime_resume = byt_runtime_resume, +#endif + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | + SDHCI_QUIRK_NO_LED, + .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON | + SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + .allow_runtime_pm = true, + .probe_slot = ni_byt_sdio_probe_slot, + .add_host = byt_add_host, + .remove_slot = byt_remove_slot, + .ops = &sdhci_intel_byt_ops, + .priv_size = sizeof(struct intel_host), +}; + +static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { +#ifdef CONFIG_PM_SLEEP + .resume = byt_resume, +#endif +#ifdef CONFIG_PM + .runtime_resume = byt_runtime_resume, +#endif + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | + SDHCI_QUIRK_NO_LED, + .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON | + SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + .allow_runtime_pm = true, + .probe_slot = byt_sdio_probe_slot, + .add_host = byt_add_host, + .remove_slot = byt_remove_slot, + .ops = &sdhci_intel_byt_ops, + .priv_size = sizeof(struct intel_host), +}; + +static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { +#ifdef CONFIG_PM_SLEEP + .resume = byt_resume, +#endif +#ifdef CONFIG_PM + .runtime_resume = byt_runtime_resume, +#endif + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | + SDHCI_QUIRK_NO_LED, + .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | + SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_STOP_WITH_TC, + .allow_runtime_pm = true, + .own_cd_for_runtime_pm = true, + .probe_slot = byt_sd_probe_slot, + .add_host = byt_add_host, + .remove_slot = byt_remove_slot, + .ops = &sdhci_intel_byt_ops, + .priv_size = sizeof(struct intel_host), +}; + +/* Define Host controllers for Intel Merrifield platform */ +#define INTEL_MRFLD_EMMC_0 0 +#define INTEL_MRFLD_EMMC_1 1 +#define INTEL_MRFLD_SD 2 +#define INTEL_MRFLD_SDIO 3 + +#ifdef CONFIG_ACPI +static void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot) +{ + struct acpi_device *device, *child; + + device = ACPI_COMPANION(&slot->chip->pdev->dev); + if (!device) + return; + + acpi_device_fix_up_power(device); + list_for_each_entry(child, &device->children, node) + if (child->status.present && child->status.enabled) + acpi_device_fix_up_power(child); +} +#else +static inline void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot) {} +#endif + +static int intel_mrfld_mmc_probe_slot(struct sdhci_pci_slot *slot) +{ + unsigned int func = PCI_FUNC(slot->chip->pdev->devfn); + + switch (func) { + case INTEL_MRFLD_EMMC_0: + case INTEL_MRFLD_EMMC_1: + slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | + MMC_CAP_8_BIT_DATA | + MMC_CAP_1_8V_DDR; + break; + case INTEL_MRFLD_SD: + slot->host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; + break; + case INTEL_MRFLD_SDIO: + /* Advertise 2.0v for compatibility with the SDIO card's OCR */ + slot->host->ocr_mask = MMC_VDD_20_21 | MMC_VDD_165_195; + slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | + MMC_CAP_POWER_OFF_CARD; + break; + default: + return -ENODEV; + } + + intel_mrfld_mmc_fix_up_power_slot(slot); + return 0; +} + +static const struct sdhci_pci_fixes sdhci_intel_mrfld_mmc = { + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .quirks2 = SDHCI_QUIRK2_BROKEN_HS200 | + SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + .allow_runtime_pm = true, + .probe_slot = intel_mrfld_mmc_probe_slot, +}; + +static int jmicron_pmos(struct sdhci_pci_chip *chip, int on) +{ + u8 scratch; + int ret; + + ret = pci_read_config_byte(chip->pdev, 0xAE, &scratch); + if (ret) + return ret; + + /* + * Turn PMOS on [bit 0], set over current detection to 2.4 V + * [bit 1:2] and enable over current debouncing [bit 6]. + */ + if (on) + scratch |= 0x47; + else + scratch &= ~0x47; + + return pci_write_config_byte(chip->pdev, 0xAE, scratch); +} + +static int jmicron_probe(struct sdhci_pci_chip *chip) +{ + int ret; + u16 mmcdev = 0; + + if (chip->pdev->revision == 0) { + chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR | + SDHCI_QUIRK_32BIT_DMA_SIZE | + SDHCI_QUIRK_32BIT_ADMA_SIZE | + SDHCI_QUIRK_RESET_AFTER_REQUEST | + SDHCI_QUIRK_BROKEN_SMALL_PIO; + } + + /* + * JMicron chips can have two interfaces to the same hardware + * in order to work around limitations in Microsoft's driver. + * We need to make sure we only bind to one of them. + * + * This code assumes two things: + * + * 1. The PCI code adds subfunctions in order. + * + * 2. The MMC interface has a lower subfunction number + * than the SD interface. + */ + if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_SD) + mmcdev = PCI_DEVICE_ID_JMICRON_JMB38X_MMC; + else if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD) + mmcdev = PCI_DEVICE_ID_JMICRON_JMB388_ESD; + + if (mmcdev) { + struct pci_dev *sd_dev; + + sd_dev = NULL; + while ((sd_dev = pci_get_device(PCI_VENDOR_ID_JMICRON, + mmcdev, sd_dev)) != NULL) { + if ((PCI_SLOT(chip->pdev->devfn) == + PCI_SLOT(sd_dev->devfn)) && + (chip->pdev->bus == sd_dev->bus)) + break; + } + + if (sd_dev) { + pci_dev_put(sd_dev); + dev_info(&chip->pdev->dev, "Refusing to bind to " + "secondary interface.\n"); + return -ENODEV; + } + } + + /* + * JMicron chips need a bit of a nudge to enable the power + * output pins. + */ + ret = jmicron_pmos(chip, 1); + if (ret) { + dev_err(&chip->pdev->dev, "Failure enabling card power\n"); + return ret; + } + + /* quirk for unsable RO-detection on JM388 chips */ + if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD || + chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) + chip->quirks |= SDHCI_QUIRK_UNSTABLE_RO_DETECT; + + return 0; +} + +static void jmicron_enable_mmc(struct sdhci_host *host, int on) +{ + u8 scratch; + + scratch = readb(host->ioaddr + 0xC0); + + if (on) + scratch |= 0x01; + else + scratch &= ~0x01; + + writeb(scratch, host->ioaddr + 0xC0); +} + +static int jmicron_probe_slot(struct sdhci_pci_slot *slot) +{ + if (slot->chip->pdev->revision == 0) { + u16 version; + + version = readl(slot->host->ioaddr + SDHCI_HOST_VERSION); + version = (version & SDHCI_VENDOR_VER_MASK) >> + SDHCI_VENDOR_VER_SHIFT; + + /* + * Older versions of the chip have lots of nasty glitches + * in the ADMA engine. It's best just to avoid it + * completely. + */ + if (version < 0xAC) + slot->host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; + } + + /* JM388 MMC doesn't support 1.8V while SD supports it */ + if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) { + slot->host->ocr_avail_sd = MMC_VDD_32_33 | MMC_VDD_33_34 | + MMC_VDD_29_30 | MMC_VDD_30_31 | + MMC_VDD_165_195; /* allow 1.8V */ + slot->host->ocr_avail_mmc = MMC_VDD_32_33 | MMC_VDD_33_34 | + MMC_VDD_29_30 | MMC_VDD_30_31; /* no 1.8V for MMC */ + } + + /* + * The secondary interface requires a bit set to get the + * interrupts. + */ + if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || + slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) + jmicron_enable_mmc(slot->host, 1); + + slot->host->mmc->caps |= MMC_CAP_BUS_WIDTH_TEST; + + return 0; +} + +static void jmicron_remove_slot(struct sdhci_pci_slot *slot, int dead) +{ + if (dead) + return; + + if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || + slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) + jmicron_enable_mmc(slot->host, 0); +} + +#ifdef CONFIG_PM_SLEEP +static int jmicron_suspend(struct sdhci_pci_chip *chip) +{ + int i, ret; + + ret = sdhci_pci_suspend_host(chip); + if (ret) + return ret; + + if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || + chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) { + for (i = 0; i < chip->num_slots; i++) + jmicron_enable_mmc(chip->slots[i]->host, 0); + } + + return 0; +} + +static int jmicron_resume(struct sdhci_pci_chip *chip) +{ + int ret, i; + + if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || + chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) { + for (i = 0; i < chip->num_slots; i++) + jmicron_enable_mmc(chip->slots[i]->host, 1); + } + + ret = jmicron_pmos(chip, 1); + if (ret) { + dev_err(&chip->pdev->dev, "Failure enabling card power\n"); + return ret; + } + + return sdhci_pci_resume_host(chip); +} +#endif + +static const struct sdhci_pci_fixes sdhci_jmicron = { + .probe = jmicron_probe, + + .probe_slot = jmicron_probe_slot, + .remove_slot = jmicron_remove_slot, + +#ifdef CONFIG_PM_SLEEP + .suspend = jmicron_suspend, + .resume = jmicron_resume, +#endif +}; + +/* SysKonnect CardBus2SDIO extra registers */ +#define SYSKT_CTRL 0x200 +#define SYSKT_RDFIFO_STAT 0x204 +#define SYSKT_WRFIFO_STAT 0x208 +#define SYSKT_POWER_DATA 0x20c +#define SYSKT_POWER_330 0xef +#define SYSKT_POWER_300 0xf8 +#define SYSKT_POWER_184 0xcc +#define SYSKT_POWER_CMD 0x20d +#define SYSKT_POWER_START (1 << 7) +#define SYSKT_POWER_STATUS 0x20e +#define SYSKT_POWER_STATUS_OK (1 << 0) +#define SYSKT_BOARD_REV 0x210 +#define SYSKT_CHIP_REV 0x211 +#define SYSKT_CONF_DATA 0x212 +#define SYSKT_CONF_DATA_1V8 (1 << 2) +#define SYSKT_CONF_DATA_2V5 (1 << 1) +#define SYSKT_CONF_DATA_3V3 (1 << 0) + +static int syskt_probe(struct sdhci_pci_chip *chip) +{ + if ((chip->pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) { + chip->pdev->class &= ~0x0000FF; + chip->pdev->class |= PCI_SDHCI_IFDMA; + } + return 0; +} + +static int syskt_probe_slot(struct sdhci_pci_slot *slot) +{ + int tm, ps; + + u8 board_rev = readb(slot->host->ioaddr + SYSKT_BOARD_REV); + u8 chip_rev = readb(slot->host->ioaddr + SYSKT_CHIP_REV); + dev_info(&slot->chip->pdev->dev, "SysKonnect CardBus2SDIO, " + "board rev %d.%d, chip rev %d.%d\n", + board_rev >> 4, board_rev & 0xf, + chip_rev >> 4, chip_rev & 0xf); + if (chip_rev >= 0x20) + slot->host->quirks |= SDHCI_QUIRK_FORCE_DMA; + + writeb(SYSKT_POWER_330, slot->host->ioaddr + SYSKT_POWER_DATA); + writeb(SYSKT_POWER_START, slot->host->ioaddr + SYSKT_POWER_CMD); + udelay(50); + tm = 10; /* Wait max 1 ms */ + do { + ps = readw(slot->host->ioaddr + SYSKT_POWER_STATUS); + if (ps & SYSKT_POWER_STATUS_OK) + break; + udelay(100); + } while (--tm); + if (!tm) { + dev_err(&slot->chip->pdev->dev, + "power regulator never stabilized"); + writeb(0, slot->host->ioaddr + SYSKT_POWER_CMD); + return -ENODEV; + } + + return 0; +} + +static const struct sdhci_pci_fixes sdhci_syskt = { + .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER, + .probe = syskt_probe, + .probe_slot = syskt_probe_slot, +}; + +static int via_probe(struct sdhci_pci_chip *chip) +{ + if (chip->pdev->revision == 0x10) + chip->quirks |= SDHCI_QUIRK_DELAY_AFTER_POWER; + + return 0; +} + +static const struct sdhci_pci_fixes sdhci_via = { + .probe = via_probe, +}; + +static int rtsx_probe_slot(struct sdhci_pci_slot *slot) +{ + slot->host->mmc->caps2 |= MMC_CAP2_HS200; + return 0; +} + +static const struct sdhci_pci_fixes sdhci_rtsx = { + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_BROKEN_64_BIT_DMA | + SDHCI_QUIRK2_BROKEN_DDR50, + .probe_slot = rtsx_probe_slot, +}; + +/*AMD chipset generation*/ +enum amd_chipset_gen { + AMD_CHIPSET_BEFORE_ML, + AMD_CHIPSET_CZ, + AMD_CHIPSET_NL, + AMD_CHIPSET_UNKNOWN, +}; + +/* AMD registers */ +#define AMD_SD_AUTO_PATTERN 0xB8 +#define AMD_MSLEEP_DURATION 4 +#define AMD_SD_MISC_CONTROL 0xD0 +#define AMD_MAX_TUNE_VALUE 0x0B +#define AMD_AUTO_TUNE_SEL 0x10800 +#define AMD_FIFO_PTR 0x30 +#define AMD_BIT_MASK 0x1F + +static void amd_tuning_reset(struct sdhci_host *host) +{ + unsigned int val; + + val = sdhci_readw(host, SDHCI_HOST_CONTROL2); + val |= SDHCI_CTRL_PRESET_VAL_ENABLE | SDHCI_CTRL_EXEC_TUNING; + sdhci_writew(host, val, SDHCI_HOST_CONTROL2); + + val = sdhci_readw(host, SDHCI_HOST_CONTROL2); + val &= ~SDHCI_CTRL_EXEC_TUNING; + sdhci_writew(host, val, SDHCI_HOST_CONTROL2); +} + +static void amd_config_tuning_phase(struct pci_dev *pdev, u8 phase) +{ + unsigned int val; + + pci_read_config_dword(pdev, AMD_SD_AUTO_PATTERN, &val); + val &= ~AMD_BIT_MASK; + val |= (AMD_AUTO_TUNE_SEL | (phase << 1)); + pci_write_config_dword(pdev, AMD_SD_AUTO_PATTERN, val); +} + +static void amd_enable_manual_tuning(struct pci_dev *pdev) +{ + unsigned int val; + + pci_read_config_dword(pdev, AMD_SD_MISC_CONTROL, &val); + val |= AMD_FIFO_PTR; + pci_write_config_dword(pdev, AMD_SD_MISC_CONTROL, val); +} + +static int amd_execute_tuning_hs200(struct sdhci_host *host, u32 opcode) +{ + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct pci_dev *pdev = slot->chip->pdev; + u8 valid_win = 0; + u8 valid_win_max = 0; + u8 valid_win_end = 0; + u8 ctrl, tune_around; + + amd_tuning_reset(host); + + for (tune_around = 0; tune_around < 12; tune_around++) { + amd_config_tuning_phase(pdev, tune_around); + + if (mmc_send_tuning(host->mmc, opcode, NULL)) { + valid_win = 0; + msleep(AMD_MSLEEP_DURATION); + ctrl = SDHCI_RESET_CMD | SDHCI_RESET_DATA; + sdhci_writeb(host, ctrl, SDHCI_SOFTWARE_RESET); + } else if (++valid_win > valid_win_max) { + valid_win_max = valid_win; + valid_win_end = tune_around; + } + } + + if (!valid_win_max) { + dev_err(&pdev->dev, "no tuning point found\n"); + return -EIO; + } + + amd_config_tuning_phase(pdev, valid_win_end - valid_win_max / 2); + + amd_enable_manual_tuning(pdev); + + host->mmc->retune_period = 0; + + return 0; +} + +static int amd_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct sdhci_host *host = mmc_priv(mmc); + + /* AMD requires custom HS200 tuning */ + if (host->timing == MMC_TIMING_MMC_HS200) + return amd_execute_tuning_hs200(host, opcode); + + /* Otherwise perform standard SDHCI tuning */ + return sdhci_execute_tuning(mmc, opcode); +} + +static int amd_probe_slot(struct sdhci_pci_slot *slot) +{ + struct mmc_host_ops *ops = &slot->host->mmc_host_ops; + + ops->execute_tuning = amd_execute_tuning; + + return 0; +} + +static int amd_probe(struct sdhci_pci_chip *chip) +{ + struct pci_dev *smbus_dev; + enum amd_chipset_gen gen; + + smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL); + if (smbus_dev) { + gen = AMD_CHIPSET_BEFORE_ML; + } else { + smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_KERNCZ_SMBUS, NULL); + if (smbus_dev) { + if (smbus_dev->revision < 0x51) + gen = AMD_CHIPSET_CZ; + else + gen = AMD_CHIPSET_NL; + } else { + gen = AMD_CHIPSET_UNKNOWN; + } + } + + if (smbus_dev) { + pci_dev_put(smbus_dev); + } + + if (gen == AMD_CHIPSET_BEFORE_ML || gen == AMD_CHIPSET_CZ) + chip->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD; + + return 0; +} + +static u32 sdhci_read_present_state(struct sdhci_host *host) +{ + return sdhci_readl(host, SDHCI_PRESENT_STATE); +} + +static void amd_sdhci_reset(struct sdhci_host *host, u8 mask) +{ + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct pci_dev *pdev = slot->chip->pdev; + u32 present_state; + + /* + * SDHC 0x7906 requires a hard reset to clear all internal state. + * Otherwise it can get into a bad state where the DATA lines are always + * read as zeros. + */ + if (pdev->device == 0x7906 && (mask & SDHCI_RESET_ALL)) { + pci_clear_master(pdev); + + pci_save_state(pdev); + + pci_set_power_state(pdev, PCI_D3cold); + pr_debug("%s: power_state=%u\n", mmc_hostname(host->mmc), + pdev->current_state); + pci_set_power_state(pdev, PCI_D0); + + pci_restore_state(pdev); + + /* + * SDHCI_RESET_ALL says the card detect logic should not be + * reset, but since we need to reset the entire controller + * we should wait until the card detect logic has stabilized. + * + * This normally takes about 40ms. + */ + readx_poll_timeout( + sdhci_read_present_state, + host, + present_state, + present_state & SDHCI_CD_STABLE, + 10000, + 100000 + ); + } + + return sdhci_reset(host, mask); +} + +static const struct sdhci_ops amd_sdhci_pci_ops = { + .set_clock = sdhci_set_clock, + .enable_dma = sdhci_pci_enable_dma, + .set_bus_width = sdhci_set_bus_width, + .reset = amd_sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +static const struct sdhci_pci_fixes sdhci_amd = { + .probe = amd_probe, + .ops = &amd_sdhci_pci_ops, + .probe_slot = amd_probe_slot, +}; + +static const struct pci_device_id pci_ids[] = { + SDHCI_PCI_DEVICE(RICOH, R5C822, ricoh), + SDHCI_PCI_DEVICE(RICOH, R5C843, ricoh_mmc), + SDHCI_PCI_DEVICE(RICOH, R5CE822, ricoh_mmc), + SDHCI_PCI_DEVICE(RICOH, R5CE823, ricoh_mmc), + SDHCI_PCI_DEVICE(ENE, CB712_SD, ene_712), + SDHCI_PCI_DEVICE(ENE, CB712_SD_2, ene_712), + SDHCI_PCI_DEVICE(ENE, CB714_SD, ene_714), + SDHCI_PCI_DEVICE(ENE, CB714_SD_2, ene_714), + SDHCI_PCI_DEVICE(MARVELL, 88ALP01_SD, cafe), + SDHCI_PCI_DEVICE(JMICRON, JMB38X_SD, jmicron), + SDHCI_PCI_DEVICE(JMICRON, JMB38X_MMC, jmicron), + SDHCI_PCI_DEVICE(JMICRON, JMB388_SD, jmicron), + SDHCI_PCI_DEVICE(JMICRON, JMB388_ESD, jmicron), + SDHCI_PCI_DEVICE(SYSKONNECT, 8000, syskt), + SDHCI_PCI_DEVICE(VIA, 95D0, via), + SDHCI_PCI_DEVICE(REALTEK, 5250, rtsx), + SDHCI_PCI_DEVICE(INTEL, QRK_SD, intel_qrk), + SDHCI_PCI_DEVICE(INTEL, MRST_SD0, intel_mrst_hc0), + SDHCI_PCI_DEVICE(INTEL, MRST_SD1, intel_mrst_hc1_hc2), + SDHCI_PCI_DEVICE(INTEL, MRST_SD2, intel_mrst_hc1_hc2), + SDHCI_PCI_DEVICE(INTEL, MFD_SD, intel_mfd_sd), + SDHCI_PCI_DEVICE(INTEL, MFD_SDIO1, intel_mfd_sdio), + SDHCI_PCI_DEVICE(INTEL, MFD_SDIO2, intel_mfd_sdio), + SDHCI_PCI_DEVICE(INTEL, MFD_EMMC0, intel_mfd_emmc), + SDHCI_PCI_DEVICE(INTEL, MFD_EMMC1, intel_mfd_emmc), + SDHCI_PCI_DEVICE(INTEL, PCH_SDIO0, intel_pch_sdio), + SDHCI_PCI_DEVICE(INTEL, PCH_SDIO1, intel_pch_sdio), + SDHCI_PCI_DEVICE(INTEL, BYT_EMMC, intel_byt_emmc), + SDHCI_PCI_SUBDEVICE(INTEL, BYT_SDIO, NI, 7884, ni_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, BYT_SDIO, intel_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, BYT_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, BYT_EMMC2, intel_byt_emmc), + SDHCI_PCI_DEVICE(INTEL, BSW_EMMC, intel_byt_emmc), + SDHCI_PCI_DEVICE(INTEL, BSW_SDIO, intel_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, BSW_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, CLV_SDIO0, intel_mfd_sd), + SDHCI_PCI_DEVICE(INTEL, CLV_SDIO1, intel_mfd_sdio), + SDHCI_PCI_DEVICE(INTEL, CLV_SDIO2, intel_mfd_sdio), + SDHCI_PCI_DEVICE(INTEL, CLV_EMMC0, intel_mfd_emmc), + SDHCI_PCI_DEVICE(INTEL, CLV_EMMC1, intel_mfd_emmc), + SDHCI_PCI_DEVICE(INTEL, MRFLD_MMC, intel_mrfld_mmc), + SDHCI_PCI_DEVICE(INTEL, SPT_EMMC, intel_byt_emmc), + SDHCI_PCI_DEVICE(INTEL, SPT_SDIO, intel_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, SPT_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, DNV_EMMC, intel_dnv_emmc), + SDHCI_PCI_DEVICE(INTEL, CDF_EMMC, intel_glk_emmc), + SDHCI_PCI_DEVICE(INTEL, BXT_EMMC, intel_byt_emmc), + SDHCI_PCI_DEVICE(INTEL, BXT_SDIO, intel_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, BXT_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, BXTM_EMMC, intel_byt_emmc), + SDHCI_PCI_DEVICE(INTEL, BXTM_SDIO, intel_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, BXTM_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, APL_EMMC, intel_byt_emmc), + SDHCI_PCI_DEVICE(INTEL, APL_SDIO, intel_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, APL_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, GLK_EMMC, intel_glk_emmc), + SDHCI_PCI_DEVICE(INTEL, GLK_SDIO, intel_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, GLK_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, CNP_EMMC, intel_glk_emmc), + SDHCI_PCI_DEVICE(INTEL, CNP_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, CNPH_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, ICP_EMMC, intel_glk_emmc), + SDHCI_PCI_DEVICE(INTEL, ICP_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, EHL_EMMC, intel_glk_emmc), + SDHCI_PCI_DEVICE(INTEL, EHL_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, CML_EMMC, intel_glk_emmc), + SDHCI_PCI_DEVICE(INTEL, CML_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, CMLH_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, JSL_EMMC, intel_glk_emmc), + SDHCI_PCI_DEVICE(INTEL, JSL_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, LKF_EMMC, intel_glk_emmc), + SDHCI_PCI_DEVICE(INTEL, LKF_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(O2, 8120, o2), + SDHCI_PCI_DEVICE(O2, 8220, o2), + SDHCI_PCI_DEVICE(O2, 8221, o2), + SDHCI_PCI_DEVICE(O2, 8320, o2), + SDHCI_PCI_DEVICE(O2, 8321, o2), + SDHCI_PCI_DEVICE(O2, FUJIN2, o2), + SDHCI_PCI_DEVICE(O2, SDS0, o2), + SDHCI_PCI_DEVICE(O2, SDS1, o2), + SDHCI_PCI_DEVICE(O2, SEABIRD0, o2), + SDHCI_PCI_DEVICE(O2, SEABIRD1, o2), + SDHCI_PCI_DEVICE(ARASAN, PHY_EMMC, arasan), + SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps), + SDHCI_PCI_DEVICE(GLI, 9750, gl9750), + SDHCI_PCI_DEVICE(GLI, 9755, gl9755), + SDHCI_PCI_DEVICE(GLI, 9763E, gl9763e), + SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd), + /* Generic SD host controller */ + {PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)}, + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(pci, pci_ids); + +/*****************************************************************************\ + * * + * SDHCI core callbacks * + * * +\*****************************************************************************/ + +int sdhci_pci_enable_dma(struct sdhci_host *host) +{ + struct sdhci_pci_slot *slot; + struct pci_dev *pdev; + + slot = sdhci_priv(host); + pdev = slot->chip->pdev; + + if (((pdev->class & 0xFFFF00) == (PCI_CLASS_SYSTEM_SDHCI << 8)) && + ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) && + (host->flags & SDHCI_USE_SDMA)) { + dev_warn(&pdev->dev, "Will use DMA mode even though HW " + "doesn't fully claim to support it.\n"); + } + + pci_set_master(pdev); + + return 0; +} + +static void sdhci_pci_gpio_hw_reset(struct sdhci_host *host) +{ + struct sdhci_pci_slot *slot = sdhci_priv(host); + int rst_n_gpio = slot->rst_n_gpio; + + if (!gpio_is_valid(rst_n_gpio)) + return; + gpio_set_value_cansleep(rst_n_gpio, 0); + /* For eMMC, minimum is 1us but give it 10us for good measure */ + udelay(10); + gpio_set_value_cansleep(rst_n_gpio, 1); + /* For eMMC, minimum is 200us but give it 300us for good measure */ + usleep_range(300, 1000); +} + +static void sdhci_pci_hw_reset(struct sdhci_host *host) +{ + struct sdhci_pci_slot *slot = sdhci_priv(host); + + if (slot->hw_reset) + slot->hw_reset(host); +} + +static const struct sdhci_ops sdhci_pci_ops = { + .set_clock = sdhci_set_clock, + .enable_dma = sdhci_pci_enable_dma, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, + .hw_reset = sdhci_pci_hw_reset, +}; + +/*****************************************************************************\ + * * + * Suspend/resume * + * * +\*****************************************************************************/ + +#ifdef CONFIG_PM_SLEEP +static int sdhci_pci_suspend(struct device *dev) +{ + struct sdhci_pci_chip *chip = dev_get_drvdata(dev); + + if (!chip) + return 0; + + if (chip->fixes && chip->fixes->suspend) + return chip->fixes->suspend(chip); + + return sdhci_pci_suspend_host(chip); +} + +static int sdhci_pci_resume(struct device *dev) +{ + struct sdhci_pci_chip *chip = dev_get_drvdata(dev); + + if (!chip) + return 0; + + if (chip->fixes && chip->fixes->resume) + return chip->fixes->resume(chip); + + return sdhci_pci_resume_host(chip); +} +#endif + +#ifdef CONFIG_PM +static int sdhci_pci_runtime_suspend(struct device *dev) +{ + struct sdhci_pci_chip *chip = dev_get_drvdata(dev); + + if (!chip) + return 0; + + if (chip->fixes && chip->fixes->runtime_suspend) + return chip->fixes->runtime_suspend(chip); + + return sdhci_pci_runtime_suspend_host(chip); +} + +static int sdhci_pci_runtime_resume(struct device *dev) +{ + struct sdhci_pci_chip *chip = dev_get_drvdata(dev); + + if (!chip) + return 0; + + if (chip->fixes && chip->fixes->runtime_resume) + return chip->fixes->runtime_resume(chip); + + return sdhci_pci_runtime_resume_host(chip); +} +#endif + +static const struct dev_pm_ops sdhci_pci_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(sdhci_pci_suspend, sdhci_pci_resume) + SET_RUNTIME_PM_OPS(sdhci_pci_runtime_suspend, + sdhci_pci_runtime_resume, NULL) +}; + +/*****************************************************************************\ + * * + * Device probing/removal * + * * +\*****************************************************************************/ + +static struct sdhci_pci_slot *sdhci_pci_probe_slot( + struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar, + int slotno) +{ + struct sdhci_pci_slot *slot; + struct sdhci_host *host; + int ret, bar = first_bar + slotno; + size_t priv_size = chip->fixes ? chip->fixes->priv_size : 0; + + if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { + dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar); + return ERR_PTR(-ENODEV); + } + + if (pci_resource_len(pdev, bar) < 0x100) { + dev_err(&pdev->dev, "Invalid iomem size. You may " + "experience problems.\n"); + } + + if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) { + dev_err(&pdev->dev, "Vendor specific interface. Aborting.\n"); + return ERR_PTR(-ENODEV); + } + + if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) { + dev_err(&pdev->dev, "Unknown interface. Aborting.\n"); + return ERR_PTR(-ENODEV); + } + + host = sdhci_alloc_host(&pdev->dev, sizeof(*slot) + priv_size); + if (IS_ERR(host)) { + dev_err(&pdev->dev, "cannot allocate host\n"); + return ERR_CAST(host); + } + + slot = sdhci_priv(host); + + slot->chip = chip; + slot->host = host; + slot->rst_n_gpio = -EINVAL; + slot->cd_gpio = -EINVAL; + slot->cd_idx = -1; + + /* Retrieve platform data if there is any */ + if (*sdhci_pci_get_data) + slot->data = sdhci_pci_get_data(pdev, slotno); + + if (slot->data) { + if (slot->data->setup) { + ret = slot->data->setup(slot->data); + if (ret) { + dev_err(&pdev->dev, "platform setup failed\n"); + goto free; + } + } + slot->rst_n_gpio = slot->data->rst_n_gpio; + slot->cd_gpio = slot->data->cd_gpio; + } + + host->hw_name = "PCI"; + host->ops = chip->fixes && chip->fixes->ops ? + chip->fixes->ops : + &sdhci_pci_ops; + host->quirks = chip->quirks; + host->quirks2 = chip->quirks2; + + host->irq = pdev->irq; + + ret = pcim_iomap_regions(pdev, BIT(bar), mmc_hostname(host->mmc)); + if (ret) { + dev_err(&pdev->dev, "cannot request region\n"); + goto cleanup; + } + + host->ioaddr = pcim_iomap_table(pdev)[bar]; + + if (chip->fixes && chip->fixes->probe_slot) { + ret = chip->fixes->probe_slot(slot); + if (ret) + goto cleanup; + } + + if (gpio_is_valid(slot->rst_n_gpio)) { + if (!devm_gpio_request(&pdev->dev, slot->rst_n_gpio, "eMMC_reset")) { + gpio_direction_output(slot->rst_n_gpio, 1); + slot->host->mmc->caps |= MMC_CAP_HW_RESET; + slot->hw_reset = sdhci_pci_gpio_hw_reset; + } else { + dev_warn(&pdev->dev, "failed to request rst_n_gpio\n"); + slot->rst_n_gpio = -EINVAL; + } + } + + host->mmc->pm_caps = MMC_PM_KEEP_POWER; + host->mmc->slotno = slotno; + host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP; + + if (device_can_wakeup(&pdev->dev)) + host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; + + if (host->mmc->caps & MMC_CAP_CD_WAKE) + device_init_wakeup(&pdev->dev, true); + + if (slot->cd_idx >= 0) { + ret = mmc_gpiod_request_cd(host->mmc, "cd", slot->cd_idx, + slot->cd_override_level, 0); + if (ret && ret != -EPROBE_DEFER) + ret = mmc_gpiod_request_cd(host->mmc, NULL, + slot->cd_idx, + slot->cd_override_level, + 0); + if (ret == -EPROBE_DEFER) + goto remove; + + if (ret) { + dev_warn(&pdev->dev, "failed to setup card detect gpio\n"); + slot->cd_idx = -1; + } + } + + if (chip->fixes && chip->fixes->add_host) + ret = chip->fixes->add_host(slot); + else + ret = sdhci_add_host(host); + if (ret) + goto remove; + + sdhci_pci_add_own_cd(slot); + + /* + * Check if the chip needs a separate GPIO for card detect to wake up + * from runtime suspend. If it is not there, don't allow runtime PM. + * Note sdhci_pci_add_own_cd() sets slot->cd_gpio to -EINVAL on failure. + */ + if (chip->fixes && chip->fixes->own_cd_for_runtime_pm && + !gpio_is_valid(slot->cd_gpio) && slot->cd_idx < 0) + chip->allow_runtime_pm = false; + + return slot; + +remove: + if (chip->fixes && chip->fixes->remove_slot) + chip->fixes->remove_slot(slot, 0); + +cleanup: + if (slot->data && slot->data->cleanup) + slot->data->cleanup(slot->data); + +free: + sdhci_free_host(host); + + return ERR_PTR(ret); +} + +static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) +{ + int dead; + u32 scratch; + + sdhci_pci_remove_own_cd(slot); + + dead = 0; + scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS); + if (scratch == (u32)-1) + dead = 1; + + sdhci_remove_host(slot->host, dead); + + if (slot->chip->fixes && slot->chip->fixes->remove_slot) + slot->chip->fixes->remove_slot(slot, dead); + + if (slot->data && slot->data->cleanup) + slot->data->cleanup(slot->data); + + sdhci_free_host(slot->host); +} + +static void sdhci_pci_runtime_pm_allow(struct device *dev) +{ + pm_suspend_ignore_children(dev, 1); + pm_runtime_set_autosuspend_delay(dev, 50); + pm_runtime_use_autosuspend(dev); + pm_runtime_allow(dev); + /* Stay active until mmc core scans for a card */ + pm_runtime_put_noidle(dev); +} + +static void sdhci_pci_runtime_pm_forbid(struct device *dev) +{ + pm_runtime_forbid(dev); + pm_runtime_get_noresume(dev); +} + +/* define by gohi, set in bios acpi dsdt table */ +#define EMMC_DSDT_MODE_HS400 0 +#define EMMC_DSDT_MODE_HS200 1 +#define EMMC_DSDT_MODE_DDR52 2 +#define EMMC_DSDT_MODE_SDR52 3 + +static int sdhci_set_quirks2_by_dsdt(struct pci_dev *pdev) +{ + struct acpi_device *acpi_dev; + struct fwnode_handle *pfwnod = pdev->dev.fwnode; + u64 mode; + int ret; + + /* Find acpi node through pci, + * the relationship between pci and acpi devices can be viewed through the /sys/bus file */ + acpi_dev = container_of(pfwnod, struct acpi_device, fwnode); + + /* DSDT need take node as: "Name (MODE, 0x0-)" */ + ret = acpi_evaluate_integer(acpi_dev->handle, "MODE", NULL, &mode); + if (ACPI_SUCCESS(ret)) { + dev_info(&pdev->dev, "SD controller get bus mode:0x%lld from dsts success.\n", mode); + switch(mode) { + case EMMC_DSDT_MODE_SDR52: + sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_BROKEN_DDR50 | SDHCI_QUIRK2_BROKEN_HS200; + sdhci_intel_dnv_emmc.probe_slot = dnv_emmc_hs_probe_slot; + dev_info(&pdev->dev, "Configure SDHCI as SDR52 attribute through dsdt.\n"); + break; + case EMMC_DSDT_MODE_DDR52: + sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; + dev_info(&pdev->dev, "Configure SDHCI as DDR52 attribute through dsdt.\n"); + break; + case EMMC_DSDT_MODE_HS200: + dev_info(&pdev->dev, "Configure SDHCI as HS200 attribute through dsdt.\n"); + break; + case EMMC_DSDT_MODE_HS400: + sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400; + dev_info(&pdev->dev, "Configure SDHCI as HS400 attribute through dsdt.\n"); + break; + default: + ret = EINVAL; + break; + } + } else { + ret = EINVAL; + } + + return ret; +} + +#ifndef COMMAND_LINE_SIZE +#define COMMAND_LINE_SIZE 1024 +#endif + +int sdhci_cmdline_read(char *cmdline) +{ + struct file *filp; + int ret = 0; + loff_t pos; + + /* Basically, the kernel parameters with arch are not exported. + * In order to not have too much influence and generalization, + * use the proc file to obtain parameter information. */ + filp = filp_open("/proc/cmdline", O_RDONLY, 0); + if (IS_ERR(filp)) { + filp = NULL; + goto exit; + } + pos = 0; + ret = kernel_read(filp, cmdline, COMMAND_LINE_SIZE, &pos); + if (ret < 0) { + goto exit; + } + filp_close(filp, NULL); + + return 0; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + return -1; +} + +static int sdhci_set_quirks2_by_cmdline(struct pci_dev *pdev) +{ + char *option, cmdline[COMMAND_LINE_SIZE]; + int ret = 0; + + mem_clear(cmdline, COMMAND_LINE_SIZE); + + ret = sdhci_cmdline_read(cmdline); + if (ret) { + return ret; + } + + option = strstr(cmdline, "sdhcimode="); + if (option == NULL) { + return EINVAL; + } + + /* Count, sdhcimode= is it 10 bytes? */ + option += 10; + + if (!strncmp(option, "sdr52", 5)) { + sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_BROKEN_DDR50 | SDHCI_QUIRK2_BROKEN_HS200; + /* Remove 1.8V ability */ + sdhci_intel_dnv_emmc.probe_slot = dnv_emmc_hs_probe_slot; + dev_info(&pdev->dev, "Configure SDHCI as SDR52 attribute through cmdline.\n"); + } else if (!strncmp(option, "ddr52", 5)) { + sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; + dev_info(&pdev->dev, "Configure SDHCI as DDR52 attribute through cmdline.\n"); + } else if (!strncmp(option, "hs200", 5)) { + dev_info(&pdev->dev, "Configure SDHCI as HS200 attribute through cmdline.\n"); + ; + } else if (!strncmp(option, "hs400", 5)) { + sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400; + dev_info(&pdev->dev, "Configure SDHCI as HS400 attribute through cmdline.\n"); + } else { + dev_info(&pdev->dev, "CSDHCI: Unknown cmdline option.\n"); + return EINVAL; + } + + return 0; +} + +static int sdhci_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct sdhci_pci_chip *chip; + struct sdhci_pci_slot *slot; + + u8 slots, first_bar; + int ret, i; + + BUG_ON(pdev == NULL); + BUG_ON(ent == NULL); + + dev_info(&pdev->dev, "SDHCI controller found [%04x:%04x] (rev %x)\n", + (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); + + /* cmdline setting priority, the kernel parameters can be changed flexibly, + * and Bios upgrades are not convenient or secure. */ + ret = sdhci_set_quirks2_by_cmdline(pdev); + if (ret) { + ret = sdhci_set_quirks2_by_dsdt(pdev); + if (ret) { + sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400; + dev_info(&pdev->dev, "Configure SDHCI as default[HS400].\n"); + } + } + + ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots); + if (ret) + return ret; + + slots = PCI_SLOT_INFO_SLOTS(slots) + 1; + dev_dbg(&pdev->dev, "found %d slot(s)\n", slots); + + BUG_ON(slots > MAX_SLOTS); + + ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar); + if (ret) + return ret; + + first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK; + + if (first_bar > 5) { + dev_err(&pdev->dev, "Invalid first BAR. Aborting.\n"); + return -ENODEV; + } + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->pdev = pdev; + chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data; + if (chip->fixes) { + chip->quirks = chip->fixes->quirks; + chip->quirks2 = chip->fixes->quirks2; + chip->allow_runtime_pm = chip->fixes->allow_runtime_pm; + } + chip->num_slots = slots; + chip->pm_retune = true; + chip->rpm_retune = true; + + pci_set_drvdata(pdev, chip); + + if (chip->fixes && chip->fixes->probe) { + ret = chip->fixes->probe(chip); + if (ret) + return ret; + } + + slots = chip->num_slots; /* Quirk may have changed this */ + + for (i = 0; i < slots; i++) { + slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i); + if (IS_ERR(slot)) { + for (i--; i >= 0; i--) + sdhci_pci_remove_slot(chip->slots[i]); + return PTR_ERR(slot); + } + + chip->slots[i] = slot; + } + + if (chip->allow_runtime_pm) + sdhci_pci_runtime_pm_allow(&pdev->dev); + + return 0; +} + +static void sdhci_pci_remove(struct pci_dev *pdev) +{ + int i; + struct sdhci_pci_chip *chip = pci_get_drvdata(pdev); + + if (chip->allow_runtime_pm) + sdhci_pci_runtime_pm_forbid(&pdev->dev); + + for (i = 0; i < chip->num_slots; i++) + sdhci_pci_remove_slot(chip->slots[i]); +} + +static struct pci_driver sdhci_driver = { + .name = "sdhci-pci", + .id_table = pci_ids, + .probe = sdhci_pci_probe, + .remove = sdhci_pci_remove, + .driver = { + .pm = &sdhci_pci_pm_ops + }, +}; + +module_pci_driver(sdhci_driver); + +MODULE_AUTHOR("Pierre Ossman "); +MODULE_DESCRIPTION("Secure Digital Host Controller Interface PCI driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-dwc-mshc.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-dwc-mshc.c new file mode 100644 index 000000000000..f78d65448d17 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-dwc-mshc.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SDHCI driver for Synopsys DWC_MSHC controller + * + * Copyright (C) 2018 Synopsys, Inc. (www.synopsys.com) + * + * Authors: + * Prabu Thangamuthu + * Manjunath M B + */ + +#include "sdhci.h" +#include "sdhci-pci.h" + +#define SDHCI_VENDOR_PTR_R 0xE8 + +/* Synopsys vendor specific registers */ +#define SDHC_GPIO_OUT 0x34 +#define SDHC_AT_CTRL_R 0x40 +#define SDHC_SW_TUNE_EN 0x00000010 + +/* MMCM DRP */ +#define SDHC_MMCM_DIV_REG 0x1020 +#define DIV_REG_100_MHZ 0x1145 +#define DIV_REG_200_MHZ 0x1083 +#define SDHC_MMCM_CLKFBOUT 0x1024 +#define CLKFBOUT_100_MHZ 0x0000 +#define CLKFBOUT_200_MHZ 0x0080 +#define SDHC_CCLK_MMCM_RST 0x00000001 + +static void sdhci_snps_set_clock(struct sdhci_host *host, unsigned int clock) +{ + u16 clk; + u32 reg, vendor_ptr; + + vendor_ptr = sdhci_readw(host, SDHCI_VENDOR_PTR_R); + + /* Disable software managed rx tuning */ + reg = sdhci_readl(host, (SDHC_AT_CTRL_R + vendor_ptr)); + reg &= ~SDHC_SW_TUNE_EN; + sdhci_writel(host, reg, (SDHC_AT_CTRL_R + vendor_ptr)); + + if (clock <= 52000000) { + sdhci_set_clock(host, clock); + } else { + /* Assert reset to MMCM */ + reg = sdhci_readl(host, (SDHC_GPIO_OUT + vendor_ptr)); + reg |= SDHC_CCLK_MMCM_RST; + sdhci_writel(host, reg, (SDHC_GPIO_OUT + vendor_ptr)); + + /* Configure MMCM */ + if (clock == 100000000) { + sdhci_writel(host, DIV_REG_100_MHZ, SDHC_MMCM_DIV_REG); + sdhci_writel(host, CLKFBOUT_100_MHZ, + SDHC_MMCM_CLKFBOUT); + } else { + sdhci_writel(host, DIV_REG_200_MHZ, SDHC_MMCM_DIV_REG); + sdhci_writel(host, CLKFBOUT_200_MHZ, + SDHC_MMCM_CLKFBOUT); + } + + /* De-assert reset to MMCM */ + reg = sdhci_readl(host, (SDHC_GPIO_OUT + vendor_ptr)); + reg &= ~SDHC_CCLK_MMCM_RST; + sdhci_writel(host, reg, (SDHC_GPIO_OUT + vendor_ptr)); + + /* Enable clock */ + clk = SDHCI_PROG_CLOCK_MODE | SDHCI_CLOCK_INT_EN | + SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + } +} + +static const struct sdhci_ops sdhci_snps_ops = { + .set_clock = sdhci_snps_set_clock, + .enable_dma = sdhci_pci_enable_dma, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +const struct sdhci_pci_fixes sdhci_snps = { + .ops = &sdhci_snps_ops, +}; diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-gli.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-gli.c new file mode 100644 index 000000000000..23b89b4cad08 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-gli.c @@ -0,0 +1,865 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Genesys Logic, Inc. + * + * Authors: Ben Chuang + * + * Version: v0.9.0 (2019-08-08) + */ + +#include +#include +#include +#include +#include +#include "sdhci.h" +#include "sdhci-pci.h" +#include "cqhci.h" + +/* Genesys Logic extra registers */ +#define SDHCI_GLI_9750_WT 0x800 +#define SDHCI_GLI_9750_WT_EN BIT(0) +#define GLI_9750_WT_EN_ON 0x1 +#define GLI_9750_WT_EN_OFF 0x0 + +#define SDHCI_GLI_9750_DRIVING 0x860 +#define SDHCI_GLI_9750_DRIVING_1 GENMASK(11, 0) +#define SDHCI_GLI_9750_DRIVING_2 GENMASK(27, 26) +#define GLI_9750_DRIVING_1_VALUE 0xFFF +#define GLI_9750_DRIVING_2_VALUE 0x3 +#define SDHCI_GLI_9750_SEL_1 BIT(29) +#define SDHCI_GLI_9750_SEL_2 BIT(31) +#define SDHCI_GLI_9750_ALL_RST (BIT(24)|BIT(25)|BIT(28)|BIT(30)) + +#define SDHCI_GLI_9750_PLL 0x864 +#define SDHCI_GLI_9750_PLL_LDIV GENMASK(9, 0) +#define SDHCI_GLI_9750_PLL_PDIV GENMASK(14, 12) +#define SDHCI_GLI_9750_PLL_DIR BIT(15) +#define SDHCI_GLI_9750_PLL_TX2_INV BIT(23) +#define SDHCI_GLI_9750_PLL_TX2_DLY GENMASK(22, 20) +#define GLI_9750_PLL_TX2_INV_VALUE 0x1 +#define GLI_9750_PLL_TX2_DLY_VALUE 0x0 +#define SDHCI_GLI_9750_PLLSSC_STEP GENMASK(28, 24) +#define SDHCI_GLI_9750_PLLSSC_EN BIT(31) + +#define SDHCI_GLI_9750_PLLSSC 0x86C +#define SDHCI_GLI_9750_PLLSSC_PPM GENMASK(31, 16) + +#define SDHCI_GLI_9750_SW_CTRL 0x874 +#define SDHCI_GLI_9750_SW_CTRL_4 GENMASK(7, 6) +#define GLI_9750_SW_CTRL_4_VALUE 0x3 + +#define SDHCI_GLI_9750_MISC 0x878 +#define SDHCI_GLI_9750_MISC_TX1_INV BIT(2) +#define SDHCI_GLI_9750_MISC_RX_INV BIT(3) +#define SDHCI_GLI_9750_MISC_TX1_DLY GENMASK(6, 4) +#define GLI_9750_MISC_TX1_INV_VALUE 0x0 +#define GLI_9750_MISC_RX_INV_ON 0x1 +#define GLI_9750_MISC_RX_INV_OFF 0x0 +#define GLI_9750_MISC_RX_INV_VALUE GLI_9750_MISC_RX_INV_OFF +#define GLI_9750_MISC_TX1_DLY_VALUE 0x5 + +#define SDHCI_GLI_9750_TUNING_CONTROL 0x540 +#define SDHCI_GLI_9750_TUNING_CONTROL_EN BIT(4) +#define GLI_9750_TUNING_CONTROL_EN_ON 0x1 +#define GLI_9750_TUNING_CONTROL_EN_OFF 0x0 +#define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1 BIT(16) +#define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2 GENMASK(20, 19) +#define GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE 0x1 +#define GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE 0x2 + +#define SDHCI_GLI_9750_TUNING_PARAMETERS 0x544 +#define SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY GENMASK(2, 0) +#define GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE 0x1 + +#define SDHCI_GLI_9763E_CTRL_HS400 0x7 + +#define SDHCI_GLI_9763E_HS400_ES_REG 0x52C +#define SDHCI_GLI_9763E_HS400_ES_BIT BIT(8) + +#define PCIE_GLI_9763E_VHS 0x884 +#define GLI_9763E_VHS_REV GENMASK(19, 16) +#define GLI_9763E_VHS_REV_R 0x0 +#define GLI_9763E_VHS_REV_M 0x1 +#define GLI_9763E_VHS_REV_W 0x2 +#define PCIE_GLI_9763E_MB 0x888 +#define GLI_9763E_MB_CMDQ_OFF BIT(19) +#define PCIE_GLI_9763E_SCR 0x8E0 +#define GLI_9763E_SCR_AXI_REQ BIT(9) + +#define SDHCI_GLI_9763E_CQE_BASE_ADDR 0x200 +#define GLI_9763E_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \ + SDHCI_TRNS_BLK_CNT_EN | \ + SDHCI_TRNS_DMA) + +#define PCI_GLI_9755_WT 0x800 +#define PCI_GLI_9755_WT_EN BIT(0) +#define GLI_9755_WT_EN_ON 0x1 +#define GLI_9755_WT_EN_OFF 0x0 + +#define PCI_GLI_9755_PLL 0x64 +#define PCI_GLI_9755_PLL_LDIV GENMASK(9, 0) +#define PCI_GLI_9755_PLL_PDIV GENMASK(14, 12) +#define PCI_GLI_9755_PLL_DIR BIT(15) +#define PCI_GLI_9755_PLLSSC_STEP GENMASK(28, 24) +#define PCI_GLI_9755_PLLSSC_EN BIT(31) + +#define PCI_GLI_9755_PLLSSC 0x68 +#define PCI_GLI_9755_PLLSSC_PPM GENMASK(15, 0) + +#define GLI_MAX_TUNING_LOOP 40 + +/* Genesys Logic chipset */ +static inline void gl9750_wt_on(struct sdhci_host *host) +{ + u32 wt_value; + u32 wt_enable; + + wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT); + wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value); + + if (wt_enable == GLI_9750_WT_EN_ON) + return; + + wt_value &= ~SDHCI_GLI_9750_WT_EN; + wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_ON); + + sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT); +} + +static inline void gl9750_wt_off(struct sdhci_host *host) +{ + u32 wt_value; + u32 wt_enable; + + wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT); + wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value); + + if (wt_enable == GLI_9750_WT_EN_OFF) + return; + + wt_value &= ~SDHCI_GLI_9750_WT_EN; + wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_OFF); + + sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT); +} + +static void gli_set_9750(struct sdhci_host *host) +{ + u32 driving_value; + u32 pll_value; + u32 sw_ctrl_value; + u32 misc_value; + u32 parameter_value; + u32 control_value; + u16 ctrl2; + + gl9750_wt_on(host); + + driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING); + pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL); + sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL); + misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC); + parameter_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_PARAMETERS); + control_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_CONTROL); + + driving_value &= ~(SDHCI_GLI_9750_DRIVING_1); + driving_value &= ~(SDHCI_GLI_9750_DRIVING_2); + driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_1, + GLI_9750_DRIVING_1_VALUE); + driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_2, + GLI_9750_DRIVING_2_VALUE); + driving_value &= ~(SDHCI_GLI_9750_SEL_1|SDHCI_GLI_9750_SEL_2|SDHCI_GLI_9750_ALL_RST); + driving_value |= SDHCI_GLI_9750_SEL_2; + sdhci_writel(host, driving_value, SDHCI_GLI_9750_DRIVING); + + sw_ctrl_value &= ~SDHCI_GLI_9750_SW_CTRL_4; + sw_ctrl_value |= FIELD_PREP(SDHCI_GLI_9750_SW_CTRL_4, + GLI_9750_SW_CTRL_4_VALUE); + sdhci_writel(host, sw_ctrl_value, SDHCI_GLI_9750_SW_CTRL); + + /* reset the tuning flow after reinit and before starting tuning */ + pll_value &= ~SDHCI_GLI_9750_PLL_TX2_INV; + pll_value &= ~SDHCI_GLI_9750_PLL_TX2_DLY; + pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_INV, + GLI_9750_PLL_TX2_INV_VALUE); + pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_DLY, + GLI_9750_PLL_TX2_DLY_VALUE); + + misc_value &= ~SDHCI_GLI_9750_MISC_TX1_INV; + misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV; + misc_value &= ~SDHCI_GLI_9750_MISC_TX1_DLY; + misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_INV, + GLI_9750_MISC_TX1_INV_VALUE); + misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, + GLI_9750_MISC_RX_INV_VALUE); + misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_DLY, + GLI_9750_MISC_TX1_DLY_VALUE); + + parameter_value &= ~SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY; + parameter_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY, + GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE); + + control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1; + control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2; + control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1, + GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE); + control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2, + GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE); + + sdhci_writel(host, pll_value, SDHCI_GLI_9750_PLL); + sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC); + + /* disable tuned clk */ + ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + ctrl2 &= ~SDHCI_CTRL_TUNED_CLK; + sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); + + /* enable tuning parameters control */ + control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN; + control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN, + GLI_9750_TUNING_CONTROL_EN_ON); + sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL); + + /* write tuning parameters */ + sdhci_writel(host, parameter_value, SDHCI_GLI_9750_TUNING_PARAMETERS); + + /* disable tuning parameters control */ + control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN; + control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN, + GLI_9750_TUNING_CONTROL_EN_OFF); + sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL); + + /* clear tuned clk */ + ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + ctrl2 &= ~SDHCI_CTRL_TUNED_CLK; + sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); + + gl9750_wt_off(host); +} + +static void gli_set_9750_rx_inv(struct sdhci_host *host, bool b) +{ + u32 misc_value; + + gl9750_wt_on(host); + + misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC); + misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV; + if (b) { + misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, + GLI_9750_MISC_RX_INV_ON); + } else { + misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, + GLI_9750_MISC_RX_INV_OFF); + } + sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC); + + gl9750_wt_off(host); +} + +static int __sdhci_execute_tuning_9750(struct sdhci_host *host, u32 opcode) +{ + int i; + int rx_inv; + + for (rx_inv = 0; rx_inv < 2; rx_inv++) { + gli_set_9750_rx_inv(host, !!rx_inv); + sdhci_start_tuning(host); + + for (i = 0; i < GLI_MAX_TUNING_LOOP; i++) { + u16 ctrl; + + sdhci_send_tuning(host, opcode); + + if (!host->tuning_done) { + sdhci_abort_tuning(host, opcode); + break; + } + + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { + if (ctrl & SDHCI_CTRL_TUNED_CLK) + return 0; /* Success! */ + break; + } + } + } + if (!host->tuning_done) { + pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n", + mmc_hostname(host->mmc)); + return -ETIMEDOUT; + } + + pr_info("%s: Tuning failed, falling back to fixed sampling clock\n", + mmc_hostname(host->mmc)); + sdhci_reset_tuning(host); + + return -EAGAIN; +} + +static int gl9750_execute_tuning(struct sdhci_host *host, u32 opcode) +{ + host->mmc->retune_period = 0; + if (host->tuning_mode == SDHCI_TUNING_MODE_1) + host->mmc->retune_period = host->tuning_count; + + gli_set_9750(host); + host->tuning_err = __sdhci_execute_tuning_9750(host, opcode); + sdhci_end_tuning(host); + + return 0; +} + +static void gl9750_disable_ssc_pll(struct sdhci_host *host) +{ + u32 pll; + + gl9750_wt_on(host); + pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); + pll &= ~(SDHCI_GLI_9750_PLL_DIR | SDHCI_GLI_9750_PLLSSC_EN); + sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); + gl9750_wt_off(host); +} + +static void gl9750_set_pll(struct sdhci_host *host, u8 dir, u16 ldiv, u8 pdiv) +{ + u32 pll; + + gl9750_wt_on(host); + pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); + pll &= ~(SDHCI_GLI_9750_PLL_LDIV | + SDHCI_GLI_9750_PLL_PDIV | + SDHCI_GLI_9750_PLL_DIR); + pll |= FIELD_PREP(SDHCI_GLI_9750_PLL_LDIV, ldiv) | + FIELD_PREP(SDHCI_GLI_9750_PLL_PDIV, pdiv) | + FIELD_PREP(SDHCI_GLI_9750_PLL_DIR, dir); + sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); + gl9750_wt_off(host); + + /* wait for pll stable */ + mdelay(1); +} + +static void gl9750_set_ssc(struct sdhci_host *host, u8 enable, u8 step, u16 ppm) +{ + u32 pll; + u32 ssc; + + gl9750_wt_on(host); + pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); + ssc = sdhci_readl(host, SDHCI_GLI_9750_PLLSSC); + pll &= ~(SDHCI_GLI_9750_PLLSSC_STEP | + SDHCI_GLI_9750_PLLSSC_EN); + ssc &= ~SDHCI_GLI_9750_PLLSSC_PPM; + pll |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_STEP, step) | + FIELD_PREP(SDHCI_GLI_9750_PLLSSC_EN, enable); + ssc |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_PPM, ppm); + sdhci_writel(host, ssc, SDHCI_GLI_9750_PLLSSC); + sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); + gl9750_wt_off(host); +} + +static void gl9750_set_ssc_pll_205mhz(struct sdhci_host *host) +{ + /* set pll to 205MHz and enable ssc */ + gl9750_set_ssc(host, 0x1, 0x1F, 0xFFE7); + gl9750_set_pll(host, 0x1, 0x246, 0x0); +} + +static void sdhci_gl9750_set_clock(struct sdhci_host *host, unsigned int clock) +{ + struct mmc_ios *ios = &host->mmc->ios; + u16 clk; + + host->mmc->actual_clock = 0; + + gl9750_disable_ssc_pll(host); + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + + if (clock == 0) + return; + + clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); + if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) { + host->mmc->actual_clock = 205000000; + gl9750_set_ssc_pll_205mhz(host); + } + + sdhci_enable_clk(host, clk); +} + +static void gli_pcie_enable_msi(struct sdhci_pci_slot *slot) +{ + int ret; + + ret = pci_alloc_irq_vectors(slot->chip->pdev, 1, 1, + PCI_IRQ_MSI | PCI_IRQ_MSIX); + if (ret < 0) { + pr_warn("%s: enable PCI MSI failed, error=%d\n", + mmc_hostname(slot->host->mmc), ret); + return; + } + + slot->host->irq = pci_irq_vector(slot->chip->pdev, 0); +} + +static inline void gl9755_wt_on(struct pci_dev *pdev) +{ + u32 wt_value; + u32 wt_enable; + + pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value); + wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value); + + if (wt_enable == GLI_9755_WT_EN_ON) + return; + + wt_value &= ~PCI_GLI_9755_WT_EN; + wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_ON); + + pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value); +} + +static inline void gl9755_wt_off(struct pci_dev *pdev) +{ + u32 wt_value; + u32 wt_enable; + + pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value); + wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value); + + if (wt_enable == GLI_9755_WT_EN_OFF) + return; + + wt_value &= ~PCI_GLI_9755_WT_EN; + wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_OFF); + + pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value); +} + +static void gl9755_disable_ssc_pll(struct pci_dev *pdev) +{ + u32 pll; + + gl9755_wt_on(pdev); + pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); + pll &= ~(PCI_GLI_9755_PLL_DIR | PCI_GLI_9755_PLLSSC_EN); + pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); + gl9755_wt_off(pdev); +} + +static void gl9755_set_pll(struct pci_dev *pdev, u8 dir, u16 ldiv, u8 pdiv) +{ + u32 pll; + + gl9755_wt_on(pdev); + pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); + pll &= ~(PCI_GLI_9755_PLL_LDIV | + PCI_GLI_9755_PLL_PDIV | + PCI_GLI_9755_PLL_DIR); + pll |= FIELD_PREP(PCI_GLI_9755_PLL_LDIV, ldiv) | + FIELD_PREP(PCI_GLI_9755_PLL_PDIV, pdiv) | + FIELD_PREP(PCI_GLI_9755_PLL_DIR, dir); + pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); + gl9755_wt_off(pdev); + + /* wait for pll stable */ + mdelay(1); +} + +static void gl9755_set_ssc(struct pci_dev *pdev, u8 enable, u8 step, u16 ppm) +{ + u32 pll; + u32 ssc; + + gl9755_wt_on(pdev); + pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); + pci_read_config_dword(pdev, PCI_GLI_9755_PLLSSC, &ssc); + pll &= ~(PCI_GLI_9755_PLLSSC_STEP | + PCI_GLI_9755_PLLSSC_EN); + ssc &= ~PCI_GLI_9755_PLLSSC_PPM; + pll |= FIELD_PREP(PCI_GLI_9755_PLLSSC_STEP, step) | + FIELD_PREP(PCI_GLI_9755_PLLSSC_EN, enable); + ssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_PPM, ppm); + pci_write_config_dword(pdev, PCI_GLI_9755_PLLSSC, ssc); + pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); + gl9755_wt_off(pdev); +} + +static void gl9755_set_ssc_pll_205mhz(struct pci_dev *pdev) +{ + /* set pll to 205MHz and enable ssc */ + gl9755_set_ssc(pdev, 0x1, 0x1F, 0xFFE7); + gl9755_set_pll(pdev, 0x1, 0x246, 0x0); +} + +static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock) +{ + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct mmc_ios *ios = &host->mmc->ios; + struct pci_dev *pdev; + u16 clk; + + pdev = slot->chip->pdev; + host->mmc->actual_clock = 0; + + gl9755_disable_ssc_pll(pdev); + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + + if (clock == 0) + return; + + clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); + if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) { + host->mmc->actual_clock = 205000000; + gl9755_set_ssc_pll_205mhz(pdev); + } + + sdhci_enable_clk(host, clk); +} + +static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot) +{ + struct sdhci_host *host = slot->host; + + gli_pcie_enable_msi(slot); + slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO; + sdhci_enable_v4_mode(host); + + return 0; +} + +static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot) +{ + struct sdhci_host *host = slot->host; + + gli_pcie_enable_msi(slot); + slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO; + sdhci_enable_v4_mode(host); + + return 0; +} + +static void sdhci_gli_voltage_switch(struct sdhci_host *host) +{ + /* + * According to Section 3.6.1 signal voltage switch procedure in + * SD Host Controller Simplified Spec. 4.20, steps 6~8 are as + * follows: + * (6) Set 1.8V Signal Enable in the Host Control 2 register. + * (7) Wait 5ms. 1.8V voltage regulator shall be stable within this + * period. + * (8) If 1.8V Signal Enable is cleared by Host Controller, go to + * step (12). + * + * Wait 5ms after set 1.8V signal enable in Host Control 2 register + * to ensure 1.8V signal enable bit is set by GL9750/GL9755. + * + * ...however, the controller in the NUC10i3FNK4 (a 9755) requires + * slightly longer than 5ms before the control register reports that + * 1.8V is ready, and far longer still before the card will actually + * work reliably. + */ + usleep_range(100000, 110000); +} + +static void sdhci_gl9750_reset(struct sdhci_host *host, u8 mask) +{ + sdhci_reset(host, mask); + gli_set_9750(host); +} + +static u32 sdhci_gl9750_readl(struct sdhci_host *host, int reg) +{ + u32 value; + + value = readl(host->ioaddr + reg); + if (unlikely(reg == SDHCI_MAX_CURRENT && !(value & 0xff))) + value |= 0xc8; + + return value; +} + +#ifdef CONFIG_PM_SLEEP +static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip) +{ + struct sdhci_pci_slot *slot = chip->slots[0]; + + pci_free_irq_vectors(slot->chip->pdev); + gli_pcie_enable_msi(slot); + + return sdhci_pci_resume_host(chip); +} + +static int sdhci_cqhci_gli_resume(struct sdhci_pci_chip *chip) +{ + struct sdhci_pci_slot *slot = chip->slots[0]; + int ret; + + ret = sdhci_pci_gli_resume(chip); + if (ret) + return ret; + + return cqhci_resume(slot->host->mmc); +} + +static int sdhci_cqhci_gli_suspend(struct sdhci_pci_chip *chip) +{ + struct sdhci_pci_slot *slot = chip->slots[0]; + int ret; + + ret = cqhci_suspend(slot->host->mmc); + if (ret) + return ret; + + return sdhci_suspend_host(slot->host); +} +#endif + +static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + u32 val; + + val = sdhci_readl(host, SDHCI_GLI_9763E_HS400_ES_REG); + if (ios->enhanced_strobe) + val |= SDHCI_GLI_9763E_HS400_ES_BIT; + else + val &= ~SDHCI_GLI_9763E_HS400_ES_BIT; + + sdhci_writel(host, val, SDHCI_GLI_9763E_HS400_ES_REG); +} + +static void sdhci_set_gl9763e_signaling(struct sdhci_host *host, + unsigned int timing) +{ + u16 ctrl_2; + + ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; + if (timing == MMC_TIMING_MMC_HS200) + ctrl_2 |= SDHCI_CTRL_UHS_SDR104; + else if (timing == MMC_TIMING_MMC_HS) + ctrl_2 |= SDHCI_CTRL_UHS_SDR25; + else if (timing == MMC_TIMING_MMC_DDR52) + ctrl_2 |= SDHCI_CTRL_UHS_DDR50; + else if (timing == MMC_TIMING_MMC_HS400) + ctrl_2 |= SDHCI_GLI_9763E_CTRL_HS400; + + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); +} + +static void sdhci_gl9763e_dumpregs(struct mmc_host *mmc) +{ + sdhci_dumpregs(mmc_priv(mmc)); +} + +static void sdhci_gl9763e_cqe_pre_enable(struct mmc_host *mmc) +{ + struct cqhci_host *cq_host = mmc->cqe_private; + u32 value; + + value = cqhci_readl(cq_host, CQHCI_CFG); + value |= CQHCI_ENABLE; + cqhci_writel(cq_host, value, CQHCI_CFG); +} + +static void sdhci_gl9763e_cqe_enable(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + + sdhci_writew(host, GLI_9763E_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE); + sdhci_cqe_enable(mmc); +} + +static u32 sdhci_gl9763e_cqhci_irq(struct sdhci_host *host, u32 intmask) +{ + int cmd_error = 0; + int data_error = 0; + + if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) + return intmask; + + cqhci_irq(host->mmc, intmask, cmd_error, data_error); + + return 0; +} + +static void sdhci_gl9763e_cqe_post_disable(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct cqhci_host *cq_host = mmc->cqe_private; + u32 value; + + value = cqhci_readl(cq_host, CQHCI_CFG); + value &= ~CQHCI_ENABLE; + cqhci_writel(cq_host, value, CQHCI_CFG); + sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE); +} + +static const struct cqhci_host_ops sdhci_gl9763e_cqhci_ops = { + .enable = sdhci_gl9763e_cqe_enable, + .disable = sdhci_cqe_disable, + .dumpregs = sdhci_gl9763e_dumpregs, + .pre_enable = sdhci_gl9763e_cqe_pre_enable, + .post_disable = sdhci_gl9763e_cqe_post_disable, +}; + +static int gl9763e_add_host(struct sdhci_pci_slot *slot) +{ + struct device *dev = &slot->chip->pdev->dev; + struct sdhci_host *host = slot->host; + struct cqhci_host *cq_host; + bool dma64; + int ret; + + ret = sdhci_setup_host(host); + if (ret) + return ret; + + cq_host = devm_kzalloc(dev, sizeof(*cq_host), GFP_KERNEL); + if (!cq_host) { + ret = -ENOMEM; + goto cleanup; + } + + cq_host->mmio = host->ioaddr + SDHCI_GLI_9763E_CQE_BASE_ADDR; + cq_host->ops = &sdhci_gl9763e_cqhci_ops; + + dma64 = host->flags & SDHCI_USE_64_BIT_DMA; + if (dma64) + cq_host->caps |= CQHCI_TASK_DESC_SZ_128; + + ret = cqhci_init(cq_host, host->mmc, dma64); + if (ret) + goto cleanup; + + ret = __sdhci_add_host(host); + if (ret) + goto cleanup; + + return 0; + +cleanup: + sdhci_cleanup_host(host); + return ret; +} + +static void sdhci_gl9763e_reset(struct sdhci_host *host, u8 mask) +{ + if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) && + host->mmc->cqe_private) + cqhci_deactivate(host->mmc); + sdhci_reset(host, mask); +} + +static void gli_set_gl9763e(struct sdhci_pci_slot *slot) +{ + struct pci_dev *pdev = slot->chip->pdev; + u32 value; + + pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); + value &= ~GLI_9763E_VHS_REV; + value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_W); + pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); + + pci_read_config_dword(pdev, PCIE_GLI_9763E_SCR, &value); + value |= GLI_9763E_SCR_AXI_REQ; + pci_write_config_dword(pdev, PCIE_GLI_9763E_SCR, value); + + pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); + value &= ~GLI_9763E_VHS_REV; + value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R); + pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); +} + +static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot) +{ + struct pci_dev *pdev = slot->chip->pdev; + struct sdhci_host *host = slot->host; + u32 value; + + host->mmc->caps |= MMC_CAP_8_BIT_DATA | + MMC_CAP_1_8V_DDR | + MMC_CAP_NONREMOVABLE; + host->mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR | + MMC_CAP2_HS400_1_8V | + MMC_CAP2_HS400_ES | + MMC_CAP2_NO_SDIO | + MMC_CAP2_NO_SD; + + pci_read_config_dword(pdev, PCIE_GLI_9763E_MB, &value); + if (!(value & GLI_9763E_MB_CMDQ_OFF)) + host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; + + gli_pcie_enable_msi(slot); + host->mmc_host_ops.hs400_enhanced_strobe = + gl9763e_hs400_enhanced_strobe; + gli_set_gl9763e(slot); + sdhci_enable_v4_mode(host); + + return 0; +} + +static const struct sdhci_ops sdhci_gl9755_ops = { + .set_clock = sdhci_gl9755_set_clock, + .enable_dma = sdhci_pci_enable_dma, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, + .voltage_switch = sdhci_gli_voltage_switch, +}; + +const struct sdhci_pci_fixes sdhci_gl9755 = { + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, + .probe_slot = gli_probe_slot_gl9755, + .ops = &sdhci_gl9755_ops, +#ifdef CONFIG_PM_SLEEP + .resume = sdhci_pci_gli_resume, +#endif +}; + +static const struct sdhci_ops sdhci_gl9750_ops = { + .read_l = sdhci_gl9750_readl, + .set_clock = sdhci_gl9750_set_clock, + .enable_dma = sdhci_pci_enable_dma, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_gl9750_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, + .voltage_switch = sdhci_gli_voltage_switch, + .platform_execute_tuning = gl9750_execute_tuning, +}; + +const struct sdhci_pci_fixes sdhci_gl9750 = { + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, + .probe_slot = gli_probe_slot_gl9750, + .ops = &sdhci_gl9750_ops, +#ifdef CONFIG_PM_SLEEP + .resume = sdhci_pci_gli_resume, +#endif +}; + +static const struct sdhci_ops sdhci_gl9763e_ops = { + .set_clock = sdhci_set_clock, + .enable_dma = sdhci_pci_enable_dma, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_gl9763e_reset, + .set_uhs_signaling = sdhci_set_gl9763e_signaling, + .voltage_switch = sdhci_gli_voltage_switch, + .irq = sdhci_gl9763e_cqhci_irq, +}; + +const struct sdhci_pci_fixes sdhci_gl9763e = { + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .probe_slot = gli_probe_slot_gl9763e, + .ops = &sdhci_gl9763e_ops, +#ifdef CONFIG_PM_SLEEP + .resume = sdhci_cqhci_gli_resume, + .suspend = sdhci_cqhci_gli_suspend, +#endif + .add_host = gl9763e_add_host, +}; diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-o2micro.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-o2micro.c new file mode 100644 index 000000000000..94e3f72f6405 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-o2micro.c @@ -0,0 +1,862 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 BayHub Technology Ltd. + * + * Authors: Peter Guo + * Adam Lee + * Ernest Zhang + */ + +#include +#include +#include +#include +#include + +#include "sdhci.h" +#include "sdhci-pci.h" + +/* + * O2Micro device registers + */ + +#define O2_SD_MISC_REG5 0x64 +#define O2_SD_LD0_CTRL 0x68 +#define O2_SD_DEV_CTRL 0x88 +#define O2_SD_LOCK_WP 0xD3 +#define O2_SD_TEST_REG 0xD4 +#define O2_SD_FUNC_REG0 0xDC +#define O2_SD_MULTI_VCC3V 0xEE +#define O2_SD_CLKREQ 0xEC +#define O2_SD_CAPS 0xE0 +#define O2_SD_ADMA1 0xE2 +#define O2_SD_ADMA2 0xE7 +#define O2_SD_INF_MOD 0xF1 +#define O2_SD_MISC_CTRL4 0xFC +#define O2_SD_MISC_CTRL 0x1C0 +#define O2_SD_PWR_FORCE_L0 0x0002 +#define O2_SD_TUNING_CTRL 0x300 +#define O2_SD_PLL_SETTING 0x304 +#define O2_SD_MISC_SETTING 0x308 +#define O2_SD_CLK_SETTING 0x328 +#define O2_SD_CAP_REG2 0x330 +#define O2_SD_CAP_REG0 0x334 +#define O2_SD_UHS1_CAP_SETTING 0x33C +#define O2_SD_DELAY_CTRL 0x350 +#define O2_SD_UHS2_L1_CTRL 0x35C +#define O2_SD_FUNC_REG3 0x3E0 +#define O2_SD_FUNC_REG4 0x3E4 +#define O2_SD_LED_ENABLE BIT(6) +#define O2_SD_FREG0_LEDOFF BIT(13) +#define O2_SD_FREG4_ENABLE_CLK_SET BIT(22) + +#define O2_SD_VENDOR_SETTING 0x110 +#define O2_SD_VENDOR_SETTING2 0x1C8 +#define O2_SD_HW_TUNING_DISABLE BIT(4) + +#define O2_PLL_DLL_WDT_CONTROL1 0x1CC +#define O2_PLL_FORCE_ACTIVE BIT(18) +#define O2_PLL_LOCK_STATUS BIT(14) +#define O2_PLL_SOFT_RESET BIT(12) +#define O2_DLL_LOCK_STATUS BIT(11) + +#define O2_SD_DETECT_SETTING 0x324 + +static const u32 dmdn_table[] = {0x2B1C0000, + 0x2C1A0000, 0x371B0000, 0x35100000}; +#define DMDN_SZ ARRAY_SIZE(dmdn_table) + +struct o2_host { + u8 dll_adjust_count; +}; + +static void sdhci_o2_wait_card_detect_stable(struct sdhci_host *host) +{ + ktime_t timeout; + u32 scratch32; + + /* Wait max 50 ms */ + timeout = ktime_add_ms(ktime_get(), 50); + while (1) { + bool timedout = ktime_after(ktime_get(), timeout); + + scratch32 = sdhci_readl(host, SDHCI_PRESENT_STATE); + if ((scratch32 & SDHCI_CARD_PRESENT) >> SDHCI_CARD_PRES_SHIFT + == (scratch32 & SDHCI_CD_LVL) >> SDHCI_CD_LVL_SHIFT) + break; + + if (timedout) { + pr_err("%s: Card Detect debounce never finished.\n", + mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + return; + } + udelay(10); + } +} + +static void sdhci_o2_enable_internal_clock(struct sdhci_host *host) +{ + ktime_t timeout; + u16 scratch; + u32 scratch32; + + /* PLL software reset */ + scratch32 = sdhci_readl(host, O2_PLL_DLL_WDT_CONTROL1); + scratch32 |= O2_PLL_SOFT_RESET; + sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); + udelay(1); + scratch32 &= ~(O2_PLL_SOFT_RESET); + sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); + + /* PLL force active */ + scratch32 |= O2_PLL_FORCE_ACTIVE; + sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); + + /* Wait max 20 ms */ + timeout = ktime_add_ms(ktime_get(), 20); + while (1) { + bool timedout = ktime_after(ktime_get(), timeout); + + scratch = sdhci_readw(host, O2_PLL_DLL_WDT_CONTROL1); + if (scratch & O2_PLL_LOCK_STATUS) + break; + if (timedout) { + pr_err("%s: Internal clock never stabilised.\n", + mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + goto out; + } + udelay(10); + } + + /* Wait for card detect finish */ + udelay(1); + sdhci_o2_wait_card_detect_stable(host); + +out: + /* Cancel PLL force active */ + scratch32 = sdhci_readl(host, O2_PLL_DLL_WDT_CONTROL1); + scratch32 &= ~O2_PLL_FORCE_ACTIVE; + sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); +} + +static int sdhci_o2_get_cd(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + + if (!(sdhci_readw(host, O2_PLL_DLL_WDT_CONTROL1) & O2_PLL_LOCK_STATUS)) + sdhci_o2_enable_internal_clock(host); + + return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); +} + +static void o2_pci_set_baseclk(struct sdhci_pci_chip *chip, u32 value) +{ + u32 scratch_32; + + pci_read_config_dword(chip->pdev, + O2_SD_PLL_SETTING, &scratch_32); + + scratch_32 &= 0x0000FFFF; + scratch_32 |= value; + + pci_write_config_dword(chip->pdev, + O2_SD_PLL_SETTING, scratch_32); +} + +static u32 sdhci_o2_pll_dll_wdt_control(struct sdhci_host *host) +{ + return sdhci_readl(host, O2_PLL_DLL_WDT_CONTROL1); +} + +/* + * This function is used to detect dll lock status. + * Since the dll lock status bit will toggle randomly + * with very short interval which needs to be polled + * as fast as possible. Set sleep_us as 1 microsecond. + */ +static int sdhci_o2_wait_dll_detect_lock(struct sdhci_host *host) +{ + u32 scratch32 = 0; + + return readx_poll_timeout(sdhci_o2_pll_dll_wdt_control, host, + scratch32, !(scratch32 & O2_DLL_LOCK_STATUS), 1, 1000000); +} + +static void sdhci_o2_set_tuning_mode(struct sdhci_host *host) +{ + u16 reg; + + /* enable hardware tuning */ + reg = sdhci_readw(host, O2_SD_VENDOR_SETTING); + reg &= ~O2_SD_HW_TUNING_DISABLE; + sdhci_writew(host, reg, O2_SD_VENDOR_SETTING); +} + +static void __sdhci_o2_execute_tuning(struct sdhci_host *host, u32 opcode) +{ + int i; + + sdhci_send_tuning(host, opcode); + + for (i = 0; i < 150; i++) { + u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + + if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { + if (ctrl & SDHCI_CTRL_TUNED_CLK) { + host->tuning_done = true; + return; + } + pr_warn("%s: HW tuning failed !\n", + mmc_hostname(host->mmc)); + break; + } + + mdelay(1); + } + + pr_info("%s: Tuning failed, falling back to fixed sampling clock\n", + mmc_hostname(host->mmc)); + sdhci_reset_tuning(host); +} + +/* + * This function is used to fix o2 dll shift issue. + * It isn't necessary to detect card present before recovery. + * Firstly, it is used by bht emmc card, which is embedded. + * Second, before call recovery card present will be detected + * outside of the execute tuning function. + */ +static int sdhci_o2_dll_recovery(struct sdhci_host *host) +{ + int ret = 0; + u8 scratch_8 = 0; + u32 scratch_32 = 0; + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct sdhci_pci_chip *chip = slot->chip; + struct o2_host *o2_host = sdhci_pci_priv(slot); + + /* UnLock WP */ + pci_read_config_byte(chip->pdev, + O2_SD_LOCK_WP, &scratch_8); + scratch_8 &= 0x7f; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8); + while (o2_host->dll_adjust_count < DMDN_SZ && !ret) { + /* Disable clock */ + sdhci_writeb(host, 0, SDHCI_CLOCK_CONTROL); + + /* PLL software reset */ + scratch_32 = sdhci_readl(host, O2_PLL_DLL_WDT_CONTROL1); + scratch_32 |= O2_PLL_SOFT_RESET; + sdhci_writel(host, scratch_32, O2_PLL_DLL_WDT_CONTROL1); + + pci_read_config_dword(chip->pdev, + O2_SD_FUNC_REG4, + &scratch_32); + /* Enable Base Clk setting change */ + scratch_32 |= O2_SD_FREG4_ENABLE_CLK_SET; + pci_write_config_dword(chip->pdev, O2_SD_FUNC_REG4, scratch_32); + o2_pci_set_baseclk(chip, dmdn_table[o2_host->dll_adjust_count]); + + /* Enable internal clock */ + scratch_8 = SDHCI_CLOCK_INT_EN; + sdhci_writeb(host, scratch_8, SDHCI_CLOCK_CONTROL); + + if (sdhci_o2_get_cd(host->mmc)) { + /* + * need wait at least 5ms for dll status stable, + * after enable internal clock + */ + usleep_range(5000, 6000); + if (sdhci_o2_wait_dll_detect_lock(host)) { + scratch_8 |= SDHCI_CLOCK_CARD_EN; + sdhci_writeb(host, scratch_8, + SDHCI_CLOCK_CONTROL); + ret = 1; + } else { + pr_warn("%s: DLL unlocked when dll_adjust_count is %d.\n", + mmc_hostname(host->mmc), + o2_host->dll_adjust_count); + } + } else { + pr_err("%s: card present detect failed.\n", + mmc_hostname(host->mmc)); + break; + } + + o2_host->dll_adjust_count++; + } + if (!ret && o2_host->dll_adjust_count == DMDN_SZ) + pr_err("%s: DLL adjust over max times\n", + mmc_hostname(host->mmc)); + /* Lock WP */ + pci_read_config_byte(chip->pdev, + O2_SD_LOCK_WP, &scratch_8); + scratch_8 |= 0x80; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8); + return ret; +} + +static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct sdhci_host *host = mmc_priv(mmc); + int current_bus_width = 0; + u32 scratch32 = 0; + u16 scratch = 0; + + /* + * This handler only implements the eMMC tuning that is specific to + * this controller. Fall back to the standard method for other TIMING. + */ + if ((host->timing != MMC_TIMING_MMC_HS200) && + (host->timing != MMC_TIMING_UHS_SDR104)) + return sdhci_execute_tuning(mmc, opcode); + + if (WARN_ON((opcode != MMC_SEND_TUNING_BLOCK_HS200) && + (opcode != MMC_SEND_TUNING_BLOCK))) + return -EINVAL; + + /* Force power mode enter L0 */ + scratch = sdhci_readw(host, O2_SD_MISC_CTRL); + scratch |= O2_SD_PWR_FORCE_L0; + sdhci_writew(host, scratch, O2_SD_MISC_CTRL); + + /* wait DLL lock, timeout value 5ms */ + if (readx_poll_timeout(sdhci_o2_pll_dll_wdt_control, host, + scratch32, (scratch32 & O2_DLL_LOCK_STATUS), 1, 5000)) + pr_warn("%s: DLL can't lock in 5ms after force L0 during tuning.\n", + mmc_hostname(host->mmc)); + /* + * Judge the tuning reason, whether caused by dll shift + * If cause by dll shift, should call sdhci_o2_dll_recovery + */ + if (!sdhci_o2_wait_dll_detect_lock(host)) + if (!sdhci_o2_dll_recovery(host)) { + pr_err("%s: o2 dll recovery failed\n", + mmc_hostname(host->mmc)); + return -EINVAL; + } + /* + * o2 sdhci host didn't support 8bit emmc tuning + */ + if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) { + current_bus_width = mmc->ios.bus_width; + mmc->ios.bus_width = MMC_BUS_WIDTH_4; + sdhci_set_bus_width(host, MMC_BUS_WIDTH_4); + } + + sdhci_o2_set_tuning_mode(host); + + sdhci_start_tuning(host); + + __sdhci_o2_execute_tuning(host, opcode); + + sdhci_end_tuning(host); + + if (current_bus_width == MMC_BUS_WIDTH_8) { + mmc->ios.bus_width = MMC_BUS_WIDTH_8; + sdhci_set_bus_width(host, current_bus_width); + } + + /* Cancel force power mode enter L0 */ + scratch = sdhci_readw(host, O2_SD_MISC_CTRL); + scratch &= ~(O2_SD_PWR_FORCE_L0); + sdhci_writew(host, scratch, O2_SD_MISC_CTRL); + + sdhci_reset(host, SDHCI_RESET_CMD); + sdhci_reset(host, SDHCI_RESET_DATA); + + host->flags &= ~SDHCI_HS400_TUNING; + return 0; +} + +static void o2_pci_led_enable(struct sdhci_pci_chip *chip) +{ + int ret; + u32 scratch_32; + + /* Set led of SD host function enable */ + ret = pci_read_config_dword(chip->pdev, + O2_SD_FUNC_REG0, &scratch_32); + if (ret) + return; + + scratch_32 &= ~O2_SD_FREG0_LEDOFF; + pci_write_config_dword(chip->pdev, + O2_SD_FUNC_REG0, scratch_32); + + ret = pci_read_config_dword(chip->pdev, + O2_SD_TEST_REG, &scratch_32); + if (ret) + return; + + scratch_32 |= O2_SD_LED_ENABLE; + pci_write_config_dword(chip->pdev, + O2_SD_TEST_REG, scratch_32); +} + +static void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip) +{ + u32 scratch_32; + int ret; + /* Improve write performance for SD3.0 */ + ret = pci_read_config_dword(chip->pdev, O2_SD_DEV_CTRL, &scratch_32); + if (ret) + return; + scratch_32 &= ~((1 << 12) | (1 << 13) | (1 << 14)); + pci_write_config_dword(chip->pdev, O2_SD_DEV_CTRL, scratch_32); + + /* Enable Link abnormal reset generating Reset */ + ret = pci_read_config_dword(chip->pdev, O2_SD_MISC_REG5, &scratch_32); + if (ret) + return; + scratch_32 &= ~((1 << 19) | (1 << 11)); + scratch_32 |= (1 << 10); + pci_write_config_dword(chip->pdev, O2_SD_MISC_REG5, scratch_32); + + /* set card power over current protection */ + ret = pci_read_config_dword(chip->pdev, O2_SD_TEST_REG, &scratch_32); + if (ret) + return; + scratch_32 |= (1 << 4); + pci_write_config_dword(chip->pdev, O2_SD_TEST_REG, scratch_32); + + /* adjust the output delay for SD mode */ + pci_write_config_dword(chip->pdev, O2_SD_DELAY_CTRL, 0x00002492); + + /* Set the output voltage setting of Aux 1.2v LDO */ + ret = pci_read_config_dword(chip->pdev, O2_SD_LD0_CTRL, &scratch_32); + if (ret) + return; + scratch_32 &= ~(3 << 12); + pci_write_config_dword(chip->pdev, O2_SD_LD0_CTRL, scratch_32); + + /* Set Max power supply capability of SD host */ + ret = pci_read_config_dword(chip->pdev, O2_SD_CAP_REG0, &scratch_32); + if (ret) + return; + scratch_32 &= ~(0x01FE); + scratch_32 |= 0x00CC; + pci_write_config_dword(chip->pdev, O2_SD_CAP_REG0, scratch_32); + /* Set DLL Tuning Window */ + ret = pci_read_config_dword(chip->pdev, + O2_SD_TUNING_CTRL, &scratch_32); + if (ret) + return; + scratch_32 &= ~(0x000000FF); + scratch_32 |= 0x00000066; + pci_write_config_dword(chip->pdev, O2_SD_TUNING_CTRL, scratch_32); + + /* Set UHS2 T_EIDLE */ + ret = pci_read_config_dword(chip->pdev, + O2_SD_UHS2_L1_CTRL, &scratch_32); + if (ret) + return; + scratch_32 &= ~(0x000000FC); + scratch_32 |= 0x00000084; + pci_write_config_dword(chip->pdev, O2_SD_UHS2_L1_CTRL, scratch_32); + + /* Set UHS2 Termination */ + ret = pci_read_config_dword(chip->pdev, O2_SD_FUNC_REG3, &scratch_32); + if (ret) + return; + scratch_32 &= ~((1 << 21) | (1 << 30)); + + pci_write_config_dword(chip->pdev, O2_SD_FUNC_REG3, scratch_32); + + /* Set L1 Entrance Timer */ + ret = pci_read_config_dword(chip->pdev, O2_SD_CAPS, &scratch_32); + if (ret) + return; + scratch_32 &= ~(0xf0000000); + scratch_32 |= 0x30000000; + pci_write_config_dword(chip->pdev, O2_SD_CAPS, scratch_32); + + ret = pci_read_config_dword(chip->pdev, + O2_SD_MISC_CTRL4, &scratch_32); + if (ret) + return; + scratch_32 &= ~(0x000f0000); + scratch_32 |= 0x00080000; + pci_write_config_dword(chip->pdev, O2_SD_MISC_CTRL4, scratch_32); +} + +static void sdhci_pci_o2_enable_msi(struct sdhci_pci_chip *chip, + struct sdhci_host *host) +{ + int ret; + + ret = pci_find_capability(chip->pdev, PCI_CAP_ID_MSI); + if (!ret) { + pr_info("%s: unsupport msi, use INTx irq\n", + mmc_hostname(host->mmc)); + return; + } + + ret = pci_alloc_irq_vectors(chip->pdev, 1, 1, + PCI_IRQ_MSI | PCI_IRQ_MSIX); + if (ret < 0) { + pr_err("%s: enable PCI MSI failed, err=%d\n", + mmc_hostname(host->mmc), ret); + return; + } + + host->irq = pci_irq_vector(chip->pdev, 0); +} + +static void sdhci_o2_enable_clk(struct sdhci_host *host, u16 clk) +{ + /* Enable internal clock */ + clk |= SDHCI_CLOCK_INT_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + sdhci_o2_enable_internal_clock(host); + if (sdhci_o2_get_cd(host->mmc)) { + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + } +} + +static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock) +{ + u16 clk; + u8 scratch; + u32 scratch_32; + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct sdhci_pci_chip *chip = slot->chip; + + host->mmc->actual_clock = 0; + + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + + if (clock == 0) + return; + + if ((host->timing == MMC_TIMING_UHS_SDR104) && (clock == 200000000)) { + pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); + + scratch &= 0x7f; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + + pci_read_config_dword(chip->pdev, O2_SD_PLL_SETTING, &scratch_32); + + if ((scratch_32 & 0xFFFF0000) != 0x2c280000) + o2_pci_set_baseclk(chip, 0x2c280000); + + pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); + + scratch |= 0x80; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + } + + clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); + sdhci_o2_enable_clk(host, clk); +} + +static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) +{ + struct sdhci_pci_chip *chip; + struct sdhci_host *host; + struct o2_host *o2_host = sdhci_pci_priv(slot); + u32 reg, caps; + int ret; + + chip = slot->chip; + host = slot->host; + + o2_host->dll_adjust_count = 0; + caps = sdhci_readl(host, SDHCI_CAPABILITIES); + + /* + * mmc_select_bus_width() will test the bus to determine the actual bus + * width. + */ + if (caps & SDHCI_CAN_DO_8BIT) + host->mmc->caps |= MMC_CAP_8_BIT_DATA; + + switch (chip->pdev->device) { + case PCI_DEVICE_ID_O2_SDS0: + case PCI_DEVICE_ID_O2_SEABIRD0: + case PCI_DEVICE_ID_O2_SEABIRD1: + case PCI_DEVICE_ID_O2_SDS1: + case PCI_DEVICE_ID_O2_FUJIN2: + reg = sdhci_readl(host, O2_SD_VENDOR_SETTING); + if (reg & 0x1) + host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; + + sdhci_pci_o2_enable_msi(chip, host); + + if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD0) { + ret = pci_read_config_dword(chip->pdev, + O2_SD_MISC_SETTING, ®); + if (ret) + return -EIO; + if (reg & (1 << 4)) { + pr_info("%s: emmc 1.8v flag is set, force 1.8v signaling voltage\n", + mmc_hostname(host->mmc)); + host->flags &= ~SDHCI_SIGNALING_330; + host->flags |= SDHCI_SIGNALING_180; + host->mmc->caps2 |= MMC_CAP2_NO_SD; + host->mmc->caps2 |= MMC_CAP2_NO_SDIO; + pci_write_config_dword(chip->pdev, + O2_SD_DETECT_SETTING, 3); + } + + slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd; + } + + if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD1) { + slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd; + host->mmc->caps2 |= MMC_CAP2_NO_SDIO; + host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; + } + + host->mmc_host_ops.execute_tuning = sdhci_o2_execute_tuning; + + if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2) + break; + /* set dll watch dog timer */ + reg = sdhci_readl(host, O2_SD_VENDOR_SETTING2); + reg |= (1 << 12); + sdhci_writel(host, reg, O2_SD_VENDOR_SETTING2); + + break; + default: + break; + } + + return 0; +} + +static int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip) +{ + int ret; + u8 scratch; + u32 scratch_32; + + switch (chip->pdev->device) { + case PCI_DEVICE_ID_O2_8220: + case PCI_DEVICE_ID_O2_8221: + case PCI_DEVICE_ID_O2_8320: + case PCI_DEVICE_ID_O2_8321: + /* This extra setup is required due to broken ADMA. */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_LOCK_WP, &scratch); + if (ret) + return ret; + scratch &= 0x7f; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + + /* Set Multi 3 to VCC3V# */ + pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08); + + /* Disable CLK_REQ# support after media DET */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_CLKREQ, &scratch); + if (ret) + return ret; + scratch |= 0x20; + pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch); + + /* Choose capabilities, enable SDMA. We have to write 0x01 + * to the capabilities register first to unlock it. + */ + ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch); + if (ret) + return ret; + scratch |= 0x01; + pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch); + pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73); + + /* Disable ADMA1/2 */ + pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39); + pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08); + + /* Disable the infinite transfer mode */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_INF_MOD, &scratch); + if (ret) + return ret; + scratch |= 0x08; + pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch); + + /* Lock WP */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_LOCK_WP, &scratch); + if (ret) + return ret; + scratch |= 0x80; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + break; + case PCI_DEVICE_ID_O2_SDS0: + case PCI_DEVICE_ID_O2_SDS1: + case PCI_DEVICE_ID_O2_FUJIN2: + /* UnLock WP */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_LOCK_WP, &scratch); + if (ret) + return ret; + + scratch &= 0x7f; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + + /* DevId=8520 subId= 0x11 or 0x12 Type Chip support */ + if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2) { + ret = pci_read_config_dword(chip->pdev, + O2_SD_FUNC_REG0, + &scratch_32); + scratch_32 = ((scratch_32 & 0xFF000000) >> 24); + + /* Check Whether subId is 0x11 or 0x12 */ + if ((scratch_32 == 0x11) || (scratch_32 == 0x12)) { + scratch_32 = 0x25100000; + + o2_pci_set_baseclk(chip, scratch_32); + ret = pci_read_config_dword(chip->pdev, + O2_SD_FUNC_REG4, + &scratch_32); + + /* Enable Base Clk setting change */ + scratch_32 |= O2_SD_FREG4_ENABLE_CLK_SET; + pci_write_config_dword(chip->pdev, + O2_SD_FUNC_REG4, + scratch_32); + + /* Set Tuning Window to 4 */ + pci_write_config_byte(chip->pdev, + O2_SD_TUNING_CTRL, 0x44); + + break; + } + } + + /* Enable 8520 led function */ + o2_pci_led_enable(chip); + + /* Set timeout CLK */ + ret = pci_read_config_dword(chip->pdev, + O2_SD_CLK_SETTING, &scratch_32); + if (ret) + return ret; + + scratch_32 &= ~(0xFF00); + scratch_32 |= 0x07E0C800; + pci_write_config_dword(chip->pdev, + O2_SD_CLK_SETTING, scratch_32); + + ret = pci_read_config_dword(chip->pdev, + O2_SD_CLKREQ, &scratch_32); + if (ret) + return ret; + scratch_32 |= 0x3; + pci_write_config_dword(chip->pdev, O2_SD_CLKREQ, scratch_32); + + ret = pci_read_config_dword(chip->pdev, + O2_SD_PLL_SETTING, &scratch_32); + if (ret) + return ret; + + scratch_32 &= ~(0x1F3F070E); + scratch_32 |= 0x18270106; + pci_write_config_dword(chip->pdev, + O2_SD_PLL_SETTING, scratch_32); + + /* Disable UHS1 funciton */ + ret = pci_read_config_dword(chip->pdev, + O2_SD_CAP_REG2, &scratch_32); + if (ret) + return ret; + scratch_32 &= ~(0xE0); + pci_write_config_dword(chip->pdev, + O2_SD_CAP_REG2, scratch_32); + + if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2) + sdhci_pci_o2_fujin2_pci_init(chip); + + /* Lock WP */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_LOCK_WP, &scratch); + if (ret) + return ret; + scratch |= 0x80; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + break; + case PCI_DEVICE_ID_O2_SEABIRD0: + case PCI_DEVICE_ID_O2_SEABIRD1: + /* UnLock WP */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_LOCK_WP, &scratch); + if (ret) + return ret; + + scratch &= 0x7f; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + + ret = pci_read_config_dword(chip->pdev, + O2_SD_PLL_SETTING, &scratch_32); + + if ((scratch_32 & 0xff000000) == 0x01000000) { + scratch_32 &= 0x0000FFFF; + scratch_32 |= 0x1F340000; + + pci_write_config_dword(chip->pdev, + O2_SD_PLL_SETTING, scratch_32); + } else { + scratch_32 &= 0x0000FFFF; + scratch_32 |= 0x25100000; + + pci_write_config_dword(chip->pdev, + O2_SD_PLL_SETTING, scratch_32); + + ret = pci_read_config_dword(chip->pdev, + O2_SD_FUNC_REG4, + &scratch_32); + scratch_32 |= (1 << 22); + pci_write_config_dword(chip->pdev, + O2_SD_FUNC_REG4, scratch_32); + } + + /* Set Tuning Windows to 5 */ + pci_write_config_byte(chip->pdev, + O2_SD_TUNING_CTRL, 0x55); + /* Lock WP */ + ret = pci_read_config_byte(chip->pdev, + O2_SD_LOCK_WP, &scratch); + if (ret) + return ret; + scratch |= 0x80; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + break; + } + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip) +{ + sdhci_pci_o2_probe(chip); + return sdhci_pci_resume_host(chip); +} +#endif + +static const struct sdhci_ops sdhci_pci_o2_ops = { + .set_clock = sdhci_pci_o2_set_clock, + .enable_dma = sdhci_pci_enable_dma, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +const struct sdhci_pci_fixes sdhci_o2 = { + .probe = sdhci_pci_o2_probe, + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .quirks2 = SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD, + .probe_slot = sdhci_pci_o2_probe_slot, +#ifdef CONFIG_PM_SLEEP + .resume = sdhci_pci_o2_resume, +#endif + .ops = &sdhci_pci_o2_ops, + .priv_size = sizeof(struct o2_host), +}; diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci.h new file mode 100644 index 000000000000..8f90c4163bb5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci.h @@ -0,0 +1,203 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __SDHCI_PCI_H +#define __SDHCI_PCI_H + +/* + * PCI device IDs, sub IDs + */ + +#define PCI_DEVICE_ID_O2_SDS0 0x8420 +#define PCI_DEVICE_ID_O2_SDS1 0x8421 +#define PCI_DEVICE_ID_O2_FUJIN2 0x8520 +#define PCI_DEVICE_ID_O2_SEABIRD0 0x8620 +#define PCI_DEVICE_ID_O2_SEABIRD1 0x8621 + +#define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809 +#define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a +#define PCI_DEVICE_ID_INTEL_BYT_EMMC 0x0f14 +#define PCI_DEVICE_ID_INTEL_BYT_SDIO 0x0f15 +#define PCI_DEVICE_ID_INTEL_BYT_SD 0x0f16 +#define PCI_DEVICE_ID_INTEL_BYT_EMMC2 0x0f50 +#define PCI_DEVICE_ID_INTEL_BSW_EMMC 0x2294 +#define PCI_DEVICE_ID_INTEL_BSW_SDIO 0x2295 +#define PCI_DEVICE_ID_INTEL_BSW_SD 0x2296 +#define PCI_DEVICE_ID_INTEL_MRFLD_MMC 0x1190 +#define PCI_DEVICE_ID_INTEL_CLV_SDIO0 0x08f9 +#define PCI_DEVICE_ID_INTEL_CLV_SDIO1 0x08fa +#define PCI_DEVICE_ID_INTEL_CLV_SDIO2 0x08fb +#define PCI_DEVICE_ID_INTEL_CLV_EMMC0 0x08e5 +#define PCI_DEVICE_ID_INTEL_CLV_EMMC1 0x08e6 +#define PCI_DEVICE_ID_INTEL_QRK_SD 0x08A7 +#define PCI_DEVICE_ID_INTEL_SPT_EMMC 0x9d2b +#define PCI_DEVICE_ID_INTEL_SPT_SDIO 0x9d2c +#define PCI_DEVICE_ID_INTEL_SPT_SD 0x9d2d +#define PCI_DEVICE_ID_INTEL_DNV_EMMC 0x19db +#define PCI_DEVICE_ID_INTEL_CDF_EMMC 0x18db +#define PCI_DEVICE_ID_INTEL_BXT_SD 0x0aca +#define PCI_DEVICE_ID_INTEL_BXT_EMMC 0x0acc +#define PCI_DEVICE_ID_INTEL_BXT_SDIO 0x0ad0 +#define PCI_DEVICE_ID_INTEL_BXTM_SD 0x1aca +#define PCI_DEVICE_ID_INTEL_BXTM_EMMC 0x1acc +#define PCI_DEVICE_ID_INTEL_BXTM_SDIO 0x1ad0 +#define PCI_DEVICE_ID_INTEL_APL_SD 0x5aca +#define PCI_DEVICE_ID_INTEL_APL_EMMC 0x5acc +#define PCI_DEVICE_ID_INTEL_APL_SDIO 0x5ad0 +#define PCI_DEVICE_ID_INTEL_GLK_SD 0x31ca +#define PCI_DEVICE_ID_INTEL_GLK_EMMC 0x31cc +#define PCI_DEVICE_ID_INTEL_GLK_SDIO 0x31d0 +#define PCI_DEVICE_ID_INTEL_CNP_EMMC 0x9dc4 +#define PCI_DEVICE_ID_INTEL_CNP_SD 0x9df5 +#define PCI_DEVICE_ID_INTEL_CNPH_SD 0xa375 +#define PCI_DEVICE_ID_INTEL_ICP_EMMC 0x34c4 +#define PCI_DEVICE_ID_INTEL_ICP_SD 0x34f8 +#define PCI_DEVICE_ID_INTEL_EHL_EMMC 0x4b47 +#define PCI_DEVICE_ID_INTEL_EHL_SD 0x4b48 +#define PCI_DEVICE_ID_INTEL_CML_EMMC 0x02c4 +#define PCI_DEVICE_ID_INTEL_CML_SD 0x02f5 +#define PCI_DEVICE_ID_INTEL_CMLH_SD 0x06f5 +#define PCI_DEVICE_ID_INTEL_JSL_EMMC 0x4dc4 +#define PCI_DEVICE_ID_INTEL_JSL_SD 0x4df8 +#define PCI_DEVICE_ID_INTEL_LKF_EMMC 0x98c4 +#define PCI_DEVICE_ID_INTEL_LKF_SD 0x98f8 + +#define PCI_DEVICE_ID_SYSKONNECT_8000 0x8000 +#define PCI_DEVICE_ID_VIA_95D0 0x95d0 +#define PCI_DEVICE_ID_REALTEK_5250 0x5250 + +#define PCI_SUBDEVICE_ID_NI_7884 0x7884 +#define PCI_SUBDEVICE_ID_NI_78E3 0x78e3 + +#define PCI_VENDOR_ID_ARASAN 0x16e6 +#define PCI_DEVICE_ID_ARASAN_PHY_EMMC 0x0670 + +#define PCI_DEVICE_ID_SYNOPSYS_DWC_MSHC 0xc202 + +#define PCI_DEVICE_ID_GLI_9755 0x9755 +#define PCI_DEVICE_ID_GLI_9750 0x9750 +#define PCI_DEVICE_ID_GLI_9763E 0xe763 + +/* + * PCI device class and mask + */ + +#define SYSTEM_SDHCI (PCI_CLASS_SYSTEM_SDHCI << 8) +#define PCI_CLASS_MASK 0xFFFF00 + +/* + * Macros for PCI device-description + */ + +#define _PCI_VEND(vend) PCI_VENDOR_ID_##vend +#define _PCI_DEV(vend, dev) PCI_DEVICE_ID_##vend##_##dev +#define _PCI_SUBDEV(subvend, subdev) PCI_SUBDEVICE_ID_##subvend##_##subdev + +#define SDHCI_PCI_DEVICE(vend, dev, cfg) { \ + .vendor = _PCI_VEND(vend), .device = _PCI_DEV(vend, dev), \ + .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \ + .driver_data = (kernel_ulong_t)&(sdhci_##cfg) \ +} + +#define SDHCI_PCI_SUBDEVICE(vend, dev, subvend, subdev, cfg) { \ + .vendor = _PCI_VEND(vend), .device = _PCI_DEV(vend, dev), \ + .subvendor = _PCI_VEND(subvend), \ + .subdevice = _PCI_SUBDEV(subvend, subdev), \ + .driver_data = (kernel_ulong_t)&(sdhci_##cfg) \ +} + +#define SDHCI_PCI_DEVICE_CLASS(vend, cl, cl_msk, cfg) { \ + .vendor = _PCI_VEND(vend), .device = PCI_ANY_ID, \ + .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \ + .class = (cl), .class_mask = (cl_msk), \ + .driver_data = (kernel_ulong_t)&(sdhci_##cfg) \ +} + +/* + * PCI registers + */ + +#define PCI_SDHCI_IFPIO 0x00 +#define PCI_SDHCI_IFDMA 0x01 +#define PCI_SDHCI_IFVENDOR 0x02 + +#define PCI_SLOT_INFO 0x40 /* 8 bits */ +#define PCI_SLOT_INFO_SLOTS(x) ((x >> 4) & 7) +#define PCI_SLOT_INFO_FIRST_BAR_MASK 0x07 + +#define MAX_SLOTS 8 + +struct sdhci_pci_chip; +struct sdhci_pci_slot; + +struct sdhci_pci_fixes { + unsigned int quirks; + unsigned int quirks2; + bool allow_runtime_pm; + bool own_cd_for_runtime_pm; + + int (*probe) (struct sdhci_pci_chip *); + + int (*probe_slot) (struct sdhci_pci_slot *); + int (*add_host) (struct sdhci_pci_slot *); + void (*remove_slot) (struct sdhci_pci_slot *, int); + +#ifdef CONFIG_PM_SLEEP + int (*suspend) (struct sdhci_pci_chip *); + int (*resume) (struct sdhci_pci_chip *); +#endif +#ifdef CONFIG_PM + int (*runtime_suspend) (struct sdhci_pci_chip *); + int (*runtime_resume) (struct sdhci_pci_chip *); +#endif + + const struct sdhci_ops *ops; + size_t priv_size; +}; + +struct sdhci_pci_slot { + struct sdhci_pci_chip *chip; + struct sdhci_host *host; + struct sdhci_pci_data *data; + + int rst_n_gpio; + int cd_gpio; + int cd_irq; + + int cd_idx; + bool cd_override_level; + + void (*hw_reset)(struct sdhci_host *host); + unsigned long private[] ____cacheline_aligned; +}; + +struct sdhci_pci_chip { + struct pci_dev *pdev; + + unsigned int quirks; + unsigned int quirks2; + bool allow_runtime_pm; + bool pm_retune; + bool rpm_retune; + const struct sdhci_pci_fixes *fixes; + + int num_slots; /* Slots on controller */ + struct sdhci_pci_slot *slots[MAX_SLOTS]; /* Pointers to host slots */ +}; + +static inline void *sdhci_pci_priv(struct sdhci_pci_slot *slot) +{ + return (void *)slot->private; +} + +#ifdef CONFIG_PM_SLEEP +int sdhci_pci_resume_host(struct sdhci_pci_chip *chip); +#endif +int sdhci_pci_enable_dma(struct sdhci_host *host); + +extern const struct sdhci_pci_fixes sdhci_arasan; +extern const struct sdhci_pci_fixes sdhci_snps; +extern const struct sdhci_pci_fixes sdhci_o2; +extern const struct sdhci_pci_fixes sdhci_gl9750; +extern const struct sdhci_pci_fixes sdhci_gl9755; +extern const struct sdhci_pci_fixes sdhci_gl9763e; + +#endif /* __SDHCI_PCI_H */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci.h new file mode 100644 index 000000000000..0770c036e2ff --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci.h @@ -0,0 +1,811 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver + * + * Header file for Host Controller registers and I/O accessors. + * + * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. + */ +#ifndef __SDHCI_HW_H +#define __SDHCI_HW_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Controller registers + */ + +#define SDHCI_DMA_ADDRESS 0x00 +#define SDHCI_ARGUMENT2 SDHCI_DMA_ADDRESS +#define SDHCI_32BIT_BLK_CNT SDHCI_DMA_ADDRESS + +#define SDHCI_BLOCK_SIZE 0x04 +#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF)) + +#define SDHCI_BLOCK_COUNT 0x06 + +#define SDHCI_ARGUMENT 0x08 + +#define SDHCI_TRANSFER_MODE 0x0C +#define SDHCI_TRNS_DMA 0x01 +#define SDHCI_TRNS_BLK_CNT_EN 0x02 +#define SDHCI_TRNS_AUTO_CMD12 0x04 +#define SDHCI_TRNS_AUTO_CMD23 0x08 +#define SDHCI_TRNS_AUTO_SEL 0x0C +#define SDHCI_TRNS_READ 0x10 +#define SDHCI_TRNS_MULTI 0x20 + +#define SDHCI_COMMAND 0x0E +#define SDHCI_CMD_RESP_MASK 0x03 +#define SDHCI_CMD_CRC 0x08 +#define SDHCI_CMD_INDEX 0x10 +#define SDHCI_CMD_DATA 0x20 +#define SDHCI_CMD_ABORTCMD 0xC0 + +#define SDHCI_CMD_RESP_NONE 0x00 +#define SDHCI_CMD_RESP_LONG 0x01 +#define SDHCI_CMD_RESP_SHORT 0x02 +#define SDHCI_CMD_RESP_SHORT_BUSY 0x03 + +#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff)) +#define SDHCI_GET_CMD(c) ((c>>8) & 0x3f) + +#define SDHCI_RESPONSE 0x10 + +#define SDHCI_BUFFER 0x20 + +#define SDHCI_PRESENT_STATE 0x24 +#define SDHCI_CMD_INHIBIT 0x00000001 +#define SDHCI_DATA_INHIBIT 0x00000002 +#define SDHCI_DOING_WRITE 0x00000100 +#define SDHCI_DOING_READ 0x00000200 +#define SDHCI_SPACE_AVAILABLE 0x00000400 +#define SDHCI_DATA_AVAILABLE 0x00000800 +#define SDHCI_CARD_PRESENT 0x00010000 +#define SDHCI_CARD_PRES_SHIFT 16 +#define SDHCI_CD_STABLE 0x00020000 +#define SDHCI_CD_LVL 0x00040000 +#define SDHCI_CD_LVL_SHIFT 18 +#define SDHCI_WRITE_PROTECT 0x00080000 +#define SDHCI_DATA_LVL_MASK 0x00F00000 +#define SDHCI_DATA_LVL_SHIFT 20 +#define SDHCI_DATA_0_LVL_MASK 0x00100000 +#define SDHCI_CMD_LVL 0x01000000 + +#define SDHCI_HOST_CONTROL 0x28 +#define SDHCI_CTRL_LED 0x01 +#define SDHCI_CTRL_4BITBUS 0x02 +#define SDHCI_CTRL_HISPD 0x04 +#define SDHCI_CTRL_DMA_MASK 0x18 +#define SDHCI_CTRL_SDMA 0x00 +#define SDHCI_CTRL_ADMA1 0x08 +#define SDHCI_CTRL_ADMA32 0x10 +#define SDHCI_CTRL_ADMA64 0x18 +#define SDHCI_CTRL_ADMA3 0x18 +#define SDHCI_CTRL_8BITBUS 0x20 +#define SDHCI_CTRL_CDTEST_INS 0x40 +#define SDHCI_CTRL_CDTEST_EN 0x80 + +#define SDHCI_POWER_CONTROL 0x29 +#define SDHCI_POWER_ON 0x01 +#define SDHCI_POWER_180 0x0A +#define SDHCI_POWER_300 0x0C +#define SDHCI_POWER_330 0x0E + +#define SDHCI_BLOCK_GAP_CONTROL 0x2A + +#define SDHCI_WAKE_UP_CONTROL 0x2B +#define SDHCI_WAKE_ON_INT 0x01 +#define SDHCI_WAKE_ON_INSERT 0x02 +#define SDHCI_WAKE_ON_REMOVE 0x04 + +#define SDHCI_CLOCK_CONTROL 0x2C +#define SDHCI_DIVIDER_SHIFT 8 +#define SDHCI_DIVIDER_HI_SHIFT 6 +#define SDHCI_DIV_MASK 0xFF +#define SDHCI_DIV_MASK_LEN 8 +#define SDHCI_DIV_HI_MASK 0x300 +#define SDHCI_PROG_CLOCK_MODE 0x0020 +#define SDHCI_CLOCK_CARD_EN 0x0004 +#define SDHCI_CLOCK_PLL_EN 0x0008 +#define SDHCI_CLOCK_INT_STABLE 0x0002 +#define SDHCI_CLOCK_INT_EN 0x0001 + +#define SDHCI_TIMEOUT_CONTROL 0x2E + +#define SDHCI_SOFTWARE_RESET 0x2F +#define SDHCI_RESET_ALL 0x01 +#define SDHCI_RESET_CMD 0x02 +#define SDHCI_RESET_DATA 0x04 + +#define SDHCI_INT_STATUS 0x30 +#define SDHCI_INT_ENABLE 0x34 +#define SDHCI_SIGNAL_ENABLE 0x38 +#define SDHCI_INT_RESPONSE 0x00000001 +#define SDHCI_INT_DATA_END 0x00000002 +#define SDHCI_INT_BLK_GAP 0x00000004 +#define SDHCI_INT_DMA_END 0x00000008 +#define SDHCI_INT_SPACE_AVAIL 0x00000010 +#define SDHCI_INT_DATA_AVAIL 0x00000020 +#define SDHCI_INT_CARD_INSERT 0x00000040 +#define SDHCI_INT_CARD_REMOVE 0x00000080 +#define SDHCI_INT_CARD_INT 0x00000100 +#define SDHCI_INT_RETUNE 0x00001000 +#define SDHCI_INT_CQE 0x00004000 +#define SDHCI_INT_ERROR 0x00008000 +#define SDHCI_INT_TIMEOUT 0x00010000 +#define SDHCI_INT_CRC 0x00020000 +#define SDHCI_INT_END_BIT 0x00040000 +#define SDHCI_INT_INDEX 0x00080000 +#define SDHCI_INT_DATA_TIMEOUT 0x00100000 +#define SDHCI_INT_DATA_CRC 0x00200000 +#define SDHCI_INT_DATA_END_BIT 0x00400000 +#define SDHCI_INT_BUS_POWER 0x00800000 +#define SDHCI_INT_AUTO_CMD_ERR 0x01000000 +#define SDHCI_INT_ADMA_ERROR 0x02000000 + +#define SDHCI_INT_NORMAL_MASK 0x00007FFF +#define SDHCI_INT_ERROR_MASK 0xFFFF8000 + +#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \ + SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX | \ + SDHCI_INT_AUTO_CMD_ERR) +#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ + SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ + SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ + SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \ + SDHCI_INT_BLK_GAP) +#define SDHCI_INT_ALL_MASK ((unsigned int)-1) + +#define SDHCI_CQE_INT_ERR_MASK ( \ + SDHCI_INT_ADMA_ERROR | SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | \ + SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | \ + SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT) + +#define SDHCI_CQE_INT_MASK (SDHCI_CQE_INT_ERR_MASK | SDHCI_INT_CQE) + +#define SDHCI_AUTO_CMD_STATUS 0x3C +#define SDHCI_AUTO_CMD_TIMEOUT 0x00000002 +#define SDHCI_AUTO_CMD_CRC 0x00000004 +#define SDHCI_AUTO_CMD_END_BIT 0x00000008 +#define SDHCI_AUTO_CMD_INDEX 0x00000010 + +#define SDHCI_HOST_CONTROL2 0x3E +#define SDHCI_CTRL_UHS_MASK 0x0007 +#define SDHCI_CTRL_UHS_SDR12 0x0000 +#define SDHCI_CTRL_UHS_SDR25 0x0001 +#define SDHCI_CTRL_UHS_SDR50 0x0002 +#define SDHCI_CTRL_UHS_SDR104 0x0003 +#define SDHCI_CTRL_UHS_DDR50 0x0004 +#define SDHCI_CTRL_HS400 0x0005 /* Non-standard */ +#define SDHCI_CTRL_VDD_180 0x0008 +#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 +#define SDHCI_CTRL_DRV_TYPE_B 0x0000 +#define SDHCI_CTRL_DRV_TYPE_A 0x0010 +#define SDHCI_CTRL_DRV_TYPE_C 0x0020 +#define SDHCI_CTRL_DRV_TYPE_D 0x0030 +#define SDHCI_CTRL_EXEC_TUNING 0x0040 +#define SDHCI_CTRL_TUNED_CLK 0x0080 +#define SDHCI_CMD23_ENABLE 0x0800 +#define SDHCI_CTRL_V4_MODE 0x1000 +#define SDHCI_CTRL_64BIT_ADDR 0x2000 +#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000 + +#define SDHCI_CAPABILITIES 0x40 +#define SDHCI_TIMEOUT_CLK_MASK GENMASK(5, 0) +#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080 +#define SDHCI_CLOCK_BASE_MASK GENMASK(13, 8) +#define SDHCI_CLOCK_V3_BASE_MASK GENMASK(15, 8) +#define SDHCI_MAX_BLOCK_MASK 0x00030000 +#define SDHCI_MAX_BLOCK_SHIFT 16 +#define SDHCI_CAN_DO_8BIT 0x00040000 +#define SDHCI_CAN_DO_ADMA2 0x00080000 +#define SDHCI_CAN_DO_ADMA1 0x00100000 +#define SDHCI_CAN_DO_HISPD 0x00200000 +#define SDHCI_CAN_DO_SDMA 0x00400000 +#define SDHCI_CAN_DO_SUSPEND 0x00800000 +#define SDHCI_CAN_VDD_330 0x01000000 +#define SDHCI_CAN_VDD_300 0x02000000 +#define SDHCI_CAN_VDD_180 0x04000000 +#define SDHCI_CAN_64BIT_V4 0x08000000 +#define SDHCI_CAN_64BIT 0x10000000 + +#define SDHCI_CAPABILITIES_1 0x44 +#define SDHCI_SUPPORT_SDR50 0x00000001 +#define SDHCI_SUPPORT_SDR104 0x00000002 +#define SDHCI_SUPPORT_DDR50 0x00000004 +#define SDHCI_DRIVER_TYPE_A 0x00000010 +#define SDHCI_DRIVER_TYPE_C 0x00000020 +#define SDHCI_DRIVER_TYPE_D 0x00000040 +#define SDHCI_RETUNING_TIMER_COUNT_MASK GENMASK(11, 8) +#define SDHCI_USE_SDR50_TUNING 0x00002000 +#define SDHCI_RETUNING_MODE_MASK GENMASK(15, 14) +#define SDHCI_CLOCK_MUL_MASK GENMASK(23, 16) +#define SDHCI_CAN_DO_ADMA3 0x08000000 +#define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */ + +#define SDHCI_MAX_CURRENT 0x48 +#define SDHCI_MAX_CURRENT_LIMIT GENMASK(7, 0) +#define SDHCI_MAX_CURRENT_330_MASK GENMASK(7, 0) +#define SDHCI_MAX_CURRENT_300_MASK GENMASK(15, 8) +#define SDHCI_MAX_CURRENT_180_MASK GENMASK(23, 16) +#define SDHCI_MAX_CURRENT_MULTIPLIER 4 + +/* 4C-4F reserved for more max current */ + +#define SDHCI_SET_ACMD12_ERROR 0x50 +#define SDHCI_SET_INT_ERROR 0x52 + +#define SDHCI_ADMA_ERROR 0x54 + +/* 55-57 reserved */ + +#define SDHCI_ADMA_ADDRESS 0x58 +#define SDHCI_ADMA_ADDRESS_HI 0x5C + +/* 60-FB reserved */ + +#define SDHCI_PRESET_FOR_SDR12 0x66 +#define SDHCI_PRESET_FOR_SDR25 0x68 +#define SDHCI_PRESET_FOR_SDR50 0x6A +#define SDHCI_PRESET_FOR_SDR104 0x6C +#define SDHCI_PRESET_FOR_DDR50 0x6E +#define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */ +#define SDHCI_PRESET_DRV_MASK GENMASK(15, 14) +#define SDHCI_PRESET_CLKGEN_SEL BIT(10) +#define SDHCI_PRESET_SDCLK_FREQ_MASK GENMASK(9, 0) + +#define SDHCI_SLOT_INT_STATUS 0xFC + +#define SDHCI_HOST_VERSION 0xFE +#define SDHCI_VENDOR_VER_MASK 0xFF00 +#define SDHCI_VENDOR_VER_SHIFT 8 +#define SDHCI_SPEC_VER_MASK 0x00FF +#define SDHCI_SPEC_VER_SHIFT 0 +#define SDHCI_SPEC_100 0 +#define SDHCI_SPEC_200 1 +#define SDHCI_SPEC_300 2 +#define SDHCI_SPEC_400 3 +#define SDHCI_SPEC_410 4 +#define SDHCI_SPEC_420 5 + +/* + * End of controller registers. + */ + +#define SDHCI_MAX_DIV_SPEC_200 256 +#define SDHCI_MAX_DIV_SPEC_300 2046 + +/* + * Host SDMA buffer boundary. Valid values from 4K to 512K in powers of 2. + */ +#define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024) +#define SDHCI_DEFAULT_BOUNDARY_ARG (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12) + +/* ADMA2 32-bit DMA descriptor size */ +#define SDHCI_ADMA2_32_DESC_SZ 8 + +/* ADMA2 32-bit descriptor */ +struct sdhci_adma2_32_desc { + __le16 cmd; + __le16 len; + __le32 addr; +} __packed __aligned(4); + +/* ADMA2 data alignment */ +#define SDHCI_ADMA2_ALIGN 4 +#define SDHCI_ADMA2_MASK (SDHCI_ADMA2_ALIGN - 1) + +/* + * ADMA2 descriptor alignment. Some controllers (e.g. Intel) require 8 byte + * alignment for the descriptor table even in 32-bit DMA mode. Memory + * allocation is at least 8 byte aligned anyway, so just stipulate 8 always. + */ +#define SDHCI_ADMA2_DESC_ALIGN 8 + +/* + * ADMA2 64-bit DMA descriptor size + * According to SD Host Controller spec v4.10, there are two kinds of + * descriptors for 64-bit addressing mode: 96-bit Descriptor and 128-bit + * Descriptor, if Host Version 4 Enable is set in the Host Control 2 + * register, 128-bit Descriptor will be selected. + */ +#define SDHCI_ADMA2_64_DESC_SZ(host) ((host)->v4_mode ? 16 : 12) + +/* + * ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte + * aligned. + */ +struct sdhci_adma2_64_desc { + __le16 cmd; + __le16 len; + __le32 addr_lo; + __le32 addr_hi; +} __packed __aligned(4); + +#define ADMA2_TRAN_VALID 0x21 +#define ADMA2_NOP_END_VALID 0x3 +#define ADMA2_END 0x2 + +/* + * Maximum segments assuming a 512KiB maximum requisition size and a minimum + * 4KiB page size. + */ +#define SDHCI_MAX_SEGS 128 + +/* Allow for a a command request and a data request at the same time */ +#define SDHCI_MAX_MRQS 2 + +/* + * 48bit command and 136 bit response in 100KHz clock could take upto 2.48ms. + * However since the start time of the command, the time between + * command and response, and the time between response and start of data is + * not known, set the command transfer time to 10ms. + */ +#define MMC_CMD_TRANSFER_TIME (10 * NSEC_PER_MSEC) /* max 10 ms */ + +enum sdhci_cookie { + COOKIE_UNMAPPED, + COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */ + COOKIE_MAPPED, /* mapped by sdhci_prepare_data() */ +}; + +struct sdhci_host { + /* Data set by hardware interface driver */ + const char *hw_name; /* Hardware bus name */ + + unsigned int quirks; /* Deviations from spec. */ + +/* Controller doesn't honor resets unless we touch the clock register */ +#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) +/* Controller has bad caps bits, but really supports DMA */ +#define SDHCI_QUIRK_FORCE_DMA (1<<1) +/* Controller doesn't like to be reset when there is no card inserted. */ +#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) +/* Controller doesn't like clearing the power reg before a change */ +#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) +/* Controller has flaky internal state so reset it on each ios change */ +#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4) +/* Controller has an unusable DMA engine */ +#define SDHCI_QUIRK_BROKEN_DMA (1<<5) +/* Controller has an unusable ADMA engine */ +#define SDHCI_QUIRK_BROKEN_ADMA (1<<6) +/* Controller can only DMA from 32-bit aligned addresses */ +#define SDHCI_QUIRK_32BIT_DMA_ADDR (1<<7) +/* Controller can only DMA chunk sizes that are a multiple of 32 bits */ +#define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<8) +/* Controller can only ADMA chunks that are a multiple of 32 bits */ +#define SDHCI_QUIRK_32BIT_ADMA_SIZE (1<<9) +/* Controller needs to be reset after each request to stay stable */ +#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<10) +/* Controller needs voltage and power writes to happen separately */ +#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<11) +/* Controller provides an incorrect timeout value for transfers */ +#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12) +/* Controller has an issue with buffer bits for small transfers */ +#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13) +/* Controller does not provide transfer-complete interrupt when not busy */ +#define SDHCI_QUIRK_NO_BUSY_IRQ (1<<14) +/* Controller has unreliable card detection */ +#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15) +/* Controller reports inverted write-protect state */ +#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16) +/* Controller has unusable command queue engine */ +#define SDHCI_QUIRK_BROKEN_CQE (1<<17) +/* Controller does not like fast PIO transfers */ +#define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18) +/* Controller does not have a LED */ +#define SDHCI_QUIRK_NO_LED (1<<19) +/* Controller has to be forced to use block size of 2048 bytes */ +#define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20) +/* Controller cannot do multi-block transfers */ +#define SDHCI_QUIRK_NO_MULTIBLOCK (1<<21) +/* Controller can only handle 1-bit data transfers */ +#define SDHCI_QUIRK_FORCE_1_BIT_DATA (1<<22) +/* Controller needs 10ms delay between applying power and clock */ +#define SDHCI_QUIRK_DELAY_AFTER_POWER (1<<23) +/* Controller uses SDCLK instead of TMCLK for data timeouts */ +#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1<<24) +/* Controller reports wrong base clock capability */ +#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1<<25) +/* Controller cannot support End Attribute in NOP ADMA descriptor */ +#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1<<26) +/* Controller is missing device caps. Use caps provided by host */ +#define SDHCI_QUIRK_MISSING_CAPS (1<<27) +/* Controller uses Auto CMD12 command to stop the transfer */ +#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1<<28) +/* Controller doesn't have HISPD bit field in HI-SPEED SD card */ +#define SDHCI_QUIRK_NO_HISPD_BIT (1<<29) +/* Controller treats ADMA descriptors with length 0000h incorrectly */ +#define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC (1<<30) +/* The read-only detection via SDHCI_PRESENT_STATE register is unstable */ +#define SDHCI_QUIRK_UNSTABLE_RO_DETECT (1<<31) + + unsigned int quirks2; /* More deviations from spec. */ + +#define SDHCI_QUIRK2_HOST_OFF_CARD_ON (1<<0) +#define SDHCI_QUIRK2_HOST_NO_CMD23 (1<<1) +/* The system physically doesn't support 1.8v, even if the host does */ +#define SDHCI_QUIRK2_NO_1_8_V (1<<2) +#define SDHCI_QUIRK2_PRESET_VALUE_BROKEN (1<<3) +#define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON (1<<4) +/* Controller has a non-standard host control register */ +#define SDHCI_QUIRK2_BROKEN_HOST_CONTROL (1<<5) +/* Controller does not support HS200 */ +#define SDHCI_QUIRK2_BROKEN_HS200 (1<<6) +/* Controller does not support DDR50 */ +#define SDHCI_QUIRK2_BROKEN_DDR50 (1<<7) +/* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */ +#define SDHCI_QUIRK2_STOP_WITH_TC (1<<8) +/* Controller does not support 64-bit DMA */ +#define SDHCI_QUIRK2_BROKEN_64_BIT_DMA (1<<9) +/* need clear transfer mode register before send cmd */ +#define SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD (1<<10) +/* Capability register bit-63 indicates HS400 support */ +#define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 (1<<11) +/* forced tuned clock */ +#define SDHCI_QUIRK2_TUNING_WORK_AROUND (1<<12) +/* disable the block count for single block transactions */ +#define SDHCI_QUIRK2_SUPPORT_SINGLE (1<<13) +/* Controller broken with using ACMD23 */ +#define SDHCI_QUIRK2_ACMD23_BROKEN (1<<14) +/* Broken Clock divider zero in controller */ +#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15) +/* Controller has CRC in 136 bit Command Response */ +#define SDHCI_QUIRK2_RSP_136_HAS_CRC (1<<16) +/* + * Disable HW timeout if the requested timeout is more than the maximum + * obtainable timeout. + */ +#define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT (1<<17) +/* + * 32-bit block count may not support eMMC where upper bits of CMD23 are used + * for other purposes. Consequently we support 16-bit block count by default. + * Otherwise, SDHCI_QUIRK2_USE_32BIT_BLK_CNT can be selected to use 32-bit + * block count. + */ +#define SDHCI_QUIRK2_USE_32BIT_BLK_CNT (1<<18) + + int irq; /* Device IRQ */ + void __iomem *ioaddr; /* Mapped address */ + phys_addr_t mapbase; /* physical address base */ + char *bounce_buffer; /* For packing SDMA reads/writes */ + dma_addr_t bounce_addr; + unsigned int bounce_buffer_size; + + const struct sdhci_ops *ops; /* Low level hw interface */ + + /* Internal data */ + struct mmc_host *mmc; /* MMC structure */ + struct mmc_host_ops mmc_host_ops; /* MMC host ops */ + u64 dma_mask; /* custom DMA mask */ + +#if IS_ENABLED(CONFIG_LEDS_CLASS) + struct led_classdev led; /* LED control */ + char led_name[32]; +#endif + + spinlock_t lock; /* Mutex */ + + int flags; /* Host attributes */ +#define SDHCI_USE_SDMA (1<<0) /* Host is SDMA capable */ +#define SDHCI_USE_ADMA (1<<1) /* Host is ADMA capable */ +#define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */ +#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */ +#define SDHCI_SDR50_NEEDS_TUNING (1<<4) /* SDR50 needs tuning */ +#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */ +#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */ +#define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */ +#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */ +#define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */ +#define SDHCI_SIGNALING_330 (1<<14) /* Host is capable of 3.3V signaling */ +#define SDHCI_SIGNALING_180 (1<<15) /* Host is capable of 1.8V signaling */ +#define SDHCI_SIGNALING_120 (1<<16) /* Host is capable of 1.2V signaling */ + + unsigned int version; /* SDHCI spec. version */ + + unsigned int max_clk; /* Max possible freq (MHz) */ + unsigned int timeout_clk; /* Timeout freq (KHz) */ + unsigned int clk_mul; /* Clock Muliplier value */ + + unsigned int clock; /* Current clock (MHz) */ + u8 pwr; /* Current voltage */ + + bool runtime_suspended; /* Host is runtime suspended */ + bool bus_on; /* Bus power prevents runtime suspend */ + bool preset_enabled; /* Preset is enabled */ + bool pending_reset; /* Cmd/data reset is pending */ + bool irq_wake_enabled; /* IRQ wakeup is enabled */ + bool v4_mode; /* Host Version 4 Enable */ + bool use_external_dma; /* Host selects to use external DMA */ + bool always_defer_done; /* Always defer to complete requests */ + + struct mmc_request *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */ + struct mmc_command *cmd; /* Current command */ + struct mmc_command *data_cmd; /* Current data command */ + struct mmc_command *deferred_cmd; /* Deferred command */ + struct mmc_data *data; /* Current data request */ + unsigned int data_early:1; /* Data finished before cmd */ + + struct sg_mapping_iter sg_miter; /* SG state for PIO */ + unsigned int blocks; /* remaining PIO blocks */ + + int sg_count; /* Mapped sg entries */ + + void *adma_table; /* ADMA descriptor table */ + void *align_buffer; /* Bounce buffer */ + + size_t adma_table_sz; /* ADMA descriptor table size */ + size_t align_buffer_sz; /* Bounce buffer size */ + + dma_addr_t adma_addr; /* Mapped ADMA descr. table */ + dma_addr_t align_addr; /* Mapped bounce buffer */ + + unsigned int desc_sz; /* ADMA current descriptor size */ + unsigned int alloc_desc_sz; /* ADMA descr. max size host supports */ + + struct workqueue_struct *complete_wq; /* Request completion wq */ + struct work_struct complete_work; /* Request completion work */ + + struct timer_list timer; /* Timer for timeouts */ + struct timer_list data_timer; /* Timer for data timeouts */ + +#if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA) + struct dma_chan *rx_chan; + struct dma_chan *tx_chan; +#endif + + u32 caps; /* CAPABILITY_0 */ + u32 caps1; /* CAPABILITY_1 */ + bool read_caps; /* Capability flags have been read */ + + bool sdhci_core_to_disable_vqmmc; /* sdhci core can disable vqmmc */ + unsigned int ocr_avail_sdio; /* OCR bit masks */ + unsigned int ocr_avail_sd; + unsigned int ocr_avail_mmc; + u32 ocr_mask; /* available voltages */ + + unsigned timing; /* Current timing */ + + u32 thread_isr; + + /* cached registers */ + u32 ier; + + bool cqe_on; /* CQE is operating */ + u32 cqe_ier; /* CQE interrupt mask */ + u32 cqe_err_ier; /* CQE error interrupt mask */ + + wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */ + unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */ + + unsigned int tuning_count; /* Timer count for re-tuning */ + unsigned int tuning_mode; /* Re-tuning mode supported by host */ + unsigned int tuning_err; /* Error code for re-tuning */ +#define SDHCI_TUNING_MODE_1 0 +#define SDHCI_TUNING_MODE_2 1 +#define SDHCI_TUNING_MODE_3 2 + /* Delay (ms) between tuning commands */ + int tuning_delay; + int tuning_loop_count; + + /* Host SDMA buffer boundary. */ + u32 sdma_boundary; + + /* Host ADMA table count */ + u32 adma_table_cnt; + + u64 data_timeout; + + unsigned long private[] ____cacheline_aligned; +}; + +struct sdhci_ops { +#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS + u32 (*read_l)(struct sdhci_host *host, int reg); + u16 (*read_w)(struct sdhci_host *host, int reg); + u8 (*read_b)(struct sdhci_host *host, int reg); + void (*write_l)(struct sdhci_host *host, u32 val, int reg); + void (*write_w)(struct sdhci_host *host, u16 val, int reg); + void (*write_b)(struct sdhci_host *host, u8 val, int reg); +#endif + + void (*set_clock)(struct sdhci_host *host, unsigned int clock); + void (*set_power)(struct sdhci_host *host, unsigned char mode, + unsigned short vdd); + + u32 (*irq)(struct sdhci_host *host, u32 intmask); + + int (*set_dma_mask)(struct sdhci_host *host); + int (*enable_dma)(struct sdhci_host *host); + unsigned int (*get_max_clock)(struct sdhci_host *host); + unsigned int (*get_min_clock)(struct sdhci_host *host); + /* get_timeout_clock should return clk rate in unit of Hz */ + unsigned int (*get_timeout_clock)(struct sdhci_host *host); + unsigned int (*get_max_timeout_count)(struct sdhci_host *host); + void (*set_timeout)(struct sdhci_host *host, + struct mmc_command *cmd); + void (*set_bus_width)(struct sdhci_host *host, int width); + void (*platform_send_init_74_clocks)(struct sdhci_host *host, + u8 power_mode); + unsigned int (*get_ro)(struct sdhci_host *host); + void (*reset)(struct sdhci_host *host, u8 mask); + int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode); + void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); + void (*hw_reset)(struct sdhci_host *host); + void (*adma_workaround)(struct sdhci_host *host, u32 intmask); + void (*card_event)(struct sdhci_host *host); + void (*voltage_switch)(struct sdhci_host *host); + void (*adma_write_desc)(struct sdhci_host *host, void **desc, + dma_addr_t addr, int len, unsigned int cmd); + void (*copy_to_bounce_buffer)(struct sdhci_host *host, + struct mmc_data *data, + unsigned int length); + void (*request_done)(struct sdhci_host *host, + struct mmc_request *mrq); + void (*dump_vendor_regs)(struct sdhci_host *host); +}; + +#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS + +static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg) +{ + if (unlikely(host->ops->write_l)) + host->ops->write_l(host, val, reg); + else + writel(val, host->ioaddr + reg); +} + +static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg) +{ + if (unlikely(host->ops->write_w)) + host->ops->write_w(host, val, reg); + else + writew(val, host->ioaddr + reg); +} + +static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg) +{ + if (unlikely(host->ops->write_b)) + host->ops->write_b(host, val, reg); + else + writeb(val, host->ioaddr + reg); +} + +static inline u32 sdhci_readl(struct sdhci_host *host, int reg) +{ + if (unlikely(host->ops->read_l)) + return host->ops->read_l(host, reg); + else + return readl(host->ioaddr + reg); +} + +static inline u16 sdhci_readw(struct sdhci_host *host, int reg) +{ + if (unlikely(host->ops->read_w)) + return host->ops->read_w(host, reg); + else + return readw(host->ioaddr + reg); +} + +static inline u8 sdhci_readb(struct sdhci_host *host, int reg) +{ + if (unlikely(host->ops->read_b)) + return host->ops->read_b(host, reg); + else + return readb(host->ioaddr + reg); +} + +#else + +static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg) +{ + writel(val, host->ioaddr + reg); +} + +static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg) +{ + writew(val, host->ioaddr + reg); +} + +static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg) +{ + writeb(val, host->ioaddr + reg); +} + +static inline u32 sdhci_readl(struct sdhci_host *host, int reg) +{ + return readl(host->ioaddr + reg); +} + +static inline u16 sdhci_readw(struct sdhci_host *host, int reg) +{ + return readw(host->ioaddr + reg); +} + +static inline u8 sdhci_readb(struct sdhci_host *host, int reg) +{ + return readb(host->ioaddr + reg); +} + +#endif /* CONFIG_MMC_SDHCI_IO_ACCESSORS */ + +struct sdhci_host *sdhci_alloc_host(struct device *dev, size_t priv_size); +void sdhci_free_host(struct sdhci_host *host); + +static inline void *sdhci_priv(struct sdhci_host *host) +{ + return host->private; +} + +void sdhci_card_detect(struct sdhci_host *host); +void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver, + const u32 *caps, const u32 *caps1); +int sdhci_setup_host(struct sdhci_host *host); +void sdhci_cleanup_host(struct sdhci_host *host); +int __sdhci_add_host(struct sdhci_host *host); +int sdhci_add_host(struct sdhci_host *host); +void sdhci_remove_host(struct sdhci_host *host, int dead); + +static inline void sdhci_read_caps(struct sdhci_host *host) +{ + __sdhci_read_caps(host, NULL, NULL, NULL); +} + +u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock, + unsigned int *actual_clock); +void sdhci_set_clock(struct sdhci_host *host, unsigned int clock); +void sdhci_enable_clk(struct sdhci_host *host, u16 clk); +void sdhci_set_power(struct sdhci_host *host, unsigned char mode, + unsigned short vdd); +void sdhci_set_power_and_bus_voltage(struct sdhci_host *host, + unsigned char mode, + unsigned short vdd); +void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, + unsigned short vdd); +void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq); +int sdhci_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq); +void sdhci_set_bus_width(struct sdhci_host *host, int width); +void sdhci_reset(struct sdhci_host *host, u8 mask); +void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); +int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); +void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); +int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios); +void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable); +void sdhci_adma_write_desc(struct sdhci_host *host, void **desc, + dma_addr_t addr, int len, unsigned int cmd); + +#ifdef CONFIG_PM +int sdhci_suspend_host(struct sdhci_host *host); +int sdhci_resume_host(struct sdhci_host *host); +int sdhci_runtime_suspend_host(struct sdhci_host *host); +int sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset); +#endif + +void sdhci_cqe_enable(struct mmc_host *mmc); +void sdhci_cqe_disable(struct mmc_host *mmc, bool recovery); +bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error, + int *data_error); + +void sdhci_dumpregs(struct sdhci_host *host); +void sdhci_enable_v4_mode(struct sdhci_host *host); + +void sdhci_start_tuning(struct sdhci_host *host); +void sdhci_end_tuning(struct sdhci_host *host); +void sdhci_reset_tuning(struct sdhci_host *host); +void sdhci_send_tuning(struct sdhci_host *host, u32 opcode); +void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode); +void sdhci_switch_external_dma(struct sdhci_host *host, bool en); +void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable); +void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd); + +#endif /* __SDHCI_HW_H */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/spi-bitbang-txrx.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/spi-bitbang-txrx.h new file mode 100644 index 000000000000..47bb9b898dfd --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/spi-bitbang-txrx.h @@ -0,0 +1,107 @@ +/* + * Mix this utility code with some glue code to get one of several types of + * simple SPI master driver. Two do polled word-at-a-time I/O: + * + * - GPIO/parport bitbangers. Provide chipselect() and txrx_word[](), + * expanding the per-word routines from the inline templates below. + * + * - Drivers for controllers resembling bare shift registers. Provide + * chipselect() and txrx_word[](), with custom setup()/cleanup() methods + * that use your controller's clock and chipselect registers. + * + * Some hardware works well with requests at spi_transfer scope: + * + * - Drivers leveraging smarter hardware, with fifos or DMA; or for half + * duplex (MicroWire) controllers. Provide chipselect() and txrx_bufs(), + * and custom setup()/cleanup() methods. + */ + +/* + * The code that knows what GPIO pins do what should have declared four + * functions, ideally as inlines, before including this header: + * + * void setsck(struct spi_device *, int is_on); + * void setmosi(struct spi_device *, int is_on); + * int getmiso(struct spi_device *); + * void spidelay(unsigned); + * + * setsck()'s is_on parameter is a zero/nonzero boolean. + * + * setmosi()'s is_on parameter is a zero/nonzero boolean. + * + * getmiso() is required to return 0 or 1 only. Any other value is invalid + * and will result in improper operation. + * + * A non-inlined routine would call bitbang_txrx_*() routines. The + * main loop could easily compile down to a handful of instructions, + * especially if the delay is a NOP (to run at peak speed). + * + * Since this is software, the timings may not be exactly what your board's + * chips need ... there may be several reasons you'd need to tweak timings + * in these routines, not just to make it faster or slower to match a + * particular CPU clock rate. + */ + +static inline u32 +bitbang_txrx_be_cpha0(struct spi_device *spi, + unsigned nsecs, unsigned cpol, unsigned flags, + u32 word, u8 bits) +{ + /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */ + + u32 oldbit = (!(word & (1<<(bits-1)))) << 31; + /* clock starts at inactive polarity */ + for (word <<= (32 - bits); likely(bits); bits--) { + + /* setup MSB (to slave) on trailing edge */ + if ((flags & SPI_MASTER_NO_TX) == 0) { + if ((word & (1 << 31)) != oldbit) { + setmosi(spi, word & (1 << 31)); + oldbit = word & (1 << 31); + } + } + spidelay(nsecs); /* T(setup) */ + + setsck(spi, !cpol); + spidelay(nsecs); + + /* sample MSB (from slave) on leading edge */ + word <<= 1; + if ((flags & SPI_MASTER_NO_RX) == 0) + word |= getmiso(spi); + setsck(spi, cpol); + } + return word; +} + +static inline u32 +bitbang_txrx_be_cpha1(struct spi_device *spi, + unsigned nsecs, unsigned cpol, unsigned flags, + u32 word, u8 bits) +{ + /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */ + + u32 oldbit = (!(word & (1<<(bits-1)))) << 31; + /* clock starts at inactive polarity */ + for (word <<= (32 - bits); likely(bits); bits--) { + + /* setup MSB (to slave) on leading edge */ + setsck(spi, !cpol); + if ((flags & SPI_MASTER_NO_TX) == 0) { + if ((word & (1 << 31)) != oldbit) { + setmosi(spi, word & (1 << 31)); + oldbit = word & (1 << 31); + } + } + spidelay(nsecs); /* T(setup) */ + + setsck(spi, cpol); + spidelay(nsecs); + + /* sample MSB (from slave) on trailing edge */ + word <<= 1; + if ((flags & SPI_MASTER_NO_RX) == 0) + word |= getmiso(spi); + } + return word; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_eeprom_93xx46.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_eeprom_93xx46.c new file mode 100644 index 000000000000..2ba7e7912ed5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_eeprom_93xx46.c @@ -0,0 +1,558 @@ +/* + * Driver for 93xx46 EEPROMs + * + * (C) 2011 DENX Software Engineering, Anatolij Gustschin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +#define OP_START 0x4 +#define OP_WRITE (OP_START | 0x1) +#define OP_READ (OP_START | 0x2) +#define ADDR_EWDS 0x00 +#define ADDR_ERAL 0x20 +#define ADDR_EWEN 0x30 + +static int g_wb_eeprom_93xx46_debug = 0; + +module_param(g_wb_eeprom_93xx46_debug, int, S_IRUGO | S_IWUSR); + +#define SPI_93xx46_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_eeprom_93xx46_debug) { \ + printk(KERN_INFO "[EEPROM-93xx46][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +struct eeprom_93xx46_devtype_data { + unsigned int quirks; +}; + +static const struct eeprom_93xx46_devtype_data atmel_at93c46d_data = { + .quirks = EEPROM_93XX46_QUIRK_SINGLE_WORD_READ | + EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH, +}; + +struct eeprom_93xx46_dev { + struct spi_device *spi; + struct eeprom_93xx46_platform_data *pdata; + struct mutex lock; + struct nvmem_config nvmem_config; + struct nvmem_device *nvmem; + int addrlen; + int size; +}; + +static inline bool has_quirk_single_word_read(struct eeprom_93xx46_dev *edev) +{ + return edev->pdata->quirks & EEPROM_93XX46_QUIRK_SINGLE_WORD_READ; +} + +static inline bool has_quirk_instruction_length(struct eeprom_93xx46_dev *edev) +{ + return edev->pdata->quirks & EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH; +} + +static int eeprom_93xx46_read(void *priv, unsigned int off, + void *val, size_t count) +{ + struct eeprom_93xx46_dev *edev = priv; + char *buf = val; + int err = 0; + + if (unlikely(off >= edev->size)) + return 0; + if ((off + count) > edev->size) + count = edev->size - off; + if (unlikely(!count)) + return count; + + mutex_lock(&edev->lock); + + if (edev->pdata->prepare) + edev->pdata->prepare(edev); + + while (count) { + struct spi_message m; + struct spi_transfer t[2] = { { 0 } }; + u16 cmd_addr = OP_READ << edev->addrlen; + size_t nbytes = count; + int bits; + int data_bit; + + if (edev->addrlen == 7) { + cmd_addr |= off & 0x7f; + bits = 10; + data_bit = 8; + if (has_quirk_single_word_read(edev)) + nbytes = 1; + } else { + cmd_addr |= (off >> 1) & 0x3f; + bits = 9; + data_bit = 16; + if (has_quirk_single_word_read(edev)) + nbytes = 2; + } + + dev_dbg(&edev->spi->dev, "read cmd 0x%x, %d Hz\n", + cmd_addr, edev->spi->max_speed_hz); + + spi_message_init(&m); + + t[0].tx_buf = (char *)&cmd_addr; + t[0].len = 2; + t[0].bits_per_word = bits; + spi_message_add_tail(&t[0], &m); + + t[1].rx_buf = buf; + t[1].len = nbytes; + t[1].bits_per_word = data_bit; + spi_message_add_tail(&t[1], &m); + + err = spi_sync(edev->spi, &m); + /* have to wait at least Tcsl ns */ + ndelay(250); + + if (err) { + dev_err(&edev->spi->dev, "read %zu bytes at %d: err. %d\n", + nbytes, (int)off, err); + break; + } + + buf += nbytes; + off += nbytes; + count -= nbytes; + } + + if (edev->pdata->finish) + edev->pdata->finish(edev); + + mutex_unlock(&edev->lock); + + return err; +} + +static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on) +{ + struct spi_message m; + struct spi_transfer t; + int bits, ret; + u16 cmd_addr; + + cmd_addr = OP_START << edev->addrlen; + if (edev->addrlen == 7) { + cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS) << 1; + bits = 10; + } else { + cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS); + bits = 9; + } + + if (has_quirk_instruction_length(edev)) { + cmd_addr <<= 2; + bits += 2; + } + + dev_dbg(&edev->spi->dev, "ew%s cmd 0x%04x, %d bits\n", + is_on ? "en" : "ds", cmd_addr, bits); + + spi_message_init(&m); + mem_clear(&t, sizeof(t)); + + t.tx_buf = &cmd_addr; + t.len = 2; + t.bits_per_word = bits; + spi_message_add_tail(&t, &m); + + mutex_lock(&edev->lock); + + if (edev->pdata->prepare) + edev->pdata->prepare(edev); + + ret = spi_sync(edev->spi, &m); + /* have to wait at least Tcsl ns */ + ndelay(250); + if (ret) + dev_err(&edev->spi->dev, "erase/write %sable error %d\n", + is_on ? "en" : "dis", ret); + + if (edev->pdata->finish) + edev->pdata->finish(edev); + + mutex_unlock(&edev->lock); + return ret; +} + +static ssize_t +eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev, + char *buf, unsigned off) +{ + struct spi_message m; + struct spi_transfer t[2]; + int bits, data_len, ret; + u16 cmd_addr; + int data_bit; + + cmd_addr = OP_WRITE << edev->addrlen; + + if (edev->addrlen == 7) { + cmd_addr |= off & 0x7f; + bits = 10; + data_len = 1; + data_bit = 8; + } else { + cmd_addr |= (off >> 1) & 0x3f; + bits = 9; + data_len = 2; + data_bit = 16; + } + + dev_dbg(&edev->spi->dev, "write cmd 0x%x\n", cmd_addr); + + spi_message_init(&m); + mem_clear(t, sizeof(t)); + + t[0].tx_buf = (char *)&cmd_addr; + t[0].len = 2; + t[0].bits_per_word = bits; + spi_message_add_tail(&t[0], &m); + + t[1].tx_buf = buf; + t[1].len = data_len; + t[1].bits_per_word = data_bit; + spi_message_add_tail(&t[1], &m); + + ret = spi_sync(edev->spi, &m); + /* have to wait program cycle time Twc ms */ + mdelay(6); + return ret; +} + +static int eeprom_93xx46_write(void *priv, unsigned int off, + void *val, size_t count) +{ + struct eeprom_93xx46_dev *edev = priv; + char *buf = val; + int i, ret, step = 1; + + if (unlikely(off >= edev->size)) + return -EFBIG; + if ((off + count) > edev->size) + count = edev->size - off; + if (unlikely(!count)) + return count; + + /* only write even number of bytes on 16-bit devices */ + if (edev->addrlen == 6) { + step = 2; + count &= ~1; + } + + /* erase/write enable */ + ret = eeprom_93xx46_ew(edev, 1); + if (ret) + return ret; + + mutex_lock(&edev->lock); + + if (edev->pdata->prepare) + edev->pdata->prepare(edev); + + for (i = 0; i < count; i += step) { + ret = eeprom_93xx46_write_word(edev, &buf[i], off + i); + if (ret) { + dev_err(&edev->spi->dev, "write failed at %d: %d\n", + (int)off + i, ret); + break; + } + } + + if (edev->pdata->finish) + edev->pdata->finish(edev); + + mutex_unlock(&edev->lock); + + /* erase/write disable */ + eeprom_93xx46_ew(edev, 0); + return ret; +} + +static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev) +{ + struct eeprom_93xx46_platform_data *pd = edev->pdata; + struct spi_message m; + struct spi_transfer t; + int bits, ret; + u16 cmd_addr; + + cmd_addr = OP_START << edev->addrlen; + if (edev->addrlen == 7) { + cmd_addr |= ADDR_ERAL << 1; + bits = 10; + } else { + cmd_addr |= ADDR_ERAL; + bits = 9; + } + + if (has_quirk_instruction_length(edev)) { + cmd_addr <<= 2; + bits += 2; + } + + dev_dbg(&edev->spi->dev, "eral cmd 0x%04x, %d bits\n", cmd_addr, bits); + + spi_message_init(&m); + mem_clear(&t, sizeof(t)); + + t.tx_buf = &cmd_addr; + t.len = 2; + t.bits_per_word = bits; + spi_message_add_tail(&t, &m); + + mutex_lock(&edev->lock); + + if (edev->pdata->prepare) + edev->pdata->prepare(edev); + + ret = spi_sync(edev->spi, &m); + if (ret) + dev_err(&edev->spi->dev, "erase error %d\n", ret); + /* have to wait erase cycle time Tec ms */ + mdelay(6); + + if (pd->finish) + pd->finish(edev); + + mutex_unlock(&edev->lock); + return ret; +} + +static ssize_t eeprom_93xx46_store_erase(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct eeprom_93xx46_dev *edev = dev_get_drvdata(dev); + int erase = 0, ret; + + sscanf(buf, "%d", &erase); + if (erase) { + ret = eeprom_93xx46_ew(edev, 1); + if (ret) + return ret; + ret = eeprom_93xx46_eral(edev); + if (ret) + return ret; + ret = eeprom_93xx46_ew(edev, 0); + if (ret) + return ret; + } + return count; +} +static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase); + +static void select_assert(void *context) +{ + struct eeprom_93xx46_dev *edev = context; + + gpiod_set_value_cansleep(edev->pdata->select, 1); +} + +static void select_deassert(void *context) +{ + struct eeprom_93xx46_dev *edev = context; + + gpiod_set_value_cansleep(edev->pdata->select, 0); +} + +static const struct of_device_id eeprom_93xx46_of_table[] = { + { .compatible = "eeprom-93xx46", }, + { .compatible = "atmel,at93c46d", .data = &atmel_at93c46d_data, }, + {} +}; +MODULE_DEVICE_TABLE(of, eeprom_93xx46_of_table); + +static int eeprom_93xx46_probe_dt(struct spi_device *spi) +{ + const struct of_device_id *of_id = + of_match_device(eeprom_93xx46_of_table, &spi->dev); + struct device_node *np = spi->dev.of_node; + struct eeprom_93xx46_platform_data *pd; + u32 tmp; + int gpio; + enum of_gpio_flags of_flags; + int ret; + + pd = devm_kzalloc(&spi->dev, sizeof(*pd), GFP_KERNEL); + if (!pd) + return -ENOMEM; + + ret = of_property_read_u32(np, "data-size", &tmp); + if (ret < 0) { + dev_err(&spi->dev, "data-size property not found\n"); + return ret; + } + + if (tmp == 8) { + pd->flags |= EE_ADDR8; + } else if (tmp == 16) { + pd->flags |= EE_ADDR16; + } else { + dev_err(&spi->dev, "invalid data-size (%d)\n", tmp); + return -EINVAL; + } + + if (of_property_read_bool(np, "read-only")) + pd->flags |= EE_READONLY; + + gpio = of_get_named_gpio_flags(np, "select-gpios", 0, &of_flags); + if (gpio_is_valid(gpio)) { + unsigned long flags = + of_flags == OF_GPIO_ACTIVE_LOW ? GPIOF_ACTIVE_LOW : 0; + + ret = devm_gpio_request_one(&spi->dev, gpio, flags, + "eeprom_93xx46_select"); + if (ret) + return ret; + + pd->select = gpio_to_desc(gpio); + pd->prepare = select_assert; + pd->finish = select_deassert; + + gpiod_direction_output(pd->select, 0); + } + + if (of_id) { + if (of_id->data) { + const struct eeprom_93xx46_devtype_data *data = of_id->data; + + pd->quirks = data->quirks; + } + } + + spi->dev.platform_data = pd; + + return 0; +} + +static int eeprom_93xx46_probe(struct spi_device *spi) +{ + struct eeprom_93xx46_platform_data *pd; + struct eeprom_93xx46_dev *edev; + int err; + + if (spi->dev.of_node) { + err = eeprom_93xx46_probe_dt(spi); + if (err < 0) + return err; + } + + pd = spi->dev.platform_data; + if (!pd) { + dev_err(&spi->dev, "missing platform data\n"); + return -ENODEV; + } + + edev = kzalloc(sizeof(*edev), GFP_KERNEL); + if (!edev) + return -ENOMEM; + + if (pd->flags & EE_ADDR8) + edev->addrlen = 7; + else if (pd->flags & EE_ADDR16) + edev->addrlen = 6; + else { + dev_err(&spi->dev, "unspecified address type\n"); + err = -EINVAL; + goto fail; + } + + mutex_init(&edev->lock); + + edev->spi = spi; + edev->pdata = pd; + + edev->size = 128; + edev->nvmem_config.name = dev_name(&spi->dev); + edev->nvmem_config.dev = &spi->dev; + edev->nvmem_config.read_only = pd->flags & EE_READONLY; + edev->nvmem_config.root_only = true; + edev->nvmem_config.owner = THIS_MODULE; + edev->nvmem_config.compat = true; + edev->nvmem_config.base_dev = &spi->dev; + edev->nvmem_config.reg_read = eeprom_93xx46_read; + edev->nvmem_config.reg_write = eeprom_93xx46_write; + edev->nvmem_config.priv = edev; + edev->nvmem_config.stride = 4; + edev->nvmem_config.word_size = 1; + edev->nvmem_config.size = edev->size; + + edev->nvmem = nvmem_register(&edev->nvmem_config); + if (IS_ERR(edev->nvmem)) { + err = PTR_ERR(edev->nvmem); + goto fail; + } + + if (g_wb_eeprom_93xx46_debug) { + dev_info(&spi->dev, "%d-bit eeprom %s\n", + (pd->flags & EE_ADDR8) ? 8 : 16, + (pd->flags & EE_READONLY) ? "(readonly)" : ""); + } + + if (!(pd->flags & EE_READONLY)) { + if (device_create_file(&spi->dev, &dev_attr_erase)) + dev_err(&spi->dev, "can't create erase interface\n"); + } + + spi_set_drvdata(spi, edev); + return 0; +fail: + kfree(edev); + return err; +} + +static int eeprom_93xx46_remove(struct spi_device *spi) +{ + struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi); + + nvmem_unregister(edev->nvmem); + + if (!(edev->pdata->flags & EE_READONLY)) + device_remove_file(&spi->dev, &dev_attr_erase); + + kfree(edev); + return 0; +} + +static struct spi_driver wb_eeprom_93xx46_driver = { + .driver = { + .name = "wb_93xx46", + .of_match_table = of_match_ptr(eeprom_93xx46_of_table), + }, + .probe = eeprom_93xx46_probe, + .remove = eeprom_93xx46_remove, +}; + +module_spi_driver(wb_eeprom_93xx46_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Driver for 93xx46 EEPROMs"); +MODULE_AUTHOR("support"); +MODULE_ALIAS("spi:93xx46"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_i2c_bus_drv.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_i2c_bus_drv.c new file mode 100644 index 000000000000..3932cb26cd77 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_i2c_bus_drv.c @@ -0,0 +1,1120 @@ +/* + * fpga_i2c_bus_drv.c + * ko to create fpga i2c adapter + */ +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) +#include +#endif +#include +#include +#include +#include +#include +#include +#include "fpga_i2c.h" + +#include +#include + +#define DRV_NAME "wb-fpga-i2c" +#define DRV_VERSION "1.0" +#define DTS_NO_CFG_FLAG (0) + +extern int i2c_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); +extern int i2c_device_func_read(const char *path, uint32_t pos, uint8_t *val, size_t size); +extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); +extern int io_device_func_read(const char *path, uint32_t pos, uint8_t *val, size_t size); +extern int spi_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int spi_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); + +#define FPGA_I2C_STRETCH_TIMEOUT (0x01) +#define FPGA_I2C_DEADLOCK_FAILED (0x02) +#define FPGA_I2C_SLAVE_NO_RESPOND (0x03) +#define FPGA_I2C_STA_FAIL (0x01) +#define FPGA_I2C_STA_BUSY (0x02) +#define FPGA_I2C_CTL_BG (0x01 << 1) +#define FPGA_I2C_CTL_NO_REG (0x01 << 2) +#define FPGA_I2C_CTL_RD (0x01) +#define FPGA_I2C_CTL_WR (0x00) +#define I2C_READ_MSG_NUM (0x02) +#define I2C_WRITE_MSG_NUM (0x01) +#define FPGA_REG_WIDTH (4) + +#define SYMBOL_I2C_DEV_MODE (1) +#define FILE_MODE (2) +#define SYMBOL_PCIE_DEV_MODE (3) +#define SYMBOL_IO_DEV_MODE (4) +#define SYMBOL_SPI_DEV_MODE (5) + +int g_wb_fpga_i2c_debug = 0; +int g_wb_fpga_i2c_error = 0; + +module_param(g_wb_fpga_i2c_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_fpga_i2c_error, int, S_IRUGO | S_IWUSR); + +#define FPGA_I2C_VERBOSE(fmt, args...) do { \ + if (g_wb_fpga_i2c_debug) { \ + printk(KERN_INFO "[FPFA_I2C_BUS][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define FPGA_I2C_ERROR(fmt, args...) do { \ + if (g_wb_fpga_i2c_error) { \ + printk(KERN_ERR "[FPFA_I2C_BUS][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static int fpga_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + filp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(filp)) { + FPGA_I2C_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + ret = kernel_read(filp, val, size, &tmp_pos); + if (ret < 0) { + FPGA_I2C_ERROR("kernel_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int fpga_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + filp = filp_open(path, O_RDWR, 777); + if (IS_ERR(filp)) { + FPGA_I2C_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + ret = kernel_write(filp, val, size, &tmp_pos); + if (ret < 0) { + FPGA_I2C_ERROR("kernel_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + vfs_fsync(filp, 1); + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int fpga_device_write(fpga_i2c_dev_t *fpga_i2c, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + + switch (fpga_i2c->i2c_func_mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + case FILE_MODE: + ret = fpga_file_write(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_SPI_DEV_MODE: + ret = spi_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + default: + FPGA_I2C_ERROR("err func_mode %d, write failed.\n", fpga_i2c->i2c_func_mode); + return -EINVAL; + } + return ret; + +} + +static int fpga_device_read(fpga_i2c_dev_t *fpga_i2c, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + + switch (fpga_i2c->i2c_func_mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_read(fpga_i2c->dev_name, pos, val, size); + break; + case FILE_MODE: + ret = fpga_file_read(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_read(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_read(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_SPI_DEV_MODE: + ret = spi_device_func_read(fpga_i2c->dev_name, pos, val, size); + break; + default: + FPGA_I2C_ERROR("err func_mode %d, read failed.\n", fpga_i2c->i2c_func_mode); + return -EINVAL; + } + + return ret; +} + +static int little_endian_dword_to_buf(uint8_t *buf, int len, uint32_t dword) +{ + uint8_t tmp_buf[FPGA_REG_WIDTH]; + + if (len < 4) { + FPGA_I2C_ERROR("Not enough buf, dword to buf: len[%d], dword[0x%x]\n", len, dword); + return -1; + } + + mem_clear(tmp_buf, sizeof(tmp_buf)); + tmp_buf[0] = dword & 0xff; + tmp_buf[1] = (dword >> 8) & 0xff; + tmp_buf[2] = (dword >> 16) & 0xff; + tmp_buf[3] = (dword >> 24) & 0xff; + + memcpy(buf, tmp_buf, sizeof(tmp_buf)); + + return 0; +} + +static int little_endian_buf_to_dword(uint8_t *buf, int len, uint32_t *dword) +{ + int i; + uint32_t dword_tmp; + + if (len != FPGA_REG_WIDTH) { + FPGA_I2C_ERROR("buf length %d error, can't convert to dowrd.\n", len); + return -1; + } + dword_tmp = 0; + for (i = 0; i < FPGA_REG_WIDTH; i++) { + dword_tmp |= (buf[i] << (i * 8)); + } + *dword = dword_tmp; + return 0; +} + +static int fpga_reg_write(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t val) +{ + int ret; + + ret = fpga_device_write(fpga_i2c, addr, &val, sizeof(uint8_t)); + if (ret < 0) { + FPGA_I2C_ERROR("fpga reg write failed, dev name:%s, offset:0x%x, value:0x%x.\n", + fpga_i2c->dev_name, addr, val); + return -EIO; + } + + FPGA_I2C_VERBOSE("fpga reg write success, dev name:%s, offset:0x%x, value:0x%x.\n", + fpga_i2c->dev_name, addr, val); + return 0; +} + +static int fpga_reg_read(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t *val) +{ + int ret; + + ret = fpga_device_read(fpga_i2c, addr, val, sizeof(uint8_t)); + if (ret < 0) { + FPGA_I2C_ERROR("fpga reg read failed, dev name:%s, offset:0x%x\n", + fpga_i2c->dev_name, addr); + return -EIO; + } + + FPGA_I2C_VERBOSE("fpga reg read success, dev name:%s, offset:0x%x, value:0x%x.\n", + fpga_i2c->dev_name, addr, *val); + return 0; +} + +static int fpga_data_write(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t *val, size_t size) +{ + int ret; + + ret = fpga_device_write(fpga_i2c, addr, val, size); + if (ret < 0) { + FPGA_I2C_ERROR("fpga data write failed, dev name:%s, offset:0x%x, size:%lu.\n", + fpga_i2c->dev_name, addr, size); + return -EIO; + } + + FPGA_I2C_VERBOSE("fpga data write success, dev name:%s, offset:0x%x, size:%lu.\n", + fpga_i2c->dev_name, addr, size); + return 0; +} + +static int fpga_data_read(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t *val, size_t size) +{ + int ret; + + ret = fpga_device_read(fpga_i2c, addr, val, size); + if (ret < 0) { + FPGA_I2C_ERROR("fpga data read failed, dev name:%s, offset:0x%x, size:%lu.\n", + fpga_i2c->dev_name, addr, size); + return -EIO; + } + + FPGA_I2C_VERBOSE("fpga data read success, dev name:%s, offset:0x%x, size:%lu.\n", + fpga_i2c->dev_name, addr, size); + return 0; +} + +static int fpga_reg_write_32(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint32_t val) +{ + int ret; + uint8_t buf[FPGA_REG_WIDTH]; + + mem_clear(buf, sizeof(buf)); + little_endian_dword_to_buf(buf, sizeof(buf), val); + ret = fpga_device_write(fpga_i2c, addr, buf, sizeof(buf)); + if (ret < 0) { + FPGA_I2C_ERROR("fpga reg write failed, dev name: %s, offset: 0x%x, value: 0x%x.\n", + fpga_i2c->dev_name, addr, val); + return -EIO; + } + + FPGA_I2C_VERBOSE("fpga reg write success, dev name: %s, offset: 0x%x, value: 0x%x.\n", + fpga_i2c->dev_name, addr, val); + return 0; +} + +static int fpga_reg_read_32(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint32_t *val) +{ + int ret; + uint8_t buf[FPGA_REG_WIDTH]; + + mem_clear(buf, sizeof(buf)); + ret = fpga_device_read(fpga_i2c, addr, buf, sizeof(buf)); + if (ret < 0) { + FPGA_I2C_ERROR("fpga reg read failed, dev name: %s, offset: 0x%x, ret: %d\n", + fpga_i2c->dev_name, addr, ret); + return -EIO; + } + little_endian_buf_to_dword(buf, sizeof(buf), val); + FPGA_I2C_VERBOSE("fpga reg read success, dev name: %s, offset: 0x%x, value: 0x%x.\n", + fpga_i2c->dev_name, addr, *val); + return 0; +} + +static int fpga_i2c_is_busy(fpga_i2c_dev_t *fpga_i2c) +{ + uint8_t val; + int ret; + fpga_i2c_reg_t *reg; + + reg = &fpga_i2c->reg; + ret = fpga_reg_read(fpga_i2c, reg->i2c_status, &val); + if (ret < 0 ) { + FPGA_I2C_ERROR("read fpga i2c status reg failed, reg addr:0x%x, ret:%d.\n", + reg->i2c_status, ret); + return 1; + } + if (val & FPGA_I2C_STA_BUSY) { + FPGA_I2C_ERROR("fpga i2c status busy, reg addr:0x%x, value:0x%x.\n", + reg->i2c_status, val); + return 1; + } else { + return 0; + } +} + +static int fpga_i2c_wait(fpga_i2c_dev_t *fpga_i2c) +{ + int retry_cnt; + + retry_cnt = FPGA_I2C_XFER_TIME_OUT/FPGA_I2C_SLEEP_TIME; + while (retry_cnt--) { + if (fpga_i2c_is_busy(fpga_i2c)) { + usleep_range(FPGA_I2C_SLEEP_TIME, FPGA_I2C_SLEEP_TIME + 1); + } else { + return 0; + } + } + + return -EBUSY; +} + +static int fpga_i2c_check_status(fpga_i2c_dev_t *fpga_i2c) +{ + uint8_t data; + int ret; + fpga_i2c_reg_t *reg; + + reg = &fpga_i2c->reg; + + ret = fpga_reg_read(fpga_i2c, reg->i2c_status, &data); + if (ret) { + FPGA_I2C_ERROR("read fpga i2c status reg failed, reg addr:0x%x, ret:%d.\n", + reg->i2c_status, ret); + return ret; + } + + if (data & FPGA_I2C_STA_FAIL) { + FPGA_I2C_ERROR("fpga i2c status error, reg addr:0x%x, value:%d.\n", + reg->i2c_status, data); + + /* read i2c_err_vec to confirm err type*/ + if (reg->i2c_err_vec != DTS_NO_CFG_FLAG) { + /* read i2c_err_vec reg */ + ret = fpga_reg_read(fpga_i2c, reg->i2c_err_vec, &data); + if (ret) { + FPGA_I2C_ERROR("read fpga i2c err vec reg failed, reg addr:0x%x, ret:%d.\n", + reg->i2c_err_vec, ret); + return ret; + } + FPGA_I2C_VERBOSE("get i2c err vec, reg addr:0x%x, read value:0x%x\n", reg->i2c_err_vec, data); + + /* match i2c_err_vec reg value and err type*/ + switch (data) { + case FPGA_I2C_STRETCH_TIMEOUT: + ret = -ETIMEDOUT; + break; + case FPGA_I2C_DEADLOCK_FAILED: + ret = -EDEADLK; + break; + case FPGA_I2C_SLAVE_NO_RESPOND: + ret = -ENXIO; + break; + default: + FPGA_I2C_ERROR("get i2c err vec value out of range, reg addr:0x%x, read value:0x%x\n", + reg->i2c_err_vec, data); + ret = -EREMOTEIO; + break; + } + return ret; + } else { + FPGA_I2C_VERBOSE("i2c err vec not config, fpga i2c status check return -1\n"); + return -EREMOTEIO; + } + } + return 0; +} + +static int fpga_i2c_do_work(fpga_i2c_dev_t *fpga_i2c, int i2c_addr, + unsigned char *data, uint32_t length, int is_read) +{ + int ret, i; + uint8_t op, i2c_reg_addr_len; + uint8_t *i2c_read_addr_buf; + fpga_i2c_reg_t *reg; + fpga_i2c_reg_addr_t *i2c_addr_desc; + + reg = &fpga_i2c->reg; + + ret = fpga_reg_write(fpga_i2c, reg->i2c_slave, i2c_addr); + if (ret) { + FPGA_I2C_ERROR("write fpga i2c slave reg failed, reg addr:0x%x, value:0x%x, ret:%d.\n", + reg->i2c_slave, i2c_addr, ret); + goto exit; + } + + i2c_addr_desc = &fpga_i2c->i2c_addr_desc; + i2c_reg_addr_len = i2c_addr_desc->reg_addr_len; + i2c_read_addr_buf = &i2c_addr_desc->read_reg_addr[0]; + + if (i2c_reg_addr_len > 0 && i2c_reg_addr_len <= I2C_REG_MAX_WIDTH) { + ret = fpga_data_write(fpga_i2c, reg->i2c_reg, i2c_read_addr_buf, i2c_reg_addr_len); + if (ret) { + FPGA_I2C_ERROR("write fpga i2c offset reg failed, fpga addr:0x%x, reg len:%d, ret:%d\n", + reg->i2c_reg, i2c_reg_addr_len, ret); + for (i = 0; i < i2c_reg_addr_len; i++) { + FPGA_I2C_ERROR("%02d : %02x\n", i, i2c_read_addr_buf[i]); + } + goto exit; + } + } + + ret = fpga_reg_write_32(fpga_i2c, reg->i2c_data_len, length); + if (ret) { + FPGA_I2C_ERROR("write fpga i2c date len reg failed, reg addr:0x%x, value:0x%x, ret:%d.\n", + reg->i2c_data_len, length, ret); + goto exit; + } + + ret = fpga_reg_write(fpga_i2c, reg->i2c_reg_len, i2c_reg_addr_len); + if (ret) { + FPGA_I2C_ERROR("write fpga i2c reg len reg failed, reg addr:0x%x, value:0x%x, ret:%d.\n", + reg->i2c_reg_len, i2c_reg_addr_len, ret); + goto exit; + } + + if (is_read) { + op = FPGA_I2C_CTL_RD | FPGA_I2C_CTL_BG; + } else { + + ret = fpga_data_write(fpga_i2c, reg->i2c_data_buf, data, length); + if (ret) { + FPGA_I2C_ERROR("write fpga i2c date buf failed, reg addr:0x%x, write len:%d, ret:%d.\n", + reg->i2c_data_buf, length, ret); + goto exit; + } + op = FPGA_I2C_CTL_WR | FPGA_I2C_CTL_BG ; + } + + ret = fpga_reg_write(fpga_i2c, reg->i2c_ctrl, op); + if (ret) { + FPGA_I2C_ERROR("write fpga i2c control reg failed, reg addr:0x%x, value:%d, ret:%d.\n", + reg->i2c_ctrl, op, ret); + goto exit; + } + + ret = fpga_i2c_wait(fpga_i2c); + if (ret) { + FPGA_I2C_ERROR("wait fpga i2c status timeout.\n"); + goto exit; + } + + ret = fpga_i2c_check_status(fpga_i2c); + if (ret) { + FPGA_I2C_ERROR("check fpga i2c status error.\n"); + goto exit; + } + + if (is_read) { + + ret = fpga_data_read(fpga_i2c, reg->i2c_data_buf, data, length); + if (ret) { + FPGA_I2C_ERROR("read fpga i2c data buf failed, reg addr:0x%x, read len:%d, ret:%d.\n", + reg->i2c_data_buf, length, ret); + goto exit; + } + } + +exit: + return ret; +} + +static int fpga_i2c_write(fpga_i2c_dev_t *fpga_i2c, int target, + u8 *data, int length, int i2c_msg_num) +{ + int ret, i; + fpga_i2c_reg_addr_t *i2c_addr_desc; + + if (i2c_msg_num == I2C_READ_MSG_NUM) { + + if (length > I2C_REG_MAX_WIDTH) { + FPGA_I2C_ERROR("read reg addr len %d, more than max length.\n", length); + return -EINVAL; + } + + i2c_addr_desc = &fpga_i2c->i2c_addr_desc; + for (i = 0; i < length; i++) { + i2c_addr_desc->read_reg_addr[i] = data[length -i -1]; + FPGA_I2C_VERBOSE("%02d : %02x\n", i, i2c_addr_desc->read_reg_addr[i]); + } + i2c_addr_desc->reg_addr_len = length; + ret = 0; + } else { + + ret = fpga_i2c_do_work(fpga_i2c, target, data, length, 0); + } + + return ret; +} + +/** + * fpga_i2c_read - receive data from the bus. + * @i2c: The struct fpga_i2c_dev_t. + * @target: Target address. + * @data: Pointer to the location to store the datae . + * @length: Length of the data. + * + * The address is sent over the bus, then the data is read. + * + * Returns 0 on success, otherwise a negative errno. + */ +static int fpga_i2c_read(fpga_i2c_dev_t *fpga_i2c, int target, + u8 *data, int length) +{ + int ret, offset_size; + int i, tmp_val; + fpga_i2c_reg_addr_t *i2c_addr_desc; + uint8_t i2c_reg_addr_len; + uint8_t *i2c_read_addr_buf; + + offset_size = 0; + i2c_addr_desc = &fpga_i2c->i2c_addr_desc; + i2c_reg_addr_len = i2c_addr_desc->reg_addr_len; + i2c_read_addr_buf = &i2c_addr_desc->read_reg_addr[0]; + + while (1) { + if (length <= fpga_i2c->reg.i2c_data_buf_len) { + return fpga_i2c_do_work(fpga_i2c, target, data + offset_size, length, 1); + } + + ret = fpga_i2c_do_work(fpga_i2c, target, data + offset_size, fpga_i2c->reg.i2c_data_buf_len, 1); + if (ret != 0) { + FPGA_I2C_ERROR("fpga_i2c_read failed, i2c addr:0x%x, offset:0x%x, ret:%d.\n", + target, offset_size, ret); + return ret; + } + + tmp_val = i2c_read_addr_buf[0]; + tmp_val += fpga_i2c->reg.i2c_data_buf_len; + if (tmp_val > 0xff) { + i2c_read_addr_buf[0] = tmp_val & 0xff; + for (i = 1; i < i2c_reg_addr_len; i++) { + if (i2c_read_addr_buf[i] == 0xff) { + i2c_read_addr_buf[i] = 0; + } else { + i2c_read_addr_buf[i]++; + break; + } + } + } else { + i2c_read_addr_buf[0] = tmp_val & 0xff; + } + offset_size += fpga_i2c->reg.i2c_data_buf_len; + length -= fpga_i2c->reg.i2c_data_buf_len; + } + + return ret; +} + +static void fpga_i2c_reset(fpga_i2c_dev_t *fpga_i2c) { + fpga_i2c_reset_cfg_t *reset_cfg; + uint32_t reset_addr; + + reset_cfg = &fpga_i2c->reset_cfg; + reset_addr = reset_cfg->reset_addr; + if (reset_cfg->reset_delay_b) { + usleep_range(reset_cfg->reset_delay_b, reset_cfg->reset_delay_b + 1); + } + + fpga_reg_write_32(fpga_i2c, reset_addr, reset_cfg->reset_on); + if (reset_cfg->reset_delay) { + usleep_range(reset_cfg->reset_delay, reset_cfg->reset_delay + 1); + } + + fpga_reg_write_32(fpga_i2c, reset_addr, reset_cfg->reset_off); + if (reset_cfg->reset_delay_a) { + usleep_range(reset_cfg->reset_delay_a, reset_cfg->reset_delay_a + 1); + } + + return; +} + +/** + * fpga_i2c_xfer - The driver's master_xfer function. + * @adap: Pointer to the i2c_adapter structure. + * @msgs: Pointer to the messages to be processed. + * @num: Length of the MSGS array. + * + * Returns the number of messages processed, or a negative errno on + * failure. + */ +static int fpga_i2c_adapter_init(fpga_i2c_dev_t *fpga_i2c) +{ + int ret; + fpga_i2c_reg_t *reg; + + reg = &fpga_i2c->reg; + + ret = 0; + ret += fpga_reg_write(fpga_i2c, reg->i2c_scale, fpga_i2c->i2c_scale_value); + ret += fpga_reg_write(fpga_i2c, reg->i2c_filter, fpga_i2c->i2c_filter_value); + ret += fpga_reg_write(fpga_i2c, reg->i2c_stretch, fpga_i2c->i2c_stretch_value); + if (ret < 0) { + FPGA_I2C_ERROR("fpga_i2c_init failed.\n"); + return ret; + } + + FPGA_I2C_VERBOSE("fpga_i2c_init ok.\n"); + return 0; +} + +static int fpga_i2c_params_check(fpga_i2c_dev_t *fpga_i2c) +{ + int ret; + fpga_i2c_reg_t *reg; + uint8_t i2c_scale_value, i2c_filter_value, i2c_stretch_value; + + reg = &fpga_i2c->reg; + ret = 0; + ret += fpga_reg_read(fpga_i2c, reg->i2c_scale, &i2c_scale_value); + ret += fpga_reg_read(fpga_i2c, reg->i2c_filter, &i2c_filter_value); + ret += fpga_reg_read(fpga_i2c, reg->i2c_stretch, &i2c_stretch_value); + if (ret < 0) { + FPGA_I2C_ERROR("read fpga i2c params failed.\n"); + return 1; + } + + if ((i2c_scale_value != fpga_i2c->i2c_scale_value) + || (i2c_filter_value != fpga_i2c->i2c_filter_value) + || (i2c_stretch_value != fpga_i2c->i2c_stretch_value)) { + FPGA_I2C_ERROR("fpga i2c params check error, read value: i2c_scale 0x%x, i2c_filter:0x%x, i2c_stretch:0x%x.\n", + i2c_scale_value, i2c_filter_value, i2c_stretch_value); + FPGA_I2C_ERROR("fpga i2c params check error, config value: i2c_scale 0x%x, i2c_filter:0x%x, i2c_stretch:0x%x.\n", + fpga_i2c->i2c_scale_value, fpga_i2c->i2c_filter_value, fpga_i2c->i2c_stretch_value); + return 1; + } + + FPGA_I2C_VERBOSE("fpga i2c params check ok.\n"); + return 0; +} + +static int fpga_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct i2c_msg *pmsg; + int i; + int ret; + fpga_i2c_dev_t *fpga_i2c; + fpga_i2c_reg_addr_t *i2c_addr_desc; + + fpga_i2c = i2c_get_adapdata(adap); + + if (num != I2C_READ_MSG_NUM && num != I2C_WRITE_MSG_NUM) { + FPGA_I2C_ERROR("unsupport i2c_msg len:%d.\n", num); + return -EINVAL; + } + + if ((num == I2C_WRITE_MSG_NUM) && (msgs[0].len > fpga_i2c->reg.i2c_data_buf_len)) { + FPGA_I2C_ERROR("unsupport i2c_msg type:msg[0].flag:0x%x, buf len:0x%x.\n", + msgs[0].flags, msgs[0].len); + return -EINVAL; + } + + if (num == I2C_READ_MSG_NUM ) { + if ((msgs[0].flags & I2C_M_RD) ||!(msgs[1].flags & I2C_M_RD)) { + FPGA_I2C_ERROR("unsupport i2c_msg type:msg[0].flag:0x%x, msg[1].flag:0x%x.\n", + msgs[0].flags, msgs[1].flags); + return -EINVAL; + } + } + + if (fpga_i2c_is_busy(fpga_i2c)) { + FPGA_I2C_ERROR("fpga i2c adapter %d is busy, do reset.\n", adap->nr); + if (fpga_i2c->reset_cfg.i2c_adap_reset_flag == 1) { + + fpga_i2c_reset(fpga_i2c); + + fpga_i2c_adapter_init(fpga_i2c); + } + return -EAGAIN; + } + + if (fpga_i2c->i2c_params_check && fpga_i2c_params_check(fpga_i2c)) { + FPGA_I2C_ERROR("fpga i2c params check failed, try to reinitialize.\n"); + fpga_i2c_adapter_init(fpga_i2c); + } + + ret = 0; + i2c_addr_desc = &fpga_i2c->i2c_addr_desc; + i2c_addr_desc->reg_addr_len = 0; + mem_clear(i2c_addr_desc->read_reg_addr, sizeof(i2c_addr_desc->read_reg_addr)); + + for (i = 0; ret == 0 && i < num; i++) { + pmsg = &msgs[i]; + FPGA_I2C_VERBOSE("Doing %s %d byte(s) to/from 0x%02x - %d of %d messages\n", + pmsg->flags & I2C_M_RD ? "read" : "write", pmsg->len, pmsg->addr, i + 1, num); + + if (pmsg->flags & I2C_M_RD) { + ret = fpga_i2c_read(fpga_i2c, pmsg->addr, pmsg->buf, pmsg->len); + + if ((pmsg->len == 1) && (pmsg->flags & I2C_M_RECV_LEN)) { + if ((ret != 0) || (pmsg->buf[0] > I2C_SMBUS_BLOCK_MAX)) { + FPGA_I2C_ERROR("smbus block data read failed, ret:%d, read len:%u.\n", + ret, pmsg->buf[0]); + return -EPROTO; + } + pmsg->len = 1 + pmsg->buf[0]; + FPGA_I2C_VERBOSE("smbus block data read, read len:%d.\n", pmsg->len); + ret = fpga_i2c_read(fpga_i2c, pmsg->addr, pmsg->buf, pmsg->len); + } + } else { + ret = fpga_i2c_write(fpga_i2c, pmsg->addr, pmsg->buf, pmsg->len, num); + } + } + + return (ret != 0) ? ret : num; +} + +static u32 fpga_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; +} + +static const struct i2c_algorithm fpga_i2c_algo = { + .master_xfer = fpga_i2c_xfer, + .functionality = fpga_i2c_functionality, +}; + +static struct i2c_adapter fpga_i2c_ops = { + .owner = THIS_MODULE, + .name = "wb_fpga_i2c", + .algo = &fpga_i2c_algo, +}; + +static int fpga_i2c_config_init(fpga_i2c_dev_t *fpga_i2c) +{ + int ret = 0, rv = 0; + fpga_i2c_reg_t *reg; + fpga_i2c_reset_cfg_t *reset_cfg; + struct device *dev; + uint32_t i2c_offset_reg, i2c_data_buf_len_reg; + int32_t i2c_offset_val; + + fpga_i2c_bus_device_t *fpga_i2c_bus_device; + + dev = fpga_i2c->dev; + reg = &fpga_i2c->reg; + reset_cfg = &fpga_i2c->reset_cfg; + + i2c_offset_val = 0; + + if (dev->of_node) { + ret = 0; + ret += of_property_read_u32(dev->of_node, "i2c_ext_9548_addr", ®->i2c_ext_9548_addr); + ret += of_property_read_u32(dev->of_node, "i2c_ext_9548_chan", ®->i2c_ext_9548_chan); + ret += of_property_read_u32(dev->of_node, "i2c_slave", ®->i2c_slave); + ret += of_property_read_u32(dev->of_node, "i2c_reg", ®->i2c_reg); + ret += of_property_read_u32(dev->of_node, "i2c_data_len", ®->i2c_data_len); + ret += of_property_read_u32(dev->of_node, "i2c_ctrl", ®->i2c_ctrl); + ret += of_property_read_u32(dev->of_node, "i2c_status", ®->i2c_status); + ret += of_property_read_u32(dev->of_node, "i2c_scale", ®->i2c_scale); + ret += of_property_read_u32(dev->of_node, "i2c_filter", ®->i2c_filter); + ret += of_property_read_u32(dev->of_node, "i2c_stretch", ®->i2c_stretch); + ret += of_property_read_u32(dev->of_node, "i2c_ext_9548_exits_flag", ®->i2c_ext_9548_exits_flag); + ret += of_property_read_u32(dev->of_node, "i2c_reg_len", ®->i2c_reg_len); + ret += of_property_read_u32(dev->of_node, "i2c_in_9548_chan", ®->i2c_in_9548_chan); + ret += of_property_read_u32(dev->of_node, "i2c_data_buf", ®->i2c_data_buf); + ret += of_property_read_string(dev->of_node, "dev_name", &fpga_i2c->dev_name); + ret += of_property_read_u32(dev->of_node, "i2c_scale_value", &fpga_i2c->i2c_scale_value); + ret += of_property_read_u32(dev->of_node, "i2c_filter_value", &fpga_i2c->i2c_filter_value); + ret += of_property_read_u32(dev->of_node, "i2c_stretch_value", &fpga_i2c->i2c_stretch_value); + ret += of_property_read_u32(dev->of_node, "i2c_timeout", &fpga_i2c->i2c_timeout); + ret += of_property_read_u32(dev->of_node, "i2c_func_mode", &fpga_i2c->i2c_func_mode); + ret += of_property_read_u32(dev->of_node, "i2c_reset_addr", &reset_cfg->reset_addr); + ret += of_property_read_u32(dev->of_node, "i2c_reset_on", &reset_cfg->reset_on); + ret += of_property_read_u32(dev->of_node, "i2c_reset_off", &reset_cfg->reset_off); + ret += of_property_read_u32(dev->of_node, "i2c_rst_delay_b", &reset_cfg->reset_delay_b); + ret += of_property_read_u32(dev->of_node, "i2c_rst_delay", &reset_cfg->reset_delay); + ret += of_property_read_u32(dev->of_node, "i2c_rst_delay_a", &reset_cfg->reset_delay_a); + ret += of_property_read_u32(dev->of_node, "i2c_adap_reset_flag", &reset_cfg->i2c_adap_reset_flag); + + if (ret != 0) { + FPGA_I2C_ERROR("dts config error, ret:%d.\n", ret); + ret = -ENXIO; + return ret; + } + + rv = of_property_read_u32(dev->of_node, "i2c_data_buf_len_reg", &i2c_data_buf_len_reg); + if (rv == 0) { + ret = fpga_reg_read_32(fpga_i2c, i2c_data_buf_len_reg, ®->i2c_data_buf_len); + if (ret < 0) { + dev_err(fpga_i2c->dev, "Failed to get fpga i2c data buf length, reg addr: 0x%x, ret: %d\n", + i2c_data_buf_len_reg, ret); + return ret; + } + FPGA_I2C_VERBOSE("fpga i2c data buf length reg addr: 0x%x, value: %d\n", + i2c_data_buf_len_reg, reg->i2c_data_buf_len); + if (reg->i2c_data_buf_len == 0) { + reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; + } + } else { + ret = of_property_read_u32(dev->of_node, "i2c_data_buf_len", ®->i2c_data_buf_len); + if (ret != 0) { + reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; + ret = 0; + } + } + + rv = of_property_read_u32(dev->of_node, "i2c_offset_reg", &i2c_offset_reg); + if (rv == 0) { + ret = fpga_reg_read_32(fpga_i2c, i2c_offset_reg, &i2c_offset_val); + if (ret < 0) { + dev_err(fpga_i2c->dev, "Failed to get fpga i2c adapter offset value, reg addr: 0x%x, ret: %d\n", + i2c_offset_reg, ret); + return ret; + } + FPGA_I2C_VERBOSE("fpga i2c adapter offset reg addr: 0x%x, value: %d\n", + i2c_offset_reg, i2c_offset_val); + reg->i2c_scale +=i2c_offset_val; + reg->i2c_filter += i2c_offset_val; + reg->i2c_stretch += i2c_offset_val; + reg->i2c_ext_9548_exits_flag += i2c_offset_val; + reg->i2c_ext_9548_addr += i2c_offset_val; + reg->i2c_ext_9548_chan += i2c_offset_val; + reg->i2c_in_9548_chan += i2c_offset_val; + reg->i2c_slave += i2c_offset_val; + reg->i2c_reg += i2c_offset_val; + reg->i2c_reg_len += i2c_offset_val; + reg->i2c_data_len += i2c_offset_val; + reg->i2c_ctrl += i2c_offset_val; + reg->i2c_status += i2c_offset_val; + reg->i2c_data_buf += i2c_offset_val; + } + + ret = of_property_read_u32(dev->of_node, "i2c_err_vec", ®->i2c_err_vec); + if (ret != 0) { + reg->i2c_err_vec = DTS_NO_CFG_FLAG; + FPGA_I2C_VERBOSE("not support i2c_err_vec cfg. ret: %d, set DTS_NO_CFG_FLAG: %d\n", + ret, reg->i2c_err_vec); + ret = 0; /* Not configuring i2c_err_vec is not an error */ + } else { + if (i2c_offset_val != 0) { + reg->i2c_err_vec += i2c_offset_val; + } + } + } else { + if (dev->platform_data == NULL) { + dev_err(fpga_i2c->dev, "Failed to get platform data config.\n"); + ret = -ENXIO; + return ret; + } + fpga_i2c_bus_device = dev->platform_data; + fpga_i2c->dev_name = fpga_i2c_bus_device->dev_name; + fpga_i2c->adap_nr = fpga_i2c_bus_device->adap_nr; + fpga_i2c->i2c_scale_value = fpga_i2c_bus_device->i2c_scale_value; + fpga_i2c->i2c_filter_value = fpga_i2c_bus_device->i2c_filter_value; + fpga_i2c->i2c_stretch_value = fpga_i2c_bus_device->i2c_stretch_value; + fpga_i2c->i2c_timeout = fpga_i2c_bus_device->i2c_timeout; + fpga_i2c->i2c_func_mode = fpga_i2c_bus_device->i2c_func_mode; + fpga_i2c->i2c_params_check = fpga_i2c_bus_device->i2c_params_check; + + reset_cfg->reset_addr = fpga_i2c_bus_device->i2c_reset_addr; + reset_cfg->reset_on = fpga_i2c_bus_device->i2c_reset_on; + reset_cfg->reset_off = fpga_i2c_bus_device->i2c_reset_off; + reset_cfg->reset_delay_b = fpga_i2c_bus_device->i2c_rst_delay_b; + reset_cfg->reset_delay = fpga_i2c_bus_device->i2c_rst_delay; + reset_cfg->reset_delay_a = fpga_i2c_bus_device->i2c_rst_delay_a; + reset_cfg->i2c_adap_reset_flag = fpga_i2c_bus_device->i2c_adap_reset_flag; + + reg->i2c_ext_9548_addr = fpga_i2c_bus_device->i2c_ext_9548_addr; + reg->i2c_ext_9548_chan = fpga_i2c_bus_device->i2c_ext_9548_chan; + reg->i2c_slave = fpga_i2c_bus_device->i2c_slave; + reg->i2c_reg = fpga_i2c_bus_device->i2c_reg; + reg->i2c_data_len = fpga_i2c_bus_device->i2c_data_len; + reg->i2c_ctrl = fpga_i2c_bus_device->i2c_ctrl; + reg->i2c_status = fpga_i2c_bus_device->i2c_status; + reg->i2c_scale = fpga_i2c_bus_device->i2c_scale; + reg->i2c_filter = fpga_i2c_bus_device->i2c_filter; + reg->i2c_stretch = fpga_i2c_bus_device->i2c_stretch; + reg->i2c_ext_9548_exits_flag = fpga_i2c_bus_device->i2c_ext_9548_exits_flag; + reg->i2c_reg_len = fpga_i2c_bus_device->i2c_reg_len; + reg->i2c_in_9548_chan = fpga_i2c_bus_device->i2c_in_9548_chan; + reg->i2c_data_buf = fpga_i2c_bus_device->i2c_data_buf; + + i2c_data_buf_len_reg = fpga_i2c_bus_device->i2c_data_buf_len_reg; + if (i2c_data_buf_len_reg > 0) { + ret = fpga_reg_read_32(fpga_i2c, i2c_data_buf_len_reg, ®->i2c_data_buf_len); + if (ret < 0) { + dev_err(fpga_i2c->dev, "Failed to get fpga i2c data buf length, reg addr: 0x%x, ret: %d\n", + i2c_data_buf_len_reg, ret); + return ret; + } + FPGA_I2C_VERBOSE("fpga i2c data buf length reg addr: 0x%x, value: %d\n", + i2c_data_buf_len_reg, reg->i2c_data_buf_len); + if (reg->i2c_data_buf_len == 0) { + reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; + } + } else { + if (fpga_i2c_bus_device->i2c_data_buf_len == 0) { + reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; + FPGA_I2C_VERBOSE("not support i2c_data_buf_len cfg, set default_val:%d\n", + reg->i2c_data_buf_len); + } else { + reg->i2c_data_buf_len = fpga_i2c_bus_device->i2c_data_buf_len; + } + } + + i2c_offset_reg = fpga_i2c_bus_device->i2c_offset_reg; + if (i2c_offset_reg > 0) { + rv = fpga_reg_read_32(fpga_i2c, i2c_offset_reg, &i2c_offset_val); + if (rv < 0) { + dev_err(fpga_i2c->dev, "Failed to get fpga i2c adapter offset value, reg addr: 0x%x, rv: %d\n", + i2c_offset_reg, rv); + return rv; + } + FPGA_I2C_VERBOSE("fpga i2c adapter offset reg addr: 0x%x, value: %d\n", + i2c_offset_reg, i2c_offset_val); + reg->i2c_scale +=i2c_offset_val; + reg->i2c_filter += i2c_offset_val; + reg->i2c_stretch += i2c_offset_val; + reg->i2c_ext_9548_exits_flag += i2c_offset_val; + reg->i2c_ext_9548_addr += i2c_offset_val; + reg->i2c_ext_9548_chan += i2c_offset_val; + reg->i2c_in_9548_chan += i2c_offset_val; + reg->i2c_slave += i2c_offset_val; + reg->i2c_reg += i2c_offset_val; + reg->i2c_reg_len += i2c_offset_val; + reg->i2c_data_len += i2c_offset_val; + reg->i2c_ctrl += i2c_offset_val; + reg->i2c_status += i2c_offset_val; + reg->i2c_data_buf += i2c_offset_val; + } + + if (fpga_i2c_bus_device->i2c_err_vec == 0) { + reg->i2c_err_vec = DTS_NO_CFG_FLAG; + FPGA_I2C_VERBOSE("not support i2c_err_vec cfg, set DTS_NO_CFG_FLAG:%d\n", + reg->i2c_err_vec); + } else { + reg->i2c_err_vec = fpga_i2c_bus_device->i2c_err_vec; + if (i2c_offset_val != 0) { + reg->i2c_err_vec += i2c_offset_val; + } + } + } + + FPGA_I2C_VERBOSE("i2c_ext_9548_addr:0x%x, i2c_ext_9548_chan:0x%x, i2c_slave:0x%x, i2c_reg:0x%x, i2c_data_len:0x%x.\n", + reg->i2c_ext_9548_addr, reg->i2c_ext_9548_chan, reg->i2c_slave, reg->i2c_reg, reg->i2c_data_len); + FPGA_I2C_VERBOSE("i2c_ctrl:0x%x, i2c_status:0x%x, i2c_scale:0x%x, i2c_filter:0x%x, i2c_stretch:0x%x.\n", + reg->i2c_ctrl, reg->i2c_status, reg->i2c_scale, reg->i2c_filter, reg->i2c_stretch); + FPGA_I2C_VERBOSE("i2c_ext_9548_exits_flag:0x%x, i2c_in_9548_chan:0x%x, i2c_data_buf:0x%x, i2c_reg_len:0x%x, i2c_data_buf_len:0x%x.\n", + reg->i2c_ext_9548_exits_flag, reg->i2c_in_9548_chan, reg->i2c_data_buf, reg->i2c_reg_len, reg->i2c_data_buf_len); + FPGA_I2C_VERBOSE("dev_name:%s, i2c_scale_value:0x%x, i2c_filter_value:0x%x, i2c_stretch_value:0x%x, i2c_timeout:0x%x.\n", + fpga_i2c->dev_name, fpga_i2c->i2c_scale_value, fpga_i2c->i2c_filter_value, fpga_i2c->i2c_stretch_value, fpga_i2c->i2c_timeout); + FPGA_I2C_VERBOSE("i2c_reset_addr:0x%x, i2c_reset_on:0x%x, i2c_reset_off:0x%x, i2c_rst_delay_b:0x%x, i2c_rst_delay:0x%x, i2c_rst_delay_a:0x%x.\n", + reset_cfg->reset_addr, reset_cfg->reset_on, reset_cfg->reset_off, reset_cfg->reset_delay_b, reset_cfg->reset_delay, reset_cfg->reset_delay_a); + FPGA_I2C_VERBOSE("i2c_adap_reset_flag:0x%x.\n", reset_cfg->i2c_adap_reset_flag); + FPGA_I2C_VERBOSE("i2c_err_vec:0x%x\n", reg->i2c_err_vec); + + return ret; +} + +static int fpga_i2c_probe(struct platform_device *pdev) +{ + int ret; + fpga_i2c_dev_t *fpga_i2c; + struct device *dev; + + fpga_i2c = devm_kzalloc(&pdev->dev, sizeof(fpga_i2c_dev_t), GFP_KERNEL); + if (!fpga_i2c) { + dev_err(&pdev->dev, "devm_kzalloc failed.\n"); + ret = -ENOMEM; + goto out; + } + + fpga_i2c->dev = &pdev->dev; + + ret = fpga_i2c_config_init(fpga_i2c); + if (ret !=0) { + dev_err(fpga_i2c->dev, "Failed to get fpga i2c dts config.\n"); + goto out; + } + + ret = fpga_i2c_adapter_init(fpga_i2c); + if (ret !=0) { + dev_err(fpga_i2c->dev, "Failed to init fpga i2c adapter.\n"); + goto out; + } + + if (fpga_i2c->dev->of_node) { + fpga_i2c->i2c_params_check = of_property_read_bool(fpga_i2c->dev->of_node, "i2c_params_check"); + } + FPGA_I2C_VERBOSE("fpga i2c params check flag:%d.\n", fpga_i2c->i2c_params_check); + + init_waitqueue_head(&fpga_i2c->queue); + + dev = fpga_i2c->dev; + fpga_i2c->adap = fpga_i2c_ops; + fpga_i2c->adap.timeout = msecs_to_jiffies(fpga_i2c->i2c_timeout); + fpga_i2c->adap.dev.parent = &pdev->dev; + fpga_i2c->adap.dev.of_node = pdev->dev.of_node; + i2c_set_adapdata(&fpga_i2c->adap, fpga_i2c); + platform_set_drvdata(pdev, fpga_i2c); + + if (fpga_i2c->dev->of_node) { + /* adap.nr get from dts aliases */ + ret = i2c_add_adapter(&fpga_i2c->adap); + } else { + fpga_i2c->adap.nr = fpga_i2c->adap_nr; + ret = i2c_add_numbered_adapter(&fpga_i2c->adap); + } + + if (ret < 0) { + dev_info(fpga_i2c->dev, "Failed to add adapter.\n"); + goto fail_add; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) + of_i2c_register_devices(&fpga_i2c->adap); +#endif + dev_info(fpga_i2c->dev, "registered i2c-%d for %s using mode %d with base address:0x%x, data buf len: %d success.\n", + fpga_i2c->adap.nr, fpga_i2c->dev_name, fpga_i2c->i2c_func_mode, fpga_i2c->reg.i2c_scale, + fpga_i2c->reg.i2c_data_buf_len); + return 0; + +fail_add: + platform_set_drvdata(pdev, NULL); +out: + return ret; +}; + +static int fpga_i2c_remove(struct platform_device *pdev) +{ + fpga_i2c_dev_t *fpga_i2c; + + fpga_i2c = platform_get_drvdata(pdev); + i2c_del_adapter(&fpga_i2c->adap); + platform_set_drvdata(pdev, NULL); + return 0; +}; + +static struct of_device_id fpga_i2c_match[] = { + { + .compatible = "wb-fpga-i2c", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, fpga_i2c_match); + +static struct platform_driver wb_fpga_i2c_driver = { + .probe = fpga_i2c_probe, + .remove = fpga_i2c_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .of_match_table = fpga_i2c_match, + }, +}; + +static int __init wb_fpga_i2c_init(void) +{ + return platform_driver_register(&wb_fpga_i2c_driver); +} + +static void __exit wb_fpga_i2c_exit(void) +{ + platform_driver_unregister(&wb_fpga_i2c_driver); +} + +module_init(wb_fpga_i2c_init); +module_exit(wb_fpga_i2c_exit); +MODULE_DESCRIPTION("fpga i2c adapter driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pca954x_drv.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pca954x_drv.c new file mode 100644 index 000000000000..8fd9e4f0f1b4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pca954x_drv.c @@ -0,0 +1,534 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fpga_i2c.h" + +extern int i2c_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); +extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); +extern int spi_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); + +#define PCA954X_MAX_NCHANS (8) +#define FPGA_INTERNAL_PCA9548 (1) +#define FPGA_EXTERNAL_PCA9548 (2) +#define FPGA_I2C_EXT_9548_EXITS (0x01 << 0) +#define FPGA_I2C_9548_NO_RESET (0x01 << 1) + +#define SYMBOL_I2C_DEV_MODE (1) +#define FILE_MODE (2) +#define SYMBOL_PCIE_DEV_MODE (3) +#define SYMBOL_IO_DEV_MODE (4) +#define SYMBOL_SPI_DEV_MODE (5) + +int g_fpga_pca954x_debug = 0; +int g_fpga_pca954x_error = 0; + +module_param(g_fpga_pca954x_debug, int, S_IRUGO | S_IWUSR); +module_param(g_fpga_pca954x_error, int, S_IRUGO | S_IWUSR); + +#define FPGA_PCA954X_VERBOSE(fmt, args...) do { \ + if (g_fpga_pca954x_debug) { \ + printk(KERN_INFO "[FPGA_PCA954X][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define FPGA_PCA954X_ERROR(fmt, args...) do { \ + if (g_fpga_pca954x_error) { \ + printk(KERN_ERR "[FPGA_PCA954X][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +enum pca_type { + pca_9540, + pca_9541, + pca_9542, + pca_9543, + pca_9544, + pca_9545, + pca_9546, + pca_9547, + pca_9548, +}; + +struct pca954x { + enum pca_type type; + struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS]; + u8 last_chan; /* last register value */ + uint32_t fpga_9548_flag; + uint32_t fpga_9548_reset_flag; + uint32_t pca9548_base_nr; + struct i2c_client *client; +}; + +struct chip_desc { + u8 nchans; + u8 enable; /* used for muxes only */ + enum muxtype { + pca954x_ismux = 0, + pca954x_isswi + } muxtype; +}; + +/* Provide specs for the PCA954x types we know about */ +static const struct chip_desc chips[] = { + [pca_9540] = { + .nchans = 2, + .enable = 0x4, + .muxtype = pca954x_ismux, + }, + [pca_9541] = { + .nchans = 1, + .muxtype = pca954x_isswi, + }, + [pca_9543] = { + .nchans = 2, + .muxtype = pca954x_isswi, + }, + [pca_9544] = { + .nchans = 4, + .enable = 0x4, + .muxtype = pca954x_ismux, + }, + [pca_9545] = { + .nchans = 4, + .muxtype = pca954x_isswi, + }, + [pca_9547] = { + .nchans = 8, + .enable = 0x8, + .muxtype = pca954x_ismux, + }, + [pca_9548] = { + .nchans = 8, + .muxtype = pca954x_isswi, + }, +}; + +static const struct i2c_device_id fpga_pca954x_id[] = { + { "wb_fpga_pca9540", pca_9540 }, + { "wb_fpga_pca9541", pca_9541 }, + { "wb_fpga_pca9542", pca_9543 }, + { "wb_fpga_pca9543", pca_9543 }, + { "wb_fpga_pca9544", pca_9544 }, + { "wb_fpga_pca9545", pca_9545 }, + { "wb_fpga_pca9546", pca_9545 }, + { "wb_fpga_pca9547", pca_9547 }, + { "wb_fpga_pca9548", pca_9548 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, fpga_pca954x_id); + +static int fpga_file_write(const char *path, int pos, unsigned char *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + filp = filp_open(path, O_RDWR, 777); + if (IS_ERR(filp)) { + FPGA_PCA954X_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + ret = kernel_write(filp, val, size, &tmp_pos); + if (ret < 0) { + FPGA_PCA954X_ERROR("kernel_write failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + vfs_fsync(filp, 1); + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; + +} + +static int fpga_device_write(fpga_i2c_dev_t *fpga_i2c, int pos, unsigned char *val, size_t size) +{ + int ret; + + switch (fpga_i2c->i2c_func_mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + case FILE_MODE: + ret = fpga_file_write(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_SPI_DEV_MODE: + ret = spi_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + default: + FPGA_PCA954X_ERROR("err func_mode %d, write failed.\n", fpga_i2c->i2c_func_mode); + return -EINVAL; + } + return ret; +} + +static int fpga_reg_write(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t val) +{ + int ret; + + ret = fpga_device_write(fpga_i2c, addr, &val, sizeof(uint8_t)); + if (ret < 0) { + FPGA_PCA954X_ERROR("fpga_device_write failed. name:%s, addr:0x%x, value:0x%x.\n", + fpga_i2c->dev_name, addr, val); + return ret; + } + + FPGA_PCA954X_VERBOSE("fpga reg write success, dev name:%s, offset:0x%x, value:0x%x.\n", + fpga_i2c->dev_name, addr, val); + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,7) +static int pca954x_select_chan(struct i2c_adapter *adap, void *client, u32 chan) +{ + struct pca954x *data = i2c_get_clientdata(client); + fpga_i2c_dev_t *fpga_i2c; + fpga_i2c_reg_t *reg; + int ret; + u8 regval, i2c_9548_opt; + + while(i2c_parent_is_i2c_adapter(adap)){ + adap = to_i2c_adapter(adap->dev.parent); + } + + FPGA_PCA954X_VERBOSE("root bus:%d, chan:0x%x, 9548 flag:0x%x, 9548 addr:0x%x.\n", + adap->nr, chan, data->fpga_9548_flag, client->addr); + fpga_i2c = i2c_get_adapdata(adap); + reg = &fpga_i2c->reg; + + regval = 1 << chan; + if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { + ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, regval); + } else { + if (data->fpga_9548_reset_flag == 1) { + i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS & ~(FPGA_I2C_9548_NO_RESET); + } else { + i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS | FPGA_I2C_9548_NO_RESET; + } + FPGA_PCA954X_VERBOSE("fpga pca9548 reset flag:0x%x, opt:0x%x.\n", + data->fpga_9548_reset_flag, i2c_9548_opt); + ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, i2c_9548_opt); + ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_addr, client->addr); + ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, regval); + } + + return ret; +} + +static int pca954x_deselect_mux(struct i2c_adapter *adap, void *client, u32 chan) +{ + struct pca954x *data = i2c_get_clientdata(client); + fpga_i2c_dev_t *fpga_i2c; + fpga_i2c_reg_t *reg; + int ret; + + while(i2c_parent_is_i2c_adapter(adap)){ + adap = to_i2c_adapter(adap->dev.parent); + } + + fpga_i2c = i2c_get_adapdata(adap); + reg = &fpga_i2c->reg; + /* Deselect active channel */ + data->last_chan = 0; + if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { + ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, 0); + } else { + + ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, FPGA_I2C_9548_NO_RESET); + ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, 0); + } + + return ret; +} +#else +static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca954x *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + struct i2c_adapter *adap; + fpga_i2c_dev_t *fpga_i2c; + fpga_i2c_reg_t *reg; + int ret; + u8 regval, i2c_9548_opt; + + adap = muxc->parent; + while(i2c_parent_is_i2c_adapter(adap)){ + adap = to_i2c_adapter(adap->dev.parent); + } + + FPGA_PCA954X_VERBOSE("root bus:%d, chan:0x%x, 9548 flag:0x%x, 9548 addr:0x%x.\n", + adap->nr, chan, data->fpga_9548_flag, client->addr); + fpga_i2c = i2c_get_adapdata(adap); + reg = &fpga_i2c->reg; + + regval = 1 << chan; + if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { + ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, regval); + } else { + if (data->fpga_9548_reset_flag == 1) { + i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS & ~(FPGA_I2C_9548_NO_RESET); + } else { + i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS | FPGA_I2C_9548_NO_RESET; + } + FPGA_PCA954X_VERBOSE("fpga pca9548 reset flag:0x%x, opt:0x%x.\n", + data->fpga_9548_reset_flag, i2c_9548_opt); + ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, i2c_9548_opt); + ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_addr, client->addr); + ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, regval); + } + + return ret; +} + +static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca954x *data = i2c_mux_priv(muxc); + struct i2c_adapter *adap; + fpga_i2c_dev_t *fpga_i2c; + fpga_i2c_reg_t *reg; + int ret; + + adap = muxc->parent; + while(i2c_parent_is_i2c_adapter(adap)){ + adap = to_i2c_adapter(adap->dev.parent); + } + + fpga_i2c = i2c_get_adapdata(adap); + reg = &fpga_i2c->reg; + ret = 0; + /* Deselect active channel */ + data->last_chan = 0; + + if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { + ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, 0); + } else { + + ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, FPGA_I2C_9548_NO_RESET); + ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, 0); + } + + return ret; +} +#endif +/* + * I2C init/probing/exit functions + */ +static int fpga_i2c_pca954x_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + int num, force, class; + struct pca954x *data; + int ret = -ENODEV; + struct device *dev; + int dynamic_nr = 1; + fpga_pca954x_device_t *fpga_pca954x_device; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(4,6,7) + struct i2c_mux_core *muxc; +#endif + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) { + dev_err(&client->dev, "i2c adapter:%d, unsupport I2C_FUNC_SMBUS_BYTE.\n", adap->nr); + goto err; + } + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) + data = kzalloc(sizeof(struct pca954x), GFP_KERNEL); + if (!data) { + dev_err(&client->dev, "kzalloc failed.\n"); + ret = -ENOMEM; + goto err; + } + + i2c_set_clientdata(client, data); +#else + muxc = i2c_mux_alloc(adap, &client->dev, + PCA954X_MAX_NCHANS, sizeof(*data), 0, + pca954x_select_chan, pca954x_deselect_mux); + if (!muxc) { + dev_err(&client->dev, "i2c_mux_alloc failed.\n"); + return -ENOMEM; + } + data = i2c_mux_priv(muxc); + i2c_set_clientdata(client, muxc); + data->client = client; +#endif + + dev = &client->dev; + if (dev == NULL) { + dev_err(&client->dev, "dev is NULL.\n"); + ret = -ENODEV; + goto exit_free; + } + + if (dev->of_node == NULL) { + if (client->dev.platform_data == NULL) { + dev_err(&client->dev, "Failed to get 954x platform data config.\n"); + ret = -EINVAL; + goto exit_free; + } + fpga_pca954x_device = client->dev.platform_data; + data->fpga_9548_flag = fpga_pca954x_device->fpga_9548_flag; + data->fpga_9548_reset_flag = fpga_pca954x_device->fpga_9548_reset_flag; + data->pca9548_base_nr = fpga_pca954x_device->pca9548_base_nr; + if (data->pca9548_base_nr == 0) { + + dynamic_nr = 1; + } else { + dynamic_nr = 0; + FPGA_PCA954X_VERBOSE("pca9548_base_nr:%u.\n", data->pca9548_base_nr); + } + } else { + data->type = id->driver_data; + /* BUS ID */ + ret = of_property_read_u32(dev->of_node, "fpga_9548_flag", &data->fpga_9548_flag); + ret += of_property_read_u32(dev->of_node, "fpga_9548_reset_flag", &data->fpga_9548_reset_flag); + if (ret != 0) { + dev_err(&client->dev, "Failed to get 954x dts config, ret:%d.\n", ret); + ret = -EINVAL; + goto exit_free; + } + if (of_property_read_u32(dev->of_node, "pca9548_base_nr", &data->pca9548_base_nr)) { + + dynamic_nr = 1; + FPGA_PCA954X_VERBOSE("pca9548_base_nr not found, use dynamic adap number"); + } else { + dynamic_nr = 0; + FPGA_PCA954X_VERBOSE("pca9548_base_nr:%u.\n", data->pca9548_base_nr); + } + } + + if (data->fpga_9548_flag != FPGA_EXTERNAL_PCA9548 && data->fpga_9548_flag != FPGA_INTERNAL_PCA9548) { + dev_err(&client->dev, "Error: fpga 954x flag config error, value:0x%x.\n", data->fpga_9548_flag); + ret = -EINVAL; + goto exit_free; + } + + data->type = id->driver_data; + data->last_chan = 0; /* force the first selection */ + + /* Now create an adapter for each channel */ + for (num = 0; num < chips[data->type].nchans; num++) { + if (dynamic_nr == 1) { + force = 0; /* dynamic adap number */ + } else { + force = data->pca9548_base_nr + num; + } + class = 0; /* no class by default */ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) + data->virt_adaps[num] = + i2c_add_mux_adapter(adap, &client->dev, client, + force, num, class, pca954x_select_chan, pca954x_deselect_mux); + + if (data->virt_adaps[num] == NULL) { + ret = -ENODEV; + dev_err(&client->dev, "Failed to register multiplexed adapter %d as bus %d\n", + num, force); + goto virt_reg_failed; + } +#else + ret = i2c_mux_add_adapter(muxc, force, num, class); + if (ret) { + dev_err(&client->dev, "Failed to register multiplexed adapter %d as bus %d\n", + num, force); + goto virt_reg_failed; + } +#endif + } /* end for num = 0; num < chips[data->type].nchans... */ + + dev_info(&client->dev, "registered %d multiplexed busses for I2C %s %s\n", + num, chips[data->type].muxtype == pca954x_ismux ? "mux" : "switch", client->name); + + return 0; + +virt_reg_failed: +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) + for (num--; num >= 0; num--) + i2c_del_mux_adapter(data->virt_adaps[num]); +exit_free: + kfree(data); +#else +exit_free: + i2c_mux_del_adapters(muxc); +#endif +err: + return ret; +} + +static int fpga_i2c_pca954x_remove(struct i2c_client *client) +{ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) + struct pca954x *data = i2c_get_clientdata(client); + const struct chip_desc *chip = &chips[data->type]; + int i; + + for (i = 0; i < chip->nchans; ++i) + if (data->virt_adaps[i]) { + i2c_del_mux_adapter(data->virt_adaps[i]); + data->virt_adaps[i] = NULL; + } + + kfree(data); +#else + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + + i2c_mux_del_adapters(muxc); +#endif + + return 0; +} + +static struct i2c_driver fpga_i2c_pca954x_driver = { + .driver = { + .name = "wb_fpga_pca954x", + .owner = THIS_MODULE, + }, + .probe = fpga_i2c_pca954x_probe, + .remove = fpga_i2c_pca954x_remove, + .id_table = fpga_pca954x_id, +}; + +static int __init fpga_i2c_pca954x_init(void) +{ + int ret; + + ret = i2c_add_driver(&fpga_i2c_pca954x_driver); + return ret; +} + +static void __exit fpga_i2c_pca954x_exit(void) +{ + i2c_del_driver(&fpga_i2c_pca954x_driver); +} + +module_init(fpga_i2c_pca954x_init); +module_exit(fpga_i2c_pca954x_exit); +MODULE_DESCRIPTION("fpga pca954x driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pcie.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pcie.c new file mode 100644 index 000000000000..aedcc78dab90 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pcie.c @@ -0,0 +1,164 @@ +/* + * wb_fpga_pcie.c + * ko to enable fpga pcie + */ +#include +#include +#include +#include +#include + +#define FPGA_MSI_IRQ_NUM (14) +#define FPGA_MSI_IRQ_BEGIN (0) +#define XILINX_FPGA_USE_MSI (0) +#define XILINX_FPGA_NUSE_MSI (1) + +int g_fpga_pcie_dev_debug = 0; +int g_fpga_pcie_dev_error = 0; +module_param(g_fpga_pcie_dev_debug, int, S_IRUGO | S_IWUSR); +module_param(g_fpga_pcie_dev_error, int, S_IRUGO | S_IWUSR); + +#define FPGA_PCIE_DEV_VERBOSE(fmt, args...) do { \ + if (g_fpga_pcie_dev_debug) { \ + printk(KERN_INFO "[FPGA_PCIE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define FPGA_PCIE_DEV_ERROR(fmt, args...) do { \ + if (g_fpga_pcie_dev_error) { \ + printk(KERN_ERR "[FPGA_PCIE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +typedef struct wb_fpga_pcie_s { + struct pci_dev *pci_dev; + int driver_data; +} wb_fpga_pcie_t; + +static void fpga_pcie_recover(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct resource *mem_base; + u32 bar0_val; + int ret; + + mem_base = &pdev->resource[0]; + ret = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0_val); + if (ret) { + FPGA_PCIE_DEV_ERROR("pci_read_config_dword failed ret %d.\n", ret); + return; + } + FPGA_PCIE_DEV_VERBOSE("mem_base->start[0x%llx], bar0_val[0x%x], ret %d.\n", + mem_base->start, bar0_val, ret); + + if (bar0_val != mem_base->start) { + ret = pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, mem_base->start); + if (ret) { + FPGA_PCIE_DEV_ERROR("pci_write_config_dword mem_base->start[0x%llx], failed ret %d.\n", mem_base->start, ret); + return; + } + FPGA_PCIE_DEV_VERBOSE("pci_write_config_dword mem_base->start[0x%llx] success.\n", mem_base->start); + } else { + FPGA_PCIE_DEV_VERBOSE("mem_base->start[0x%llx], bar0_val[0x%x], do nothing.\n", + mem_base->start, bar0_val); + } +} + +static int fpga_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int err; + wb_fpga_pcie_t *wb_fpga_pcie; + + FPGA_PCIE_DEV_VERBOSE("Enter vendor 0x%x, subsystem_vendor 0x%x.\n", pdev->vendor, pdev->subsystem_vendor); + + wb_fpga_pcie = devm_kzalloc(&pdev->dev, sizeof(wb_fpga_pcie_t), GFP_KERNEL); + if (!wb_fpga_pcie) { + dev_err(&pdev->dev, "devm_kzalloc failed.\n"); + return -ENOMEM; + } + + fpga_pcie_recover(pdev, id); + + /* enable device: ask low-level code to enable I/O and memory */ + FPGA_PCIE_DEV_VERBOSE("start pci_enable_device!\n"); + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Failed to enable pci device, ret:%d.\n", err); + return err; + } + + FPGA_PCIE_DEV_VERBOSE("start pci_set_master!\n"); + pci_set_master(pdev); + + wb_fpga_pcie->driver_data = id->driver_data; + wb_fpga_pcie->pci_dev = pdev; + pci_set_drvdata(pdev, wb_fpga_pcie); + + if (wb_fpga_pcie->driver_data == XILINX_FPGA_USE_MSI) { + FPGA_PCIE_DEV_VERBOSE("start pci_enable_msi_range!\n"); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,152) + err = pci_enable_msi_range(pdev, FPGA_MSI_IRQ_BEGIN + 1, FPGA_MSI_IRQ_NUM); +#else + err = pci_alloc_irq_vectors_affinity(pdev, FPGA_MSI_IRQ_BEGIN + 1, + FPGA_MSI_IRQ_NUM, PCI_IRQ_MSI, NULL); +#endif + if (err != FPGA_MSI_IRQ_NUM) { + FPGA_PCIE_DEV_ERROR("pci_enable_msi_block err %d FPGA_MSI_IRQ_NUM %d.\n", err, + FPGA_MSI_IRQ_NUM); + dev_err(&pdev->dev, "Failed to enable pci msi, ret:%d.\n", err); + return -EINVAL; + } + } + + dev_info(&pdev->dev, "fpga pci device init success.\n"); + return 0; +} + +static void fpga_pcie_remove(struct pci_dev *pdev) +{ + wb_fpga_pcie_t *wb_fpga_pcie; + + FPGA_PCIE_DEV_VERBOSE("fpga_pcie_remove.\n"); + + wb_fpga_pcie = pci_get_drvdata(pdev); + if (wb_fpga_pcie->driver_data == XILINX_FPGA_USE_MSI) { + FPGA_PCIE_DEV_VERBOSE("start pci_disable_msi!\n"); + pci_disable_msi(pdev); + } + + pci_disable_device(pdev); + return; +} + +static const struct pci_device_id fpga_pci_ids[] = { + { PCI_DEVICE(0x10ee, 0x7022), .driver_data = XILINX_FPGA_USE_MSI}, + { PCI_DEVICE(0x10ee, 0x7011), .driver_data = XILINX_FPGA_NUSE_MSI}, + {0} +}; +MODULE_DEVICE_TABLE(pci, fpga_pci_ids); + +static struct pci_driver wb_fpga_pcie_driver = { + .name = "wb_fpga_pcie", + .id_table = fpga_pci_ids,/* only dynamic id's */ + .probe = fpga_pcie_probe, + .remove = fpga_pcie_remove, +}; + +static int __init wb_fpga_pcie_init(void) +{ + + FPGA_PCIE_DEV_VERBOSE("wb_fpga_pcie_init enter!\n"); + return pci_register_driver(&wb_fpga_pcie_driver); +} + +static void __exit wb_fpga_pcie_exit(void) +{ + FPGA_PCIE_DEV_VERBOSE("wb_fpga_pcie_exit enter!\n"); + pci_unregister_driver(&wb_fpga_pcie_driver); + return; +} + +module_init(wb_fpga_pcie_init); +module_exit(wb_fpga_pcie_exit); +MODULE_DESCRIPTION("fpga pcie driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_d1500.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_d1500.c new file mode 100644 index 000000000000..7d5d5da87ea7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_d1500.c @@ -0,0 +1,367 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2011, 2012 Cavium Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPIO_NAME "wb_gpio_d1500" + +#define GPIO_BASE (0x500) +#define GP_IO_SEL (GPIO_BASE + 0x4) +#define GP_LVL (GPIO_BASE + 0xC) +#define GPI_NMI_EN (GPIO_BASE + 0x28) +#define GPI_NMI_STS (GPIO_BASE + 0x2a) +#define GPI_INV (GPIO_BASE + 0x2c) +#define GPIO_USE_SEL2 (GPIO_BASE + 0x30) +#define GP_IO_SEL2 (GPIO_BASE + 0x34) +#define GP_LVL2 (GPIO_BASE + 0x38) +#define GPI_NMI_EN_2 (GPIO_BASE + 0x3c) +#define GPI_NMI_STS_2 (GPIO_BASE + 0x3e) +#define GPIO_USE_SEL3 (GPIO_BASE + 0x40) +#define GP_IO_SEL3 (GPIO_BASE + 0x44) +#define GP_LVL3 (GPIO_BASE + 0x48) +#define GPI_NMI_EN_3 (GPIO_BASE + 0x50) +#define GPI_NMI_STS_3 (GPIO_BASE + 0x54) + +#define GPIO_BASE_ID (0) +#define BANKSIZE (32) +#define D1500_GPIO_PIN_NUM (96) +#define CELL_NUM (2) + +int g_gpio_d1500_debug = 0; +int g_gpio_d1500_error = 0; +module_param(g_gpio_d1500_debug, int, S_IRUGO | S_IWUSR); +module_param(g_gpio_d1500_error, int, S_IRUGO | S_IWUSR); + +#define GPIO_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_gpio_d1500_debug) { \ + printk(KERN_ERR "[GPIO-D1500][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define GPIO_DEBUG_ERROR(fmt, args...) do { \ + if (g_gpio_d1500_error) { \ + printk(KERN_ERR "[GPIO-D1500][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static DEFINE_SPINLOCK(sio_lock); + +struct gpio_d1500_t { + struct gpio_chip chip; + u64 register_base; +}; + +static int wb_gpio_get(struct gpio_chip *gc, unsigned gpio_num) +{ + u32 data = 0; + unsigned int bank, offset; + unsigned long flags; + + bank = gpio_num / BANKSIZE; + offset = gpio_num % BANKSIZE; + + spin_lock_irqsave(&sio_lock, flags); + if (bank == 0) { + data = inl(GP_LVL) & (1 << offset); + if (data) { + data = 1; + } + } else if (bank == 1) { + data = inl(GP_LVL2) & (1 << offset); + if (data) { + data = 1; + } + } else if (bank == 2) { + data = inl(GP_LVL3) & (1 << offset); + if (data) { + data = 1; + } + } + spin_unlock_irqrestore(&sio_lock, flags); + + return data; +} + +static int wb_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num) +{ + u32 data; + unsigned int bank, offset; + unsigned long flags; + + bank = gpio_num / BANKSIZE; + offset = gpio_num % BANKSIZE; + + spin_lock_irqsave(&sio_lock, flags); + if (bank == 0) { + data = inl(GP_IO_SEL); + data = data | (1 << offset); + outl(data, GP_IO_SEL); + } else if (bank == 1) { + data = inl(GP_IO_SEL2); + data = data | (1 << offset); + outl(data, GP_IO_SEL2); + } else if (bank == 2) { + data = inl(GP_IO_SEL3); + data = data | (1 << offset); + outl(data, GP_IO_SEL3); + } + spin_unlock_irqrestore(&sio_lock, flags); + + return 0; +} + +static void wb_gpio_set(struct gpio_chip *gc, + unsigned gpio_num, int val) +{ + u32 data; + unsigned int bank, offset; + unsigned long flags; + + bank = gpio_num / BANKSIZE; + offset = gpio_num % BANKSIZE; + + spin_lock_irqsave(&sio_lock, flags); + if (bank == 0) { + data = inl(GP_LVL); + if (val) { + data = data | (1 << offset); + } else { + data = data & ~(1 << offset); + } + outl(data, GP_LVL); + } else if (bank == 1) { + data = inl(GP_LVL2); + if (val) { + data = data | (1 << offset); + } else { + data = data & ~(1 << offset); + } + outl(data, GP_LVL2); + } else if (bank == 2) { + data = inl(GP_LVL3); + if (val) { + data = data | (1 << offset); + } else { + data = data & ~(1 << offset); + } + outl(data, GP_LVL3); + } + spin_unlock_irqrestore(&sio_lock, flags); + + return; +} + +static int wb_gpio_direction_out(struct gpio_chip *gc, + unsigned gpio_num, int val) +{ + u32 data; + unsigned int bank, offset; + unsigned long flags; + + bank = gpio_num / BANKSIZE; + offset = gpio_num % BANKSIZE; + + spin_lock_irqsave(&sio_lock, flags); + if (bank == 0) { + data = inl(GP_IO_SEL); + data = data & ~(1 << offset); + outl(data, GP_IO_SEL); + + data = inl(GP_LVL); + if (val) { + data = data | (1 << offset); + } else { + data = data & ~(1 << offset); + } + outl(data, GP_LVL); + } else if (bank == 1) { + data = inl(GP_IO_SEL2); + data = data & ~(1 << offset); + outl(data, GP_IO_SEL2); + + data = inl(GP_LVL2); + if (val) { + data = data | (1 << offset); + } else { + data = data & ~(1 << offset); + } + outl(data, GP_LVL2); + } else if (bank == 2) { + data = inl(GP_IO_SEL3); + data = data & ~(1 << offset); + outl(data, GP_IO_SEL3); + + data = inl(GP_LVL3); + if (val) { + data = data | (1 << offset); + } else { + data = data & ~(1 << offset); + } + outl(data, GP_LVL3); + } + spin_unlock_irqrestore(&sio_lock, flags); + + return 0; +} + +#ifdef CONFIG_OF +static int wb_gpio_of_xlate(struct gpio_chip *chip, + const struct of_phandle_args *gpio_desc, + u32 *flags) +{ + if (chip->of_gpio_n_cells < 2) { + return -EINVAL; + } + + if (flags) { + *flags = gpio_desc->args[1]; + } + + return gpio_desc->args[0]; +} +#endif + +static int wb_gpio_request(struct gpio_chip *chip, unsigned int offset) +{ + u32 data; + unsigned int bank, tmp_offset; + unsigned long flags; + + bank = offset / BANKSIZE; + tmp_offset = offset % BANKSIZE; + + spin_lock_irqsave(&sio_lock, flags); + if (bank == 0) { + data = inl(GPIO_BASE); + data = data | (1 << tmp_offset); + outl(data, GPIO_BASE); + } else if (bank == 1) { + data = inl(GPIO_USE_SEL2); + data = data | (1 << tmp_offset); + outl(data, GPIO_USE_SEL2); + } else if (bank == 2) { + data = inl(GPIO_USE_SEL3); + data = data | (1 << tmp_offset); + outl(data, GPIO_USE_SEL3); + } + spin_unlock_irqrestore(&sio_lock, flags); + + return 0; +} + +#if 0 +static void wb_gpio_free(struct gpio_chip *chip, unsigned int offset) +{ + u32 data; + unsigned int bank, tmp_offset; + unsigned long flags; + + bank = offset / BANKSIZE; + tmp_offset = offset % BANKSIZE; + + spin_lock_irqsave(&sio_lock, flags); + if (bank == 0) { + data = inl(GPIO_BASE); + data = data & ~(1 << tmp_offset); + outl(data, GPIO_BASE); + } else if (bank == 1) { + data = inl(GPIO_USE_SEL2); + data = data & ~(1 << tmp_offset); + outl(data, GPIO_USE_SEL2); + } else if (bank == 2) { + data = inl(GPIO_USE_SEL3); + data = data & ~(1 << tmp_offset); + outl(data, GPIO_USE_SEL3); + } + + spin_unlock_irqrestore(&sio_lock, flags); + + return; +} +#endif + +static struct gpio_chip wb_gpio_chip = { + .label = GPIO_NAME, + .owner = THIS_MODULE, + .base = GPIO_BASE_ID, + .get = wb_gpio_get, + .direction_input = wb_gpio_direction_in, + .set = wb_gpio_set, + .direction_output = wb_gpio_direction_out, +#ifdef CONFIG_OF + .of_xlate = wb_gpio_of_xlate, +#endif + .request = wb_gpio_request, + .ngpio = D1500_GPIO_PIN_NUM, +#ifdef CONFIG_OF + .of_gpio_n_cells = CELL_NUM, +#endif + .can_sleep = false, +}; + +static int wb_gpio_probe(struct platform_device *pdev) +{ + struct gpio_d1500_t *gpio; + int err; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) { + dev_err(&pdev->dev, "gpio kzalloc failed\n"); + return -ENOMEM; + } + + wb_gpio_chip.parent = &pdev->dev; + gpio->register_base = GPIO_BASE; + gpio->chip = wb_gpio_chip; + pdev->dev.platform_data = &wb_gpio_chip; + err = devm_gpiochip_add_data(&pdev->dev, &wb_gpio_chip, gpio); + if (err) { + dev_err(&pdev->dev, "gpiochip add failed\n"); + return err; + } + + dev_info(&pdev->dev, "register %llu gpio success.\n", gpio->register_base); + + return 0; +} + +static int wb_gpio_remove(struct platform_device *pdev) +{ + dev_info(&pdev->dev, "unregister d1500 gpio success\n"); + return 0; +} + +static const struct of_device_id gpio_d1500_match[] = { + { + .compatible = "wb_gpio_d1500", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, gpio_d1500_match); + +static struct platform_driver wb_gpio_driver = { + .driver = { + .name = GPIO_NAME, + .of_match_table = gpio_d1500_match, + }, + .probe = wb_gpio_probe, + .remove = wb_gpio_remove, +}; + +module_platform_driver(wb_gpio_driver); + +MODULE_DESCRIPTION("d1500 gpio driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_device.c new file mode 100644 index 000000000000..75f883b5909d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_device.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include + +static int g_wb_gpio_device_debug = 0; +static int g_wb_gpio_device_error = 0; + +module_param(g_wb_gpio_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_gpio_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_GPIO_DEVICE_VERBOSE(fmt, args...) do { \ + if (g_wb_gpio_device_debug) { \ + printk(KERN_INFO "[WB_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_GPIO_DEVICE_ERROR(fmt, args...) do { \ + if (g_wb_gpio_device_error) { \ + printk(KERN_ERR "[WB_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static void wb_gpio_device_release(struct device *dev) +{ + return; +} + +static struct platform_device wb_gpio_d1500_device = { + .name = "wb_gpio_d1500", + .id = -1, + .dev = { + .release = wb_gpio_device_release, + }, +}; + +static int __init wb_gpio_device_init(void) +{ + WB_GPIO_DEVICE_VERBOSE("wb_gpio_device_init enter!\n"); + return platform_device_register(&wb_gpio_d1500_device); +} + +static void __exit wb_gpio_device_exit(void) +{ + WB_GPIO_DEVICE_VERBOSE("wb_gpio_device_exit enter!\n"); + return platform_device_unregister(&wb_gpio_d1500_device); +} + +module_init(wb_gpio_device_init); +module_exit(wb_gpio_device_exit); +MODULE_DESCRIPTION("GPIO Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.c new file mode 100644 index 000000000000..4abdccabeda9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.c @@ -0,0 +1,815 @@ +/* + * wb_io_dev.c + * ko to read/write i2c client through /dev/XXX device + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_i2c_dev.h" + +#define MAX_I2C_DEV_NUM (256) +#define FPGA_MAX_LEN (256) +#define MAX_NAME_SIZE (20) +#define MAX_BUS_WIDTH (16) +#define TRANSFER_WRITE_BUFF (FPGA_MAX_LEN + MAX_BUS_WIDTH) + +#define WIDTH_1Byte (1) +#define WIDTH_2Byte (2) +#define WIDTH_4Byte (4) + +static int g_i2c_dev_debug = 0; +static int g_i2c_dev_error = 0; + +module_param(g_i2c_dev_debug, int, S_IRUGO | S_IWUSR); +module_param(g_i2c_dev_error, int, S_IRUGO | S_IWUSR); + +#define I2C_DEV_DEBUG_DMESG(fmt, args...) do { \ + if (g_i2c_dev_debug) { \ + printk(KERN_ERR "[I2C_DEV][DEBUG][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define I2C_DEV_DEBUG_ERROR(fmt, args...) do { \ + if (g_i2c_dev_error) { \ + printk(KERN_ERR "[I2C_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static struct i2c_dev_info* i2c_dev_arry[MAX_I2C_DEV_NUM]; + +struct i2c_dev_info { + const char *name; + uint32_t data_bus_width; + uint32_t addr_bus_width; + uint32_t per_rd_len; + uint32_t per_wr_len; + uint32_t i2c_len; + struct miscdevice misc; + struct i2c_client *client; +}; + +static int transfer_read(struct i2c_client *client, u8 *buf, loff_t regaddr, size_t count) +{ + struct i2c_adapter *adap; + union i2c_smbus_data data; + int i, j; + u8 offset_buf[MAX_BUS_WIDTH]; + struct i2c_msg msgs[2]; + int msgs_num, ret; + struct i2c_dev_info *i2c_dev; + u8 offset; + u8 length; + + if (!client) { + I2C_DEV_DEBUG_ERROR("can't get read client\n"); + return -ENODEV; + } + + adap = client->adapter; + if (!adap) { + I2C_DEV_DEBUG_ERROR("can't get read adap\n"); + return -ENODEV; + } + + i2c_dev = i2c_get_clientdata(client); + if (!i2c_dev) { + I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\n"); + return -ENODEV; + } + + i = 0; + + mem_clear(offset_buf, sizeof(offset_buf)); + + switch (i2c_dev->addr_bus_width) { + case WIDTH_4Byte: + offset_buf[i++] = (regaddr >> 24) & 0xFF; + offset_buf[i++] = (regaddr >> 16) & 0xFF; + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_2Byte: + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_1Byte: + offset_buf[i++] = regaddr & 0xFF; + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\n", + i2c_dev->addr_bus_width); + return -EINVAL; + } + + if (adap->algo->master_xfer) { + mem_clear(msgs, sizeof(msgs)); + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = i2c_dev->addr_bus_width; + msgs[0].buf = offset_buf; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = count; + msgs[1].buf = buf; + + msgs_num = 2; + ret = i2c_transfer(client->adapter, msgs, msgs_num); + if (ret != msgs_num) { + I2C_DEV_DEBUG_ERROR("i2c_transfer read error\n"); + return -EINVAL; + } + } else { + if (i2c_dev->addr_bus_width == WIDTH_1Byte) { + offset = regaddr & 0xFF; + if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + for (j = 0; j < count; j += I2C_SMBUS_BLOCK_MAX) { + if (count - j > I2C_SMBUS_BLOCK_MAX) { + length = I2C_SMBUS_BLOCK_MAX; + } else { + length = count - j; + } + data.block[0] = length; + ret = adap->algo->smbus_xfer(adap, client->addr, + 0, + I2C_SMBUS_READ, + offset, I2C_SMBUS_I2C_BLOCK_DATA, &data); + if (ret) { + I2C_DEV_DEBUG_ERROR("smbus_xfer read block error, ret = %d\n", ret); + return -EFAULT; + } + memcpy(buf + j, data.block + 1, length); + offset += length; + } + } else { + for (j = 0; j < count; j++) { + ret = adap->algo->smbus_xfer(adap, client->addr, + 0, + I2C_SMBUS_READ, + offset, I2C_SMBUS_BYTE_DATA, &data); + + if (!ret) { + buf[j] = data.byte; + } else { + I2C_DEV_DEBUG_ERROR("smbus_xfer read byte error, ret = %d\n", ret); + return -EFAULT; + } + offset++; + } + } + } else { + I2C_DEV_DEBUG_ERROR("smbus_xfer not support addr_bus_width = %d\n", i2c_dev->addr_bus_width); + return -EINVAL; + } + } + return 0; +} + +static int transfer_write(struct i2c_client *client, u8 *buf, loff_t regaddr, size_t count) +{ + struct i2c_adapter *adap; + int i; + u8 offset_buf[TRANSFER_WRITE_BUFF]; + struct i2c_msg msgs[1]; + int msgs_num, ret; + struct i2c_dev_info *i2c_dev; + + if (!client) { + I2C_DEV_DEBUG_ERROR("can't get write client\n"); + return -ENODEV; + } + + adap = client->adapter; + if (!adap) { + I2C_DEV_DEBUG_ERROR("can't get write adap\n"); + return -ENODEV; + } + + i2c_dev = i2c_get_clientdata(client); + if (!i2c_dev) { + I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\n"); + return -ENODEV; + } + + i = 0; + + mem_clear(offset_buf, sizeof(offset_buf)); + + switch (i2c_dev->addr_bus_width) { + case WIDTH_4Byte: + offset_buf[i++] = (regaddr >> 24) & 0xFF; + offset_buf[i++] = (regaddr >> 16) & 0xFF; + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_2Byte: + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_1Byte: + offset_buf[i++] = regaddr & 0xFF; + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\n", + i2c_dev->addr_bus_width); + return -EINVAL; + } + + memcpy(offset_buf + i2c_dev->addr_bus_width, buf, count); + + if (adap->algo->master_xfer) { + mem_clear(msgs, sizeof(msgs)); + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = i2c_dev->addr_bus_width + count; + msgs[0].buf = offset_buf; + + msgs_num = 1; + ret = i2c_transfer(adap, msgs, msgs_num); + if (ret != msgs_num) { + I2C_DEV_DEBUG_ERROR("i2c_transfer write error\n"); + return -EINVAL; + } + } else { + I2C_DEV_DEBUG_ERROR("don't find write master_xfer\n"); + return -EINVAL; + } + + return 0; +} + +static long i2c_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static int i2c_dev_open(struct inode *inode, struct file *file) +{ + unsigned int minor = iminor(inode); + struct i2c_dev_info *i2c_dev; + + i2c_dev = i2c_dev_arry[minor]; + if (i2c_dev == NULL) { + return -ENODEV; + } + + file->private_data = i2c_dev; + + return 0; +} + +static int i2c_dev_release(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + + return 0; +} + +static int device_read(struct i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int i, j, ret; + u8 tmp_offset; + u8 val[FPGA_MAX_LEN]; + u32 width, rd_len, per_len, tmp; + u32 max_per_len; + + if (offset > i2c_dev->i2c_len) { + I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, count: %lu, EOF.\n", + offset, i2c_dev->i2c_len, count); + return 0; + } + + if (count > (i2c_dev->i2c_len - offset)) { + I2C_DEV_DEBUG_DMESG("read count out of range. input len:%lu, read len:%u.\n", + count, i2c_dev->i2c_len - offset); + count = i2c_dev->i2c_len - offset; + } + + if (count == 0) { + I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, read len: %lu, EOF.\n", + offset, i2c_dev->i2c_len, count); + return 0; + } + + width = i2c_dev->data_bus_width; + switch (width) { + case WIDTH_4Byte: + tmp_offset = offset & 0x3; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", + width, offset, count); + return -EINVAL; + } + break; + case WIDTH_2Byte: + tmp_offset = offset & 0x1; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", + width, offset, count); + return -EINVAL; + } + break; + case WIDTH_1Byte: + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\n", width); + return -EINVAL; + } + + max_per_len = i2c_dev->per_rd_len; + tmp = (width - 1) & count; + rd_len = (tmp == 0) ? count : count + width - tmp; + per_len = (rd_len > max_per_len) ? (max_per_len) : (rd_len); + + mem_clear(val, sizeof(val)); + for (i = 0; i < rd_len; i += per_len) { + ret = transfer_read(i2c_dev->client, val + i, offset + i, per_len); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("read error.read offset = %u\n", (offset + i)); + return -EFAULT; + } + } + + if (width == WIDTH_1Byte) { + memcpy(buf, val, count); + } else { + for (i = 0; i < count; i += width) { + for (j = 0; (j < width) && (i + j < count); j++) { + buf[i + j] = val[i + width - j - 1]; + } + } + } + + return count; +} + +static int device_write(struct i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int i, j, ret; + u8 tmp_offset; + u32 width; + u8 val[FPGA_MAX_LEN]; + u32 wr_len, per_len, tmp; + u32 max_per_len; + + if (offset > i2c_dev->i2c_len) { + I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, count: %lu, EOF.\n", + offset, i2c_dev->i2c_len, count); + return 0; + } + + if (count > (i2c_dev->i2c_len - offset)) { + I2C_DEV_DEBUG_DMESG("read count out of range. input len:%lu, read len:%u.\n", + count, i2c_dev->i2c_len - offset); + count = i2c_dev->i2c_len - offset; + } + + if (count == 0) { + I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, read len: %lu, EOF.\n", + offset, i2c_dev->i2c_len, count); + return 0; + } + + width = i2c_dev->data_bus_width; + switch (width) { + case WIDTH_4Byte: + tmp_offset = offset & 0x3; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", + width, offset, count); + return -EINVAL; + } + break; + case WIDTH_2Byte: + tmp_offset = offset & 0x1; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", + width, offset, count); + return -EINVAL; + } + break; + case WIDTH_1Byte: + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\n", width); + return -EINVAL; + } + + mem_clear(val, sizeof(val)); + + if (width == WIDTH_1Byte) { + memcpy(val, buf, count); + } else { + for (i = 0; i < count; i += width) { + for (j = 0; (j < width) && (i + j < count); j++) { + val[i + width - j - 1] = buf[i + j]; + } + } + } + + max_per_len = i2c_dev->per_wr_len; + tmp = (width - 1) & count; + wr_len = (tmp == 0) ? count : count + width - tmp; + per_len = (wr_len > max_per_len) ? (max_per_len) : (wr_len); + + for (i = 0; i < wr_len; i += per_len) { + ret = transfer_write(i2c_dev->client, val + i, offset + i, per_len); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("write error.offset = %u\n", (offset + i)); + return -EFAULT; + } + } + return count; +} + +static ssize_t i2c_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) +{ + u8 val[FPGA_MAX_LEN]; + int ret, read_len; + struct i2c_dev_info *i2c_dev; + + i2c_dev = file->private_data; + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("can't get read private_data.\n"); + return -EINVAL; + } + + if (count == 0) { + I2C_DEV_DEBUG_ERROR("Invalid params, read count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(val)) { + I2C_DEV_DEBUG_DMESG("read count %lu exceed max %lu.\n", count, sizeof(val)); + count = sizeof(val); + } + + mem_clear(val, sizeof(val)); + read_len = device_read(i2c_dev, (uint32_t)*offset, val, count); + if (read_len < 0) { + I2C_DEV_DEBUG_ERROR("i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", + i2c_dev->name, (uint32_t)*offset, count); + return read_len; + } + + if (access_ok(buf, read_len)) { + I2C_DEV_DEBUG_DMESG("user space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + if (copy_to_user(buf, val, read_len)) { + I2C_DEV_DEBUG_ERROR("copy_to_user failed.\n"); + return -EFAULT; + } + } else { + I2C_DEV_DEBUG_DMESG("kernel space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + memcpy(buf, val, read_len); + } + + *offset += read_len; + ret = read_len; + return ret; +} + +static ssize_t i2c_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) +{ + int ret; + + I2C_DEV_DEBUG_DMESG("i2c_dev_read_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, to->count, iocb->ki_pos); + ret = i2c_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos); + return ret; +} + +static ssize_t i2c_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) +{ + u8 val[FPGA_MAX_LEN]; + int write_len; + struct i2c_dev_info *i2c_dev; + + i2c_dev = file->private_data; + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("get write private_data error.\n"); + return -EINVAL; + } + + if (count == 0) { + I2C_DEV_DEBUG_ERROR("Invalid params, write count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(val)) { + I2C_DEV_DEBUG_DMESG("write count %lu exceed max %lu.\n", count, sizeof(val)); + count = sizeof(val); + } + + mem_clear(val, sizeof(val)); + if (access_ok(buf, count)) { + I2C_DEV_DEBUG_DMESG("user space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + if (copy_from_user(val, buf, count)) { + I2C_DEV_DEBUG_ERROR("copy_from_user failed.\n"); + return -EFAULT; + } + } else { + I2C_DEV_DEBUG_DMESG("kernel space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + memcpy(val, buf, count); + } + + write_len = device_write(i2c_dev, (uint32_t)*offset, val, count); + if (write_len < 0) { + I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%llx, len:%lu.\n", + i2c_dev->name, *offset, count); + return write_len; + } + + *offset += write_len; + return write_len; +} + +static ssize_t i2c_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) +{ + int ret; + + I2C_DEV_DEBUG_DMESG("i2c_dev_write_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, from->count, iocb->ki_pos); + ret = i2c_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos); + return ret; +} + +static loff_t i2c_dev_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t ret = 0; + struct i2c_dev_info *i2c_dev; + + i2c_dev = file->private_data; + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("i2c_dev is NULL, llseek failed.\n"); + return -EINVAL; + } + + switch (origin) { + case SEEK_SET: + if (offset < 0) { + I2C_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); + ret = -EINVAL; + break; + } + if (offset > i2c_dev->i2c_len) { + I2C_DEV_DEBUG_ERROR("SEEK_SET out of range, offset:%lld, i2c_len:0x%x.\n", + offset, i2c_dev->i2c_len); + ret = - EINVAL; + break; + } + file->f_pos = offset; + ret = file->f_pos; + break; + case SEEK_CUR: + if (((file->f_pos + offset) > i2c_dev->i2c_len) || ((file->f_pos + offset) < 0)) { + I2C_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld, i2c_len:0x%x.\n", + file->f_pos, offset, i2c_dev->i2c_len); + ret = - EINVAL; + break; + } + file->f_pos += offset; + ret = file->f_pos; + break; + default: + I2C_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); + ret = -EINVAL; + break; + } + return ret; +} + +static const struct file_operations i2c_dev_fops = { + .owner = THIS_MODULE, + .llseek = i2c_dev_llseek, + .read_iter = i2c_dev_read_iter, + .write_iter = i2c_dev_write_iter, + .unlocked_ioctl = i2c_dev_ioctl, + .open = i2c_dev_open, + .release = i2c_dev_release, +}; + +static struct i2c_dev_info * dev_match(const char *path) +{ + struct i2c_dev_info * i2c_dev; + char dev_name[MAX_NAME_SIZE]; + int i; + for (i = 0; i < MAX_I2C_DEV_NUM; i++) { + if (i2c_dev_arry[ i ] == NULL) { + continue; + } + i2c_dev = i2c_dev_arry[ i ]; + snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", i2c_dev->name); + if (!strcmp(path, dev_name)) { + I2C_DEV_DEBUG_DMESG("get dev_name = %s, minor = %d\n", dev_name, i); + return i2c_dev; + } + } + + return NULL; +} + +int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + struct i2c_dev_info *i2c_dev = NULL; + int ret; + + if(path == NULL){ + I2C_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if(buf == NULL){ + I2C_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + if (count > FPGA_MAX_LEN) { + I2C_DEV_DEBUG_ERROR("read count %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); + return -EINVAL; + } + + i2c_dev = dev_match(path); + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + ret = device_read(i2c_dev, offset, buf, count); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("fpga i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", + i2c_dev->name, offset, count); + return -EINVAL; + } + + return count; +} +EXPORT_SYMBOL(i2c_device_func_read); + +int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + struct i2c_dev_info *i2c_dev = NULL; + int ret; + + if(path == NULL){ + I2C_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if(buf == NULL){ + I2C_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + if (count > FPGA_MAX_LEN) { + I2C_DEV_DEBUG_ERROR("write count %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); + return -EINVAL; + } + + i2c_dev = dev_match(path); + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + ret = device_write (i2c_dev, offset, buf, count); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%x, len:%lu.\n", + i2c_dev->name, offset, count); + return -EINVAL; + } + + return count; +} +EXPORT_SYMBOL(i2c_device_func_write); + +static int i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret = 0; + struct i2c_dev_info *i2c_dev; + struct miscdevice *misc; + i2c_dev_device_t *i2c_dev_device; + + i2c_dev = devm_kzalloc(&client->dev, sizeof(struct i2c_dev_info), GFP_KERNEL); + if (!i2c_dev) { + dev_err(&client->dev, "devm_kzalloc error. \n"); + return -ENOMEM; + } + + i2c_set_clientdata(client, i2c_dev); + i2c_dev->client = client; + + if (client->dev.of_node) { + + ret += of_property_read_string(client->dev.of_node, "i2c_name", &i2c_dev->name); + ret += of_property_read_u32(client->dev.of_node, "data_bus_width", &i2c_dev->data_bus_width); + ret += of_property_read_u32(client->dev.of_node, "addr_bus_width", &i2c_dev->addr_bus_width); + ret += of_property_read_u32(client->dev.of_node, "per_rd_len", &i2c_dev->per_rd_len); + ret += of_property_read_u32(client->dev.of_node, "per_wr_len", &i2c_dev->per_wr_len); + ret += of_property_read_u32(client->dev.of_node, "i2c_len", &i2c_dev->i2c_len); + if (ret != 0) { + dev_err(&client->dev, "dts config error.ret:%d.\n", ret); + return -ENXIO; + } + } else { + if (client->dev.platform_data == NULL) { + dev_err(&client->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + i2c_dev_device = client->dev.platform_data; + i2c_dev->name = i2c_dev_device->i2c_name; + i2c_dev->data_bus_width = i2c_dev_device->data_bus_width; + i2c_dev->addr_bus_width = i2c_dev_device->addr_bus_width; + i2c_dev->per_rd_len = i2c_dev_device->per_rd_len; + i2c_dev->per_wr_len = i2c_dev_device->per_wr_len; + i2c_dev->i2c_len = i2c_dev_device->i2c_len; + } + + if ((i2c_dev->per_rd_len & (i2c_dev->data_bus_width - 1)) || + (i2c_dev->per_wr_len & (i2c_dev->data_bus_width - 1))) { + dev_err(&client->dev, "Invalid config per_rd_len %d per_wr_len %d data bus_width %d.\n", + i2c_dev->per_rd_len, i2c_dev->per_wr_len, i2c_dev->data_bus_width); + return -ENXIO; + } + + if ((i2c_dev->i2c_len == 0) || (i2c_dev->i2c_len & (i2c_dev->data_bus_width - 1))) { + dev_err(&client->dev, "Invalid config i2c_len %d, data bus_width %d.\n", + i2c_dev->i2c_len, i2c_dev->data_bus_width); + return -ENXIO; + } + + misc = &i2c_dev->misc; + misc->minor = MISC_DYNAMIC_MINOR; + misc->name = i2c_dev->name; + misc->fops = &i2c_dev_fops; + misc->mode = 0666; + if (misc_register(misc) != 0) { + dev_err(&client->dev, "register %s faild.\n", misc->name); + return -ENXIO; + } + + if (misc->minor >= MAX_I2C_DEV_NUM) { + dev_err(&client->dev, "minor number beyond the limit! is %d.\n", misc->minor); + misc_deregister(misc); + return -ENXIO; + } + i2c_dev_arry[misc->minor] = i2c_dev; + + dev_info(&client->dev, "register %u addr_bus_width %u data_bus_width 0x%x i2c_len device %s with %u per_rd_len %u per_wr_len success.\n", + i2c_dev->addr_bus_width, i2c_dev->data_bus_width, i2c_dev->i2c_len, i2c_dev->name, i2c_dev->per_rd_len, i2c_dev->per_wr_len); + + return 0; +} + +static int i2c_dev_remove(struct i2c_client *client) +{ + int i; + for (i = 0; i < MAX_I2C_DEV_NUM; i++) { + if (i2c_dev_arry[i] != NULL) { + misc_deregister(&i2c_dev_arry[i]->misc); + i2c_dev_arry[i] = NULL; + } + } + return 0; +} + +static const struct i2c_device_id i2c_dev_id[] = { + { "wb-i2c-dev", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, i2c_dev_id); + +static const struct of_device_id i2c_dev_of_match[] = { + { .compatible = "wb-i2c-dev" }, + { }, +}; +MODULE_DEVICE_TABLE(of, i2c_dev_of_match); + +static struct i2c_driver i2c_dev_driver = { + .driver = { + .name = "wb-i2c-dev", + .of_match_table = i2c_dev_of_match, + }, + .probe = i2c_dev_probe, + .remove = i2c_dev_remove, + .id_table = i2c_dev_id, +}; +module_i2c_driver(i2c_dev_driver); + +MODULE_DESCRIPTION("i2c dev driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.h new file mode 100644 index 000000000000..9cc95d88e804 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.h @@ -0,0 +1,20 @@ +#ifndef __WB_I2C_DEV_H__ +#define __WB_I2C_DEV_H__ +#include + +#define mem_clear(data, size) memset((data), 0, (size)) +#define I2C_DEV_NAME_MAX_LEN (64) + +typedef struct i2c_dev_device_s { + struct i2c_client *client; + uint32_t i2c_bus; + uint32_t i2c_addr; + char i2c_name[I2C_DEV_NAME_MAX_LEN]; + uint32_t data_bus_width; + uint32_t addr_bus_width; + uint32_t per_rd_len; + uint32_t per_wr_len; + uint32_t i2c_len; +} i2c_dev_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.c new file mode 100644 index 000000000000..1f69d96bad0b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.c @@ -0,0 +1,1143 @@ +// 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 +#include +#include + +#include "wb_i2c_ocores.h" + +#define OCORES_FLAG_POLL BIT(0) + +/* 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 OCORE_WAIT_SCH (40) +#define REG_IO_WIDTH_1 (1) +#define REG_IO_WIDTH_2 (2) +#define REG_IO_WIDTH_4 (4) + +#define SYMBOL_I2C_DEV_MODE (1) +#define FILE_MODE (2) +#define SYMBOL_PCIE_DEV_MODE (3) +#define SYMBOL_IO_DEV_MODE (4) + +typedef struct wb_pci_dev_s { + uint32_t domain; + uint32_t bus; + uint32_t slot; + uint32_t fn; +} wb_pci_dev_t; + +/* + * 'process_lock' exists because ocores_process() and ocores_process_timeout() + * can't run in parallel. + */ +struct ocores_i2c { + uint32_t base_addr; + uint32_t reg_shift; + uint32_t reg_io_width; + unsigned long flags; + wait_queue_head_t wait; + struct i2c_adapter adap; + int adap_nr; + struct i2c_msg *msg; + int pos; + int nmsgs; + int state; + spinlock_t process_lock; + uint32_t ip_clock_khz; + uint32_t bus_clock_khz; + void (*setreg)(struct ocores_i2c *i2c, int reg, u32 value); + u32 (*getreg)(struct ocores_i2c *i2c, int reg); + const char *dev_name; + uint32_t reg_access_mode; + uint32_t big_endian; + uint32_t irq_offset; + wb_pci_dev_t wb_pci_dev; + struct device *dev; +}; + +int g_wb_ocores_i2c_debug = 0; +int g_wb_ocores_i2c_error = 0; +int g_wb_ocores_i2c_xfer = 0; + +module_param(g_wb_ocores_i2c_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_ocores_i2c_error, int, S_IRUGO | S_IWUSR); +module_param(g_wb_ocores_i2c_xfer, int, S_IRUGO | S_IWUSR); + +#define OCORES_I2C_VERBOSE(fmt, args...) do { \ + if (g_wb_ocores_i2c_debug) { \ + printk(KERN_INFO "[OCORES_I2C][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define OCORES_I2C_ERROR(fmt, args...) do { \ + if (g_wb_ocores_i2c_error) { \ + printk(KERN_ERR "[OCORES_I2C][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define OCORES_I2C_XFER(fmt, args...) do { \ + if (g_wb_ocores_i2c_xfer) { \ + printk(KERN_INFO "[OCORES_I2C][XFER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +extern int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +#if 0 +int __attribute__((weak)) i2c_device_func_read(const char *path, uint32_t offset, + uint8_t *buf, size_t count) +{ + OCORES_I2C_ERROR("enter __weak i2c func read\r\n"); + return -EINVAL; +} + +int __attribute__((weak)) i2c_device_func_write(const char *path, uint32_t offset, + uint8_t *buf, size_t count) +{ + OCORES_I2C_ERROR("enter __weak i2c func write\r\n"); + return -EINVAL; +} + +int __attribute__((weak)) pcie_device_func_read(const char *path, uint32_t offset, + uint8_t *buf, size_t count) +{ + OCORES_I2C_ERROR("enter __weak pcie func read\r\n"); + return -EINVAL; +} + +int __attribute__((weak)) pcie_device_func_write(const char *path, uint32_t offset, + uint8_t *buf, size_t count) +{ + OCORES_I2C_ERROR("enter __weak pcie func write\r\n"); + return -EINVAL; +} + +int __attribute__((weak)) io_device_func_read(const char *path, uint32_t offset, + uint8_t *buf, size_t count) +{ + OCORES_I2C_ERROR("enter __weak io func read\r\n"); + return -EINVAL; +} + +int __attribute__((weak)) io_device_func_write(const char *path, uint32_t offset, + uint8_t *buf, size_t count) +{ + OCORES_I2C_ERROR("enter __weak io func write\r\n"); + return -EINVAL; +} +#endif +static int ocores_i2c_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + filp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(filp)) { + OCORES_I2C_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + ret = kernel_read(filp, val, size, &tmp_pos); + if (ret < 0) { + OCORES_I2C_ERROR("kernel_read failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int ocores_i2c_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + + int ret; + struct file *filp; + loff_t tmp_pos; + + filp = filp_open(path, O_RDWR, 777); + if (IS_ERR(filp)) { + OCORES_I2C_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + ret = kernel_write(filp, val, size, &tmp_pos); + if (ret < 0) { + OCORES_I2C_ERROR("kernel_write failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + vfs_fsync(filp, 1); + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int ocores_i2c_reg_write(struct ocores_i2c *i2c, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + + switch (i2c->reg_access_mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_write(i2c->dev_name, pos, val, size); + break; + case FILE_MODE: + ret = ocores_i2c_file_write(i2c->dev_name, pos, val, size); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_write(i2c->dev_name, pos, val, size); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_write(i2c->dev_name, pos, val, size); + break; + default: + OCORES_I2C_ERROR("err func_mode, write failed.\n"); + return -EINVAL; + } + + return ret; +} + +static int ocores_i2c_reg_read(struct ocores_i2c *i2c, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + + switch (i2c->reg_access_mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_read(i2c->dev_name, pos, val, size); + break; + case FILE_MODE: + ret = ocores_i2c_file_read(i2c->dev_name, pos, val, size); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_read(i2c->dev_name, pos, val, size); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_read(i2c->dev_name, pos, val, size); + break; + default: + OCORES_I2C_ERROR("err func_mode, read failed.\n"); + return -EINVAL; + } + + return ret; +} +static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_1]; + u32 pos; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + + buf_tmp[0] = (value & 0Xff); + ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_1); + return; +} + +static void oc_setreg_16(struct ocores_i2c *i2c, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 pos; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + + buf_tmp[0] = (value & 0Xff); + buf_tmp[1] = (value >> 8) & 0xff; + ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_2); + return; +} + +static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 pos; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + + buf_tmp[0] = (value & 0xff); + buf_tmp[1] = (value >> 8) & 0xff; + buf_tmp[2] = (value >> 16) & 0xff; + buf_tmp[3] = (value >> 24) & 0xff; + + ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_4); + return; +} + +static void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 pos; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + + buf_tmp[0] = (value >> 8) & 0xff; + buf_tmp[1] = (value & 0Xff); + ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_2); + return; +} + +static void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 pos; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + + buf_tmp[0] = (value >> 24) & 0xff; + buf_tmp[1] = (value >> 16) & 0xff; + buf_tmp[2] = (value >> 8) & 0xff; + buf_tmp[3] = (value & 0xff); + ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_4); + return; +} + +static inline u32 oc_getreg_8(struct ocores_i2c *i2c, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_1]; + u32 value, pos; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_1); + value = buf_tmp[0]; + + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + + return value; +} + +static inline u32 oc_getreg_16(struct ocores_i2c *i2c, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 value, pos; + int i; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + mem_clear(buf_tmp, sizeof(buf_tmp)); + ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_2); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_2 ; i++) { + value |= buf_tmp[i] << (8 * i); + } + + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + return value; +} + +static inline u32 oc_getreg_32(struct ocores_i2c *i2c, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 value, pos; + int i; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + mem_clear(buf_tmp, sizeof(buf_tmp)); + ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_4); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_4 ; i++) { + value |= buf_tmp[i] << (8 * i); + } + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + return value; +} + +static inline u32 oc_getreg_16be(struct ocores_i2c *i2c, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 value, pos; + int i; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + + mem_clear(buf_tmp, sizeof(buf_tmp)); + ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_2); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_2 ; i++) { + value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_2 -i - 1)); + } + + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + return value; +} + +static inline u32 oc_getreg_32be(struct ocores_i2c *i2c, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 value, pos; + int i; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + + mem_clear(buf_tmp, sizeof(buf_tmp)); + ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_4); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_4 ; i++) { + value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_4 -i - 1)); + } + + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + return value; + +} + +static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u32 value) +{ + i2c->setreg(i2c, reg, value); + return; +} + +static inline u32 oc_getreg(struct ocores_i2c *i2c, int reg) +{ + return i2c->getreg(i2c, reg); +} + +static int ocores_msg_check(struct i2c_msg *msgs, int num) +{ + int i, ret = 0; + + if (!msgs) { + ret = -EFAULT; + goto out; + } + + for (i = 0; i < num; ++i) { + if (!msgs[i].buf) { + ret = -EFAULT; + goto out; + } + } + +out: + return ret; +} + +static void ocores_process(struct ocores_i2c *i2c, u8 stat) +{ + struct i2c_msg *msg = i2c->msg; + + OCORES_I2C_XFER("Enter nr %d.\n", i2c->adap.nr); + 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); + OCORES_I2C_XFER("stop has been sent, exit.\n"); + goto out; + } + + /* error? */ + if (stat & OCI2C_STAT_ARBLOST) { + i2c->state = STATE_ERROR; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + OCORES_I2C_XFER("error exit, lose arbitration.\n"); + goto out; + } + + if (ocores_msg_check(i2c->msg, i2c->nmsgs) != 0) { + OCORES_I2C_XFER("msg buf is NULL\n"); + i2c->state = STATE_ERROR; + 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; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + OCORES_I2C_XFER("OCI2C_STAT_NACK, exit.\n"); + goto out; + } + } else { + msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA); + } + + /* end of msg? */ + if (i2c->pos == msg->len) { + OCORES_I2C_XFER("Enter end of msg.\n"); + 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); + OCORES_I2C_XFER("send start, exit.\n"); + 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); + OCORES_I2C_XFER("send OCI2C_CMD_STOP, exit.\n"); + 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: + OCORES_I2C_XFER("normal, exit nr %d.\n", i2c->adap.nr); + return; +} + +static irqreturn_t ocores_isr(int irq, void *dev_id) +{ + struct ocores_i2c *i2c = dev_id; + u8 stat; + unsigned long flags; + + if (!i2c) { + return IRQ_NONE; + } + + spin_lock_irqsave(&i2c->process_lock, flags); + stat = oc_getreg(i2c, OCI2C_STATUS); + if (!(stat & OCI2C_STAT_IF)) { + spin_unlock_irqrestore(&i2c->process_lock, flags); + return IRQ_NONE; + } + OCORES_I2C_XFER("Enter, irq %d nr %d addr 0x%x.\n", irq, i2c->adap.nr, (!i2c->msg)? 0 : i2c->msg->addr); + ocores_process(i2c, stat); + OCORES_I2C_XFER("Leave, irq %d nr %d addr 0x%x.\n", irq, i2c->adap.nr, (!i2c->msg)? 0 : i2c->msg->addr); + spin_unlock_irqrestore(&i2c->process_lock, flags); + + 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); + mdelay(1); + spin_unlock_irqrestore(&i2c->process_lock, flags); + return; +} + +/** + * 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) +{ + u8 status; + unsigned long j, jiffies_tmp; + unsigned int usleep; + + usleep = OCORE_WAIT_SCH; + j = jiffies + timeout; + while (1) { + jiffies_tmp = jiffies; + status = oc_getreg(i2c, reg); + + if ((status & mask) == val) { + break; + } + + if (time_after(jiffies_tmp, j)) { + OCORES_I2C_XFER("STATUS timeout, mask[0x%x] val[0x%x] status[0x%x]\n", mask, val, status); + return -ETIMEDOUT; + } + usleep_range(usleep,usleep + 1); + } + 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 100ms we timeout then something is broken. + */ + err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, msecs_to_jiffies(100)); + if (err) { + OCORES_I2C_XFER("STATUS timeout, bit 0x%x did not clear in 100ms, err %d\n", mask, err); + } + 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 int ocores_process_polling(struct ocores_i2c *i2c) +{ + irqreturn_t ret; + int err; + + while (1) { + 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 */ + } + } + + return err; +} + +static int ocores_xfer_core(struct ocores_i2c *i2c, + struct i2c_msg *msgs, int num, + bool polling) +{ + int ret; + u8 ctrl; + unsigned long flags; + + OCORES_I2C_VERBOSE("Enter ocores_xfer_core. polling mode:%d.\n", polling); + spin_lock_irqsave(&i2c->process_lock, flags); + + 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); + + spin_unlock_irqrestore(&i2c->process_lock, flags); + + if (polling) { + ret = ocores_process_polling(i2c); + if (ret) { + ocores_process_timeout(i2c); + return -ETIMEDOUT; + } + } 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(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct ocores_i2c *i2c; + int ret; + + OCORES_I2C_VERBOSE("Enter ocores_xfer.\n"); + if (!adap || ocores_msg_check(msgs, num)) { + OCORES_I2C_ERROR("[MAY BE USER SPACE ERROR]:msg buf is NULL\n"); + return -EFAULT; + } + OCORES_I2C_VERBOSE("i2c bus:%d, msgs num:%d.\n", adap->nr, num); + + i2c = i2c_get_adapdata(adap); + + if (i2c->flags & OCORES_FLAG_POLL) { + ret = ocores_xfer_core(i2c, msgs, num, true); + } else { + ret = ocores_xfer_core(i2c, msgs, num, false); + } + + return ret; +} + +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 const struct i2c_algorithm ocores_algorithm = { + .master_xfer = ocores_xfer, + .functionality = ocores_func, +}; + +static const struct i2c_adapter ocores_adapter = { + .owner = THIS_MODULE, + .name = "wb-i2c-ocores", + .class = I2C_CLASS_DEPRECATED, + .algo = &ocores_algorithm, +}; + +static const struct of_device_id ocores_i2c_match[] = { + { + .compatible = "opencores,wb-i2c-ocores", + .data = (void *)TYPE_OCORES, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ocores_i2c_match); + +static int fpga_ocores_i2c_get_irq(struct ocores_i2c *i2c) +{ + int devfn, irq; + struct device *dev; + wb_pci_dev_t *wb_pci_dev; + struct pci_dev *pci_dev; + i2c_ocores_device_t *i2c_ocores_device; + int ret; + + dev = i2c->dev; + wb_pci_dev = &i2c->wb_pci_dev; + + if (dev->of_node) { + ret = 0; + ret += of_property_read_u32(dev->of_node, "pci_domain", &wb_pci_dev->domain); + ret += of_property_read_u32(dev->of_node, "pci_bus", &wb_pci_dev->bus); + ret += of_property_read_u32(dev->of_node, "pci_slot", &wb_pci_dev->slot); + ret += of_property_read_u32(dev->of_node, "pci_fn", &wb_pci_dev->fn); + + if (ret != 0) { + OCORES_I2C_ERROR("dts config error, ret:%d.\n", ret); + ret = -EINVAL; + return ret; + } + } else { + if (i2c->dev->platform_data == NULL) { + OCORES_I2C_ERROR("Failed to get platform data config.\n"); + ret = -EINVAL; + return ret; + } + i2c_ocores_device = i2c->dev->platform_data; + wb_pci_dev->domain = i2c_ocores_device->pci_domain; + wb_pci_dev->bus = i2c_ocores_device->pci_bus; + wb_pci_dev->slot = i2c_ocores_device->pci_slot; + wb_pci_dev->fn = i2c_ocores_device->pci_fn; + } + + OCORES_I2C_VERBOSE("pci_domain:0x%x, pci_bus:0x%x, pci_slot:0x%x, pci_fn:0x%x.\n", + wb_pci_dev->domain, wb_pci_dev->bus, wb_pci_dev->slot, wb_pci_dev->fn); + + devfn = PCI_DEVFN(wb_pci_dev->slot, wb_pci_dev->fn); + pci_dev = pci_get_domain_bus_and_slot(wb_pci_dev->domain, wb_pci_dev->bus, devfn); + if (pci_dev == NULL) { + OCORES_I2C_ERROR("Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", + wb_pci_dev->domain, wb_pci_dev->bus, devfn); + return -ENODEV; + } + irq = pci_dev->irq + i2c->irq_offset; + OCORES_I2C_VERBOSE("get irq no:%d.\n", irq); + return irq; +} + +static int ocores_i2c_config_init(struct ocores_i2c *i2c) +{ + int ret; + struct device *dev; + i2c_ocores_device_t *i2c_ocores_device; + + dev = i2c->dev; + ret = 0; + + if (dev->of_node) { + ret += of_property_read_string(dev->of_node, "dev_name", &i2c->dev_name); + ret += of_property_read_u32(dev->of_node, "dev_base", &i2c->base_addr); + ret += of_property_read_u32(dev->of_node, "reg_shift", &i2c->reg_shift); + ret += of_property_read_u32(dev->of_node, "reg_io_width", &i2c->reg_io_width); + ret += of_property_read_u32(dev->of_node, "ip_clock_khz", &i2c->ip_clock_khz); + ret += of_property_read_u32(dev->of_node, "bus_clock_khz", &i2c->bus_clock_khz); + ret += of_property_read_u32(dev->of_node, "reg_access_mode", &i2c->reg_access_mode); + + if (ret != 0) { + OCORES_I2C_ERROR("dts config error, ret:%d.\n", ret); + ret = -ENXIO; + return ret; + } + } else { + if (i2c->dev->platform_data == NULL) { + OCORES_I2C_ERROR("Failed to get platform data config.\n"); + ret = -ENXIO; + return ret; + } + i2c_ocores_device = i2c->dev->platform_data; + i2c->dev_name = i2c_ocores_device->dev_name; + i2c->adap_nr = i2c_ocores_device->adap_nr; + i2c->big_endian = i2c_ocores_device->big_endian; + i2c->base_addr = i2c_ocores_device->dev_base; + i2c->reg_shift = i2c_ocores_device->reg_shift; + i2c->reg_io_width = i2c_ocores_device->reg_io_width; + i2c->ip_clock_khz = i2c_ocores_device->ip_clock_khz; + i2c->bus_clock_khz = i2c_ocores_device->bus_clock_khz; + i2c->reg_access_mode = i2c_ocores_device->reg_access_mode; + } + + OCORES_I2C_VERBOSE("name:%s, base:0x%x, reg_shift:0x%x, io_width:0x%x, ip_clock_khz:0x%x, bus_clock_khz:0x%x.\n", + i2c->dev_name, i2c->base_addr, i2c->reg_shift, i2c->reg_io_width, i2c->ip_clock_khz, i2c->bus_clock_khz); + OCORES_I2C_VERBOSE("reg access mode:%d.\n", i2c->reg_access_mode); + return ret; +} + +static int ocores_i2c_probe(struct platform_device *pdev) +{ + struct ocores_i2c *i2c; + int irq, ret; + bool be; + i2c_ocores_device_t *i2c_ocores_device; + + OCORES_I2C_VERBOSE("Enter main probe\n"); + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) { + dev_err(&pdev->dev, "devm_kzalloc failed.\n"); + return -ENOMEM; + } + + spin_lock_init(&i2c->process_lock); + + i2c->dev = &pdev->dev; + ret = ocores_i2c_config_init(i2c); + if (ret !=0) { + dev_err(i2c->dev, "Failed to get ocores i2c dts config.\n"); + goto out; + } + + if (i2c->dev->of_node) { + if (of_property_read_u32(i2c->dev->of_node, "big_endian", &i2c->big_endian)) { + + be = 0; + } else { + be = i2c->big_endian; + } + } else { + be = i2c->big_endian; + } + + if (i2c->reg_io_width == 0) { + i2c->reg_io_width = 1; /* Set to default value */ + } + + if (!i2c->setreg || !i2c->getreg) { + switch (i2c->reg_io_width) { + case REG_IO_WIDTH_1: + i2c->setreg = oc_setreg_8; + i2c->getreg = oc_getreg_8; + break; + + case REG_IO_WIDTH_2: + i2c->setreg = be ? oc_setreg_16be : oc_setreg_16; + i2c->getreg = be ? oc_getreg_16be : oc_getreg_16; + break; + + case REG_IO_WIDTH_4: + i2c->setreg = be ? oc_setreg_32be : oc_setreg_32; + i2c->getreg = be ? oc_getreg_32be : oc_getreg_32; + break; + + default: + dev_err(i2c->dev, "Unsupported I/O width (%d)\n", + i2c->reg_io_width); + ret = -EINVAL; + goto out; + } + } + + init_waitqueue_head(&i2c->wait); + irq = -1; + + if (i2c->dev->of_node) { + if (of_property_read_u32(i2c->dev->of_node, "irq_offset", &i2c->irq_offset)) { + + i2c->flags |= OCORES_FLAG_POLL; + } else { + + irq = fpga_ocores_i2c_get_irq(i2c); + if (irq < 0 ) { + dev_err(i2c->dev, "Failed to get ocores i2c irq number, ret: %d.\n", irq); + ret = irq; + goto out; + } + } + } else { + if (i2c->dev->platform_data == NULL) { + + i2c->flags |= OCORES_FLAG_POLL; + OCORES_I2C_VERBOSE("Failed to get platform data config, set OCORES_FLAG_POLL.\n"); + } else { + i2c_ocores_device = i2c->dev->platform_data; + if (i2c_ocores_device->irq_type == 0) { + + i2c->flags |= OCORES_FLAG_POLL; + } else { + + irq = fpga_ocores_i2c_get_irq(i2c); + if (irq < 0 ) { + dev_err(i2c->dev, "Failed to get ocores i2c irq number, ret: %d.\n", irq); + ret = irq; + goto out; + } + } + } + } + + if (!(i2c->flags & OCORES_FLAG_POLL)) { + ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, + pdev->name, i2c); + if (ret) { + dev_err(i2c->dev, "Cannot claim IRQ\n"); + goto out; + } + } + + ret = ocores_init(i2c->dev, i2c); + if (ret) { + goto out; + } + + /* 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; + i2c->adap.dev.of_node = pdev->dev.of_node; + + if (i2c->dev->of_node) { + /* adap.nr get from dts aliases */ + ret = i2c_add_adapter(&i2c->adap); + } else { + i2c->adap.nr = i2c->adap_nr; + ret = i2c_add_numbered_adapter(&i2c->adap); + } + if (ret) { + goto fail_add; + } + OCORES_I2C_VERBOSE("Main probe out\n"); + dev_info(i2c->dev, "registered i2c-%d for %s with base address:0x%x success.\n", + i2c->adap.nr, i2c->dev_name, i2c->base_addr); + return 0; +fail_add: + platform_set_drvdata(pdev, NULL); +out: + return ret; +} + +static int 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); + return 0; +} + +static struct platform_driver ocores_i2c_driver = { + .probe = ocores_i2c_probe, + .remove = ocores_i2c_remove, + .driver = { + .name = "wb-ocores-i2c", + .of_match_table = ocores_i2c_match, + }, +}; + +module_platform_driver(ocores_i2c_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("OpenCores I2C bus driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ocores-i2c"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.h new file mode 100644 index 000000000000..acd2710a92f0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.h @@ -0,0 +1,28 @@ +#ifndef __WB_I2C_OCORES_H__ +#define __WB_I2C_OCORES_H__ +#include + +#define mem_clear(data, size) memset((data), 0, (size)) +#define I2C_OCORES_DEV_NAME_MAX_LEN (64) + +typedef struct i2c_ocores_device_s { + uint32_t big_endian; + char dev_name[I2C_OCORES_DEV_NAME_MAX_LEN]; + int adap_nr; + uint32_t dev_base; + uint32_t reg_shift; + uint32_t reg_io_width; + uint32_t ip_clock_khz; + uint32_t bus_clock_khz; + uint32_t reg_access_mode; + + uint32_t irq_type; + uint32_t irq_offset; + uint32_t pci_domain; + uint32_t pci_bus; + uint32_t pci_slot; + uint32_t pci_fn; + int device_flag; +} i2c_ocores_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.c new file mode 100644 index 000000000000..b1f5294b85ab --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.c @@ -0,0 +1,571 @@ +/* + * wb_io_dev.c + * ko to read/write ioports through /dev/XXX device + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_io_dev.h" + +#define PROXY_NAME "wb-io-dev" +#define MAX_IO_DEV_NUM (256) +#define IO_RDWR_MAX_LEN (256) +#define MAX_NAME_SIZE (20) +#define IO_INDIRECT_ADDR_H(addr) ((addr >> 8) & 0xff) +#define IO_INDIRECT_ADDR_L(addr) ((addr) & 0xff) +#define IO_INDIRECT_OP_WRITE (0x2) +#define IO_INDIRECT_OP_READ (0X3) + +static int g_io_dev_debug = 0; +static int g_io_dev_error = 0; + +module_param(g_io_dev_debug, int, S_IRUGO | S_IWUSR); +module_param(g_io_dev_error, int, S_IRUGO | S_IWUSR); + +#define IO_DEV_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_io_dev_debug) { \ + printk(KERN_INFO "[IO_DEV][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define IO_DEV_DEBUG_ERROR(fmt, args...) do { \ + if (g_io_dev_error) { \ + printk(KERN_ERR "[IO_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +typedef struct wb_io_dev_s { + const char *name; + uint32_t io_base; + uint32_t io_len; + uint32_t indirect_addr; + uint32_t wr_data; + uint32_t addr_low; + uint32_t addr_high; + uint32_t rd_data; + uint32_t opt_ctl; + spinlock_t io_dev_lock; + struct miscdevice misc; +} wb_io_dev_t; + +static wb_io_dev_t* io_dev_arry[MAX_IO_DEV_NUM]; + +static int io_dev_open(struct inode *inode, struct file *file) +{ + unsigned int minor = iminor(inode); + wb_io_dev_t *wb_io_dev; + + if (minor >= MAX_IO_DEV_NUM) { + IO_DEV_DEBUG_ERROR("minor out of range, minor = %d.\n", minor); + return -ENODEV; + } + + wb_io_dev = io_dev_arry[minor]; + if (wb_io_dev == NULL) { + IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, open failed, minor = %d\n", minor); + return -ENODEV; + } + + file->private_data = wb_io_dev; + return 0; +} + +static int io_dev_release(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + return 0; +} + +uint8_t io_indirect_addressing_read(wb_io_dev_t *wb_io_dev, uint32_t address) +{ + uint8_t addr_l, addr_h, value; + unsigned long flags; + + addr_h = IO_INDIRECT_ADDR_H(address); + addr_l = IO_INDIRECT_ADDR_L(address); + IO_DEV_DEBUG_VERBOSE("read one count, addr = 0x%x\n", address); + + spin_lock_irqsave(&wb_io_dev->io_dev_lock, flags); + + outb(addr_l, wb_io_dev->io_base + wb_io_dev->addr_low); + + outb(addr_h, wb_io_dev->io_base + wb_io_dev->addr_high); + + outb(IO_INDIRECT_OP_READ, wb_io_dev->io_base + wb_io_dev->opt_ctl); + + value = inb(wb_io_dev->io_base + wb_io_dev->rd_data); + + spin_unlock_irqrestore(&wb_io_dev->io_dev_lock, flags); + + return value; +} + +static int io_dev_read_tmp(wb_io_dev_t *wb_io_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int i; + + if (offset > wb_io_dev->io_len) { + IO_DEV_DEBUG_VERBOSE("offset:0x%x, io len:0x%x, EOF.\n", offset, wb_io_dev->io_len); + return 0; + } + + if (count > wb_io_dev->io_len - offset) { + IO_DEV_DEBUG_VERBOSE("read count out of range. input len:%lu, read len:%u.\n", + count, wb_io_dev->io_len - offset); + count = wb_io_dev->io_len - offset; + } + if (wb_io_dev->indirect_addr) { + for (i = 0; i < count; i++) { + buf[i] = io_indirect_addressing_read(wb_io_dev, offset + i); + } + } else { + for (i = 0; i < count; i++) { + buf[i] = inb(wb_io_dev->io_base + offset + i); + } + } + + return count; +} + +static ssize_t io_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) +{ + wb_io_dev_t *wb_io_dev; + int ret, read_len; + u8 buf_tmp[IO_RDWR_MAX_LEN]; + + wb_io_dev = file->private_data; + if (wb_io_dev == NULL) { + IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, read failed.\n"); + return -EINVAL; + } + + if (count == 0) { + IO_DEV_DEBUG_ERROR("Invalid params, read count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(buf_tmp)) { + IO_DEV_DEBUG_VERBOSE("read count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); + count = sizeof(buf_tmp); + } + + mem_clear(buf_tmp, sizeof(buf_tmp)); + read_len = io_dev_read_tmp(wb_io_dev, *offset, buf_tmp, count); + if (read_len < 0) { + IO_DEV_DEBUG_ERROR("io_dev_read_tmp failed, ret:%d.\n", read_len); + return read_len; + } + + if (access_ok(buf, read_len)) { + IO_DEV_DEBUG_VERBOSE("user space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + if (copy_to_user(buf, buf_tmp, read_len)) { + IO_DEV_DEBUG_ERROR("copy_to_user failed.\n"); + return -EFAULT; + } + } else { + IO_DEV_DEBUG_VERBOSE("kernel space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + memcpy(buf, buf_tmp, read_len); + } + *offset += read_len; + ret = read_len; + return ret; +} + +static ssize_t io_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) +{ + int ret; + + IO_DEV_DEBUG_VERBOSE("io_dev_read_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, to->count, iocb->ki_pos); + ret = io_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos); + return ret; +} + +void io_indirect_addressing_write(wb_io_dev_t *wb_io_dev, uint32_t address, uint8_t reg_val) +{ + uint8_t addr_l, addr_h; + unsigned long flags; + + addr_h = IO_INDIRECT_ADDR_H(address); + addr_l = IO_INDIRECT_ADDR_L(address); + IO_DEV_DEBUG_VERBOSE("write one count, addr = 0x%x\n", address); + + spin_lock_irqsave(&wb_io_dev->io_dev_lock, flags); + + outb(reg_val, wb_io_dev->io_base + wb_io_dev->wr_data); + + outb(addr_l, wb_io_dev->io_base + wb_io_dev->addr_low); + + outb(addr_h, wb_io_dev->io_base + wb_io_dev->addr_high); + + outb(IO_INDIRECT_OP_WRITE, wb_io_dev->io_base + wb_io_dev->opt_ctl); + + spin_unlock_irqrestore(&wb_io_dev->io_dev_lock, flags); + + return; +} + +static int io_dev_write_tmp(wb_io_dev_t *wb_io_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int i; + + if (offset > wb_io_dev->io_len) { + IO_DEV_DEBUG_VERBOSE("offset:0x%x, io len:0x%x, EOF.\n", offset, wb_io_dev->io_len); + return 0; + } + + if (count > wb_io_dev->io_len - offset) { + IO_DEV_DEBUG_VERBOSE("write count out of range. input len:%lu, write len:%u.\n", + count, wb_io_dev->io_len - offset); + count = wb_io_dev->io_len - offset; + } + if (wb_io_dev->indirect_addr) { + for (i = 0; i < count; i++) { + io_indirect_addressing_write(wb_io_dev, offset + i, buf[i]); + } + } else { + for (i = 0; i < count; i++) { + outb(buf[i], wb_io_dev->io_base + offset + i); + } + } + + return count; +} + +static ssize_t io_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) +{ + wb_io_dev_t *wb_io_dev; + int write_len; + u8 buf_tmp[IO_RDWR_MAX_LEN]; + + wb_io_dev = file->private_data; + if (wb_io_dev == NULL) { + IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, write failed.\n"); + return -EINVAL; + } + + if (count == 0) { + IO_DEV_DEBUG_ERROR("Invalid params, write count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(buf_tmp)) { + IO_DEV_DEBUG_VERBOSE("write count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); + count = sizeof(buf_tmp); + } + + mem_clear(buf_tmp, sizeof(buf_tmp)); + if (access_ok(buf, count)) { + IO_DEV_DEBUG_VERBOSE("user space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + if (copy_from_user(buf_tmp, buf, count)) { + IO_DEV_DEBUG_ERROR("copy_from_user failed.\n"); + return -EFAULT; + } + } else { + IO_DEV_DEBUG_VERBOSE("kernel space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + memcpy(buf_tmp, buf, count); + } + + write_len = io_dev_write_tmp(wb_io_dev, *offset, buf_tmp, count); + if (write_len < 0) { + IO_DEV_DEBUG_ERROR("io_dev_write_tmp failed, ret:%d.\n", write_len); + return write_len; + } + + *offset += write_len; + return write_len; +} + +static ssize_t io_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) +{ + int ret; + + IO_DEV_DEBUG_VERBOSE("io_dev_write_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, from->count, iocb->ki_pos); + ret = io_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos); + return ret; +} + +static loff_t io_dev_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t ret = 0; + wb_io_dev_t *wb_io_dev; + + wb_io_dev = file->private_data; + if (wb_io_dev == NULL) { + IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, llseek failed.\n"); + return -EINVAL; + } + + switch (origin) { + case SEEK_SET: + if (offset < 0) { + IO_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); + ret = -EINVAL; + break; + } + if (offset > wb_io_dev->io_len) { + IO_DEV_DEBUG_ERROR("SEEK_SET out of range, offset:%lld, io_len:0x%x.\n", + offset, wb_io_dev->io_len); + ret = - EINVAL; + break; + } + file->f_pos = offset; + ret = file->f_pos; + break; + case SEEK_CUR: + if (((file->f_pos + offset) > wb_io_dev->io_len) || ((file->f_pos + offset) < 0)) { + IO_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld, io_len:0x%x.\n", + file->f_pos, offset, wb_io_dev->io_len); + ret = - EINVAL; + break; + } + file->f_pos += offset; + ret = file->f_pos; + break; + default: + IO_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); + ret = -EINVAL; + break; + } + return ret; +} + +static long io_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static const struct file_operations io_dev_fops = { + .owner = THIS_MODULE, + .llseek = io_dev_llseek, + .read_iter = io_dev_read_iter, + .write_iter = io_dev_write_iter, + .unlocked_ioctl = io_dev_ioctl, + .open = io_dev_open, + .release = io_dev_release, +}; + +static wb_io_dev_t *dev_match(const char *path) +{ + wb_io_dev_t *wb_io_dev; + char dev_name[MAX_NAME_SIZE]; + int i; + + for (i = 0; i < MAX_IO_DEV_NUM; i++) { + if (io_dev_arry[i] == NULL) { + continue; + } + wb_io_dev = io_dev_arry[i]; + snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", wb_io_dev->name); + if (!strcmp(path, dev_name)) { + IO_DEV_DEBUG_VERBOSE("get dev_name = %s, minor = %d\n", dev_name, i); + return wb_io_dev; + } + } + + return NULL; +} + +int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + wb_io_dev_t *wb_io_dev; + int read_len; + + if (path == NULL) { + IO_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if (buf == NULL) { + IO_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + wb_io_dev = dev_match(path); + if (wb_io_dev == NULL) { + IO_DEV_DEBUG_ERROR("io_dev match failed. dev path = %s", path); + return -EINVAL; + } + + read_len = io_dev_read_tmp(wb_io_dev, offset, buf, count); + if (read_len < 0) { + IO_DEV_DEBUG_ERROR("io_dev_read_tmp failed, ret:%d.\n", read_len); + } + return read_len; +} +EXPORT_SYMBOL(io_device_func_read); + +int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + wb_io_dev_t *wb_io_dev; + int write_len; + + if (path == NULL) { + IO_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if (buf == NULL) { + IO_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + wb_io_dev = dev_match(path); + if (wb_io_dev == NULL) { + IO_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + write_len = io_dev_write_tmp(wb_io_dev, offset, buf, count); + if (write_len < 0) { + IO_DEV_DEBUG_ERROR("io_dev_write_tmp failed, ret:%d.\n", write_len); + } + return write_len; +} +EXPORT_SYMBOL(io_device_func_write); + +static int io_dev_probe(struct platform_device *pdev) +{ + int ret; + wb_io_dev_t *wb_io_dev; + struct miscdevice *misc; + io_dev_device_t *io_dev_device; + + wb_io_dev = devm_kzalloc(&pdev->dev, sizeof(wb_io_dev_t), GFP_KERNEL); + if (!wb_io_dev) { + dev_err(&pdev->dev, "devm_kzalloc failed.\n"); + ret = -ENOMEM; + return ret; + } + spin_lock_init(&wb_io_dev->io_dev_lock); + + if (pdev->dev.of_node) { + ret = 0; + ret += of_property_read_string(pdev->dev.of_node, "io_dev_name", &wb_io_dev->name); + ret += of_property_read_u32(pdev->dev.of_node, "io_base", &wb_io_dev->io_base); + ret += of_property_read_u32(pdev->dev.of_node, "io_len", &wb_io_dev->io_len); + if (of_property_read_bool(pdev->dev.of_node, "indirect_addr")) { + + wb_io_dev->indirect_addr = 1; + ret += of_property_read_u32(pdev->dev.of_node, "wr_data", &wb_io_dev->wr_data); + ret += of_property_read_u32(pdev->dev.of_node, "addr_low", &wb_io_dev->addr_low); + ret += of_property_read_u32(pdev->dev.of_node, "addr_high", &wb_io_dev->addr_high); + ret += of_property_read_u32(pdev->dev.of_node, "rd_data", &wb_io_dev->rd_data); + ret += of_property_read_u32(pdev->dev.of_node, "opt_ctl", &wb_io_dev->opt_ctl); + } else { + + wb_io_dev->indirect_addr = 0; + } + if (ret != 0) { + dev_err(&pdev->dev, "Failed to get dts config, ret:%d.\n", ret); + return -ENXIO; + } + } else { + if (pdev->dev.platform_data == NULL) { + dev_err(&pdev->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + io_dev_device = pdev->dev.platform_data; + wb_io_dev->name = io_dev_device->io_dev_name; + wb_io_dev->io_base = io_dev_device->io_base; + wb_io_dev->io_len = io_dev_device->io_len; + wb_io_dev->indirect_addr = io_dev_device->indirect_addr; + if (wb_io_dev->indirect_addr == 1) { + wb_io_dev->wr_data = io_dev_device->wr_data; + wb_io_dev->addr_low = io_dev_device->addr_low; + wb_io_dev->addr_high = io_dev_device->addr_high; + wb_io_dev->rd_data = io_dev_device->rd_data; + wb_io_dev->opt_ctl = io_dev_device->opt_ctl; + } + } + + IO_DEV_DEBUG_VERBOSE("name:%s, io base:0x%x, io len:0x%x, addressing type:%s.\n", + wb_io_dev->name, wb_io_dev->io_base, wb_io_dev->io_len, + wb_io_dev->indirect_addr ? "indirect" : "direct"); + + misc = &wb_io_dev->misc; + misc->minor = MISC_DYNAMIC_MINOR; + misc->name = wb_io_dev->name; + misc->fops = &io_dev_fops; + misc->mode = 0666; + if (misc_register(misc) != 0) { + dev_err(&pdev->dev, "Failed to register %s device.\n", misc->name); + return -ENXIO; + } + if (misc->minor >= MAX_IO_DEV_NUM) { + dev_err(&pdev->dev, "Error: device minor[%d] more than max io device num[%d].\n", + misc->minor, MAX_IO_DEV_NUM); + misc_deregister(misc); + return -EINVAL; + } + io_dev_arry[misc->minor] = wb_io_dev; + dev_info(&pdev->dev, "register %s device [0x%x][0x%x] with minor %d using %s addressing success.\n", + misc->name, wb_io_dev->io_base, wb_io_dev->io_len, misc->minor, + wb_io_dev->indirect_addr ? "indirect" : "direct"); + + return 0; +} + +static int io_dev_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < MAX_IO_DEV_NUM ; i++) { + if (io_dev_arry[i] != NULL) { + misc_deregister(&io_dev_arry[i]->misc); + io_dev_arry[i] = NULL; + } + } + + return 0; +} + +static struct of_device_id io_dev_match[] = { + { + .compatible = "wb-io-dev", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, io_dev_match); + +static struct platform_driver wb_io_dev_driver = { + .probe = io_dev_probe, + .remove = io_dev_remove, + .driver = { + .owner = THIS_MODULE, + .name = PROXY_NAME, + .of_match_table = io_dev_match, + }, +}; + +static int __init wb_io_dev_init(void) +{ + return platform_driver_register(&wb_io_dev_driver); +} + +static void __exit wb_io_dev_exit(void) +{ + platform_driver_unregister(&wb_io_dev_driver); +} + +module_init(wb_io_dev_init); +module_exit(wb_io_dev_exit); +MODULE_DESCRIPTION("IO device driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.h new file mode 100644 index 000000000000..3a1a10f0f20c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.h @@ -0,0 +1,21 @@ +#ifndef __WB_IO_DEV_H__ +#define __WB_IO_DEV_H__ +#include + +#define mem_clear(data, size) memset((data), 0, (size)) +#define IO_DEV_NAME_MAX_LEN (64) + +typedef struct io_dev_device_s { + char io_dev_name[IO_DEV_NAME_MAX_LEN]; + uint32_t io_base; + uint32_t io_len; + uint32_t indirect_addr; + uint32_t wr_data; + uint32_t addr_low; + uint32_t addr_high; + uint32_t rd_data; + uint32_t opt_ctl; + int device_flag; +} io_dev_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.c new file mode 100644 index 000000000000..c079dc409696 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.c @@ -0,0 +1,166 @@ +/* + * wb_lpc_drv.c + * ko to set lpc pcie config io addr and enable lpc + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_lpc_drv.h" + +#define LPC_DRIVER_NAME "wb-lpc" +#define LPC_MAKE_PCI_IO_RANGE(__base) ((0xfc0001) | ((__base) & (0xFFFC))) + +int g_lpc_dev_debug = 0; +int g_lpc_dev_error = 0; + +module_param(g_lpc_dev_debug, int, S_IRUGO | S_IWUSR); +module_param(g_lpc_dev_error, int, S_IRUGO | S_IWUSR); + +#define LPC_DEV_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_lpc_dev_debug) { \ + printk(KERN_INFO "[LPC_DEV][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define LPC_DEV_DEBUG_ERROR(fmt, args...) do { \ + if (g_lpc_dev_error) { \ + printk(KERN_ERR "[LPC_DEV][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +typedef struct wb_lpc_dev_s { + const char *lpc_io_name; + uint32_t domain; + uint32_t bus; + uint32_t slot; + uint32_t fn; + uint32_t lpc_io_base; + uint32_t lpc_io_size; + uint32_t lpc_gen_dec; +} wb_lpc_dev_t; + +static int wb_lpc_probe(struct platform_device *pdev) +{ + int ret, devfn; + wb_lpc_dev_t *wb_lpc_dev; + struct pci_dev *pci_dev; + lpc_drv_device_t *lpc_drv_device; + + wb_lpc_dev = devm_kzalloc(&pdev->dev, sizeof(wb_lpc_dev_t), GFP_KERNEL); + if (!wb_lpc_dev) { + dev_err(&pdev->dev, "devm_kzalloc failed.\n"); + ret = -ENOMEM; + return ret; + } + + if (pdev->dev.of_node) { + ret = 0; + ret += of_property_read_string(pdev->dev.of_node, "lpc_io_name", &wb_lpc_dev->lpc_io_name); + ret += of_property_read_u32(pdev->dev.of_node, "pci_domain", &wb_lpc_dev->domain); + ret += of_property_read_u32(pdev->dev.of_node, "pci_bus", &wb_lpc_dev->bus); + ret += of_property_read_u32(pdev->dev.of_node, "pci_slot", &wb_lpc_dev->slot); + ret += of_property_read_u32(pdev->dev.of_node, "pci_fn", &wb_lpc_dev->fn); + ret += of_property_read_u32(pdev->dev.of_node, "lpc_io_base", &wb_lpc_dev->lpc_io_base); + ret += of_property_read_u32(pdev->dev.of_node, "lpc_io_size", &wb_lpc_dev->lpc_io_size); + ret += of_property_read_u32(pdev->dev.of_node, "lpc_gen_dec", &wb_lpc_dev->lpc_gen_dec); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to get dts config, ret:%d.\n", ret); + return -ENXIO; + } + } else { + if (pdev->dev.platform_data == NULL) { + dev_err(&pdev->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + lpc_drv_device = pdev->dev.platform_data; + wb_lpc_dev->lpc_io_name = lpc_drv_device->lpc_io_name; + wb_lpc_dev->domain = lpc_drv_device->pci_domain; + wb_lpc_dev->bus = lpc_drv_device->pci_bus; + wb_lpc_dev->slot = lpc_drv_device->pci_slot; + wb_lpc_dev->fn = lpc_drv_device->pci_fn; + wb_lpc_dev->lpc_io_base = lpc_drv_device->lpc_io_base; + wb_lpc_dev->lpc_io_size = lpc_drv_device->lpc_io_size; + wb_lpc_dev->lpc_gen_dec = lpc_drv_device->lpc_gen_dec; + } + + LPC_DEV_DEBUG_VERBOSE("domain:0x%04x, bus:0x%02x, slot:0x%02x, fn:%u\n", + wb_lpc_dev->domain,wb_lpc_dev->bus, wb_lpc_dev->slot, wb_lpc_dev->fn); + LPC_DEV_DEBUG_VERBOSE("lpc_io_name:%s, lpc_io_base:0x%x, lpc_io_size:%u, lpc_gen_dec:0x%x.\n", + wb_lpc_dev->lpc_io_name, wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size, wb_lpc_dev->lpc_gen_dec); + + devfn = PCI_DEVFN(wb_lpc_dev->slot, wb_lpc_dev->fn); + pci_dev = pci_get_domain_bus_and_slot(wb_lpc_dev->domain, wb_lpc_dev->bus, devfn); + if (pci_dev == NULL) { + dev_err(&pdev->dev, "Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", + wb_lpc_dev->domain, wb_lpc_dev->bus, devfn); + return -ENXIO; + } + + pci_write_config_dword(pci_dev, wb_lpc_dev->lpc_gen_dec, LPC_MAKE_PCI_IO_RANGE(wb_lpc_dev->lpc_io_base)); + if (!request_region(wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size, wb_lpc_dev->lpc_io_name)) { + dev_err(&pdev->dev, "Failed to request_region [0x%x][0x%x].\n", wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size); + return -EBUSY; + } + + platform_set_drvdata(pdev, wb_lpc_dev); + + dev_info(&pdev->dev, "lpc request_region [0x%x][0x%x] success.\n", wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size); + + return 0; +} + +static int wb_lpc_remove(struct platform_device *pdev) +{ + wb_lpc_dev_t *wb_lpc_dev; + + wb_lpc_dev = platform_get_drvdata(pdev); + if (wb_lpc_dev) { + release_region(wb_lpc_dev->lpc_io_base , wb_lpc_dev->lpc_io_size); + LPC_DEV_DEBUG_VERBOSE("lpc base:0x%x, len:0x%x.\n", wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size); + } + LPC_DEV_DEBUG_VERBOSE("lpc remove.\n"); + + return 0; +} + +static struct of_device_id lpc_dev_match[] = { + { + .compatible = "wb-lpc", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, lpc_dev_match); + +static struct platform_driver wb_lpc_driver = { + .probe = wb_lpc_probe, + .remove = wb_lpc_remove, + .driver = { + .owner = THIS_MODULE, + .name = LPC_DRIVER_NAME, + .of_match_table = lpc_dev_match, + }, +}; + +static int __init wb_lpc_init(void) +{ + return platform_driver_register(&wb_lpc_driver); +} + +static void __exit wb_lpc_exit(void) +{ + platform_driver_unregister(&wb_lpc_driver); +} + +module_init(wb_lpc_init); +module_exit(wb_lpc_exit); +MODULE_DESCRIPTION("lpc driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.h new file mode 100644 index 000000000000..76e8c32c12e9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.h @@ -0,0 +1,18 @@ +#ifndef __WB_LPC_DRV_H__ +#define __WB_LPC_DRV_H__ + +#define LPC_IO_NAME_MAX_LEN (64) + +typedef struct lpc_drv_device_s { + char lpc_io_name[LPC_IO_NAME_MAX_LEN]; + int pci_domain; + int pci_bus; + int pci_slot; + int pci_fn; + int lpc_io_base; + int lpc_io_size; + int lpc_gen_dec; + int device_flag; +} lpc_drv_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mac_bsc.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mac_bsc.c new file mode 100644 index 000000000000..d72e91ace060 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mac_bsc.c @@ -0,0 +1,845 @@ +/* + * + * Copyright (c) 1998, 1999 Frodo Looijaard + * + * 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 + +#define mem_clear(data, size) memset((data), 0, (size)) + +#define MAC_TEMP_INVALID (99999999) +#define MAC_ID_REG (0x02000000) + +#define MAC_REG_ADDR_WIDTH (4) +#define MAC_REG_DATA_WIDTH (4) +#define MAC_BSC_MAX_TEMP_NUM (16) +#define MAC_BSC_MAX_READ_REG_STEP (6) +#define MAC_BSC_MAX_SETUP_NUM (1) + +static int g_wb_mac_bsc_debug = 0; +static int g_wb_mac_bsc_error = 0; + +module_param(g_wb_mac_bsc_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_mac_bsc_error, int, S_IRUGO | S_IWUSR); + +#define WB_MAC_BSC_DEBUG(fmt, args...) do { \ + if (g_wb_mac_bsc_debug) { \ + printk(KERN_INFO "[MAC_BSC][VER][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_MAC_BSC_ERROR(fmt, args...) do { \ + if (g_wb_mac_bsc_error) { \ + printk(KERN_ERR "[MAC_BSC][ERR][func:%s line:%d]"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +typedef enum{ + MAC_TYPE_START, + TD4_X9 = 0xb780, + TD4_X9_8 = 0xb788, + TH3 = 0xb980, + TD3 = 0xb870, + TD3_X2 = 0xb274, + TD4 = 0xb880, + TH4 = 0xb990, + MAC_TYPE_END, +} mac_id; + +typedef enum { + MAC_TEMP_START, + MAC_TEMP_INDEX1, + MAC_TEMP_INDEX2, + MAC_TEMP_INDEX3, + MAC_TEMP_INDEX4, + MAC_TEMP_INDEX5, + MAC_TEMP_INDEX6, + MAC_TEMP_INDEX7, + MAC_TEMP_INDEX8, + MAC_TEMP_INDEX9, + MAC_TEMP_INDEX10, + MAC_TEMP_INDEX11, + MAC_TEMP_INDEX12, + MAC_TEMP_INDEX13, + MAC_TEMP_INDEX14, + MAC_TEMP_INDEX15, + MAC_TEMP_END, +} mac_hwmon_index; + +typedef enum action_e { + I2C_WRITE, + I2C_READ +} action_t; + +typedef struct i2c_op_s { + action_t op; + uint32_t reg_addr; + uint32_t reg_val; + int read_back; +} i2c_op_t; + +typedef struct dev_params_s { + int mac_id; + i2c_op_t sbus_setup[MAC_BSC_MAX_SETUP_NUM]; + i2c_op_t vtmon_read[MAC_BSC_MAX_READ_REG_STEP]; + uint32_t vtmon_reg_addrs[MAC_BSC_MAX_TEMP_NUM]; + uint8_t vtmon_instances; + uint32_t vtmon_data_width; + int vtmon_scalar; + int vtmon_offset; + uint8_t sbus_setup_ops; + int vtmon_read_ops; + int sbus_addr_op; + int sbus_error_op; + uint32_t sbus_error_mask; +} dev_params_t; + +static dev_params_t mac_temp_conf[] = { + { + .mac_id = TD3_X2, + /* CMIC_TOP_SBUS_RING_MAP_0_7 = 0x52222100 */ + .sbus_setup = {{I2C_WRITE, 0x1010000c, 0x52222100, 0}}, + .vtmon_read = { + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000000 */ + {I2C_WRITE, 0x10110400, 0x00000000, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[0] = 0x2c380200 */ + {I2C_WRITE, 0x1011040c, 0x2c380200, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] = TOP_PVTMON_RESULT_0 */ + {I2C_WRITE, 0x10110410, 0x02005300, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000001 */ + {I2C_WRITE, 0x10110400, 0x00000001, 0}, + /* CMIC_COMMON_POOL_SCHAN_CH4_ERR */ + {I2C_READ, 0x10110408}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] */ + {I2C_READ, 0x10110410} + }, + .vtmon_reg_addrs = { + 0x02005300, 0x02005400, 0x02005500, 0x02005600, 0x02005700, 0x02005800 + }, + .vtmon_instances = 6, + .vtmon_data_width = 10, + .vtmon_scalar = -5570, + .vtmon_offset = 4578289, + .sbus_setup_ops = 1, + .vtmon_read_ops = 6, + .sbus_addr_op = 2, + .sbus_error_op = 4, + .sbus_error_mask = 0x00000041, + }, + { + .mac_id = TD3, /* TD3_X7*/ + /* CMIC_TOP_SBUS_RING_MAP_0_7 = 0x52222100 */ + .sbus_setup = {{I2C_WRITE, 0x0320000c, 0x52222100, 0}}, + .vtmon_read = { + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000000 */ + {I2C_WRITE, 0x03210400, 0x00000000, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[0] = 0x2c380200 */ + {I2C_WRITE, 0x0321040c, 0x2c380200, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] = TOP_PVTMON_RESULT_0 */ + {I2C_WRITE, 0x03210410, 0x02004700, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000001 */ + {I2C_WRITE, 0x03210400, 0x00000001, 0}, + /* CMIC_COMMON_POOL_SCHAN_CH4_ERR */ + {I2C_READ, 0x03210408}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] */ + {I2C_READ, 0x03210410} + }, + .vtmon_reg_addrs = { + 0x02004700, 0x02004800, 0x02004900, 0x02004a00, 0x02004b00, 0x02004c00, + 0x02004d00, 0x02004e00, 0x02005200, 0x02005100, 0x02005000, 0x02004f00 + }, + .vtmon_instances = 12, + .vtmon_data_width = 10, + .vtmon_scalar = -5350, + .vtmon_offset = 4341000, + .sbus_setup_ops = 0, + .vtmon_read_ops = 6, + .sbus_addr_op = 2, + .sbus_error_op = 4, + .sbus_error_mask = 0x00000041, + }, + { + .mac_id = TH3, + .vtmon_read = { + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000000 */ + {I2C_WRITE, 0x03210400, 0x00000000, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[0] = 0x2c400200 */ + {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] = TOP_PVTMON_RESULT_0 */ + {I2C_WRITE, 0x03210410, 0x02004a00, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000001 */ + {I2C_WRITE, 0x03210400, 0x00000001, 0}, + /* CMIC_COMMON_POOL_SCHAN_CH4_ERR */ + {I2C_READ, 0x03210408}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] */ + {I2C_READ, 0x03210410} + }, + .vtmon_reg_addrs = { + 0x02004a00, 0x02004b00, 0x02004c00, 0x02004d00, 0x02004e00, 0x02004f00, + 0x02005000, 0x02005100, 0x02005200, 0x02005300, 0x02005400, 0x02005500, + 0x02005600, 0x02005700, 0x02005800 + }, + .vtmon_instances = 15, + .vtmon_data_width = 10, + .vtmon_scalar = -5350, + .vtmon_offset = 4341000, + .sbus_setup_ops = 0, + .vtmon_read_ops = 6, + .sbus_addr_op = 2, + .sbus_error_op = -1, + }, + { + .mac_id = TD4_X9, + /* CMIC_TOP_SBUS_RING_MAP_8_15r = 0x00000000 */ + .sbus_setup = {{I2C_WRITE, 0x03200010, 0x00000000, 0}}, + .vtmon_read = { + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ + {I2C_WRITE, 0x03210400, 0x00000000, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ + {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ + {I2C_WRITE, 0x03210410, 0x02005a00, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ + {I2C_WRITE, 0x03210400, 0x00000001, 0}, + /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ + {I2C_READ, 0x03210408}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ + {I2C_READ, 0x03210410} + }, + .vtmon_reg_addrs = { + 0x02005a00, 0x02005c00, 0x02005e00, 0x02006000, 0x02006200, 0x02006400, + 0x02006600, 0x02006800, 0x02006a00 + }, + .vtmon_instances = 9, + .vtmon_data_width = 11, + .vtmon_scalar = -2454, + .vtmon_offset = 3668120, + .sbus_setup_ops = 0, + .vtmon_read_ops = 6, + .sbus_addr_op = 2, + .sbus_error_op = 4, + .sbus_error_mask = 0x00000041, + }, + { + .mac_id = TD4_X9_8, + /* CMIC_TOP_SBUS_RING_MAP_8_15r = 0x00000000 */ + .sbus_setup = {{I2C_WRITE, 0x03200010, 0x00000000, 0}}, + .vtmon_read = { + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ + {I2C_WRITE, 0x03210400, 0x00000000, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ + {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ + {I2C_WRITE, 0x03210410, 0x02005a00, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ + {I2C_WRITE, 0x03210400, 0x00000001, 0}, + /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ + {I2C_READ, 0x03210408}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ + {I2C_READ, 0x03210410} + }, + .vtmon_reg_addrs = { + 0x02005a00, 0x02005c00, 0x02005e00, 0x02006000, 0x02006200, 0x02006400, + 0x02006600, 0x02006800, 0x02006a00 + }, + .vtmon_instances = 9, + .vtmon_data_width = 11, + .vtmon_scalar = -2454, + .vtmon_offset = 3668120, + .sbus_setup_ops = 0, + .vtmon_read_ops = 6, + .sbus_addr_op = 2, + .sbus_error_op = 4, + .sbus_error_mask = 0x00000041, + }, + { + .mac_id = TD4, /* TD4-X11 */ + /* CMIC_TOP_SBUS_RING_MAP_8_15r = 0x00000000 */ + .sbus_setup = {{I2C_WRITE, 0x03200010, 0x00000000, 0}}, + .vtmon_read = { + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ + {I2C_WRITE, 0x03210400, 0x00000000, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ + {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ + {I2C_WRITE, 0x03210410, 0x02004900, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ + {I2C_WRITE, 0x03210400, 0x00000001, 0}, + /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ + {I2C_READ, 0x03210408}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ + {I2C_READ, 0x03210410} + }, + .vtmon_reg_addrs = { + 0x02004900, 0x02004b00, 0x02004d00, 0x02004f00, 0x02005100, 0x02005300, + 0x02005500, 0x02005700, 0x02005900, 0x02005b00, 0x02005d00, 0x02005f00, + 0x02006100, 0x02006300, 0x02006500 + }, + .vtmon_instances = 15, + .vtmon_data_width = 11, + .vtmon_scalar = -2454, + .vtmon_offset = 3668120, + .sbus_setup_ops = 0, + .vtmon_read_ops = 6, + .sbus_addr_op = 2, + .sbus_error_op = 4, + .sbus_error_mask = 0x00000041, + }, + { + .mac_id = TH4, + .vtmon_read = { + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ + {I2C_WRITE, 0x03210400, 0x00000000, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ + {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ + {I2C_WRITE, 0x03210410, 0x0201d800, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ + {I2C_WRITE, 0x03210400, 0x00000001, 0}, + /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ + {I2C_READ, 0x03210408}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ + {I2C_READ, 0x03210410} + }, + .vtmon_reg_addrs = { + 0x0201d800, 0x0201e000, 0x0201e800, 0x0201f000, 0x0201f800, 0x02020000, + 0x02020800, 0x02021000, 0x02021800, 0x02022000, 0x02022800, 0x02023000, + 0x02023800, 0x02024000, 0x02024800, + }, + .vtmon_instances = 15, + .vtmon_data_width = 11, + .vtmon_scalar = -2454, + .vtmon_offset = 3668120, + .sbus_setup_ops = 0, + .vtmon_read_ops = 6, + .sbus_addr_op = 2, + .sbus_error_op = -1, + }, +}; + +struct mac_data { + struct i2c_client *client; + struct device *hwmon_dev; + struct mutex update_lock; + dev_params_t dev_param; +}; + +static int bsc_i2c_read(struct i2c_client *client, uint32_t reg_addr, uint32_t *reg_val) +{ + int msgs_num, ret, i; + uint8_t addr_buf[MAC_REG_ADDR_WIDTH]; + uint8_t data_buf[MAC_REG_DATA_WIDTH]; + uint32_t val; + struct i2c_msg msgs[2]; + + for (i = 0; i < MAC_REG_ADDR_WIDTH; i++) { + addr_buf[i] = (reg_addr >> ((MAC_REG_ADDR_WIDTH -i -1) * 8)) & 0xff; + } + + mem_clear(msgs, sizeof(msgs)); + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = MAC_REG_ADDR_WIDTH; + msgs[0].buf = addr_buf; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = MAC_REG_DATA_WIDTH; + msgs[1].buf = data_buf; + + msgs_num = 2; + ret = i2c_transfer(client->adapter, msgs, msgs_num); + if (ret != msgs_num) { + WB_MAC_BSC_ERROR("i2c_transfer read failed, reg_addr: 0x%x, ret: %d\n", reg_addr, ret); + return -EIO; + } + val = 0; + for (i = 0; i < MAC_REG_DATA_WIDTH; i++) { + val |= data_buf[i] << ((MAC_REG_DATA_WIDTH - i -1) * 8); + } + WB_MAC_BSC_DEBUG("bsc_i2c_read success, reg_addr: 0x%x, reg_val: 0x%x\n", reg_addr, val); + *reg_val = val; + return 0; +} + +static int bsc_i2c_write(struct i2c_client *client, uint32_t reg_addr, uint32_t reg_val) +{ + int ret, i; + uint8_t write_buf[MAC_REG_ADDR_WIDTH + MAC_REG_DATA_WIDTH]; + struct i2c_msg msgs[1]; + + /* fill reg_addr first*/ + for (i = 0; i < MAC_REG_ADDR_WIDTH; i++) { + write_buf[i] = (reg_addr >> ((MAC_REG_ADDR_WIDTH -i -1) * 8)) & 0xff; + } + for (i = 0; i < MAC_REG_DATA_WIDTH; i++) { + write_buf[i + MAC_REG_ADDR_WIDTH] = (reg_val >> ((MAC_REG_DATA_WIDTH -i -1) * 8)) & 0xff; + } + + mem_clear(msgs, sizeof(msgs)); + msgs[0].len = MAC_REG_ADDR_WIDTH + MAC_REG_DATA_WIDTH; + msgs[0].buf = write_buf; + msgs[0].addr = client->addr; + msgs[0].flags = I2C_M_IGNORE_NAK; + + ret = i2c_transfer(client->adapter, msgs, 1); + if (ret < 0) { + WB_MAC_BSC_DEBUG("i2c_transfer write failed, reg_addr: 0x%x, reg_val: 0x%x, ret: %d\n", + reg_addr, reg_val, ret); + return ret; + } + WB_MAC_BSC_DEBUG("i2c_transfer write reg_addr: 0x%x, reg_val: 0x%x success\n", + reg_addr, reg_val); + return 0; +} + +static int handle_operation(struct i2c_client *client, i2c_op_t *operation) +{ + int ret; + uint32_t rd_back_val; + + if (operation->op == I2C_WRITE) { + ret = bsc_i2c_write(client, operation->reg_addr, operation->reg_val); + WB_MAC_BSC_DEBUG("bsc_i2c_write reg_addr: 0x%x, set val: 0x%x, ret: %d\n", + operation->reg_addr, operation->reg_val, ret); + if (operation->read_back) { + ret = bsc_i2c_read(client, operation->reg_addr, &rd_back_val); + if (rd_back_val != operation->reg_val) { + WB_MAC_BSC_ERROR("bsc_i2c_write failed, reg_addr: 0x%x, set val: 0x%x, read back valu: 0x%x\n", + operation->reg_addr, operation->reg_val, rd_back_val); + return -1; + } + WB_MAC_BSC_DEBUG("bsc_i2c_write success, reg_addr: 0x%x, set val: 0x%x, read_back val: 0x%x\n", + operation->reg_addr, operation->reg_val, rd_back_val); + } + return 0; + } + + if (operation->op == I2C_READ) { + ret = bsc_i2c_read(client, operation->reg_addr, &operation->reg_val); + WB_MAC_BSC_DEBUG("bsc_i2c_read reg_addr: 0x%x, get val: 0x%x, ret: %d\n", + operation->reg_addr, operation->reg_val, ret); + return ret; + } + + WB_MAC_BSC_ERROR("Unsupport operation type: %d\n", operation->op); + return -EINVAL; +} + +static int get_mac_reg(struct i2c_client *client, uint32_t reg_addr, uint32_t *reg_value) +{ + int i, ret; + i2c_op_t *op; + struct mac_data *data; + dev_params_t *dev_params; + uint32_t val_tmp; + + data = i2c_get_clientdata(client); + dev_params = &data->dev_param; + val_tmp = 0; + for (i = 0; i < dev_params->vtmon_read_ops; i++) { + op = &dev_params->vtmon_read[i]; + if (i == dev_params->sbus_addr_op) { + op->reg_val = reg_addr; + } + WB_MAC_BSC_DEBUG("Start to handle %s operation, step: %d, reg_addr: 0x%x, reg_value: 0x%x, read back flag: %d\n", + op->op == I2C_READ ? "I2C_READ" : "I2C_WRITE", i, op->reg_addr, op->reg_val, op->read_back); + ret = handle_operation(client, op); + if (ret < 0) { + WB_MAC_BSC_ERROR("handle operation %d failed, ret: %d\n", i, ret); + return ret; + } + if (op->op == I2C_READ) { + val_tmp = op->reg_val; + } + + if (i == dev_params->sbus_error_op) { + if (val_tmp & dev_params->sbus_error_mask) { + WB_MAC_BSC_ERROR("SBUS error seen, status value: 0x%x\n", op->reg_val); + return -EIO; + } + WB_MAC_BSC_DEBUG("Error status check ok, status: 0x%x, error_mask: 0x%x \n", + val_tmp, dev_params->sbus_error_mask); + } + } + + if (val_tmp == reg_addr) { + WB_MAC_BSC_ERROR("get mac register error, register value: 0x%x equal to reg_addr: 0x%x\n", + val_tmp, reg_addr); + return -EIO; + } + + *reg_value = val_tmp; + WB_MAC_BSC_DEBUG("get_mac_reg success, reg_addr: 0x%x, reg_value: 0x%x", reg_addr, *reg_value); + return 0; +} + +static int read_vtmon(struct i2c_client *client, uint8_t vtmon, int *temp) +{ + struct mac_data *data; + dev_params_t *dev_params; + uint32_t reg_addr, reg_val; + uint32_t vtmon_val; + int ret; + + data = i2c_get_clientdata(client); + dev_params = &data->dev_param; + + if (vtmon >= dev_params->vtmon_instances) { + WB_MAC_BSC_ERROR("VTMON index [%d] greater or equal to VTMON instance number: %d\n", + vtmon, dev_params->vtmon_instances); + return -1; + } + reg_addr = dev_params->vtmon_reg_addrs[vtmon]; + ret = get_mac_reg(client, reg_addr, ®_val); + if (ret < 0) { + WB_MAC_BSC_ERROR("Read VTMON[%d] failed, reg_addr: 0x%x, ret: %d\n", + vtmon, reg_addr, ret); + return ret; + } + + vtmon_val = reg_val & ((1 << dev_params->vtmon_data_width) - 1); + *temp = ((dev_params->vtmon_scalar * vtmon_val) + dev_params->vtmon_offset) / 10; + + if ((*temp / 1000 < -40) || (*temp / 1000 > 120)) { + WB_MAC_BSC_ERROR("MAC temp invalid, vtmon: %d, temp: %d\n", vtmon, *temp); + return -EINVAL; + } + WB_MAC_BSC_DEBUG("Read mac temp success, index: %d, value: %d\n", vtmon + 1, *temp); + return 0; +} + +static ssize_t show_mac_temp(struct device *dev, struct device_attribute *da, char *buf) +{ + struct mac_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + u32 temp_index = to_sensor_dev_attr(da)->index; + int ret, temp; + + mutex_lock(&data->update_lock); + ret = read_vtmon(client, temp_index - 1, &temp); + if (ret < 0) { + temp = -MAC_TEMP_INVALID; + WB_MAC_BSC_ERROR("get_mactemp index: %d failed, ret = %d\n", temp_index, ret); + } + mutex_unlock(&data->update_lock); + return snprintf(buf, PAGE_SIZE, "%d\n", temp); +} + +static ssize_t show_mac_max_temp(struct device *dev, struct device_attribute *da, char *buf) +{ + struct mac_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + dev_params_t *dev_params; + int i, ret; + int tmp, temp; + + mutex_lock(&data->update_lock); + + dev_params = &data->dev_param; + temp = -MAC_TEMP_INVALID; + for (i = 0; i < dev_params->vtmon_instances ; i++) { + ret = read_vtmon(client, i, &tmp); + if (ret < 0) { + WB_MAC_BSC_ERROR("Get mactemp failed, temp index: %d, ret = %d\n", + i, ret); + tmp = -MAC_TEMP_INVALID; + } + + temp = (temp > tmp) ? temp : tmp; + } + + mutex_unlock(&data->update_lock); + return snprintf(buf, PAGE_SIZE, "%d\n", temp); +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX1); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX2); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX3); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX4); +static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX5); +static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX6); +static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX7); +static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX8); +static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX9); +static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX10); +static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX11); +static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX12); +static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX13); +static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX14); +static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX15); +static SENSOR_DEVICE_ATTR(temp99_input, S_IRUGO, show_mac_max_temp, NULL, 0); + +static struct attribute *mac_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp5_input.dev_attr.attr, + &sensor_dev_attr_temp6_input.dev_attr.attr, + &sensor_dev_attr_temp7_input.dev_attr.attr, + &sensor_dev_attr_temp8_input.dev_attr.attr, + &sensor_dev_attr_temp9_input.dev_attr.attr, + &sensor_dev_attr_temp10_input.dev_attr.attr, + &sensor_dev_attr_temp11_input.dev_attr.attr, + &sensor_dev_attr_temp12_input.dev_attr.attr, + &sensor_dev_attr_temp13_input.dev_attr.attr, + &sensor_dev_attr_temp14_input.dev_attr.attr, + &sensor_dev_attr_temp15_input.dev_attr.attr, + &sensor_dev_attr_temp99_input.dev_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(mac_hwmon); + +static void mac_bsc_setup(struct i2c_client *client) +{ + int i, ret; + struct mac_data *data; + dev_params_t *dev_params; + uint32_t reg_value; + + data = i2c_get_clientdata(client); + dev_params = &data->dev_param; + + for (i = 0; i < dev_params->sbus_setup_ops; i++) { + ret = bsc_i2c_read(client, dev_params->sbus_setup[i].reg_addr, ®_value); + if ((ret < 0) || (reg_value != dev_params->sbus_setup[i].reg_val)) { + WB_MAC_BSC_DEBUG("bsc setup op%d, ret: %d, reg_addr: 0x%x, read value: 0x%x not equal to set value: 0x%x\n", + i, ret, dev_params->sbus_setup[i].reg_addr, reg_value, dev_params->sbus_setup[i].reg_val); + bsc_i2c_write(client, dev_params->sbus_setup[i].reg_addr, dev_params->sbus_setup[i].reg_val); + } else { + WB_MAC_BSC_DEBUG("bsc setup op%d, reg_addr: 0x%x, read value: 0x%x equal to set value: 0x%x\n", + i, dev_params->sbus_setup[i].reg_addr, reg_value, dev_params->sbus_setup[i].reg_val); + } + } + return; +} + +static int mac_bsc_init(struct i2c_client *client) +{ + int ret, mac_id; + uint32_t reg_value; + + ret = get_mac_reg(client, MAC_ID_REG, ®_value); + if (ret < 0) { + WB_MAC_BSC_ERROR("Get MAC ID failed, reg_addr: 0x%x, ret = %d\n", + MAC_ID_REG, ret); + return ret; + } + + WB_MAC_BSC_DEBUG("Get MAC ID success, reg_addr: 0x%x, value: 0x%x \n", + MAC_ID_REG, reg_value); + mac_id = reg_value & 0xffff; + return mac_id; +} + +static int find_mac_config(int type, int *index) +{ + int i, size; + + size = ARRAY_SIZE(mac_temp_conf); + for (i = 0; i < size; i++) { + if (mac_temp_conf[i].mac_id == type) { + *index = i; + return 0; + } + } + return -1; +} + +static int mac_bsc_config_check(dev_params_t *dev_params) +{ + i2c_op_t *last_op; + i2c_op_t *err_op; + i2c_op_t *addr_op; + + /* vtmon_instances should not more than the MAC_BSC_MAX_TEMP_NUM */ + if ((dev_params->vtmon_instances > MAC_BSC_MAX_TEMP_NUM) || + (dev_params->vtmon_instances <= 0)) { + WB_MAC_BSC_ERROR("VTMON instance number %d more than the max number: %d\n", + dev_params->vtmon_instances, MAC_BSC_MAX_TEMP_NUM); + return -1; + } + + /* vtmon read operation steps should not more than the MAC_BSC_MAX_READ_REG_STEP */ + if ((dev_params->vtmon_read_ops > MAC_BSC_MAX_READ_REG_STEP) || + (dev_params->vtmon_read_ops <=0)) { + WB_MAC_BSC_ERROR("VTMON read ops number %d more than the max step: %d\n", + dev_params->vtmon_read_ops, MAC_BSC_MAX_READ_REG_STEP); + return -1; + } + + /* the last operation must be I2C_READ to get temperature register value */ + last_op = &dev_params->vtmon_read[dev_params->vtmon_read_ops - 1]; + if (last_op->op != I2C_READ) { + WB_MAC_BSC_ERROR("VTMON read ops config error, last operation not I2C_READ, last step: %d, op_code: %d\n", + dev_params->vtmon_read_ops - 1, last_op->op); + return -1; + } + + /* the address operation steps should not more than the vtmon_read_ops and not the last step */ + if ((dev_params->sbus_addr_op >= (dev_params->vtmon_read_ops - 1)) || + (dev_params->sbus_addr_op < 0)) { + WB_MAC_BSC_ERROR("VTMON addr op step invalid, index %d, read ops: %d\n", + dev_params->sbus_addr_op, dev_params->vtmon_read_ops); + return -1; + } + + /* the address operation must be I2C_WRITE to set temperature register address */ + addr_op = &dev_params->vtmon_read[dev_params->sbus_addr_op]; + if (addr_op->op != I2C_WRITE) { + WB_MAC_BSC_ERROR("VTMON addr op config error, addr operation not I2C_WRITE, addr op step: %d, op_code: %d\n", + dev_params->sbus_addr_op, addr_op->op); + return -1; + } + + /* the error status operation steps should not more than the vtmon_read_ops and not the last step */ + if (dev_params->sbus_error_op >= (dev_params->vtmon_read_ops - 1)) { + WB_MAC_BSC_ERROR("VTMON error op step invalid, index %d, read ops: %d\n", + dev_params->sbus_error_op, dev_params->vtmon_read_ops); + return -1; + } + + /* if error status operation exist, it must be I2C_READ to get error status register */ + if (dev_params->sbus_error_op >=0) { + err_op = &dev_params->vtmon_read[dev_params->sbus_error_op]; + if (err_op->op != I2C_READ) { + WB_MAC_BSC_ERROR("VTMON error op config error, error operation not I2C_READ, error op step: %d, op_code: %d\n", + dev_params->sbus_error_op, err_op->op); + return -1; + } + } + WB_MAC_BSC_DEBUG("dev_params check ok, instance number: %d, read_ops: %d, addr_op: %d, error_op: %d\n", + dev_params->vtmon_instances, dev_params->vtmon_read_ops, + dev_params->sbus_addr_op, dev_params->sbus_error_op); + return 0; +} + +static int mac_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct mac_data *data; + int ret, mac_id, index; + + WB_MAC_BSC_DEBUG("=========mac_probe(%d-%04x)===========\n", + client->adapter->nr, client->addr); + + if (!client->adapter->algo->master_xfer) { + dev_err(&client->adapter->dev, "I2C level transfers not supported\n"); + return -EOPNOTSUPP; + } + + data = devm_kzalloc(&client->dev, sizeof(struct mac_data), GFP_KERNEL); + if (!data) { + dev_err(&client->dev, "Failed to devm_kzalloc.\n"); + return -ENOMEM; + } + + data->client = client; + i2c_set_clientdata(client, data); + + mac_id = id->driver_data; + ret = find_mac_config(mac_id, &index); + if (ret < 0) { + dev_err(&client->dev, "Failed to find mac config, mac id from driver_data: 0x%x\n", mac_id); + return -EINVAL; + } + data->dev_param = mac_temp_conf[index]; + ret = mac_bsc_config_check(&data->dev_param); + if (ret < 0) { + dev_err(&client->dev, "Invalid config parameter, mac id: 0x%x, config index: %d\n", + mac_id, index); + return -EINVAL; + } + + mac_bsc_setup(client); + + if (mac_id == TD4) { + ret = mac_bsc_init(client); + if (ret < 0) { + dev_err(&client->dev, "Failed to get mac id, ret: %d\n", ret); + return -EIO; + } + mac_id = ret; + ret = find_mac_config(mac_id, &index); + if (ret < 0) { + dev_err(&client->dev, "Failed to find mac config, mac id from chip: 0x%x\n", mac_id); + return -EINVAL; + } + data->dev_param = mac_temp_conf[index]; + ret = mac_bsc_config_check(&data->dev_param); + if (ret < 0) { + dev_err(&client->dev, "Invalid config parameter, mac id: 0x%x, config index: %d\n", + mac_id, index); + return -EINVAL; + } + } + + WB_MAC_BSC_DEBUG("mac_id: 0x%x, config index: %d\n", mac_id, index); + + mutex_init(&data->update_lock); + data->hwmon_dev = hwmon_device_register_with_groups(&client->dev, client->name, data, mac_hwmon_groups); + if (IS_ERR(data->hwmon_dev)) { + dev_err(&client->dev, "Failed to register mac bsc hwmon\n"); + return PTR_ERR(data->hwmon_dev); + } + + dev_info(&client->dev, "Register mac bsc %x with %d vtmon instance number success\n", + mac_id, data->dev_param.vtmon_instances); + return 0; +} + +static int mac_remove(struct i2c_client *client) +{ + struct mac_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + return 0; +} + +static const struct i2c_device_id mac_id_table[] = { + { "wb_mac_bsc_td3", TD3 }, + { "wb_mac_bsc_td3_x2", TD3_X2 }, + { "wb_mac_bsc_td4", TD4 }, + { "wb_mac_bsc_th3", TH3 }, + { "wb_mac_bsc_th4", TH4 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, mac_id_table); + +static struct i2c_driver wb_mac_bsc_driver = { + .driver = { + .name = "wb_mac_bsc", + }, + .probe = mac_probe, + .remove = mac_remove, + .id_table = mac_id_table, +}; + +module_i2c_driver(wb_mac_bsc_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("mac bsc driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_optoe.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_optoe.c new file mode 100644 index 000000000000..c09162368ad0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_optoe.c @@ -0,0 +1,1192 @@ +/* + * optoe.c - A driver to read and write the EEPROM on optical transceivers + * (SFP, QSFP and similar I2C based devices) + * + * Copyright (C) 2014 Cumulus networks Inc. + * Copyright (C) 2017 Finisar Corp. + * + * 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 Freeoftware Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/* + * Description: + * a) Optical transceiver EEPROM read/write transactions are just like + * the at24 eeproms managed by the at24.c i2c driver + * b) The register/memory layout is up to 256 128 byte pages defined by + * a "pages valid" register and switched via a "page select" + * register as explained in below diagram. + * c) 256 bytes are mapped at a time. 'Lower page 00h' is the first 128 + * bytes of address space, and always references the same + * location, independent of the page select register. + * All mapped pages are mapped into the upper 128 bytes + * (offset 128-255) of the i2c address. + * d) Devices with one I2C address (eg QSFP) use I2C address 0x50 + * (A0h in the spec), and map all pages in the upper 128 bytes + * of that address. + * e) Devices with two I2C addresses (eg SFP) have 256 bytes of data + * at I2C address 0x50, and 256 bytes of data at I2C address + * 0x51 (A2h in the spec). Page selection and paged access + * only apply to this second I2C address (0x51). + * e) The address space is presented, by the driver, as a linear + * address space. For devices with one I2C client at address + * 0x50 (eg QSFP), offset 0-127 are in the lower + * half of address 50/A0h/client[0]. Offset 128-255 are in + * page 0, 256-383 are page 1, etc. More generally, offset + * 'n' resides in page (n/128)-1. ('page -1' is the lower + * half, offset 0-127). + * f) For devices with two I2C clients at address 0x50 and 0x51 (eg SFP), + * the address space places offset 0-127 in the lower + * half of 50/A0/client[0], offset 128-255 in the upper + * half. Offset 256-383 is in the lower half of 51/A2/client[1]. + * Offset 384-511 is in page 0, in the upper half of 51/A2/... + * Offset 512-639 is in page 1, in the upper half of 51/A2/... + * Offset 'n' is in page (n/128)-3 (for n > 383) + * + * One I2c addressed (eg QSFP) Memory Map + * + * 2-Wire Serial Address: 1010000x + * + * Lower Page 00h (128 bytes) + * ===================== + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * |Page Select Byte(127)| + * ===================== + * | + * | + * | + * | + * V + * ------------------------------------------------------------ + * | | | | + * | | | | + * | | | | + * | | | | + * | | | | + * | | | | + * | | | | + * | | | | + * | | | | + * V V V V + * ------------ -------------- --------------- -------------- + * | | | | | | | | + * | Upper | | Upper | | Upper | | Upper | + * | Page 00h | | Page 01h | | Page 02h | | Page 03h | + * | | | (Optional) | | (Optional) | | (Optional | + * | | | | | | | for Cable | + * | | | | | | | Assemblies) | + * | ID | | AST | | User | | | + * | Fields | | Table | | EEPROM Data | | | + * | | | | | | | | + * | | | | | | | | + * | | | | | | | | + * ------------ -------------- --------------- -------------- + * + * The SFF 8436 (QSFP) spec only defines the 4 pages described above. + * In anticipation of future applications and devices, this driver + * supports access to the full architected range, 256 pages. + * + * The CMIS (Common Management Interface Specification) defines use of + * considerably more pages (at least to page 0xAF), which this driver + * supports. + * + * NOTE: This version of the driver ONLY SUPPORTS BANK 0 PAGES on CMIS + * devices. + * + **/ + +/* #define DEBUG 1 */ + +#undef EEPROM_CLASS +#ifdef CONFIG_EEPROM_CLASS +#define EEPROM_CLASS +#endif +#ifdef CONFIG_EEPROM_CLASS_MODULE +#define EEPROM_CLASS +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define mem_clear(data, size) memset((data), 0, (size)) +#ifdef EEPROM_CLASS +#include +#endif + +#include + +/* The maximum length of a port name */ +#define MAX_PORT_NAME_LEN 20 + +struct optoe_platform_data { + u32 byte_len; /* size (sum of all addr) */ + u16 page_size; /* for writes */ + u8 flags; + void *dummy1; /* backward compatibility */ + void *dummy2; /* backward compatibility */ + +#ifdef EEPROM_CLASS + struct eeprom_platform_data *eeprom_data; +#endif + char port_name[MAX_PORT_NAME_LEN]; +}; + +/* fundamental unit of addressing for EEPROM */ +#define OPTOE_PAGE_SIZE 128 +/* + * Single address devices (eg QSFP) have 256 pages, plus the unpaged + * low 128 bytes. If the device does not support paging, it is + * only 2 'pages' long. + */ +#define OPTOE_ARCH_PAGES 256 +#define ONE_ADDR_EEPROM_SIZE ((1 + OPTOE_ARCH_PAGES) * OPTOE_PAGE_SIZE) +#define ONE_ADDR_EEPROM_UNPAGED_SIZE (2 * OPTOE_PAGE_SIZE) +/* + * Dual address devices (eg SFP) have 256 pages, plus the unpaged + * low 128 bytes, plus 256 bytes at 0x50. If the device does not + * support paging, it is 4 'pages' long. + */ +#define TWO_ADDR_EEPROM_SIZE ((3 + OPTOE_ARCH_PAGES) * OPTOE_PAGE_SIZE) +#define TWO_ADDR_EEPROM_UNPAGED_SIZE (4 * OPTOE_PAGE_SIZE) +#define TWO_ADDR_NO_0X51_SIZE (2 * OPTOE_PAGE_SIZE) + +/* a few constants to find our way around the EEPROM */ +#define OPTOE_PAGE_SELECT_REG 0x7F +#define ONE_ADDR_PAGEABLE_REG 0x02 +#define QSFP_NOT_PAGEABLE (1<<2) +#define CMIS_NOT_PAGEABLE (1<<7) +#define TWO_ADDR_PAGEABLE_REG 0x40 +#define TWO_ADDR_PAGEABLE (1<<4) +#define TWO_ADDR_0X51_REG 92 +#define TWO_ADDR_0X51_SUPP (1<<6) +#define OPTOE_ID_REG 0 +#define OPTOE_READ_OP 0 +#define OPTOE_WRITE_OP 1 +#define OPTOE_EOF 0 /* used for access beyond end of device */ + +struct optoe_data { + struct optoe_platform_data chip; + int use_smbus; + char port_name[MAX_PORT_NAME_LEN]; + + /* + * Lock protects against activities from other Linux tasks, + * but not from changes by other I2C masters. + */ + struct mutex lock; + struct bin_attribute bin; + struct attribute_group attr_group; + + u8 *writebuf; + unsigned int write_max; + + unsigned int num_addresses; + +#ifdef EEPROM_CLASS + struct eeprom_device *eeprom_dev; +#endif + + /* dev_class: ONE_ADDR (QSFP) or TWO_ADDR (SFP) */ + int dev_class; + + struct i2c_client *client[]; +}; + +/* + * This parameter is to help this driver avoid blocking other drivers out + * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C + * clock, one 256 byte read takes about 1/43 second which is excessive; + * but the 1/170 second it takes at 400 kHz may be quite reasonable; and + * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible. + * + * This value is forced to be a power of two so that writes align on pages. + */ +static unsigned int io_limit = OPTOE_PAGE_SIZE; + +/* + * specs often allow 5 msec for a page write, sometimes 20 msec; + * it's important to recover from write timeouts. + */ +static unsigned int write_timeout = 50; + +/* + * flags to distinguish one-address (QSFP family) from two-address (SFP family) + * If the family is not known, figure it out when the device is accessed + */ +#define ONE_ADDR 1 +#define TWO_ADDR 2 +#define CMIS_ADDR 3 + +static const struct i2c_device_id optoe_ids[] = { + { "wb_optoe1", ONE_ADDR }, + { "wb_optoe2", TWO_ADDR }, + { "wb_optoe3", CMIS_ADDR }, + { "wb_sff8436", ONE_ADDR }, + { "wb_24c04", TWO_ADDR }, + { /* END OF LIST */ } +}; +MODULE_DEVICE_TABLE(i2c, optoe_ids); + +/*-------------------------------------------------------------------------*/ +/* + * This routine computes the addressing information to be used for + * a given r/w request. + * + * Task is to calculate the client (0 = i2c addr 50, 1 = i2c addr 51), + * the page, and the offset. + * + * Handles both single address (eg QSFP) and two address (eg SFP). + * For SFP, offset 0-255 are on client[0], >255 is on client[1] + * Offset 256-383 are on the lower half of client[1] + * Pages are accessible on the upper half of client[1]. + * Offset >383 are in 128 byte pages mapped into the upper half + * + * For QSFP, all offsets are on client[0] + * offset 0-127 are on the lower half of client[0] (no paging) + * Pages are accessible on the upper half of client[1]. + * Offset >127 are in 128 byte pages mapped into the upper half + * + * Callers must not read/write beyond the end of a client or a page + * without recomputing the client/page. Hence offset (within page) + * plus length must be less than or equal to 128. (Note that this + * routine does not have access to the length of the call, hence + * cannot do the validity check.) + * + * Offset within Lower Page 00h and Upper Page 00h are not recomputed + */ + +static uint8_t optoe_translate_offset(struct optoe_data *optoe, + loff_t *offset, struct i2c_client **client) +{ + unsigned int page = 0; + + *client = optoe->client[0]; + + /* if SFP style, offset > 255, shift to i2c addr 0x51 */ + if (optoe->dev_class == TWO_ADDR) { + if (*offset > 255) { + /* like QSFP, but shifted to client[1] */ + *client = optoe->client[1]; + *offset -= 256; + } + } + + /* + * if offset is in the range 0-128... + * page doesn't matter (using lower half), return 0. + * offset is already correct (don't add 128 to get to paged area) + */ + if (*offset < OPTOE_PAGE_SIZE) + return page; + + /* note, page will always be positive since *offset >= 128 */ + page = (*offset >> 7)-1; + /* 0x80 places the offset in the top half, offset is last 7 bits */ + *offset = OPTOE_PAGE_SIZE + (*offset & 0x7f); + + return page; /* note also returning client and offset */ +} + +static ssize_t optoe_eeprom_read(struct optoe_data *optoe, + struct i2c_client *client, + char *buf, unsigned int offset, size_t count) +{ + struct i2c_msg msg[2]; + u8 msgbuf[2]; + unsigned long timeout, read_time; + int status, i; + + mem_clear(msg, sizeof(msg)); + + switch (optoe->use_smbus) { + case I2C_SMBUS_I2C_BLOCK_DATA: + /*smaller eeproms can work given some SMBus extension calls */ + if (count > I2C_SMBUS_BLOCK_MAX) + count = I2C_SMBUS_BLOCK_MAX; + break; + case I2C_SMBUS_WORD_DATA: + /* Check for odd length transaction */ + count = (count == 1) ? 1 : 2; + break; + case I2C_SMBUS_BYTE_DATA: + count = 1; + break; + default: + /* + * When we have a better choice than SMBus calls, use a + * combined I2C message. Write address; then read up to + * io_limit data bytes. msgbuf is u8 and will cast to our + * needs. + */ + i = 0; + msgbuf[i++] = offset; + + msg[0].addr = client->addr; + msg[0].buf = msgbuf; + msg[0].len = i; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].buf = buf; + msg[1].len = count; + } + + /* + * Reads fail if the previous write didn't complete yet. We may + * loop a few times until this one succeeds, waiting at least + * long enough for one entire page write to work. + */ + timeout = jiffies + msecs_to_jiffies(write_timeout); + do { + read_time = jiffies; + + switch (optoe->use_smbus) { + case I2C_SMBUS_I2C_BLOCK_DATA: + status = i2c_smbus_read_i2c_block_data(client, offset, + count, buf); + break; + case I2C_SMBUS_WORD_DATA: + status = i2c_smbus_read_word_data(client, offset); + if (status >= 0) { + buf[0] = status & 0xff; + if (count == 2) + buf[1] = status >> 8; + status = count; + } + break; + case I2C_SMBUS_BYTE_DATA: + status = i2c_smbus_read_byte_data(client, offset); + if (status >= 0) { + buf[0] = status; + status = count; + } + break; + default: + status = i2c_transfer(client->adapter, msg, 2); + if (status == 2) + status = count; + } + + dev_dbg(&client->dev, "eeprom read %zu@%d --> %d (%ld)\n", + count, offset, status, jiffies); + + if (status == count) /* happy path */ + return count; + + /* REVISIT: at HZ=100, this is sloooow */ + usleep_range(1000, 2000); + } while (time_before(read_time, timeout)); + + return -ETIMEDOUT; +} + +static ssize_t optoe_eeprom_write(struct optoe_data *optoe, + struct i2c_client *client, + const char *buf, + unsigned int offset, size_t count) +{ + struct i2c_msg msg; + ssize_t status; + unsigned long timeout, write_time; + unsigned int next_page_start; + int i = 0; + + /* write max is at most a page + * (In this driver, write_max is actually one byte!) + */ + if (count > optoe->write_max) + count = optoe->write_max; + + /* shorten count if necessary to avoid crossing page boundary */ + next_page_start = roundup(offset + 1, OPTOE_PAGE_SIZE); + if (offset + count > next_page_start) + count = next_page_start - offset; + + switch (optoe->use_smbus) { + case I2C_SMBUS_I2C_BLOCK_DATA: + /*smaller eeproms can work given some SMBus extension calls */ + if (count > I2C_SMBUS_BLOCK_MAX) + count = I2C_SMBUS_BLOCK_MAX; + break; + case I2C_SMBUS_WORD_DATA: + /* Check for odd length transaction */ + count = (count == 1) ? 1 : 2; + break; + case I2C_SMBUS_BYTE_DATA: + count = 1; + break; + default: + /* If we'll use I2C calls for I/O, set up the message */ + msg.addr = client->addr; + msg.flags = 0; + + /* msg.buf is u8 and casts will mask the values */ + msg.buf = optoe->writebuf; + + msg.buf[i++] = offset; + memcpy(&msg.buf[i], buf, count); + msg.len = i + count; + break; + } + + /* + * Reads fail if the previous write didn't complete yet. We may + * loop a few times until this one succeeds, waiting at least + * long enough for one entire page write to work. + */ + timeout = jiffies + msecs_to_jiffies(write_timeout); + do { + write_time = jiffies; + + switch (optoe->use_smbus) { + case I2C_SMBUS_I2C_BLOCK_DATA: + status = i2c_smbus_write_i2c_block_data(client, + offset, count, buf); + if (status == 0) + status = count; + break; + case I2C_SMBUS_WORD_DATA: + if (count == 2) { + status = i2c_smbus_write_word_data(client, + offset, (u16)((buf[0])|(buf[1] << 8))); + } else { + /* count = 1 */ + status = i2c_smbus_write_byte_data(client, + offset, buf[0]); + } + if (status == 0) + status = count; + break; + case I2C_SMBUS_BYTE_DATA: + status = i2c_smbus_write_byte_data(client, offset, + buf[0]); + if (status == 0) + status = count; + break; + default: + status = i2c_transfer(client->adapter, &msg, 1); + if (status == 1) + status = count; + break; + } + + dev_dbg(&client->dev, "eeprom write %zu@%d --> %ld (%lu)\n", + count, offset, (long int) status, jiffies); + + if (status == count) + return count; + + /* REVISIT: at HZ=100, this is sloooow */ + usleep_range(1000, 2000); + } while (time_before(write_time, timeout)); + + return -ETIMEDOUT; +} + +static ssize_t optoe_eeprom_update_client(struct optoe_data *optoe, + char *buf, loff_t off, + size_t count, int opcode) +{ + struct i2c_client *client; + ssize_t retval = 0; + uint8_t page = 0; + uint8_t loc; + loff_t phy_offset = off; + int ret = 0; + + page = optoe_translate_offset(optoe, &phy_offset, &client); + dev_dbg(&client->dev, + "%s off %lld page:%d phy_offset:%lld, count:%ld, opcode:%d\n", + __func__, off, page, phy_offset, (long int) count, opcode); + + ret = optoe_eeprom_read(optoe, client, &loc, OPTOE_PAGE_SELECT_REG, 1); + if (ret < 0) { + dev_dbg(&client->dev, "Read page register for get now location page failed. ret:%d\n", ret); + return ret; + } + + /* Only when read and now location page is inconsistent, will doing switch page */ + if (loc != page) { + ret = optoe_eeprom_write(optoe, client, &page, + OPTOE_PAGE_SELECT_REG, 1); + if (ret < 0) { + dev_dbg(&client->dev, + "Write page register for page %d failed ret:%d!\n", + page, ret); + return ret; + } + } + + while (count) { + ssize_t status; + + if (opcode == OPTOE_READ_OP) { + status = optoe_eeprom_read(optoe, client, + buf, phy_offset, count); + } else { + status = optoe_eeprom_write(optoe, client, + buf, phy_offset, count); + } + if (status <= 0) { + if (retval == 0) + retval = status; + break; + } + buf += status; + phy_offset += status; + count -= status; + retval += status; + } + + return retval; +} + +/* + * Figure out if this access is within the range of supported pages. + * Note this is called on every access because we don't know if the + * module has been replaced since the last call. + * If/when modules support more pages, this is the routine to update + * to validate and allow access to additional pages. + * + * Returns updated len for this access: + * - entire access is legal, original len is returned. + * - access begins legal but is too long, len is truncated to fit. + * - initial offset exceeds supported pages, return OPTOE_EOF (zero) + */ +static ssize_t optoe_page_legal(struct optoe_data *optoe, + loff_t off, size_t len) +{ + struct i2c_client *client = optoe->client[0]; + u8 regval; + int not_pageable; + int status; + size_t maxlen; + + if (off < 0) + return -EINVAL; + if (optoe->dev_class == TWO_ADDR) { + /* SFP case */ + /* if only using addr 0x50 (first 256 bytes) we're good */ + if ((off + len) <= TWO_ADDR_NO_0X51_SIZE) + return len; + /* if offset exceeds possible pages, we're not good */ + if (off >= TWO_ADDR_EEPROM_SIZE) + return OPTOE_EOF; + /* in between, are pages supported? */ + status = optoe_eeprom_read(optoe, client, ®val, + TWO_ADDR_PAGEABLE_REG, 1); + if (status < 0) + return status; /* error out (no module?) */ + if (regval & TWO_ADDR_PAGEABLE) { + /* Pages supported, trim len to the end of pages */ + maxlen = TWO_ADDR_EEPROM_SIZE - off; + } else { + /* pages not supported, trim len to unpaged size */ + if (off >= TWO_ADDR_EEPROM_UNPAGED_SIZE) + return OPTOE_EOF; + + /* will be accessing addr 0x51, is that supported? */ + /* byte 92, bit 6 implies DDM support, 0x51 support */ + status = optoe_eeprom_read(optoe, client, ®val, + TWO_ADDR_0X51_REG, 1); + if (status < 0) + return status; + if (regval & TWO_ADDR_0X51_SUPP) { + /* addr 0x51 is OK */ + maxlen = TWO_ADDR_EEPROM_UNPAGED_SIZE - off; + } else { + /* addr 0x51 NOT supported, trim to 256 max */ + if (off >= TWO_ADDR_NO_0X51_SIZE) + return OPTOE_EOF; + maxlen = TWO_ADDR_NO_0X51_SIZE - off; + } + } + len = (len > maxlen) ? maxlen : len; + dev_dbg(&client->dev, + "page_legal, SFP, off %lld len %ld\n", + off, (long int) len); + } else { + /* QSFP case, CMIS case */ + /* if no pages needed, we're good */ + if ((off + len) <= ONE_ADDR_EEPROM_UNPAGED_SIZE) + return len; + /* if offset exceeds possible pages, we're not good */ + if (off >= ONE_ADDR_EEPROM_SIZE) + return OPTOE_EOF; + /* in between, are pages supported? */ + status = optoe_eeprom_read(optoe, client, ®val, + ONE_ADDR_PAGEABLE_REG, 1); + if (status < 0) + return status; /* error out (no module?) */ + + if (optoe->dev_class == ONE_ADDR) { + not_pageable = QSFP_NOT_PAGEABLE; + } else { + not_pageable = CMIS_NOT_PAGEABLE; + } + dev_dbg(&client->dev, + "Paging Register: 0x%x; not_pageable mask: 0x%x\n", + regval, not_pageable); + + if (regval & not_pageable) { + /* pages not supported, trim len to unpaged size */ + if (off >= ONE_ADDR_EEPROM_UNPAGED_SIZE) + return OPTOE_EOF; + maxlen = ONE_ADDR_EEPROM_UNPAGED_SIZE - off; + } else { + /* Pages supported, trim len to the end of pages */ + maxlen = ONE_ADDR_EEPROM_SIZE - off; + } + len = (len > maxlen) ? maxlen : len; + dev_dbg(&client->dev, + "page_legal, QSFP, off %lld len %ld\n", + off, (long int) len); + } + return len; +} + +static ssize_t optoe_read_write(struct optoe_data *optoe, + char *buf, loff_t off, size_t len, int opcode) +{ + struct i2c_client *client = optoe->client[0]; + int chunk; + int status = 0; + ssize_t retval; + size_t pending_len = 0, chunk_len = 0; + loff_t chunk_offset = 0, chunk_start_offset = 0; + loff_t chunk_end_offset = 0; + + dev_dbg(&client->dev, + "%s: off %lld len:%ld, opcode:%s\n", + __func__, off, (long int) len, + (opcode == OPTOE_READ_OP) ? "r" : "w"); + if (unlikely(!len)) + return len; + + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&optoe->lock); + + /* + * Confirm this access fits within the device suppored addr range + */ + status = optoe_page_legal(optoe, off, len); + if ((status == OPTOE_EOF) || (status < 0)) { + mutex_unlock(&optoe->lock); + return status; + } + len = status; + + /* + * For each (128 byte) chunk involved in this request, issue a + * separate call to sff_eeprom_update_client(), to + * ensure that each access recalculates the client/page + * and writes the page register as needed. + * Note that chunk to page mapping is confusing, is different for + * QSFP and SFP, and never needs to be done. Don't try! + */ + pending_len = len; /* amount remaining to transfer */ + retval = 0; /* amount transferred */ + for (chunk = off >> 7; chunk <= (off + len - 1) >> 7; chunk++) { + + /* + * Compute the offset and number of bytes to be read/write + * + * 1. start at an offset not equal to 0 (within the chunk) + * and read/write less than the rest of the chunk + * 2. start at an offset not equal to 0 and read/write the rest + * of the chunk + * 3. start at offset 0 (within the chunk) and read/write less + * than entire chunk + * 4. start at offset 0 (within the chunk), and read/write + * the entire chunk + */ + chunk_start_offset = chunk * OPTOE_PAGE_SIZE; + chunk_end_offset = chunk_start_offset + OPTOE_PAGE_SIZE; + + if (chunk_start_offset < off) { + chunk_offset = off; + if ((off + pending_len) < chunk_end_offset) + chunk_len = pending_len; + else + chunk_len = chunk_end_offset - off; + } else { + chunk_offset = chunk_start_offset; + if (pending_len < OPTOE_PAGE_SIZE) + chunk_len = pending_len; + else + chunk_len = OPTOE_PAGE_SIZE; + } + + dev_dbg(&client->dev, + "sff_r/w: off %lld, len %ld, chunk_start_offset %lld, chunk_offset %lld, chunk_len %ld, pending_len %ld\n", + off, (long int) len, chunk_start_offset, chunk_offset, + (long int) chunk_len, (long int) pending_len); + + /* + * note: chunk_offset is from the start of the EEPROM, + * not the start of the chunk + */ + status = optoe_eeprom_update_client(optoe, buf, + chunk_offset, chunk_len, opcode); + if (status != chunk_len) { + /* This is another 'no device present' path */ + dev_dbg(&client->dev, + "o_u_c: chunk %d c_offset %lld c_len %ld failed %d!\n", + chunk, chunk_offset, (long int) chunk_len, status); + if (status > 0) + retval += status; + if (retval == 0) + retval = status; + break; + } + buf += status; + pending_len -= status; + retval += status; + } + mutex_unlock(&optoe->lock); + + return retval; +} + +static ssize_t optoe_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct i2c_client *client = to_i2c_client(container_of(kobj, + struct device, kobj)); + struct optoe_data *optoe = i2c_get_clientdata(client); + + return optoe_read_write(optoe, buf, off, count, OPTOE_READ_OP); +} + +static ssize_t optoe_bin_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct i2c_client *client = to_i2c_client(container_of(kobj, + struct device, kobj)); + struct optoe_data *optoe = i2c_get_clientdata(client); + + return optoe_read_write(optoe, buf, off, count, OPTOE_WRITE_OP); +} + +static int optoe_remove(struct i2c_client *client) +{ + struct optoe_data *optoe; + int i; + + optoe = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &optoe->attr_group); + sysfs_remove_bin_file(&client->dev.kobj, &optoe->bin); + + for (i = 1; i < optoe->num_addresses; i++) + i2c_unregister_device(optoe->client[i]); + +#ifdef EEPROM_CLASS + eeprom_device_unregister(optoe->eeprom_dev); +#endif + + kfree(optoe->writebuf); + kfree(optoe); + return 0; +} + +static ssize_t show_dev_class(struct device *dev, + struct device_attribute *dattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct optoe_data *optoe = i2c_get_clientdata(client); + ssize_t count; + + mutex_lock(&optoe->lock); + count = sprintf(buf, "%d\n", optoe->dev_class); + mutex_unlock(&optoe->lock); + + return count; +} + +static ssize_t set_dev_class(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct optoe_data *optoe = i2c_get_clientdata(client); + int dev_class; + + /* + * dev_class is actually the number of i2c addresses used, thus + * legal values are "1" (QSFP class) and "2" (SFP class) + * And... CMIS spec is 1 i2c address, but puts the pageable + * bit in a different location, so CMIS devices are "3" + */ + + if (kstrtoint(buf, 0, &dev_class) != 0 || + dev_class < 1 || dev_class > 3) + return -EINVAL; + + mutex_lock(&optoe->lock); + if (dev_class == TWO_ADDR) { + /* SFP family */ + /* if it doesn't exist, create 0x51 i2c address */ + if (!optoe->client[1]) { + optoe->client[1] = i2c_new_dummy_device(client->adapter, 0x51); + if (!optoe->client[1]) { + dev_err(&client->dev, + "address 0x51 unavailable\n"); + mutex_unlock(&optoe->lock); + return -EADDRINUSE; + } + } + optoe->bin.size = TWO_ADDR_EEPROM_SIZE; + optoe->num_addresses = 2; + } else { + /* one-address (eg QSFP) and CMIS family */ + /* if it exists, remove 0x51 i2c address */ + if (optoe->client[1]) { + i2c_unregister_device(optoe->client[1]); + optoe->client[1] = NULL; + } + optoe->bin.size = ONE_ADDR_EEPROM_SIZE; + optoe->num_addresses = 1; + } + optoe->dev_class = dev_class; + mutex_unlock(&optoe->lock); + + return count; +} + +/* + * if using the EEPROM CLASS driver, we don't report a port_name, + * the EEPROM CLASS drive handles that. Hence all this code is + * only compiled if we are NOT using the EEPROM CLASS driver. + */ +#ifndef EEPROM_CLASS + +static ssize_t show_port_name(struct device *dev, + struct device_attribute *dattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct optoe_data *optoe = i2c_get_clientdata(client); + ssize_t count; + + mutex_lock(&optoe->lock); + count = sprintf(buf, "%s\n", optoe->port_name); + mutex_unlock(&optoe->lock); + + return count; +} + +static ssize_t set_port_name(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct optoe_data *optoe = i2c_get_clientdata(client); + char port_name[MAX_PORT_NAME_LEN]; + + /* no checking, this value is not used except by show_port_name */ + + if (sscanf(buf, "%19s", port_name) != 1) + return -EINVAL; + + mutex_lock(&optoe->lock); + strcpy(optoe->port_name, port_name); + mutex_unlock(&optoe->lock); + + return count; +} + +static DEVICE_ATTR(port_name, 0644, show_port_name, set_port_name); +#endif /* if NOT defined EEPROM_CLASS, the common case */ + +static DEVICE_ATTR(dev_class, 0644, show_dev_class, set_dev_class); + +static struct attribute *optoe_attrs[] = { +#ifndef EEPROM_CLASS + &dev_attr_port_name.attr, +#endif + &dev_attr_dev_class.attr, + NULL, +}; + +static struct attribute_group optoe_attr_group = { + .attrs = optoe_attrs, +}; + +static int optoe_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err; + int use_smbus = 0; + struct optoe_platform_data chip; + struct optoe_data *optoe; + int num_addresses = 0; + char port_name[MAX_PORT_NAME_LEN]; + + if (client->addr != 0x50) { + dev_dbg(&client->dev, "probe, bad i2c addr: 0x%x\n", + client->addr); + err = -EINVAL; + goto exit; + } + + if (client->dev.platform_data) { + chip = *(struct optoe_platform_data *)client->dev.platform_data; + /* take the port name from the supplied platform data */ +#ifdef EEPROM_CLASS + strncpy(port_name, chip.eeprom_data->label, MAX_PORT_NAME_LEN); +#else + memcpy(port_name, chip.port_name, MAX_PORT_NAME_LEN); +#endif + dev_dbg(&client->dev, + "probe, chip provided, flags:0x%x; name: %s\n", + chip.flags, client->name); + } else { + if (!id->driver_data) { + err = -ENODEV; + goto exit; + } + dev_dbg(&client->dev, "probe, building chip\n"); + strcpy(port_name, "unitialized"); + chip.flags = 0; +#ifdef EEPROM_CLASS + chip.eeprom_data = NULL; +#endif + } + + /* Use I2C operations unless we're stuck with SMBus extensions. */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + use_smbus = I2C_SMBUS_I2C_BLOCK_DATA; + } else if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_WORD_DATA)) { + use_smbus = I2C_SMBUS_WORD_DATA; + } else if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BYTE_DATA)) { + use_smbus = I2C_SMBUS_BYTE_DATA; + } else { + err = -EPFNOSUPPORT; + goto exit; + } + } + + /* + * Make room for two i2c clients + */ + num_addresses = 2; + + optoe = kzalloc(sizeof(struct optoe_data) + + num_addresses * sizeof(struct i2c_client *), + GFP_KERNEL); + if (!optoe) { + err = -ENOMEM; + goto exit; + } + + mutex_init(&optoe->lock); + + /* determine whether this is a one-address or two-address module */ + if ((strcmp(client->name, "wb_optoe1") == 0) || + (strcmp(client->name, "wb_sff8436") == 0)) { + /* one-address (eg QSFP) family */ + optoe->dev_class = ONE_ADDR; + chip.byte_len = ONE_ADDR_EEPROM_SIZE; + num_addresses = 1; + } else if ((strcmp(client->name, "wb_optoe2") == 0) || + (strcmp(client->name, "wb_24c04") == 0)) { + /* SFP family */ + optoe->dev_class = TWO_ADDR; + chip.byte_len = TWO_ADDR_EEPROM_SIZE; + num_addresses = 2; + } else if (strcmp(client->name, "wb_optoe3") == 0) { + /* CMIS spec */ + optoe->dev_class = CMIS_ADDR; + chip.byte_len = ONE_ADDR_EEPROM_SIZE; + num_addresses = 1; + } else { /* those were the only choices */ + err = -EINVAL; + goto exit; + } + + dev_dbg(&client->dev, "dev_class: %d\n", optoe->dev_class); + optoe->use_smbus = use_smbus; + optoe->chip = chip; + optoe->num_addresses = num_addresses; + memcpy(optoe->port_name, port_name, MAX_PORT_NAME_LEN); + + /* + * Export the EEPROM bytes through sysfs, since that's convenient. + * By default, only root should see the data (maybe passwords etc) + */ + sysfs_bin_attr_init(&optoe->bin); + optoe->bin.attr.name = "eeprom"; + optoe->bin.attr.mode = 0444; + optoe->bin.read = optoe_bin_read; + optoe->bin.size = chip.byte_len; + + if (!use_smbus || + (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) || + i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WRITE_WORD_DATA) || + i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { + /* + * NOTE: AN-2079 + * Finisar recommends that the host implement 1 byte writes + * only since this module only supports 32 byte page boundaries. + * 2 byte writes are acceptable for PE and Vout changes per + * Application Note AN-2071. + */ + unsigned int write_max = 1; + + optoe->bin.write = optoe_bin_write; + optoe->bin.attr.mode |= 0200; + + if (write_max > io_limit) + write_max = io_limit; + if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX) + write_max = I2C_SMBUS_BLOCK_MAX; + optoe->write_max = write_max; + + /* buffer (data + address at the beginning) */ + optoe->writebuf = kmalloc(write_max + 2, GFP_KERNEL); + if (!optoe->writebuf) { + err = -ENOMEM; + goto exit_kfree; + } + } else { + dev_warn(&client->dev, + "cannot write due to controller restrictions."); + } + + optoe->client[0] = client; + + /* SFF-8472 spec requires that the second I2C address be 0x51 */ + if (num_addresses == 2) { + optoe->client[1] = i2c_new_dummy_device(client->adapter, 0x51); + if (!optoe->client[1]) { + dev_err(&client->dev, "address 0x51 unavailable\n"); + err = -EADDRINUSE; + goto err_struct; + } + } + + /* create the sysfs eeprom file */ + err = sysfs_create_bin_file(&client->dev.kobj, &optoe->bin); + if (err) + goto err_struct; + + optoe->attr_group = optoe_attr_group; + + err = sysfs_create_group(&client->dev.kobj, &optoe->attr_group); + if (err) { + dev_err(&client->dev, "failed to create sysfs attribute group.\n"); + goto err_struct; + } + +#ifdef EEPROM_CLASS + optoe->eeprom_dev = eeprom_device_register(&client->dev, + chip.eeprom_data); + if (IS_ERR(optoe->eeprom_dev)) { + dev_err(&client->dev, "error registering eeprom device.\n"); + err = PTR_ERR(optoe->eeprom_dev); + goto err_sysfs_cleanup; + } +#endif + + i2c_set_clientdata(client, optoe); + + dev_info(&client->dev, "%zu byte %s EEPROM, %s\n", + optoe->bin.size, client->name, + optoe->bin.write ? "read/write" : "read-only"); + + if (use_smbus == I2C_SMBUS_WORD_DATA || + use_smbus == I2C_SMBUS_BYTE_DATA) { + dev_notice(&client->dev, + "Falling back to %s reads, performance will suffer\n", + use_smbus == I2C_SMBUS_WORD_DATA ? "word" : "byte"); + } + + return 0; + +#ifdef EEPROM_CLASS +err_sysfs_cleanup: + sysfs_remove_group(&client->dev.kobj, &optoe->attr_group); + sysfs_remove_bin_file(&client->dev.kobj, &optoe->bin); +#endif + +err_struct: + if (num_addresses == 2) { + if (optoe->client[1]) { + i2c_unregister_device(optoe->client[1]); + optoe->client[1] = NULL; + } + } + + kfree(optoe->writebuf); +exit_kfree: + kfree(optoe); +exit: + dev_dbg(&client->dev, "probe error %d\n", err); + + return err; +} + +/*-------------------------------------------------------------------------*/ + +static struct i2c_driver optoe_driver = { + .driver = { + .name = "wb_optoe", + .owner = THIS_MODULE, + }, + .probe = optoe_probe, + .remove = optoe_remove, + .id_table = optoe_ids, +}; + +static int __init optoe_init(void) +{ + + if (!io_limit) { + pr_err("optoe: io_limit must not be 0!\n"); + return -EINVAL; + } + + io_limit = rounddown_pow_of_two(io_limit); + return i2c_add_driver(&optoe_driver); +} +module_init(optoe_init); + +static void __exit optoe_exit(void) +{ + i2c_del_driver(&optoe_driver); +} +module_exit(optoe_exit); + +MODULE_DESCRIPTION("Driver for optical transceiver (SFP, QSFP, ...) EEPROMs"); +MODULE_AUTHOR("support"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.c new file mode 100644 index 000000000000..757c100e4738 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.c @@ -0,0 +1,770 @@ +/* + * wb_pcie_dev.c + * ko to read/write pcie iomem and ioports through /dev/XXX device + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_pcie_dev.h" + +#define PROXY_NAME "wb-pci-dev" +#define MAX_NAME_SIZE (20) +#define MAX_PCIE_NUM (256) +#define PCI_RDWR_MAX_LEN (256) +#define PCIE_BUS_WIDTH_1 (1) +#define PCIE_BUS_WIDTH_2 (2) +#define PCIE_BUS_WIDTH_4 (4) + +static int g_pcie_dev_debug = 0; +static int g_pcie_dev_error = 0; + +module_param(g_pcie_dev_debug, int, S_IRUGO | S_IWUSR); +module_param(g_pcie_dev_error, int, S_IRUGO | S_IWUSR); + +#define PCIE_DEV_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_pcie_dev_debug) { \ + printk(KERN_INFO "[PCIE_DEV][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define PCIE_DEV_DEBUG_ERROR(fmt, args...) do { \ + if (g_pcie_dev_error) { \ + printk(KERN_ERR "[PCIE_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +typedef struct firmware_upg_s { + int upg_ctrl_base; + int upg_flash_base; +} firmware_upg_t; + +typedef struct wb_pci_dev_s { + const char *name; + uint32_t domain; + uint32_t bus; + uint32_t slot; + uint32_t fn; + uint32_t bar; + void __iomem *pci_mem_base; + uint32_t pci_io_base; + uint32_t bar_len; + uint32_t bar_flag; + uint32_t bus_width; + struct miscdevice misc; + void (*setreg)(struct wb_pci_dev_s *wb_pci_dev, int reg, u32 value); + u32 (*getreg)(struct wb_pci_dev_s *wb_pci_dev, int reg); + firmware_upg_t firmware_upg; +} wb_pci_dev_t; + +static wb_pci_dev_t* pcie_dev_arry[MAX_PCIE_NUM]; + +static void pci_dev_setreg_8(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) +{ + u8 w_value; + + w_value = (u8)(value & 0xff); + if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { + writeb(w_value, wb_pci_dev->pci_mem_base + reg); + } else { + outb(w_value, wb_pci_dev->pci_io_base + reg); + } + return; +} + +static void pci_dev_setreg_16(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) +{ + u16 w_value; + + w_value = (u16)(value & 0xffff); + if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { + writew(w_value, wb_pci_dev->pci_mem_base + reg); + } else { + outw(w_value, wb_pci_dev->pci_io_base + reg); + } + + return; +} + +static void pci_dev_setreg_32(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) +{ + + if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { + writel(value, wb_pci_dev->pci_mem_base + reg); + } else { + outl(value, wb_pci_dev->pci_io_base + reg); + } + return; +} + +static inline u32 pci_dev_getreg_8(wb_pci_dev_t *wb_pci_dev, int reg) +{ + u32 value; + + if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { + value = readb(wb_pci_dev->pci_mem_base + reg); + } else { + value = inb(wb_pci_dev->pci_io_base + reg); + } + + return value; +} + +static inline u32 pci_dev_getreg_16(wb_pci_dev_t *wb_pci_dev, int reg) +{ + u32 value; + + if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { + value = readw(wb_pci_dev->pci_mem_base + reg); + } else { + value = inw(wb_pci_dev->pci_io_base + reg); + } + + return value; +} + +static inline u32 pci_dev_getreg_32(wb_pci_dev_t *wb_pci_dev, int reg) +{ + u32 value; + + if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { + value = readl(wb_pci_dev->pci_mem_base + reg); + } else { + value = inl(wb_pci_dev->pci_io_base + reg); + } + + return value; +} + +static inline void pci_dev_setreg(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) +{ + wb_pci_dev->setreg(wb_pci_dev, reg, value); +} + +static inline u32 pci_dev_getreg(wb_pci_dev_t *wb_pci_dev, int reg) +{ + return wb_pci_dev->getreg(wb_pci_dev, reg); +} + +static int pci_dev_open(struct inode *inode, struct file *file) +{ + unsigned int minor = iminor(inode); + wb_pci_dev_t *wb_pci_dev; + + PCIE_DEV_DEBUG_VERBOSE("inode: %p, file: %p, minor: %u", inode, file, minor); + + if (minor >= MAX_PCIE_NUM) { + PCIE_DEV_DEBUG_ERROR("minor out of range, minor = %d.\n", minor); + return -ENODEV; + } + + wb_pci_dev = pcie_dev_arry[minor]; + if (wb_pci_dev == NULL) { + PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, open failed, minor = %d\n", minor); + return -ENODEV; + } + + file->private_data = wb_pci_dev; + return 0; +} + +static int pci_dev_release(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + return 0; +} + +static int pci_dev_read_tmp(wb_pci_dev_t *wb_pci_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int width, i, j; + u32 val; + + if (offset > wb_pci_dev->bar_len) { + PCIE_DEV_DEBUG_VERBOSE("offset:0x%x, bar len:0x%x, EOF.\n", offset, wb_pci_dev->bar_len); + return 0; + } + + width = wb_pci_dev->bus_width; + + if (offset % width) { + PCIE_DEV_DEBUG_ERROR("pci bus width:%d, offset:0x%x, read size %lu invalid.\n", + width, offset, count); + return -EINVAL; + } + + if (count > wb_pci_dev->bar_len - offset) { + PCIE_DEV_DEBUG_VERBOSE("read count out of range. input len:%lu, read len:%u.\n", + count, wb_pci_dev->bar_len - offset); + count = wb_pci_dev->bar_len - offset; + } + + for (i = 0; i < count; i += width) { + val = pci_dev_getreg(wb_pci_dev, offset + i); + for (j = 0; (j < width) && (i + j < count); j++) { + buf[i + j] = (val >> (8 * j)) & 0xff; + } + } + return count; +} + +static ssize_t pci_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) +{ + wb_pci_dev_t *wb_pci_dev; + int ret, read_len; + u8 buf_tmp[PCI_RDWR_MAX_LEN]; + + wb_pci_dev = file->private_data; + if (wb_pci_dev == NULL) { + PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, read failed.\n"); + return -EINVAL; + } + + if (count == 0) { + PCIE_DEV_DEBUG_ERROR("Invalid params, read count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(buf_tmp)) { + PCIE_DEV_DEBUG_VERBOSE("read count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); + count = sizeof(buf_tmp); + } + + mem_clear(buf_tmp, sizeof(buf_tmp)); + read_len = pci_dev_read_tmp(wb_pci_dev, *offset, buf_tmp, count); + if (read_len < 0) { + PCIE_DEV_DEBUG_ERROR("pci_dev_read_tmp failed, ret:%d.\n", read_len); + return read_len; + } + if (access_ok(buf, read_len)) { + PCIE_DEV_DEBUG_VERBOSE("user space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + if (copy_to_user(buf, buf_tmp, read_len)) { + PCIE_DEV_DEBUG_ERROR("copy_to_user failed.\n"); + return -EFAULT; + } + } else { + PCIE_DEV_DEBUG_VERBOSE("kernel space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + memcpy(buf, buf_tmp, read_len); + } + *offset += read_len; + ret = read_len; + return ret; +} + +static ssize_t pci_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) +{ + int ret; + + PCIE_DEV_DEBUG_VERBOSE("pci_dev_read_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, to->count, iocb->ki_pos); + ret = pci_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos); + return ret; +} + +static int pci_dev_write_tmp(wb_pci_dev_t *wb_pci_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int width, i, j; + u32 val; + + if (offset > wb_pci_dev->bar_len) { + PCIE_DEV_DEBUG_VERBOSE("offset:0x%x, bar len:0x%x, EOF.\n", offset, wb_pci_dev->bar_len); + return 0; + } + + width = wb_pci_dev->bus_width; + + if (offset % width) { + PCIE_DEV_DEBUG_ERROR("pci bus width:%d, offset:0x%x, read size %lu invalid.\n", + width, offset, count); + return -EINVAL; + } + + if (count > wb_pci_dev->bar_len - offset) { + PCIE_DEV_DEBUG_VERBOSE("write count out of range. input len:%lu, write len:%u.\n", + count, wb_pci_dev->bar_len - offset); + count = wb_pci_dev->bar_len - offset; + } + + for (i = 0; i < count; i += width) { + val = 0; + for (j = 0; (j < width) && (i + j < count); j++) { + val |= buf[i + j] << (8 * j); + } + pci_dev_setreg(wb_pci_dev, i + offset, val); + } + + return count; +} + +static ssize_t pci_dev_write(struct file *file, const char __user *buf, size_t count, + loff_t *offset) +{ + wb_pci_dev_t *wb_pci_dev; + u8 buf_tmp[PCI_RDWR_MAX_LEN]; + int write_len; + + wb_pci_dev = file->private_data; + if (wb_pci_dev == NULL) { + PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, write failed.\n"); + return -EINVAL; + } + + if (count == 0) { + PCIE_DEV_DEBUG_ERROR("Invalid params, write count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(buf_tmp)) { + PCIE_DEV_DEBUG_VERBOSE("write count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); + count = sizeof(buf_tmp); + } + + mem_clear(buf_tmp, sizeof(buf_tmp)); + if (access_ok(buf, count)) { + PCIE_DEV_DEBUG_VERBOSE("user space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + if (copy_from_user(buf_tmp, buf, count)) { + PCIE_DEV_DEBUG_ERROR("copy_from_user failed.\n"); + return -EFAULT; + } + } else { + PCIE_DEV_DEBUG_VERBOSE("kernel space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + memcpy(buf_tmp, buf, count); + } + + write_len = pci_dev_write_tmp(wb_pci_dev, *offset, buf_tmp, count); + if (write_len < 0) { + PCIE_DEV_DEBUG_ERROR("pci_dev_write_tmp failed, ret:%d.\n", write_len); + return write_len; + } + + *offset += write_len; + return write_len; +} + +static ssize_t pci_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) +{ + int ret; + + PCIE_DEV_DEBUG_VERBOSE("pci_dev_write_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, from->count, iocb->ki_pos); + ret = pci_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos); + return ret; +} + +static loff_t pci_dev_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t ret = 0; + wb_pci_dev_t *wb_pci_dev; + + wb_pci_dev = file->private_data; + if (wb_pci_dev == NULL) { + PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, llseek failed.\n"); + return -EINVAL; + } + + switch (origin) { + case SEEK_SET: + if (offset < 0) { + PCIE_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); + ret = -EINVAL; + break; + } + if (offset > wb_pci_dev->bar_len) { + PCIE_DEV_DEBUG_ERROR("SEEK_SET out of range, offset:%lld, bar len:0x%x.\n", + offset, wb_pci_dev->bar_len); + ret = - EINVAL; + break; + } + file->f_pos = offset; + ret = file->f_pos; + break; + case SEEK_CUR: + if (((file->f_pos + offset) > wb_pci_dev->bar_len) || ((file->f_pos + offset) < 0)) { + PCIE_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld, bar len:0x%x.\n", + file->f_pos, offset, wb_pci_dev->bar_len); + ret = - EINVAL; + break; + } + file->f_pos += offset; + ret = file->f_pos; + break; + default: + PCIE_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); + ret = -EINVAL; + break; + } + return ret; +} + +static long pci_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + wb_pci_dev_t *wb_pci_dev; + void __user *argp; + firmware_upg_t *firmware_upg; + int upg_ctrl_base; + int upg_flash_base; + + PCIE_DEV_DEBUG_VERBOSE("ioctl, cmd=0x%02x, arg=0x%02lx\n",cmd, arg); + + wb_pci_dev = file->private_data; + if (wb_pci_dev == NULL) { + PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, ioctl failed.\n"); + return -EINVAL; + } + + firmware_upg = &wb_pci_dev->firmware_upg; + + argp = (void __user *)arg; + + switch (cmd) { + case GET_FPGA_UPG_CTL_BASE: + if (firmware_upg->upg_ctrl_base < 0) { + PCIE_DEV_DEBUG_ERROR("dts not adaptive upg_ctrl_base\n"); + return -EFAULT; + } else { + upg_ctrl_base = firmware_upg->upg_ctrl_base; + if (copy_to_user(argp, &upg_ctrl_base, sizeof(upg_ctrl_base))) { + PCIE_DEV_DEBUG_ERROR("upg_ctrl_base copy_from_user failed\n"); + return -EFAULT; + } + } + break; + case GET_FPGA_UPG_FLASH_BASE: + if (firmware_upg->upg_flash_base < 0) { + PCIE_DEV_DEBUG_ERROR("dts not adaptive upg_flash_base\n"); + return -EFAULT; + } else { + upg_flash_base = firmware_upg->upg_flash_base; + if (copy_to_user(argp, &upg_flash_base, sizeof(upg_flash_base))) { + PCIE_DEV_DEBUG_ERROR("upg_flash_base copy_from_user failed\n"); + return -EFAULT; + } + } + break; + default: + PCIE_DEV_DEBUG_ERROR("command unsupported \n"); + return -ENOTTY; + } + + return 0; +} + +static const struct file_operations pcie_dev_fops = { + .owner = THIS_MODULE, + .llseek = pci_dev_llseek, + .read_iter = pci_dev_read_iter, + .write_iter = pci_dev_write_iter, + .unlocked_ioctl = pci_dev_ioctl, + .open = pci_dev_open, + .release = pci_dev_release, +}; + +static wb_pci_dev_t *dev_match(const char *path) +{ + wb_pci_dev_t *wb_pci_dev; + char dev_name[MAX_NAME_SIZE]; + int i; + + for (i = 0; i < MAX_PCIE_NUM; i++) { + if (pcie_dev_arry[i] == NULL) { + continue; + } + wb_pci_dev = pcie_dev_arry[i]; + snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", wb_pci_dev->name); + if (!strcmp(path, dev_name)) { + PCIE_DEV_DEBUG_VERBOSE("get dev_name = %s, minor = %d\n", dev_name, i); + return wb_pci_dev; + } + } + + return NULL; +} + +int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + wb_pci_dev_t *wb_pci_dev; + int read_len; + + if (path == NULL) { + PCIE_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if (buf == NULL) { + PCIE_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + wb_pci_dev = dev_match(path); + if (wb_pci_dev == NULL) { + PCIE_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + read_len = pci_dev_read_tmp(wb_pci_dev, offset, buf, count); + if (read_len < 0) { + PCIE_DEV_DEBUG_ERROR("pci_dev_read_tmp failed, ret:%d.\n", read_len); + } + return read_len; +} +EXPORT_SYMBOL(pcie_device_func_read); + +int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + wb_pci_dev_t *wb_pci_dev; + int write_len; + + if (path == NULL) { + PCIE_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if (buf == NULL) { + PCIE_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + wb_pci_dev = dev_match(path); + if (wb_pci_dev == NULL) { + PCIE_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + write_len = pci_dev_write_tmp(wb_pci_dev, offset, buf, count); + if (write_len < 0) { + PCIE_DEV_DEBUG_ERROR("pci_dev_write_tmp failed, ret:%d.\n", write_len); + } + return write_len; +} +EXPORT_SYMBOL(pcie_device_func_write); + +static int pci_setup_bars(wb_pci_dev_t *wb_pci_dev, struct pci_dev *dev) +{ + int ret; + uint32_t addr, len, flags; + + ret = 0; + addr = pci_resource_start(dev, wb_pci_dev->bar); + len = pci_resource_len(dev, wb_pci_dev->bar); + if (addr == 0 || len == 0) { + PCIE_DEV_DEBUG_ERROR("get bar addr failed. bar:%d, addr:0x%x, len:0x%x.\n", + wb_pci_dev->bar, addr, len); + return -EFAULT; + } + wb_pci_dev->bar_len = len; + + flags = pci_resource_flags(dev, wb_pci_dev->bar); + PCIE_DEV_DEBUG_VERBOSE("bar:%d, flag:0x%08x, phys addr:0x%x, len:0x%x\n", + wb_pci_dev->bar, flags, addr, len); + if (flags & IORESOURCE_MEM) { + wb_pci_dev->bar_flag = IORESOURCE_MEM; + wb_pci_dev->pci_mem_base = ioremap(addr, len); + PCIE_DEV_DEBUG_VERBOSE("pci mem base:%p.\n", wb_pci_dev->pci_mem_base); + } else if (flags & IORESOURCE_IO) { + wb_pci_dev->bar_flag = IORESOURCE_IO; + wb_pci_dev->pci_io_base = addr; + PCIE_DEV_DEBUG_VERBOSE("pci io base:0x%x.\n", wb_pci_dev->pci_io_base); + } else { + PCIE_DEV_DEBUG_ERROR("unknow pci bar flag:0x%08x.\n", flags); + ret = -EINVAL; + } + + return ret; +} + +static int pci_dev_probe(struct platform_device *pdev) +{ + int ret, devfn; + wb_pci_dev_t *wb_pci_dev; + struct pci_dev *pci_dev; + struct miscdevice *misc; + firmware_upg_t *firmware_upg; + pci_dev_device_t *pci_dev_device; + + wb_pci_dev = devm_kzalloc(&pdev->dev, sizeof(wb_pci_dev_t), GFP_KERNEL); + if (!wb_pci_dev) { + dev_err(&pdev->dev, "devm_kzalloc failed.\n"); + ret = -ENOMEM; + return ret; + } + + firmware_upg = &wb_pci_dev->firmware_upg; + + if (pdev->dev.of_node) { + ret = 0; + ret += of_property_read_string(pdev->dev.of_node, "pci_dev_name", &wb_pci_dev->name); + ret += of_property_read_u32(pdev->dev.of_node, "pci_domain", &wb_pci_dev->domain); + ret += of_property_read_u32(pdev->dev.of_node, "pci_bus", &wb_pci_dev->bus); + ret += of_property_read_u32(pdev->dev.of_node, "pci_slot", &wb_pci_dev->slot); + ret += of_property_read_u32(pdev->dev.of_node, "pci_fn", &wb_pci_dev->fn); + ret += of_property_read_u32(pdev->dev.of_node, "pci_bar", &wb_pci_dev->bar); + ret += of_property_read_u32(pdev->dev.of_node, "bus_width", &wb_pci_dev->bus_width); + + if (ret != 0) { + dev_err(&pdev->dev, "Failed to get dts config, ret:%d.\n", ret); + return -ENXIO; + } + + ret = 0; + ret += of_property_read_u32(pdev->dev.of_node, "upg_ctrl_base", &firmware_upg->upg_ctrl_base); + ret += of_property_read_u32(pdev->dev.of_node, "upg_flash_base", &firmware_upg->upg_flash_base); + if (ret != 0) { + PCIE_DEV_DEBUG_VERBOSE("dts don't adaptive fpga upg related, ret:%d.\n", ret); + firmware_upg->upg_ctrl_base = -1; + firmware_upg->upg_flash_base = -1; + } else { + PCIE_DEV_DEBUG_VERBOSE("upg_ctrl_base:0x%04x, upg_flash_base:0x%02x.\n", + firmware_upg->upg_ctrl_base, firmware_upg->upg_flash_base); + } + } else { + if (pdev->dev.platform_data == NULL) { + dev_err(&pdev->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + pci_dev_device = pdev->dev.platform_data; + wb_pci_dev->name = pci_dev_device->pci_dev_name; + wb_pci_dev->domain = pci_dev_device->pci_domain; + wb_pci_dev->bus = pci_dev_device->pci_bus; + wb_pci_dev->slot = pci_dev_device->pci_slot; + wb_pci_dev->fn = pci_dev_device->pci_fn; + wb_pci_dev->bar = pci_dev_device->pci_bar; + wb_pci_dev->bus_width = pci_dev_device->bus_width; + firmware_upg->upg_ctrl_base = pci_dev_device->upg_ctrl_base; + firmware_upg->upg_flash_base = pci_dev_device->upg_flash_base; + PCIE_DEV_DEBUG_VERBOSE("upg_ctrl_base:0x%04x, upg_flash_base:0x%02x.\n", + firmware_upg->upg_ctrl_base, firmware_upg->upg_flash_base); + } + + PCIE_DEV_DEBUG_VERBOSE("name:%s, domain:0x%04x, bus:0x%02x, slot:0x%02x, fn:%u, bar:%u, bus_width:%d.\n", + wb_pci_dev->name, wb_pci_dev->domain, wb_pci_dev->bus, wb_pci_dev->slot, wb_pci_dev->fn, + wb_pci_dev->bar, wb_pci_dev->bus_width); + + devfn = PCI_DEVFN(wb_pci_dev->slot, wb_pci_dev->fn); + pci_dev = pci_get_domain_bus_and_slot(wb_pci_dev->domain, wb_pci_dev->bus, devfn); + if (pci_dev == NULL) { + dev_err(&pdev->dev, "Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", + wb_pci_dev->domain, wb_pci_dev->bus, devfn); + return -ENXIO; + } + ret = pci_setup_bars(wb_pci_dev, pci_dev); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to get pci bar address.\n"); + return ret; + } + + if (!wb_pci_dev->setreg || !wb_pci_dev->getreg) { + switch (wb_pci_dev->bus_width) { + case 1: + wb_pci_dev->setreg = pci_dev_setreg_8; + wb_pci_dev->getreg = pci_dev_getreg_8; + break; + + case 2: + wb_pci_dev->setreg = pci_dev_setreg_16; + wb_pci_dev->getreg = pci_dev_getreg_16; + break; + + case 4: + wb_pci_dev->setreg = pci_dev_setreg_32; + wb_pci_dev->getreg = pci_dev_getreg_32; + break; + default: + dev_err(&pdev->dev, "Error: unsupported I/O width (%d).\n", wb_pci_dev->bus_width); + ret = -EINVAL; + goto io_unmap; + } + } + + misc = &wb_pci_dev->misc; + misc->minor = MISC_DYNAMIC_MINOR; + misc->name = wb_pci_dev->name; + misc->fops = &pcie_dev_fops; + misc->mode = 0666; + if (misc_register(misc) != 0) { + dev_err(&pdev->dev, "Failed to register %s device.\n", misc->name); + ret = -ENXIO; + goto io_unmap; + } + if (misc->minor >= MAX_PCIE_NUM) { + dev_err(&pdev->dev, "Error: device minor[%d] more than max pcie num[%d].\n", + misc->minor, MAX_PCIE_NUM); + misc_deregister(misc); + ret = -EINVAL; + goto io_unmap; + } + pcie_dev_arry[misc->minor] = wb_pci_dev; + dev_info(&pdev->dev, "%04x:%02x:%02x.%d[bar%d: %s]: register %s device with minor:%d success.\n", + wb_pci_dev->domain, wb_pci_dev->bus, wb_pci_dev->slot, wb_pci_dev->fn, wb_pci_dev->bar, + wb_pci_dev->bar_flag == IORESOURCE_MEM ? "IORESOURCE_MEM" : "IORESOURCE_IO", + misc->name, misc->minor ); + return 0; + +io_unmap: + if (wb_pci_dev->pci_mem_base) { + iounmap(wb_pci_dev->pci_mem_base); + } + return ret; +} + +static int pci_dev_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < MAX_PCIE_NUM ; i++) { + if (pcie_dev_arry[i] != NULL) { + if (pcie_dev_arry[i]->pci_mem_base) { + iounmap(pcie_dev_arry[i]->pci_mem_base); + } + misc_deregister(&pcie_dev_arry[i]->misc); + pcie_dev_arry[i] = NULL; + } + } + + return 0; +} + +static struct of_device_id pci_dev_match[] = { + { + .compatible = "wb-pci-dev", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, pci_dev_match); + +static struct platform_driver wb_pci_dev_driver = { + .probe = pci_dev_probe, + .remove = pci_dev_remove, + .driver = { + .owner = THIS_MODULE, + .name = PROXY_NAME, + .of_match_table = pci_dev_match, + }, +}; + +static int __init wb_pci_dev_init(void) +{ + return platform_driver_register(&wb_pci_dev_driver); +} + +static void __exit wb_pci_dev_exit(void) +{ + platform_driver_unregister(&wb_pci_dev_driver); +} + +module_init(wb_pci_dev_init); +module_exit(wb_pci_dev_exit); +MODULE_DESCRIPTION("pcie device driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.h new file mode 100644 index 000000000000..9ba0f3b457ea --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.h @@ -0,0 +1,26 @@ +#ifndef __WB_PCIE_DEV_H__ +#define __WB_PCIE_DEV_H__ +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +#define UPG_TYPE 'U' +#define GET_FPGA_UPG_CTL_BASE _IOR(UPG_TYPE, 0, int) +#define GET_FPGA_UPG_FLASH_BASE _IOR(UPG_TYPE, 1, int) + +#define PCI_DEV_NAME_MAX_LEN (64) + +typedef struct pci_dev_device_s { + char pci_dev_name[PCI_DEV_NAME_MAX_LEN]; + int pci_domain; + int pci_bus; + int pci_slot; + int pci_fn; + int pci_bar; + int bus_width; + int upg_ctrl_base; + int upg_flash_base; + int device_flag; +} pci_dev_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.c new file mode 100644 index 000000000000..092c99da2ad8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.c @@ -0,0 +1,749 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_platform_i2c_dev.h" + +#define PROXY_NAME "wb-platform-i2c-dev" +#define MAX_I2C_DEV_NUM (256) +#define FPGA_MAX_LEN (256) +#define MAX_NAME_SIZE (20) +#define MAX_BUS_WIDTH (16) +#define TRANSFER_WRITE_BUFF (FPGA_MAX_LEN + MAX_BUS_WIDTH) + +#define WIDTH_1Byte (1) +#define WIDTH_2Byte (2) +#define WIDTH_4Byte (4) + +int g_i2c_dev_debug = 0; +int g_i2c_dev_error = 0; + +module_param(g_i2c_dev_debug, int, S_IRUGO | S_IWUSR); +module_param(g_i2c_dev_error, int, S_IRUGO | S_IWUSR); + +#define I2C_DEV_DEBUG_DMESG(fmt, args...) do { \ + if (g_i2c_dev_debug) { \ + printk(KERN_ERR "[I2C_DEV][DEBUG][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define I2C_DEV_DEBUG_ERROR(fmt, args...) do { \ + if (g_i2c_dev_error) { \ + printk(KERN_ERR "[I2C_DEV][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static struct platform_i2c_dev_info* i2c_dev_arry[MAX_I2C_DEV_NUM]; + +struct platform_i2c_dev_info { + uint32_t i2c_bus; + uint32_t i2c_addr; + const char *name; + uint32_t data_bus_width; + uint32_t addr_bus_width; + uint32_t per_rd_len; + uint32_t per_wr_len; + struct miscdevice misc; +}; + +static int transfer_read(struct platform_i2c_dev_info *i2c_dev, u8 *buf, loff_t regaddr, size_t count) +{ + int i, j; + struct i2c_adapter *adap; + union i2c_smbus_data data; + u8 offset_buf[MAX_BUS_WIDTH]; + struct i2c_msg msgs[2]; + int msgs_num, ret; + u8 offset; + u8 length; + + if (!i2c_dev) { + I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\r\n"); + return -ENODEV; + } + + i = 0; + + mem_clear(offset_buf, sizeof(offset_buf)); + + switch (i2c_dev->addr_bus_width) { + case WIDTH_4Byte: + offset_buf[i++] = (regaddr >> 24) & 0xFF; + offset_buf[i++] = (regaddr >> 16) & 0xFF; + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_2Byte: + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_1Byte: + offset_buf[i++] = regaddr & 0xFF; + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\r\n", i2c_dev->addr_bus_width); + return -EINVAL; + } + + adap = i2c_get_adapter(i2c_dev->i2c_bus); + if (adap == NULL) { + I2C_DEV_DEBUG_ERROR("get i2c adapter %d faild.\n", i2c_dev->i2c_bus); + return -ENXIO; + } + + if (adap->algo->master_xfer) { + mem_clear(msgs, sizeof(msgs)); + msgs[0].addr = i2c_dev->i2c_addr; + msgs[0].flags = 0; + msgs[0].len = i2c_dev->addr_bus_width; + msgs[0].buf = offset_buf; + + msgs[1].addr = i2c_dev->i2c_addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = count; + msgs[1].buf = buf; + + msgs_num = 2; + ret = i2c_transfer(adap, msgs, msgs_num); + if (ret != msgs_num) { + I2C_DEV_DEBUG_ERROR("i2c_transfer read error\r\n"); + ret = -EFAULT; + goto error_exit; + } + } else { + if (i2c_dev->addr_bus_width == WIDTH_1Byte) { + offset = regaddr & 0xFF; + if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + for (j = 0; j < count; j += I2C_SMBUS_BLOCK_MAX) { + if (count - j > I2C_SMBUS_BLOCK_MAX) { + length = I2C_SMBUS_BLOCK_MAX; + } else { + length = count - j; + } + data.block[0] = length; + ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, + 0, + I2C_SMBUS_READ, + offset, I2C_SMBUS_I2C_BLOCK_DATA, &data); + if (ret) { + I2C_DEV_DEBUG_ERROR("smbus_xfer read block error, ret = %d\n", ret); + ret = -EFAULT; + goto error_exit; + } + memcpy(buf + j, data.block + 1, length); + offset += length; + } + } else { + for (j = 0; j < count; j++) { + ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, + 0, + I2C_SMBUS_READ, + offset, I2C_SMBUS_BYTE_DATA, &data); + + if (!ret) { + buf[j] = data.byte; + } else { + I2C_DEV_DEBUG_ERROR("smbus_xfer read byte error, ret = %d\n", ret); + ret = -EFAULT; + goto error_exit; + } + offset++; + } + } + } else { + I2C_DEV_DEBUG_ERROR("smbus_xfer not support addr_bus_width = %d\n", i2c_dev->addr_bus_width); + ret = -EINVAL; + goto error_exit; + } + } + + i2c_put_adapter(adap); + return 0; +error_exit: + i2c_put_adapter(adap); + return ret; +} + +static int transfer_write(struct platform_i2c_dev_info *i2c_dev, u8 *buf, loff_t regaddr, size_t count) +{ + int i, j; + struct i2c_adapter *adap; + union i2c_smbus_data data; + u8 offset_buf[TRANSFER_WRITE_BUFF]; + struct i2c_msg msgs[1]; + int msgs_num, ret; + u8 offset; + u8 length; + + if (!i2c_dev) { + I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\r\n"); + return -ENODEV; + } + + i = 0; + + mem_clear(offset_buf, sizeof(offset_buf)); + + switch (i2c_dev->addr_bus_width) { + case WIDTH_4Byte: + offset_buf[i++] = (regaddr >> 24) & 0xFF; + offset_buf[i++] = (regaddr >> 16) & 0xFF; + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_2Byte: + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_1Byte: + offset_buf[i++] = regaddr & 0xFF; + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\r\n", i2c_dev->addr_bus_width); + return -EINVAL; + } + + memcpy(offset_buf + i2c_dev->addr_bus_width, buf, count); + + adap = i2c_get_adapter(i2c_dev->i2c_bus); + if (adap == NULL) { + I2C_DEV_DEBUG_ERROR("get i2c adapter %d faild.\n", i2c_dev->i2c_bus); + return -ENXIO; + } + + if (adap->algo->master_xfer) { + mem_clear(msgs, sizeof(msgs)); + + msgs[0].addr = i2c_dev->i2c_addr; + msgs[0].flags = 0; + msgs[0].len = i2c_dev->addr_bus_width + count; + msgs[0].buf = offset_buf; + + msgs_num = 1; + ret = i2c_transfer(adap, msgs, msgs_num); + if (ret != msgs_num) { + I2C_DEV_DEBUG_ERROR("i2c_transfer write error\r\n"); + ret = -EFAULT; + goto error_exit; + } + } else { + if (i2c_dev->addr_bus_width == WIDTH_1Byte) { + offset = regaddr & 0xFF; + if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { + for (j = 0; j < count; j += I2C_SMBUS_BLOCK_MAX) { + if (count - j > I2C_SMBUS_BLOCK_MAX) { + length = I2C_SMBUS_BLOCK_MAX; + } else { + length = count - j; + } + data.block[0] = length; + memcpy(data.block + 1, buf + j, length); + ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, + 0, + I2C_SMBUS_WRITE, + offset, I2C_SMBUS_I2C_BLOCK_DATA, &data); + if (ret) { + I2C_DEV_DEBUG_ERROR("smbus_xfer write block error, ret = %d\r\n", ret); + ret = -EFAULT; + goto error_exit; + } + offset += length; + } + } else { + for (j = 0; j < count; j++) { + data.byte = buf[j]; + ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, + 0, + I2C_SMBUS_WRITE, + offset, I2C_SMBUS_BYTE_DATA, &data); + if (ret) { + I2C_DEV_DEBUG_ERROR("smbus_xfer write byte error, ret = %d\r\n", ret); + ret = -EFAULT; + goto error_exit; + } + offset += 1; + } + } + } else { + I2C_DEV_DEBUG_ERROR("smbus_xfer not support addr_bus_width = %d\r\n", i2c_dev->addr_bus_width); + ret = -EINVAL; + goto error_exit; + } + } + + i2c_put_adapter(adap); + return 0; +error_exit: + i2c_put_adapter(adap); + return ret; +} + +static long i2c_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static int i2c_dev_open(struct inode *inode, struct file *file) +{ + unsigned int minor = iminor(inode); + struct platform_i2c_dev_info *i2c_dev; + + i2c_dev = i2c_dev_arry[minor]; + if (i2c_dev == NULL) { + return -ENODEV; + } + + file->private_data = i2c_dev; + + return 0; +} + +static int i2c_dev_release(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + + return 0; +} + +static int device_read(struct platform_i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, int count) +{ + int i, j, ret; + u8 tmp_offset; + u8 val[FPGA_MAX_LEN]; + u32 width, rd_len, per_len, tmp; + u32 max_per_len; + + width = i2c_dev->data_bus_width; + switch (width) { + case WIDTH_4Byte: + tmp_offset = offset & 0x3; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %d invalid.\r\n", width, offset, count); + return -EINVAL; + } + break; + case WIDTH_2Byte: + tmp_offset = offset & 0x1; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %d invalid.\r\n", width, offset, count); + return -EINVAL; + } + break; + case WIDTH_1Byte: + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\r\n", width); + return -EINVAL; + } + + max_per_len = i2c_dev->per_rd_len; + tmp = (width - 1) & count; + rd_len = (tmp == 0) ? count : count + width - tmp; + per_len = (rd_len > max_per_len) ? (max_per_len) : (rd_len); + + mem_clear(val, sizeof(val)); + for (i = 0; i < rd_len; i += per_len) { + ret = transfer_read(i2c_dev, val + i, offset + i, per_len); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("read error.read offset = %u\r\n", (offset + i)); + return -EFAULT; + } + } + + if (width == WIDTH_1Byte) { + memcpy(buf, val, count); + } else { + for (i = 0; i < count; i += width) { + for (j = 0; (j < width) && (i + j < count); j++) { + buf[i + j] = val[i + width - j - 1]; + } + } + } + + return 0; +} + +static int device_write(struct platform_i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int i, j, ret; + u8 tmp_offset; + u32 width; + u8 val[FPGA_MAX_LEN]; + u32 wr_len, per_len, tmp; + u32 max_per_len; + + width = i2c_dev->data_bus_width; + switch (width) { + case WIDTH_4Byte: + tmp_offset = offset & 0x3; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\r\n", width, offset, count); + return -EINVAL; + } + break; + case WIDTH_2Byte: + tmp_offset = offset & 0x1; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\r\n", width, offset, count); + return -EINVAL; + } + break; + case WIDTH_1Byte: + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\r\n", width); + return -EINVAL; + } + + mem_clear(val, sizeof(val)); + + if (width == WIDTH_1Byte) { + memcpy(val, buf, count); + } else { + for (i = 0; i < count; i += width) { + for (j = 0; (j < width) && (i + j < count); j++) { + val[i + width - j - 1] = buf[i + j]; + } + } + } + + max_per_len = i2c_dev->per_wr_len; + tmp = (width - 1) & count; + wr_len = (tmp == 0) ? count : count + width - tmp; + per_len = (wr_len > max_per_len) ? (max_per_len) : (wr_len); + + for (i = 0; i < wr_len; i += per_len) { + ret = transfer_write(i2c_dev, val + i, offset + i, per_len); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("write error.offset = %u\r\n", (offset + i)); + return -EFAULT; + } + } + return 0; +} + +static ssize_t i2c_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) +{ + u8 val[FPGA_MAX_LEN]; + int ret; + struct platform_i2c_dev_info *i2c_dev; + + if (count <= 0 || count > sizeof(val)) { + I2C_DEV_DEBUG_ERROR("read conut %lu , beyond max:%lu.\n", count, sizeof(val)); + return -EINVAL; + } + + i2c_dev = file->private_data; + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("can't get read private_data .\r\n"); + return -EINVAL; + } + + ret = device_read(i2c_dev, (uint32_t)*offset, val, count); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", + i2c_dev->name, (uint32_t)*offset, count); + return -EINVAL; + } + + if (copy_to_user(buf, val, count)) { + I2C_DEV_DEBUG_ERROR("copy_to_user error \r\n"); + return -EFAULT; + } else{ + *offset += count; + } + + return count; +} + +static ssize_t i2c_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) +{ + u8 val[FPGA_MAX_LEN]; + int ret; + struct platform_i2c_dev_info *i2c_dev; + + if (count <= 0 || count > sizeof(val)) { + I2C_DEV_DEBUG_ERROR("write conut %lu, beyond max val:%lu.\n", count, sizeof(val)); + return -EINVAL; + } + + i2c_dev = file->private_data; + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("get write private_data error.\r\n"); + return -EINVAL; + } + + mem_clear(val, sizeof(val)); + if (copy_from_user(val, buf, count)) { + I2C_DEV_DEBUG_ERROR("copy_from_user error.\r\n"); + return -EFAULT; + } + + ret = device_write (i2c_dev, (uint32_t)*offset, val, count); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%llx, len:%lu.\n", + i2c_dev->name, *offset, count); + return -EINVAL; + } + + *offset += count; + return count; +} + +static loff_t i2c_dev_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t ret = 0; + + switch (origin) { + case SEEK_SET: + if (offset < 0) { + I2C_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\r\n", offset); + ret = -EINVAL; + break; + } + file->f_pos = offset; + ret = file->f_pos; + break; + case SEEK_CUR: + if (file->f_pos + offset < 0) { + I2C_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld.\n", + file->f_pos, offset); + } + file->f_pos += offset; + ret = file->f_pos; + break; + default: + I2C_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); + ret = -EINVAL; + break; + } + return ret; +} + +static const struct file_operations i2c_dev_fops = { + .owner = THIS_MODULE, + .llseek = i2c_dev_llseek, + .read = i2c_dev_read, + .write = i2c_dev_write, + .unlocked_ioctl = i2c_dev_ioctl, + .open = i2c_dev_open, + .release = i2c_dev_release, +}; + +static struct platform_i2c_dev_info * dev_match(const char *path) +{ + struct platform_i2c_dev_info *i2c_dev; + char dev_name[MAX_NAME_SIZE]; + int i; + for (i = 0; i < MAX_I2C_DEV_NUM; i++) { + if (i2c_dev_arry[ i ] == NULL) { + continue; + } + i2c_dev = i2c_dev_arry[ i ]; + snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", i2c_dev->name); + if (!strcmp(path, dev_name)) { + I2C_DEV_DEBUG_DMESG("get dev_name = %s, minor = %d\n", dev_name, i); + return i2c_dev; + } + } + + return NULL; +} + +int platform_i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + struct platform_i2c_dev_info *i2c_dev = NULL; + int ret; + + if(path == NULL){ + I2C_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if(buf == NULL){ + I2C_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + if (count > FPGA_MAX_LEN) { + I2C_DEV_DEBUG_ERROR("read conut %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); + return -EINVAL; + } + + i2c_dev = dev_match(path); + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + ret = device_read(i2c_dev, offset, buf, count); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("fpga i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", + i2c_dev->name, offset, count); + return -EINVAL; + } + + return count; +} +EXPORT_SYMBOL(platform_i2c_device_func_read); + +int platform_i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + struct platform_i2c_dev_info *i2c_dev = NULL; + int ret; + + if(path == NULL){ + I2C_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if(buf == NULL){ + I2C_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + if (count > FPGA_MAX_LEN) { + I2C_DEV_DEBUG_ERROR("write conut %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); + return -EINVAL; + } + + i2c_dev = dev_match(path); + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + ret = device_write (i2c_dev, offset, buf, count); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%x, len:%lu.\n", + i2c_dev->name, offset, count); + return -EINVAL; + } + + return count; +} +EXPORT_SYMBOL(platform_i2c_device_func_write); + +static int platform_i2c_dev_probe(struct platform_device *pdev) +{ + int ret = 0; + struct platform_i2c_dev_info *i2c_dev; + struct miscdevice *misc; + platform_i2c_dev_device_t *platform_i2c_dev_device; + + i2c_dev = devm_kzalloc(&pdev->dev, sizeof(struct platform_i2c_dev_info), GFP_KERNEL); + if (!i2c_dev) { + dev_err(&pdev->dev, "devm_kzalloc error. \r\n"); + return -ENOMEM; + } + + if (pdev->dev.of_node) { + + ret += of_property_read_u32(pdev->dev.of_node, "i2c_bus", &i2c_dev->i2c_bus); + ret += of_property_read_u32(pdev->dev.of_node, "i2c_addr", &i2c_dev->i2c_addr); + ret += of_property_read_string(pdev->dev.of_node, "i2c_name", &i2c_dev->name); + ret += of_property_read_u32(pdev->dev.of_node, "data_bus_width", &i2c_dev->data_bus_width); + ret += of_property_read_u32(pdev->dev.of_node, "addr_bus_width", &i2c_dev->addr_bus_width); + ret += of_property_read_u32(pdev->dev.of_node, "per_rd_len", &i2c_dev->per_rd_len); + ret += of_property_read_u32(pdev->dev.of_node, "per_wr_len", &i2c_dev->per_wr_len); + if (ret != 0) { + dev_err(&pdev->dev, "dts config error.ret:%d.\r\n", ret); + return -ENXIO; + } + } else { + if (pdev->dev.platform_data == NULL) { + dev_err(&pdev->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + platform_i2c_dev_device = pdev->dev.platform_data; + i2c_dev->i2c_bus = platform_i2c_dev_device->i2c_bus; + i2c_dev->i2c_addr = platform_i2c_dev_device->i2c_addr; + i2c_dev->name = platform_i2c_dev_device->i2c_name; + i2c_dev->data_bus_width = platform_i2c_dev_device->data_bus_width; + i2c_dev->addr_bus_width = platform_i2c_dev_device->addr_bus_width; + i2c_dev->per_rd_len = platform_i2c_dev_device->per_rd_len; + i2c_dev->per_wr_len = platform_i2c_dev_device->per_wr_len; + } + + if ((i2c_dev->per_rd_len & (i2c_dev->data_bus_width - 1)) || (i2c_dev->per_wr_len & (i2c_dev->data_bus_width - 1))) { + dev_err(&pdev->dev, "Invalid config per_rd_len %d per_wr_len %d data bus_width %d.\r\n", i2c_dev->per_rd_len, + i2c_dev->per_wr_len, i2c_dev->data_bus_width); + return -ENXIO; + } + + misc = &i2c_dev->misc; + misc->minor = MISC_DYNAMIC_MINOR; + misc->name = i2c_dev->name; + misc->fops = &i2c_dev_fops; + if (misc_register(misc) != 0) { + dev_err(&pdev->dev, "register %s faild.\r\n", misc->name); + return -ENXIO; + } + + if (misc->minor >= MAX_I2C_DEV_NUM) { + dev_err(&pdev->dev, "minor number beyond the limit! is %d.\r\n", misc->minor); + misc_deregister(misc); + return -ENXIO; + } + i2c_dev_arry[misc->minor] = i2c_dev; + + dev_info(&pdev->dev, "register %u addr_bus_width %u data_bus_width device %s with %u per_rd_len %u per_wr_len success.\r\n", + i2c_dev->addr_bus_width, i2c_dev->data_bus_width, i2c_dev->name, i2c_dev->per_rd_len, i2c_dev->per_wr_len); + + return 0; +} + +static int platform_i2c_dev_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < MAX_I2C_DEV_NUM ; i++) { + if (i2c_dev_arry[i] != NULL) { + misc_deregister(&i2c_dev_arry[i]->misc); + i2c_dev_arry[i] = NULL; + } + } + + return 0; +} + +static const struct of_device_id platform_i2c_dev_of_match[] = { + { .compatible = "wb-platform-i2c-dev" }, + { }, +}; +MODULE_DEVICE_TABLE(of, platform_i2c_dev_of_match); + +static struct platform_driver wb_platform_i2c_dev_driver = { + .probe = platform_i2c_dev_probe, + .remove = platform_i2c_dev_remove, + .driver = { + .owner = THIS_MODULE, + .name = PROXY_NAME, + .of_match_table = platform_i2c_dev_of_match, + }, +}; + +static int __init wb_platform_i2c_dev_init(void) +{ + return platform_driver_register(&wb_platform_i2c_dev_driver); +} + +static void __exit wb_platform_i2c_dev_exit(void) +{ + platform_driver_unregister(&wb_platform_i2c_dev_driver); +} + +module_init(wb_platform_i2c_dev_init); +module_exit(wb_platform_i2c_dev_exit); + +MODULE_DESCRIPTION("platform i2c dev driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.h new file mode 100644 index 000000000000..b5158c9fec57 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.h @@ -0,0 +1,19 @@ +#ifndef __WB_PLATFORM_I2C_DEV_H__ +#define __WB_PLATFORM_I2C_DEV_H__ +#include + +#define mem_clear(data, size) memset((data), 0, (size)) +#define I2C_DEV_NAME_MAX_LEN (64) + +typedef struct platform_i2c_dev_device_s { + uint32_t i2c_bus; + uint32_t i2c_addr; + char i2c_name[I2C_DEV_NAME_MAX_LEN]; + uint32_t data_bus_width; + uint32_t addr_bus_width; + uint32_t per_rd_len; + uint32_t per_wr_len; + int device_flag; +} platform_i2c_dev_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_93xx46.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_93xx46.c new file mode 100644 index 000000000000..abc4f1567aec --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_93xx46.c @@ -0,0 +1,111 @@ +/* + * EEPROMs access control driver for display configuration EEPROMs + * on DigsyMTC board. + * + * (C) 2011 DENX Software Engineering, Anatolij Gustschin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_SPI_BUS_NUM (0) +#define DEFAULT_SPI_CS_NUM (0) +#define DEFAULT_SPI_HZ (100000) + +#define GPIO_EEPROM_CS (-1) + +int g_wb_spi_93xx46_debug = 0; +int g_wb_spi_93xx46_error = 0; +int spi_bus_num = DEFAULT_SPI_BUS_NUM; +int spi_cs_gpio = GPIO_EEPROM_CS; + +module_param(g_wb_spi_93xx46_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_spi_93xx46_error, int, S_IRUGO | S_IWUSR); +module_param(spi_bus_num, int, S_IRUGO | S_IWUSR); +module_param(spi_cs_gpio, int, S_IRUGO | S_IWUSR); + +#define SPI_93xx46_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_spi_93xx46_debug) { \ + printk(KERN_INFO "[SPI-93xx46][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define SPI_93xx46_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_spi_93xx46_error) { \ + printk(KERN_ERR "[SPI-93xx46][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +struct eeprom_93xx46_platform_data eeprom_data = { + .flags = EE_ADDR16, + .quirks = EEPROM_93XX46_QUIRK_SINGLE_WORD_READ, +}; + +struct spi_board_info eeprom_93xx46_info __initdata = { + .modalias = "wb_93xx46", + .max_speed_hz = DEFAULT_SPI_HZ, + .bus_num = DEFAULT_SPI_BUS_NUM, + .chip_select = DEFAULT_SPI_CS_NUM, + .mode = SPI_MODE_0 | SPI_CS_HIGH, + .controller_data = (void *)GPIO_EEPROM_CS, + .platform_data = &eeprom_data, +}; + +static struct spi_device *g_spi_device; + +static int __init wb_spi_93xx46_init(void) +{ + struct spi_master *master; + + SPI_93xx46_DEBUG_VERBOSE("Enter.\n"); + + eeprom_93xx46_info.bus_num = spi_bus_num; + eeprom_93xx46_info.controller_data = (void *)(long)spi_cs_gpio; + master = spi_busnum_to_master(eeprom_93xx46_info.bus_num); + if (!master) { + SPI_93xx46_DEBUG_ERROR("get bus_num %u spi master failed.\n", + eeprom_93xx46_info.bus_num); + return -EINVAL; + } + + g_spi_device = spi_new_device(master, &eeprom_93xx46_info); + put_device(&master->dev); + if (!g_spi_device) { + SPI_93xx46_DEBUG_ERROR("register spi new device failed.\n"); + return -EPERM; + } + + if (g_wb_spi_93xx46_debug) { + dev_info(&g_spi_device->dev, "register %u bus_num spi 93xx46 eeprom success\n", + eeprom_93xx46_info.bus_num); + } + + return 0; +} + +static void __exit wb_spi_93xx46_exit(void) +{ + spi_unregister_device(g_spi_device); + + if (g_wb_spi_93xx46_debug) { + dev_info(&g_spi_device->dev, "unregister spi 93xx46 eeprom success\n"); + } + + return; +} + +module_init(wb_spi_93xx46_init); +module_exit(wb_spi_93xx46_exit); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("create 93xx46 eeprom device"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.c new file mode 100644 index 000000000000..b569ace32526 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.c @@ -0,0 +1,684 @@ +/* + * wb_spi_dev.c + * ko to read/write spi device through /dev/XXX device + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_spi_dev.h" + +#define MAX_SPI_DEV_NUM (256) +#define MAX_RW_LEN (256) +#define MAX_NAME_SIZE (20) +#define MAX_ADDR_BUS_WIDTH (4) + +#define TRANSFER_WRITE_BUFF (1 + MAX_ADDR_BUS_WIDTH + MAX_RW_LEN) + +#define WIDTH_1Byte (1) +#define WIDTH_2Byte (2) +#define WIDTH_4Byte (4) + +#define OP_READ (0x3) +#define OP_WRITE (0x2) + +static int g_spi_dev_debug = 0; +static int g_spi_dev_error = 0; + +module_param(g_spi_dev_debug, int, S_IRUGO | S_IWUSR); +module_param(g_spi_dev_error, int, S_IRUGO | S_IWUSR); + +#define SPI_DEV_DEBUG(fmt, args...) do { \ + if (g_spi_dev_debug) { \ + printk(KERN_ERR "[SPI_DEV][DEBUG][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define SPI_DEV_ERROR(fmt, args...) do { \ + if (g_spi_dev_error) { \ + printk(KERN_ERR "[SPI_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static struct spi_dev_info* spi_dev_arry[MAX_SPI_DEV_NUM]; + +struct spi_dev_info { + const char *name; + uint32_t data_bus_width; + uint32_t addr_bus_width; + uint32_t per_rd_len; + uint32_t per_wr_len; + uint32_t spi_len; + struct miscdevice misc; + struct spi_device *spi_device; +}; + +static int transfer_read(struct spi_dev_info *spi_dev, u8 *buf, uint32_t regaddr, size_t count) +{ + int i, ret; + u8 tx_buf[MAX_ADDR_BUS_WIDTH + 1]; + struct spi_message m; + struct spi_transfer xfer[2]; + + i = 0; + mem_clear(tx_buf, sizeof(tx_buf)); + tx_buf[i++] = OP_READ; + + switch (spi_dev->addr_bus_width) { + case WIDTH_4Byte: + tx_buf[i++] = (regaddr >> 24) & 0xFF; + tx_buf[i++] = (regaddr >> 16) & 0xFF; + tx_buf[i++] = (regaddr >> 8) & 0xFF; + tx_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_2Byte: + tx_buf[i++] = (regaddr >> 8) & 0xFF; + tx_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_1Byte: + tx_buf[i++] = regaddr & 0xFF; + break; + default: + SPI_DEV_ERROR("Only support 1,2,4 Byte Width,but set width = %u\n", + spi_dev->addr_bus_width); + return -EINVAL; + } + + mem_clear(xfer, sizeof(xfer)); + spi_message_init(&m); + xfer[0].tx_buf = tx_buf; + xfer[0].len = spi_dev->addr_bus_width + 1; + spi_message_add_tail(&xfer[0], &m); + + xfer[1].rx_buf = buf; + xfer[1].len = count; + spi_message_add_tail(&xfer[1], &m); + + ret = spi_sync(spi_dev->spi_device, &m); + if (ret) { + SPI_DEV_ERROR("transfer_read failed, reg addr:0x%x, len:%lu, ret:%d.\n", + regaddr, count, ret); + return -EIO; + } + return 0; +} + +static int transfer_write(struct spi_dev_info *spi_dev, u8 *buf, uint32_t regaddr, size_t count) +{ + int i, ret; + u8 tx_buf[TRANSFER_WRITE_BUFF]; + struct spi_message m; + struct spi_transfer xfer ; + + i = 0; + mem_clear(tx_buf, sizeof(tx_buf)); + tx_buf[i++] = OP_WRITE; + switch (spi_dev->addr_bus_width) { + case WIDTH_4Byte: + tx_buf[i++] = (regaddr >> 24) & 0xFF; + tx_buf[i++] = (regaddr >> 16) & 0xFF; + tx_buf[i++] = (regaddr >> 8) & 0xFF; + tx_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_2Byte: + tx_buf[i++] = (regaddr >> 8) & 0xFF; + tx_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_1Byte: + tx_buf[i++] = regaddr & 0xFF; + break; + default: + SPI_DEV_ERROR("Only support 1,2,4 Byte Width, but set width = %u\n", + spi_dev->addr_bus_width); + return -EINVAL; + } + + memcpy(tx_buf + i, buf, count); + + mem_clear(&xfer, sizeof(xfer)); + spi_message_init(&m); + xfer.tx_buf = tx_buf; + xfer.len = count + i; + spi_message_add_tail(&xfer, &m); + + ret = spi_sync(spi_dev->spi_device, &m); + if (ret) { + SPI_DEV_ERROR("transfer_write failed, reg addr:0x%x, len:%lu, ret:%d.\n", + regaddr, count, ret); + return -EIO; + } + return 0; +} + +static long spi_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static int spi_dev_open(struct inode *inode, struct file *file) +{ + unsigned int minor = iminor(inode); + struct spi_dev_info *spi_dev; + + if (minor >= MAX_SPI_DEV_NUM) { + SPI_DEV_ERROR("minor out of range, minor = %d.\n", minor); + return -ENODEV; + } + + spi_dev = spi_dev_arry[minor]; + if (spi_dev == NULL) { + SPI_DEV_ERROR("spi_dev is NULL, open failed, minor = %d\n", minor); + return -ENODEV; + } + + file->private_data = spi_dev; + + return 0; +} + +static int spi_dev_release(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + + return 0; +} + +static int device_read(struct spi_dev_info *spi_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int i, j, ret; + u8 val[MAX_RW_LEN]; + u32 data_width, rd_len, per_len, tmp; + u32 max_per_len; + + if (offset > spi_dev->spi_len) { + SPI_DEV_DEBUG("offset: 0x%x, spi len: 0x%x, count: %lu, EOF.\n", + offset, spi_dev->spi_len, count); + return 0; + } + + data_width = spi_dev->data_bus_width; + if (offset % data_width) { + SPI_DEV_ERROR("data bus width:%d, offset:0x%x, read size %lu invalid.\n", + data_width, offset, count); + return -EINVAL; + } + + if (count > (spi_dev->spi_len - offset)) { + SPI_DEV_DEBUG("read count out of range. input len:%lu, read len:%u.\n", + count, spi_dev->spi_len - offset); + count = spi_dev->spi_len - offset; + } + + if (count == 0) { + SPI_DEV_DEBUG("offset: 0x%x, spi len: 0x%x, read len: %lu, EOF.\n", + offset, spi_dev->spi_len, count); + return 0; + } + + max_per_len = spi_dev->per_rd_len; + tmp = (data_width - 1) & count; + rd_len = (tmp == 0) ? count : count + data_width - tmp; + per_len = (rd_len > max_per_len) ? (max_per_len) : (rd_len); + + mem_clear(val, sizeof(val)); + for (i = 0; i < rd_len; i += per_len) { + ret = transfer_read(spi_dev, val + i, offset + i, per_len); + if (ret < 0) { + SPI_DEV_ERROR("read error.read offset = %u\n", (offset + i)); + return -EFAULT; + } + } + + if (data_width == WIDTH_1Byte) { + memcpy(buf, val, count); + } else { + for (i = 0; i < count; i += data_width) { + for (j = 0; (j < data_width) && (i + j < count); j++) { + buf[i + j] = val[i + data_width - j - 1]; + } + } + } + + return count; +} + +static int device_write(struct spi_dev_info *spi_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int i, j, ret; + u32 data_width; + u8 val[MAX_RW_LEN]; + u32 wr_len, per_len, tmp; + u32 max_per_len; + + if (offset > spi_dev->spi_len) { + SPI_DEV_DEBUG("offset: 0x%x, spi len: 0x%x, count: %lu, EOF.\n", + offset, spi_dev->spi_len, count); + return 0; + } + + data_width = spi_dev->data_bus_width; + if (offset % data_width) { + SPI_DEV_ERROR("data bus width:%d, offset:0x%x, read size %lu invalid.\n", + data_width, offset, count); + return -EINVAL; + } + + if (count > (spi_dev->spi_len - offset)) { + SPI_DEV_DEBUG("read count out of range. input len:%lu, read len:%u.\n", + count, spi_dev->spi_len - offset); + count = spi_dev->spi_len - offset; + } + + if (count == 0) { + SPI_DEV_DEBUG("offset: 0x%x, i2c len: 0x%x, read len: %lu, EOF.\n", + offset, spi_dev->spi_len, count); + return 0; + } + + mem_clear(val, sizeof(val)); + + if (data_width == WIDTH_1Byte) { + memcpy(val, buf, count); + } else { + for (i = 0; i < count; i += data_width) { + for (j = 0; (j < data_width) && (i + j < count); j++) { + val[i + data_width - j - 1] = buf[i + j]; + } + } + } + + max_per_len = spi_dev->per_wr_len; + tmp = (data_width - 1) & count; + wr_len = (tmp == 0) ? count : count + data_width - tmp; + per_len = (wr_len > max_per_len) ? (max_per_len) : (wr_len); + + for (i = 0; i < wr_len; i += per_len) { + ret = transfer_write(spi_dev, val + i, offset + i, per_len); + if (ret < 0) { + SPI_DEV_ERROR("write error.offset = %u\n", (offset + i)); + return -EFAULT; + } + } + return count; +} + +static ssize_t spi_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) +{ + u8 val[MAX_RW_LEN]; + int ret, read_len; + struct spi_dev_info *spi_dev; + + spi_dev = file->private_data; + if (spi_dev == NULL) { + SPI_DEV_ERROR("can't get read private_data.\n"); + return -EINVAL; + } + + if (count == 0) { + SPI_DEV_ERROR("Invalid params, read count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(val)) { + SPI_DEV_DEBUG("read count %lu exceed max %lu.\n", count, sizeof(val)); + count = sizeof(val); + } + + mem_clear(val, sizeof(val)); + read_len = device_read(spi_dev, (uint32_t)*offset, val, count); + if (read_len < 0) { + SPI_DEV_ERROR("spi dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", + spi_dev->name, (uint32_t)*offset, count); + return read_len; + } + + if (access_ok(buf, read_len)) { + SPI_DEV_DEBUG("user space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + if (copy_to_user(buf, val, read_len)) { + SPI_DEV_ERROR("copy_to_user failed.\n"); + return -EFAULT; + } + } else { + SPI_DEV_DEBUG("kernel space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + memcpy(buf, val, read_len); + } + + *offset += read_len; + ret = read_len; + return ret; +} + +static ssize_t spi_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) +{ + int ret; + + SPI_DEV_DEBUG("spi_dev_read_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, to->count, iocb->ki_pos); + ret = spi_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos); + return ret; +} + +static ssize_t spi_dev_write(struct file *file, const char __user *buf, + size_t count, loff_t *offset) +{ + u8 val[MAX_RW_LEN]; + int write_len; + struct spi_dev_info *spi_dev; + + spi_dev = file->private_data; + if (spi_dev == NULL) { + SPI_DEV_ERROR("get write private_data error.\n"); + return -EINVAL; + } + + if (count == 0) { + SPI_DEV_ERROR("Invalid params, write count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(val)) { + SPI_DEV_DEBUG("write count %lu exceed max %lu.\n", count, sizeof(val)); + count = sizeof(val); + } + + mem_clear(val, sizeof(val)); + if (access_ok(buf, count)) { + SPI_DEV_DEBUG("user space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + if (copy_from_user(val, buf, count)) { + SPI_DEV_ERROR("copy_from_user failed.\n"); + return -EFAULT; + } + } else { + SPI_DEV_DEBUG("kernel space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + memcpy(val, buf, count); + } + + write_len = device_write(spi_dev, (uint32_t)*offset, val, count); + if (write_len < 0) { + SPI_DEV_ERROR("spi dev write failed, dev name:%s, offset:0x%llx, len:%lu.\n", + spi_dev->name, *offset, count); + return write_len; + } + + *offset += write_len; + return write_len; +} + +static ssize_t spi_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) +{ + int ret; + + SPI_DEV_DEBUG("spi_dev_write_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, from->count, iocb->ki_pos); + ret = spi_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos); + return ret; +} + +static loff_t spi_dev_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t ret = 0; + struct spi_dev_info *spi_dev; + + spi_dev = file->private_data; + if (spi_dev == NULL) { + SPI_DEV_ERROR("spi_dev is NULL, llseek failed.\n"); + return -EINVAL; + } + + switch (origin) { + case SEEK_SET: + if (offset < 0) { + SPI_DEV_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); + ret = -EINVAL; + break; + } + if (offset > spi_dev->spi_len) { + SPI_DEV_ERROR("SEEK_SET out of range, offset:%lld, i2c_len:0x%x.\n", + offset, spi_dev->spi_len); + ret = - EINVAL; + break; + } + file->f_pos = offset; + ret = file->f_pos; + break; + case SEEK_CUR: + if (((file->f_pos + offset) > spi_dev->spi_len) || ((file->f_pos + offset) < 0)) { + SPI_DEV_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld.\n", + file->f_pos, offset); + } + file->f_pos += offset; + ret = file->f_pos; + break; + default: + SPI_DEV_ERROR("unsupport llseek type:%d.\n", origin); + ret = -EINVAL; + break; + } + return ret; +} + +static const struct file_operations spi_dev_fops = { + .owner = THIS_MODULE, + .llseek = spi_dev_llseek, + .read_iter = spi_dev_read_iter, + .write_iter = spi_dev_write_iter, + .unlocked_ioctl = spi_dev_ioctl, + .open = spi_dev_open, + .release = spi_dev_release, +}; + +static struct spi_dev_info * dev_match(const char *path) +{ + struct spi_dev_info * spi_dev; + char dev_name[MAX_NAME_SIZE]; + int i; + for (i = 0; i < MAX_SPI_DEV_NUM; i++) { + if (spi_dev_arry[ i ] == NULL) { + continue; + } + spi_dev = spi_dev_arry[ i ]; + snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", spi_dev->name); + if (!strcmp(path, dev_name)) { + SPI_DEV_DEBUG("get dev_name = %s, minor = %d\n", dev_name, i); + return spi_dev; + } + } + + return NULL; +} + +int spi_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + struct spi_dev_info *spi_dev = NULL; + int ret; + + if(path == NULL){ + SPI_DEV_ERROR("path NULL"); + return -EINVAL; + } + + if(buf == NULL){ + SPI_DEV_ERROR("buf NULL"); + return -EINVAL; + } + + if (count > MAX_RW_LEN) { + SPI_DEV_ERROR("read count %lu, beyond max:%d.\n", count, MAX_RW_LEN); + return -EINVAL; + } + + spi_dev = dev_match(path); + if (spi_dev == NULL) { + SPI_DEV_ERROR("spi_dev match failed. dev path = %s", path); + return -EINVAL; + } + + ret = device_read(spi_dev, offset, buf, count); + if (ret < 0) { + SPI_DEV_ERROR("spi dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", + spi_dev->name, offset, count); + return -EINVAL; + } + + return count; +} +EXPORT_SYMBOL(spi_device_func_read); + +int spi_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + struct spi_dev_info *spi_dev = NULL; + int ret; + + if(path == NULL){ + SPI_DEV_ERROR("path NULL"); + return -EINVAL; + } + + if(buf == NULL){ + SPI_DEV_ERROR("buf NULL"); + return -EINVAL; + } + + if (count > MAX_RW_LEN) { + SPI_DEV_ERROR("write count %lu, beyond max:%d.\n", count, MAX_RW_LEN); + return -EINVAL; + } + + spi_dev = dev_match(path); + if (spi_dev == NULL) { + SPI_DEV_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + ret = device_write (spi_dev, offset, buf, count); + if (ret < 0) { + SPI_DEV_ERROR("i2c dev write failed, dev name:%s, offset:0x%x, len:%lu.\n", + spi_dev->name, offset, count); + return -EINVAL; + } + + return count; +} +EXPORT_SYMBOL(spi_device_func_write); + +static int spi_dev_probe(struct spi_device *spi) +{ + int ret; + struct spi_dev_info *spi_dev; + struct miscdevice *misc; + spi_dev_device_t *spi_dev_device; + + spi_dev = devm_kzalloc(&spi->dev, sizeof(struct spi_dev_info), GFP_KERNEL); + if (!spi_dev) { + dev_err(&spi->dev, "devm_kzalloc error. \n"); + return -ENOMEM; + } + + spi_set_drvdata(spi, spi_dev); + spi_dev->spi_device = spi; + + if (spi->dev.of_node) { + + ret = 0; + ret += of_property_read_string(spi->dev.of_node, "spi_dev_name", &spi_dev->name); + ret += of_property_read_u32(spi->dev.of_node, "data_bus_width", &spi_dev->data_bus_width); + ret += of_property_read_u32(spi->dev.of_node, "addr_bus_width", &spi_dev->addr_bus_width); + ret += of_property_read_u32(spi->dev.of_node, "per_rd_len", &spi_dev->per_rd_len); + ret += of_property_read_u32(spi->dev.of_node, "per_wr_len", &spi_dev->per_wr_len); + ret += of_property_read_u32(spi->dev.of_node, "spi_len", &spi_dev->spi_len); + if (ret != 0) { + dev_err(&spi->dev, "dts config error.ret:%d.\n", ret); + return -ENXIO; + } + } else { + if (spi->dev.platform_data == NULL) { + dev_err(&spi->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + spi_dev_device = spi->dev.platform_data; + spi_dev->name = spi_dev_device->spi_dev_name; + spi_dev->data_bus_width = spi_dev_device->data_bus_width; + spi_dev->addr_bus_width = spi_dev_device->addr_bus_width; + spi_dev->per_rd_len = spi_dev_device->per_rd_len; + spi_dev->per_wr_len = spi_dev_device->per_wr_len; + spi_dev->spi_len = spi_dev_device->spi_len; + } + + if ((spi_dev->per_rd_len & (spi_dev->data_bus_width - 1)) + || (spi_dev->per_wr_len & (spi_dev->data_bus_width - 1))) { + dev_err(&spi->dev, "Invalid config per_rd_len [%u] per_wr_len [%u] data bus_width [%u], addr bus width [%u].\n", + spi_dev->per_rd_len, spi_dev->per_wr_len, spi_dev->data_bus_width, spi_dev->addr_bus_width); + return -ENXIO; + } + + misc = &spi_dev->misc; + misc->minor = MISC_DYNAMIC_MINOR; + misc->name = spi_dev->name; + misc->fops = &spi_dev_fops; + misc->mode = 0666; + if (misc_register(misc) != 0) { + dev_err(&spi->dev, "register %s faild.\n", misc->name); + return -ENXIO; + } + + if (misc->minor >= MAX_SPI_DEV_NUM) { + dev_err(&spi->dev, "minor number beyond the limit! is %d.\n", misc->minor); + misc_deregister(misc); + return -ENXIO; + } + spi_dev_arry[misc->minor] = spi_dev; + + dev_info(&spi->dev, "register %u data_bus_width %u addr_bus_witdh 0x%x spi_len device %s with %u per_rd_len %u per_wr_len success.\n", + spi_dev->data_bus_width, spi_dev->addr_bus_width, spi_dev->spi_len, spi_dev->name, spi_dev->per_rd_len, spi_dev->per_wr_len); + + return 0; +} + +static int spi_dev_remove(struct spi_device *spi) +{ + int i; + + for (i = 0; i < MAX_SPI_DEV_NUM; i++) { + if (spi_dev_arry[i] != NULL) { + misc_deregister(&spi_dev_arry[i]->misc); + spi_dev_arry[i] = NULL; + } + } + return 0; +} + +static const struct of_device_id spi_dev_of_match[] = { + { .compatible = "wb-spi-dev" }, + { }, +}; + +MODULE_DEVICE_TABLE(of, spi_dev_of_match); + +static struct spi_driver spi_dev_driver = { + .driver = { + .name = "wb-spi-dev", + .of_match_table = of_match_ptr(spi_dev_of_match), + }, + .probe = spi_dev_probe, + .remove = spi_dev_remove, +}; + +module_spi_driver(spi_dev_driver); + +MODULE_DESCRIPTION("spi dev driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.h new file mode 100644 index 000000000000..fed5237e3860 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.h @@ -0,0 +1,17 @@ +#ifndef __WB_SPI_DEV_H__ +#define __WB_SPI_DEV_H__ +#include + +#define mem_clear(data, size) memset((data), 0, (size)) +#define SPI_DEV_NAME_MAX_LEN (64) + +typedef struct spi_dev_device_s { + char spi_dev_name[SPI_DEV_NAME_MAX_LEN]; + uint32_t data_bus_width; + uint32_t addr_bus_width; + uint32_t per_rd_len; + uint32_t per_wr_len; + uint32_t spi_len; +} spi_dev_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio.c new file mode 100644 index 000000000000..16408f067be1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio.c @@ -0,0 +1,477 @@ +/* + * SPI master driver using generic bitbanged GPIO + * + * Copyright (C) 2006,2008 David Brownell + * Copyright (C) 2017 Linus Walleij + * + * 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. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * This bitbanging SPI master driver should help make systems usable + * when a native hardware SPI engine is not available, perhaps because + * its driver isn't yet working or because the I/O pins it requires + * are used for other purposes. + * + * platform_device->driver_data ... points to spi_gpio + * + * spi->controller_state ... reserved for bitbang framework code + * spi->controller_data ... holds chipselect GPIO + * + * spi->master->dev.driver_data ... points to spi_gpio->bitbang + */ + +struct spi_gpio { + struct spi_bitbang bitbang; + struct spi_gpio_platform_data pdata; + struct platform_device *pdev; + struct gpio_desc *sck; + struct gpio_desc *miso; + struct gpio_desc *mosi; + struct gpio_desc **cs_gpios; + bool has_cs; +}; + +/*----------------------------------------------------------------------*/ + +/* + * Because the overhead of going through four GPIO procedure calls + * per transferred bit can make performance a problem, this code + * is set up so that you can use it in either of two ways: + * + * - The slow generic way: set up platform_data to hold the GPIO + * numbers used for MISO/MOSI/SCK, and issue procedure calls for + * each of them. This driver can handle several such busses. + * + * - The quicker inlined way: only helps with platform GPIO code + * that inlines operations for constant GPIOs. This can give + * you tight (fast!) inner loops, but each such bus needs a + * new driver. You'll define a new C file, with Makefile and + * Kconfig support; the C code can be a total of six lines: + * + * #define DRIVER_NAME "myboard_spi2" + * #define SPI_MISO_GPIO 119 + * #define SPI_MOSI_GPIO 120 + * #define SPI_SCK_GPIO 121 + * #define SPI_N_CHIPSEL 4 + * #include "spi-gpio.c" + */ + +#ifndef DRIVER_NAME +#define DRIVER_NAME "wb_spi_gpio" + +#define GENERIC_BITBANG /* vs tight inlines */ + +#endif + +/*----------------------------------------------------------------------*/ + +static inline struct spi_gpio *__pure +spi_to_spi_gpio(const struct spi_device *spi) +{ + const struct spi_bitbang *bang; + struct spi_gpio *spi_gpio; + + bang = spi_master_get_devdata(spi->master); + spi_gpio = container_of(bang, struct spi_gpio, bitbang); + return spi_gpio; +} + +static inline struct spi_gpio_platform_data *__pure +spi_to_pdata(const struct spi_device *spi) +{ + return &spi_to_spi_gpio(spi)->pdata; +} + +/* These helpers are in turn called by the bitbang inlines */ +static inline void setsck(const struct spi_device *spi, int is_on) +{ + struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + + gpiod_set_value_cansleep(spi_gpio->sck, is_on); +} + +static inline void setmosi(const struct spi_device *spi, int is_on) +{ + struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + + gpiod_set_value_cansleep(spi_gpio->mosi, is_on); +} + +static inline int getmiso(const struct spi_device *spi) +{ + struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + + if (spi->mode & SPI_3WIRE) + return !!gpiod_get_value_cansleep(spi_gpio->mosi); + else + return !!gpiod_get_value_cansleep(spi_gpio->miso); +} + +/* + * NOTE: this clocks "as fast as we can". It "should" be a function of the + * requested device clock. Software overhead means we usually have trouble + * reaching even one Mbit/sec (except when we can inline bitops), so for now + * we'll just assume we never need additional per-bit slowdowns. + */ +#define spidelay(nsecs) do {} while (0) + +#include "spi-bitbang-txrx.h" + +/* + * These functions can leverage inline expansion of GPIO calls to shrink + * costs for a txrx bit, often by factors of around ten (by instruction + * count). That is particularly visible for larger word sizes, but helps + * even with default 8-bit words. + * + * REVISIT overheads calling these functions for each word also have + * significant performance costs. Having txrx_bufs() calls that inline + * the txrx_word() logic would help performance, e.g. on larger blocks + * used with flash storage or MMC/SD. There should also be ways to make + * GCC be less stupid about reloading registers inside the I/O loops, + * even without inlined GPIO calls; __attribute__((hot)) on GCC 4.3? + */ + +static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits, unsigned flags) +{ + return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits); +} + +static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits, unsigned flags) +{ + return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits); +} + +static u32 spi_gpio_txrx_word_mode2(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits, unsigned flags) +{ + return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits); +} + +static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits, unsigned flags) +{ + return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits); +} + +/* + * These functions do not call setmosi or getmiso if respective flag + * (SPI_MASTER_NO_RX or SPI_MASTER_NO_TX) is set, so they are safe to + * call when such pin is not present or defined in the controller. + * A separate set of callbacks is defined to get highest possible + * speed in the generic case (when both MISO and MOSI lines are + * available), as optimiser will remove the checks when argument is + * constant. + */ + +static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits, unsigned flags) +{ + flags = spi->master->flags; + return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits); +} + +static u32 spi_gpio_spec_txrx_word_mode1(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits, unsigned flags) +{ + flags = spi->master->flags; + return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits); +} + +static u32 spi_gpio_spec_txrx_word_mode2(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits, unsigned flags) +{ + flags = spi->master->flags; + return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits); +} + +static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits, unsigned flags) +{ + flags = spi->master->flags; + return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits); +} + +/*----------------------------------------------------------------------*/ + +static void spi_gpio_chipselect(struct spi_device *spi, int is_active) +{ + struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + + /* set initial clock line level */ + if (is_active) + gpiod_set_value_cansleep(spi_gpio->sck, spi->mode & SPI_CPOL); + + /* Drive chip select line, if we have one */ + if (spi_gpio->has_cs) { + struct gpio_desc *cs = spi_gpio->cs_gpios[spi->chip_select]; + + /* SPI chip selects are normally active-low */ + gpiod_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active); + } +} + +static int spi_gpio_setup(struct spi_device *spi) +{ + struct gpio_desc *cs; + int status = 0; + struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + + /* + * The CS GPIOs have already been + * initialized from the descriptor lookup. + */ + cs = spi_gpio->cs_gpios[spi->chip_select]; + if (!spi->controller_state && cs) + status = gpiod_direction_output(cs, + !(spi->mode & SPI_CS_HIGH)); + + if (!status) + status = spi_bitbang_setup(spi); + + return status; +} + +static int spi_gpio_set_direction(struct spi_device *spi, bool output) +{ + struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + + if (output) + return gpiod_direction_output(spi_gpio->mosi, 1); + else + return gpiod_direction_input(spi_gpio->mosi); +} + +static void spi_gpio_cleanup(struct spi_device *spi) +{ + spi_bitbang_cleanup(spi); +} + +/* + * It can be convenient to use this driver with pins that have alternate + * functions associated with a "native" SPI controller if a driver for that + * controller is not available, or is missing important functionality. + * + * On platforms which can do so, configure MISO with a weak pullup unless + * there's an external pullup on that signal. That saves power by avoiding + * floating signals. (A weak pulldown would save power too, but many + * drivers expect to see all-ones data as the no slave "response".) + */ +static int spi_gpio_request(struct device *dev, + struct spi_gpio *spi_gpio, + unsigned int num_chipselects, + u16 *mflags) +{ + int i; + + spi_gpio->mosi = devm_gpiod_get_optional(dev, "mosi", GPIOD_OUT_LOW); + if (IS_ERR(spi_gpio->mosi)) + return PTR_ERR(spi_gpio->mosi); + if (!spi_gpio->mosi) + /* HW configuration without MOSI pin */ + *mflags |= SPI_MASTER_NO_TX; + + spi_gpio->miso = devm_gpiod_get_optional(dev, "miso", GPIOD_IN); + if (IS_ERR(spi_gpio->miso)) + return PTR_ERR(spi_gpio->miso); + /* + * No setting SPI_MASTER_NO_RX here - if there is only a MOSI + * pin connected the host can still do RX by changing the + * direction of the line. + */ + + spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW); + if (IS_ERR(spi_gpio->sck)) + return PTR_ERR(spi_gpio->sck); + + for (i = 0; i < num_chipselects; i++) { + spi_gpio->cs_gpios[i] = devm_gpiod_get_index(dev, "cs", + i, GPIOD_OUT_HIGH); + if (IS_ERR(spi_gpio->cs_gpios[i])) + return PTR_ERR(spi_gpio->cs_gpios[i]); + } + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id spi_gpio_dt_ids[] = { + { .compatible = "wb-spi-gpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids); + +static int spi_gpio_probe_dt(struct platform_device *pdev) +{ + int ret; + u32 tmp; + struct spi_gpio_platform_data *pdata; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id = + of_match_device(spi_gpio_dt_ids, &pdev->dev); + + if (!of_id) + return 0; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + ret = of_property_read_u32(np, "num-chipselects", &tmp); + if (ret < 0) { + dev_err(&pdev->dev, "num-chipselects property not found\n"); + goto error_free; + } + + pdata->num_chipselect = tmp; + pdev->dev.platform_data = pdata; + + return 1; + +error_free: + devm_kfree(&pdev->dev, pdata); + return ret; +} +#else +static inline int spi_gpio_probe_dt(struct platform_device *pdev) +{ + return 0; +} +#endif + +static int spi_gpio_probe(struct platform_device *pdev) +{ + int status; + struct spi_master *master; + struct spi_gpio *spi_gpio; + struct spi_gpio_platform_data *pdata; + u16 master_flags = 0; + bool use_of = 0; + + status = spi_gpio_probe_dt(pdev); + if (status < 0) + return status; + if (status > 0) + use_of = 1; + + pdata = dev_get_platdata(&pdev->dev); +#ifdef GENERIC_BITBANG + if (!pdata || (!use_of && !pdata->num_chipselect)) + return -ENODEV; +#endif + + master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio)); + if (!master) + return -ENOMEM; + + spi_gpio = spi_master_get_devdata(master); + + spi_gpio->cs_gpios = devm_kcalloc(&pdev->dev, + pdata->num_chipselect, + sizeof(*spi_gpio->cs_gpios), + GFP_KERNEL); + if (!spi_gpio->cs_gpios) + return -ENOMEM; + + platform_set_drvdata(pdev, spi_gpio); + + /* Determine if we have chip selects connected */ + spi_gpio->has_cs = !!pdata->num_chipselect; + + spi_gpio->pdev = pdev; + if (pdata) + spi_gpio->pdata = *pdata; + + status = spi_gpio_request(&pdev->dev, spi_gpio, + pdata->num_chipselect, &master_flags); + if (status) + return status; + + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); + master->mode_bits = SPI_3WIRE | SPI_CPHA | SPI_CPOL | SPI_CS_HIGH; + master->flags = master_flags; + master->bus_num = pdev->id; + /* The master needs to think there is a chipselect even if not connected */ + master->num_chipselect = spi_gpio->has_cs ? pdata->num_chipselect : 1; + master->setup = spi_gpio_setup; + master->cleanup = spi_gpio_cleanup; + + if (pdev->dev.of_node) { + master->dev.of_node = pdev->dev.of_node; + } + + spi_gpio->bitbang.master = master; + spi_gpio->bitbang.chipselect = spi_gpio_chipselect; + spi_gpio->bitbang.set_line_direction = spi_gpio_set_direction; + + if ((master_flags & SPI_MASTER_NO_TX) == 0) { + spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0; + spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1; + spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2; + spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_word_mode3; + } else { + spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0; + spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_spec_txrx_word_mode1; + spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_spec_txrx_word_mode2; + spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_spec_txrx_word_mode3; + } + spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer; + + status = spi_bitbang_start(&spi_gpio->bitbang); + if (status) + spi_master_put(master); + + return status; +} + +static int spi_gpio_remove(struct platform_device *pdev) +{ + struct spi_gpio *spi_gpio; + struct spi_gpio_platform_data *pdata; + + spi_gpio = platform_get_drvdata(pdev); + pdata = dev_get_platdata(&pdev->dev); + + /* stop() unregisters child devices too */ + spi_bitbang_stop(&spi_gpio->bitbang); + + spi_master_put(spi_gpio->bitbang.master); + + return 0; +} + +MODULE_ALIAS("platform:" DRIVER_NAME); + +static struct platform_driver spi_gpio_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(spi_gpio_dt_ids), + }, + .probe = spi_gpio_probe, + .remove = spi_gpio_remove, +}; +module_platform_driver(spi_gpio_driver); + +MODULE_DESCRIPTION("SPI master driver using generic bitbanged GPIO "); +MODULE_AUTHOR("support"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio_device.c new file mode 100644 index 000000000000..b073dac08a8a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio_device.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +#define DEFAULT_GPIO_SCK (67) +#define DEFAULT_GPIO_MISO (32) +#define DEFAULT_GPIO_MOSI (65) +#define DEFAULT_GPIO_CS (6) +#define DEFAULT_SPI_BUS (0) + +static int sck = DEFAULT_GPIO_SCK; +module_param(sck, int, S_IRUGO | S_IWUSR); + +static int miso = DEFAULT_GPIO_MISO; +module_param(miso, int, S_IRUGO | S_IWUSR); + +static int mosi = DEFAULT_GPIO_MOSI; +module_param(mosi, int, S_IRUGO | S_IWUSR); + +static int cs = DEFAULT_GPIO_CS; +module_param(cs, int, S_IRUGO | S_IWUSR); + +static int bus = DEFAULT_SPI_BUS; +module_param(bus, int, S_IRUGO | S_IWUSR); + +static int g_wb_spi_gpio_device_debug = 0; +static int g_wb_spi_gpio_device_error = 0; + +module_param(g_wb_spi_gpio_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_spi_gpio_device_error, int, S_IRUGO | S_IWUSR); + +static char gpiod_lookup_table_devid[64]; + +static char *gpio_chip_name = NULL; +module_param(gpio_chip_name, charp, 0644); +MODULE_PARM_DESC(str_var, "A string variable for GPIO controller"); + +#define WB_SPI_GPIO_DEVICE_VERBOSE(fmt, args...) do { \ + if (g_wb_spi_gpio_device_debug) { \ + printk(KERN_INFO "[WB_SPI_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_SPI_GPIO_DEVICE_ERROR(fmt, args...) do { \ + if (g_wb_spi_gpio_device_error) { \ + printk(KERN_ERR "[WB_SPI_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static struct gpiod_lookup_table wb_spi_gpio_table = { + .table = { + GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_SCK, + "sck", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_MOSI, + "mosi", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_MISO, + "miso", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_CS, + "cs", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct spi_gpio_platform_data spi_pdata = { + .num_chipselect = 1, +}; + +static void spi_gpio_release(struct device *dev) +{ + return; +} + +static struct platform_device wb_spi_gpio_device = { + .name = "wb_spi_gpio", + .num_resources = 0, + .id = -1, + + .dev = { + .platform_data = &spi_pdata, + .release = spi_gpio_release, + } +}; + +static void wb_spi_gpio_table_devid_name_set(void) { + int size; + + size = sizeof(gpiod_lookup_table_devid); + wb_spi_gpio_device.id = bus; + + mem_clear(gpiod_lookup_table_devid, size); + switch (bus) { + case PLATFORM_DEVID_NONE: + snprintf(gpiod_lookup_table_devid, size, "%s", wb_spi_gpio_device.name); + break; + case PLATFORM_DEVID_AUTO: + snprintf(gpiod_lookup_table_devid, size, "%s.%d.auto", wb_spi_gpio_device.name, bus); + break; + default: + snprintf(gpiod_lookup_table_devid, size, "%s.%d", wb_spi_gpio_device.name, bus); + break; + } + + wb_spi_gpio_table.dev_id = gpiod_lookup_table_devid; + return ; +} +static int __init wb_spi_gpio_device_init(void) +{ + int err; + struct gpiod_lookup *p; + + WB_SPI_GPIO_DEVICE_VERBOSE("enter!\n"); + wb_spi_gpio_table.table[0].chip_hwnum = sck; + wb_spi_gpio_table.table[1].chip_hwnum = mosi; + wb_spi_gpio_table.table[2].chip_hwnum = miso; + wb_spi_gpio_table.table[3].chip_hwnum = cs; + if (gpio_chip_name) { + wb_spi_gpio_table.table[0].key = gpio_chip_name; + wb_spi_gpio_table.table[1].key = gpio_chip_name; + wb_spi_gpio_table.table[2].key = gpio_chip_name; + wb_spi_gpio_table.table[3].key = gpio_chip_name; + } + wb_spi_gpio_table_devid_name_set(); + WB_SPI_GPIO_DEVICE_VERBOSE("spi gpi device table bus[%d] dev id[%s]\n", bus, wb_spi_gpio_table.dev_id); + for (p = &wb_spi_gpio_table.table[0]; p->key; p++) { + WB_SPI_GPIO_DEVICE_VERBOSE("con_id:%s gpio:%d\n", p->con_id, p->chip_hwnum); + } + + gpiod_add_lookup_table(&wb_spi_gpio_table); + err = platform_device_register(&wb_spi_gpio_device); + if (err < 0) { + printk(KERN_ERR "register spi gpio device fail(%d). \n", err); + gpiod_remove_lookup_table(&wb_spi_gpio_table); + return -1; + } + + return 0; +} + +static void __exit wb_spi_gpio_device_exit(void) +{ + WB_SPI_GPIO_DEVICE_VERBOSE("enter!\n"); + platform_device_unregister(&wb_spi_gpio_device); + gpiod_remove_lookup_table(&wb_spi_gpio_table); +} + +module_init(wb_spi_gpio_device_init); +module_exit(wb_spi_gpio_device_exit); +MODULE_DESCRIPTION("SPI GPIO Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_nor_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_nor_device.c new file mode 100644 index 000000000000..4196601f717b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_nor_device.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include + +/* The SPI Bus number that the device is mounted on can be specified manually when this module is loaded */ +#define DEFAULT_SPI_BUS_NUM (0) +#define DEFAULT_SPI_CS_NUM (0) +#define DEFAULT_SPI_HZ (100000) + +int g_wb_spi_nor_dev_debug = 0; +int g_wb_spi_nor_dev_error = 0; +int spi_bus_num = DEFAULT_SPI_BUS_NUM; + +module_param(g_wb_spi_nor_dev_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_spi_nor_dev_error, int, S_IRUGO | S_IWUSR); +module_param(spi_bus_num, int, S_IRUGO | S_IWUSR); + +#define SPI_NOR_DEV_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_spi_nor_dev_debug) { \ + printk(KERN_INFO "[SPI_NOR_DEV][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define SPI_NOR_DEV_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_spi_nor_dev_error) { \ + printk(KERN_ERR "[SPI_NOR_DEV][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +struct spi_board_info spi_nor_device_info __initdata= { + .modalias = "mx25l6405d", + .bus_num = DEFAULT_SPI_BUS_NUM, + .chip_select = DEFAULT_SPI_CS_NUM, + .max_speed_hz = 10 * 1000 * 1000, +}; + +static struct spi_device *g_spi_device; + +static int __init wb_spi_nor_dev_init(void) +{ + struct spi_master *master; + + SPI_NOR_DEV_DEBUG_VERBOSE("Enter.\n"); + + spi_nor_device_info.bus_num = spi_bus_num; + master = spi_busnum_to_master(spi_nor_device_info.bus_num); /* Get the controller according to the SPI Bus number */ + if (!master) { + SPI_NOR_DEV_DEBUG_ERROR("get bus_num %u spi master failed.\n", + spi_nor_device_info.bus_num); + return -EINVAL; + } + + g_spi_device = spi_new_device(master, &spi_nor_device_info); + put_device(&master->dev); + if (!g_spi_device) { + SPI_NOR_DEV_DEBUG_ERROR("register spi new device failed.\n"); + return -EPERM; + } + + if (g_wb_spi_nor_dev_debug) { + dev_info(&g_spi_device->dev, "register %u bus_num spi nor device success\n", + spi_nor_device_info.bus_num); + } + + return 0; +} + +static void __exit wb_spi_nor_dev_exit(void) +{ + spi_unregister_device(g_spi_device); + + if (g_wb_spi_nor_dev_debug) { + dev_info(&g_spi_device->dev, "unregister spi nor device success\n"); + } + + return; +} + +module_init(wb_spi_nor_dev_init); +module_exit(wb_spi_nor_dev_exit); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("create spi nor device"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.c new file mode 100644 index 000000000000..a709427c5b73 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.c @@ -0,0 +1,1025 @@ +/* + * wb_spi_ocores.c + * ko to create ocores spi adapter + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_spi_ocores.h" + +#define SPIOC_WAIT_SCH (5) +#define SPIOC_CONF (0x00) +#define SPIOC_LSBF BIT(0) /* 0:MSB 1:LSB */ +#define SPIOC_IDLE_LOW BIT(1) +#define SPIOC_INTREN BIT(2) /* 0:enable 1:disabel */ +#define SPIOC_DIV_MASK (0xf0) +#define SPIOC_MAX_DIV (0x0E) +#define SPIOC_DIV(div) (((div) & 0x0f) << 4) + +#define SPIOC_STS (0x01) +#define SPIOC_INTR_STS BIT(0) +#define SPIOC_BUSY_STS BIT(1) +#define SPIOC_RXNUM_SHIFT (4) +#define SPIOC_RXNUM_MASK (0xf << SPIOC_RXNUM_SHIFT) +/* Just for read */ +#define SPIOC_RXNUM(reg) (((reg) & SPIOC_RXNUM_MASK) >> SPIOC_RXNUM_SHIFT ) + +#define SPIOC_TXTOT_NUM (0x02) +#define SPIOC_TXNUM(reg) ((reg) & 0x0f) +#define SPIOC_TOTNUM(reg) (((reg) & 0x0f) << 4) + +#define SPIOC_TXCTL (0x03) +#define SPIOC_CSLV BIT(0) /* 0:Deassert SPICS 1:Laeve SPICS */ +#define SPIOC_TRSTART BIT(1) +#define SPIOC_CSID_SHIFT (5) +#define SPIOC_CSID_MASK (0x7 << SPIOC_CSID_SHIFT) +/* Just for write */ +#define SPIOC_CSID(id) (((id) << SPIOC_CSID_SHIFT) & SPIOC_CSID_MASK) + +/* Just single byte */ +#define SPIOC_RX(i) ((0x4) + i) +#define SPIOC_TX(i) ((0x4) + i) + +#define SPIOC_MAX_LEN ((unsigned int)8) +#define SPIOC_TXRX_MAX_LEN ((unsigned int)7) + +#define MODEBITS (SPI_CPHA |SPI_CPOL | SPI_LSB_FIRST |SPI_CS_HIGH) + +#define REG_IO_WIDTH_1 (1) +#define REG_IO_WIDTH_2 (2) +#define REG_IO_WIDTH_4 (4) + +#define SYMBOL_I2C_DEV_MODE (1) +#define FILE_MODE (2) +#define SYMBOL_PCIE_DEV_MODE (3) +#define SYMBOL_IO_DEV_MODE (4) + +int g_spi_oc_debug = 0; +int g_spi_oc_error = 0; + +module_param(g_spi_oc_debug, int, S_IRUGO | S_IWUSR); +module_param(g_spi_oc_error, int, S_IRUGO | S_IWUSR); + +#define SPI_OC_VERBOSE(fmt, args...) do { \ + if (g_spi_oc_debug) { \ + printk(KERN_INFO "[OC_SPI_BUS][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define SPI_OC_ERROR(fmt, args...) do { \ + if (g_spi_oc_error) { \ + printk(KERN_ERR "[OC_SPI_BUS][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +struct spioc { + /* bitbang has to be first */ + struct spi_bitbang bitbang; + int irq; + struct completion done; + unsigned int reamin_len; + unsigned int cur_pos; + unsigned int cur_len; + const u8 *txp; + u8 *rxp; + u8 chip_select; + void (*setreg)(struct spioc *spioc, int reg, u32 value); + u32 (*getreg)(struct spioc *spioc, int reg); + uint32_t bus_num; + const char *dev_name; + uint32_t reg_access_mode; + uint32_t base_addr; + uint32_t reg_shift; + uint32_t reg_io_width; + uint32_t num_chipselect; + uint32_t freq; + uint32_t big_endian; + struct device *dev; + int transfer_busy_flag; +}; + +extern int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); + +static int oc_spi_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + filp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(filp)) { + SPI_OC_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + ret = kernel_read(filp, val, size, &tmp_pos); + if (ret < 0) { + SPI_OC_ERROR("kernel_read failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int oc_spi_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + + int ret; + struct file *filp; + loff_t tmp_pos; + + filp = filp_open(path, O_RDWR, 777); + if (IS_ERR(filp)) { + SPI_OC_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + ret = kernel_write(filp, val, size, &tmp_pos); + if (ret < 0) { + SPI_OC_ERROR("kernel_write failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + vfs_fsync(filp, 1); + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int oc_spi_reg_write(struct spioc *spioc, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + + switch (spioc->reg_access_mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_write(spioc->dev_name, pos, val, size); + break; + case FILE_MODE: + ret = oc_spi_file_write(spioc->dev_name, pos, val, size); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_write(spioc->dev_name, pos, val, size); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_write(spioc->dev_name, pos, val, size); + break; + default: + SPI_OC_ERROR("err func_mode, write failed.\n"); + return -EINVAL; + } + + return ret; +} + +static int oc_spi_reg_read(struct spioc *spioc, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + + switch (spioc->reg_access_mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_read(spioc->dev_name, pos, val, size); + break; + case FILE_MODE: + ret = oc_spi_file_read(spioc->dev_name, pos, val, size); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_read(spioc->dev_name, pos, val, size); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_read(spioc->dev_name, pos, val, size); + break; + default: + SPI_OC_ERROR("err func_mode, read failed.\n"); + return -EINVAL; + } + + return ret; +} + +static void oc_spi_setreg_8(struct spioc *spioc, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_1]; + u32 pos; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + + buf_tmp[0] = (value & 0Xff); + oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_1); + return; +} + +static void oc_spi_setreg_16(struct spioc *spioc, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 pos; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + + buf_tmp[0] = (value & 0Xff); + buf_tmp[1] = (value >> 8) & 0xff; + oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_2); + return; +} + +static void oc_spi_setreg_32(struct spioc *spioc, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 pos; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + + buf_tmp[0] = (value & 0xff); + buf_tmp[1] = (value >> 8) & 0xff; + buf_tmp[2] = (value >> 16) & 0xff; + buf_tmp[3] = (value >> 24) & 0xff; + + oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_4); + return; +} + +static void oc_spi_setreg_16be(struct spioc *spioc, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 pos; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + + buf_tmp[0] = (value >> 8) & 0xff; + buf_tmp[1] = (value & 0Xff); + oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_2); + return; +} + +static void oc_spi_setreg_32be(struct spioc *spioc, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 pos; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + + buf_tmp[0] = (value >> 24) & 0xff; + buf_tmp[1] = (value >> 16) & 0xff; + buf_tmp[2] = (value >> 8) & 0xff; + buf_tmp[3] = (value & 0xff); + oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_4); + return; +} + +static inline u32 oc_spi_getreg_8(struct spioc *spioc, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_1]; + u32 value, pos; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_1); + value = buf_tmp[0]; + + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + + return value; +} + +static inline u32 oc_spi_getreg_16(struct spioc *spioc, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 value, pos; + int i; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + mem_clear(buf_tmp, sizeof(buf_tmp)); + oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_2); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_2 ; i++) { + value |= buf_tmp[i] << (8 * i); + } + + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + return value; +} + +static inline u32 oc_spi_getreg_32(struct spioc *spioc, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 value, pos; + int i; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + mem_clear(buf_tmp, sizeof(buf_tmp)); + oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_4); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_4 ; i++) { + value |= buf_tmp[i] << (8 * i); + } + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + return value; +} + +static inline u32 oc_spi_getreg_16be(struct spioc *spioc, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 value, pos; + int i; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + + mem_clear(buf_tmp, sizeof(buf_tmp)); + oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_2); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_2 ; i++) { + value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_2 -i - 1)); + } + + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + return value; +} + +static inline u32 oc_spi_getreg_32be(struct spioc *spioc, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 value, pos; + int i; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + + mem_clear(buf_tmp, sizeof(buf_tmp)); + oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_4); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_4 ; i++) { + value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_4 -i - 1)); + } + + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + return value; + +} + +static inline void oc_spi_setreg(struct spioc *spioc, int reg, u32 value) +{ + spioc->setreg(spioc, reg, value); + return; +} + +static inline u32 oc_spi_getreg(struct spioc *spioc, int reg) +{ + return spioc->getreg(spioc, reg); +} + +static int spioc_get_clkdiv(struct spioc *spioc, u32 speed) +{ + u32 rate, div; + + rate = spioc->freq; + SPI_OC_VERBOSE("clk get rate:%u, speed:%u\n", rate, speed); + /* fs = fw/((DIV+2)*2) */ + + if (speed > (rate / 4)) { + div = 0; + SPI_OC_VERBOSE("spi device speed[%u] more than a quarter of clk rate[%u].\n", + speed, rate); + return div; + } + div = (rate/(2 * speed)) - 2; + if (div > SPIOC_MAX_DIV) { + SPI_OC_ERROR("Unsupport spi device speed, div:%u.\n", div); + return -1; + } + SPI_OC_VERBOSE("DIV is:0x%x\n", div); + return div; +} + +static inline int spioc_wait_trans(struct spioc *spioc, const unsigned long timeout) +{ + unsigned long j; + unsigned int sch_time; + u8 reg; + + j = jiffies + timeout; + sch_time = SPIOC_WAIT_SCH; + while (1) { + reg = oc_spi_getreg(spioc, SPIOC_STS); + if (!(reg & SPIOC_BUSY_STS)) { + SPI_OC_VERBOSE("wait ok!\n"); + break; + } + + if (time_after(jiffies, j)) { + return -ETIMEDOUT; + } + + usleep_range(sch_time, sch_time + 1); + } + + return 0; +} + +static void spioc_chipselect(struct spi_device *spi, int is_active) +{ + struct spioc *spioc; + u8 tx_conf; + int ret; + + spioc = spi_master_get_devdata(spi->master); + spioc->transfer_busy_flag = 0; + ret = spioc_wait_trans(spioc, msecs_to_jiffies(100)); + if (ret < 0) { + SPI_OC_ERROR("spi transfer is busy, ret=%d.\n", ret); + spioc->transfer_busy_flag = 1; + return; + } + spioc->chip_select = spi->chip_select; + SPI_OC_VERBOSE("spioc_chipselect:%u, value:%d.\n", spioc->chip_select, is_active); + tx_conf = 0; + tx_conf |= SPIOC_CSID(spioc->chip_select); + if (is_active) { + tx_conf |= SPIOC_CSLV; + } + + SPI_OC_VERBOSE("tx_config:[0x%x]\n", tx_conf); + oc_spi_setreg(spioc, SPIOC_TXCTL, tx_conf); + return; +} + +static void spioc_copy_tx(struct spioc *spioc) +{ + const u8 *src; + int i; + + if (!spioc->txp) { + SPI_OC_ERROR("spioc->txp is NULL.\n"); + return; + } + + src = (u8 *)spioc->txp + spioc->cur_pos; + SPI_OC_VERBOSE("current tx len:0x%x, tx pos:[0x%x]\n", spioc->cur_len, spioc->cur_pos); + + for (i = 0; i < spioc->cur_len; i++) { + SPI_OC_VERBOSE("write %d, val:[0x%x]\n", i, src[i]); + oc_spi_setreg(spioc, SPIOC_TX(i), src[i]); + } +} + +static void spioc_copy_rx(struct spioc *spioc) +{ + u8 *dest; + int i; + + if (!spioc->rxp) { + SPI_OC_ERROR("spioc->rxp is NULL.\n"); + return; + } + + dest = (u8 *)spioc->rxp + spioc->cur_pos; + SPI_OC_VERBOSE("current rx len:0x%x, rx pos:[0x%x]\n", spioc->cur_len, spioc->cur_pos); + + for (i = 0; i < spioc->cur_len; i++) { + dest[i] = oc_spi_getreg(spioc, SPIOC_RX(i)); + SPI_OC_VERBOSE("read %d, val:[0x%x]\n", i, dest[i]); + } +} + +static int spioc_setup_transfer(struct spi_device *spi, struct spi_transfer *transfer) +{ + struct spioc *spioc; + u8 ctrl; + u32 hz; + int div; + + spioc = spi_master_get_devdata(spi->master); + ctrl = 0; + + if (spi->mode & SPI_LSB_FIRST) { + ctrl |= SPIOC_LSBF; + } + + if (!(spi->mode & SPI_CPOL)) { + ctrl |= SPIOC_IDLE_LOW; + } + + if (spioc->irq < 0) { + + ctrl |= SPIOC_INTREN; + } + + if (transfer != NULL) { + hz = transfer->speed_hz; + + if (hz == 0) { + hz = spi->max_speed_hz; + } + } else { + hz = spi->max_speed_hz; + } + + if (hz == 0) { + SPI_OC_ERROR("Unsupport zero speed.\n"); + return -EINVAL; + } + + div = spioc_get_clkdiv(spioc, hz); + if (div < 0) { + SPI_OC_ERROR("get div error, div:%d.\n", div); + return -EINVAL; + } + ctrl |= SPIOC_DIV(div); + + SPI_OC_VERBOSE("ctrl:[0x%x].\n", ctrl); + + oc_spi_setreg(spioc, SPIOC_CONF, ctrl); + return 0; +} + +static int spioc_spi_setup(struct spi_device *spi) +{ + struct spioc *spioc; + + if (!(spi->mode & SPI_CPHA)) { + SPI_OC_ERROR("Unsupport spi device mde:0x%x, SPI_CPHA must be 1.\n", spi->mode); + return -EINVAL; + } + + spioc = spi_master_get_devdata(spi->master); + if (spi->chip_select >= spioc->num_chipselect) { + SPI_OC_ERROR("Spi device chipselect:%u, more than max chipselect:%u.\n", + spi->chip_select, spioc->num_chipselect); + return -EINVAL; + } + SPI_OC_VERBOSE("Support spi device mode:0x%x, chip_select:%u.\n", + spi->mode, spi->chip_select); + return 0; +} + +static int spioc_transfer_start(struct spioc *spioc) +{ + u8 tx_conf; + int ret; + + tx_conf = oc_spi_getreg(spioc, SPIOC_TXCTL); + tx_conf |= SPIOC_TRSTART; + + SPI_OC_VERBOSE("tx_config:[0x%x]\n", tx_conf); + oc_spi_setreg(spioc, SPIOC_TXCTL, tx_conf); + + ret = spioc_wait_trans(spioc, msecs_to_jiffies(100)); + return ret; +} + +static int spioc_tx_start_one(struct spioc *spioc) +{ + unsigned int txlen; + u8 txreg; + int ret; + + if (!spioc->reamin_len) { + SPI_OC_VERBOSE("spioc txlen:[0x0]\n"); + return 0; + } + + spioc->cur_len = spioc->reamin_len > SPIOC_MAX_LEN ? SPIOC_MAX_LEN : spioc->reamin_len; + + txlen = spioc->cur_len; + spioc->reamin_len -= txlen; + SPI_OC_VERBOSE("txlen:[0x%x], tx len remain:[0x%x]\n", txlen, spioc->reamin_len); + + spioc_copy_tx(spioc); + + /* when we only send, txlen == totlen */ + txreg = SPIOC_TXNUM(txlen) | SPIOC_TOTNUM(txlen); + SPI_OC_VERBOSE("txreg:[0x%x]\n", txreg); + oc_spi_setreg(spioc, SPIOC_TXTOT_NUM, txreg); + + ret = spioc_transfer_start(spioc); + if (ret) { + SPI_OC_ERROR("spioc tx rx poll wait for transfer timeout.\n"); + return ret; + } + + if (spioc->reamin_len) { + spioc->cur_pos += txlen; + SPI_OC_VERBOSE("cur_txpos:[0x%x]\n", spioc->cur_pos); + } + + return 0; +} + +static int spioc_rx_start_one(struct spioc *spioc) +{ + unsigned int rxlen; + u8 txtnum; + int ret; + + if (!spioc->reamin_len) { + SPI_OC_VERBOSE("spioc reamin_len:[0x0]\n"); + return 0; + } + + spioc->cur_len = spioc->reamin_len > SPIOC_MAX_LEN ? SPIOC_MAX_LEN : spioc->reamin_len; + + rxlen = spioc->cur_len; + spioc->reamin_len -= rxlen; + SPI_OC_VERBOSE("rxlen:[0x%x], rx len remain:[0x%x]\n", rxlen, spioc->reamin_len); + + /* when we only receive, rxnum=totnum. txnum=0 */ + txtnum = SPIOC_TOTNUM(rxlen); + SPI_OC_VERBOSE("tx total reg:0x%x\n", txtnum); + oc_spi_setreg(spioc, SPIOC_TXTOT_NUM, txtnum); + + ret = spioc_transfer_start(spioc); + if (ret) { + SPI_OC_ERROR("spioc tx rx poll wait for transfer timeout.\n"); + return ret; + } + + spioc_copy_rx(spioc); + + if (spioc->reamin_len) { + spioc->cur_pos += rxlen; + SPI_OC_VERBOSE("cur_rxpos:[0x%x]\n", spioc->cur_pos); + } + + return 0; +} + +static int spioc_tx_rx_start_one(struct spioc *spioc) +{ + unsigned int txlen, total_len; + u8 txreg; + int ret; + + if (!spioc->reamin_len) { + SPI_OC_VERBOSE("spioc reamin_len:[0x0]\n"); + return 0; + } + + spioc->cur_len = spioc->reamin_len > SPIOC_TXRX_MAX_LEN ? SPIOC_TXRX_MAX_LEN : spioc->reamin_len; + + txlen = spioc->cur_len; + spioc->reamin_len -= txlen; + SPI_OC_VERBOSE("tx len:[0x%x], tx len remain:[0x%x]\n", txlen, spioc->reamin_len); + + spioc_copy_tx(spioc); + + total_len = 2 * txlen; /* total_len=txlen + rxlen; rxlen=txlen */ + txreg = SPIOC_TXNUM(txlen) | SPIOC_TOTNUM(total_len); + SPI_OC_VERBOSE("txreg:[0x%x]\n", txreg); + oc_spi_setreg(spioc, SPIOC_TXTOT_NUM, txreg); + + ret = spioc_transfer_start(spioc); + if (ret) { + SPI_OC_ERROR("spioc tx rx poll wait for transfer timeout.\n"); + return ret; + } + + spioc_copy_rx(spioc); + if (spioc->reamin_len) { + spioc->cur_pos += txlen; + SPI_OC_VERBOSE("cur_txrx pos:[0x%x]\n", spioc->cur_pos); + } + return 0; +} + +static int spioc_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) +{ + struct spioc *spioc; + int ret , len; + + if(!t->len || (!t->tx_buf && !t->rx_buf)) { + SPI_OC_ERROR("params error, tx_buf and rx_buf may both NULL, transfer len:0x%x.\n", + t->len); + return 0; + } + + spioc = spi_master_get_devdata(spi->master); + if (spioc->transfer_busy_flag) { + ret = -EBUSY; + goto err; + } + + spioc->txp = t->tx_buf; + spioc->rxp = t->rx_buf; + spioc->reamin_len = t->len; + spioc->cur_len = 0; + spioc->cur_pos = 0; + len = t->len; + ret = 0; + if (spioc->irq >= 0) { + /* use interrupt driven data transfer */ + if (t->tx_buf && t->rx_buf) { + spioc_tx_rx_start_one(spioc); + wait_for_completion(&spioc->done); + } else if (t->tx_buf) { + spioc_tx_start_one(spioc); + wait_for_completion(&spioc->done); + + } else { + spioc_rx_start_one(spioc); + wait_for_completion(&spioc->done); + } + } else { + if (t->tx_buf && t->rx_buf) { + SPI_OC_VERBOSE("start tx rx, len:0x%x\n", t->len); + while (spioc->reamin_len) { + ret = spioc_tx_rx_start_one(spioc); + if (ret) { + goto err; + } + } + } else if (t->tx_buf) { + SPI_OC_VERBOSE("start tx, txlen:0x%x\n", t->len); + while (spioc->reamin_len) { + ret = spioc_tx_start_one(spioc); + if (ret) { + goto err; + } + } + } else { + SPI_OC_VERBOSE("start rx, rxlen:0x%x\n", t->len); + while (spioc->reamin_len) { + ret = spioc_rx_start_one(spioc); + if (ret) { + goto err; + } + } + } + } + SPI_OC_VERBOSE("return num: 0x%x\n", len); + return len; +err: + return ret; +} + +static irqreturn_t spioc_spi_irq(int irq, void *dev) +{ + struct spioc *spioc; + + spioc = dev; + /* gooooohi, interrupt status bit judgment is not done */ + + if (spioc->txp && spioc->rxp) { + if (!spioc->reamin_len) { + complete(&spioc->done); + } else { + spioc_tx_rx_start_one(spioc); + } + } else if (spioc->txp) { + if (!spioc->reamin_len) { + complete(&spioc->done); + } else { + spioc_tx_start_one(spioc); + } + } else if (spioc->rxp){ + if (!spioc->reamin_len) { + complete(&spioc->done); + } else { + spioc_rx_start_one(spioc); + } + } + + return IRQ_HANDLED; +} + +static int ocores_spi_config_init(struct spioc *spioc) +{ + int ret = 0; + struct device *dev; + spi_ocores_device_t *spi_ocores_device; + + dev = spioc->dev; + if (dev->of_node) { + ret += of_property_read_string(dev->of_node, "dev_name", &spioc->dev_name); + ret += of_property_read_u32(dev->of_node, "dev_base", &spioc->base_addr); + ret += of_property_read_u32(dev->of_node, "reg_shift", &spioc->reg_shift); + ret += of_property_read_u32(dev->of_node, "reg_io_width", &spioc->reg_io_width); + ret += of_property_read_u32(dev->of_node, "clock-frequency", &spioc->freq); + ret += of_property_read_u32(dev->of_node, "reg_access_mode", &spioc->reg_access_mode); + ret += of_property_read_u32(dev->of_node, "num_chipselect", &spioc->num_chipselect); + + if (ret != 0) { + SPI_OC_ERROR("dts config error, ret:%d.\n", ret); + ret = -ENXIO; + return ret; + } + } else { + if (spioc->dev->platform_data == NULL) { + SPI_OC_ERROR("platform data config error.\n"); + ret = -ENXIO; + return ret; + } + spi_ocores_device = spioc->dev->platform_data; + spioc->bus_num = spi_ocores_device->bus_num; + spioc->dev_name = spi_ocores_device->dev_name; + spioc->big_endian = spi_ocores_device->big_endian; + spioc->base_addr = spi_ocores_device->dev_base; + spioc->reg_shift = spi_ocores_device->reg_shift; + spioc->reg_io_width = spi_ocores_device->reg_io_width; + spioc->freq = spi_ocores_device->clock_frequency; + spioc->reg_access_mode = spi_ocores_device->reg_access_mode; + spioc->num_chipselect = spi_ocores_device->num_chipselect; + } + + SPI_OC_VERBOSE("name:%s, base:0x%x, reg_shift:0x%x, io_width:0x%x, clock-frequency:0x%x.\n", + spioc->dev_name, spioc->base_addr, spioc->reg_shift, spioc->reg_io_width, spioc->freq); + SPI_OC_VERBOSE("reg access mode:%u, num_chipselect:%u.\n", + spioc->reg_access_mode, spioc->num_chipselect); + return ret; +} + +static int spioc_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct spioc *spioc; + int ret; + bool be; + + ret = -1; + master = spi_alloc_master(&pdev->dev, sizeof(struct spioc)); + if (!master) { + dev_err(&pdev->dev, "Failed to alloc spi master.\n"); + goto out; + } + + spioc = spi_master_get_devdata(master); + platform_set_drvdata(pdev, spioc); + + spioc->dev = &pdev->dev; + ret = ocores_spi_config_init(spioc); + if (ret != 0) { + dev_err(spioc->dev, "Failed to get ocores spi dts config.\n"); + goto free; + } + + if (spioc->dev->of_node) { + if (of_property_read_u32(spioc->dev->of_node, "big_endian", &spioc->big_endian)) { + + be = 0; + } else { + be = spioc->big_endian; + } + } else { + be = spioc->big_endian; + } + + if (spioc->reg_io_width == 0) { + spioc->reg_io_width = 1; /* Set to default value */ + } + + if (!spioc->setreg || !spioc->getreg) { + switch (spioc->reg_io_width) { + case REG_IO_WIDTH_1: + spioc->setreg = oc_spi_setreg_8; + spioc->getreg = oc_spi_getreg_8; + break; + + case REG_IO_WIDTH_2: + spioc->setreg = be ? oc_spi_setreg_16be : oc_spi_setreg_16; + spioc->getreg = be ? oc_spi_getreg_16be : oc_spi_getreg_16; + break; + + case REG_IO_WIDTH_4: + spioc->setreg = be ? oc_spi_setreg_32be : oc_spi_setreg_32; + spioc->getreg = be ? oc_spi_getreg_32be : oc_spi_getreg_32; + break; + + default: + dev_err(spioc->dev, "Unsupported I/O width (%d)\n", spioc->reg_io_width); + ret = -EINVAL; + goto free; + } + } + + /* master state */ + master->num_chipselect = spioc->num_chipselect; + master->mode_bits = MODEBITS; + master->setup = spioc_spi_setup; + if (spioc->dev->of_node) { + master->dev.of_node = pdev->dev.of_node; + } else { + master->bus_num = spioc->bus_num; + } + + /* setup the state for the bitbang driver */ + spioc->bitbang.master = master; + spioc->bitbang.setup_transfer = spioc_setup_transfer; + spioc->bitbang.chipselect = spioc_chipselect; + spioc->bitbang.txrx_bufs = spioc_spi_txrx_bufs; + + /* gooooohi need revision */ + spioc->irq = platform_get_irq(pdev, 0); + if (spioc->irq >= 0) { + SPI_OC_VERBOSE("spi oc use irq, irq number:%d.\n", spioc->irq); + init_completion(&spioc->done); + ret = devm_request_irq(&pdev->dev, spioc->irq, spioc_spi_irq, 0, + pdev->name, spioc); + if (ret) { + dev_err(spioc->dev, "Failed to request irq:%d.\n", spioc->irq); + goto free; + } + } + + ret = spi_bitbang_start(&spioc->bitbang); + if (ret) { + dev_err(spioc->dev, "Failed to start spi bitbang, ret:%d.\n", ret); + goto free; + } + dev_info(spioc->dev, "registered spi-%d for %s with base address:0x%x success.\n", + master->bus_num, spioc->dev_name, spioc->base_addr); + + return ret; +free: + spi_master_put(master); +out: + return ret; +} + +static int spioc_remove(struct platform_device *pdev) +{ + struct spioc *spioc; + struct spi_master *master; + + spioc = platform_get_drvdata(pdev); + master = spioc->bitbang.master; + spi_bitbang_stop(&spioc->bitbang); + platform_set_drvdata(pdev, NULL); + spi_master_put(master); + + return 0; +} + +static const struct of_device_id spioc_match[] = { + { .compatible = "wb-spi-oc", }, + {}, +}; +MODULE_DEVICE_TABLE(of, spioc_match); + +static struct platform_driver spioc_driver = { + .probe = spioc_probe, + .remove = spioc_remove, + .driver = { + .name = "wb-spioc", + .owner = THIS_MODULE, + .of_match_table = spioc_match, + }, +}; + +module_platform_driver(spioc_driver); + +MODULE_DESCRIPTION("spi open core adapter driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.h new file mode 100644 index 000000000000..647ff0c5f9cf --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.h @@ -0,0 +1,21 @@ +#ifndef __WB_SPI_OCORES_H__ +#define __WB_SPI_OCORES_H__ +#include + +#define mem_clear(data, size) memset((data), 0, (size)) +#define SPI_OCORES_DEV_NAME_MAX_LEN (64) + +typedef struct spi_ocores_device_s { + uint32_t bus_num; + uint32_t big_endian; + char dev_name[SPI_OCORES_DEV_NAME_MAX_LEN]; + uint32_t reg_access_mode; + uint32_t dev_base; + uint32_t reg_shift; + uint32_t reg_io_width; + uint32_t clock_frequency; + uint32_t num_chipselect; + int device_flag; +} spi_ocores_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_uio_irq.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_uio_irq.c new file mode 100644 index 000000000000..da2b582443b8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_uio_irq.c @@ -0,0 +1,282 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct dfd_irq_s { + int gpio; + int irq_type; + struct uio_info dfd_irq_info; + spinlock_t lock; + struct attribute_group attr_group; +} dfd_irq_t; + +#define DRV_NAME "uio-irq" +#define DRV_VERSION "1.0" +#define ENABLE_VAL (1) +#define DISABLE_VAL (0) + +#define DEBUG_ERR_LEVEL (0x1) +#define DEBUG_WARN_LEVEL (0x2) +#define DEBUG_INFO_LEVEL (0x4) +#define DEBUG_VER_LEVEL (0x8) + +static int debug = 0; +module_param(debug, int, S_IRUGO | S_IWUSR); +#define DEBUG_ERROR(fmt, args...) \ + do { \ + if (debug & DEBUG_ERR_LEVEL) { \ + printk(KERN_ERR "[ERR][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ + } else { \ + pr_debug(fmt, ## args); \ + } \ + } while(0) + +#define DEBUG_WARN(fmt, args...) \ + do { \ + if (debug & DEBUG_WARN_LEVEL) { \ + printk(KERN_WARNING "[WARN][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ + } else { \ + pr_debug(fmt, ## args); \ + } \ + } while(0) + +#define DEBUG_INFO(fmt, args...) \ + do { \ + if (debug & DEBUG_INFO_LEVEL) { \ + printk(KERN_INFO "[INFO][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ + } else { \ + pr_debug(fmt, ## args); \ + } \ + } while(0) + +#define DEBUG_VERBOSE(fmt, args...) \ + do { \ + if (debug & DEBUG_VER_LEVEL) { \ + printk(KERN_DEBUG "[VER][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ + } else { \ + pr_debug(fmt, ## args); \ + } \ + } while(0) + +static irqreturn_t dfd_genirq_handler(int irq, struct uio_info *dev_info) +{ + disable_irq_nosync(irq); + DEBUG_VERBOSE("handler disable irq"); + return IRQ_HANDLED; +} + +static int dfd_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on) +{ + struct irq_data *irqdata; + + irqdata = irq_get_irq_data(dev_info->irq); + + if (irqd_irq_disabled(irqdata) == !irq_on) { + DEBUG_VERBOSE("irq already disable"); + return 0; + } + if (irq_on) { + DEBUG_VERBOSE("irqcontrol enable irq"); + enable_irq(dev_info->irq); + } else { + DEBUG_VERBOSE("irqcontrol disable irq"); + disable_irq(dev_info->irq); + } + + return 0; +} + +static ssize_t set_irq_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + dfd_irq_t *dfd_irq; + struct uio_info *dev_info; + unsigned long flags; + int ret, val; + + dfd_irq = dev_get_drvdata(dev); + dev_info = &dfd_irq->dfd_irq_info; + + spin_lock_irqsave(&dfd_irq->lock, flags); + + sscanf(buf, "%d", &val); + DEBUG_VERBOSE("set val:%d.\n", val); + + if ((val != ENABLE_VAL) && (val != DISABLE_VAL)) { + DEBUG_ERROR("unsupport val:%d ", val); + ret = -EINVAL; + goto fail; + } + + if (val) { + DEBUG_VERBOSE("sysfs enable irq"); + enable_irq(dev_info->irq); + } else { + DEBUG_VERBOSE("sysfs disable irq"); + disable_irq(dev_info->irq); + } + + spin_unlock_irqrestore(&dfd_irq->lock, flags); + return count; + +fail: + spin_unlock_irqrestore(&dfd_irq->lock, flags); + return ret; +} + +static DEVICE_ATTR(irq_enable, S_IWUSR, NULL, set_irq_enable); + +static struct attribute *irq_attrs[] = { + &dev_attr_irq_enable.attr, + NULL, +}; + +static struct attribute_group irq_attr_group = { + .attrs = irq_attrs, +}; + +static int dfd_irq_probe(struct platform_device *pdev) +{ + u32 gpio, irq_type, pirq_line; + int ret, ret1, ret2; + struct uio_info *dfd_irq_info; + dfd_irq_t *dfd_irq; + + dfd_irq = kzalloc(sizeof(dfd_irq_t), GFP_KERNEL); + if (!dfd_irq) { + dev_err(&pdev->dev, "dfd_irq_t kzalloc failed.\n"); + return -ENOMEM; + } + + dfd_irq_info = &dfd_irq->dfd_irq_info; + dfd_irq_info->version = "1.0"; + dfd_irq_info->name = "uio-irq"; + + /* get pirq line for x86 */ + ret1 = of_property_read_u32(pdev->dev.of_node, "pirq-line", &pirq_line); + if (!ret1) { + DEBUG_VERBOSE("use pirq-line method, pirq-line:%u", pirq_line); + dfd_irq_info->irq = pirq_line; + } + + ret2 = of_property_read_u32(pdev->dev.of_node, "gpio", &gpio); + if (!ret2 && ret1) { + dfd_irq->gpio = gpio; + gpio_request(dfd_irq->gpio, "GPIOA"); + dfd_irq_info->irq = gpio_to_irq(dfd_irq->gpio); + DEBUG_VERBOSE("use gpio:%u, irq num:%ld", gpio, dfd_irq_info->irq); + } else if (ret2 && ret1){ + ret = -ENXIO; + dev_err(&pdev->dev, "no define irq num. ret2:%d, ret1:%d.\n", ret2, ret1); + goto free_mem; + } + + ret = of_property_read_u32(pdev->dev.of_node, "irq_type", &irq_type); + if (!ret && ret1) { + DEBUG_VERBOSE("use irq_type:%u", irq_type); + dfd_irq->irq_type = irq_type; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) + irq_set_irq_type(dfd_irq_info->irq, dfd_irq->irq_type); +#else + set_irq_type(dfd_irq_info->irq, dfd_irq->irq_type); +#endif + } else if (ret && ret1){ + ret = -ENXIO; + dev_err(&pdev->dev, "no define irq type. ret:%d, ret1:%d.\n", ret, ret1); + goto free_mem; + } + + dfd_irq_info->irq_flags = IRQF_SHARED; + dfd_irq_info->handler = dfd_genirq_handler; + dfd_irq_info->irqcontrol = dfd_genirq_irqcontrol; + + if(uio_register_device(&pdev->dev, dfd_irq_info)){ + ret = -ENODEV; + dev_err(&pdev->dev, "uio register failed.\n"); + goto free_mem; + } + + spin_lock_init(&dfd_irq->lock); + + dfd_irq->attr_group = irq_attr_group; + ret = sysfs_create_group(&pdev->dev.kobj, &dfd_irq->attr_group); + if (ret != 0) { + dev_err(&pdev->dev, "sysfs_create_group failed. ret:%d.\n", ret); + goto free_mem; + } + DEBUG_VERBOSE("sysfs create group success\n"); + + platform_set_drvdata(pdev, dfd_irq); + + return 0; + +free_mem: + kfree(dfd_irq); + + return ret; +} + +static int dfd_irq_remove(struct platform_device *pdev) +{ + dfd_irq_t *dfd_irq; + struct uio_info *dfd_irq_info; + + dfd_irq = platform_get_drvdata(pdev); + dfd_irq_info = &dfd_irq->dfd_irq_info; + + uio_unregister_device(dfd_irq_info); + kfree(dfd_irq); + + sysfs_remove_group(&pdev->dev.kobj, &dfd_irq->attr_group); + + return 0; +} + +static struct of_device_id dfd_irq_match[] = { + { + .compatible = "uio-irq", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, dfd_irq_match); + +static struct platform_driver dfd_irq_driver = { + .probe = dfd_irq_probe, + .remove = dfd_irq_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .of_match_table = dfd_irq_match, + }, +}; + +static int __init dfd_irq_init(void) +{ + int ret; + + ret = platform_driver_register(&dfd_irq_driver); + if (ret != 0 ) { + return ret; + } + + return 0; +} + +static void __exit dfd_irq_exit(void) +{ + platform_driver_unregister(&dfd_irq_driver); +} + +module_init(dfd_irq_init); +module_exit(dfd_irq_exit); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.c new file mode 100644 index 000000000000..c97288944061 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.c @@ -0,0 +1,1187 @@ +/* + * wb_wdt.c + * ko for watchdog function + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_wdt.h" + +#define GPIO_FEED_WDT_MODE (1) +#define LOGIC_FEED_WDT_MODE (2) + +#define SYMBOL_I2C_DEV_MODE (1) +#define SYMBOL_PCIE_DEV_MODE (2) +#define SYMBOL_IO_DEV_MODE (3) +#define FILE_MODE (4) + +#define ONE_BYTE (1) + +#define WDT_OFF (0) +#define WDT_ON (1) + +#define MS_TO_S (1000) +#define MS_TO_NS (1000 * 1000) + +#define MAX_REG_VAL (255) + +extern int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); + +int g_wb_wdt_debug = 0; +int g_wb_wdt_error = 0; + +module_param(g_wb_wdt_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_wdt_error, int, S_IRUGO | S_IWUSR); + +#define WDT_VERBOSE(fmt, args...) do { \ + if (g_wb_wdt_debug) { \ + printk(KERN_INFO "[WDT][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WDT_ERROR(fmt, args...) do { \ + if (g_wb_wdt_error) { \ + printk(KERN_ERR "[WDT][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +enum { + HW_ALGO_TOGGLE, + HW_ALGO_LEVEL, + HW_ALGO_EIGENVALUES, +}; + +enum { + WATCHDOG_DEVICE_TYPE = 0, + HRTIMER_TYPE, + THREAD_TYPE, +}; + +typedef struct wb_wdt_priv_s { + struct task_struct *thread; + struct hrtimer hrtimer; + ktime_t m_kt; + const char *config_dev_name; + uint8_t config_mode; + uint8_t hw_algo; + uint8_t enable_val; + uint8_t disable_val; + uint8_t enable_mask; + uint8_t priv_func_mode; + uint8_t feed_wdt_type; + uint32_t enable_reg; + uint32_t timeout_cfg_reg; + uint32_t timeleft_cfg_reg; + uint32_t hw_margin; + uint32_t feed_time; + uint8_t timer_accuracy_reg_flag; + uint32_t timer_accuracy_reg; + uint8_t timer_accuracy_reg_val; + uint32_t timer_accuracy; + uint8_t timer_update_reg_flag; + uint32_t timer_update_reg; + uint8_t timer_update_reg_val; + gpio_wdt_info_t gpio_wdt; + logic_wdt_info_t logic_wdt; + struct device *dev; + const struct attribute_group *sysfs_group; + uint8_t sysfs_index; + struct mutex update_lock; + struct watchdog_device wdd; +}wb_wdt_priv_t; + +static int wdt_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + filp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(filp)) { + WDT_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + ret = kernel_read(filp, val, size, &tmp_pos); + if (ret < 0) { + WDT_ERROR("kernel_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int wdt_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + filp = filp_open(path, O_RDWR, 777); + if (IS_ERR(filp)) { + WDT_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + ret = kernel_write(filp, val, size, &tmp_pos); + if (ret < 0) { + WDT_ERROR("kernel_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + vfs_fsync(filp, 1); + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int wb_wdt_read(uint8_t mode, const char *path, + uint32_t offset, uint8_t *buf, size_t count) +{ + int ret; + + switch (mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_read(path, offset, buf, count); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_read(path, offset, buf, count); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_read(path, offset, buf, count); + break; + case FILE_MODE: + ret = wdt_file_read(path, offset, buf, count); + break; + default: + WDT_ERROR("mode %u error, wdt func read failed.\n", mode); + return -EINVAL; + } + + WDT_VERBOSE("wdt func read mode:%u,dev_nam:%s, offset:0x%x, read_val:0x%x, size:%lu.\n", + mode, path, offset, *buf, count); + + return ret; +} + +static int wb_wdt_write(uint8_t mode, const char *path, + uint32_t offset, uint8_t *buf, size_t count) +{ + int ret; + + switch (mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_write(path, offset, buf, count); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_write(path, offset, buf, count); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_write(path, offset, buf, count); + break; + case FILE_MODE: + ret = wdt_file_write(path, offset, buf, count); + break; + default: + WDT_ERROR("mode %u error, wdt func write failed.\n", mode); + return -EINVAL; + } + + WDT_VERBOSE("wdt func write mode:%u, dev_nam:%s, offset:0x%x, write_val:0x%x, size:%lu.\n", + mode, path, offset, *buf, count); + + return ret; +} + +static int wb_wdt_enable_ctrl(wb_wdt_priv_t *priv, uint8_t flag) +{ + int ret; + uint8_t val; + uint8_t ctrl_val; + + switch (flag) { + case WDT_ON: + ctrl_val = priv->enable_val; + break; + case WDT_OFF: + ctrl_val = priv->disable_val; + break; + default: + WDT_ERROR("unsupport wdt enable ctrl:%u.\n", flag); + return -EINVAL; + } + + ret = wb_wdt_read(priv->priv_func_mode, priv->config_dev_name, + priv->enable_reg, &val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "read wdt control reg error.\n"); + return ret; + } + + val &= ~priv->enable_mask; + + val |= ctrl_val & priv->enable_mask; + + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->enable_reg, &val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "write wdt control reg error.\n"); + return ret; + } + + return 0; +} + +static void wdt_hwping(wb_wdt_priv_t *priv) +{ + gpio_wdt_info_t *gpio_wdt; + logic_wdt_info_t *logic_wdt; + uint8_t tmp_val; + int ret; + + if (priv->config_mode == GPIO_FEED_WDT_MODE) { + gpio_wdt = &priv->gpio_wdt; + switch (priv->hw_algo) { + case HW_ALGO_TOGGLE: + gpio_wdt = &priv->gpio_wdt; + gpio_wdt->state = !gpio_wdt->state; + gpio_set_value_cansleep(gpio_wdt->gpio, gpio_wdt->state); + WDT_VERBOSE("gpio toggle wdt work. val:%u\n", gpio_wdt->state); + break; + case HW_ALGO_LEVEL: + gpio_wdt = &priv->gpio_wdt; + /* Pulse */ + gpio_set_value_cansleep(gpio_wdt->gpio, !gpio_wdt->active_low); + udelay(1); + gpio_set_value_cansleep(gpio_wdt->gpio, gpio_wdt->active_low); + WDT_VERBOSE("gpio level wdt work.\n"); + break; + } + } else { + logic_wdt = &priv->logic_wdt; + switch (priv->hw_algo) { + case HW_ALGO_TOGGLE: + logic_wdt->active_val = !logic_wdt->active_val; + ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, + logic_wdt->feed_reg, &logic_wdt->active_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("logic toggle wdt write failed.ret = %d\n", ret); + } + WDT_VERBOSE("logic toggle wdt work.\n"); + break; + case HW_ALGO_LEVEL: + tmp_val = !logic_wdt->active_val; + ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, + logic_wdt->feed_reg, &tmp_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("logic level wdt write first failed.ret = %d\n", ret); + } + udelay(1); + ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, + logic_wdt->feed_reg, &logic_wdt->active_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("logic level wdt write second failed.ret = %d\n", ret); + } + WDT_VERBOSE("logic level wdt work.\n"); + break; + case HW_ALGO_EIGENVALUES: + ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, + logic_wdt->feed_reg, &logic_wdt->active_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("logic eigenvalues wdt write failed, path: %s, mode: %d, reg: 0x%x, val: 0x%x, ret: %d\n", + logic_wdt->feed_dev_name, logic_wdt->logic_func_mode, logic_wdt->feed_reg, + logic_wdt->active_val, ret); + } + WDT_VERBOSE("logic eigenvalues wdt work, path: %s, mode: %d, reg: 0x%x, val: 0x%x\n", + logic_wdt->feed_dev_name, logic_wdt->logic_func_mode, logic_wdt->feed_reg, logic_wdt->active_val); + break; + } + } + return; +} + +static enum hrtimer_restart hrtimer_hwping(struct hrtimer *timer) +{ + wb_wdt_priv_t *priv = container_of(timer, wb_wdt_priv_t, hrtimer); + + wdt_hwping(priv); + hrtimer_forward(timer, timer->base->get_time(), priv->m_kt); + return HRTIMER_RESTART; +} + +static int thread_timer_cfg(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) +{ + struct device *dev; + uint32_t hw_margin; + uint32_t feed_time; + uint32_t accuracy; + uint8_t set_time_val; + int ret; + + dev = priv->dev; + + ret = 0; + if (dev->of_node) { + ret += of_property_read_u32(dev->of_node, "feed_time", &priv->feed_time); + if (ret != 0) { + dev_err(dev, "thread Failed to priv dts.\n"); + return -ENXIO; + } + } else { + priv->feed_time = wb_wdt_device->feed_time; + } + WDT_VERBOSE("thread priv->feed_time: %u.\n", priv->feed_time); + + hw_margin = priv->hw_margin; + feed_time = priv->feed_time; + accuracy = priv->timer_accuracy; + + if ((feed_time > (hw_margin / 2)) || (feed_time == 0)) { + dev_err(dev, "thread timer feed_time[%d] should be less than half hw_margin or zero.\n", feed_time); + return -EINVAL; + } + + if (priv->timer_accuracy_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); + return ret; + } + } + + set_time_val = hw_margin / accuracy; + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); + if (ret < 0) { + dev_err(dev, "set wdt thread timer reg error.\n"); + return ret; + } + + if (priv->timer_update_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_update_reg, priv->timer_update_reg_val, ret); + return ret; + } + } + + return 0; +} + +static int wdt_thread_timer(void *data) +{ + wb_wdt_priv_t *priv = data; + + while (!kthread_should_stop()) { + schedule_timeout_uninterruptible(msecs_to_jiffies(priv->feed_time)); + wdt_hwping(priv); + } + return 0; +} + +static int thread_timer_create(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) +{ + struct task_struct *p; + int ret; + + ret = thread_timer_cfg(priv, wb_wdt_device); + if (ret < 0) { + dev_err(priv->dev, "set wdt thread timer failed.\n"); + return ret; + } + + p = kthread_create(wdt_thread_timer, (void *)priv, "%s", "wb_wdt"); + if (!IS_ERR(p)) { + WDT_VERBOSE("timer thread create success.\n"); + priv->thread = p; + wake_up_process(p); + } else { + dev_err(priv->dev, "timer thread create failed.\n"); + return -ENXIO; + } + + ret = wb_wdt_enable_ctrl(priv, WDT_ON); + if (ret < 0) { + dev_err(priv->dev, "thread enable wdt failed.\n"); + return -ENXIO; + } + + return 0; +} + +static int hrtimer_cfg(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) +{ + struct device *dev; + struct hrtimer *hrtimer; + uint8_t set_time_val; + uint8_t hrtimer_s; + uint32_t hrtimer_ns; + int ret; + uint32_t hw_margin; + uint32_t feed_time; + uint32_t accuracy; + uint32_t max_timeout; + + dev = priv->dev; + + ret = 0; + if (dev->of_node) { + ret += of_property_read_u32(dev->of_node, "feed_time", &priv->feed_time); + if (ret != 0) { + dev_err(dev, "hrtimer Failed to priv dts.\n"); + return -ENXIO; + } + } else { + priv->feed_time = wb_wdt_device->feed_time; + } + WDT_VERBOSE("hrtimer priv->feed_time: %u.\n", priv->feed_time); + + hrtimer = &priv->hrtimer; + hw_margin = priv->hw_margin; + feed_time = priv->feed_time; + accuracy = priv->timer_accuracy; + max_timeout = accuracy * 255; + + if (hw_margin < accuracy || hw_margin > max_timeout) { + dev_err(dev, "hrtimer_hw_margin should be between %u and %u.\n", + accuracy, max_timeout); + return -EINVAL; + } + if ((feed_time > (hw_margin / 2)) || (feed_time == 0)) { + dev_err(dev, "feed_time[%d] should be less than half hw_margin or zeor.\n", feed_time); + return -EINVAL; + } + + hrtimer_s = feed_time / MS_TO_S; + hrtimer_ns = (feed_time % MS_TO_S) * MS_TO_NS; + set_time_val = hw_margin / accuracy; + + if (priv->timer_accuracy_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); + return ret; + } + } + + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); + if (ret < 0) { + dev_err(dev, "set wdt time reg error.\n"); + return ret; + } + + if (priv->timer_update_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_update_reg, priv->timer_update_reg_val, ret); + return ret; + } + } + + priv->m_kt = ktime_set(hrtimer_s, hrtimer_ns); + hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hrtimer->function = hrtimer_hwping; + hrtimer_start(hrtimer, priv->m_kt, HRTIMER_MODE_REL); + + ret = wb_wdt_enable_ctrl(priv, WDT_ON); + if (ret < 0) { + dev_err(dev, "hrtimer enable wdt failed.\n"); + return -ENXIO; + } + + return 0; +} + +static int wb_wdt_ping(struct watchdog_device *wdd) +{ + wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); + + wdt_hwping(priv); + return 0; +} + +static int wb_wdt_start(struct watchdog_device *wdd) +{ + wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); + int ret; + + ret = wb_wdt_enable_ctrl(priv, WDT_ON); + if (ret < 0) { + WDT_ERROR("start wdt enable failed.\n"); + return -ENXIO; + } + set_bit(WDOG_HW_RUNNING, &wdd->status); + return 0; +} + +static int wb_wdt_stop(struct watchdog_device *wdd) +{ + wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); + int ret; + + ret = wb_wdt_enable_ctrl(priv, WDT_OFF); + if (ret < 0) { + WDT_ERROR("stop wdt enable failed.\n"); + return -ENXIO; + } + clear_bit(WDOG_HW_RUNNING, &wdd->status); + return 0; +} + +static int wb_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) +{ + wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); + uint32_t timeout_ms; + uint32_t accuracy; + uint8_t set_time_val; + int ret; + + accuracy = priv->timer_accuracy; + timeout_ms = t * 1000; + if (timeout_ms > accuracy * 255) { + WDT_ERROR("set wdt timeout too larger error.timeout_ms:%u\n", timeout_ms); + return -EINVAL; + } + + if (priv->timer_accuracy_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); + return ret; + } + } + + set_time_val = timeout_ms / accuracy; + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("set wdt timeout reg error, set_time_val:%u ret:%d\n", set_time_val, ret); + return ret; + } + + if (priv->timer_update_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_update_reg, priv->timer_update_reg_val, ret); + return ret; + } + } + + wdd->timeout = t; + + return 0; +} + +static unsigned int wb_wdt_get_timeleft(struct watchdog_device *wdd) +{ + wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); + unsigned int time_left; + uint32_t accuracy; + uint8_t get_time_val; + int ret; + + accuracy = priv->timer_accuracy; + + ret = wb_wdt_read(priv->priv_func_mode, priv->config_dev_name, + priv->timeleft_cfg_reg, &get_time_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("get wdt timeout reg error.ret:%d\n", ret); + return ret; + } + time_left = get_time_val * accuracy / MS_TO_S; + + WDT_VERBOSE("get wdt timeleft %d get_time_val %d accuracy=%d\n", + time_left, get_time_val, accuracy); + return time_left; +} + +static const struct watchdog_info wb_wdt_ident = { + .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, + .firmware_version = 0, + .identity = "CPLD Watchdog", +}; + +static const struct watchdog_ops wb_wdt_ops = { + .owner = THIS_MODULE, + .start = wb_wdt_start, + .stop = wb_wdt_stop, + .ping = wb_wdt_ping, + .set_timeout = wb_wdt_set_timeout, + .get_timeleft = wb_wdt_get_timeleft, +}; + +static int watchdog_device_cfg(wb_wdt_priv_t *priv) +{ + int ret; + uint8_t set_time_val; + + ret = wb_wdt_enable_ctrl(priv, WDT_OFF); + if (ret < 0) { + dev_err(priv->dev, "probe disable wdt failed.\n"); + return -ENXIO; + } + + if (priv->timer_accuracy_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); + return ret; + } + } + + set_time_val = priv->hw_margin / priv->timer_accuracy; + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "set wdt time reg error.\n"); + return ret; + } + + if (priv->timer_update_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_update_reg, priv->timer_update_reg_val, ret); + return ret; + } + } + + watchdog_set_drvdata(&priv->wdd, priv); + + priv->wdd.info = &wb_wdt_ident; + priv->wdd.ops = &wb_wdt_ops; + priv->wdd.bootstatus = 0; + priv->wdd.timeout = priv->hw_margin / MS_TO_S; + priv->wdd.min_timeout = priv->timer_accuracy / MS_TO_S; + priv->wdd.max_timeout = priv->timer_accuracy * MAX_REG_VAL / MS_TO_S; + priv->wdd.parent = priv->dev; + + watchdog_stop_on_reboot(&priv->wdd); + + ret = devm_watchdog_register_device(priv->dev, &priv->wdd); + if (ret != 0) { + dev_err(priv->dev, "cannot register watchdog device (err=%d)\n", ret); + return -ENXIO; + } + + return 0; +} + +static int logic_wdt_init(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) +{ + struct device *dev; + logic_wdt_info_t *logic_wdt; + int ret; + + dev = priv->dev; + logic_wdt = &priv->logic_wdt; + + ret = 0; + if (dev->of_node) { + ret += of_property_read_string(dev->of_node, "feed_dev_name", &logic_wdt->feed_dev_name); + ret += of_property_read_u32(dev->of_node, "feed_reg", &logic_wdt->feed_reg); + ret += of_property_read_u8(dev->of_node, "active_val", &logic_wdt->active_val); + ret += of_property_read_u8(dev->of_node, "logic_func_mode", &logic_wdt->logic_func_mode); + if (ret != 0) { + dev_err(dev, "Failed to logic_wdt dts.\n"); + return -ENXIO; + } + } else { + logic_wdt->feed_dev_name = wb_wdt_device->wdt_config_mode.logic_wdt.feed_dev_name; + logic_wdt->feed_reg = wb_wdt_device->wdt_config_mode.logic_wdt.feed_reg; + logic_wdt->active_val = wb_wdt_device->wdt_config_mode.logic_wdt.active_val; + logic_wdt->logic_func_mode = wb_wdt_device->wdt_config_mode.logic_wdt.logic_func_mode; + } + + logic_wdt->state_val = logic_wdt->active_val; + + WDT_VERBOSE("feed_dev_name:%s, feed_reg:0x%x, active_val:%u, logic_func_mode:%u\n", + logic_wdt->feed_dev_name, logic_wdt->feed_reg, + logic_wdt->active_val, logic_wdt->logic_func_mode); + + return 0; +} + +static int gpio_wdt_init(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) +{ + struct device *dev; + gpio_wdt_info_t *gpio_wdt; + enum of_gpio_flags flags; + uint32_t f = 0; + int ret; + + dev = priv->dev; + gpio_wdt = &priv->gpio_wdt; + + if (dev->of_node) { + gpio_wdt->gpio = of_get_gpio_flags(dev->of_node, 0, &flags); + } else { + gpio_wdt->gpio = wb_wdt_device->wdt_config_mode.gpio_wdt.gpio; + flags = wb_wdt_device->wdt_config_mode.gpio_wdt.flags; + } + if (!gpio_is_valid(gpio_wdt->gpio)) { + dev_err(dev, "gpio is invalid.\n"); + return gpio_wdt->gpio; + } + + gpio_wdt->active_low = flags & OF_GPIO_ACTIVE_LOW; + + if(priv->hw_algo == HW_ALGO_TOGGLE) { + f = GPIOF_IN; + } else { + f = gpio_wdt->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + } + + ret = devm_gpio_request_one(dev, gpio_wdt->gpio, f, + dev_name(dev)); + if (ret) { + dev_err(dev, "devm_gpio_request_one failed.\n"); + return ret; + } + + gpio_wdt->state = gpio_wdt->active_low; + gpio_direction_output(gpio_wdt->gpio, gpio_wdt->state); + + WDT_VERBOSE("active_low:%d\n", gpio_wdt->active_low); + return 0; +} + +static ssize_t set_wdt_sysfs_value(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + wb_wdt_priv_t *priv = dev_get_drvdata(dev); + int ret, val; + + val = 0; + sscanf(buf, "%d", &val); + WDT_VERBOSE("set wdt, val:%d.\n", val); + + if (val < 0 || val > 255) { + WDT_ERROR("set wdt val %d failed.\n", val); + return -EINVAL; + } + + mutex_lock(&priv->update_lock); + + ret = wb_wdt_enable_ctrl(priv, val); + if (ret < 0) { + WDT_ERROR("set wdt sysfs value:%u failed.\n", val); + goto fail; + } + + WDT_VERBOSE("set wdt sysfs value:%u successed.\n", val); + mutex_unlock(&priv->update_lock); + return count; + +fail: + mutex_unlock(&priv->update_lock); + return ret; +} + +static ssize_t show_wdt_sysfs_value(struct device *dev, + struct device_attribute *da, char *buf) +{ + wb_wdt_priv_t *priv = dev_get_drvdata(dev); + uint8_t val, status; + int ret; + + mutex_lock(&priv->update_lock); + + ret = wb_wdt_read(priv->priv_func_mode, priv->config_dev_name, + priv->enable_reg, &val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "read wdt enable reg val error.\n"); + goto fail; + } + + val &= priv->enable_mask; + if (val == priv->enable_val) { + status = WDT_ON; + } else if(val == priv->disable_val) { + status = WDT_OFF; + } else { + WDT_ERROR("enable reg read val not match set val, read val:%u, mask:%u, enable_val:%u, disable_val:%u", + val, priv->enable_mask, priv->enable_val, priv->disable_val); + ret = -EIO; + goto fail; + } + + WDT_VERBOSE("read_val:%u, mask:%u, enable_val:%u, disable_val:%u, status:%u", + val, priv->enable_mask, priv->enable_val, priv->disable_val, status); + + mutex_unlock(&priv->update_lock); + return sprintf(buf, "%u\n", status); + +fail: + mutex_unlock(&priv->update_lock); + return ret; +} + +static SENSOR_DEVICE_ATTR(wdt_status, S_IRUGO | S_IWUSR, show_wdt_sysfs_value, set_wdt_sysfs_value, 0); + +static struct attribute *wdt_sysfs_attrs[] = { + &sensor_dev_attr_wdt_status.dev_attr.attr, + NULL +}; + +static const struct attribute_group wdt_sysfs_group = { + .attrs = wdt_sysfs_attrs, +}; + +struct wdt_attr_match_group { + uint8_t index; + const struct attribute_group *attr_group_ptr; +}; + +static struct wdt_attr_match_group g_wdt_attr_match[] = { + {0, &wdt_sysfs_group}, +}; + +static const struct attribute_group *wdt_get_attr_group(uint32_t index) +{ + int i; + struct wdt_attr_match_group *group; + + for (i = 0; i < ARRAY_SIZE(g_wdt_attr_match); i++) { + group = &g_wdt_attr_match[i]; + if (index == group->index) { + WDT_VERBOSE("get wdt attr, index:%u.\n", index); + return group->attr_group_ptr; + } + } + + return NULL; +} + +static int wb_wdt_probe(struct platform_device *pdev) +{ + wb_wdt_priv_t *priv; + int ret; + const char *algo; + wb_wdt_device_t *wb_wdt_device; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "devm_kzalloc failed.\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, priv); + + if (pdev->dev.of_node) { + ret = 0; + ret += of_property_read_string(pdev->dev.of_node, "config_dev_name", &priv->config_dev_name); + ret += of_property_read_string(pdev->dev.of_node, "hw_algo", &algo); + ret += of_property_read_u8(pdev->dev.of_node, "config_mode", &priv->config_mode); + ret += of_property_read_u8(pdev->dev.of_node, "priv_func_mode", &priv->priv_func_mode); + ret += of_property_read_u8(pdev->dev.of_node, "enable_val", &priv->enable_val); + ret += of_property_read_u8(pdev->dev.of_node, "disable_val", &priv->disable_val); + ret += of_property_read_u8(pdev->dev.of_node, "enable_mask", &priv->enable_mask); + ret += of_property_read_u32(pdev->dev.of_node, "enable_reg", &priv->enable_reg); + ret += of_property_read_u32(pdev->dev.of_node, "timeout_cfg_reg", &priv->timeout_cfg_reg); + ret += of_property_read_u32(pdev->dev.of_node,"hw_margin_ms", &priv->hw_margin); + ret += of_property_read_u8(pdev->dev.of_node,"feed_wdt_type", &priv->feed_wdt_type); + ret += of_property_read_u32(pdev->dev.of_node,"timer_accuracy", &priv->timer_accuracy); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to priv dts.\n"); + return -ENXIO; + } + + priv->sysfs_index = SYSFS_NO_CFG; + of_property_read_u8(pdev->dev.of_node,"sysfs_index", &priv->sysfs_index); + + priv->timeleft_cfg_reg = priv->timeout_cfg_reg; + of_property_read_u32(pdev->dev.of_node,"timeleft_cfg_reg", &priv->timeleft_cfg_reg); + + /* timer accuracy register is optional */ + ret = of_property_read_u8(pdev->dev.of_node,"timer_accuracy_reg_flag", &priv->timer_accuracy_reg_flag); + if (ret < 0) { + /* case: don't has timer_accuracy_reg */ + dev_dbg(&pdev->dev, "Failed to get property in dts: timer_accuracy_reg_flag.\n"); + priv->timer_accuracy_reg_flag = 0; + } else { + ret = of_property_read_u32(pdev->dev.of_node, "timer_accuracy_reg", &priv->timer_accuracy_reg); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get timer accuracy register address.\n"); + return -ENXIO; + } + ret = of_property_read_u8(pdev->dev.of_node, "timer_accuracy_reg_val", &priv->timer_accuracy_reg_val); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get timer accuracy register value.\n"); + return -ENXIO; + } + } + + /* timer update register is optional */ + ret = of_property_read_u8(pdev->dev.of_node,"timer_update_reg_flag", &priv->timer_update_reg_flag); + if (ret < 0) { + /* case: don't has timer_update_reg */ + dev_dbg(&pdev->dev, "Failed to get property in dts: timer_update_reg_flag.\n"); + priv->timer_update_reg_flag = 0; /* no timer update register */ + } else { + ret = of_property_read_u32(pdev->dev.of_node, "timer_update_reg", &priv->timer_update_reg); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get timer update register address.\n"); + return -ENXIO; + } + ret = of_property_read_u8(pdev->dev.of_node, "timer_update_reg_val", &priv->timer_update_reg_val); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get timer update register value.\n"); + return -ENXIO; + } + } + } else { + if (pdev->dev.platform_data == NULL) { + dev_err(&pdev->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + wb_wdt_device = pdev->dev.platform_data; + priv->config_dev_name = wb_wdt_device->config_dev_name; + algo = wb_wdt_device->hw_algo; + priv->config_mode = wb_wdt_device->config_mode; + priv->priv_func_mode = wb_wdt_device->priv_func_mode; + priv->enable_val = wb_wdt_device->enable_val; + priv->disable_val = wb_wdt_device->disable_val; + priv->enable_mask = wb_wdt_device->enable_mask; + priv->enable_reg = wb_wdt_device->enable_reg; + priv->timeout_cfg_reg = wb_wdt_device->timeout_cfg_reg; + priv->hw_margin = wb_wdt_device->hw_margin; + priv->timer_accuracy = wb_wdt_device->timer_accuracy; + priv->feed_wdt_type = wb_wdt_device->feed_wdt_type; + priv->sysfs_index = wb_wdt_device->sysfs_index; + priv->timeleft_cfg_reg = wb_wdt_device->timeleft_cfg_reg; + priv->timer_accuracy_reg_flag = wb_wdt_device->timer_accuracy_reg_flag; + priv->timer_accuracy_reg = wb_wdt_device->timer_accuracy_reg; + priv->timer_accuracy_reg_val = wb_wdt_device->timer_accuracy_reg_val; + priv->timer_update_reg_flag = wb_wdt_device->timer_update_reg_flag; + priv->timer_update_reg = wb_wdt_device->timer_update_reg; + priv->timer_update_reg_val = wb_wdt_device->timer_update_reg_val; + } + + if (!strcmp(algo, "toggle")) { + priv->hw_algo = HW_ALGO_TOGGLE; + } else if (!strcmp(algo, "level")) { + priv->hw_algo = HW_ALGO_LEVEL; + } else if (!strcmp(algo, "eigenvalues")) { + priv->hw_algo = HW_ALGO_EIGENVALUES; + } else { + dev_err(&pdev->dev, "hw_algo config error.must be toggle or level.\n"); + return -EINVAL; + } + + WDT_VERBOSE("config_dev_name:%s, config_mode:%u, priv_func_mode:%u, enable_reg:0x%x, timeout_cfg_reg:0x%x\n", + priv->config_dev_name, priv->config_mode, priv->priv_func_mode, priv->enable_reg, priv->timeout_cfg_reg); + WDT_VERBOSE("timeout_cfg_reg:0x%x, enable_val:0x%x, disable_val:0x%x, enable_mask:0x%x, hw_margin:%u, feed_wdt_type:%u\n", + priv->timeleft_cfg_reg, priv->enable_val, priv->disable_val, priv->enable_mask, priv->hw_margin, priv->feed_wdt_type); + WDT_VERBOSE("timer_accuracy_reg_flag: %d, timer_accuracy_reg: 0x%x, timer_accuracy_reg_val: 0x%x, timer_accuracy: %d\n", + priv->timer_accuracy_reg_flag, priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, priv->timer_accuracy); + WDT_VERBOSE("timer_update_reg_flag: %d, timer_update_reg: 0x%x, timer_update_reg_val: 0x%x\n", priv->timer_update_reg_flag, + priv->timer_update_reg, priv->timer_update_reg_val); + + priv->dev = &pdev->dev; + if (priv->config_mode == GPIO_FEED_WDT_MODE) { + ret = gpio_wdt_init(priv, wb_wdt_device); + if (ret < 0) { + dev_err(&pdev->dev, "init gpio mode wdt failed.\n"); + return -ENXIO; + } + } else if (priv->config_mode == LOGIC_FEED_WDT_MODE) { + ret = logic_wdt_init(priv, wb_wdt_device); + if (ret < 0) { + dev_err(&pdev->dev, "init func mode wdt failed.\n"); + return -ENXIO; + } + } else { + dev_err(&pdev->dev, "unsupport %u config_mode, dts configure error.\n", + priv->config_mode); + return -ENXIO; + } + + switch (priv->feed_wdt_type) { + case WATCHDOG_DEVICE_TYPE: + ret = watchdog_device_cfg(priv); + break; + case HRTIMER_TYPE: + ret = hrtimer_cfg(priv, wb_wdt_device); + break; + case THREAD_TYPE: + ret = thread_timer_create(priv, wb_wdt_device); + break; + default: + dev_err(&pdev->dev, "timer type %u unsupport.\n", priv->feed_wdt_type); + return -EINVAL; + } + if (ret < 0) { + dev_err(&pdev->dev, "init timer feed_wdt_type %u failed.\n", priv->feed_wdt_type); + return -ENXIO; + } + + dev_info(&pdev->dev, "register %s mode, config_mode %u, func_mode %u, %u ms overtime wdt success\n", + algo, priv->config_mode, priv->priv_func_mode, priv->hw_margin); + + if (priv->sysfs_index != SYSFS_NO_CFG) { + + priv->sysfs_group = wdt_get_attr_group(priv->sysfs_index); + if (priv->sysfs_group) { + ret = sysfs_create_group(&pdev->dev.kobj, priv->sysfs_group); + if (ret != 0) { + dev_err(&pdev->dev, "sysfs_create_group failed. ret:%d.\n", ret); + return -ENOMEM; + } + dev_info(&pdev->dev, "sysfs create group success\n"); + } else { + dev_err(&pdev->dev, "failed to find %u index wdt, return NULL.\n", priv->sysfs_index); + return -ENOMEM; + } + + mutex_init(&priv->update_lock); + + dev_info(&pdev->dev, "register %u index wdt sysfs success." ,priv->sysfs_index); + } + + return 0; +} + +static void unregister_action(struct platform_device *pdev) +{ + wb_wdt_priv_t *priv = platform_get_drvdata(pdev); + gpio_wdt_info_t *gpio_wdt; + logic_wdt_info_t *logic_wdt; + int ret; + + ret = wb_wdt_enable_ctrl(priv, WDT_OFF); + if (ret < 0) { + dev_err(&pdev->dev, "remove disable wdt failed.\n"); + } + + if (priv->sysfs_index != SYSFS_NO_CFG) { + sysfs_remove_group(&pdev->dev.kobj, priv->sysfs_group); + } + + if (priv->feed_wdt_type == HRTIMER_TYPE) { + hrtimer_cancel(&priv->hrtimer); + } else if (priv->feed_wdt_type == THREAD_TYPE) { + kthread_stop(priv->thread); + priv->thread = NULL; + } else { + WDT_VERBOSE("wdd type, do nothing.\n"); + } + + if (priv->config_mode == GPIO_FEED_WDT_MODE) { + gpio_wdt = &priv->gpio_wdt; + gpio_set_value_cansleep(gpio_wdt->gpio, !gpio_wdt->active_low); + + if (priv->hw_algo == HW_ALGO_TOGGLE) { + gpio_direction_input(gpio_wdt->gpio); + } + } else { + logic_wdt = &priv->logic_wdt; + logic_wdt->state_val = !logic_wdt->state_val; + ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, + logic_wdt->feed_reg, &logic_wdt->state_val, ONE_BYTE); + if (ret < 0) { + dev_err(&pdev->dev, "set wdt control reg error.\n"); + } + } + + return; +} + +static int wb_wdt_remove(struct platform_device *pdev) +{ + WDT_VERBOSE("enter remove wdt.\n"); + unregister_action(pdev); + dev_info(&pdev->dev, "remove wdt finish.\n"); + + return 0; +} + +static void wb_wdt_shutdown(struct platform_device *pdev) +{ + WDT_VERBOSE("enter shutdown wdt.\n"); + unregister_action(pdev); + dev_info(&pdev->dev, "shutdown wdt finish.\n"); + + return; +} + +static const struct of_device_id wb_wdt_dt_ids[] = { + { .compatible = "wb_wdt", }, + { } +}; +MODULE_DEVICE_TABLE(of, wb_wdt_dt_ids); + +static struct platform_driver wb_wdt_driver = { + .driver = { + .name = "wb_wdt", + .of_match_table = wb_wdt_dt_ids, + }, + .probe = wb_wdt_probe, + .remove = wb_wdt_remove, + .shutdown = wb_wdt_shutdown, +}; + +#ifdef CONFIG_GPIO_WATCHDOG_ARCH_INITCALL +static int __init wb_wdt_init(void) +{ + return platform_driver_register(&wb_wdt_driver); +} +arch_initcall(wb_wdt_init); +#else +module_platform_driver(wb_wdt_driver); +#endif + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("watchdog driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.h new file mode 100644 index 000000000000..d45904ba32ea --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.h @@ -0,0 +1,53 @@ +#ifndef __WB_WDT_H__ +#define __WB_WDT_H__ + +#include + +#define SYSFS_NO_CFG (0xff) +#define INVALID_REG_ADDR (0xffffffff) + +typedef struct gpio_wdt_info_s { + int gpio; + enum of_gpio_flags flags; + bool active_low; + bool state; +}gpio_wdt_info_t; + +typedef struct logic_wdt_info_s { + const char *feed_dev_name; + uint8_t logic_func_mode; + uint32_t feed_reg; + uint8_t active_val; + uint8_t state_val; +}logic_wdt_info_t; + +typedef struct wb_wdt_device_s { + int device_flag; + const char *config_dev_name; + uint8_t config_mode; + const char *hw_algo; + uint8_t enable_val; + uint8_t disable_val; + uint8_t enable_mask; + uint8_t priv_func_mode; + uint8_t feed_wdt_type; + uint32_t enable_reg; + uint32_t timeout_cfg_reg; + uint32_t timeleft_cfg_reg; + uint32_t hw_margin; + uint32_t feed_time; + uint8_t timer_accuracy_reg_flag; + uint32_t timer_accuracy_reg; + uint8_t timer_accuracy_reg_val; + uint32_t timer_accuracy; + uint8_t timer_update_reg_flag; + uint32_t timer_update_reg; + uint8_t timer_update_reg_val; + union { + gpio_wdt_info_t gpio_wdt; + logic_wdt_info_t logic_wdt; + } wdt_config_mode; + uint8_t sysfs_index; +} wb_wdt_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_xdpe132g5c.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_xdpe132g5c.c new file mode 100644 index 000000000000..edc12d34b6e2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_xdpe132g5c.c @@ -0,0 +1,574 @@ +/* + * xdpe132g5c_i2c_drv.c + * + * This module create sysfs to set AVS and create hwmon to get out power + * through xdpe132g5c I2C address. + * + * History + * [Version] [Date] [Description] + * * v1.0 2021-09-17 Initial version + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WB_I2C_RETRY_SLEEP_TIME (10000) /* 10ms */ +#define WB_I2C_RETRY_TIME (10) +#define WB_XDPE_I2C_PAGE_ADDR (0xff) +#define WB_XDPE_I2C_VOUT_MODE (0x40) +#define WB_XDPE_I2C_VOUT_COMMAND (0x42) +#define WB_XDPE_I2C_VOUT_PAGE (0x06) +#define WB_XDPE_VOUT_MAX_THRESHOLD ((0xFFFF * 1000L * 1000L) / (256)) +#define WB_XDPE_VOUT_MIN_THRESHOLD (0) + +static int g_wb_xdpe_debug = 0; +static int g_wb_xdpe_error = 0; + +module_param(g_wb_xdpe_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_xdpe_error, int, S_IRUGO | S_IWUSR); + +#define WB_XDPE_VERBOSE(fmt, args...) do { \ + if (g_wb_xdpe_debug) { \ + printk(KERN_INFO "[WB_XDPE][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_XDPE_ERROR(fmt, args...) do { \ + if (g_wb_xdpe_error) { \ + printk(KERN_ERR "[WB_XDPE][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +struct xdpe_data { + struct i2c_client *client; + struct device *hwmon_dev; + struct mutex update_lock; + long vout_max; + long vout_min; +}; + +typedef struct xdpe_vout_data_s { + u8 vout_mode; + int vout_precision; +} xdpe_vout_data_t; + +static xdpe_vout_data_t g_xdpe_vout_group[] = { + {.vout_mode = 0x18, .vout_precision = 256}, + {.vout_mode = 0x17, .vout_precision = 512}, + {.vout_mode = 0x16, .vout_precision = 1024}, + {.vout_mode = 0x15, .vout_precision = 2048}, + {.vout_mode = 0x14, .vout_precision = 4096}, +}; + +static s32 wb_i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command) +{ + int i; + s32 ret; + + for (i = 0; i < WB_I2C_RETRY_TIME; i++) { + ret = i2c_smbus_read_byte_data(client, command); + if (ret >= 0) { + return ret; + } + usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); + } + return ret; +} + +static s32 wb_i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command, u8 value) +{ + int i; + s32 ret; + + for (i = 0; i < WB_I2C_RETRY_TIME; i++) { + ret = i2c_smbus_write_byte_data(client, command, value); + if (ret >= 0) { + return ret; + } + usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); + } + return ret; +} + +static s32 wb_i2c_smbus_read_word_data(const struct i2c_client *client, u8 command) +{ + int i; + s32 ret; + + for (i = 0; i < WB_I2C_RETRY_TIME; i++) { + ret = i2c_smbus_read_word_data(client, command); + if (ret >= 0) { + return ret; + } + usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); + } + return ret; +} + +static s32 wb_i2c_smbus_write_word_data(const struct i2c_client *client, u8 command, + u16 value) +{ + int i; + s32 ret; + + for (i = 0; i < WB_I2C_RETRY_TIME; i++) { + ret = i2c_smbus_write_word_data(client, command, value); + if (ret >= 0) { + return ret; + } + usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); + } + return ret; +} + +static long calc_power_linear11_data(int data) +{ + s16 exponent; + s32 mantissa; + long val; + + exponent = ((s16)data) >> 11; + mantissa = ((s16)((data & 0x7ff) << 5)) >> 5; + val = mantissa; + val = val * 1000L * 1000L; + + if (exponent >= 0) { + val <<= exponent; + } else { + val >>= -exponent; + } + return val; +} + +static int read_xdpe_power_value(const struct i2c_client *client, u8 page, u8 reg, long *value) +{ + int ret, data; + + ret = wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, page); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: set xdpe page%u failed, ret: %d\n", client->adapter->nr, + client->addr, page, ret); + return ret; + } + data = wb_i2c_smbus_read_word_data(client, reg); + if (data < 0) { + WB_XDPE_ERROR("%d-%04x: read xdpe page%u reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, page, reg, data); + return data; + } + *value = calc_power_linear11_data(data); + WB_XDPE_VERBOSE("%d-%04x: page%u reg: 0x%x rd_data: 0x%x, decode linear11 value: %ld\n", + client->adapter->nr, client->addr, page, reg, data, *value); + return 0; +} + +static ssize_t xdpe_power_value_show(struct device *dev, struct device_attribute *da, + char *buf) +{ + int ret, ori_page; + u16 sensor_h, sensor_l; + u8 page, reg; + struct sensor_device_attribute *attr; + struct i2c_client *client; + struct xdpe_data *data; + long value1, value2; + + data = dev_get_drvdata(dev); + client = data->client; + attr = to_sensor_dev_attr(da); + sensor_h = ((attr->index) >> 16) & 0xffff; + sensor_l = (attr->index) & 0xffff; + + mutex_lock(&data->update_lock); + + ori_page = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_PAGE_ADDR); + if (ori_page < 0) { + WB_XDPE_ERROR("%d-%04x: read xdpe origin page failed, ret: %d\n", client->adapter->nr, + client->addr, ori_page); + mutex_unlock(&data->update_lock); + return ori_page; + } + value1 = 0; + value2 = 0; + + if (sensor_h) { + page = (sensor_h >> 8) & 0xff; + reg = sensor_h & 0xff; + ret = read_xdpe_power_value(client, page, reg, &value1); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: read xdpe sensor high sensor page%u reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, page, reg, ret); + goto error; + } + WB_XDPE_VERBOSE("%d-%04x: read xdpe sensor high sensor page%u reg: 0x%x success, value: %ld\n", + client->adapter->nr, client->addr, page, reg, value1); + } + + page = (sensor_l >> 8) & 0xff; + reg = sensor_l & 0xff; + ret = read_xdpe_power_value(client, page, reg, &value2); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: read xdpe sensor low sensor page%u reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, page, reg, ret); + goto error; + } + WB_XDPE_VERBOSE("%d-%04x: read xdpe sensor low sensor page%u reg: 0x%x success, value: %ld\n", + client->adapter->nr, client->addr, page, reg, value2); + + wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); + mutex_unlock(&data->update_lock); + return snprintf(buf, PAGE_SIZE, "%ld\n", value1 + value2); +error: + wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); + mutex_unlock(&data->update_lock); + return ret; +} + +static int xdpe_get_vout_precision(const struct i2c_client *client, int *vout_precision) +{ + int i, vout_mode, a_size; + + vout_mode = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_VOUT_MODE); + if (vout_mode < 0) { + WB_XDPE_ERROR("%d-%04x: read xdpe vout mode reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_MODE, vout_mode); + return vout_mode; + } + + a_size = ARRAY_SIZE(g_xdpe_vout_group); + for (i = 0; i < a_size; i++) { + if (g_xdpe_vout_group[i].vout_mode == vout_mode) { + *vout_precision = g_xdpe_vout_group[i].vout_precision; + WB_XDPE_VERBOSE("%d-%04x: match, vout mode: 0x%x, precision: %d\n", + client->adapter->nr, client->addr, vout_mode, *vout_precision); + break; + } + } + if (i == a_size) { + WB_XDPE_ERROR("%d-%04x: invalid vout mode: 0x%x\n",client->adapter->nr, client->addr, + vout_mode); + return -EINVAL; + } + return 0; +} + +static ssize_t xdpe_avs_vout_show(struct device *dev, struct device_attribute *da, char *buf) +{ + int ret, ori_page, vout_cmd, vout_precision; + struct i2c_client *client; + struct xdpe_data *data; + long vout; + + client = to_i2c_client(dev); + data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + ori_page = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_PAGE_ADDR); + if (ori_page < 0) { + WB_XDPE_ERROR("%d-%04x: read xdpe origin page failed, ret: %d\n", client->adapter->nr, + client->addr, ori_page); + mutex_unlock(&data->update_lock); + return ori_page; + } + + ret = wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, WB_XDPE_I2C_VOUT_PAGE); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: set xdpe avs vout page%u failed, ret: %d\n", client->adapter->nr, + client->addr, WB_XDPE_I2C_VOUT_PAGE, ret); + goto error; + } + + ret = xdpe_get_vout_precision(client, &vout_precision); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: get xdpe avs vout precision failed, ret: %d\n", + client->adapter->nr, client->addr, ret); + goto error; + } + + vout_cmd = wb_i2c_smbus_read_word_data(client, WB_XDPE_I2C_VOUT_COMMAND); + if (vout_cmd < 0) { + ret = vout_cmd; + WB_XDPE_ERROR("%d-%04x: read xdpe vout command reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_COMMAND, ret); + goto error; + } + + wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); + mutex_unlock(&data->update_lock); + + vout = vout_cmd * 1000L * 1000L / vout_precision; + WB_XDPE_VERBOSE("%d-%04x: vout: %ld, vout_cmd: 0x%x, precision: %d\n", client->adapter->nr, + client->addr, vout, vout_cmd, vout_precision); + return snprintf(buf, PAGE_SIZE, "%ld\n", vout); +error: + wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t xdpe_avs_vout_store(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int ret, ori_page, vout_cmd, vout_cmd_set, vout_precision; + struct i2c_client *client; + struct xdpe_data *data; + long vout, vout_max, vout_min; + + client = to_i2c_client(dev); + ret = kstrtol(buf, 10, &vout); + if (ret) { + WB_XDPE_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + data = i2c_get_clientdata(client); + vout_max = data->vout_max; + vout_min = data->vout_min; + if ((vout > vout_max) || (vout < vout_min)) { + WB_XDPE_ERROR("%d-%04x: vout value: %ld, out of range [%ld, %ld] \n", client->adapter->nr, + client->addr, vout, vout_min, vout_max); + return -EINVAL; + } + + mutex_lock(&data->update_lock); + + ori_page = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_PAGE_ADDR); + if (ori_page < 0) { + WB_XDPE_ERROR("%d-%04x: read xdpe origin page failed, ret: %d\n", client->adapter->nr, + client->addr, ori_page); + mutex_unlock(&data->update_lock); + return ori_page; + } + + ret = wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, WB_XDPE_I2C_VOUT_PAGE); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: set xdpe avs vout page%u failed, ret: %d\n", client->adapter->nr, + client->addr, WB_XDPE_I2C_VOUT_PAGE, ret); + goto error; + } + + ret = xdpe_get_vout_precision(client, &vout_precision); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: get xdpe avs vout precision failed, ret: %d\n", + client->adapter->nr, client->addr, ret); + goto error; + } + + vout_cmd_set = (vout * vout_precision) / (1000L * 1000L); + if (vout_cmd_set > 0xffff) { + WB_XDPE_ERROR("%d-%04x: invalid value, vout %ld, vout_precision: %d, vout_cmd_set: 0x%x\n", + client->adapter->nr, client->addr, vout, vout_precision, vout_cmd_set); + ret = -EINVAL; + goto error; + } + ret = wb_i2c_smbus_write_word_data(client, WB_XDPE_I2C_VOUT_COMMAND, vout_cmd_set); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: set xdpe vout cmd reg: 0x%x, value: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_COMMAND, vout_cmd_set, ret); + goto error; + } + + vout_cmd = wb_i2c_smbus_read_word_data(client, WB_XDPE_I2C_VOUT_COMMAND); + if (vout_cmd < 0) { + ret = vout_cmd; + WB_XDPE_ERROR("%d-%04x: read xdpe vout command reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_COMMAND, ret); + goto error; + } + if (vout_cmd != vout_cmd_set) { + ret = -EIO; + WB_XDPE_ERROR("%d-%04x: vout cmd value check error, vout cmd read: 0x%x, vout cmd set: 0x%x\n", + client->adapter->nr, client->addr, vout_cmd, vout_cmd_set); + goto error; + + } + + wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); + mutex_unlock(&data->update_lock); + WB_XDPE_VERBOSE("%d-%04x: set vout cmd success, vout %ld, vout_precision: %d, vout_cmd_set: 0x%x\n", + client->adapter->nr, client->addr, vout, vout_precision, vout_cmd_set); + return count; +error: + wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t xdpe_avs_vout_max_show(struct device *dev, struct device_attribute *da, char *buf) +{ + struct i2c_client *client; + struct xdpe_data *data; + long vout_max; + + client = to_i2c_client(dev); + data = i2c_get_clientdata(client); + vout_max = data->vout_max; + return snprintf(buf, PAGE_SIZE, "%ld\n", vout_max); +} + +static ssize_t xdpe_avs_vout_max_store(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int ret; + struct i2c_client *client; + struct xdpe_data *data; + long vout_max; + + client = to_i2c_client(dev); + ret = kstrtol(buf, 10, &vout_max); + if (ret) { + WB_XDPE_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + WB_XDPE_VERBOSE("%d-%04x: vout max threshold: %ld", client->adapter->nr, client->addr, + vout_max); + data = i2c_get_clientdata(client); + data->vout_max = vout_max; + return count; +} + +static ssize_t xdpe_avs_vout_min_show(struct device *dev, struct device_attribute *da, char *buf) +{ + struct i2c_client *client; + struct xdpe_data *data; + long vout_min; + + client = to_i2c_client(dev); + data = i2c_get_clientdata(client); + vout_min = data->vout_min; + return snprintf(buf, PAGE_SIZE, "%ld\n", vout_min); +} + +static ssize_t xdpe_avs_vout_min_store(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int ret; + struct i2c_client *client; + struct xdpe_data *data; + long vout_min; + + client = to_i2c_client(dev); + ret = kstrtol(buf, 10, &vout_min); + if (ret) { + WB_XDPE_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + WB_XDPE_VERBOSE("%d-%04x: vout min threshold: %ld", client->adapter->nr, client->addr, + vout_min); + data = i2c_get_clientdata(client); + data->vout_min = vout_min; + return count; +} + +/* xdpe hwmon */ +static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO ,xdpe_power_value_show, NULL, 0x072c); +static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO ,xdpe_power_value_show, NULL, 0x0b2c); +static SENSOR_DEVICE_ATTR(power3_input, S_IRUGO ,xdpe_power_value_show, NULL, 0x072c0b2c); + +static struct attribute *xdpe_hwmon_attrs[] = { + &sensor_dev_attr_power1_input.dev_attr.attr, + &sensor_dev_attr_power2_input.dev_attr.attr, + &sensor_dev_attr_power3_input.dev_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(xdpe_hwmon); + +/* xdpe sysfs */ +static SENSOR_DEVICE_ATTR(avs_vout, S_IRUGO | S_IWUSR, xdpe_avs_vout_show, xdpe_avs_vout_store, 0); +static SENSOR_DEVICE_ATTR(avs_vout_max, S_IRUGO | S_IWUSR, xdpe_avs_vout_max_show, xdpe_avs_vout_max_store, 0); +static SENSOR_DEVICE_ATTR(avs_vout_min, S_IRUGO | S_IWUSR, xdpe_avs_vout_min_show, xdpe_avs_vout_min_store, 0); + +static struct attribute *xdpe132g5c_sysfs_attrs[] = { + &sensor_dev_attr_avs_vout.dev_attr.attr, + &sensor_dev_attr_avs_vout_max.dev_attr.attr, + &sensor_dev_attr_avs_vout_min.dev_attr.attr, + NULL, +}; + +static const struct attribute_group xdpe132g5c_sysfs_attrs_group = { + .attrs = xdpe132g5c_sysfs_attrs, +}; + +static int xdpe132g5c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct xdpe_data *data; + int ret; + + WB_XDPE_VERBOSE("bus: %d, addr: 0x%02x do probe.\n", client->adapter->nr, client->addr); + data = devm_kzalloc(&client->dev, sizeof(struct xdpe_data), GFP_KERNEL); + if (!data) { + dev_err(&client->dev, "devm_kzalloc failed.\n"); + return -ENOMEM; + } + + data->client = client; + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + ret = sysfs_create_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); + if (ret != 0) { + dev_err(&client->dev, "Create xdpe132g5c sysfs failed, ret: %d\n", ret); + return ret; + } + data->hwmon_dev = hwmon_device_register_with_groups(&client->dev, client->name, data, + xdpe_hwmon_groups); + if (IS_ERR(data->hwmon_dev)) { + ret = PTR_ERR(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); + dev_err(&client->dev, "Failed to register xdpe hwmon device, ret: %d\n", ret); + return ret; + } + data->vout_max = WB_XDPE_VOUT_MAX_THRESHOLD; + data->vout_min = WB_XDPE_VOUT_MIN_THRESHOLD; + dev_info(&client->dev, "xdpe132g5c probe success\n"); + return 0; +} + +static int xdpe132g5c_remove(struct i2c_client *client) +{ + struct xdpe_data *data; + + WB_XDPE_VERBOSE("bus: %d, addr: 0x%02x do remove\n", client->adapter->nr, client->addr); + data = i2c_get_clientdata(client); + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); + return 0; +} + +static const struct i2c_device_id xdpe132g5c_id[] = { + {"wb_xdpe132g5c", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, xdpe132g5c_id); + +static const struct of_device_id __maybe_unused xdpe132g5c_of_match[] = { + {.compatible = "infineon,wb_xdpe132g5c"}, + {} +}; +MODULE_DEVICE_TABLE(of, xdpe132g5c_of_match); + +static struct i2c_driver wb_xdpe132g5c_driver = { + .driver = { + .name = "wb_xdpe132g5c", + .of_match_table = of_match_ptr(xdpe132g5c_of_match), + }, + .probe = xdpe132g5c_probe, + .remove = xdpe132g5c_remove, + .id_table = xdpe132g5c_id, +}; + +module_i2c_driver(wb_xdpe132g5c_driver); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("I2C driver for Infineon XDPE132 family"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/auto_update.py b/platform/broadcom/sonic-platform-modules-micas/common/script/auto_update.py new file mode 100755 index 000000000000..838e64f6b417 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/auto_update.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python3 + +try: + import os + import json + import logging + import sys + from sonic_py_common import device_info + from sonic_platform.platform import Platform +except ImportError as e: + raise ImportError(str(e) + "- required module not found") from e + +PLATFORM_COMPONENTS_FILE = "platform_components.json" +CHASSIS_KEY = "chassis" +COMPONENT_KEY = "component" +FIRMWARE_KEY = "firmware" +VERSION_KEY = "version" +chassis_component_map = {} +current_chassis_component_map = {} +current_chassis = Platform().get_chassis() + + +def parse_component_section(section, component): + if not isinstance(component, dict): + logging.error("dictionary is expected: key=%s", COMPONENT_KEY) + return False + + if not component: + return False + + missing_key = None + chassis_component_map[section] = {} + + for key1, value1 in component.items(): + if not isinstance(value1, dict): + logging.error("dictionary is expected: key=%s", key1) + return False + + if value1: + if len(value1) < 1 or len(value1) > 3: + logging.error("unexpected number of records: key=%s", key1) + return False + + if FIRMWARE_KEY not in value1: + missing_key = FIRMWARE_KEY + break + + for key2, value2 in value1.items(): + if not isinstance(value2, str): + logging.error("string is expected: key=%s", key2) + return False + + chassis_component_map[section][key1] = value1 + + if missing_key is not None: + logging.error("\"%s\" key hasn't been found", missing_key) + return False + + return True + + +def parse_chassis_section(chassis): + if not isinstance(chassis, dict): + logging.error("dictionary is expected: key=%s", CHASSIS_KEY) + return False + + if not chassis: + logging.error("dictionary is empty: key=%s", CHASSIS_KEY) + return False + + if len(chassis) != 1: + logging.error("unexpected number of records: key=%s", CHASSIS_KEY) + return False + + for key, value in chassis.items(): + if not isinstance(value, dict): + logging.error("dictionary is expected: key=%s", key) + return False + + if not value: + logging.error("dictionary is empty: key=%s", key) + return False + + if COMPONENT_KEY not in value: + logging.error("\"%s\" key hasn't been found", COMPONENT_KEY) + return False + + if len(value) != 1: + logging.error("unexpected number of records: key=%s", key) + return False + + return parse_component_section(key, value[COMPONENT_KEY]) + + return False + + +def get_platform_components_path(): + PLATFORM_COMPONENTS_PATH_TEMPLATE = "/usr/share/sonic/device/{}/{}" + PLATFORM_COMPONENTS_FILE_PATH = PLATFORM_COMPONENTS_PATH_TEMPLATE.format( + device_info.get_platform(), PLATFORM_COMPONENTS_FILE) + return PLATFORM_COMPONENTS_FILE_PATH + + +def parse_platform_components(): + platform_components_path = get_platform_components_path() + with open(platform_components_path) as platform_components: + data = json.load(platform_components) + + if not isinstance(data, dict): + logging.error("dictionary is expected: key=root") + return False + + if not data: + logging.error("dictionary is empty: key=root") + return False + + if CHASSIS_KEY not in data: + logging.error("\"%s\" key hasn't been found", CHASSIS_KEY) + return False + + return parse_chassis_section(data[CHASSIS_KEY]) + + +def get_current_chassis_component_map(): + chassis_name = current_chassis.get_name() + current_chassis_component_map[chassis_name] = {} + + component_list = current_chassis.get_all_components() + for component in component_list: + component_name = component.get_name() + current_chassis_component_map[chassis_name][component_name] = component + + return current_chassis_component_map + + +def get_upgrade_dict(): + upgrade_dict = {} + firmware_version_current = "" + firmware_version_available = "" + + if not parse_platform_components(): + logging.error("Reading platform_components.json i, ion exception") + sys.exit(1) + + if not get_current_chassis_component_map(): + logging.error("Reading firmware i, ion from the driver is abnormal") + sys.exit(1) + + chassis_name = current_chassis.get_name() + diff_keys = set(chassis_component_map.keys()) ^ set(current_chassis_component_map.keys()) + if diff_keys: + logging.error("%s names mismatch: keys=%s", chassis_name, str(list(diff_keys))) + return None + + for chassis_name, component_map in current_chassis_component_map.items(): + for component_name, component in component_map.items(): + firmware_version_current = component.get_firmware_version() + if component_name in chassis_component_map[chassis_name]: + firmware_version_available = chassis_component_map[chassis_name][component_name][VERSION_KEY] + else: + logging.warning("can't find %s in %s", component_name, PLATFORM_COMPONENTS_FILE) + break + + if not os.path.exists(chassis_component_map[chassis_name][component_name][FIRMWARE_KEY]): + logging.error("%s does not exist", chassis_component_map[chassis_name][component_name][FIRMWARE_KEY]) + break + + if firmware_version_available != firmware_version_current: + upgrade_dict[component_name] = chassis_component_map[chassis_name][component_name][FIRMWARE_KEY] + + return upgrade_dict + + +def auto_upgrade(): + upgrade_result_dict = {} + chassis_name = current_chassis.get_name() + + upgrade_dict = get_upgrade_dict() + if not upgrade_dict: + logging.info("No firmware found for automatic upgrade") + return None + + component_map = current_chassis_component_map[chassis_name] + for value, path in upgrade_dict.items(): + status = component_map[value].install_firmware(path) + if status: + upgrade_result_dict[value] = "success" + logging.info("%s Upgrade Success", value) + else: + upgrade_result_dict[value] = "failed" + logging.error("%s Upgrade Failed", value) + return upgrade_result_dict + + +if __name__ == '__main__': + auto_upgrade() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/avscontrol.py b/platform/broadcom/sonic-platform-modules-micas/common/script/avscontrol.py new file mode 100755 index 000000000000..a0a2ccaac938 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/avscontrol.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 +import sys +import os +import time +import syslog +import glob +import click +from platform_config import MAC_DEFAULT_PARAM +from platform_util import getSdkReg, write_sysfs, get_value, get_format_value + + +AVSCTROL_DEBUG_FILE = "/etc/.avscontrol_debug_flag" + +AVSCTROLERROR = 1 +AVSCTROLDEBUG = 2 + +debuglevel = 0 + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def avscontrol_debug(s): + if AVSCTROLDEBUG & debuglevel: + syslog.openlog("AVSCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def avscontrol_error(s): + if AVSCTROLERROR & debuglevel: + syslog.openlog("AVSCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def avserror(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("AVSCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def avsinfo(s): + syslog.openlog("AVSCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_INFO, s) + + +def debug_init(): + global debuglevel + if os.path.exists(AVSCTROL_DEBUG_FILE): + debuglevel = debuglevel | AVSCTROLDEBUG | AVSCTROLERROR + else: + debuglevel = debuglevel & ~(AVSCTROLDEBUG | AVSCTROLERROR) + + +def set_avs_value_sysfs(conf, dcdc_value): + msg = "" + formula = conf.get("formula", None) + loc = conf.get("loc") + locations = glob.glob(loc) + if len(locations) == 0: + msg = "avs sysfs loc: %s not found" % loc + avscontrol_error(msg) + return False, msg + sysfs_loc = locations[0] + avscontrol_debug("set_avs_value_sysfs, loc: %s, origin dcdc value: %s, formula: %s" % + (sysfs_loc, dcdc_value, formula)) + if formula is not None: + dcdc_value = get_format_value(formula % (dcdc_value)) + wr_val = str(dcdc_value) + avscontrol_debug("set_avs_value_sysfs, write val: %s" % wr_val) + ret, log = write_sysfs(sysfs_loc, wr_val) + if ret is False: + msg = "set_avs_value_sysfs failed, msg: %s" % log + avscontrol_error(msg) + return ret, msg + + +def set_avs_value(avs_conf, dcdc_value): + set_avs_way = avs_conf.get("set_avs", {}).get("gettype") + if set_avs_way != "sysfs": + msg = "unsupport set avs value type: %s" % set_avs_way + avscontrol_error(msg) + return False, msg + ret, msg = set_avs_value_sysfs(avs_conf["set_avs"], dcdc_value) + return ret, msg + + +def get_dcdc_value(avs_conf, rov_value): + msg = "" + mac_avs_param = avs_conf.get("mac_avs_param", {}) + if rov_value not in mac_avs_param.keys(): + if avs_conf["type"] == 0: + msg = "VID:0x%x out of range, voltage regulate stop" % rov_value + avsinfo(msg) + return False, msg + dcdc_value = mac_avs_param[avs_conf["default"]] + avsinfo("VID:0x%x out of range, use default VID:0x%x" % (rov_value, dcdc_value)) + else: + dcdc_value = mac_avs_param[rov_value] + return True, dcdc_value + + +def get_rov_value_cpld(avs_conf): + cpld_avs_config = avs_conf["cpld_avs"] + return get_value(cpld_avs_config) + + +def get_rov_value_sdk(avs_conf): + name = avs_conf["sdkreg"] + ret, status = getSdkReg(name) + if ret is False: + return False, status + status = int(status, 16) + # shift operation + if avs_conf["sdktype"] != 0: + status = (status >> avs_conf["macregloc"]) & avs_conf["mask"] + macavs = status + return True, macavs + + +def doAvsCtrol_single(avs_conf): + try: + avs_name = avs_conf.get("name") + rov_source = avs_conf["rov_source"] + if rov_source == 0: + ret, rov_value = get_rov_value_cpld(avs_conf) # get rov from cpld reg + else: + ret, rov_value = get_rov_value_sdk(avs_conf) # get rov from sdk reg + if ret is False: + msg = "%s get rov_value failed, msg: %s" % (avs_name, rov_value) + avscontrol_error(msg) + return False, msg + avscontrol_debug("%s rov_value: 0x%x" % (avs_name, rov_value)) + ret, dcdc_value = get_dcdc_value(avs_conf, rov_value) + if ret is False: + msg = "%s get output voltage value failed, msg: %s" % (avs_name, dcdc_value) + avscontrol_error(msg) + return False, msg + ret, msg = set_avs_value(avs_conf, dcdc_value) + return ret, msg + except Exception as e: + msg = "%s avscontrol raise exception, msg: %s" % (avs_name, str(e)) + avscontrol_error(msg) + return False, msg + + +def doAvsCtrol(avs_conf): + retry_time = avs_conf.get("retry", 10) + for i in range(retry_time): + debug_init() + ret, log = doAvsCtrol_single(avs_conf) + if ret is True: + return True, log + time.sleep(1) + return False, log + + +def run(): + # wait 30s for device steady + time.sleep(30) + errcnt = 0 + msg = "" + for item in MAC_DEFAULT_PARAM: + status, log = doAvsCtrol(item) + if status is False: + errcnt += 1 + msg += log + + if errcnt == 0: + avsinfo("%%AVSCONTROL success") + sys.exit(0) + avserror("%%DEV_MONITOR-AVS: MAC Voltage adjust failed.") + avserror("%%DEV_MONITOR-AVS: errmsg: %s" % msg) + sys.exit(1) + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''device operator''' + + +@main.command() +def start(): + '''start AVS control''' + avsinfo("%%AVSCONTROL start") + run() + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/dev_monitor.py b/platform/broadcom/sonic-platform-modules-micas/common/script/dev_monitor.py new file mode 100755 index 000000000000..e13377b80fe9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/dev_monitor.py @@ -0,0 +1,303 @@ +#!/usr/bin/env python3 +import sys +import os +import time +import syslog +import traceback +import click +from platform_config import DEV_MONITOR_PARAM +from platform_util import io_rd, wbi2cget + + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +DEVMONITOR_DEBUG_FILE = "/etc/.devmonitor_debug_flag" + +debuglevel = 0 + + +def debug_init(): + global debuglevel + if os.path.exists(DEVMONITOR_DEBUG_FILE): + debuglevel = 1 + else: + debuglevel = 0 + + +def devwarninglog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("DEVMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_WARNING, s) + + +def devcriticallog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("DEVMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_CRIT, s) + + +def deverror(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("DEVMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def devinfo(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("DEVMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_INFO, s) + + +def devdebuglog(s): + # s = s.decode('utf-8').encode('gb2312') + if debuglevel == 1: + syslog.openlog("DEVMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +class DevMonitor(): + + def getpresentstatus(self, param): + try: + ret = {} + ret["status"] = '' + gettype = param.get('gettype') + presentbit = param.get('presentbit') + okval = param.get('okval') + if gettype == "io": + io_addr = param.get('io_addr') + val = io_rd(io_addr) + if val is None: + ret["status"] = "NOT OK" + return ret + retval = val + else: + bus = param.get('bus') + loc = param.get('loc') + offset = param.get('offset') + ind, val = wbi2cget(bus, loc, offset) + if ind is not True: + ret["status"] = "NOT OK" + return ret + retval = val + val_t = (int(retval, 16) & (1 << presentbit)) >> presentbit + if val_t != okval: + ret["status"] = "ABSENT" + else: + ret["status"] = "PRESENT" + except Exception as e: + ret["status"] = "NOT OK" + deverror("getpresentstatus error") + deverror(str(e)) + return ret + + def removeDev(self, bus, loc): + cmd = "echo 0x%02x > /sys/bus/i2c/devices/i2c-%d/delete_device" % (loc, bus) + devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) + if os.path.exists(devpath): + os.system(cmd) + + def addDev(self, name, bus, loc): + if name == "lm75": + time.sleep(0.1) + cmd = "echo %s 0x%02x > /sys/bus/i2c/devices/i2c-%d/new_device" % (name, loc, bus) + devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) + if os.path.exists(devpath) is False: + os.system(cmd) + + def checkattr(self, bus, loc, attr): + try: + attrpath = "/sys/bus/i2c/devices/%d-%04x/%s" % (bus, loc, attr) + if os.path.exists(attrpath): + return True + except Exception as e: + deverror("checkattr error") + deverror(str(e)) + return False + + def monitor(self, ret): + totalerr = 0 + for item in ret: + try: + name = item.get('name') + itemattr = '%sattr' % name + val_t = getattr(DevMonitor, itemattr, None) + if val_t == 'OK': + continue + present = item.get('present', None) + devices = item.get('device') + err_t = 0 + for item_dev in devices: + item_devattr = '%s' % (item_dev['id']) + val_t = getattr(DevMonitor, item_devattr, None) + if val_t == 'OK': + continue + devname = item_dev.get('name') + bus = item_dev.get('bus') + loc = item_dev.get('loc') + attr = item_dev.get('attr') + if self.checkattr(bus, loc, attr) is False: + err_t -= 1 + setattr(DevMonitor, item_devattr, 'NOT OK') + if present is not None: + presentstatus = self.getpresentstatus(present) + devdebuglog("%s present status:%s" % (name, presentstatus.get('status'))) + if presentstatus.get('status') == 'PRESENT': + self.removeDev(bus, loc) + time.sleep(0.1) + self.addDev(devname, bus, loc) + else: + self.removeDev(bus, loc) + time.sleep(0.1) + self.addDev(devname, bus, loc) + else: + setattr(DevMonitor, item_devattr, 'OK') + val_t = getattr(DevMonitor, item_devattr, None) + devdebuglog("%s status %s" % (item_devattr, val_t)) + if err_t == 0: + setattr(DevMonitor, itemattr, 'OK') + else: + totalerr -= 1 + setattr(DevMonitor, itemattr, 'NOT OK') + val_t = getattr(DevMonitor, itemattr, None) + devdebuglog("%s status %s" % (itemattr, val_t)) + except Exception as e: + totalerr -= 1 + deverror("monitor error") + deverror(str(e)) + return totalerr + + def psusmonitor(self): + psus_conf = DEV_MONITOR_PARAM.get('psus') + if psus_conf is None: + return 0 + psusattr = 'psusattr' + val_t = getattr(DevMonitor, psusattr, None) + if val_t == 'OK': + return 0 + ret = self.monitor(psus_conf) + if ret == 0: + setattr(DevMonitor, psusattr, 'OK') + else: + setattr(DevMonitor, psusattr, 'NOT OK') + val_t = getattr(DevMonitor, psusattr, None) + devdebuglog("psusattr:value:%s" % (val_t)) + return ret + + def fansmonitor(self): + fans_conf = DEV_MONITOR_PARAM.get('fans') + if fans_conf is None: + return 0 + fansattr = 'fansattr' + val_t = getattr(DevMonitor, fansattr, None) + if val_t == 'OK': + return 0 + ret = self.monitor(fans_conf) + if ret == 0: + setattr(DevMonitor, fansattr, 'OK') + else: + setattr(DevMonitor, fansattr, 'NOT OK') + val_t = getattr(DevMonitor, fansattr, None) + devdebuglog("fansattr:value:%s" % (val_t)) + return ret + + def slotsmonitor(self): + slots_conf = DEV_MONITOR_PARAM.get('slots') + if slots_conf is None: + return 0 + slotsattr = 'slotsattr' + val_t = getattr(DevMonitor, slotsattr, None) + if val_t == 'OK': + return 0 + ret = self.monitor(slots_conf) + if ret == 0: + setattr(DevMonitor, slotsattr, 'OK') + else: + setattr(DevMonitor, slotsattr, 'NOT OK') + val_t = getattr(DevMonitor, slotsattr, None) + devdebuglog("slotsattr:value:%s" % (val_t)) + return ret + + def othersmonitor(self): + others_conf = DEV_MONITOR_PARAM.get('others') + if others_conf is None: + return 0 + othersattr = 'othersattr' + val_t = getattr(DevMonitor, othersattr, None) + if val_t == 'OK': + return 0 + ret = self.monitor(others_conf) + if ret == 0: + setattr(DevMonitor, othersattr, 'OK') + else: + setattr(DevMonitor, othersattr, 'NOT OK') + val_t = getattr(DevMonitor, othersattr, None) + devdebuglog("othersattr:value:%s" % (val_t)) + return ret + + +def doDevMonitor(devMonitor): + ret_t = 0 + ret_t += devMonitor.psusmonitor() + ret_t += devMonitor.fansmonitor() + ret_t += devMonitor.slotsmonitor() + ret_t += devMonitor.othersmonitor() + return ret_t + + +def run(interval, devMonitor): + # devMonitor.devattrinit() + while True: + try: + debug_init() + ret = doDevMonitor(devMonitor) + except Exception as e: + traceback.print_exc() + deverror(str(e)) + ret = -1 + if ret == 0: + time.sleep(5) + devinfo("dev_monitor finished!") + sys.exit(0) + time.sleep(interval) + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''device operator''' + + +@main.command() +def start(): + '''start device monitor''' + devinfo("dev_monitor start") + devMonitor = DevMonitor() + interval = DEV_MONITOR_PARAM.get('polling_time', 10) + run(interval, devMonitor) + + +@main.command() +def stop(): + '''stop device monitor ''' + devinfo("stop") + + +# device_i2c operation +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/drv_update.py b/platform/broadcom/sonic-platform-modules-micas/common/script/drv_update.py new file mode 100755 index 000000000000..9de4911e8023 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/drv_update.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +import syslog +import os +import shutil +from platform_config import DRVIER_UPDATE_CONF +from platform_util import exec_os_cmd + + +DRV_UPDATE_DEBUG_FILE = "/etc/.drv_update_debug_flag" + +DRVUPDATEERROR = 1 +DRVUPDATEDEBUG = 2 +debuglevel = 0 + + +def drv_update_debug(s): + if DRVUPDATEDEBUG & debuglevel: + syslog.openlog("DRV_UPDATE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_INFO, s) + + +def drv_update_error(s): + if DRVUPDATEERROR & debuglevel: + syslog.openlog("DRV_UPDATE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def drv_update_info(s): + syslog.openlog("DRV_UPDATE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_NOTICE, s) + +def debug_init(): + global debuglevel + try: + with open(DRV_UPDATE_DEBUG_FILE, "r") as fd: + value = fd.read() + debuglevel = int(value) + except Exception: + debuglevel = 0 + + +def get_driver_md5sum(drv_path): + status, output = exec_os_cmd("md5sum %s" % drv_path) + if status or len(output) == 0: + return False, output + drv_md5 = output.strip().split(" ")[0] + return True, drv_md5 + + +def do_driver_replace(src_file, target_file): + # Backup target file + src_file_dir = os.path.dirname(src_file) + target_file_name = os.path.basename(target_file) + drv_update_debug("src_file: %s, src_file_dir: %s" % (src_file, src_file_dir)) + drv_update_debug("target_file: %s, target_file_name: %s" % (target_file, target_file_name)) + try: + shutil.copyfile(target_file, "%s/%s.bak" % (src_file_dir, target_file_name)) + shutil.copyfile(src_file, target_file) + return True + except Exception as e: + drv_update_error("do_driver_replace error, msg: %s" % str(e)) + return False + + +def doDrvUpdate(): + reboot_flag = DRVIER_UPDATE_CONF.get("reboot_flag", 0) + drv_list = DRVIER_UPDATE_CONF.get("drv_list", []) + err_cnt = 0 + update_initramfs_flag = 0 + # get kernel version + status, output = exec_os_cmd("uname -r") + if status or len(output) == 0: + drv_update_error("Failed to get kernel version, status: %s, log: %s" % (status, output)) + return + kversion = output.strip() + drv_update_debug("kernel version: %s" % kversion) + for item in drv_list: + try: + source_drv = item.get("source") + target_drv = item.get("target") + judge_flag = item.get("judge_flag") + if source_drv is None or target_drv is None or judge_flag is None: + drv_update_error("driver update config error, source_drv: %s, target_drv: %s, judge_file: %s" % (source_drv, target_drv, judge_flag)) + err_cnt += 1 + continue + drv_update_debug("source_drv: %s, target_drv: %s, judge_flag: %s" % (source_drv, target_drv, judge_flag)) + + # Check if the current driver is expected + if os.path.exists(judge_flag): + drv_update_debug("The current driver is expected, do nothing") + continue + + # get source driver file path + source_drv_path = "/lib/modules/%s/%s" % (kversion, source_drv) + drv_update_debug("source driver: %s, file path: %s" % (source_drv, source_drv_path)) + + # get target driver file path + target_drv_path = "/lib/modules/%s/%s" % (kversion, target_drv) + drv_update_debug("target driver: %s, file path: %s" % (target_drv, target_drv_path)) + + # get source driver md5sum + status, source_drv_md5 = get_driver_md5sum(source_drv_path) + if status is False: + msg = "get %s md5sum failed msg: %s" % (source_drv_path, source_drv_md5) + drv_update_error(msg) + err_cnt += 1 + continue + drv_update_debug("source driver file path: %s, md5sum: %s" % (source_drv_path, source_drv_md5)) + + # get target driver md5sum + status, target_drv_md5 = get_driver_md5sum(target_drv_path) + if status is False: + msg = "get %s md5sum failed msg: %s" % (target_drv_path, target_drv_md5) + drv_update_error(msg) + err_cnt += 1 + continue + drv_update_debug("target driver file path: %s, md5sum: %s" % (target_drv_path, target_drv_md5)) + + if source_drv_md5 != target_drv_md5: + drv_update_debug("source_drv_md5 not equal to target_drv_md5, try to use source driver replace target driver") + status = do_driver_replace(source_drv_path, target_drv_path) + if status is False: + err_cnt += 1 + continue + else: + drv_update_debug("source_drv_md5 equal to target_drv_md5, do nothing") + + drv_update_debug("Driver replacement completed, set update_initramfs_flag") + update_initramfs_flag = 1 + + except Exception as e: + err_cnt += 1 + drv_update_error(str(e)) + + if update_initramfs_flag == 1: + drv_update_debug("starting to update initramfs") + os.system("update-initramfs -u") + drv_update_debug("update initramfs finish") + + os.system("sync") + if update_initramfs_flag == 1 and err_cnt == 0 and reboot_flag == 1: + reboot_log = "%DRV_UPDATE-5-REBOOT: Update initramfs is completed, restarting the system to take effect." + reboot_log_cmd = "echo '%s' > /dev/ttyS0" % reboot_log + exec_os_cmd(reboot_log_cmd) + drv_update_info(reboot_log) + os.system("/sbin/reboot") + return + +if __name__ == '__main__': + debug_init() + doDrvUpdate() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/generate_airflow.py b/platform/broadcom/sonic-platform-modules-micas/common/script/generate_airflow.py new file mode 100755 index 000000000000..89d3e72335ff --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/generate_airflow.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +''' +generate board air flow according to fan and psu air flow +write resulet to AIRFLOW_RESULT_FILE, file format: +{ + "FAN1": { + "model":"M1HFAN I-F", + "airflow":"intake", + }, + "PSU1": { + "model":"CSU550AP-3-500", + "airflow":"intake", + }, + "board":"intake" +} +''' +import os +import syslog +import json +from platform_config import AIR_FLOW_CONF, AIRFLOW_RESULT_FILE +from platform_util import dev_file_read, byteTostr +from eepromutil.fru import ipmifru +from eepromutil.cust_fru import CustFru +from eepromutil.fantlv import fan_tlv + + +AIRFLOW_DEBUG_FILE = "/etc/.airflow_debug_flag" + +AIRFLOWERROR = 1 +AIRFLOWDEBUG = 2 + +debuglevel = 0 + + +def airflow_info(s): + syslog.openlog("AIRFLOW", syslog.LOG_PID) + syslog.syslog(syslog.LOG_INFO, s) + + +def airflow_error(s): + syslog.openlog("AIRFLOW", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def airflow_debug(s): + if AIRFLOWDEBUG & debuglevel: + syslog.openlog("AIRFLOW", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def airflow_debug_error(s): + if AIRFLOWERROR & debuglevel: + syslog.openlog("AIRFLOW", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def debug_init(): + global debuglevel + try: + with open(AIRFLOW_DEBUG_FILE, "r") as fd: + value = fd.read() + debuglevel = int(value) + except Exception: + debuglevel = 0 + + +def get_model_fru(device, eeprom): + try: + fru = ipmifru() + fru.decodeBin(eeprom) + dev_name = device.get("name") + area = device.get("area") + field = device.get("field") + tmp_area = getattr(fru, area, None) + if tmp_area is None: + msg = "%s fru %s area config error" % (dev_name, area) + return False, msg + model = getattr(tmp_area, field, None) + if model is None: + msg = "%s get model error, area: %s, field: %s" % (dev_name, area, field) + return False, msg + airflow_debug("%s get model success, model: %s" % (dev_name, model)) + return True, model + except Exception as e: + return False, str(e) + +def get_model_custfru(device, eeprom): + try: + custfru = CustFru() + custfru.decode(eeprom) + dev_name = device.get("name") + field = device.get("field") + model = getattr(custfru, field, None) + if model is None: + msg = "%s get model error, field: %s" % (dev_name, field) + return False, msg + airflow_debug("%s get model success, model: %s" % (dev_name, model)) + return True, model + except Exception as e: + return False, str(e) + + +def get_model_fantlv(device, eeprom): + try: + dev_name = device.get("name") + tlv = fan_tlv() + rets = tlv.decode(eeprom) + if len(rets) == 0: + msg = "%s decode fantlv eeprom info error" % dev_name + return False, msg + + field = device.get("field") + for fantlv_item in rets: + if fantlv_item.get("name") == field: + return True, fantlv_item["value"] + msg = "%s get model error, field: %s not found" % (dev_name, field) + return False, msg + except Exception as e: + return False, str(e) + + +def get_device_modele(device): + e2_type = device.get("e2_type") + dev_name = device.get("name") + support_e2_type = ("fru", "fantlv", "custfru") + if e2_type not in support_e2_type: + msg = "%s unsupport e2_type: %s" % (dev_name, e2_type) + return False, msg + + e2_path = device.get("e2_path") + e2_size = device.get("e2_size", 256) + ret, binval_bytes = dev_file_read(e2_path, 0, e2_size) + if ret is False: + msg = "%s eeprom read error, eeprom path: %s, msg: %s" % (dev_name, e2_path, binval_bytes) + return False, msg + + binval = byteTostr(binval_bytes) + if e2_type == "fru": + return get_model_fru(device, binval) + if e2_type == "custfru": + return get_model_custfru(device, binval) + return get_model_fantlv(device, binval) + + +def get_board_air_flow(fan_intake_num, fan_exhaust_num, psu_intake_num, psu_exhaust_num): + airflow_debug("fan_intake_num: %d, fan_exhaust_num: %d, psu_intake_num: %d, psu_exhaust_num: %d" % + (fan_intake_num, fan_exhaust_num, psu_intake_num, psu_exhaust_num)) + + if fan_intake_num == 0 and fan_exhaust_num == 0 and psu_intake_num == 0 and psu_exhaust_num == 0: + airflow_error("get all fans and psus air flow failed") + return "N/A" + + if fan_intake_num > fan_exhaust_num: + airflow_debug("fan intake number more than fan exhaust number, set board air flow: intake") + return "intake" + + if fan_intake_num < fan_exhaust_num: + airflow_debug("fan intake number less than fan exhaust number, set board air flow: exhaust") + return "exhaust" + + airflow_debug("fan intake number equal to exhaust number, check psu air flow") + + if psu_intake_num > psu_exhaust_num: + airflow_debug("psu intake number more than psu exhaust number, set board air flow: intake") + return "intake" + + if psu_intake_num < psu_exhaust_num: + airflow_debug("psu intake number less than psu exhaust number, set board air flow: exhaust") + return "exhaust" + + airflow_debug("fan and psu intake and exhaust number equal, return intake") + return "intake" + + +def generate_airflow(): + fan_intake_list = [] + fan_exhaust_list = [] + psu_intake_list = [] + psu_exhaust_list = [] + ret = {} + fans = AIR_FLOW_CONF.get("fans", []) + psus = AIR_FLOW_CONF.get("psus", []) + + for fan in fans: + dev_name = fan.get("name") + air_flow = "N/A" + status, model = get_device_modele(fan) + if status is False: + ret[dev_name] = {"model": "N/A", "airflow": "N/A"} + airflow_error(model) + continue + model = model.strip() + airflowconifg = AIR_FLOW_CONF[fan["decode"]] + for key, value in airflowconifg.items(): + if model in value: + air_flow = key + ret[dev_name] = {"model": model, "airflow": air_flow} + airflow_debug("%s model: %s, airflow: %s" % (dev_name, model, air_flow)) + if air_flow == "intake": + fan_intake_list.append(fan.get("name")) + elif air_flow == "exhaust": + fan_exhaust_list.append(fan.get("name")) + + airflow_debug("fan_intake_list: %s" % fan_intake_list) + airflow_debug("fan_exhaust_list: %s" % fan_exhaust_list) + + for psu in psus: + dev_name = psu.get("name") + air_flow = "N/A" + status, model = get_device_modele(psu) + if status is False: + ret[dev_name] = {"model": "N/A", "airflow": "N/A"} + airflow_error(model) + continue + model = model.strip() + airflowconifg = AIR_FLOW_CONF[psu["decode"]] + for key, value in airflowconifg.items(): + if model in value: + air_flow = key + ret[dev_name] = {"model": model, "airflow": air_flow} + airflow_debug("%s model: %s, airflow: %s" % (dev_name, model, air_flow)) + if air_flow == "intake": + psu_intake_list.append(psu.get("name")) + elif air_flow == "exhaust": + psu_exhaust_list.append(psu.get("name")) + + airflow_debug("psu_intake_list: %s" % psu_intake_list) + airflow_debug("psu_exhaust_list: %s" % psu_exhaust_list) + + fan_intake_num = len(fan_intake_list) + fan_exhaust_num = len(fan_exhaust_list) + psu_intake_num = len(psu_intake_list) + psu_exhaust_num = len(psu_exhaust_list) + + board_airflow = get_board_air_flow(fan_intake_num, fan_exhaust_num, psu_intake_num, psu_exhaust_num) + airflow_debug("board_airflow: %s" % board_airflow) + ret["board"] = board_airflow + ret_json = json.dumps(ret, ensure_ascii=False, indent=4) + + out_file_dir = os.path.dirname(AIRFLOW_RESULT_FILE) + if len(out_file_dir) != 0: + cmd = "mkdir -p %s" % out_file_dir + os.system(cmd) + os.system("sync") + with open(AIRFLOW_RESULT_FILE, "w") as fd: + fd.write(ret_json) + os.system("sync") + + +if __name__ == '__main__': + debug_init() + airflow_debug("enter main") + generate_airflow() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/hal_fanctrl.py b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_fanctrl.py new file mode 100755 index 000000000000..7722b111f944 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_fanctrl.py @@ -0,0 +1,1135 @@ +#!/usr/bin/env python3 +import os +import subprocess +import time +import syslog +import traceback +from plat_hal.interface import interface +from plat_hal.baseutil import baseutil +from algorithm.pid import pid +from algorithm.openloop import openloop +from algorithm.hysteresis import hysteresis + + +SWITCH_TEMP = "SWITCH_TEMP" +INLET_TEMP = "INLET_TEMP" +BOARD_TEMP = "BOARD_TEMP" +OUTLET_TEMP = "OUTLET_TEMP" +CPU_TEMP = "CPU_TEMP" + +FANCTROL_DEBUG_FILE = "/etc/.fancontrol_debug_flag" +# coordination with REBOOT_CAUSE_PARA +OTP_SWITCH_REBOOT_JUDGE_FILE = "/etc/.otp_reboot_flag" +OTP_OTHER_REBOOT_JUDGE_FILE = OTP_SWITCH_REBOOT_JUDGE_FILE + +FANCTROLERROR = 1 +FANCTROLDEBUG = 2 +FANAIRFLOWDEBUG = 4 + +debuglevel = 0 + +F2B_AIR_FLOW = "intake" +B2F_AIR_FLOW = "exhaust" +ONIE_E2_NAME = "ONIE_E2" + +TEMP_REBOOT_CRIT_SWITCH_FLAG = 1 +TEMP_REBOOT_CRIT_OTHER_FLAG = 2 + + +def fancontrol_debug(s): + if FANCTROLDEBUG & debuglevel: + syslog.openlog("FANCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def fancontrol_error(s): + if FANCTROLERROR & debuglevel: + syslog.openlog("FANCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def fanairflow_debug(s): + if FANAIRFLOWDEBUG & debuglevel: + syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def fancontrol_warn(s): + syslog.openlog("FANCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_WARNING, s) + + +def fancontrol_crit(s): + syslog.openlog("FANCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_CRIT, s) + + +def fancontrol_alert(s): + syslog.openlog("FANCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_ALERT, s) + + +def fancontrol_emerg(s): + syslog.openlog("FANCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_EMERG, s) + + +def exec_os_cmd(cmd): + status, output = subprocess.getstatusoutput(cmd) + if status: + print(output) + return status, output + + +def debug_init(): + global debuglevel + try: + with open(FANCTROL_DEBUG_FILE, "r") as fd: + value = fd.read() + debuglevel = int(value) + except Exception: + debuglevel = 0 + + +error_temp = -9999 # get temp error +invalid_temp = -10000 # get temp invalid +PRE_FAN_NOK_UNKNOWN = "UNKNOWN" + + +class DevFan(object): + + def __init__(self, name, hal_interface): + self.__name = name + self.origin_name = None + self.display_name = None + self.air_flow = None + self.air_flow_inconsistent = False + self.int_case = hal_interface + + @property + def name(self): + return self.__name + + def get_fan_rotor_number(self): + return self.int_case.get_fan_rotor_number(self.name) + + def get_fan_presence(self): + return self.int_case.get_fan_presence(self.name) + + def get_fan_rotor_status(self, rotor_name): + return self.int_case.get_fan_rotor_status(self.name, rotor_name) + + def get_fan_fru_info(self): + return self.int_case.get_fan_fru_info(self.name) + + @property + def na_ret(self): + return self.int_case.na_ret + + def update_fru_info(self): + try: + dic = self.get_fan_fru_info() + self.origin_name = dic["PN"] + self.air_flow = dic["AirFlow"] + self.display_name = dic["DisplayName"] + except Exception as e: + fanairflow_debug("update %s fru info error, msg: %s" % (self.name, str(e))) + self.origin_name = self.na_ret + self.air_flow = self.na_ret + self.display_name = self.na_ret + + +class DevPsu(object): + + def __init__(self, name, hal_interface): + self.__name = name + self.origin_name = None + self.display_name = None + self.air_flow = None + self.air_flow_inconsistent = False + self.int_case = hal_interface + + @property + def name(self): + return self.__name + + def get_psu_fru_info(self): + return self.int_case.get_psu_fru_info(self.name) + + @property + def na_ret(self): + return self.int_case.na_ret + + def update_fru_info(self): + try: + dic = self.get_psu_fru_info() + self.origin_name = dic["PN"] + self.air_flow = dic["AirFlow"] + self.display_name = dic["DisplayName"] + except Exception as e: + fanairflow_debug("update %s fru info error, msg: %s" % (self.name, str(e))) + self.origin_name = self.na_ret + self.air_flow = self.na_ret + self.display_name = self.na_ret + + +class fancontrol(object): + __int_case = None + + __pwm = 0x80 + + def __init__(self): + self.int_case = interface() + self.__config = baseutil.get_monitor_config() + self.__pid_config = self.__config["pid"] + self.__hyst_config = self.__config.get("hyst", {}) + self.__temps_threshold_config = self.__config["temps_threshold"] + for temp_threshold in self.__temps_threshold_config.values(): + temp_threshold['temp'] = 0 + temp_threshold['fail_num'] = 0 + temp_threshold['warning_num'] = 0 # temp warning times + temp_threshold['critical_num'] = 0 # temp critical times + temp_threshold['emergency_num'] = 0 # temp emergency times + temp_threshold.setdefault('ignore_threshold', 0) # default temp threshold on + temp_threshold.setdefault('invalid', invalid_temp) + temp_threshold.setdefault('error', error_temp) + + self.__otp_reboot_judge_file_config = self.__config.get("otp_reboot_judge_file", None) + if self.__otp_reboot_judge_file_config is None: + self.__otp_switch_reboot_judge_file = OTP_SWITCH_REBOOT_JUDGE_FILE + self.__otp_other_reboot_judge_file = OTP_OTHER_REBOOT_JUDGE_FILE + else: + self.__otp_switch_reboot_judge_file = self.__otp_reboot_judge_file_config.get( + "otp_switch_reboot_judge_file", OTP_SWITCH_REBOOT_JUDGE_FILE) + self.__otp_other_reboot_judge_file = self.__otp_reboot_judge_file_config.get( + "otp_other_reboot_judge_file", OTP_OTHER_REBOOT_JUDGE_FILE) + + self.__fan_rotor_error_num = {} + self.__fan_present_status = {} # {"FAN1":0, "FAN2":1...} 1:present, 0:absent + self.__fan_rotate_status = {} # {"FAN1":0, "FAN2":1...} 1:OK, 0:NOT OK + self.__fan_repair_flag = {} # {"FAN1":0, "FAN2":1...} 1:repair, 0:give up + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + self.__fan_present_status[fan_name] = 1 # present + self.__fan_rotate_status[fan_name] = 1 # OK + self.__fan_repair_flag[fan_name] = 1 # repair + rotor_num = self.get_rotor_number(fan_name) + tmp_fan = {} + for j in range(rotor_num): + rotor_name = "Rotor" + str(j + 1) + tmp_fan[rotor_name] = 0 # not error + self.__fan_rotor_error_num[fan_name] = tmp_fan + + self.__fancontrol_para = self.__config["fancontrol_para"] + self.__interval = self.__fancontrol_para.get("interval", 5) + self.__fan_status_interval = self.__fancontrol_para.get("fan_status_interval", 0) + self.__max_pwm = self.__fancontrol_para.get("max_pwm", 0xff) + self.__min_pwm = self.__fancontrol_para.get("min_pwm", 0x80) + self.__abnormal_pwm = self.__fancontrol_para.get("abnormal_pwm", 0xbb) + self.__warning_pwm = self.__fancontrol_para.get("warning_pwm", 0xff) + self.__temp_invalid_pid_pwm = self.__fancontrol_para.get("temp_invalid_pid_pwm", 0x80) + self.__temp_error_pid_pwm = self.__fancontrol_para.get("temp_error_pid_pwm", 0x80) + self.__temp_fail_num = self.__fancontrol_para.get("temp_fail_num", 3) + self.__check_temp_fail = self.__fancontrol_para.get("check_temp_fail", []) + self.__temp_warning_num = self.__fancontrol_para.get("temp_warning_num", 3) + self.__temp_critical_num = self.__fancontrol_para.get("temp_critical_num", 3) + self.__temp_emergency_num = self.__fancontrol_para.get("temp_emergency_num", 3) + self.__temp_warning_countdown = self.__fancontrol_para.get("temp_warning_countdown", 60) + self.__temp_critical_countdown = self.__fancontrol_para.get("temp_critical_countdown", 60) + self.__temp_emergency_countdown = self.__fancontrol_para.get("temp_emergency_countdown", 60) + self.__rotor_error_count = self.__fancontrol_para.get("rotor_error_count", 6) + self.__inlet_mac_diff = self.__fancontrol_para.get("inlet_mac_diff", 50) + self.__check_crit_reboot_flag = self.__fancontrol_para.get("check_crit_reboot_flag", 1) + self.__check_emerg_reboot_flag = self.__fancontrol_para.get("check_emerg_reboot_flag", 1) + self.__check_crit_reboot_num = self.__fancontrol_para.get("check_crit_reboot_num", 3) + self.__check_crit_sleep_time = self.__fancontrol_para.get("check_crit_sleep_time", 20) + self.__check_emerg_reboot_num = self.__fancontrol_para.get("check_emerg_reboot_num", 3) + self.__check_emerg_sleep_time = self.__fancontrol_para.get("check_emerg_sleep_time", 20) + self.__check_temp_emergency = self.__fancontrol_para.get("check_temp_emergency", 0) + self.__check_temp_critical = self.__fancontrol_para.get("check_temp_critical", 1) + self.__check_temp_warning = self.__fancontrol_para.get("check_temp_warning", 1) + self.__check_temp_emergency_reboot = self.__fancontrol_para.get("check_temp_emergency_reboot", []) + self.__psu_absent_fullspeed_num = self.__fancontrol_para.get("psu_absent_fullspeed_num", 1) + self.__fan_absent_fullspeed_num = self.__fancontrol_para.get("fan_absent_fullspeed_num", 1) + self.__rotor_error_fullspeed_num = self.__fancontrol_para.get("rotor_error_fullspeed_num", 1) + self.__psu_fan_control = self.__fancontrol_para.get("psu_fan_control", 1) # default control psu fan + self.__fan_plug_in_pwm = self.__fancontrol_para.get("fan_plug_in_pwm", 0x80) + self.__fan_plug_in_default_countdown = self.__fancontrol_para.get("fan_plug_in_default_countdown", 0) + self.__deal_fan_error_policy = self.__fancontrol_para.get("deal_fan_error", 0) + self.__deal_fan_error_conf = self.__fancontrol_para.get("deal_fan_error_conf", {}) + self.__deal_fan_error_default_countdown = self.__deal_fan_error_conf.get("countdown", 0) + + self.__warning_countdown = 0 # temp warning flag for normal fancontrol + self.__critical_countdown = 0 # temp critical flag for normal fancontrol + self.__emergency_countdown = 0 # temp emergency flag for normal fancontrol + self.__fan_plug_in_countdown = 0 # fan plug in flag for normal fancontrol + self.__deal_fan_error_countdown = 0 + self.__fan_absent_num = 0 + self.__fan_nok_num = 0 + self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN + self.openloop = openloop() + self.pid = pid() + self.hyst = hysteresis() + self.__pwm = self.__min_pwm + + self.__board_air_flow = "" + self.__fan_air_flow_monitor = self.__fancontrol_para.get("fan_air_flow_monitor", 0) + self.__psu_air_flow_monitor = self.__fancontrol_para.get("psu_air_flow_monitor", 0) + self.__air_flow_correct_fan_pwm = self.__fancontrol_para.get("air_flow_correct_fan_pwm", 0xff) + self.__air_flow_correct_psu_pwm = self.__fancontrol_para.get("air_flow_correct_psu_pwm", 0xff) + self.__air_flow_error_fan_pwm = self.__fancontrol_para.get("air_flow_error_fan_pwm", 0) + self.__air_flow_error_psu_pwm = self.__fancontrol_para.get("air_flow_error_psu_pwm", 0) + self.fan_air_flow_inconsistent_flag = False + self.psu_air_flow_inconsistent_flag = False + self.air_flow_inconsistent_flag = False + self.fan_obj_list = [] + self.psu_obj_list = [] + + @property + def na_ret(self): + return self.int_case.na_ret + + def get_onie_e2_obj(self, name): + return self.int_case.get_onie_e2_obj(name) + + @property + def board_air_flow(self): + air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) + if self.__board_air_flow not in air_flow_tuple: + self.__board_air_flow = self.int_case.get_device_airflow(ONIE_E2_NAME) + fanairflow_debug("board_air_flow: %s" % self.__board_air_flow) + return self.__board_air_flow + + @property + def fan_air_flow_monitor(self): + return self.__fan_air_flow_monitor + + @property + def psu_air_flow_monitor(self): + return self.__psu_air_flow_monitor + + @property + def air_flow_correct_fan_pwm(self): + return self.__air_flow_correct_fan_pwm + + @property + def air_flow_correct_psu_pwm(self): + return self.__air_flow_correct_psu_pwm + + @property + def air_flow_error_fan_pwm(self): + return self.__air_flow_error_fan_pwm + + @property + def air_flow_error_psu_pwm(self): + return self.__air_flow_error_psu_pwm + + def get_para(self, t): + para = self.__pid_config.get(t) + return para + + def update_over_temp_threshold_num(self): + for temp_threshold in self.__temps_threshold_config.values(): + if temp_threshold['ignore_threshold']: + continue + emergency_threshold = temp_threshold.get('emergency', None) + critical_threshold = temp_threshold.get('critical', None) + warning_threshold = temp_threshold.get('warning', None) + fancontrol_debug("%s warning = %s, critical = %s, emergency = %s" % + (temp_threshold['name'], warning_threshold, critical_threshold, emergency_threshold)) + + if emergency_threshold is not None and temp_threshold['temp'] >= emergency_threshold: + temp_threshold['emergency_num'] += 1 + else: + temp_threshold['emergency_num'] = 0 + + if critical_threshold is not None and temp_threshold['temp'] >= critical_threshold: + temp_threshold['critical_num'] += 1 + else: + temp_threshold['critical_num'] = 0 + + if warning_threshold is not None and temp_threshold['temp'] >= warning_threshold: + temp_threshold['warning_num'] += 1 + else: + temp_threshold['warning_num'] = 0 + + fancontrol_debug("%s warning_num = %d, critical_num = %d, emergency_num = %d" % + (temp_threshold['name'], temp_threshold['warning_num'], temp_threshold['critical_num'], temp_threshold.get("emergency_num"))) + + def get_monitor_temp(self): + sensorlist = self.int_case.get_temp_info() + + for temp_threshold in self.__temps_threshold_config.values(): + sensor = sensorlist.get(temp_threshold['name']) + if sensor["Value"] is None or int(sensor["Value"]) == self.int_case.error_ret: + temp_threshold['fail_num'] += 1 + fancontrol_error("get %s failed, fail_num = %d" % (temp_threshold['name'], temp_threshold['fail_num'])) + else: + temp_threshold['fail_num'] = 0 + temp_threshold.setdefault('fix', 0) + temp_threshold['temp'] = sensor["Value"] + temp_threshold['fix'] + fancontrol_debug("%s = %d" % (temp_threshold['name'], temp_threshold['temp'])) + self.update_over_temp_threshold_num() + + def is_temp_warning(self): + warning_flag = False + for temp_threshold in self.__temps_threshold_config.values(): + if temp_threshold['ignore_threshold']: + continue + if temp_threshold['warning_num'] >= self.__temp_warning_num: + warning_flag = True + fancontrol_warn("%%FANCONTROL-4-TEMP_HIGH: %s temperature %sC is larger than warning threshold %sC." % + (temp_threshold['name'], temp_threshold['temp'], temp_threshold.get('warning'))) + return warning_flag + + def checkTempWarning(self): + try: + if self.is_temp_warning(): + self.__warning_countdown = self.__temp_warning_countdown + fancontrol_debug("temp is over warning") + return True + if self.__warning_countdown > 0: + self.__warning_countdown -= 1 + return False + except Exception as e: + fancontrol_error("%%policy: checkTempWarning failed") + fancontrol_error(str(e)) + return False + + def checkTempWarningCountdown(self): + if self.__warning_countdown > 0: + return True + return False + + def is_temp_critical(self): + critical_flag = False + for temp_threshold in self.__temps_threshold_config.values(): + temp_threshold['critical_flag'] = False + if temp_threshold['ignore_threshold']: + continue + if temp_threshold['critical_num'] >= self.__temp_critical_num: + critical_flag = True + temp_threshold['critical_flag'] = True + fancontrol_crit("%%FANCONTROL-2-TEMP_HIGH: %s temperature %sC is larger than critical threshold %sC." % + (temp_threshold['name'], temp_threshold['temp'], temp_threshold.get('critical'))) + return critical_flag + + def checkTempCritical(self): + try: + if self.is_temp_critical(): + self.__critical_countdown = self.__temp_critical_countdown + fancontrol_debug("temp is over critical") + return True + if self.__critical_countdown > 0: + self.__critical_countdown -= 1 + return False + except Exception as e: + fancontrol_error("%%policy: checkTempCrit failed") + fancontrol_error(str(e)) + return False + + def is_temp_emergency(self): + emergency_flag = False + for temp_threshold in self.__temps_threshold_config.values(): + temp_threshold['emergency_flag'] = False + if temp_threshold['ignore_threshold']: + continue + if temp_threshold['emergency_num'] >= self.__temp_emergency_num: + emergency_flag = True + temp_threshold['emergency_flag'] = True + fancontrol_alert("%%FANCONTROL-1-TEMP_HIGH: %s temperature %sC is larger than emergency threshold %sC." % + (temp_threshold['name'], temp_threshold['temp'], temp_threshold.get('emergency'))) + return emergency_flag + + def checkTempEmergency(self): + try: + if self.is_temp_emergency(): + self.__emergency_countdown = self.__temp_emergency_countdown + fancontrol_debug("temp is over emergency") + return True + if self.__emergency_countdown > 0: + self.__emergency_countdown -= 1 + return False + except Exception as e: + fancontrol_error("%%policy: checkTempEmergency failed") + fancontrol_error(str(e)) + return False + + def checkTempCriticalCountdown(self): + if self.__critical_countdown > 0: + return True + return False + + def checkTempEmergencyCountdown(self): + if self.__emergency_countdown > 0: + return True + return False + + def checkTempRebootCrit(self): + try: + if self.is_temp_critical(): + temp_dict = dict(self.__temps_threshold_config) + tmp = temp_dict.get(SWITCH_TEMP) + if tmp['critical_flag'] is True: + fancontrol_debug("switch temp is over reboot critical") + return TEMP_REBOOT_CRIT_SWITCH_FLAG + del temp_dict[SWITCH_TEMP] + for temp_items in temp_dict.values(): + if temp_items['ignore_threshold']: + continue + if temp_items['critical_flag'] is False: + return 0 + + fancontrol_debug("other temp is over reboot critical") + return TEMP_REBOOT_CRIT_OTHER_FLAG + except Exception as e: + fancontrol_error("%%policy: checkTempRebootCrit failed") + fancontrol_error(str(e)) + return 0 + + def checkCritReboot(self): + try: + reboot_flag = self.checkTempRebootCrit() + if reboot_flag > 0: + self.set_all_fan_speed_pwm(self.__max_pwm) + for i in range(self.__check_crit_reboot_num): + time.sleep(self.__check_crit_sleep_time) + self.get_monitor_temp() + reboot_flag = self.checkTempRebootCrit() + if reboot_flag > 0: + fancontrol_emerg("%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot critical value lasts for %d seconds." % + (self.__check_crit_sleep_time * (i + 1))) + continue + fancontrol_debug("The temperature of device is not over reboot critical value.") + break + if reboot_flag > 0: + fancontrol_emerg( + "%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot critical value, system is going to reboot now.") + for temp_threshold in self.__temps_threshold_config.values(): + fancontrol_emerg( + "%%FANCONTROL-TEMP_EMERG: %s temperature: %sC." % + (temp_threshold['name'], temp_threshold['temp'])) + if reboot_flag == TEMP_REBOOT_CRIT_SWITCH_FLAG: + create_judge_file = "touch %s" % self.__otp_switch_reboot_judge_file + else: + create_judge_file = "touch %s" % self.__otp_other_reboot_judge_file + exec_os_cmd(create_judge_file) + exec_os_cmd("sync") + time.sleep(3) + os.system("/sbin/reboot") + except Exception as e: + fancontrol_error("%%policy: checkCritReboot failed") + fancontrol_error(str(e)) + + def checkTempRebootEmerg(self): + try: + if self.is_temp_emergency(): + temp_emerg_reboot_flag = False + for temp_list in self.__check_temp_emergency_reboot: + for temp in temp_list: + tmp = self.__temps_threshold_config.get(temp) + if tmp['emergency_flag'] is False: + fancontrol_debug("temp_list %s, temp: %s not emergency" % (temp_list, temp)) + temp_emerg_reboot_flag = False + break + temp_emerg_reboot_flag = True + if temp_emerg_reboot_flag is True: + fancontrol_debug("temp_list %s, all temp is over emergency reboot" % temp_list) + return True + except Exception as e: + fancontrol_error("%%policy: checkTempRebootEmerg failed") + fancontrol_error(str(e)) + return False + + def checkEmergReboot(self): + try: + reboot_flag = False + if self.checkTempRebootEmerg() is True: + self.set_all_fan_speed_pwm(self.__max_pwm) + for i in range(self.__check_emerg_reboot_num): + time.sleep(self.__check_emerg_sleep_time) + self.get_monitor_temp() + if self.checkTempRebootEmerg() is True: + fancontrol_emerg("%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot emergency value lasts for %d seconds." % + (self.__check_emerg_sleep_time * (i + 1))) + reboot_flag = True + continue + fancontrol_debug("The temperature of device is not over reboot emergency value.") + reboot_flag = False + break + if reboot_flag is True: + fancontrol_emerg( + "%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot emergency value, system is going to reboot now.") + for temp_threshold in self.__temps_threshold_config.values(): + fancontrol_emerg( + "%%FANCONTROL-0-TEMP_EMERG: %s temperature: %sC." % + (temp_threshold['name'], temp_threshold['temp'])) + create_judge_file = "touch %s" % OTP_SWITCH_REBOOT_JUDGE_FILE + exec_os_cmd(create_judge_file) + exec_os_cmd("sync") + time.sleep(3) + os.system("/sbin/reboot") + except Exception as e: + fancontrol_error("%%policy: checkEmergReboot failed") + fancontrol_error(str(e)) + + def get_fan_total_number(self): + return self.int_case.get_fan_total_number() + + def get_rotor_number(self, fan_name): + return self.int_case.get_fan_rotor_number(fan_name) + + def get_fan_presence(self, fan_name): + return self.int_case.get_fan_presence(fan_name) + + def get_fan_rotor_status(self, fan_name, rotor_name): + return self.int_case.get_fan_rotor_status(fan_name, rotor_name) + + def get_psu_total_number(self): + return self.int_case.get_psu_total_number() + + def get_psu_presence(self, psu_name): + return self.int_case.get_psu_presence(psu_name) + + def get_psu_input_output_status(self, psu_name): + return self.int_case.get_psu_input_output_status(psu_name) + + def checkFanPresence(self): + absent_num = 0 + + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + rotor_num = self.get_rotor_number(fan_name) + tmp_fan = self.__fan_rotor_error_num.get(fan_name) + status = self.get_fan_presence(fan_name) + if status is False: + absent_num = absent_num + 1 + self.__fan_present_status[fan_name] = 0 + fancontrol_debug("%s absent" % fan_name) + else: + if self.__fan_present_status[fan_name] == 0: # absent -> present + self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN + self.__fan_plug_in_countdown = self.__fan_plug_in_default_countdown + self.__fan_repair_flag[fan_name] = 1 + for j in range(rotor_num): + rotor_name = "Rotor" + str(j + 1) + tmp_fan[rotor_name] = 0 + self.__fan_present_status[fan_name] = 1 + fancontrol_debug("%s presence" % fan_name) + return absent_num + + def checkFanRotorStatus(self): + err_num = 0 + self.__fan_nok_num = 0 + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + rotor_num = self.get_rotor_number(fan_name) + tmp_fan = self.__fan_rotor_error_num.get(fan_name) + fan_rotor_err_cnt = 0 + for j in range(rotor_num): + rotor_name = "Rotor" + str(j + 1) + status = self.get_fan_rotor_status(fan_name, rotor_name) + if status is True: + tmp_fan[rotor_name] = 0 + fancontrol_debug("%s %s ok" % (fan_name, rotor_name)) + else: + tmp_fan[rotor_name] += 1 + if tmp_fan[rotor_name] >= self.__rotor_error_count: + err_num = err_num + 1 + fan_rotor_err_cnt += 1 + fancontrol_debug("%s %s error" % (fan_name, rotor_name)) + fancontrol_debug("%s %s error %d times" % (fan_name, rotor_name, tmp_fan[rotor_name])) + if fan_rotor_err_cnt == 0: + self.__fan_rotate_status[fan_name] = 1 # FAN is ok + else: + self.__fan_rotate_status[fan_name] = 0 # FAN is not ok + self.__fan_nok_num += 1 + fancontrol_debug("fan not ok number:%d." % self.__fan_nok_num) + return err_num + + def checkPsuPresence(self): + absent_num = 0 + psu_num = self.get_psu_total_number() + for i in range(psu_num): + psu_name = "PSU" + str(i + 1) + status = self.get_psu_presence(psu_name) + if status is False: + absent_num = absent_num + 1 + fancontrol_debug("%s absent" % psu_name) + else: + fancontrol_debug("%s presence" % psu_name) + return absent_num + + def checkPsuStatus(self): + err_num = 0 + psu_num = self.get_psu_total_number() + for i in range(psu_num): + psu_name = "PSU" + str(i + 1) + status = self.get_psu_input_output_status(psu_name) + if status is False: + err_num = err_num + 1 + fancontrol_debug("%s error" % psu_name) + else: + fancontrol_debug("%s ok" % psu_name) + return err_num + + def checkDevError(self): + pwm = self.__min_pwm + switchtemp = self.__temps_threshold_config.get(SWITCH_TEMP)['temp'] + inlettemp = self.__temps_threshold_config.get(INLET_TEMP)['temp'] + temp_diff = abs(switchtemp - inlettemp) + fancontrol_debug("|switchtemp - inlettemp| = %d" % temp_diff) + if temp_diff >= self.__inlet_mac_diff: + fancontrol_debug("temp_diff is over than inlet_mac_diff(%d)" % self.__inlet_mac_diff) + if self.__pwm > self.__abnormal_pwm: + pwm = self.__max_pwm + else: + pwm = self.__abnormal_pwm + return pwm + + def checktempfail(self): + pwm = self.__min_pwm + for temp in self.__check_temp_fail: + temp_name = temp.get("temp_name") + temp_fail_num = self.__temps_threshold_config.get(temp_name)['fail_num'] + if temp_fail_num >= self.__temp_fail_num: + pwm = self.__abnormal_pwm + fancontrol_debug("%s temp_fail_num = %d" % (temp_name, temp_fail_num)) + fancontrol_debug("self.__temp_fail_num = %d" % self.__temp_fail_num) + return pwm + + def abnormal_check(self): + pwm_list = [] + pwm_min = self.__min_pwm + pwm_list.append(pwm_min) + + if self.__check_temp_emergency == 1: + status = self.checkTempEmergency() + if status is True: + over_emerg_pwm = self.__max_pwm + pwm_list.append(over_emerg_pwm) + fancontrol_debug("over_emerg_pwm = 0x%x" % over_emerg_pwm) + # do reset check + if self.__check_emerg_reboot_flag == 1: + self.checkEmergReboot() + else: + if self.checkTempEmergencyCountdown() is True: # temp lower than emergency in 5 min + over_emerg_countdown_pwm = self.__max_pwm + pwm_list.append(over_emerg_countdown_pwm) + fancontrol_debug("TempEmergencyCountdown: %d, over_emerg_countdown_pwm = 0x%x" % + (self.__emergency_countdown, over_emerg_countdown_pwm)) + + if self.__check_temp_critical == 1: + status = self.checkTempCritical() + if status is True: + over_crit_pwm = self.__max_pwm + pwm_list.append(over_crit_pwm) + fancontrol_debug("over_crit_pwm = 0x%x" % over_crit_pwm) + # do reset check + if self.__check_crit_reboot_flag == 1: + self.checkCritReboot() + else: + if self.checkTempCriticalCountdown() is True: # temp lower than critical in 5 min + over_crit_countdown_pwm = self.__max_pwm + pwm_list.append(over_crit_countdown_pwm) + fancontrol_debug("TempCriticalCountdown: %d, over_crit_countdown_pwm = 0x%x" % + (self.__critical_countdown, over_crit_countdown_pwm)) + + if self.__check_temp_warning == 1: + status = self.checkTempWarning() + if status is True: + over_warn_pwm = self.__warning_pwm + pwm_list.append(over_warn_pwm) + fancontrol_debug("over_warn_pwm = 0x%x" % over_warn_pwm) + else: + if self.checkTempWarningCountdown() is True: # temp lower than warning in 5 min + over_warn_countdown_pwm = self.__warning_pwm + pwm_list.append(over_warn_countdown_pwm) + fancontrol_debug("TempWarningCountdown: %d, over_warn_countdown_pwm = 0x%x" % + (self.__warning_countdown, over_warn_countdown_pwm)) + + self.__fan_absent_num = self.checkFanPresence() + if self.__fan_absent_num >= self.__fan_absent_fullspeed_num: + fan_absent_pwm = self.__max_pwm + pwm_list.append(fan_absent_pwm) + fancontrol_debug("fan_absent_pwm = 0x%x" % fan_absent_pwm) + + rotor_err_num = self.checkFanRotorStatus() + if rotor_err_num >= self.__rotor_error_fullspeed_num: + rotor_err_pwm = self.__max_pwm + pwm_list.append(rotor_err_pwm) + fancontrol_debug("rotor_err_pwm = 0x%x" % rotor_err_pwm) + + psu_absent_num = self.checkPsuPresence() + if psu_absent_num >= self.__psu_absent_fullspeed_num: + psu_absent_pwm = self.__max_pwm + pwm_list.append(psu_absent_pwm) + fancontrol_debug("psu_absent_pwm = 0x%x" % psu_absent_pwm) + + dev_err_pwm = self.checkDevError() + pwm_list.append(dev_err_pwm) + fancontrol_debug("dev_err_pwm = 0x%x" % dev_err_pwm) + + temp_fail_pwm = self.checktempfail() + pwm_list.append(temp_fail_pwm) + fancontrol_debug("temp_fail_pwm = 0x%x" % temp_fail_pwm) + + pwm = max(pwm_list) + return pwm + + def get_error_fan(self): + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + if self.__fan_rotate_status[fan_name] == 0: + return fan_name + return None + + def fan_error_update_pwm(self, fan_pwm_dict): + try: + fancontrol_debug("enter deal fan error policy") + ori_fan_pwm_dict = fan_pwm_dict.copy() + + err_fan_name = self.get_error_fan() + if err_fan_name is None: + fancontrol_debug("fan name is None, do nothing.") + return ori_fan_pwm_dict + + if self.__fan_repair_flag[err_fan_name] == 0: + fancontrol_debug("%s already repaired, do nothing." % err_fan_name) + return ori_fan_pwm_dict + + if self.__pre_fan_nok != err_fan_name: + fancontrol_debug( + "not ok fan change from %s to %s, update countdown." % + (self.__pre_fan_nok, err_fan_name)) + self.__deal_fan_error_countdown = self.__deal_fan_error_default_countdown + if self.__pre_fan_nok != PRE_FAN_NOK_UNKNOWN: + fancontrol_debug( + "%s repaire success, %s NOT OK, try to repaire." % + (self.__pre_fan_nok, err_fan_name)) + self.__fan_repair_flag[self.__pre_fan_nok] = 0 + self.__pre_fan_nok = err_fan_name + + if self.__deal_fan_error_countdown > 0: + self.__deal_fan_error_countdown -= 1 + fancontrol_debug("%s repaire, countdown %d." % (err_fan_name, self.__deal_fan_error_countdown)) + + if self.__deal_fan_error_countdown == 0: + self.__fan_repair_flag[err_fan_name] = 0 + fancontrol_debug("%s set repaire fail flag, use origin pwm." % err_fan_name) + return ori_fan_pwm_dict + + fan_err_pwm_conf_list = self.__deal_fan_error_conf[err_fan_name] + for item in fan_err_pwm_conf_list: + fan_pwm_dict[item["name"]] = item["pwm"] + fancontrol_debug("fan pwm update, fan pwm dict:%s" % fan_pwm_dict) + + return fan_pwm_dict + except Exception as e: + fancontrol_error("%%policy: deal_fan_error raise Exception:%s" % str(e)) + self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN + return ori_fan_pwm_dict + + def get_fan_pwm_dict(self, default_pwm): + fan_pwm_dict = {} + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + fan_pwm_dict[fan_name] = default_pwm + if self.__deal_fan_error_policy: + if self.__fan_absent_num == 0 and self.__fan_nok_num == 1: + fan_pwm_dict = self.fan_error_update_pwm(fan_pwm_dict) + else: + if self.__pre_fan_nok != PRE_FAN_NOK_UNKNOWN and self.__fan_rotate_status[self.__pre_fan_nok] == 1: + fancontrol_debug("%s repaire success." % (self.__pre_fan_nok)) + self.__fan_repair_flag[self.__pre_fan_nok] = 0 + self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN + return fan_pwm_dict + + def get_psu_pwm_dict(self, default_pwm): + psu_pwm_dict = {} + psu_num = self.get_psu_total_number() + for i in range(psu_num): + psu_name = "PSU" + str(i + 1) + psu_pwm_dict[psu_name] = default_pwm + return psu_pwm_dict + + def check_board_air_flow(self): + board_air_flow = self.board_air_flow + air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) + if board_air_flow not in air_flow_tuple: + fanairflow_debug("get board air flow error, value [%s]" % board_air_flow) + return False + fanairflow_debug("board air flow check ok: %s" % board_air_flow) + return True + + def check_fan_air_flow(self): + if self.fan_air_flow_monitor: + fanairflow_debug("open air flow monitor, check fan air flow") + ret = self.check_board_air_flow() + if ret is False: + fanairflow_debug("get board air flow error, set fan_air_flow_inconsistent_flag False") + self.fan_air_flow_inconsistent_flag = False + return + air_flow_inconsistent_flag_tmp = False + for fan_obj in self.fan_obj_list: + fan_obj.update_fru_info() + fanairflow_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % + (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow)) + if fan_obj.air_flow == self.na_ret: + fanairflow_debug("%s get air flow failed, set air_flow_inconsistent flag False" % fan_obj.name) + fan_obj.air_flow_inconsistent = False + continue + if fan_obj.air_flow != self.board_air_flow: + fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], fan air flow [%s], board air flow [%s]" % + (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) + air_flow_inconsistent_flag_tmp = True + fan_obj.air_flow_inconsistent = True + else: + fanairflow_debug("%s air flow check ok, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s]" % + (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) + fan_obj.air_flow_inconsistent = False + self.fan_air_flow_inconsistent_flag = air_flow_inconsistent_flag_tmp + else: + fanairflow_debug("air flow monitor not open, set fan_air_flow_inconsistent_flag False") + self.fan_air_flow_inconsistent_flag = False + return + + def check_psu_air_flow(self): + if self.psu_air_flow_monitor: + fanairflow_debug("open air flow monitor, check psu air flow") + ret = self.check_board_air_flow() + if ret is False: + fanairflow_debug("get board air flow error, set psu_air_flow_inconsistent_flag False") + self.psu_air_flow_inconsistent_flag = False + return + air_flow_inconsistent_flag_tmp = False + for psu_obj in self.psu_obj_list: + psu_obj.update_fru_info() + fanairflow_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % + (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow)) + if psu_obj.air_flow == self.na_ret: + fanairflow_debug("%s get air flow failed, set air_flow_inconsistent flag False" % psu_obj.name) + psu_obj.air_flow_inconsistent = False + continue + if psu_obj.air_flow != self.board_air_flow: + fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], psu air flow [%s], board air flow [%s]" % + (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) + air_flow_inconsistent_flag_tmp = True + psu_obj.air_flow_inconsistent = True + else: + fanairflow_debug("%s air flow check ok, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s]" % + (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) + psu_obj.air_flow_inconsistent = False + self.psu_air_flow_inconsistent_flag = air_flow_inconsistent_flag_tmp + else: + fanairflow_debug("air flow monitor not open, set psu_air_flow_inconsistent_flag False") + self.psu_air_flow_inconsistent_flag = False + return + + def do_fancontrol(self): + pwm_list = [] + pwm_min = self.__min_pwm + pwm_list.append(pwm_min) + + # first check air flow + self.check_fan_air_flow() + self.check_psu_air_flow() + if self.fan_air_flow_inconsistent_flag is True or self.psu_air_flow_inconsistent_flag is True: + self.air_flow_inconsistent_flag = True + else: + self.air_flow_inconsistent_flag = False + fanairflow_debug("check_air_flow, air_flow_inconsistent_flag: %s" % self.air_flow_inconsistent_flag) + # get_monitor_temp + self.get_monitor_temp() + fancontrol_debug("last_pwm = 0x%x" % self.__pwm) + # openloop + inlettemp = self.__temps_threshold_config.get(INLET_TEMP)['temp'] + linear_value = self.openloop.linear_cacl(inlettemp) + if linear_value is None: + linear_value = self.__min_pwm + pwm_list.append(linear_value) + fancontrol_debug("linear_value = 0x%x" % linear_value) + + curve_value = self.openloop.curve_cacl(inlettemp) + if curve_value is None: + curve_value = self.__min_pwm + pwm_list.append(curve_value) + fancontrol_debug("curve_value = 0x%x" % curve_value) + + # hyst + for hyst_index in self.__hyst_config.values(): + temp_name = hyst_index.get("name") + hyst_flag = hyst_index.get("flag", 0) + if hyst_flag == 0: + fancontrol_debug("%s hyst flag is 0, do nothing" % temp_name) + continue + tmp_temp = int(self.__temps_threshold_config.get(temp_name)['temp']) # make sure temp is int + hyst_value = self.hyst.cacl(temp_name, tmp_temp) + if hyst_value is None: + hyst_value = self.__min_pwm + pwm_list.append(hyst_value) + fancontrol_debug("%s hyst_value = 0x%x" % (temp_name, hyst_value)) + + # pid + for pid_index in self.__pid_config.values(): + temp_name = pid_index.get("name") + pid_flag = pid_index.get("flag", 0) + if pid_flag == 0: + fancontrol_debug("%s pid flag is 0, do nothing" % temp_name) + continue + tmp_temp = self.__temps_threshold_config.get(temp_name)['temp'] + if tmp_temp is not None: + tmp_temp = int(tmp_temp) # make sure temp is int + invalid_temp_val = self.__temps_threshold_config.get(temp_name)['invalid'] + error_temp_val = self.__temps_threshold_config.get(temp_name)['error'] + if tmp_temp == invalid_temp_val: # temp is invalid + temp = None + self.pid.cacl(self.__pwm, temp_name, temp) # temp invalid, PID need to record None + pid_value = self.__temp_invalid_pid_pwm + fancontrol_debug("%s is invalid, pid_value = 0x%x" % (temp_name, pid_value)) + fancontrol_debug("temp = %d, invalid_temp = %d" % (tmp_temp, invalid_temp_val)) + elif tmp_temp == error_temp_val: # temp is error + temp = None + self.pid.cacl(self.__pwm, temp_name, temp) # temp error, PID need to record None + pid_value = self.__temp_error_pid_pwm + fancontrol_debug("%s is error, pid_value = 0x%x" % (temp_name, pid_value)) + fancontrol_debug("temp = %d, error_temp = %d" % (tmp_temp, error_temp_val)) + else: + pid_value = self.pid.cacl(self.__pwm, temp_name, tmp_temp) + else: # temp get failed + pid_value = self.pid.cacl(self.__pwm, temp_name, tmp_temp) + if pid_value is None: + pid_value = self.__min_pwm + pwm_list.append(pid_value) + fancontrol_debug("%s pid_value = 0x%x" % (temp_name, pid_value)) + + # abnormal + abnormal_value = self.abnormal_check() + pwm_list.append(abnormal_value) + fancontrol_debug("abnormal_value = 0x%x" % abnormal_value) + + if self.__fan_plug_in_countdown > 0 and self.__fan_absent_num == 0: + fancontrol_debug("fan plug in countdown %d, set plug in pwm: 0x%x" % + (self.__fan_plug_in_countdown, self.__fan_plug_in_pwm)) + self.__pwm = self.__fan_plug_in_pwm + self.__fan_plug_in_countdown -= 1 + else: + self.__pwm = max(pwm_list) + fancontrol_debug("__pwm = 0x%x\n" % self.__pwm) + if self.air_flow_inconsistent_flag is True: + fanairflow_debug("air flow inconsistent, set all fan speed pwm") + self.set_all_fan_speed_pwm(self.__pwm) + else: + fanairflow_debug("air flow consistent, deal fan error policy") + fan_pwm_dict = self.get_fan_pwm_dict(self.__pwm) + psu_pwm_dict = self.get_psu_pwm_dict(self.__pwm) + self.set_fan_pwm_independent(fan_pwm_dict, psu_pwm_dict) + + def run(self): + start_time = time.time() + while True: + try: + debug_init() + if self.__fan_status_interval > 0 and self.__fan_status_interval < self.__interval: + delta_time = time.time() - start_time + if delta_time >= self.__interval or delta_time < 0: + self.do_fancontrol() + start_time = time.time() + else: + self.checkFanPresence() + time.sleep(self.__fan_status_interval) + else: + self.do_fancontrol() + time.sleep(self.__interval) + except Exception as e: + traceback.print_exc() + fancontrol_error(str(e)) + + def set_all_fan_speed_pwm(self, pwm): + fan_pwm_dict = {} + psu_pwm_dict = {} + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + fan_pwm_dict[fan_name] = pwm + + psu_num = self.get_psu_total_number() + for i in range(psu_num): + psu_name = "PSU" + str(i + 1) + psu_pwm_dict[psu_name] = pwm + self.set_fan_pwm_independent(fan_pwm_dict, psu_pwm_dict) + + def set_fan_pwm_independent(self, fan_pwm_dict, psu_pwm_dict): + if self.air_flow_inconsistent_flag is True: + for psu_obj in self.psu_obj_list: + if psu_obj.air_flow_inconsistent is True: + psu_pwm_dict[psu_obj.name] = self.air_flow_error_psu_pwm + fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s], set psu pwm: 0x%x" % + (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow, self.air_flow_error_psu_pwm)) + else: + psu_pwm_dict[psu_obj.name] = self.air_flow_correct_psu_pwm + fanairflow_debug("%s air flow correct, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s], set psu pwm: 0x%x" % + (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow, self.air_flow_correct_psu_pwm)) + + for fan_obj in self.fan_obj_list: + if fan_obj.air_flow_inconsistent is True: + fan_pwm_dict[fan_obj.name] = self.air_flow_error_fan_pwm + fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s], set fan pwm: 0x%x" % + (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow, self.air_flow_error_fan_pwm)) + else: + fan_pwm_dict[fan_obj.name] = self.air_flow_correct_fan_pwm + fanairflow_debug("%s air flow correct, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s], set fan pwm: 0x%x" % + (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow, self.air_flow_correct_fan_pwm)) + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + self.fan_set_speed_pwm_by_name(fan_name, fan_pwm_dict[fan_name]) + if self.__psu_fan_control == 1: + psu_num = self.get_psu_total_number() + for i in range(psu_num): + psu_name = "PSU" + str(i + 1) + self.psu_set_speed_pwm_by_name(psu_name, psu_pwm_dict[psu_name]) + + def fan_set_speed_pwm_by_name(self, fan_name, pwm): + duty = round(pwm * 100 / 255) + rotor_len = self.get_rotor_number(fan_name) + for i in range(rotor_len): + val = self.int_case.set_fan_speed_pwm(fan_name, i + 1, duty) + if val != 0: + fancontrol_error("%s rotor%d: %d" % (fan_name, i + 1, val)) + + def psu_set_speed_pwm_by_name(self, psu_name, pwm): + duty = round(pwm * 100 / 255) + status = self.int_case.set_psu_fan_speed_pwm(psu_name, int(duty)) + if status is not True: + fancontrol_error("set %s speed fail" % psu_name) + + def fan_obj_init(self): + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + fan_obj = DevFan(fan_name, self.int_case) + self.fan_obj_list.append(fan_obj) + fanairflow_debug("fan object initialize success") + + def psu_obj_init(self): + psu_num = self.get_psu_total_number() + for i in range(psu_num): + psu_name = "PSU" + str(i + 1) + psu_obj = DevPsu(psu_name, self.int_case) + self.psu_obj_list.append(psu_obj) + fanairflow_debug("psu object initialize success") + + +if __name__ == '__main__': + debug_init() + fancontrol_debug("enter main") + fan_control = fancontrol() + fan_control.fan_obj_init() + fan_control.psu_obj_init() + fan_control.run() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/hal_ledctrl.py b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_ledctrl.py new file mode 100755 index 000000000000..c21fd3c1f585 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_ledctrl.py @@ -0,0 +1,830 @@ +#!/usr/bin/env python3 +import time +import syslog +import traceback +from plat_hal.interface import interface +from plat_hal.baseutil import baseutil +try: + import abc +except ImportError as error: + raise ImportError(str(error) + " - required module not found") from error + +SWITCH_TEMP = "SWITCH_TEMP" +F2B_AIR_FLOW = "intake" +B2F_AIR_FLOW = "exhaust" +ONIE_E2_NAME = "ONIE_E2" + +# status +STATUS_PRESENT = "PRESENT" +STATUS_ABSENT = "ABSENT" +STATUS_OK = "OK" +STATUS_NOT_OK = "NOT OK" +STATUS_FAILED = "FAILED" +STATUS_UNKNOWN = "UNKNOWN" + +LEDCTROL_DEBUG_FILE = "/etc/.ledcontrol_debug_flag" + +LEDCTROLERROR = 1 +LEDCTROLDEBUG = 2 + +debuglevel = 0 +# led status defined +COLOR_GREEN = 1 +COLOR_AMBER = 2 +COLOR_RED = 3 +LED_STATUS_DICT = {COLOR_GREEN: "green", COLOR_AMBER: "amber", COLOR_RED: "red"} + + +def ledcontrol_debug(s): + if LEDCTROLDEBUG & debuglevel: + syslog.openlog("LEDCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def ledcontrol_error(s): + if LEDCTROLERROR & debuglevel: + syslog.openlog("LEDCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def air_flow_warn(s): + syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_WARNING, s) + + +def air_flow_error(s): + syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_ERR, s) + + +def air_flow_emerg(s): + syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_EMERG, s) + + +def debug_init(): + global debuglevel + try: + with open(LEDCTROL_DEBUG_FILE, "r") as fd: + value = fd.read() + debuglevel = int(value) + except Exception: + debuglevel = 0 + + +class DevBase(object): + __metaclass__ = abc.ABCMeta + + def __init__(self, name, air_flow_monitor): + self.__name = name + self.__air_flow_monitor = air_flow_monitor + self.present = STATUS_UNKNOWN + self.status = STATUS_UNKNOWN + self.status_summary = STATUS_UNKNOWN + self.origin_name = STATUS_UNKNOWN + self.display_name = STATUS_UNKNOWN + self.air_flow = STATUS_UNKNOWN + self.led_status = COLOR_GREEN + + @property + def name(self): + return self.__name + + @property + def air_flow_monitor(self): + return self.__air_flow_monitor + + @abc.abstractmethod + def get_present(self): + """ + Gets the present status of PSU/FAN + + Returns: + A string, e.g. 'PRESENT, ABSENT, FAILED' + """ + raise NotImplementedError + + @abc.abstractmethod + def get_status(self): + """ + Gets the status of PSU/FAN + + Returns: + A string, e.g. 'OK, NOT OK, FAILED' + """ + raise NotImplementedError + + @abc.abstractmethod + def update_dev_info(self): + """ + update status and fru info of PSU/FAN + + include present, status, status_summary, part_model_name, product_name, air_flow + """ + raise NotImplementedError + + @abc.abstractmethod + def set_module_led(self, color): + """ + set PSU/FAN module LED status + + Args: + color: A string representing the color with which to set the + PSU/FAN module LED status + + Returns: + bool: True if status LED state is set successfully, False if not + """ + raise NotImplementedError + + +class DevPsu(DevBase): + + def __init__(self, name, air_flow_monitor, hal_interface): + super(DevPsu, self).__init__(name, air_flow_monitor) + self.int_case = hal_interface + + def get_psu_presence(self): + return self.int_case.get_psu_presence(self.name) + + def get_psu_input_output_status(self): + return self.int_case.get_psu_input_output_status(self.name) + + def get_psu_fru_info(self): + return self.int_case.get_psu_fru_info(self.name) + + @property + def na_ret(self): + return self.int_case.na_ret + + def get_present(self): + try: + status = self.get_psu_presence() + if status is True: + return STATUS_PRESENT + if status is False: + return STATUS_ABSENT + except Exception as e: + ledcontrol_error("get %s present status error, msg: %s" % (self.name, str(e))) + return STATUS_FAILED + + def get_status(self): + try: + status = self.get_psu_input_output_status() + if status is True: + return STATUS_OK + if status is False: + return STATUS_NOT_OK + except Exception as e: + ledcontrol_error("get %s status error, msg: %s" % (self.name, str(e))) + return STATUS_FAILED + + def update_dev_info(self): + try: + # update status + self.present = self.get_present() + if self.present != STATUS_PRESENT: + self.status = STATUS_UNKNOWN + self.status_summary = self.present + else: + self.status = self.get_status() + self.status_summary = self.status + # update fru info if need air flow monitor + if self.air_flow_monitor: + dic = self.get_psu_fru_info() + self.origin_name = dic["PN"] + self.air_flow = dic["AirFlow"] + self.display_name = dic["DisplayName"] + except Exception as e: + ledcontrol_error("update %s info error, msg: %s" % (self.name, str(e))) + self.present = STATUS_FAILED + self.status = STATUS_FAILED + self.status_summary = STATUS_FAILED + self.origin_name = self.na_ret + self.air_flow = self.na_ret + self.display_name = self.na_ret + + def set_module_led(self, color): + """ + set PSU module LED is not support, always return True + """ + return True + + +class DevFan(DevBase): + + def __init__(self, name, air_flow_monitor, hal_interface): + super(DevFan, self).__init__(name, air_flow_monitor) + self.int_case = hal_interface + + def get_fan_rotor_number(self): + return self.int_case.get_fan_rotor_number(self.name) + + def get_fan_presence(self): + return self.int_case.get_fan_presence(self.name) + + def get_fan_rotor_status(self, rotor_name): + return self.int_case.get_fan_rotor_status(self.name, rotor_name) + + def get_fan_fru_info(self): + return self.int_case.get_fan_fru_info(self.name) + + @property + def na_ret(self): + return self.int_case.na_ret + + def get_present(self): + try: + status = self.get_fan_presence() + if status is True: + return STATUS_PRESENT + if status is False: + return STATUS_ABSENT + except Exception as e: + ledcontrol_error("get %s present status error, msg: %s" % (self.name, str(e))) + return STATUS_FAILED + + def get_status(self): + try: + rotor_num = self.get_fan_rotor_number() + err_motor_num = 0 + for j in range(rotor_num): + rotor_name = "Rotor" + str(j + 1) + roll_status = self.get_fan_rotor_status(rotor_name) + if roll_status is not True: + err_motor_num += 1 + ledcontrol_debug("%s %s error, status %s" % (self.name, rotor_name, roll_status)) + else: + ledcontrol_debug("%s %s ok" % (self.name, rotor_name)) + if err_motor_num > 0: + return STATUS_NOT_OK + return STATUS_OK + except Exception as e: + ledcontrol_error("get %s status error, msg: %s" % (self.name, str(e))) + return STATUS_FAILED + + def update_dev_info(self): + try: + # update status + self.present = self.get_present() + if self.present != STATUS_PRESENT: + self.status = STATUS_UNKNOWN + self.status_summary = self.present + else: + self.status = self.get_status() + self.status_summary = self.status + # update fru info if need air flow monitor + if self.air_flow_monitor: + dic = self.get_fan_fru_info() + self.origin_name = dic["PN"] + self.air_flow = dic["AirFlow"] + self.display_name = dic["DisplayName"] + except Exception as e: + ledcontrol_error("update %s fru info error, msg: %s" % (self.name, str(e))) + self.present = STATUS_FAILED + self.status = STATUS_FAILED + self.status_summary = STATUS_FAILED + self.origin_name = self.na_ret + self.air_flow = self.na_ret + self.display_name = self.na_ret + + def set_module_led(self, color): + ret = self.int_case.set_fan_led(self.name, color) + if ret == 0: + return True + return False + + +class ledcontrol(object): + + def __init__(self): + self.fan_obj_list = [] + self.psu_obj_list = [] + self.board_psu_led_status = COLOR_GREEN + self.board_fan_led_status = COLOR_GREEN + self.__board_air_flow = "" + self.int_case = interface() + self.__config = baseutil.get_monitor_config() + self.__temps_threshold_config = self.__config["temps_threshold"] + for temp_threshold in self.__temps_threshold_config.values(): + temp_threshold['temp'] = 0 + temp_threshold['fail_num'] = 0 + self.__ledcontrol_para = self.__config["ledcontrol_para"] + self.__interval = self.__ledcontrol_para.get("interval", 5) + self.__checkpsu = self.__ledcontrol_para.get("checkpsu", 0) + self.__checkfan = self.__ledcontrol_para.get("checkfan", 0) + self.__psu_amber_num = self.__ledcontrol_para.get("psu_amber_num") + self.__fan_amber_num = self.__ledcontrol_para.get("fan_amber_num") + self.__psu_air_flow_amber_num = self.__ledcontrol_para.get("psu_air_flow_amber_num", 0) + self.__fan_air_flow_amber_num = self.__ledcontrol_para.get("fan_air_flow_amber_num", 0) + self.__board_sys_led = self.__ledcontrol_para.get("board_sys_led", []) + self.__board_psu_led = self.__ledcontrol_para.get("board_psu_led", []) + self.__board_fan_led = self.__ledcontrol_para.get("board_fan_led", []) + self.__psu_air_flow_monitor = self.__ledcontrol_para.get("psu_air_flow_monitor", 0) + self.__fan_air_flow_monitor = self.__ledcontrol_para.get("fan_air_flow_monitor", 0) + self.__fan_mix_list = self.__ledcontrol_para.get("fan_mix_list", []) + + @property + def na_ret(self): + return self.int_case.na_ret + + @property + def checkpsu(self): + return self.__checkpsu + + @property + def checkfan(self): + return self.__checkfan + + @property + def psu_amber_num(self): + return self.__psu_amber_num + + @property + def fan_amber_num(self): + return self.__fan_amber_num + + @property + def psu_air_flow_amber_num(self): + return self.__psu_air_flow_amber_num + + @property + def fan_air_flow_amber_num(self): + return self.__fan_air_flow_amber_num + + @property + def psu_air_flow_monitor(self): + return self.__psu_air_flow_monitor + + @property + def fan_air_flow_monitor(self): + return self.__fan_air_flow_monitor + + @property + def board_sys_led(self): + return self.__board_sys_led + + @property + def board_psu_led(self): + return self.__board_psu_led + + @property + def board_fan_led(self): + return self.__board_fan_led + + @property + def fan_mix_list(self): + return self.__fan_mix_list + + @property + def interval(self): + return self.__interval + + def get_fan_total_number(self): + return self.int_case.get_fan_total_number() + + def get_psu_total_number(self): + return self.int_case.get_psu_total_number() + + def get_onie_e2_obj(self, name): + return self.int_case.get_onie_e2_obj(name) + + def set_led_color(self, led_name, color): + try: + ret = self.int_case.set_led_color(led_name, color) + except Exception as e: + ledcontrol_error("set %s led %s error, msg: %s" % (led_name, color, str(e))) + ret = False + return ret + + def set_sys_led(self, color): + for led in self.board_sys_led: + led_name = led.get("led_name") + ret = self.set_led_color(led_name, color) + if ret is True: + ledcontrol_debug("set %s success, color:%s," % (led_name, color)) + else: + ledcontrol_debug("set %s failed, color:%s," % (led_name, color)) + + def set_psu_led(self, color): + for led in self.board_psu_led: + led_name = led.get("led_name") + ret = self.set_led_color(led_name, color) + if ret is True: + ledcontrol_debug("set %s success, color:%s," % (led_name, color)) + else: + ledcontrol_debug("set %s failed, color:%s," % (led_name, color)) + + def set_fan_led(self, color): + for led in self.board_fan_led: + led_name = led.get("led_name") + ret = self.set_led_color(led_name, color) + if ret is True: + ledcontrol_debug("set %s success, color:%s," % (led_name, color)) + else: + ledcontrol_debug("set %s failed, color:%s," % (led_name, color)) + + def set_fan_module_led(self): + for fan_obj in self.fan_obj_list: + color = LED_STATUS_DICT.get(fan_obj.led_status) + ret = fan_obj.set_module_led(color) + if ret is True: + ledcontrol_debug("set %s module led success, color: %s," % (fan_obj.name, color)) + else: + ledcontrol_debug("set %s module led failed, color: %s," % (fan_obj.name, color)) + + @property + def board_air_flow(self): + air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) + if self.__board_air_flow not in air_flow_tuple: + self.__board_air_flow = self.int_case.get_device_airflow(ONIE_E2_NAME) + ledcontrol_debug("board_air_flow: %s" % self.__board_air_flow) + return self.__board_air_flow + + def update_psu_info(self): + for psu_obj in self.psu_obj_list: + psu_obj.update_dev_info() + ledcontrol_debug("%s present: [%s], status: [%s] status_summary [%s]" % + (psu_obj.name, psu_obj.present, psu_obj.status, psu_obj.status_summary)) + if psu_obj.air_flow_monitor: + ledcontrol_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % + (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow)) + + def update_fan_info(self): + for fan_obj in self.fan_obj_list: + fan_obj.update_dev_info() + ledcontrol_debug("%s present: [%s], status: [%s] status_summary [%s]" % + (fan_obj.name, fan_obj.present, fan_obj.status, fan_obj.status_summary)) + if fan_obj.air_flow_monitor: + ledcontrol_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % + (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow)) + + def get_monitor_temp(self): + sensorlist = self.int_case.get_temp_info() + + for temp_threshold in self.__temps_threshold_config.values(): + sensor = sensorlist.get(temp_threshold['name']) + if sensor["Value"] is None: + temp_threshold['fail_num'] += 1 + ledcontrol_error("get %s failed, fail_num = %d" % (temp_threshold['name'], temp_threshold['fail_num'])) + else: + temp_threshold['fail_num'] = 0 + temp_threshold.setdefault('fix', 0) + temp_threshold['temp'] = sensor["Value"] + temp_threshold['fix'] + ledcontrol_debug("%s = %d" % (temp_threshold['name'], temp_threshold['temp'])) + ledcontrol_debug("warning = %d, critical = %d" % (temp_threshold['warning'], temp_threshold['critical'])) + + def is_temp_warning(self): + warning_flag = False + for temp_threshold in self.__temps_threshold_config.values(): + if temp_threshold['temp'] >= temp_threshold['warning']: + warning_flag = True + ledcontrol_debug("%s is over warning" % temp_threshold['name']) + ledcontrol_debug( + "%s = %d, warning = %d" % + (temp_threshold['name'], + temp_threshold['temp'], + temp_threshold['warning'])) + return warning_flag + + def checkTempWarning(self): + try: + if self.is_temp_warning(): + ledcontrol_debug("temp is over warning") + return True + except Exception as e: + ledcontrol_error("%%policy: checkTempWarning failed") + ledcontrol_error(str(e)) + return False + + def is_temp_critical(self): + critical_flag = False + for temp_threshold in self.__temps_threshold_config.values(): + temp_threshold['critical_flag'] = False + if temp_threshold['temp'] >= temp_threshold['critical']: + critical_flag = True + temp_threshold['critical_flag'] = True + ledcontrol_debug("%s is over critical" % temp_threshold['name']) + ledcontrol_debug( + "%s = %d, critical = %d" % + (temp_threshold['name'], + temp_threshold['temp'], + temp_threshold['critical'])) + return critical_flag + + def checkTempCrit(self): + try: + if self.is_temp_critical(): + temp_dict = dict(self.__temps_threshold_config) + tmp = temp_dict.get(SWITCH_TEMP) + if tmp['critical_flag'] is True: + ledcontrol_debug("temp is over critical") + return True + + del temp_dict[SWITCH_TEMP] + for temp_items in temp_dict.values(): + if temp_items['critical_flag'] is False: + return False + + ledcontrol_debug("temp is over critical") + return True + except Exception as e: + ledcontrol_error("%%policy: checkTempCrit failed") + ledcontrol_error(str(e)) + return False + + def check_board_air_flow(self): + board_air_flow = self.board_air_flow + air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) + if board_air_flow not in air_flow_tuple: + air_flow_error("%%AIR_FLOW_MONITOR-3-BOARD: Get board air flow failed, value: %s." % board_air_flow) + return False + ledcontrol_debug("board air flow check ok: %s" % board_air_flow) + return True + + def get_monitor_fan_status(self): + fanerrnum = 0 + for fan_obj in self.fan_obj_list: + status = fan_obj.status_summary + ledcontrol_debug("%s status: %s" % (fan_obj.name, status)) + if status != STATUS_OK: + fan_obj.led_status = COLOR_RED + fanerrnum += 1 + else: + fan_obj.led_status = COLOR_GREEN + ledcontrol_debug("fan error number: %d" % fanerrnum) + + if fanerrnum == 0: + fan_led_status = COLOR_GREEN + elif fanerrnum <= self.fan_amber_num: + fan_led_status = COLOR_AMBER + else: + fan_led_status = COLOR_RED + ledcontrol_debug("monitor fan status, set fan led: %s" % LED_STATUS_DICT.get(fan_led_status)) + return fan_led_status + + def get_monitor_psu_status(self): + psuerrnum = 0 + for psu_obj in self.psu_obj_list: + status = psu_obj.status_summary + ledcontrol_debug("%s status: %s" % (psu_obj.name, status)) + if status != STATUS_OK: + psu_obj.led_status = COLOR_RED + psuerrnum += 1 + else: + psu_obj.led_status = COLOR_GREEN + ledcontrol_debug("psu error number: %d" % psuerrnum) + + if psuerrnum == 0: + psu_led_status = COLOR_GREEN + elif psuerrnum <= self.psu_amber_num: + psu_led_status = COLOR_AMBER + else: + psu_led_status = COLOR_RED + ledcontrol_debug("monitor psu status, set psu led: %s" % LED_STATUS_DICT.get(psu_led_status)) + return psu_led_status + + def get_monitor_fan_air_flow(self): + if self.fan_air_flow_monitor == 0: + ledcontrol_debug("fan air flow monitor not open, default green") + return COLOR_GREEN + + ret = self.check_board_air_flow() + if ret is False: + ledcontrol_debug("check board air flow error, skip fan air flow monitor.") + return COLOR_GREEN + + fan_led_status_list = [] + fan_air_flow_ok_obj_list = [] + fan_air_flow_ok_set = set() + fan_module_led_list = [] + fan_air_flow_err_num = 0 + for fan_obj in self.fan_obj_list: + if fan_obj.present != STATUS_PRESENT: + fan_module_led_list.append(COLOR_GREEN) + continue + if fan_obj.air_flow == self.na_ret: + air_flow_warn("%%AIR_FLOW_MONITOR-4-FAN: %s get air flow failed, fan model: %s, air flow: %s." % + (fan_obj.name, fan_obj.display_name, fan_obj.air_flow)) + led_status = COLOR_AMBER + fan_module_led_list.append(led_status) + elif fan_obj.air_flow != self.board_air_flow: + air_flow_emerg("%%AIR_FLOW_MONITOR-0-FAN: %s air flow error, fan model: %s, fan air flow: %s, board air flow: %s." % + (fan_obj.name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) + led_status = COLOR_RED + fan_air_flow_err_num += 1 + else: + fan_air_flow_ok_obj_list.append(fan_obj) + fan_air_flow_ok_set.add(fan_obj.origin_name) + ledcontrol_debug("%s air flow check ok, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s]" % + (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) + led_status = COLOR_GREEN + fan_module_led_list.append(led_status) + if led_status > fan_obj.led_status: + fan_obj.led_status = led_status + if len(fan_module_led_list) != 0: + fan_led_status = max(fan_module_led_list) + fan_led_status_list.append(fan_led_status) + # check fan mixing + if len(fan_air_flow_ok_set) > 1 and fan_air_flow_ok_set not in self.fan_mix_list: + for fan_obj in fan_air_flow_ok_obj_list: + air_flow_warn("%%AIR_FLOW_MONITOR-4-FAN: %s mixing, fan model: %s, air flow: %s." % + (fan_obj.name, fan_obj.origin_name, fan_obj.air_flow)) + fan_led_status = COLOR_AMBER + fan_led_status_list.append(fan_led_status) + # check fan air flow error number + if fan_air_flow_err_num == 0: + fan_led_status = COLOR_GREEN + elif fan_air_flow_err_num <= self.fan_air_flow_amber_num: + fan_led_status = COLOR_AMBER + else: + fan_led_status = COLOR_RED + fan_led_status_list.append(fan_led_status) + + fan_led_status = max(fan_led_status_list) + ledcontrol_debug("monitor fan air flow, set fan led: %s" % LED_STATUS_DICT.get(fan_led_status)) + return fan_led_status + + def get_monitor_psu_air_flow(self): + if self.psu_air_flow_monitor == 0: + ledcontrol_debug("psu air flow monitor not open, default green") + return COLOR_GREEN + + ret = self.check_board_air_flow() + if ret is False: + ledcontrol_debug("check board air flow error, skip psu air flow monitor.") + return COLOR_GREEN + + psu_led_status_list = [] + psu_module_led_list = [] + psu_air_flow_err_num = 0 + for psu_obj in self.psu_obj_list: + if psu_obj.present != STATUS_PRESENT: + psu_module_led_list.append(COLOR_GREEN) + continue + if psu_obj.air_flow == self.na_ret: + air_flow_warn("%%AIR_FLOW_MONITOR-4-PSU: %s get air flow failed, psu model: %s, air flow: %s." % + (psu_obj.name, psu_obj.display_name, psu_obj.air_flow)) + led_status = COLOR_AMBER + psu_module_led_list.append(led_status) + elif psu_obj.air_flow != self.board_air_flow: + air_flow_emerg("%%AIR_FLOW_MONITOR-0-PSU: %s air flow error, psu model: %s, psu air flow: %s, board air flow: %s." % + (psu_obj.name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) + led_status = COLOR_RED + psu_air_flow_err_num += 1 + else: + ledcontrol_debug("%s psu air flow check ok, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s]" % + (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) + led_status = COLOR_GREEN + psu_module_led_list.append(led_status) + if led_status > psu_obj.led_status: + psu_obj.led_status = led_status + + if len(psu_module_led_list) != 0: + psu_led_status = max(psu_module_led_list) + psu_led_status_list.append(psu_led_status) + + # check fan air flow error number + if psu_air_flow_err_num == 0: + psu_led_status = COLOR_GREEN + elif psu_air_flow_err_num <= self.psu_air_flow_amber_num: + psu_led_status = COLOR_AMBER + else: + psu_led_status = COLOR_RED + psu_led_status_list.append(psu_led_status) + + psu_led_status = max(psu_led_status_list) + ledcontrol_debug("monitor psu air flow, set psu led: %s" % LED_STATUS_DICT.get(psu_led_status)) + return psu_led_status + + def get_temp_sys_led_status(self): + if self.checkTempCrit() is True: + sys_led_status = COLOR_RED + elif self.checkTempWarning() is True: + sys_led_status = COLOR_AMBER + else: + sys_led_status = COLOR_GREEN + ledcontrol_debug("monitor temperature, set sys led: %s" % LED_STATUS_DICT.get(sys_led_status)) + return sys_led_status + + def get_sys_led_follow_fan_status(self): + + if self.checkfan: + sys_led_status = self.board_fan_led_status + ledcontrol_debug("sys led follow fan led, set sys led: %s" % LED_STATUS_DICT.get(sys_led_status)) + else: + sys_led_status = COLOR_GREEN + ledcontrol_debug("sys led don't follow fan led, set default green") + return sys_led_status + + def get_sys_led_follow_psu_status(self): + if self.checkpsu: + sys_led_status = self.board_psu_led_status + ledcontrol_debug("sys led follow psu led, set sys led: %s" % LED_STATUS_DICT.get(sys_led_status)) + else: + sys_led_status = COLOR_GREEN + ledcontrol_debug("sys led don't follow psu led, set default green") + return sys_led_status + + def dealSysLedStatus(self): + sys_led_status_list = [] + # get_monitor_temp + self.get_monitor_temp() + + # monitor temp get sys led status + sys_led_status = self.get_temp_sys_led_status() + sys_led_status_list.append(sys_led_status) + + # check sys led follow fan led status + sys_led_status = self.get_sys_led_follow_fan_status() + sys_led_status_list.append(sys_led_status) + + # check sys led follow psu led status + sys_led_status = self.get_sys_led_follow_psu_status() + sys_led_status_list.append(sys_led_status) + + sys_led_status = max(sys_led_status_list) + sys_led_color = LED_STATUS_DICT.get(sys_led_status) + + # set sys led + self.set_sys_led(sys_led_color) + + def dealFanLedStatus(self): + fan_led_status_list = [] + # update fan info + self.update_fan_info() + + # monitor fan status first + fan_led_status = self.get_monitor_fan_status() + fan_led_status_list.append(fan_led_status) + + # monitor fan air flow + fan_led_status = self.get_monitor_fan_air_flow() + fan_led_status_list.append(fan_led_status) + + self.board_fan_led_status = max(fan_led_status_list) + fan_led_color = LED_STATUS_DICT.get(self.board_fan_led_status) + + # set fan led + self.set_fan_led(fan_led_color) + # set fan module led + self.set_fan_module_led() + + def dealPsuLedStatus(self): + psu_led_status_list = [] + # update psu info + self.update_psu_info() + + # monitor psu status first + psu_led_status = self.get_monitor_psu_status() + psu_led_status_list.append(psu_led_status) + + # monitor psu air flow + psu_led_status = self.get_monitor_psu_air_flow() + psu_led_status_list.append(psu_led_status) + + self.board_psu_led_status = max(psu_led_status_list) + psu_led_color = LED_STATUS_DICT.get(self.board_psu_led_status) + + # set psu led + self.set_psu_led(psu_led_color) + + def do_ledcontrol(self): + self.dealPsuLedStatus() + self.dealFanLedStatus() + self.dealSysLedStatus() + + def fan_obj_init(self): + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + fan_obj = DevFan(fan_name, self.fan_air_flow_monitor, self.int_case) + self.fan_obj_list.append(fan_obj) + ledcontrol_debug("fan object initialize success") + + def psu_obj_init(self): + psu_num = self.get_psu_total_number() + for i in range(psu_num): + psu_name = "PSU" + str(i + 1) + psu_obj = DevPsu(psu_name, self.psu_air_flow_monitor, self.int_case) + self.psu_obj_list.append(psu_obj) + ledcontrol_debug("psu object initialize success") + + def run(self): + while True: + try: + debug_init() + self.do_ledcontrol() + time.sleep(self.interval) + except Exception as e: + traceback.print_exc() + ledcontrol_error(str(e)) + + +if __name__ == '__main__': + debug_init() + ledcontrol_debug("enter main") + led_control = ledcontrol() + led_control.fan_obj_init() + led_control.psu_obj_init() + led_control.run() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/hal_pltfm.py b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_pltfm.py new file mode 100755 index 000000000000..11196f507ef1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_pltfm.py @@ -0,0 +1,492 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +import inspect +import sys +import json +import time +from plat_hal.interface import interface + + +class Command(): + def __init__(self, name, f): + self.name = name + self.f = f + self.paramcount = self.f.__code__.co_argcount + + def dofun(self, args): + fn = self.f.__call__ + fn(*args) + + +class Group(): + def __init__(self, name, f): + self.groups = [] + self.commands = [] + self.name = name + self.f = f + + def add_groups(self, command): + self.groups.append(command) + + def add_commands(self, commnad): + x = Command(commnad.__name__, commnad) + self.commands.append(x) + + def find_valuebyname(self, name): + for item in self.groups: + if name == item.name: + return item + for item in self.commands: + if name == item.name: + return item + return None + + def deal(self, args): + if len(args) <= 0: + return self.print_help() + funclevel = args[0] + val = self.find_valuebyname(funclevel) + if val is None: + return self.print_help() + if isinstance(val, Command): + if len(args) < (val.paramcount + 1): + return self.print_help() + inputargs = args[1: (1 + val.paramcount)] + return val.dofun(inputargs) + if isinstance(val, Group): + args = args[1:] + return val.deal(args) + return self.print_help() + + def get_max(self, arr): + lentmp = 0 + for ar in arr: + lentmp = len(ar) if (len(ar) > lentmp) else lentmp + return lentmp + + def print_help(self): + + namesize = [] + for item in self.groups: + namesize.append(item.name) + for item in self.commands: + namesize.append(item.name) + maxvalue = self.get_max(namesize) + + if len(self.groups) > 0: + print("Groups:") + for item in self.groups: + print(" %-*s %s" % (maxvalue, item.name, item.f.__doc__ or '')) + if len(self.commands) > 0: + print("Commands:") + for item in self.commands: + print(" %-*s %s" % (maxvalue, item.name, item.f.__doc__ or '')) + + +class clival(): + @staticmethod + def Fire(val=None): + group = Group("top", 'mainlevel') + clival.iterGroup(val, group) + # context = {} + # caller = inspect.stack()[1] + # caller_frame = caller[0] + # caller_globals = caller_frame.f_globals + # caller_locals = caller_frame.f_locals + # context.update(caller_globals) + # context.update(caller_locals) + args = sys.argv[1:] + group.deal(args) + + @staticmethod + def iterGroup(val, group): + for key, item in val.items(): + if item is None: # first level + if inspect.isfunction(key): + group.add_commands(key) + else: + group1 = Group(key.__name__, key) + clival.iterGroup(item, group1) + group.add_groups(group1) + + +def psu(): + r'''test psu ''' + + +def fan(): + r'''test fan ''' + + +def sensor(): + r'''test sensor ''' + + +def dcdc(): + r'''test dcdc ''' + + +def led(): + r'''test led ''' + + +def e2(): + r'''test onie eeprom ''' + + +def temps(): + r'''test temps sensor''' + +def cpu(): + r'''test cpu''' + + +int_case = interface() + + +def get_total_number(): + r'''psu get_total_number ''' + print("=================get_total_number======================") + print(int_case.get_psu_total_number()) + + +def get_presence(): + r'''psu get_presence ''' + print("=================get_presence======================") + psus = int_case.get_psus() + for psu_item in psus: + print(psu_item.name, end=' ') + print(int_case.get_psu_presence(psu_item.name)) + + +def get_fru_info(): + r'''psu get_fru_info ''' + print("=================get_fru_info======================") + psus = int_case.get_psus() + for psu_item in psus: + print(psu_item.name, end=' ') + print(json.dumps(int_case.get_psu_fru_info(psu_item.name), ensure_ascii=False, indent=4)) + + +def get_status(): + r'''psu get_status ''' + print("=================get_status======================") + psus = int_case.get_psus() + for psu_item in psus: + print(psu_item.name, end=' ') + print(json.dumps(int_case.get_psu_status(psu_item.name), ensure_ascii=False, indent=4)) + + +def set_psu_fan_speed_pwm(realspeed): + r'''set_psu_fan_speed_pwm''' + print("=================set_psu_fan_speed_pwm======================") + psus = int_case.get_psus() + for psu_item in psus: + print(psu_item.name, end=' ') + print(int_case.set_psu_fan_speed_pwm(psu_item.name, int(realspeed))) + + +def get_psu_fan_speed_pwm(): + r'''get_psu_fan_speed_pwm''' + print("=================get_psu_fan_speed_pwm======================") + psus = int_case.get_psus() + for psu_item in psus: + print(psu_item.name, end=' ') + print(json.dumps(int_case.get_psu_fan_speed_pwm(psu_item.name))) + + +def get_psu_power_status(): + r'''psu get_psu_power_status ''' + print("=================get_psu_power_status======================") + psus = int_case.get_psus() + for psu_item in psus: + print(psu_item.name, end=' ') + print(json.dumps(int_case.get_psu_power_status(psu_item.name), ensure_ascii=False, indent=4)) + + +def get_info_all(): + r'''psu get_info_all ''' + print("=================get_info_all======================") + print(json.dumps(int_case.get_psu_info_all(), ensure_ascii=False, indent=4)) + + +def fan_get_total_number(): + print("=================get_info_all======================") + print(json.dumps(int_case.get_fan_total_number(), ensure_ascii=False, indent=4)) + + +def fan_get_rotor_number(): + r'''fan_get_rotor_number''' + print("=================fan_get_rotor_number======================") + fans = int_case.get_fans() + for fan_item in fans: + print(fan_item.name, end=' ') + print(int_case.get_fan_rotor_number(fan_item.name)) + + +def fan_get_speed(): + r'''fan_get_speed''' + print("=================fan_get_speed======================") + fans = int_case.get_fans() + for fan_item in fans: + rotors = fan_item.rotor_list + for rotor in rotors: + index = rotors.index(rotor) + print("%s rotor%d" % (fan_item.name, index + 1), end=' ') + print(int_case.get_fan_speed(fan_item.name, index + 1)) + + +def fan_get_speed_pwm(): + r'''fan_get_speed_pwm''' + print("=================fan_get_speed_pwm======================") + fans = int_case.get_fans() + for fan_item in fans: + rotors = fan_item.rotor_list + for rotor in rotors: + index = rotors.index(rotor) + print("%s rotor%d" % (fan_item.name, index + 1), end=' ') + print(int_case.get_fan_speed_pwm(fan_item.name, index + 1)) + + +def fan_set_speed_pwm(pwm): + r'''fan_set_speed_pwm''' + print("=================fan_set_speed_pwm======================") + fans = int_case.get_fans() + for fan_item in fans: + rotors = fan_item.rotor_list + for rotor in rotors: + index = rotors.index(rotor) + print("%s %s" % (fan_item.name, rotor.name), end=' ') + val = int_case.set_fan_speed_pwm(fan_item.name, index + 1, pwm) + print(val) + + +def fan_get_watchdog_status(): + r'''fan_get_watchdog_status''' + print("=================fan_get_watchdog_status======================") + print(int_case.get_fan_watchdog_status()) + + +def fan_enable_watchdog(): + r'''fan_enable_watchdog''' + print("=================fan_enable_watchdog======================") + print('enable', int_case.enable_fan_watchdog()) + + +def fan_disable_watchdog(): + r'''fan_disable_watchdog''' + print("=================fan_disable_watchdog======================") + print('disable', int_case.enable_fan_watchdog(enable=False)) + + +def fan_get_speed1(): + r'''fan_get_speed''' + print("=================fan_get_speed======================") + fans = int_case.get_fans() + for fan_item in fans: + rotors = fan_item.rotor_list + for rotor in rotors: + print("%s %s" % (fan_item.name, rotor.name), end=' ') + print(int_case.get_fan_speed(fan_item.name, rotor.name)) + + +def fan_feed_watchdog(): + r'''fan_feed_watchdog''' + print("=================fan_feed_watchdog======================") + fan_get_speed() + print(int_case.feed_fan_watchdog()) + time.sleep(2) + fan_get_speed() + + +def fan_set_led(color): + r'''fan_set_led''' + print("=================fan_set_led======================") + fans = int_case.get_fans() + for fan_item in fans: + print("%s" % fan_item.name) + print(color, int_case.set_fan_led(fan_item.name, color)) + +def fan_get_led(): + r'''fan_get_led''' + print("=================fan_get_led======================") + fans = int_case.get_fans() + for fan_item in fans: + print("%s" % fan_item.name) + print(int_case.get_fan_led(fan_item.name)) + + +def fan_get_presence(): + r'''fan_get_presence''' + print("=================fan_get_presence======================") + fans = int_case.get_fans() + for fan_item in fans: + print("%s" % fan_item.name) + print(int_case.get_fan_presence(fan_item.name)) + + +def fan_get_info(): + r'''fan_get_info''' + print("=================fan_get_info======================") + fans = int_case.get_fans() + for fan_item in fans: + print("%s" % fan_item.name) + print(json.dumps(int_case.get_fan_info(fan_item.name), ensure_ascii=False, indent=4)) + + +def fan_get_status(): + r'''fan_get_status''' + print("=================fan_get_status======================") + fans = int_case.get_fans() + for fan_item in fans: + print("%s" % fan_item.name) + print(json.dumps(int_case.get_fan_status(fan_item.name), ensure_ascii=False, indent=4)) + + +def fan_get_info_all(): + r'''fan_get_info_all''' + print("=================fan_get_info_all======================") + print(json.dumps(int_case.get_fan_info_all(), ensure_ascii=False, indent=4)) + + +def get_sensor_info(): + r'''get_sensor_info''' + print("=================get_sensor_info======================") + print(json.dumps(int_case.get_sensor_info(), ensure_ascii=False, indent=4)) + + +def get_dcdc_all_info(): + r'''get_dcdc_all_info''' + print("=================get_dcdc_all_info======================") + print(json.dumps(int_case.get_dcdc_all_info(), ensure_ascii=False, indent=4)) + + +def set_all_led_color(color): + r'''set_all_led_color color''' + print("=================set_all_led_color======================") + leds = int_case.get_leds() + for led_item in leds: + print("%s" % led_item.name) + print(color, int_case.set_led_color(led_item.name, color)) + + +def get_all_led_color(): + r'''get_all_led_color''' + print("=================get_all_led_color======================") + leds = int_case.get_leds() + for led_item in leds: + print("%s" % led_item.name) + print(int_case.get_led_color(led_item.name)) + + +def set_single_led_color(led_name, color): + r'''set_single_led_color led_name color''' + print("=================set_single_led_color======================") + leds = int_case.get_leds() + for led_item in leds: + if led_name == led_item.name: + print("%s" % led_item.name) + print(color, int_case.set_led_color(led_item.name, color)) + + +def get_single_led_color(led_name): + r'''get_single_led_color''' + print("=================get_single_led_color======================") + leds = int_case.get_leds() + for led_item in leds: + if led_name == led_item.name: + print("%s" % led_item.name) + print(int_case.get_led_color(led_item.name)) + + +def get_onie_e2_path(): + r'''get_onie_e2_path''' + print("=================get_onie_e2_path======================") + path = int_case.get_onie_e2_path("ONIE_E2") + print("%s" % path) + + +def get_device_airflow(): + r'''get_device_airflow''' + print("=================get_device_airflow======================") + airflow = int_case.get_device_airflow("ONIE_E2") + print("%s" % airflow) + + +def get_temps_sensor(): + r'''get_temps_sensor''' + print("=================get_temps_sensor======================") + temp_list = int_case.get_temps() + for temp in temp_list: + print("id: %s, name: %s, API name: %s, value: %s" % (temp.temp_id, temp.name, temp.api_name, temp.Value)) + +def get_cpu_reset_num(): + r'''get_cpu_reset_num''' + print("=================get_cpu_reset_num======================") + print(int_case.get_cpu_reset_num()) + +def get_cpu_reboot_cause(): + r'''get_cpu_reboot_cause''' + print("=================get_cpu_reboot_cause======================") + print(int_case.get_cpu_reboot_cause()) + + +def run_cli_man(): + clival.Fire( + { + psu: { + get_total_number: None, + get_presence: None, + get_fru_info: None, + set_psu_fan_speed_pwm: None, + get_psu_fan_speed_pwm: None, + get_status: None, + get_psu_power_status: None, + get_info_all: None + }, + fan: { + fan_get_total_number: None, + fan_get_rotor_number: None, + fan_get_speed: None, + fan_get_speed_pwm: None, + fan_set_speed_pwm: None, + fan_get_watchdog_status: None, + fan_enable_watchdog: None, + fan_disable_watchdog: None, + fan_feed_watchdog: None, + fan_set_led: None, + fan_get_led: None, + fan_get_presence: None, + fan_get_info: None, + fan_get_status: None, + fan_get_info_all: None + }, + sensor: { + get_sensor_info: None + }, + dcdc: { + get_dcdc_all_info: None + }, + led: { + set_all_led_color: None, + set_single_led_color: None, + get_all_led_color: None, + get_single_led_color: None, + }, + e2: { + get_onie_e2_path: None, + get_device_airflow: None, + }, + temps: { + get_temps_sensor: None, + }, + cpu: { + get_cpu_reset_num: None, + get_cpu_reboot_cause: None, + } + } + ) + + +if __name__ == '__main__': + run_cli_man() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor.py b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor.py new file mode 100755 index 000000000000..33d5bfba64e6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor.py @@ -0,0 +1,144 @@ +#!/usr/bin/python3 +# -*- coding: UTF-8 -*- + +import os +import time +import syslog +from plat_hal.interface import interface +from plat_hal.baseutil import baseutil +from platform_util import io_rd, wbi2cget + +INTELLIGENT_MONITOR_DEBUG_FILE = "/etc/.intelligent_monitor_debug" + +debuglevel = 0 + + +def monitor_syslog_debug(s): + if debuglevel: + syslog.openlog("INTELLIGENT_MONITOR_DEBUG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def monitor_syslog(s): + syslog.openlog("INTELLIGENT_MONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_WARNING, s) + + +def pmon_syslog_notice(s): + syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_NOTICE, s) + + +class IntelligentMonitor(): + def __init__(self): + self.dcdc_dict = {} + self.int_case = interface() + self.__config = baseutil.get_monitor_config() + self.__intelligent_monitor_para = self.__config.get('intelligent_monitor_para', {}) + self.__interval = self.__intelligent_monitor_para.get('interval', 60) + self.__dcdc_whitelist = self.__config.get('dcdc_monitor_whitelist', {}) + self.__error_ret = self.int_case.error_ret + + @property + def error_ret(self): + return self.__error_ret + + @property + def interval(self): + return self.__interval + + def debug_init(self): + global debuglevel + if os.path.exists(INTELLIGENT_MONITOR_DEBUG_FILE): + debuglevel = 1 + else: + debuglevel = 0 + + def dcdc_whitelist_check(self, dcdc_name): + try: + check_item = self.__dcdc_whitelist.get(dcdc_name, {}) + if len(check_item) == 0: + return False + gettype = check_item.get("gettype", None) + checkbit = check_item.get("checkbit", None) + okval = check_item.get("okval", None) + if gettype is None or checkbit is None or okval is None: + monitor_syslog('%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s config error. gettype:%s, checkbit:%s, okval:%s' % + (dcdc_name, gettype, checkbit, okval)) + return False + if gettype == "io": + io_addr = check_item.get('io_addr', None) + val = io_rd(io_addr) + if val is not None: + retval = val + else: + monitor_syslog( + '%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s io_rd error. io_addr:%s' % + (dcdc_name, io_addr)) + return False + elif gettype == "i2c": + bus = check_item.get('bus', None) + addr = check_item.get('addr', None) + offset = check_item.get('offset', None) + ind, val = wbi2cget(bus, addr, offset) + if ind is True: + retval = val + else: + monitor_syslog('%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s i2cget error. bus:%s, addr:%s, offset:%s' % + (dcdc_name, bus, addr, offset)) + return False + else: + monitor_syslog('%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s gettype not support' % dcdc_name) + return False + + val_t = (int(retval, 16) & (1 << checkbit)) >> checkbit + if val_t != okval: + return False + return True + except Exception as e: + monitor_syslog('%%WHITELIST_CHECK: %s check error, msg: %s.' % (dcdc_name, str(e))) + return False + + def update_dcdc_status(self): + try: + self.dcdc_dict = self.int_case.get_dcdc_all_info() + for dcdc_name, item in self.dcdc_dict.items(): + ret = self.dcdc_whitelist_check(dcdc_name) + if ret is False: + if item['Value'] == self.error_ret: + monitor_syslog( + '%%INTELLIGENT_MONITOR-3-DCDC_SENSOR_FAILED: The value of %s read failed.' % + (dcdc_name)) + elif float(item['Value']) > float(item['Max']): + pmon_syslog_notice('%%PMON-5-VOLTAGE_HIGH: %s voltage %.3f%s is larger than max threshold %.3f%s.' % + (dcdc_name, float(item['Value']), item['Unit'], float(item['Max']), item['Unit'])) + elif float(item['Value']) < float(item['Min']): + pmon_syslog_notice('%%PMON-5-VOLTAGE_LOW: %s voltage %.3f%s is lower than min threshold %.3f%s.' % + (dcdc_name, float(item['Value']), item['Unit'], float(item['Min']), item['Unit'])) + else: + monitor_syslog_debug('%%INTELLIGENT_MONITOR-6-DCDC_SENSOR_OK: %s normal, value is %.3f%s.' % + (dcdc_name, item['Value'], item['Unit'])) + else: + monitor_syslog_debug( + '%%INTELLIGENT_MONITOR-6-DCDC_WHITELIST_CHECK: %s is in dcdc whitelist, not monitor voltage' % + dcdc_name) + continue + except Exception as e: + monitor_syslog('%%INTELLIGENT_MONITOR-3-EXCEPTION: update dcdc sensors status error, msg: %s.' % (str(e))) + + def doWork(self): + self.update_dcdc_status() + + def run(self): + while True: + try: + self.debug_init() + self.doWork() + time.sleep(self.interval) + except Exception as e: + monitor_syslog('%%INTELLIGENT_MONITOR-3-EXCEPTION: %s.' % (str(e))) + + +if __name__ == '__main__': + intelligent_monitor = IntelligentMonitor() + intelligent_monitor.run() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor/monitor_fan.py b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor/monitor_fan.py new file mode 100755 index 000000000000..c84319f3b798 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor/monitor_fan.py @@ -0,0 +1,284 @@ +#!/usr/bin/python3 +# -*- coding: UTF-8 -*- + +import os +import time +import logging +from logging.handlers import RotatingFileHandler + +from plat_hal.interface import interface +from plat_hal.baseutil import baseutil + + +DEBUG_FILE = "/etc/.monitor_fan_debug_flag" + +LOG_FILE = "/var/log/intelligent_monitor/monitor_fan_log" + +E2_NAME = "ONIE_E2" + + +def _init_logger(): + if not os.path.exists(LOG_FILE): + os.system("mkdir -p %s" % os.path.dirname(LOG_FILE)) + os.system("sync") + handler = RotatingFileHandler(filename=LOG_FILE, maxBytes=5 * 1024 * 1024, backupCount=1) + formatter = logging.Formatter("%(asctime)s %(levelname)s %(filename)s[%(funcName)s][%(lineno)s]: %(message)s") + handler.setFormatter(formatter) + logger = logging.getLogger(__name__) + logger.setLevel(logging.INFO) + logger.addHandler(handler) + return logger + + +class Fan(object): + + def __init__(self, name, hal_interface): + self.name = name + self.fan_dict = {} + self.int_case = hal_interface + self.update_time = 0 + self.pre_present = False + self.pre_status = True + self.plugin_cnt = 0 + self.plugout_cnt = 0 + self.status_normal_cnt = 0 + self.status_error_cnt = 0 + + def fan_dict_update(self): + local_time = time.time() + if not self.fan_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds + self.update_time = local_time + self.fan_dict = self.int_case.get_fan_info(self.name) + + def get_model(self): + self.fan_dict_update() + return self.fan_dict["NAME"] + + def get_serial(self): + self.fan_dict_update() + return self.fan_dict["SN"] + + def get_presence(self): + return self.int_case.get_fan_presence(self.name) + + def get_rotor_speed(self, rotor_name): + """ + Retrieves the speed of fan as a percentage of full speed + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + fan_dir = {} + fan_dir = self.int_case.get_fan_info_rotor(self.name) + # get fan rotor pwm + value = fan_dir[rotor_name]["Speed"] + max_speed = fan_dir[rotor_name]["SpeedMax"] + + if isinstance(value, str) or value is None: + return 0 + pwm = value * 100 / max_speed + if pwm > 100: + pwm = 100 + elif pwm < 0: + pwm = 0 + return int(pwm) + + def get_rotor_speed_tolerance(self, rotor_name): + """ + Retrieves the speed tolerance of the fan + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + # The default tolerance value is fixed as 30% + fan_dir = {} + fan_dir = self.int_case.get_fan_info_rotor(self.name) + # get fan rotor tolerance + tolerance = fan_dir[rotor_name]["Tolerance"] + + if isinstance(tolerance, str) or tolerance is None: + return 30 + return tolerance + + 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) + """ + pwm = self.int_case.get_fan_speed_pwm(self.name, 0) + return int(pwm) + + def get_status(self): + """ + Retrieves the operational status of the FAN + Returns: + bool: True if FAN is operating properly, False if not + """ + if not self.get_presence(): + return False + + rotor_num = self.int_case.get_fan_rotor_number(self.name) + for i in range(rotor_num): + rotor_name = "Rotor" + str(i + 1) + speed = self.get_rotor_speed(rotor_name) + tolerance = self.get_rotor_speed_tolerance(rotor_name) + target = self.get_target_speed() + if (speed - target) > target * tolerance / 100: + return False + if (target - speed) > target * tolerance / 100: + return False + + return True + + def get_direction(self): + """ + Retrieves the fan airflow direction + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + + Notes: + - Forward/Exhaust : Air flows from Port side to Fan side. + - Reverse/Intake : Air flows from Fan side to Port side. + """ + self.fan_dict_update() + return self.fan_dict["AirFlow"] + + +class MonitorFan(object): + + def __init__(self): + self.int_case = interface() + self.logger = _init_logger() + self.fan_obj_list = [] + self.__config = baseutil.get_monitor_config() + self.__monitor_fan_config = self.__config.get("monitor_fan_para", {}) + self.__present_interval = self.__monitor_fan_config.get("present_interval", 0.5) + self.__status_interval = self.__monitor_fan_config.get("status_interval", 5) + self.__present_check_cnt = self.__monitor_fan_config.get("present_check_cnt", 3) + self.__status_check_cnt = self.__monitor_fan_config.get("status_check_cnt", 3) + + def debug_init(self): + if os.path.exists(DEBUG_FILE): + self.logger.setLevel(logging.DEBUG) + else: + self.logger.setLevel(logging.INFO) + + def get_fan_total_number(self): + return self.int_case.get_fan_total_number() + + def get_device_airflow(self): + return self.int_case.get_device_airflow(E2_NAME) + + def fan_obj_init(self): + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + fan_obj = Fan(fan_name, self.int_case) + self.fan_obj_list.append(fan_obj) + self.logger.info("fan object initialize success") + + def fan_airflow_check(self, fan_obj): + fan_airflow = fan_obj.get_direction() + device_airflow = self.get_device_airflow() + if fan_airflow != device_airflow: + self.logger.error("%s airflow[%s] not match device airflow[%s]", fan_obj.name, fan_airflow, device_airflow) + else: + self.logger.debug("%s airflow[%s] match device airflow[%s]", fan_obj.name, fan_airflow, device_airflow) + + def fan_plug_in_out_check(self, fan_obj): + present = fan_obj.get_presence() + if present is True: + self.logger.debug("%s is present", fan_obj.name) + else: + self.logger.debug("%s is absent", fan_obj.name) + + if present != fan_obj.pre_present: + if present is True: + fan_obj.plugin_cnt += 1 + fan_obj.plugout_cnt = 0 + if fan_obj.plugin_cnt >= self.__present_check_cnt: + fan_obj.pre_present = True + self.logger.info("%s [serial:%s] is plugin", fan_obj.name, fan_obj.get_serial()) + self.fan_airflow_check(fan_obj) + else: + fan_obj.plugin_cnt = 0 + fan_obj.plugout_cnt += 1 + if fan_obj.plugout_cnt >= self.__present_check_cnt: + fan_obj.pre_present = False + self.logger.info("%s is plugout", fan_obj.name) + else: + fan_obj.plugin_cnt = 0 + fan_obj.plugout_cnt = 0 + self.logger.debug("%s present status is not change", fan_obj.name) + + def fan_status_check(self, fan_obj): + status = fan_obj.get_status() + if status is True: + self.logger.debug("%s is normal", fan_obj.name) + else: + self.logger.debug("%s is error", fan_obj.name) + + if status != fan_obj.pre_status: + if status is True: + fan_obj.status_normal_cnt += 1 + fan_obj.status_error_cnt = 0 + if fan_obj.status_normal_cnt >= self.__status_check_cnt: + fan_obj.pre_status = True + self.logger.info( + "%s [serial:%s] is form error change to normal", + fan_obj.name, + fan_obj.get_serial()) + else: + fan_obj.status_normal_cnt = 0 + fan_obj.status_error_cnt += 1 + if fan_obj.status_error_cnt >= self.__status_check_cnt: + fan_obj.pre_status = False + self.logger.info( + "%s [serial:%s] is form normal change to error", + fan_obj.name, + fan_obj.get_serial()) + else: + fan_obj.status_normal_cnt = 0 + fan_obj.status_error_cnt = 0 + self.logger.debug("%s status is not change", fan_obj.name) + + def checkFanPresence(self): + for fan_obj in self.fan_obj_list: + self.fan_plug_in_out_check(fan_obj) + + def checkFanStatus(self): + for fan_obj in self.fan_obj_list: + self.fan_status_check(fan_obj) + + def run(self): + start_time = time.time() + while True: + try: + self.debug_init() + delta_time = time.time() - start_time + if self.__present_interval <= self.__status_interval: + if delta_time >= self.__status_interval or delta_time < 0: + self.checkFanStatus() + start_time = time.time() + else: + self.checkFanPresence() + time.sleep(self.__present_interval) + else: + if delta_time >= self.__present_interval or delta_time < 0: + self.checkFanPresence() + start_time = time.time() + else: + self.checkFanStatus() + time.sleep(self.__status_interval) + except Exception as e: + self.logger.error('EXCEPTION: %s.', str(e)) + + +if __name__ == '__main__': + monitor_fan = MonitorFan() + monitor_fan.fan_obj_init() + monitor_fan.run() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_common.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_common.py new file mode 100755 index 000000000000..35c16728f72c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_common.py @@ -0,0 +1,186 @@ +#!/usr/bin/python3 + +__all__ = [ + "BLACKLIST_DRIVERS", + "DRIVERLISTS", + "DEVICE", + "STARTMODULE", + "MAC_LED_RESET", + "MAC_DEFAULT_PARAM", + "DEV_MONITOR_PARAM", + "SLOT_MONITOR_PARAM", + "MANUINFO_CONF", + "REBOOT_CTRL_PARAM", + "PMON_SYSLOG_STATUS", + "OPTOE", + "REBOOT_CAUSE_PARA", + "UPGRADE_SUMMARY", + "WARM_UPGRADE_PARAM", + "WARM_UPG_FLAG", + "WARM_UPGRADE_STARTED_FLAG", + "PLATFORM_E2_CONF", + "AIR_FLOW_CONF", + "AIRFLOW_RESULT_FILE", + "INIT_PARAM_PRE", + "INIT_COMMAND_PRE", + "INIT_PARAM", + "INIT_COMMAND", + "SET_MAC_CONF", + "DRVIER_UPDATE_CONF", + "MONITOR_TEMP_MIN", + "MONITOR_K", + "MONITOR_MAC_IN", + "MONITOR_DEFAULT_SPEED", + "MONITOR_MAX_SPEED", + "MONITOR_MIN_SPEED", + "MONITOR_MAC_ERROR_SPEED", + "MONITOR_FAN_TOTAL_NUM", + "MONITOR_MAC_UP_TEMP", + "MONITOR_MAC_LOWER_TEMP", + "MONITOR_MAC_MAX_TEMP", + "MONITOR_FALL_TEMP", + "MONITOR_MAC_WARNING_THRESHOLD", + "MONITOR_OUTTEMP_WARNING_THRESHOLD", + "MONITOR_BOARDTEMP_WARNING_THRESHOLD", + "MONITOR_CPUTEMP_WARNING_THRESHOLD", + "MONITOR_INTEMP_WARNING_THRESHOLD", + "MONITOR_MAC_CRITICAL_THRESHOLD", + "MONITOR_OUTTEMP_CRITICAL_THRESHOLD", + "MONITOR_BOARDTEMP_CRITICAL_THRESHOLD", + "MONITOR_CPUTEMP_CRITICAL_THRESHOLD", + "MONITOR_INTEMP_CRITICAL_THRESHOLD", + "MONITOR_CRITICAL_NUM", + "MONITOR_SHAKE_TIME", + "MONITOR_INTERVAL", + "MONITOR_LED_INTERVAL", + "MONITOR_PID_FLAG", + "MONITOR_MAC_SOURCE_SYSFS", + "MONITOR_MAC_SOURCE_PATH", + "MONITOR_PID_MODULE", + "PSU_FAN_FOLLOW", + "MONITOR_SYS_LED", + "MONITOR_SYS_FAN_LED", + "MONITOR_FANS_LED", + "MONITOR_SYS_PSU_LED", + "MONITOR_FAN_STATUS", + "MONITOR_PSU_STATUS", + "MONITOR_DEV_STATUS", + "MONITOR_DEV_STATUS_DECODE", + "DEV_LEDS", + "fanloc" +] + +# driver blacklist parameter +BLACKLIST_DRIVERS = [] + +# driver list parameter +DRIVERLISTS = [] + +# device list parameter +DEVICE = [] + +# start module parameters +STARTMODULE = {} + +# mac led reset parameter +MAC_LED_RESET = {} + +# avscontrol parameter +MAC_DEFAULT_PARAM = [] + +# dev_monitor parameter +DEV_MONITOR_PARAM = {} + +# slot_monitor parameter +SLOT_MONITOR_PARAM = {} + +# platform_manufacturer parameter +MANUINFO_CONF = {} + +# reboot_ctrl parameter +REBOOT_CTRL_PARAM = {} + +# pmon_syslog parameter +PMON_SYSLOG_STATUS = {} + +# sfp optoe device parameter +OPTOE = [] + +# reboot_cause parameter +REBOOT_CAUSE_PARA = [] + +# upgrade parameter +UPGRADE_SUMMARY = {} + +# warm_uprade parameter +WARM_UPGRADE_PARAM = {} +WARM_UPG_FLAG = "/etc/sonic/.warm_upg_flag" +WARM_UPGRADE_STARTED_FLAG = "/etc/sonic/.doing_warm_upg" + +# platform_e2 parameter +PLATFORM_E2_CONF = {} + +# generate_airflow parameter +AIR_FLOW_CONF = {} +AIRFLOW_RESULT_FILE = "/etc/sonic/.airflow" + +# Initialization parameters +INIT_PARAM_PRE = [] +INIT_COMMAND_PRE = [] +INIT_PARAM = [] +INIT_COMMAND = [] + +# Set eth mac address parameters +SET_MAC_CONF = [] + +# driver update config +DRVIER_UPDATE_CONF = {} + +################################ fancontrol parameter################################### +MONITOR_TEMP_MIN = 38 +MONITOR_K = 11 +MONITOR_MAC_IN = 35 +MONITOR_DEFAULT_SPEED = 0x60 +MONITOR_MAX_SPEED = 0xFF +MONITOR_MIN_SPEED = 0x60 +MONITOR_MAC_ERROR_SPEED = 0XBB +MONITOR_FAN_TOTAL_NUM = 4 +MONITOR_MAC_UP_TEMP = 50 +MONITOR_MAC_LOWER_TEMP = -50 +MONITOR_MAC_MAX_TEMP = 100 # + +MONITOR_FALL_TEMP = 4 +MONITOR_MAC_WARNING_THRESHOLD = 100 +MONITOR_OUTTEMP_WARNING_THRESHOLD = 85 +MONITOR_BOARDTEMP_WARNING_THRESHOLD = 85 +MONITOR_CPUTEMP_WARNING_THRESHOLD = 85 +MONITOR_INTEMP_WARNING_THRESHOLD = 70 + +MONITOR_MAC_CRITICAL_THRESHOLD = 105 +MONITOR_OUTTEMP_CRITICAL_THRESHOLD = 90 +MONITOR_BOARDTEMP_CRITICAL_THRESHOLD = 90 +MONITOR_CPUTEMP_CRITICAL_THRESHOLD = 100 +MONITOR_INTEMP_CRITICAL_THRESHOLD = 80 +MONITOR_CRITICAL_NUM = 3 +MONITOR_SHAKE_TIME = 20 +MONITOR_INTERVAL = 60 +MONITOR_LED_INTERVAL = 2 +MONITOR_PID_FLAG = 0 + +MONITOR_MAC_SOURCE_SYSFS = 0 +MONITOR_MAC_SOURCE_PATH = None + +MONITOR_PID_MODULE = {} + +PSU_FAN_FOLLOW = {} + +MONITOR_SYS_LED = [] +MONITOR_SYS_FAN_LED = [] +MONITOR_FANS_LED = [] +MONITOR_SYS_PSU_LED = [] +MONITOR_FAN_STATUS = [] +MONITOR_PSU_STATUS = [] +MONITOR_DEV_STATUS = {} +MONITOR_DEV_STATUS_DECODE = {} +DEV_LEDS = {} +fanloc = [] diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_config.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_config.py new file mode 100755 index 000000000000..d6b3151e47cf --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_config.py @@ -0,0 +1,192 @@ +#!/usr/bin/python3 + +import sys +import os +from wbutil.baseutil import get_machine_info +from wbutil.baseutil import get_platform_info +from wbutil.baseutil import get_board_id + +__all__ = [ + "MAILBOX_DIR", + "PLATFORM_GLOBALCONFIG", + "GLOBALCONFIG", + "STARTMODULE", + "MAC_LED_RESET", + "MAC_DEFAULT_PARAM", + "DEV_MONITOR_PARAM", + "SLOT_MONITOR_PARAM", + "MANUINFO_CONF", + "REBOOT_CTRL_PARAM", + "PMON_SYSLOG_STATUS", + "REBOOT_CAUSE_PARA", + "UPGRADE_SUMMARY", + "WARM_UPGRADE_PARAM", + "WARM_UPG_FLAG", + "WARM_UPGRADE_STARTED_FLAG", + "PLATFORM_E2_CONF", + "AIR_FLOW_CONF", + "AIRFLOW_RESULT_FILE", + "GLOBALINITPARAM", + "GLOBALINITCOMMAND", + "GLOBALINITPARAM_PRE", + "GLOBALINITCOMMAND_PRE", + "SET_MAC_CONF", + "DRVIER_UPDATE_CONF", + "MONITOR_CONST", + "PSU_FAN_FOLLOW", + "MONITOR_SYS_LED", + "MONITOR_FANS_LED", + "MONITOR_SYS_FAN_LED", + "MONITOR_SYS_PSU_LED", + "MONITOR_FAN_STATUS", + "MONITOR_PSU_STATUS", + "MONITOR_DEV_STATUS", + "MONITOR_DEV_STATUS_DECODE", + "DEV_LEDS", + "fanloc" +] + + +def getdeviceplatform(): + x = get_platform_info(get_machine_info()) + if x is not None: + filepath = "/usr/share/sonic/device/" + x + return filepath + return None + + +platform = get_platform_info(get_machine_info()) +board_id = get_board_id(get_machine_info()) +platformpath = getdeviceplatform() +MAILBOX_DIR = "/sys/bus/i2c/devices/" +grtd_productfile = (platform + "_config").replace("-", "_") +common_productfile = "platform_common" +platform_configfile = (platform + "_" + board_id + "_config").replace("-", "_") # platfrom + board_id +configfile_pre = "/usr/local/bin/" +sys.path.append(platformpath) +sys.path.append(configfile_pre) + +############################################################################################ +if os.path.exists(configfile_pre + platform_configfile + ".py"): + module_product = __import__(platform_configfile, globals(), locals(), [], 0) +elif os.path.exists(configfile_pre + grtd_productfile + ".py"): + module_product = __import__(grtd_productfile, globals(), locals(), [], 0) +elif os.path.exists(configfile_pre + common_productfile + ".py"): + module_product = __import__(common_productfile, globals(), locals(), [], 0) +else: + print("config file not exist") + sys.exit(-1) +############################################################################################ + +PLATFORM_GLOBALCONFIG = { + "DRIVERLISTS": module_product.DRIVERLISTS, + "OPTOE": module_product.OPTOE, + "DEVS": module_product.DEVICE, + "BLACKLIST_DRIVERS": module_product.BLACKLIST_DRIVERS +} +GLOBALCONFIG = PLATFORM_GLOBALCONFIG + +# start module parameters +STARTMODULE = module_product.STARTMODULE + +# mac led reset parameter +MAC_LED_RESET = module_product.MAC_LED_RESET + +# avscontrol parameter +MAC_DEFAULT_PARAM = module_product.MAC_DEFAULT_PARAM + +# dev_monitor parameter +DEV_MONITOR_PARAM = module_product.DEV_MONITOR_PARAM + +# slot_monitor parameter +SLOT_MONITOR_PARAM = module_product.SLOT_MONITOR_PARAM + +# platform_manufacturer parameter +MANUINFO_CONF = module_product.MANUINFO_CONF + +# reboot_ctrl parameter +REBOOT_CTRL_PARAM = module_product.REBOOT_CTRL_PARAM + +# pmon_syslog parameter +PMON_SYSLOG_STATUS = module_product.PMON_SYSLOG_STATUS + +# reboot_cause parameter +REBOOT_CAUSE_PARA = module_product.REBOOT_CAUSE_PARA + +# upgrade parameter +UPGRADE_SUMMARY = module_product.UPGRADE_SUMMARY + +# warm_uprade parameter +WARM_UPGRADE_PARAM = module_product.WARM_UPGRADE_PARAM +WARM_UPG_FLAG = module_product.WARM_UPG_FLAG +WARM_UPGRADE_STARTED_FLAG = module_product.WARM_UPGRADE_STARTED_FLAG + +# platform_e2 parameter +PLATFORM_E2_CONF = module_product.PLATFORM_E2_CONF + +# generate_airflow parameter +AIR_FLOW_CONF = module_product.AIR_FLOW_CONF +AIRFLOW_RESULT_FILE = module_product.AIRFLOW_RESULT_FILE + +# Initialization parameters +GLOBALINITPARAM = module_product.INIT_PARAM +GLOBALINITCOMMAND = module_product.INIT_COMMAND +GLOBALINITPARAM_PRE = module_product.INIT_PARAM_PRE +GLOBALINITCOMMAND_PRE = module_product.INIT_COMMAND_PRE + +# Set eth mac address parameters +SET_MAC_CONF = module_product.SET_MAC_CONF + +# driver update config +DRVIER_UPDATE_CONF = module_product.DRVIER_UPDATE_CONF + +################################ fancontrol parameter################################### + + +class MONITOR_CONST: + TEMP_MIN = module_product.MONITOR_TEMP_MIN + K = module_product.MONITOR_K + MAC_IN = module_product.MONITOR_MAC_IN + DEFAULT_SPEED = module_product.MONITOR_DEFAULT_SPEED + MAX_SPEED = module_product.MONITOR_MAX_SPEED + MIN_SPEED = module_product.MONITOR_MIN_SPEED + MAC_ERROR_SPEED = module_product.MONITOR_MAC_ERROR_SPEED + FAN_TOTAL_NUM = module_product.MONITOR_FAN_TOTAL_NUM + MAC_UP_TEMP = module_product.MONITOR_MAC_UP_TEMP + MAC_LOWER_TEMP = module_product.MONITOR_MAC_LOWER_TEMP + MAC_MAX_TEMP = module_product.MONITOR_MAC_MAX_TEMP + + MAC_WARNING_THRESHOLD = module_product.MONITOR_MAC_WARNING_THRESHOLD + OUTTEMP_WARNING_THRESHOLD = module_product.MONITOR_OUTTEMP_WARNING_THRESHOLD + BOARDTEMP_WARNING_THRESHOLD = module_product.MONITOR_BOARDTEMP_WARNING_THRESHOLD + CPUTEMP_WARNING_THRESHOLD = module_product.MONITOR_CPUTEMP_WARNING_THRESHOLD + INTEMP_WARNING_THRESHOLD = module_product.MONITOR_INTEMP_WARNING_THRESHOLD + + MAC_CRITICAL_THRESHOLD = module_product.MONITOR_MAC_CRITICAL_THRESHOLD + OUTTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_OUTTEMP_CRITICAL_THRESHOLD + BOARDTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_BOARDTEMP_CRITICAL_THRESHOLD + CPUTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_CPUTEMP_CRITICAL_THRESHOLD + INTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_INTEMP_CRITICAL_THRESHOLD + CRITICAL_NUM = module_product.MONITOR_CRITICAL_NUM + SHAKE_TIME = module_product.MONITOR_SHAKE_TIME + MONITOR_INTERVAL = module_product.MONITOR_INTERVAL + MONITOR_LED_INTERVAL = module_product.MONITOR_LED_INTERVAL + MONITOR_FALL_TEMP = module_product.MONITOR_FALL_TEMP + MONITOR_PID_FLAG = module_product.MONITOR_PID_FLAG + MONITOR_PID_MODULE = module_product.MONITOR_PID_MODULE + + MONITOR_MAC_SOURCE_SYSFS = module_product.MONITOR_MAC_SOURCE_SYSFS + MONITOR_MAC_SOURCE_PATH = module_product.MONITOR_MAC_SOURCE_PATH + + +PSU_FAN_FOLLOW = module_product.PSU_FAN_FOLLOW +MONITOR_SYS_LED = module_product.MONITOR_SYS_LED +MONITOR_FANS_LED = module_product.MONITOR_FANS_LED +MONITOR_SYS_FAN_LED = module_product.MONITOR_SYS_FAN_LED +MONITOR_SYS_PSU_LED = module_product.MONITOR_SYS_PSU_LED +MONITOR_FAN_STATUS = module_product.MONITOR_FAN_STATUS +MONITOR_PSU_STATUS = module_product.MONITOR_PSU_STATUS +MONITOR_DEV_STATUS = module_product.MONITOR_DEV_STATUS +MONITOR_DEV_STATUS_DECODE = module_product.MONITOR_DEV_STATUS_DECODE +DEV_LEDS = module_product.DEV_LEDS +fanloc = module_product.fanloc diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_driver.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_driver.py new file mode 100755 index 000000000000..6d2c6de653d9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_driver.py @@ -0,0 +1,258 @@ +#!/usr/bin/env python3 +import os +import subprocess +import time +import click +from platform_config import GLOBALCONFIG, WARM_UPGRADE_STARTED_FLAG, WARM_UPG_FLAG + + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def log_os_system(cmd): + status, output = subprocess.getstatusoutput(cmd) + if status: + print(output) + return status, output + + +def platform_process_file_check(): + # WARM_UPGRADE_STARTED_FLAG is used as warm_upgrade.py process start flag + if os.path.exists(WARM_UPGRADE_STARTED_FLAG): + os.remove(WARM_UPGRADE_STARTED_FLAG) + + # WARM_UPG_FLAG is used as port related service judgment flag + if os.path.exists(WARM_UPG_FLAG): + os.remove(WARM_UPG_FLAG) + + +def startCommon_operation(): + platform_process_file_check() + + +def check_driver(): + status, output = log_os_system("lsmod | grep wb | wc -l") + if status: + return False + if output.isdigit() and int(output) > 0: + return True + return False + + +def removeDev(bus, loc): + cmd = "echo 0x%02x > /sys/bus/i2c/devices/i2c-%d/delete_device" % (loc, bus) + devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) + if os.path.exists(devpath): + log_os_system(cmd) + + +def addDev(name, bus, loc): + if name == "lm75": + time.sleep(0.1) + pdevpath = "/sys/bus/i2c/devices/i2c-%d/" % (bus) + for i in range(1, 100): + if os.path.exists(pdevpath) is True: + break + time.sleep(0.1) + if i % 10 == 0: + click.echo("%%WB_PLATFORM_DRIVER-INIT: %s not found, wait 0.1 second ! i %d " % (pdevpath, i)) + + cmd = "echo %s 0x%02x > /sys/bus/i2c/devices/i2c-%d/new_device" % (name, loc, bus) + devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) + if os.path.exists(devpath) is False: + os.system(cmd) + + +def removeOPTOE(startbus, endbus): + for bus in range(endbus, startbus - 1, -1): + removeDev(bus, 0x50) + + +def addOPTOE(name, startbus, endbus): + for bus in range(startbus, endbus + 1): + addDev(name, bus, 0x50) + + +def removeoptoes(): + optoes = GLOBALCONFIG["OPTOE"] + for index in range(len(optoes) - 1, -1, -1): + removeOPTOE(optoes[index]["startbus"], optoes[index]["endbus"]) + + +def addoptoes(): + optoes = GLOBALCONFIG["OPTOE"] + for optoe in optoes: + addOPTOE(optoe["name"], optoe["startbus"], optoe["endbus"]) + + +def removedevs(): + devs = GLOBALCONFIG["DEVS"] + for index in range(len(devs) - 1, -1, -1): + removeDev(devs[index]["bus"], devs[index]["loc"]) + + +def adddevs(): + devs = GLOBALCONFIG["DEVS"] + for dev in devs: + addDev(dev["name"], dev["bus"], dev["loc"]) + + +def checksignaldriver(name): + modisexistcmd = "lsmod | grep -w %s | wc -l" % name + status, output = log_os_system(modisexistcmd) + if status: + return False + if output.isdigit() and int(output) > 0: + return True + return False + + +def adddriver(name, delay): + cmd = "modprobe %s" % name + if delay != 0: + time.sleep(delay) + if checksignaldriver(name) is not True: + log_os_system(cmd) + + +def removedriver(name, delay, removeable=1): + realname = name.lstrip().split(" ")[0] + cmd = "rmmod -f %s" % realname + if checksignaldriver(realname) and removeable: + log_os_system(cmd) + if delay > 0: + time.sleep(delay) + + +def removedrivers(): + if GLOBALCONFIG is None: + click.echo("%%WB_PLATFORM_DRIVER-INIT: load global config failed.") + return + drivers = GLOBALCONFIG.get("DRIVERLISTS", None) + if drivers is None: + click.echo("%%WB_PLATFORM_DRIVER-INIT: load driver list failed.") + return + for index in range(len(drivers) - 1, -1, -1): + delay = 0 + name = "" + removeable = drivers[index].get("removable", 1) + if isinstance(drivers[index], dict) and "delay" in drivers[index]: + name = drivers[index].get("name") + delay = drivers[index]["delay"] + else: + name = drivers[index] + removedriver(name, delay, removeable) + + +def adddrivers(): + if GLOBALCONFIG is None: + click.echo("%%WB_PLATFORM_DRIVER-INIT: load global config failed.") + return + drivers = GLOBALCONFIG.get("DRIVERLISTS", None) + if drivers is None: + click.echo("%%WB_PLATFORM_DRIVER-INIT: load driver list failed.") + return + for driver in drivers: + delay = 0 + name = "" + if isinstance(driver, dict) and "delay" in driver: + name = driver.get("name") + delay = driver["delay"] + else: + name = driver + adddriver(name, delay) + + +def blacklist_driver_remove(): + if GLOBALCONFIG is None: + click.echo("%%WB_PLATFORM_DRIVER-INIT: load global config failed.") + return + blacklist_drivers = GLOBALCONFIG.get("BLACKLIST_DRIVERS", []) + for driver in blacklist_drivers: + delay = 0 + name = "" + if isinstance(driver, dict) and "delay" in driver: + name = driver.get("name") + delay = driver["delay"] + else: + name = driver + removedriver(name, delay) + + +def unload_driver(): + removeoptoes() + removedevs() + removedrivers() + + +def reload_driver(): + removedevs() + removedrivers() + time.sleep(1) + adddrivers() + adddevs() + + +def i2c_check(bus, retrytime=6): + try: + i2cpath = "/sys/bus/i2c/devices/" + bus + while retrytime and not os.path.exists(i2cpath): + click.echo("%%WB_PLATFORM_DRIVER-HA: i2c bus abnormal, last bus %s is not exist." % i2cpath) + reload_driver() + retrytime -= 1 + time.sleep(1) + except Exception as e: + click.echo("%%WB_PLATFORM_DRIVER-HA: %s" % str(e)) + + +def load_driver(): + startCommon_operation() + adddrivers() + adddevs() + addoptoes() + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''device operator''' + + +@main.command() +def start(): + '''load drivers and device ''' + blacklist_driver_remove() + if check_driver(): + unload_driver() + load_driver() + + +@main.command() +def stop(): + '''stop drivers device ''' + unload_driver() + + +@main.command() +def restart(): + '''restart drivers and device''' + unload_driver() + load_driver() + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_e2.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_e2.py new file mode 100755 index 000000000000..152dd16a25a6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_e2.py @@ -0,0 +1,439 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +import click + +from eepromutil.fru import ipmifru +from eepromutil.cust_fru import CustFru +from eepromutil.fantlv import fan_tlv +import eepromutil.onietlv as ot +from platform_config import PLATFORM_E2_CONF +from platform_util import byteTostr, dev_file_read + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +class ExtraFunc(object): + @staticmethod + def decode_mac(encodedata): + if encodedata is None: + return None + ret = ":".join("%02x" % ord(data) for data in encodedata) + return ret.upper() + + @staticmethod + def decode_mac_number(encodedata): + if encodedata is None: + return None + return (ord(encodedata[0]) << 8) | (ord(encodedata[1]) & 0x00ff) + + @staticmethod + @staticmethod + def fru_decode_mac_number(params): + ipmi_fru = params.get("fru") + area = params.get("area") + field = params.get("field") + area_info = getattr(ipmi_fru, area, None) + if area_info is not None: + raw_mac_number = getattr(area_info, field, None) + mac_number = decode_mac_number(raw_mac_number) + ipmi_fru.setValue(area, field, mac_number) + + @staticmethod + def fru_decode_mac(params): + ipmi_fru = params.get("fru") + area = params.get("area") + field = params.get("field") + area_info = getattr(ipmi_fru, area, None) + if area_info is not None: + raw_mac = getattr(area_info, field, None) + decoded_mac = decode_mac(raw_mac) + ipmi_fru.setValue(area, field, decoded_mac) + + @staticmethod + def fru_decode_hw(params): + ipmi_fru = params.get("fru") + area = params.get("area") + field = params.get("field") + area_info = getattr(ipmi_fru, area, None) + if area_info is not None: + raw_hw = getattr(area_info, field, None) + decode_hw = str(int(raw_hw, 16)) + ipmi_fru.setValue(area, field, decode_hw) + + +def set_onie_value(params): + onie = params.get("onie") + field = params.get("field") + config_value = params.get("config_value") + for index, onie_item in enumerate(onie): + if onie_item.get("name") == field: + if "value" in onie_item.keys(): + onie[index]["value"] = config_value + + +def onie_eeprom_decode(onie, e2_decode): + for e2_decode_item in e2_decode: + field = e2_decode_item.get("field") + decode_type = e2_decode_item.get("decode_type") + if decode_type == 'func': + params = { + "onie": onie, + "field": field + } + func_name = e2_decode_item.get("func_name") + if func_name is not None: + run_func(func_name, params) + elif decode_type == 'config': + config_value = e2_decode_item.get("config_value") + if config_value is not None: + params = { + "onie": onie, + "field": field, + "config_value": config_value + } + set_onie_value(params) + else: + print("unsupport decode type") + continue + + +def onie_eeprom_show(eeprom, e2_decode=None): + try: + onietlv = ot.onie_tlv() + rets = onietlv.decode(eeprom) + if e2_decode is not None: + onie_eeprom_decode(rets, e2_decode) + print("%-20s %-5s %-5s %-20s" % ("TLV name", "Code", "lens", "Value")) + for item in rets: + if item["code"] == 0xfd: + print("%-20s 0x%-02X %-5s" % (item["name"], item["code"], item["lens"])) + else: + print("%-20s 0x%-02X %-5s %-20s" % (item["name"], item["code"], item["lens"], item["value"])) + except Exception as e: + print(str(e)) + + +def set_fantlv_value(params): + fantlv_dict = params.get("fantlv") + field = params.get("field") + config_value = params.get("config_value") + for index, fantlv_item in enumerate(fantlv_dict): + if fantlv_item.get("name") == field: + if "value" in fantlv_item.keys(): + fantlv_dict[index]["value"] = config_value + + +def fantlv_eeprom_decode(fantlv_dict, e2_decode): + for e2_decode_item in e2_decode: + field = e2_decode_item.get("field") + decode_type = e2_decode_item.get("decode_type") + if decode_type == 'func': + params = { + "fantlv": fantlv_dict, + "field": field + } + func_name = e2_decode_item.get("func_name") + if func_name is not None: + run_func(func_name, params) + elif decode_type == 'config': + config_value = e2_decode_item.get("config_value") + if config_value is not None: + params = { + "fantlv": fantlv_dict, + "field": field, + "config_value": config_value + } + set_fantlv_value(params) + else: + print("unsupport decode type") + continue + + +def fantlv_eeprom_show(eeprom, e2_decode=None): + try: + tlv = fan_tlv() + rets = tlv.decode(eeprom) + if len(rets) == 0: + print("fan tlv eeprom info error.!") + return + if e2_decode is not None: + fantlv_eeprom_decode(rets, e2_decode) + print("%-15s %-5s %-5s %-20s" % ("TLV name", "Code", "lens", "Value")) + for item in rets: + print("%-15s 0x%-02X %-5s %-20s" % (item["name"], item["code"], item["lens"], item["value"])) + except Exception as e: + print(str(e)) + return + + +def run_func(funcname, params): + try: + func = getattr(ExtraFunc, funcname) + func(params) + except Exception as e: + print(str(e)) + +def set_fru_value(params): + ipmi_fru = params.get("fru") + area = params.get("area") + field = params.get("field") + config_value = params.get("config_value") + ipmi_fru.setValue(area, field, config_value) + + +def fru_eeprom_decode(ipmi_fru, e2_decode): + for e2_decode_item in e2_decode: + area = e2_decode_item.get("area") + field = e2_decode_item.get("field") + decode_type = e2_decode_item.get("decode_type") + if decode_type == 'func': + params = { + "fru": ipmi_fru, + "area": area, + "field": field + } + func_name = e2_decode_item.get("func_name") + if func_name is not None: + run_func(func_name, params) + elif decode_type == 'config': + config_value = e2_decode_item.get("config_value") + if config_value is not None: + params = { + "fru": ipmi_fru, + "area": area, + "field": field, + "config_value": config_value + } + set_fru_value(params) + else: + print("unsupport decode type") + continue + + +def fru_eeprom_show(eeprom, e2_decode=None): + try: + ipmi_fru = ipmifru() + ipmi_fru.decodeBin(eeprom) + if e2_decode is not None: + fru_eeprom_decode(ipmi_fru, e2_decode) + print("=================board=================") + print(ipmi_fru.boardInfoArea) + print("=================product=================") + print(ipmi_fru.productInfoArea) + except Exception as e: + print(str(e)) + + +def custfru_eeprom_show(eeprom, e2_decode=None): + try: + custfru = CustFru() + custfru.decode(eeprom) + print(custfru) + except Exception as e: + print(str(e)) + + +def eeprom_parase(eeprom_conf): + name = eeprom_conf.get("name") + e2_type = eeprom_conf.get("e2_type") + e2_path = eeprom_conf.get("e2_path") + e2_size = eeprom_conf.get("e2_size", 256) + e2_decode = eeprom_conf.get("e2_decode") + print("===================%s===================" % name) + ret, binval_bytes = dev_file_read(e2_path, 0, e2_size) + if ret is False: + print("eeprom read error, eeprom path: %s, msg: %s" % (e2_path, binval_bytes)) + return + binval = byteTostr(binval_bytes) + if e2_type == "onie_tlv": + onie_eeprom_show(binval, e2_decode) + elif e2_type == "fru": + fru_eeprom_show(binval, e2_decode) + elif e2_type == "fantlv": + fantlv_eeprom_show(binval, e2_decode) + elif e2_type == "custfru": + custfru_eeprom_show(binval, e2_decode) + else: + print("Unknow eeprom type: %s" % e2_type) + return + + +def get_fans_eeprom_info(param): + fan_eeprom_conf = PLATFORM_E2_CONF.get("fan", []) + fan_num = len(fan_eeprom_conf) + if fan_num == 0: + print("fan number is 0, can't get fan eeprom info") + return + if param == 'all': + for conf in fan_eeprom_conf: + eeprom_parase(conf) + return + if not param.isdigit(): + print("param error, %s is not digital or 'all'" % param) + return + fan_index = int(param, 10) - 1 + if fan_index < 0 or fan_index >= fan_num: + print("param error, total fan number: %d, fan index: %d" % (fan_num, fan_index + 1)) + return + eeprom_parase(fan_eeprom_conf[fan_index]) + return + + +def get_psus_eeprom_info(param): + psu_eeprom_conf = PLATFORM_E2_CONF.get("psu", []) + psu_num = len(psu_eeprom_conf) + if psu_num == 0: + print("psu number is 0, can't get psu eeprom info") + return + if param == 'all': + for conf in psu_eeprom_conf: + eeprom_parase(conf) + return + if not param.isdigit(): + print("param error, %s is not digital or 'all'" % param) + return + psu_index = int(param, 10) - 1 + if psu_index < 0 or psu_index >= psu_num: + print("param error, total psu number: %d, psu index: %d" % (psu_num, psu_index + 1)) + return + eeprom_parase(psu_eeprom_conf[psu_index]) + return + + +def get_slots_eeprom_info(param): + slot_eeprom_conf = PLATFORM_E2_CONF.get("slot", []) + slot_num = len(slot_eeprom_conf) + if slot_num == 0: + print("slot number is 0, can't get slot eeprom info") + return + if param == 'all': + for conf in slot_eeprom_conf: + eeprom_parase(conf) + return + if not param.isdigit(): + print("param error, %s is not digital or 'all'" % param) + return + slot_index = int(param, 10) - 1 + if slot_index < 0 or slot_index >= slot_num: + print("param error, total slot number: %d, slot index: %d" % (slot_num, slot_index + 1)) + return + eeprom_parase(slot_eeprom_conf[slot_index]) + return + + +def get_syseeprom_info(param): + syseeprom_conf = PLATFORM_E2_CONF.get("syseeprom", []) + syseeprom_num = len(syseeprom_conf) + if syseeprom_num == 0: + print("syseeprom number is 0, can't get syseeprom info") + return + if param == 'all': + for conf in syseeprom_conf: + eeprom_parase(conf) + return + if not param.isdigit(): + print("param error, %s is not digital or 'all'" % param) + return + syseeprom_index = int(param, 10) - 1 + if syseeprom_index < 0 or syseeprom_index >= syseeprom_num: + print("param error, total syseeprom number: %d, syseeprom index: %d" % (syseeprom_num, syseeprom_index + 1)) + return + eeprom_parase(syseeprom_conf[syseeprom_index]) + return + + +def decode_eeprom_info(e2_type, e2_path, e2_size): + if not e2_size.isdigit(): + print("param error, e2_size %s is not digital" % e2_size) + return + e2_size = int(e2_size, 10) + eeprom_conf = {} + eeprom_conf["name"] = e2_type + eeprom_conf["e2_type"] = e2_type + eeprom_conf["e2_path"] = e2_path + eeprom_conf["e2_size"] = e2_size + eeprom_parase(eeprom_conf) + return + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''platform eeprom display script''' + + +# fan eeprom info display +@main.command() +@click.argument('fan_index', required=True) +def fan(fan_index): + '''fan_index(1, 2, 3...)/all''' + get_fans_eeprom_info(fan_index) + + +# psu eeprom info display +@main.command() +@click.argument('psu_index', required=True) +def psu(psu_index): + '''psu_index(1, 2, 3...)/all''' + get_psus_eeprom_info(psu_index) + + +# slot eeprom info display +@main.command() +@click.argument('slot_index', required=True) +def slot(slot_index): + '''slot_index(1, 2, 3...)/all''' + get_slots_eeprom_info(slot_index) + + +# syseeprom info display +@main.command() +@click.argument('syseeprom_index', required=True) +def syseeprom(syseeprom_index): + '''syseeprom_index(1, 2, 3...)/all''' + get_syseeprom_info(syseeprom_index) + + +# fru eeprom info decode +@main.command() +@click.argument('e2_path', required=True) +@click.argument('e2_size', required=False, default="256") +def fru(e2_path, e2_size): + '''e2_path''' + decode_eeprom_info("fru", e2_path, e2_size) + + +# fantlv eeprom info decode +@main.command() +@click.argument('e2_path', required=True) +@click.argument('e2_size', required=False, default="256") +def fantlv(e2_path, e2_size): + '''e2_path''' + decode_eeprom_info("fantlv", e2_path, e2_size) + + +# onie_tlv eeprom info decode +@main.command() +@click.argument('e2_path', required=True) +@click.argument('e2_size', required=False, default="256") +def onie_tlv(e2_path, e2_size): + '''e2_path''' + decode_eeprom_info("onie_tlv", e2_path, e2_size) + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_intf.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_intf.py new file mode 100755 index 000000000000..43f36f040d6a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_intf.py @@ -0,0 +1,384 @@ +#!/usr/bin/env python3 +import os +import syslog +import importlib.machinery +from platform_util import getplatform_name, dev_file_read, dev_file_write, write_sysfs, read_sysfs + +__all__ = [ + "platform_reg_read", + "platform_reg_write", + "platform_set_optoe_type", + "platform_get_optoe_type", + "platform_sfp_read", + "platform_sfp_write", +] + +CPLD = 0 +FPGA = 1 +CPLD_PATH = "/dev/cpld%d" +FPGA_PATH = "/dev/fpga%d" + + +OPTOE_PATH = "/sys/bus/i2c/devices/%d-0050/" +OPTOE_DEV_CLASS = "dev_class" +OPTOE_EEPROM = "eeprom" + + +PLATFORM_INTF_DEBUG_FILE = "/etc/.platform_intf_debug_flag" + + +CONFIG_FILE_LIST = [ + "/usr/local/bin/", + "/usr/local/lib/python3/dist-packages/config/", + "/usr/local/lib/python3.7/dist-packages/config/", + "/usr/local/lib/python3.9/dist-packages/config/"] + + +def platform_intf_debug(s): + if os.path.exists(PLATFORM_INTF_DEBUG_FILE): + syslog.openlog("PLATFORM_INTF_DEBUG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def platform_intf_error(s): + if os.path.exists(PLATFORM_INTF_DEBUG_FILE): + syslog.openlog("PLATFORM_INTF_ERROR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +class IntfPlatform: + CONFIG_NAME = 'PLATFORM_INTF_OPTOE' + __port_optoe_dict = {} + + def __init__(self): + real_path = None + platform_name = (getplatform_name()).replace("-", "_") + for configfile_path in CONFIG_FILE_LIST: + configfile = configfile_path + platform_name + "_port_config.py" + if os.path.exists(configfile): + real_path = configfile + break + if real_path is None: + raise Exception("get port config error") + config = importlib.machinery.SourceFileLoader(self.CONFIG_NAME, real_path).load_module() + self.__port_optoe_dict = config.PLATFORM_INTF_OPTOE + + def get_dev_path(self, dev_type, dev_id): + if dev_type == CPLD: + path = CPLD_PATH % dev_id + elif dev_type == FPGA: + path = FPGA_PATH % dev_id + else: + msg = "dev_type error!" + return False, msg + platform_intf_debug("path:%s" % path) + return True, path + + def get_port_path(self, port): + port_num = self.__port_optoe_dict.get("port_num", 0) + if port_num <= 0: + msg = "PLATFORM_INTF_OPTOE port_num config error, port_num: %d!" % port_num + return False, msg + + if port <= 0 or port > port_num: + msg = "port out of range !" + return False, msg + + port_bus_map = self.__port_optoe_dict.get("port_bus_map") + optoe_start_bus = self.__port_optoe_dict.get("optoe_start_bus", 0) + if port_bus_map is None: # get port bus by optoe_start_bus + if optoe_start_bus <= 0: + msg = "PLATFORM_INTF_OPTOE optoe_start_bus config error, optoe_start_bus: %d" % optoe_start_bus + return False, msg + port_bus = port + optoe_start_bus - 1 + else: # get port bus by port_bus_map + port_bus = port_bus_map.get(port) + if port_bus is None: + msg = "port %d don't has i2c bus" % port + return False, msg + if not isinstance(port_bus, int) or port_bus < 0: + msg = "port %d i2c bus config error, port_bus: %s " % port_bus + return False, msg + + path = OPTOE_PATH % (port_bus) + platform_intf_debug("path:%s" % path) + return True, path + + ########################################### + # reg_read - read logic device register + # @dev_type: 0: CPLD, 1: FPGA + # @dev_id: device ID, start from 0 + # @offset: register offset + # @size: read length + # return: + # @ret: True if read success, False if not + # @info: The read value list if read success, otherwise the detail error message + ########################################### + def reg_read(self, dev_type, dev_id, offset, size): + ret, path = self.get_dev_path(dev_type, dev_id) + if ret is False: + return False, path + ret, info = dev_file_read(path, offset, size) + return ret, info + + ########################################### + # platform_reg_write - write logic device register + # @dev_type: 0: CPLD, 1: FPGA + # @dev_id: device ID, start from 0 + # @offset: register offset + # @val_list: The write value list + # return: + # @ret: True if write success, False if not + # @info: The write value length if write success, otherwise the detail error message + ########################################### + def reg_write(self, dev_type, dev_id, offset, val_list): + ret, path = self.get_dev_path(dev_type, dev_id) + if ret is False: + return False, path + ret, info = dev_file_write(path, offset, val_list) + return ret, info + + ########################################### + # set_optoe_type - set port optoe type + # @port: port index start from 1 + # @optoe_type: optoe type, including the following values + # 1: OPTOE1 + # 2: OPTOE2 + # 3: OPTOE3 + # return: + # @ret: True if set optoe type success, False if not + # @info: None if set optoe type success, otherwise the detail error message + ########################################### + def set_optoe_type(self, port, optoe_type): + ret, path = self.get_port_path(port) + if ret is False: + return False, path + optoe_type_path = path + OPTOE_DEV_CLASS + ret, info = write_sysfs(optoe_type_path, "%d" % optoe_type) + if ret is False: + return False, info + return True, None + + ########################################### + # get_optoe_type - get port optoe type + # @port: port index start from 1 + # return: + # @ret: True if set optoe type success, False if not + # @info: Optoe type value if get optoe type success, otherwise the detail error message + # optoe type including the following values + # 1: OPTOE1 + # 2: OPTOE2 + # 3: OPTOE3 + ########################################### + def get_optoe_type(self, port): + ret, path = self.get_port_path(port) + if ret is False: + return False, path + optoe_type_path = path + OPTOE_DEV_CLASS + ret, info = read_sysfs(optoe_type_path) + if ret is False: + return False, info + return True, int(info) + + ########################################### + # sfp_read -read sfp eeprom + # @port_id: port index start from 1 + # @offset: sfp eeprom offset + # @size: read sfp eeprom length + # return: + # @ret: True if read success, False if not + # @info: The read value list if read success, otherwise the detail error message + ########################################### + def sfp_read(self, port_id, offset, size): + ret, path = self.get_port_path(port_id) + if ret is False: + return False, path + optoe_eeprom_path = path + OPTOE_EEPROM + ret, info = dev_file_read(optoe_eeprom_path, offset, size) + return ret, info + + ########################################### + # sfp_write -write sfp eeprom + # @port_id: port index start from 1 + # @offset: sfp eeprom offset + # @val_list: The write value list + # return: + # @ret: True if read success, False if not + # @info: The write value length if write success, otherwise the detail error message + ########################################### + def sfp_write(self, port_id, offset, val_list): + ret, path = self.get_port_path(port_id) + if ret is False: + return False, path + optoe_eeprom_path = path + OPTOE_EEPROM + ret, info = dev_file_write(optoe_eeprom_path, offset, val_list) + return ret, info + + +platform = IntfPlatform() + + +########################################### +# platform_reg_read - read logic device register +# @dev_type: 0: CPLD, 1: FPGA +# @dev_id: device ID, start from 0 +# @offset: register offset +# @size: read length +# return: +# @ret: True if read success, False if not +# @info: The read value list if read success, otherwise the detail error message +########################################### +def platform_reg_read(dev_type, dev_id, offset, size): + ret = False + info = None + + # params check + if (isinstance(dev_type, int) is False or isinstance(dev_id, int) is False or + isinstance(offset, int) is False or isinstance(size, int) is False): + info = "params type check fail in platform_reg_read" + return ret, info + if dev_id < 0 or offset < 0 or size <= 0: + info = "params value check fail in platform_reg_read" + return ret, info + support_dev_type = (CPLD, FPGA) + if dev_type not in support_dev_type: + info = "dev_type match erro, fail in platform_reg_read" + return ret, info + + # call the solve func + return platform.reg_read(dev_type, dev_id, offset, size) + + +########################################### +# platform_reg_write - write logic device register +# @dev_type: 0: CPLD, 1: FPGA +# @dev_id: device ID, start from 0 +# @offset: register offset +# @val_list: The write value list +# return: +# @ret: True if write success, False if not +# @info: The write value length if write success, otherwise the detail error message +########################################### +def platform_reg_write(dev_type, dev_id, offset, val_list): + ret = False + info = None + + # params check + if (isinstance(dev_type, int) is False or isinstance(dev_id, int) is False or + isinstance(offset, int) is False or isinstance(val_list, list) is False): + info = "params type check fail in platform_reg_write" + return ret, info + if dev_id < 0 or offset < 0 or len(val_list) <= 0: + info = "params value check fail in platform_reg_write" + return ret, info + support_dev_type = (CPLD, FPGA) + if dev_type not in support_dev_type: + info = "dev_type match erro, fail in platform_reg_write" + return ret, info + + # call the solve func + return platform.reg_write(dev_type, dev_id, offset, val_list) + + +########################################### +# platform_set_optoe_type - set port optoe type +# @port: port index start from 1 +# @optoe_type: optoe type, including the following values +# 1: OPTOE1 +# 2: OPTOE2 +# 3: OPTOE3 +# return: +# @ret: True if set optoe type success, False if not +# @info: None if set optoe type success, otherwise the detail error message +########################################### +def platform_set_optoe_type(port, optoe_type): + ret = False + info = None + + # params check + if isinstance(port, int) is False or isinstance(optoe_type, int) is False: + info = "params type check fail in platform_set_optoe_type" + return ret, info + if port < 0 or optoe_type < 1 or optoe_type > 3: + info = "params value check fail in platform_set_optoe_type" + return ret, info + + # call the solve func + return platform.set_optoe_type(port, optoe_type) + + +########################################### +# platform_get_optoe_type - get port optoe type +# @port: port index start from 1 +# return: +# @ret: True if set optoe type success, False if not +# @info: Optoe type value if get optoe type success, otherwise the detail error message +# optoe type including the following values +# 1: OPTOE1 +# 2: OPTOE2 +# 3: OPTOE3 +########################################### +def platform_get_optoe_type(port): + ret = False + info = None + + # params check + if isinstance(port, int) is False: + info = "params type check fail in platform_get_optoe_type" + return ret, info + if port < 0: + info = "params value check fail in platform_get_optoe_type" + return ret, info + + # call the solve func + return platform.get_optoe_type(port) + + +########################################### +# platform_sfp_read -read sfp eeprom +# @port_id: port index start from 1 +# @offset: sfp eeprom offset +# @size: read sfp eeprom length +# return: +# @ret: True if read success, False if not +# @info: The read value list if read success, otherwise the detail error message +########################################### +def platform_sfp_read(port_id, offset, size): + ret = False + info = None + + # params check + if isinstance(port_id, int) is False or isinstance(offset, int) is False or isinstance(size, int) is False: + info = "params type check fail in platform_sfp_read" + return ret, info + if port_id < 0 or offset < 0 or size <= 0: + info = "params value check fail in platform_sfp_read" + return ret, info + + # call the solve func + return platform.sfp_read(port_id, offset, size) + + +########################################### +# platform_sfp_write -write sfp eeprom +# @port_id: port index start from 1 +# @offset: sfp eeprom offset +# @val_list: The write value list +# return: +# @ret: True if read success, False if not +# @info: The write value length if write success, otherwise the detail error message +########################################### +def platform_sfp_write(port_id, offset, val_list): + ret = False + info = None + + # params check + if isinstance(port_id, int) is False or isinstance(offset, int) is False or isinstance(val_list, list) is False: + info = "params type check fail in platform_sfp_write" + return ret, info + if port_id < 0 or offset < 0 or len(val_list) <= 0: + info = "params value check fail in platform_sfp_write" + return ret, info + + # call the solve func + return platform.sfp_write(port_id, offset, val_list) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_ipmi.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_ipmi.py new file mode 100755 index 000000000000..c9b72c99cca9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_ipmi.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import sys +import os +import syslog +import click +from platform_util import exec_os_cmd + + +IPMITOOL_CMD = "ipmitool raw 0x32 0x04" # All products are the same command + +PLATFORM_IPMI_DEBUG_FILE = "/etc/.platform_ipmi_debug_flag" +UPGRADEDEBUG = 1 +debuglevel = 0 + + +def debug_init(): + global debuglevel + if os.path.exists(PLATFORM_IPMI_DEBUG_FILE): + debuglevel = debuglevel | UPGRADEDEBUG + else: + debuglevel = debuglevel & ~(UPGRADEDEBUG) + + +def ipmidebuglog(s): + # s = s.decode('utf-8').encode('gb2312') + if UPGRADEDEBUG & debuglevel: + syslog.openlog("PLATFORM_IPMI", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def ipmierror(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("PLATFORM_IPMI", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +@click.command() +@click.argument('cmd', required=True) +def platform_ipmi_main(cmd): + '''Send command to BMC through ipmi''' + try: + # Convert string command to ASCII + user_cmd = "" + for ch in cmd: + user_cmd += " " + str(ord(ch)) + + final_cmd = IPMITOOL_CMD + user_cmd + ipmidebuglog("final cmd:%s" % final_cmd) + + # exec ipmitool cmd + status, output = exec_os_cmd(final_cmd) + if status: + ipmierror("exec ipmitool_cmd:%s user_cmd:%s failed" % (IPMITOOL_CMD, cmd)) + ipmierror("failed log: %s" % output) + return False, "exec final_cmd failed" + + # the data read by ipmitool is hex value, needs transformation + data_list = output.replace("\n", "").strip(' ').split(' ') + ipmidebuglog("data_list: %s" % data_list) + result = "" + for data in data_list: + result += chr(int(data, 16)) + + # 'result' string include ret and log, separated by , + result_list = result.split(',', 2) + if len(result_list) != 2: + log = "split failed. len(result) != 2. result:%s" % result + ipmierror(log) + return False, log + if int(result_list[0]) != 0: + ipmierror("finally analy ipmitool_cmd:%s user_cmd:%s exec failed" % (IPMITOOL_CMD, cmd)) + ipmierror("failed return log: %s" % result_list[1]) + print(result_list[1]) + return False, result_list[1] + + ipmidebuglog("finally exec ipmitool_cmd:%s user_cmd:%s success" % (IPMITOOL_CMD, cmd)) + print(result_list[1]) + return True, result_list[1] + + except Exception as e: + log = "An exception occurred, exception log:%s" % str(e) + ipmierror(log) + return False, log + + +if __name__ == '__main__': + debug_init() + ret, msg = platform_ipmi_main() + if ret is False: + sys.exit(1) + sys.exit(0) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_manufacturer.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_manufacturer.py new file mode 100755 index 000000000000..b2643da9bce4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_manufacturer.py @@ -0,0 +1,562 @@ +#!/usr/bin/env python3 + +import re +import mmap +import fcntl +import subprocess +import shlex +import signal +import os +import time +import sys +from platform_config import MANUINFO_CONF +from monitor import status + + +INDENT = 4 + + +def printerr(vchar): + sys.stderr.write(vchar + '\n') + + +g_extra_cache = {} +g_meminfo_cache = {} +g_exphy_cache = {} + + +def exec_os_cmd(cmd, timeout = None): + status, output = subprocess.getstatusoutput(cmd) + return status, output + + +def exphyfwsplit(): + # improve performance + global g_exphy_cache + if g_exphy_cache: + return + cmd = "bcmcmd -t 1 \"phy control xe,ce fw_get\" |grep fw_version" + ret, output = exec_os_cmd(cmd) + if ret or len(output) == 0: + raise Exception("run cmd: {} error, status: {}, msg: {}".format(cmd, ret, output)) + exphyfwstr = output.strip() + portlist = exphyfwstr.split("\n") + for port in portlist: + phy_addr_str = get_regular_val(port, r"phy_addr\s*=\s*\w+", 0) + if phy_addr_str.startswith("ERR"): + continue + phy_addr_key = phy_addr_str.replace(" ", "") + if phy_addr_key in g_exphy_cache: + continue + + g_exphy_cache[phy_addr_key] = {} + + fw_version_str = get_regular_val(port, r"fw_version\s*=\s*\w+", 0) + if fw_version_str.startswith("ERR"): + del g_exphy_cache[phy_addr_key] + continue + + fw_version = fw_version_str.split("=")[1].strip() + g_exphy_cache[phy_addr_key]["fw_version"] = fw_version + + if "success" in port: + ret = "OK" + else: + ret = "Unexpected" + g_exphy_cache[phy_addr_key]["status"] = ret + return + + +def lshwmemorysplit(): + # improve performance + global g_meminfo_cache + if g_meminfo_cache: + return + cmd = "lshw -c memory" + ret, output = exec_os_cmd(cmd) + if ret or len(output) == 0: + raise Exception("run cmd: {} error, status: {}, msg: {}".format(cmd, ret, output)) + memstr = output.strip() + memlist = memstr.split("*-") + for item in memlist: + if item.strip().startswith("memory") and "System Memory" not in item: + continue + line_index = 0 + for line in item.splitlines(): + line_index += 1 + if line_index == 1: + memdict_key = line + g_meminfo_cache[memdict_key] = {} + else: + if ":" not in line: + continue + key = line.split(":", 1)[0].strip() + value = line.split(":", 1)[1].strip() + g_meminfo_cache[memdict_key][key] = value + if "empty" in item: + break + return + + +def run_extra_func(funcname): + # improve performance + if funcname in g_extra_cache: + return g_extra_cache.get(funcname) + func = getattr(status, funcname) + ret = [] + func(ret) + if ret: + g_extra_cache[funcname] = ret + return ret + + +def get_extra_value(funcname, itemid, key): + for item in run_extra_func(funcname): + if item.get("id") == itemid: + return item.get(key, "NA") + return "NA" + + +def io_wr(reg_addr, reg_data): + try: + regdata = 0 + regaddr = 0 + if isinstance(reg_addr, int): + regaddr = reg_addr + else: + regaddr = int(reg_addr, 16) + if isinstance(reg_data, int): + regdata = reg_data + else: + regdata = int(reg_data, 16) + devfile = "/dev/port" + fd = os.open(devfile, os.O_RDWR | os.O_CREAT) + os.lseek(fd, regaddr, os.SEEK_SET) + os.write(fd, regdata.to_bytes(1, 'little')) + return True + except ValueError as e: + print(e) + return False + except Exception as e: + print(e) + return False + finally: + os.close(fd) + + +def checksignaldriver(name): + modisexistcmd = "lsmod | grep -w %s | wc -l" % name + ret, output = exec_os_cmd(modisexistcmd) + if ret: + return False + if output.isdigit() and int(output) > 0: + return True + return False + + +def adddriver(name): + cmd = "modprobe %s" % name + if checksignaldriver(name) is not True: + ret, log = exec_os_cmd(cmd) + if ret != 0 or len(log) > 0: + return False + return True + return True + + +def removedriver(name): + cmd = "rmmod %s" % name + if checksignaldriver(name): + exec_os_cmd(cmd) + +def deal_itmes(item_list): + for item in item_list: + dealtype = item.get("dealtype") + if dealtype == "shell": + cmd = item.get("cmd") + timeout = item.get("timeout", 10) + exec_os_cmd(cmd, timeout) + elif dealtype == "io_wr": + io_addr = item.get("io_addr") + wr_value = item.get("value") + io_wr(io_addr, wr_value) + + +def get_func_value(funcname, params): + func = getattr(ExtraFunc, funcname) + ret = func(params) + return ret + + +def read_pci_reg(pcibus, slot, fn, resource, offset): + '''read pci register''' + if offset % 4 != 0: + return "ERR offset: %d not 4 bytes align" + filename = "/sys/bus/pci/devices/0000:%02x:%02x.%x/resource%d" % (int(pcibus), int(slot), int(fn), int(resource)) + size = os.path.getsize(filename) + with open(filename, "r+") as file: + data = mmap.mmap(file.fileno(), size) + result = data[offset: offset + 4] + s = result[::-1] + val = 0 + for value in s: + val = val << 8 | value + data.close() + return "%08x" % val + + +def devfileread(path, offset, length, bit_width): + ret = "" + val_str = '' + val_list = [] + fd = -1 + if not os.path.exists(path): + return "%s not found !" % path + if length % bit_width != 0: + return "only support read by bit_width" + if length < bit_width: + return "len needs to greater than or equal to bit_width" + + try: + fd = os.open(path, os.O_RDONLY) + os.lseek(fd, offset, os.SEEK_SET) + ret = os.read(fd, length) + for item in ret: + val_list.append(item) + + for i in range(0, length, bit_width): + for j in range(0, bit_width): + val_str += "%02x" % val_list[i + bit_width - j - 1] + except Exception as e: + return str(e) + finally: + if fd > 0: + os.close(fd) + return val_str + + +def read_reg(loc, offset, size): + with open(loc, 'rb') as file: + file.seek(offset) + return ' '.join(["%02x" % item for item in file.read(size)]) + + +def std_match(stdout, pattern): + if pattern is None: + return stdout.strip() + for line in stdout.splitlines(): + if re.match(pattern, line): + return line.strip() + raise EOFError("pattern: {} does not match anything in stdout {}".format( + pattern, stdout)) + + +def i2c_rd(bus, loc, offset): + ''' + read i2c with i2cget command + ''' + cmd = "i2cget -f -y {} {} {}".format(bus, loc, offset) + retrytime = 6 + for i in range(retrytime): + ret, stdout = subprocess.getstatusoutput(cmd) + if ret == 0: + return stdout + time.sleep(0.1) + raise RuntimeError("run cmd: {} error, status {}".format(cmd, ret)) + + +def i2c_rd_bytes(bus, loc, offset, size): + blist = [] + for i in range(size): + ret = i2c_rd(bus, loc, offset + i) + blist.append(ret) + + return blist + + +def get_pair_val(source, separator): + try: + value = source.split(separator, 1)[1] + except (ValueError, IndexError): + return "ERR separator: {} does not match in source: {}".format(separator, source) + return value.strip() + + +def get_regular_val(source, pattern, group): + try: + value = re.findall(pattern, source)[group] + except Exception: + return "ERR pattern: {} does not match in source: {} with group: {}".format(pattern, source, group) + return value.strip() + + +def find_match(file2read, pattern): + with open(file2read, 'r') as file: + for line in file: + if not re.match(pattern, line): + continue + return line.strip() + return "ERR pattern %s not match in %s" % (pattern, file2read) + + +def readaline(file2read): + with open(file2read, 'r') as file: + return file.readline() + + +def sort_key(e): + return e.arrt_index + + +class ExtraFunc(object): + @staticmethod + def get_bcm5387_version(params): + version = "" + try: + before_deal_list = params.get("before", []) + deal_itmes(before_deal_list) + + ret, version = exec_os_cmd(params["get_version"]) + if ret != 0: + version = "ERR " + version + + after_deal_list = params.get("after", []) + deal_itmes(after_deal_list) + + except Exception as e: + version = "ERR %s" % (str(e)) + finally: + finally_deal_list = params.get("finally", []) + deal_itmes(finally_deal_list) + return version + + @staticmethod + def get_memory_value(params): + root_key = params.get("root_key") + sub_key = params.get("sub_key") + lshwmemorysplit() + return g_meminfo_cache.get(root_key, {}).get(sub_key, "NA") + + @staticmethod + def get_memory_bank_value(params): + lshwmemorysplit() + bank = params.get("bankid") + if g_meminfo_cache.get(bank, {}): + return True + return False + + @staticmethod + def get_exphy_fw(phyid): + exphyfwsplit() + if phyid not in g_exphy_cache: + return "ERR %s not found." % phyid + fw_version = g_exphy_cache.get(phyid).get("fw_version") + ret = g_exphy_cache.get(phyid).get("status") + msg = "%s %s" % (fw_version, ret) + return msg + +class CallbackSet: + def cpld_format(self, blist): + if isinstance(blist, str): + blist = blist.split() + elif not isinstance(blist, list) or len(blist) != 4: + raise ValueError("cpld format: wrong parameter: {}".format(blist)) + + return "{}{}{}{}".format(*blist).replace("0x", "") + + +class VersionHunter: + call = CallbackSet() + + def __init__(self, entires): + self.head = None + self.next = None + self.key = None + self.cmd = None + self.file = None + self.reg = None + self.i2c = None + self.extra = None + self.pattern = None + self.separator = None + self.parent = None + self.ignore = False + self.children = [] + self.level = 0 + self.callback = None + self.delspace = None + self.arrt_index = None + self.config = None + self.precheck = None + self.func = None + self.regular = None + self.group = 0 + self.pci = None + self.devfile = None + self.decode = None + self.timeout = 10 + self.__dict__.update(entires) + + def check_para(self): + if self.pattern is None: + return False + if self.cmd is None or self.file is None: + return False + return True + + def get_version(self): + ret = "NA" + try: + if self.cmd is not None: + ret, output = exec_os_cmd(self.cmd, self.timeout) + if ret or len(output) == 0: + raise RuntimeError("run cmd: {} error, status: {}, msg: {}".format(self.cmd, ret, output)) + ret = std_match(output, self.pattern) + elif self.file is not None: + ret = self.read_file() + elif self.reg is not None: + ret = read_reg(self.reg.get("loc"), self.reg.get("offset"), + self.reg.get("size")) + elif self.extra: + ret = get_extra_value(self.extra.get("funcname"), + self.extra.get("id"), + self.extra.get("key")) + elif self.i2c: + ret = i2c_rd_bytes(self.i2c.get("bus"), self.i2c.get("loc"), + self.i2c.get("offset"), + self.i2c.get("size")) + elif self.config: + ret = self.config + elif self.func: + ret = get_func_value(self.func.get("funcname"), + self.func.get("params")) + elif self.pci: + ret = read_pci_reg(self.pci.get("bus"), self.pci.get("slot"), + self.pci.get("fn"), self.pci.get("bar"), self.pci.get("offset")) + elif self.devfile: + ret = devfileread(self.devfile.get("loc"), self.devfile.get("offset"), + self.devfile.get("len"), self.devfile.get("bit_width")) + + except Exception as e: + # printerr(e.message) + return "ERR %s" % str(e) + return self.exe_callback(ret) + + def exe_callback(self, data): + try: + if self.callback: + method = getattr(self.call, self.callback) + return method(data) + except Exception: + return "ERR run callback method: {} error, data: {}".format(self.callback, data) + return data + + def read_file(self): + if self.pattern is not None: + return find_match(self.file, self.pattern) + return readaline(self.file) + + def hunt(self): + if self.ignore: + return + indent = self.level * INDENT * " " + + if self.precheck: + try: + ret = get_func_value(self.precheck.get("funcname"), self.precheck.get("params")) + if ret is not True: + return + except Exception as e: + err_msg = "ERR %s" % str(e) + format_str = "{}{:<{}}{}".format(indent, self.key + ':', + (30 - len(indent)), err_msg) + print(format_str) + return + # has children + if self.children: + self.children.sort(key=sort_key) + format_str = "{}{}:".format(indent, self.key) + print(format_str) + for child in self.children: + if not isinstance(child, VersionHunter): + continue + child.level = self.level + 1 + child.hunt() + else: + version = self.get_version() or "" + if not version.startswith("ERR"): + version = version.replace("\x00", "").strip() + if self.separator is not None: + version = get_pair_val(version, self.separator) + if self.delspace is not None: + version = version.replace(" ", "") + if self.regular is not None: + version = get_regular_val(version, self.regular, self.group) + if self.decode is not None: + tmp_version = self.decode.get(version) + if tmp_version is None: + version = "ERR decode %s failed" % version + else: + version = tmp_version + format_str = "{}{:<{}}{}".format(indent, self.key + ':', + (30 - len(indent)), version) + print(format_str) + + if self.next: + print("") + self.next.hunt() + + +pidfile = 0 + + +def ApplicationInstance(): + global pidfile + pidfile = open(os.path.realpath(__file__), "r") + try: + fcntl.flock(pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB) + return True + except Exception: + return False + + +def run(): + if os.geteuid() != 0: + print("Root privileges are required for this operation") + sys.exit(1) + + start_time = time.time() + while True: + ret = ApplicationInstance() + if ret is True: + break + if time.time() - start_time > 10: + printerr("manufacturer is running.") + sys.exit(1) + time.sleep(0.5) + + objmap = {} + + try: + target = {} + target.update(MANUINFO_CONF) + for objname, value in target.items(): + objmap[objname] = VersionHunter(value) + except Exception as e: + printerr(str(e)) + sys.exit(1) + + head = None + for objname, obj in objmap.items(): + if head is None and obj.head: + head = obj + if obj.parent: + objmap.get(obj.parent).children.append(obj) + if obj.next: + obj.next = objmap.get(obj.next) + + head.hunt() + + +if __name__ == "__main__": + run() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_process.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_process.py new file mode 100755 index 000000000000..f19231bba0a4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_process.py @@ -0,0 +1,413 @@ +#!/usr/bin/env python3 +import os +import subprocess +import glob +import time +import click +import shutil +from platform_config import STARTMODULE, MAC_LED_RESET, AIRFLOW_RESULT_FILE +from platform_config import GLOBALINITPARAM, GLOBALINITCOMMAND, GLOBALINITPARAM_PRE, GLOBALINITCOMMAND_PRE +from platform_util import wbpciwr + + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def log_os_system(cmd): + status, output = subprocess.getstatusoutput(cmd) + if status: + print(output) + return status, output + + +def write_sysfs_value(reg_name, value): + mb_reg_file = "/sys/bus/i2c/devices/" + reg_name + locations = glob.glob(mb_reg_file) + if len(locations) == 0: + print("%s not found" % mb_reg_file) + return False + sysfs_loc = locations[0] + try: + with open(sysfs_loc, 'w') as fd: + fd.write(value) + except Exception: + return False + return True + + +def getPid(name): + ret = [] + for dirname in os.listdir('/proc'): + if dirname == 'curproc': + continue + try: + with open('/proc/{}/cmdline'.format(dirname), mode='r') as fd: + content = fd.read() + except Exception: + continue + if name in content: + ret.append(dirname) + return ret + + +def startAvscontrol(): + if STARTMODULE.get('avscontrol', 0) == 1: + cmd = "nohup avscontrol.py start >/dev/null 2>&1 &" + rets = getPid("avscontrol.py") + if len(rets) == 0: + os.system(cmd) + + +def startFanctrol(): + if STARTMODULE.get('fancontrol', 0) == 1: + cmd = "nohup fancontrol.py start >/dev/null 2>&1 &" + rets = getPid("fancontrol.py") + if len(rets) == 0: + os.system(cmd) + + +def starthal_fanctrl(): + if STARTMODULE.get('hal_fanctrl', 0) == 1: + cmd = "nohup hal_fanctrl.py start >/dev/null 2>&1 &" + rets = getPid("hal_fanctrl.py") + if len(rets) == 0: + os.system(cmd) + + +def starthal_ledctrl(): + if STARTMODULE.get('hal_ledctrl', 0) == 1: + cmd = "nohup hal_ledctrl.py start >/dev/null 2>&1 &" + rets = getPid("hal_ledctrl.py") + if len(rets) == 0: + os.system(cmd) + + +def startDevmonitor(): + if STARTMODULE.get('dev_monitor', 0) == 1: + cmd = "nohup dev_monitor.py start >/dev/null 2>&1 &" + rets = getPid("dev_monitor.py") + if len(rets) == 0: + os.system(cmd) + + +def startSlotmonitor(): + if STARTMODULE.get('slot_monitor', 0) == 1: + cmd = "nohup slot_monitor.py start >/dev/null 2>&1 &" + rets = getPid("slot_monitor.py") + if len(rets) == 0: + os.system(cmd) + + +def startIntelligentmonitor(): + if STARTMODULE.get('intelligent_monitor', 0) == 1: + cmd = "nohup intelligent_monitor.py >/dev/null 2>&1 &" + rets = getPid("intelligent_monitor.py") + if len(rets) == 0: + os.system(cmd) + + +def startSignalmonitor(): + if STARTMODULE.get('signal_monitor', 0) == 1: + cmd = "nohup signal_monitor.py start >/dev/null 2>&1 &" + rets = getPid("signal_monitor.py") + if len(rets) == 0: + os.system(cmd) + + +def startSff_temp_polling(): + if STARTMODULE.get('sff_temp_polling', 0) == 1: + cmd = "nohup sfp_highest_temperatue.py >/dev/null 2>&1 &" + rets = getPid("sfp_highest_temperatue.py") + if len(rets) == 0: + os.system(cmd) + + +def startRebootCause(): + if STARTMODULE.get('reboot_cause', 0) == 1: + cmd = "nohup reboot_cause.py >/dev/null 2>&1 &" + rets = getPid("reboot_cause.py") + if len(rets) == 0: + os.system(cmd) + + +def startPMON_sys(): + if STARTMODULE.get('pmon_syslog', 0) == 1: + cmd = "nohup pmon_syslog.py >/dev/null 2>&1 &" + rets = getPid("pmon_syslog.py") + if len(rets) == 0: + os.system(cmd) + + +def startSff_polling(): + if STARTMODULE.get('sff_polling', 0) == 1: + cmd = "nohup sff_polling.py start > /dev/null 2>&1 &" + rets = getPid("sff_polling.py") + if len(rets) == 0: + os.system(cmd) + + +def generate_air_flow(): + cmd = "nohup generate_airflow.py > /dev/null 2>&1 &" + rets = getPid("generate_airflow.py") + if len(rets) == 0: + os.system(cmd) + time.sleep(1) + + +def startGenerate_air_flow(): + if STARTMODULE.get('generate_airflow', 0) == 1: + for i in range(10): + generate_air_flow() + if os.path.exists(AIRFLOW_RESULT_FILE): + click.echo("%%WB_PLATFORM_PROCESS: generate air flow success") + return + time.sleep(1) + click.echo("%%WB_PLATFORM_PROCESS: generate air flow,failed, %s not exits" % AIRFLOW_RESULT_FILE) + return + + +def start_tty_console(): + if STARTMODULE.get('tty_console', 0) == 1: + cmd = "nohup tty_console.py > /dev/null 2>&1 &" + rets = getPid("tty_console.py") + if len(rets) == 0: + os.system(cmd) + +def startDrvUpdate(): + if STARTMODULE.get('drv_update', 0) == 1: + cmd = "nohup drv_update.py >/dev/null 2>&1 &" + rets = getPid("drv_update.py") + if len(rets) == 0: + os.system(cmd) + + +def stopAvscontrol(): + if STARTMODULE.get('avscontrol', 0) == 1: + rets = getPid("avscontrol.py") + for ret in rets: + cmd = "kill " + ret + os.system(cmd) + + +def stopFanctrol(): + if STARTMODULE.get('fancontrol', 0) == 1: + rets = getPid("fancontrol.py") # + for ret in rets: + cmd = "kill " + ret + os.system(cmd) + + +def stophal_fanctrl(): + if STARTMODULE.get('hal_fanctrl', 0) == 1: + rets = getPid("hal_fanctrl.py") + for ret in rets: + cmd = "kill " + ret + os.system(cmd) + + +def stophal_ledctrl(): + if STARTMODULE.get('hal_ledctrl', 0) == 1: + rets = getPid("hal_ledctrl.py") + for ret in rets: + cmd = "kill " + ret + os.system(cmd) + + +def stopDevmonitor(): + if STARTMODULE.get('dev_monitor', 0) == 1: + rets = getPid("dev_monitor.py") # + for ret in rets: + cmd = "kill " + ret + os.system(cmd) + + +def stopSlotmonitor(): + if STARTMODULE.get('slot_monitor', 0) == 1: + rets = getPid("slot_monitor.py") # + for ret in rets: + cmd = "kill " + ret + os.system(cmd) + + +def stopIntelligentmonitor(): + if STARTMODULE.get('intelligent_monitor', 0) == 1: + rets = getPid("intelligent_monitor.py") + for ret in rets: + cmd = "kill " + ret + os.system(cmd) + + +def stopSignalmonitor(): + if STARTMODULE.get('signal_monitor', 0) == 1: + rets = getPid("signal_monitor.py") # + for ret in rets: + cmd = "kill " + ret + os.system(cmd) + + +def stopSff_temp_polling(): + if STARTMODULE.get('sff_temp_polling', 0) == 1: + rets = getPid("sfp_highest_temperatue.py") + for ret in rets: + cmd = "kill " + ret + os.system(cmd) + + +def stopPMON_sys(): + if STARTMODULE.get('pmon_syslog', 0) == 1: + rets = getPid("pmon_syslog.py") + for ret in rets: + cmd = "kill " + ret + os.system(cmd) + + +def stopRebootCause(): + if STARTMODULE.get('reboot_cause', 0) == 1: + rets = getPid("reboot_cause.py") + for ret in rets: + cmd = "kill " + ret + os.system(cmd) + + +def stopSff_polling(): + if STARTMODULE.get('sff_polling', 0) == 1: + rets = getPid("sff_polling.py") + for ret in rets: + cmd = "kill " + ret + os.system(cmd) + + +def stopGenerate_air_flow(): + if STARTMODULE.get('generate_airflow', 0) == 1: + rets = getPid("generate_airflow.py") + for ret in rets: + cmd = "kill " + ret + os.system(cmd) + + +def stop_tty_console(): + if STARTMODULE.get('tty_console', 0) == 1: + rets = getPid("tty_console.py") + for ret in rets: + cmd = "kill " + ret + os.system(cmd) + + +def otherinit(): + for index in GLOBALINITPARAM: + write_sysfs_value(index["loc"], index["value"]) + + for index in GLOBALINITCOMMAND: + log_os_system(index) + + +def otherinit_pre(): + for index in GLOBALINITPARAM_PRE: + write_sysfs_value(index["loc"], index["value"]) + + for index in GLOBALINITCOMMAND_PRE: + log_os_system(index) + + +def unload_apps(): + stopSff_polling() + stopPMON_sys() + stopSignalmonitor() + stopIntelligentmonitor() + stopSlotmonitor() + stopDevmonitor() + stopAvscontrol() + stophal_ledctrl() + stophal_fanctrl() + stopFanctrol() + stopSff_temp_polling() + stopRebootCause() + stop_tty_console() + stopGenerate_air_flow() + + +def MacLedSet(data): + '''write pci register''' + pcibus = MAC_LED_RESET.get("pcibus") + slot = MAC_LED_RESET.get("slot") + fn = MAC_LED_RESET.get("fn") + resource = MAC_LED_RESET.get("bar") + offset = MAC_LED_RESET.get("offset") + val = MAC_LED_RESET.get(data, None) + if val is None: + click.echo("%%WB_PLATFORM_PROCESS-INIT: MacLedSet wrong input") + return + wbpciwr(pcibus, slot, fn, resource, offset, val) + + +def copy_machineconf(): + try: + shutil.copyfile("/host/machine.conf", "/etc/sonic/machine.conf") + return True + except Exception: + return False + +def load_apps(): + copy_machineconf() + otherinit_pre() + startDrvUpdate() + startGenerate_air_flow() + start_tty_console() + startRebootCause() + startSff_temp_polling() + startFanctrol() + starthal_fanctrl() + starthal_ledctrl() + startAvscontrol() + startDevmonitor() + startSlotmonitor() + startIntelligentmonitor() + startSignalmonitor() + startPMON_sys() + startSff_polling() + otherinit() + if STARTMODULE.get("macledreset", 0) == 1: + MacLedSet("reset") + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''device operator''' + + +@main.command() +def start(): + '''load process ''' + load_apps() + + +@main.command() +def stop(): + '''stop process ''' + unload_apps() + + +@main.command() +def restart(): + '''restart process''' + unload_apps() + load_apps() + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_sensors.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_sensors.py new file mode 100755 index 000000000000..d5b72f48f51b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_sensors.py @@ -0,0 +1,272 @@ +#!/usr/bin/python3 + +import os +import sys +import importlib.machinery + + +def get_machine_info(): + if not os.path.isfile('/host/machine.conf'): + return None + machine_vars = {} + with open('/host/machine.conf') as machine_file: + for line in machine_file: + tokens = line.split('=') + if len(tokens) < 2: + continue + machine_vars[tokens[0]] = tokens[1].strip() + return machine_vars + + +def get_platform_info(machine_info): + if machine_info is not None: + if 'onie_platform' in machine_info: + return machine_info['onie_platform'] + if 'aboot_platform' in machine_info: + return machine_info['aboot_platform'] + return None + + +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +PLATFORM_SPECIFIC_MODULE_NAME = 'monitor' +PLATFORM_SPECIFIC_CLASS_NAME = 'status' +platform_status_class = None +platform = None + + +def get_platform_name(): + global platform + platform = get_platform_info(get_machine_info()) + return platform + + +val = get_platform_name() +sys.path.append("/".join([PLATFORM_ROOT_PATH, platform])) + +# Loads platform specific sfputil module from source + + +def load_platform_monitor(): + global platform_status_class + platform_name = get_platform_info(get_machine_info()) + platform_path = "/".join([PLATFORM_ROOT_PATH, platform_name]) + try: + module_file = "/".join([platform_path, PLATFORM_SPECIFIC_MODULE_NAME + ".py"]) + module = importlib.machinery.SourceFileLoader(PLATFORM_SPECIFIC_MODULE_NAME, module_file).load_module() + except IOError: + return -1 + try: + platform_status_class = getattr(module, PLATFORM_SPECIFIC_CLASS_NAME) + except AttributeError: + return -2 + return 0 + + +def printerr(msg): + print("\033[0;31m%s\033[0m" % msg) + + +def print_console(msg): + print(msg) + + +val_t = load_platform_monitor() +if val_t != 0: + raise Exception("load monitor.py error") + + +def print_platform(): + platform_info = get_platform_name() + print_console(platform_info) + print_console("") + + +def print_cputemp_sensors(): + val_ret = get_call_value_by_function("getcputemp") + print_info_str = "" + toptile = "Onboard coretemp Sensors:" + formatstr = " {name:<20} : {temp} C (high = {max} C , crit = {crit} C )" + + if len(val_ret) != 0: + print_info_str += toptile + '\n' + for item in val_ret: + print_info_str += formatstr.format(**item) + '\n' + print_console(print_info_str) + + +def print_boardtemp(): + val_ret = get_call_value_by_function("getTemp") + print_info_str = "" + toptile = "Onboard Temperature Sensors:" + errformat = " {id:<20} : {errmsg}" + formatstr = " {id:<20} : {temp1_input} C (high = {temp1_max} C, hyst = {temp1_max_hyst} C)" + + if len(val_ret) != 0: + print_info_str += toptile + '\n' + for item in val_ret: + realformat = formatstr if item.get('errcode', 0) == 0 else errformat + print_info_str += realformat.format(**item) + '\n' + print_console(print_info_str) + + +def print_mactemp_sensors(): + val_ret = get_call_value_by_function("getmactemp") + print_info_str = "" + toptile = "Onboard MAC Temperature Sensors:" + errformat = " {id:<20} : {errmsg}" + formatstr = " {id:<20} : {temp_input} C" + + if len(val_ret) != 0: + print_info_str += toptile + '\n' + for item in val_ret: + realformat = formatstr if item.get('errcode', 0) == 0 else errformat + print_info_str += realformat.format(**item) + '\n' + print_console(print_info_str) + + +def print_macpower_sensors(): + val_ret = get_call_value_by_function("getmacpower") + print_info_str = "" + toptile = "Onboard MAC Power Sensors:" + errformat = " {id:<20} : {errmsg}" + formatstr = " {id:<20} : {power_input} W" + + if len(val_ret) != 0: + print_info_str += toptile + '\n' + for item in val_ret: + realformat = formatstr if item.get('errcode', 0) == 0 else errformat + print_info_str += realformat.format(**item) + '\n' + print_console(print_info_str) + + +def print_fan_sensor(): + val_ret = get_call_value_by_function("checkFan") + print_info_str = "" + toptile = "Onboard fan Sensors:" + errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" + fan_signle_rotor_format = " {id} : \n" \ + " fan_type : {fan_type}\n" \ + " sn : {sn}\n" \ + " hw_version: {hw_version}\n" \ + " Speed : {Speed} RPM\n" \ + " status : {errmsg} \n" + fan_double_rotor_format = " {id} : \n" \ + " fan_type : {fan_type}\n" \ + " sn : {sn}\n" \ + " hw_version: {hw_version}\n" \ + " Speed :\n" \ + " speed_front : {rotor1_speed:<5} RPM\n" \ + " speed_rear : {rotor2_speed:<5} RPM\n" \ + " status : {errmsg} \n" + + if len(val_ret) != 0: + print_info_str += toptile + '\n' + for item in val_ret: + if item.get('Speed', None) is None: + realformat = fan_double_rotor_format if item.get('errcode', 0) == 0 else errformat + else: + realformat = fan_signle_rotor_format if item.get('errcode', 0) == 0 else errformat + print_info_str += realformat.format(**item) + print_console(print_info_str) + + +def print_psu_sensor(): + val_ret = get_call_value_by_function("getPsu") + print_info_str = "" + toptile = "Onboard Power Supply Unit Sensors:" + errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" + psuformat = " {id} : \n" \ + " type : {type1}\n" \ + " sn : {sn}\n" \ + " in_current : {in_current} A\n" \ + " in_voltage : {in_voltage} V\n" \ + " out_current: {out_current} A\n" \ + " out_voltage: {out_voltage} V\n" \ + " temp : {temp} C \n" \ + " fan_speed : {fan_speed} RPM\n" \ + " in_power : {in_power} W\n" \ + " out_power : {out_power} W\n" + + if len(val_ret) != 0: + print_info_str += toptile + '\r\n' + for item in val_ret: + realformat = psuformat if item.get('errcode', 0) == 0 else errformat + print_info_str += realformat.format(**item) + print_console(print_info_str) + +def print_cust_psu_sensor(): + val_ret = get_call_value_by_function("getCustPsu") + print_info_str = "" + toptile = "Onboard Power Supply Unit Sensors:" + errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" + psuformat = " {id} : \n" \ + " Model : {type1}\n" \ + " Serial : {sn}\n" \ + " HW Rev : {hw_version}\n" \ + " Status : {errmsg}\n" + + if len(val_ret) != 0: + print_info_str += toptile + '\r\n' + for item in val_ret: + realformat = psuformat if item.get('errcode', 0) == 0 else errformat + print_info_str += realformat.format(**item) + print_console(print_info_str) + + +def print_slot_sensor(): + val_ret = get_call_value_by_function("checkSlot") + print_info_str = "" + toptile = "Onboard slot Sensors:" + errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" + psuformat = " {id} : \n" \ + " slot_type : {slot_type}\n" \ + " sn : {sn}\n" \ + " hw_version : {hw_version} \n" \ + " status : {errmsg}\n" + + if len(val_ret) != 0: + print_info_str += toptile + '\r\n' + for item in val_ret: + realformat = psuformat if item.get('errcode', 0) == 0 else errformat + print_info_str += realformat.format(**item) + print_console(print_info_str) + + +def print_boarddcdc(): + val_ret = get_call_value_by_function("getDcdc") + print_info_str = "" + toptile = "Onboard DCDC Sensors:" + errformat = " {id:<26} : {errmsg}" + formatstr = " {id:<26} : {dcdc_input:<6} {dcdc_unit:<1} (Min = {dcdc_min:<6} {dcdc_unit:<1}, Max = {dcdc_max:<6} {dcdc_unit:<1})" + + if len(val_ret) != 0: + print_info_str += toptile + '\n' + for item in val_ret: + realformat = formatstr if item.get('errcode', 0) == 0 else errformat + print_info_str += realformat.format(**item) + '\n' + print_console(print_info_str) + + +def get_call_value_by_function(function_name): + valtemp = [] + if hasattr(platform_status_class, function_name): + test2_func = getattr(platform_status_class, function_name) + test2_func(valtemp) + return valtemp + + +def getsensors(): + print_platform() + print_cputemp_sensors() + print_boardtemp() + print_mactemp_sensors() + print_macpower_sensors() + print_fan_sensor() + print_psu_sensor() + print_cust_psu_sensor() + print_slot_sensor() + print_boarddcdc() + + +if __name__ == "__main__": + getsensors() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_test.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_test.py new file mode 100755 index 000000000000..da7119a9ce49 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_test.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- + +try: + import click + from platform_intf import platform_reg_read, platform_reg_write, platform_get_optoe_type + from platform_intf import platform_set_optoe_type, platform_sfp_read, platform_sfp_write +except ImportError as error: + raise ImportError('%s - required module not found' % str(error)) from error + + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def print_reg(info, offset): + try: + size = len(info) + j = offset % 16 + tmp = j + offset -= j + print_buf = "\n " + + for i in range(16): + print_buf = print_buf + "%2x " % i + print(print_buf) + + print_buf = None + for i in range(size + j): + if i % 16 == 0: + print_buf = "" + print_buf = "0x%08x " % offset + offset = offset + 16 + if tmp: + print_buf = print_buf + " " + tmp = tmp - 1 + else: + print_buf = print_buf + "%02x " % info[i - j] + if (i + 1) % 16 == 0 or i == size + j - 1: + print(print_buf) + except Exception as e: + msg = str(e) + print("i = %d, j = %d," % (i, j)) + print(msg) + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''platform_test main''' + + +@main.command() +@click.argument('dev_type', required=True) +@click.argument('dev_id', required=True) +@click.argument('offset', required=True) +@click.argument('size', required=True) +def reg_rd(dev_type, dev_id, offset, size): + '''read cpld/fpga reg''' + ret, info = platform_reg_read(int(dev_type), int(dev_id), int(offset), int(size)) + print(ret) + if ret is True: + print_reg(info, int(offset)) + else: + print(info) + + +@main.command() +@click.argument('dev_type', required=True) +@click.argument('dev_id', required=True) +@click.argument('offset', required=True) +@click.argument('value', required=True) +def reg_wr(dev_type, dev_id, offset, value): + '''write cpld/fpga reg''' + value_list = [] + value_list.append(int(value)) + ret, info = platform_reg_write(int(dev_type), int(dev_id), int(offset), value_list) + print(ret) + print(info) + + +@main.command() +@click.argument('port', required=True) +def get_optoe_type(port): + '''get optoe type''' + ret, info = platform_get_optoe_type(int(port)) + print(ret) + print(info) + + +@main.command() +@click.argument('port', required=True) +@click.argument('optoe_type', required=True) +def set_optoe_type(port, optoe_type): + '''set optoe type''' + ret, info = platform_set_optoe_type(int(port), int(optoe_type)) + print(ret) + print(info) + + +@main.command() +@click.argument('port_id', required=True) +@click.argument('offset', required=True) +@click.argument('size', required=True) +def sfp_rd(port_id, offset, size): + '''read sfp''' + ret, info = platform_sfp_read(int(port_id), int(offset), int(size)) + print(ret) + if ret is True: + print_reg(info, int(offset)) + else: + print(info) + + +@main.command() +@click.argument('port_id', required=True) +@click.argument('offset', required=True) +@click.argument('value', required=True) +def sfp_wr(port_id, offset, value): + '''write sfp''' + value_list = [] + value_list.append(int(value)) + ret, info = platform_sfp_write(int(port_id), int(offset), value_list) + print(ret) + print(info) + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_util.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_util.py new file mode 100755 index 000000000000..71a97e5a236d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_util.py @@ -0,0 +1,838 @@ +#!/usr/bin/python3 + +import sys +import os +import re +import subprocess +import shlex +import time +import mmap +import glob +import logging.handlers +import shutil +import gzip +import ast + + +CONFIG_DB_PATH = "/etc/sonic/config_db.json" +MAILBOX_DIR = "/sys/bus/i2c/devices/" + + +__all__ = [ + "strtoint", + "byteTostr", + "getplatform_name", + "wbi2cget", + "wbi2cset", + "wbpcird", + "wbpciwr", + "wbi2cgetWord", + "wbi2csetWord", + "wbi2cset_pec", + "wbi2cset_wordpec", + "wbsysset", + "dev_file_read", + "dev_file_write", + "wb_os_system", + "io_rd", + "io_wr", + "exec_os_cmd", + "exec_os_cmd_log", + "write_sysfs", + "read_sysfs", + "get_sysfs_value", + "write_sysfs_value", + "get_value", + "set_value", + "getSdkReg", + "getMacTemp", + "getMacTemp_sysfs", + "get_format_value" +] + +class CodeVisitor(ast.NodeVisitor): + + def __init__(self): + self.value = None + + def get_value(self): + return self.value + + def get_op_value(self, node): + if isinstance(node, ast.Call): # node is func call + value = self.visit_Call(node) + elif isinstance(node, ast.BinOp): # node is BinOp + value = self.visit_BinOp(node) + elif isinstance(node, ast.UnaryOp): # node is UnaryOp + value = self.visit_UnaryOp(node) + elif isinstance(node, ast.Num): # node is Num Constant + value = node.n + elif isinstance(node, ast.Str): # node is Str Constant + value = node.s + else: + raise NotImplementedError("Unsupport operand type: %s" % type(node)) + return value + + def visit_UnaryOp(self, node): + ''' + node.op: operand type, only support ast.UAdd/ast.USub + node.operand: only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.UnaryOp + ''' + + operand_value = self.get_op_value(node.operand) + if isinstance(node.op, ast.UAdd): + self.value = operand_value + elif isinstance(node.op, ast.USub): + self.value = 0 - operand_value + else: + raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) + return self.value + + def visit_BinOp(self, node): + ''' + node.left: left operand, only support ast.Call/ast.Constant(ast.Num)/ast.BinOp + node.op: operand type, only support ast.Add/ast.Sub/ast.Mult/ast.Div + node.right: right operan, only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp + ''' + left_value = self.get_op_value(node.left) + right_value = self.get_op_value(node.right) + + if isinstance(node.op, ast.Add): + self.value = left_value + right_value + elif isinstance(node.op, ast.Sub): + self.value = left_value - right_value + elif isinstance(node.op, ast.Mult): + self.value = left_value * right_value + elif isinstance(node.op, ast.Div): + self.value = left_value / right_value + else: + raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) + return self.value + + def visit_Call(self, node): + ''' + node.func.id: func name, only support 'float', 'int', 'str' + node.args: func args list,only support ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.Call + str/float only support one parameter, eg: float(XXX), str(xxx) + int support one or two parameters, eg: int(xxx) or int(xxx, 16) + xxx can be ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp + ''' + calc_tuple = ("float", "int", "str") + + if node.func.id not in calc_tuple: + raise NotImplementedError("Unsupport function call type: %s" % node.func.id) + + args_val_list = [] + for item in node.args: + ret = self.get_op_value(item) + args_val_list.append(ret) + + if node.func.id == "str": + if len(args_val_list) != 1: + raise TypeError("str() takes 1 positional argument but %s were given" % len(args_val_list)) + value = str(args_val_list[0]) + self.value = value + return value + + if node.func.id == "float": + if len(args_val_list) != 1: + raise TypeError("float() takes 1 positional argument but %s were given" % len(args_val_list)) + value = float(args_val_list[0]) + self.value = value + return value + # int + if len(args_val_list) == 1: + value = int(args_val_list[0]) + self.value = value + return value + if len(args_val_list) == 2: + value = int(args_val_list[0], args_val_list[1]) + self.value = value + return value + raise TypeError("int() takes 1 or 2 arguments (%s given)" % len(args_val_list)) + +def inttostr(vl, length): + if not isinstance(vl, int): + raise Exception(" type error") + index = 0 + ret_t = "" + while index < length: + ret = 0xff & (vl >> index * 8) + ret_t += chr(ret) + index += 1 + return ret_t + + +def strtoint(str_tmp): + value = 0 + rest_v = str_tmp.replace("0X", "").replace("0x", "") + str_len = len(rest_v) + for index, val in enumerate(rest_v): + value |= int(val, 16) << ((str_len - index - 1) * 4) + return value + + +def inttobytes(val, length): + if not isinstance(val, int): + raise Exception("type error") + data_array = bytearray() + index = 0 + while index < length: + ret = 0xff & (val >> index * 8) + data_array.append(ret) + index += 1 + return data_array + + +def byteTostr(val): + strtmp = '' + for value in val: + strtmp += chr(value) + return strtmp + + +def typeTostr(val): + strtmp = '' + if isinstance(val, bytes): + strtmp = byteTostr(val) + return strtmp + + +def getonieplatform(path): + if not os.path.isfile(path): + return "" + machine_vars = {} + with open(path) as machine_file: + for line in machine_file: + tokens = line.split('=') + if len(tokens) < 2: + continue + machine_vars[tokens[0]] = tokens[1].strip() + return machine_vars.get("onie_platform") + + +def getplatform_config_db(): + if not os.path.isfile(CONFIG_DB_PATH): + return "" + val = os.popen("sonic-cfggen -j %s -v DEVICE_METADATA.localhost.platform" % CONFIG_DB_PATH).read().strip() + if len(val) <= 0: + return "" + return val + + +def getplatform_name(): + if os.path.isfile('/host/machine.conf'): + return getonieplatform('/host/machine.conf') + if os.path.isfile('/etc/sonic/machine.conf'): + return getonieplatform('/etc/sonic/machine.conf') + return getplatform_config_db() + + +def wbi2cget(bus, devno, address, word=None): + if word is None: + command_line = "i2cget -f -y %d 0x%02x 0x%02x " % (bus, devno, address) + else: + command_line = "i2cget -f -y %d 0x%02x 0x%02x %s" % (bus, devno, address, word) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = wb_os_system(command_line) + if ret == 0: + return True, ret_t + time.sleep(0.1) + return False, ret_t + + +def wbi2cset(bus, devno, address, byte): + command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x" % ( + bus, devno, address, byte) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = wb_os_system(command_line) + if ret == 0: + return True, ret_t + return False, ret_t + + +def wbpcird(pcibus, slot, fn, resource, offset): + '''read pci register''' + if offset % 4 != 0: + return "ERR offset: %d not 4 bytes align" + filename = "/sys/bus/pci/devices/0000:%02x:%02x.%x/resource%d" % (int(pcibus), int(slot), int(fn), int(resource)) + with open(filename, "r+") as file: + size = os.path.getsize(filename) + data = mmap.mmap(file.fileno(), size) + result = data[offset: offset + 4] + s = result[::-1] + val = 0 + for value in s: + val = val << 8 | value + data.close() + return "0x%08x" % val + + +def wbpciwr(pcibus, slot, fn, resource, offset, data): + '''write pci register''' + ret = inttobytes(data, 4) + filename = "/sys/bus/pci/devices/0000:%02x:%02x.%x/resource%d" % (int(pcibus), int(slot), int(fn), int(resource)) + with open(filename, "r+") as file: + size = os.path.getsize(filename) + data = mmap.mmap(file.fileno(), size) + data[offset: offset + 4] = ret + result = data[offset: offset + 4] + s = result[::-1] + val = 0 + for value in s: + val = val << 8 | value + data.close() + + +def wbi2cgetWord(bus, devno, address): + command_line = "i2cget -f -y %d 0x%02x 0x%02x w" % (bus, devno, address) + retrytime = 3 + ret_t = "" + for i in range(retrytime): + ret, ret_t = wb_os_system(command_line) + if ret == 0: + return True, ret_t + return False, ret_t + + +def wbi2csetWord(bus, devno, address, byte): + command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%x w" % ( + bus, devno, address, byte) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = wb_os_system(command_line) + if ret == 0: + return True, ret_t + return False, ret_t + + +def wbi2cset_pec(bus, devno, address, byte): + command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x bp" % ( + bus, devno, address, byte) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = wb_os_system(command_line) + if ret == 0: + return True, ret_t + return False, ret_t + + +def wbi2cset_wordpec(bus, devno, address, byte): + command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x wp" % ( + bus, devno, address, byte) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = wb_os_system(command_line) + if ret == 0: + return True, ret_t + return False, ret_t + + +def wbsysset(location, value): + command_line = "echo 0x%02x > %s" % (value, location) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = wb_os_system(command_line) + if ret == 0: + return True, ret_t + return False, ret_t + + +def dev_file_read(path, offset, read_len): + val_list = [] + msg = "" + ret = "" + fd = -1 + + if not os.path.exists(path): + msg = path + " not found !" + return False, msg + + try: + fd = os.open(path, os.O_RDONLY) + os.lseek(fd, offset, os.SEEK_SET) + ret = os.read(fd, read_len) + for item in ret: + val_list.append(item) + except Exception as e: + msg = str(e) + return False, msg + finally: + if fd > 0: + os.close(fd) + return True, val_list + + +def dev_file_write(path, offset, buf_list): + msg = "" + fd = -1 + + if not isinstance(buf_list, list) or len(buf_list) == 0: + msg = "buf:%s is not list type or is NONE !" % buf_list + return False, msg + + if not os.path.exists(path): + msg = path + " not found !" + return False, msg + + try: + fd = os.open(path, os.O_WRONLY) + os.lseek(fd, offset, os.SEEK_SET) + ret = os.write(fd, bytes(buf_list)) + except Exception as e: + msg = str(e) + return False, msg + finally: + if fd > 0: + os.close(fd) + + return True, ret + + +def wb_os_system(cmd): + status, output = subprocess.getstatusoutput(cmd) + return status, output + + +def io_rd(reg_addr, read_len=1): + try: + regaddr = 0 + if isinstance(reg_addr, int): + regaddr = reg_addr + else: + regaddr = int(reg_addr, 16) + devfile = "/dev/port" + fd = os.open(devfile, os.O_RDWR | os.O_CREAT) + os.lseek(fd, regaddr, os.SEEK_SET) + val = os.read(fd, read_len) + return "".join(["%02x" % item for item in val]) + except ValueError: + return None + except Exception as e: + print(e) + return None + finally: + os.close(fd) + + +def io_wr(reg_addr, reg_data): + try: + regdata = 0 + regaddr = 0 + if isinstance(reg_addr, int): + regaddr = reg_addr + else: + regaddr = int(reg_addr, 16) + if isinstance(reg_data, int): + regdata = reg_data + else: + regdata = int(reg_data, 16) + devfile = "/dev/port" + fd = os.open(devfile, os.O_RDWR | os.O_CREAT) + os.lseek(fd, regaddr, os.SEEK_SET) + os.write(fd, regdata.to_bytes(1, 'little')) + return True + except ValueError as e: + print(e) + return False + except Exception as e: + print(e) + return False + finally: + os.close(fd) + + +def exec_os_cmd(cmd): + status, output = subprocess.getstatusoutput(cmd) + return status, output + + +def exec_os_cmd_log(cmd): + proc = subprocess.Popen(shlex.split(cmd), stdin=subprocess.PIPE, shell=False, stderr=sys.stderr, close_fds=True, + stdout=sys.stdout, universal_newlines=True, bufsize=1) + proc.wait() + stdout = proc.communicate()[0] + stdout = typeTostr(stdout) + return proc.returncode, stdout + + +def write_sysfs(location, value): + try: + if not os.path.isfile(location): + return False, ("location[%s] not found !" % location) + with open(location, 'w') as fd1: + fd1.write(value) + except Exception as e: + return False, (str(e) + " location[%s]" % location) + return True, ("set location[%s] %s success !" % (location, value)) + + +def read_sysfs(location): + try: + locations = glob.glob(location) + with open(locations[0], 'rb') as fd1: + retval = fd1.read() + retval = typeTostr(retval) + retval = retval.rstrip('\r\n') + retval = retval.lstrip(" ") + except Exception as e: + return False, (str(e) + "location[%s]" % location) + return True, retval + + +def get_pmc_register(reg_name): + retval = 'ERR' + mb_reg_file = MAILBOX_DIR + reg_name + filepath = glob.glob(mb_reg_file) + if len(filepath) == 0: + return "%s %s notfound" % (retval, mb_reg_file) + mb_reg_file = filepath[0] + if not os.path.isfile(mb_reg_file): + return "%s %s notfound" % (retval, mb_reg_file) + try: + with open(mb_reg_file, 'r') as fd: + retval = fd.read() + except Exception as error: + retval = retval + str(error) + retval = retval.rstrip('\r\n') + retval = retval.lstrip(" ") + return retval + + +def get_sysfs_value(location): + pos_t = str(location) + name = get_pmc_register(pos_t) + return name + + +def write_sysfs_value(reg_name, value): + fileLoc = MAILBOX_DIR + reg_name + try: + if not os.path.isfile(fileLoc): + print(fileLoc, 'not found !') + return False + with open(fileLoc, 'w') as fd: + fd.write(value) + except Exception: + print("Unable to open " + fileLoc + "file !") + return False + return True + + +def get_value_once(config): + try: + way = config.get("gettype") + int_decode = config.get("int_decode", 16) + if way == 'sysfs': + loc = config.get("loc") + ret, val = read_sysfs(loc) + if ret is True: + return True, int(val, int_decode) + return False, ("sysfs read %s failed. log:%s" % (loc, val)) + if way == "i2c": + bus = config.get("bus") + addr = config.get("loc") + offset = config.get("offset", 0) + ret, val = wbi2cget(bus, addr, offset) + if ret is True: + return True, int(val, int_decode) + return False, ("i2c read failed. bus:%d , addr:0x%x, offset:0x%x" % (bus, addr, offset)) + if way == "io": + io_addr = config.get('io_addr') + val = io_rd(io_addr) + if len(val) != 0: + return True, int(val, int_decode) + return False, ("io_addr read 0x%x failed" % io_addr) + if way == "i2cword": + bus = config.get("bus") + addr = config.get("loc") + offset = config.get("offset") + ret, val = wbi2cgetWord(bus, addr, offset) + if ret is True: + return True, int(val, int_decode) + return False, ("i2cword read failed. bus:%d, addr:0x%x, offset:0x%x" % (bus, addr, offset)) + if way == "devfile": + path = config.get("path") + offset = config.get("offset") + read_len = config.get("read_len") + ret, val_list = dev_file_read(path, offset, read_len) + if ret is True: + return True, val_list + return False, ("devfile read failed. path:%s, offset:0x%x, read_len:%d" % (path, offset, read_len)) + if way == 'cmd': + cmd = config.get("cmd") + ret, val = exec_os_cmd(cmd) + if ret: + return False, ("cmd read exec %s failed, log: %s" % (cmd, val)) + return True, int(val, int_decode) + if way == 'file_exist': + judge_file = config.get('judge_file', None) + if os.path.exists(judge_file): + return True, True + return True, False + return False, "not support read type" + except Exception as e: + return False, ("get_value_once exception:%s happen" % str(e)) + + +def set_value_once(config): + try: + delay_time = config.get("delay", None) + if delay_time is not None: + time.sleep(delay_time) + + way = config.get("gettype") + if way == 'sysfs': + loc = config.get("loc") + value = config.get("value") + mask = config.get("mask", 0xff) + mask_tuple = (0xff, 0) + if mask not in mask_tuple: + ret, read_value = read_sysfs(loc) + if ret is True: + read_value = int(read_value, base=16) + value = (read_value & mask) | value + else: + return False, ("sysfs read %s failed. log:%s" % (loc, read_value)) + ret, log = write_sysfs(loc, "0x%02x" % value) + if ret is not True: + return False, ("sysfs %s write 0x%x failed" % (loc, value)) + return True, ("sysfs write 0x%x success" % value) + if way == "i2c": + bus = config.get("bus") + addr = config.get("loc") + offset = config.get("offset") + value = config.get("value") + mask = config.get("mask", 0xff) + mask_tuple = (0xff, 0) + if mask not in mask_tuple: + ret, read_value = wbi2cget(bus, addr, offset) + if ret is True: + read_value = int(read_value, base=16) + value = (read_value & mask) | value + else: + return False, ("i2c read failed. bus:%d , addr:0x%x, offset:0x%x" % (bus, addr, offset)) + ret, log = wbi2cset(bus, addr, offset, value) + if ret is not True: + return False, ("i2c write bus:%d, addr:0x%x, offset:0x%x, value:0x%x failed" % + (bus, addr, offset, value)) + return True, ("i2c write bus:%d, addr:0x%x, offset:0x%x, value:0x%x success" % + (bus, addr, offset, value)) + if way == "io": + io_addr = config.get('io_addr') + value = config.get('value') + mask = config.get("mask", 0xff) + mask_tuple = (0xff, 0) + if mask not in mask_tuple: + read_value = io_rd(io_addr) + if read_value is None: + return False, ("io_addr 0x%x read failed" % (io_addr)) + read_value = int(read_value, base=16) + value = (read_value & mask) | value + ret = io_wr(io_addr, value) + if ret is not True: + return False, ("io_addr 0x%x write 0x%x failed" % (io_addr, value)) + return True, ("io_addr 0x%x write 0x%x success" % (io_addr, value)) + if way == 'i2cword': + bus = config.get("bus") + addr = config.get("loc") + offset = config.get("offset") + value = config.get("value") + mask = config.get("mask", 0xff) + mask_tuple = (0xff, 0) + if mask not in mask_tuple: + ret, read_value = wbi2cgetWord(bus, addr, offset) + if ret is True: + read_value = int(read_value, base=16) + value = (read_value & mask) | value + else: + return False, ("i2c read word failed. bus:%d , addr:0x%x, offset:0x%x" % (bus, addr, offset)) + ret, log = wbi2csetWord(bus, addr, offset, value) + if ret is not True: + return False, ("i2cword write bus:%d, addr:0x%x, offset:0x%x, value:0x%x failed" % + (bus, addr, offset, value)) + return True, ("i2cword write bus:%d, addr:0x%x, offset:0x%x, value:0x%x success" % + (bus, addr, offset, value)) + if way == "devfile": + path = config.get("path") + offset = config.get("offset") + buf_list = config.get("value") + ret, log = dev_file_write(path, offset, buf_list) + if ret is True: + return True, ("devfile write path:%s, offset:0x%x, buf_list:%s success." % (path, offset, buf_list)) + return False, ("devfile read path:%s, offset:0x%x, buf_list:%s failed.log:%s" % + (path, offset, buf_list, log)) + if way == 'cmd': + cmd = config.get("cmd") + ret, log = exec_os_cmd(cmd) + if ret: + return False, ("cmd write exec %s failed, log: %s" % (cmd, log)) + return True, ("cmd write exec %s success" % cmd) + if way == 'bit_wr': + mask = config.get("mask") + bit_val = config.get("value") + val_config = config.get("val_config") + ret, rd_value = get_value_once(val_config) + if ret is False: + return False, ("bit_wr read failed, log: %s" % rd_value) + wr_val = (rd_value & mask) | bit_val + val_config["value"] = wr_val + ret, log = set_value_once(val_config) + if ret is False: + return False, ("bit_wr failed, log: %s" % log) + return True, ("bit_wr success, log: %s" % log) + if way == 'creat_file': + file_name = config.get("file") + ret, log = exec_os_cmd("touch %s" % file_name) + if ret: + return False, ("creat file %s failed, log: %s" % (file_name, log)) + exec_os_cmd("sync") + return True, ("creat file %s success" % file_name) + if way == 'remove_file': + file_name = config.get("file") + ret, log = exec_os_cmd("rm -rf %s" % file_name) + if ret: + return False, ("remove file %s failed, log: %s" % (file_name, log)) + exec_os_cmd("sync") + return True, ("remove file %s success" % file_name) + return False, "not support write type" + except Exception as e: + return False, ("set_value_once exception:%s happen" % str(e)) + + +def get_value(config): + retrytime = 6 + for i in range(retrytime): + ret, val = get_value_once(config) + if ret is True: + return True, val + time.sleep(0.1) + return False, val + + +def set_value(config): + retrytime = 6 + ignore_result_flag = config.get("ignore_result", 0) + for i in range(retrytime): + ret, log = set_value_once(config) + if ret is True: + return True, log + if ignore_result_flag == 1: + return True, log + time.sleep(0.1) + return False, log + + +class CompressedRotatingFileHandler(logging.handlers.RotatingFileHandler): + def doRollover(self): + """ + Do a rollover, as described in __init__(). + """ + if self.stream: + self.stream.close() + self.stream = None + if self.backupCount > 0: + for i in range(self.backupCount - 1, 0, -1): + sfn = "%s.%d.gz" % (self.baseFilename, i) + dfn = "%s.%d.gz" % (self.baseFilename, i + 1) + if os.path.exists(sfn): + if os.path.exists(dfn): + os.remove(dfn) + os.rename(sfn, dfn) + dfn = self.baseFilename + ".1.gz" + if os.path.exists(dfn): + os.remove(dfn) + # These two lines below are the only new lines. I commented out the os.rename(self.baseFilename, dfn) and + # replaced it with these two lines. + with open(self.baseFilename, 'rb') as f_in, gzip.open(dfn, 'wb') as f_out: + shutil.copyfileobj(f_in, f_out) + self.mode = 'w' + self.stream = self._open() + + +def getSdkReg(reg): + try: + cmd = "bcmcmd -t 1 'getr %s ' < /dev/null" % reg + ret, result = wb_os_system(cmd) + result_t = result.strip().replace("\r", "").replace("\n", "") + if ret != 0 or "Error:" in result_t: + return False, result + patt = r"%s.(.*):(.*)>drivshell" % reg + rt = re.findall(patt, result_t, re.S) + test = re.findall("=(.*)", rt[0][0])[0] + except Exception: + return False, 'getsdk register error' + return True, test + + +def getMacTemp(): + result = {} + wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") + ret, log = wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") + if ret: + return False, result + logs = log.splitlines() + for line in logs: + if "average" in line: + b = re.findall(r'\d+.\d+', line) + result["average"] = b[0] + elif "maximum" in line: + b = re.findall(r'\d+.\d+', line) + result["maximum"] = b[0] + return True, result + + +def getMacTemp_sysfs(mactempconf): + temp = -1000000 + try: + temp_list = [] + mac_temp_loc = mactempconf.get("loc", []) + mac_temp_flag = mactempconf.get("flag", None) + if mac_temp_flag is not None: + gettype = mac_temp_flag.get('gettype') + okbit = mac_temp_flag.get('okbit') + okval = mac_temp_flag.get('okval') + if gettype == "io": + io_addr = mac_temp_flag.get('io_addr') + val = io_rd(io_addr) + if val is None: + raise Exception("get mac_flag by io failed.") + else: + bus = mac_temp_flag.get('bus') + loc = mac_temp_flag.get('loc') + offset = mac_temp_flag.get('offset') + ind, val = wbi2cget(bus, loc, offset) + if ind is not True: + raise Exception("get mac_flag by i2c failed.") + val_t = (int(val, 16) & (1 << okbit)) >> okbit + if val_t != okval: + raise Exception("mac_flag invalid, val_t:%d." % val_t) + for loc in mac_temp_loc: + temp_s = get_sysfs_value(loc) + if isinstance(temp_s, str) and temp_s.startswith("ERR"): + raise Exception("get mac temp error. loc:%s" % loc) + temp_t = int(temp_s) + if temp_t == -1000000: + raise Exception("mac temp invalid.loc:%s" % loc) + temp_list.append(temp_t) + temp_list.sort(reverse=True) + temp = temp_list[0] + except Exception: + return False, temp + return True, temp + +def get_format_value(format_str): + ast_obj = ast.parse(format_str, mode='eval') + visitor = CodeVisitor() + visitor.visit(ast_obj) + ret = visitor.get_value() + return ret + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/pmon_syslog.py b/platform/broadcom/sonic-platform-modules-micas/common/script/pmon_syslog.py new file mode 100755 index 000000000000..8bdceef8c1b5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/pmon_syslog.py @@ -0,0 +1,519 @@ +#!/usr/bin/python3 +# * onboard interval check +# * FAN trays +# * PSU +# * SFF +import time +import syslog +import traceback +import glob +from platform_config import PMON_SYSLOG_STATUS + +PMON_DEBUG_FILE = "/etc/.pmon_syslog_debug_flag" +debuglevel = 0 +PMONERROR = 1 +PMONDEBUG = 2 + + +def pmon_debug(s): + if PMONDEBUG & debuglevel: + syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def pmon_error(s): + if PMONERROR & debuglevel: + syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def dev_syslog(s): + syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_NOTICE, s) + + +# status +STATUS_PRESENT = 'PRESENT' +STATUS_ABSENT = 'ABSENT' +STATUS_OK = 'OK' +STATUS_NOT_OK = 'NOT OK' +STATUS_FAILED = 'FAILED' + + +class checkBase(object): + def __init__(self, path, dev_name, display_name, obj_type, config): + self._peroid_syslog = None + self._peroid_failed_syslog = None # exception + self._preDevStatus = None + self._path = path + self._name = dev_name + self._display_name = display_name + self._type = obj_type + self._config = config + + def getCurstatus(self): + # get ok/not ok/absent status + status, log = self.getPresent() + if status == STATUS_PRESENT: + # check status + property_status, log = self.getStatus() + if property_status is not None: + status = property_status + return status, log + + def getPresent(self): + presentFilepath = self.getPath() + try: + # get ok/not ok/absent status + presentConfig = self._config["present"] + mask = presentConfig.get("mask", 0xff) + absent_val = presentConfig.get("ABSENT", None) + absent_val = absent_val & mask + with open(presentFilepath, "r") as fd: + retval = fd.read() + if int(retval) == absent_val: + return STATUS_ABSENT, None + return STATUS_PRESENT, None + except Exception as e: + return STATUS_FAILED, (str(e) + " location[%s]" % presentFilepath) + + def getStatus(self): + if "status" in self._config: + statusConfig = self._config["status"] + for itemConfig in statusConfig: + mask = itemConfig.get("mask", 0xff) + ok_val = itemConfig.get("okval", None) + ok_val = ok_val & mask + Filepath = itemConfig["path"] % self._name + try: + with open(Filepath, "r") as fd1: + retval = fd1.read() + if int(retval) != ok_val: + return STATUS_NOT_OK, None + except Exception as e: + return STATUS_FAILED, (str(e) + " location[%s]" % Filepath) + return STATUS_OK, None + return None, None + + def getPath(self): + return self._path + + def getName(self): + return self._name + + def getType(self): + return self._type + + def getDisplayName(self): + return self._display_name + + def getnochangedMsgFlag(self): + return self._config["nochangedmsgflag"] + + def getnochangedMsgTime(self): + return self._config["nochangedmsgtime"] + + def getnoprintFirstTimeFlag(self): + return self._config["noprintfirsttimeflag"] + + def checkStatus(self): + # syslog msg + dev_type = self.getType() + display_name = self.getDisplayName() + nochangedMsgTime = self.getnochangedMsgTime() + getnochangedMsgFlag = self.getnochangedMsgFlag() + noprintFirstTimeFlag = self.getnoprintFirstTimeFlag() + MSG_IN = '%%PMON-5-' + dev_type + '_PLUG_IN: %s is PRESENT.' + MSG_OUT = '%%PMON-5-' + dev_type + '_PLUG_OUT: %s is ABSENT.' + MSG_OK = '%%PMON-5-' + dev_type + '_OK: %s is OK.' + MSG_NOT_OK = '%%PMON-5-' + dev_type + '_FAILED: %s is NOT OK.' + MSG_ABSENT = '%%PMON-5-' + dev_type + '_ABSENT: %s is ABSENT.' + MSG_UNKNOWN = '%%PMON-5-' + dev_type + '_UNKNOWN: %s is UNKNOWN.%s' + MSG_RECOVER = '%%PMON-5-' + dev_type + '_OK: %s is OK. Recover from ' + dev_type + ' FAILED.' + + curStatus, log = self.getCurstatus() + pmon_debug("%s: current status %s" % (display_name, curStatus)) + pmon_debug("%s: pre status %s" % (display_name, self._preDevStatus)) + pmon_debug("%s: peroid_syslog %s" % (display_name, self._peroid_syslog)) + + if curStatus == STATUS_FAILED: + # get status failed + if self._peroid_failed_syslog is not None: + if getnochangedMsgFlag and time.time() - self._peroid_failed_syslog >= nochangedMsgTime: + # absent as before for some time, notice + dev_syslog(MSG_UNKNOWN % (display_name, log)) + self._peroid_failed_syslog = time.time() + else: # first time failed + dev_syslog(MSG_UNKNOWN % (display_name, log)) + self._peroid_failed_syslog = time.time() + return + self._peroid_failed_syslog = time.time() + + if self._preDevStatus is None: + # 1st time + if noprintFirstTimeFlag == 1: + self._peroid_syslog = time.time() + else: + if curStatus == STATUS_PRESENT: + # present + dev_syslog(MSG_IN % display_name) + elif curStatus == STATUS_OK: + # ok + dev_syslog(MSG_OK % display_name) + elif curStatus == STATUS_NOT_OK: + # not ok + dev_syslog(MSG_NOT_OK % display_name) + self._peroid_syslog = time.time() + else: + # absent + dev_syslog(MSG_ABSENT % display_name) + self._peroid_syslog = time.time() + else: + # from 2nd time... + if self._preDevStatus == curStatus: + # status not changed + if self._preDevStatus == STATUS_ABSENT: + if self._peroid_syslog is not None: + if getnochangedMsgFlag and time.time() - self._peroid_syslog >= nochangedMsgTime: + # absent as before for some time, notice + dev_syslog(MSG_ABSENT % display_name) + self._peroid_syslog = time.time() + elif self._preDevStatus == STATUS_NOT_OK: + if self._peroid_syslog is not None: + if getnochangedMsgFlag and time.time() - self._peroid_syslog >= nochangedMsgTime: + # not ok as before for some time, notice + dev_syslog(MSG_NOT_OK % display_name) + self._peroid_syslog = time.time() + else: + # status changed + if self._preDevStatus == STATUS_ABSENT: + if curStatus == STATUS_NOT_OK: + # absent -> not ok + dev_syslog(MSG_IN % display_name) + dev_syslog(MSG_NOT_OK % display_name) + self._peroid_syslog = time.time() + elif curStatus == STATUS_OK: + # absent -> ok + dev_syslog(MSG_IN % display_name) + dev_syslog(MSG_OK % display_name) + else: + # absent -> prsent + dev_syslog(MSG_IN % display_name) + + elif self._preDevStatus == STATUS_OK: + if curStatus == STATUS_NOT_OK: + # ok -> not ok + dev_syslog(MSG_NOT_OK % display_name) + self._peroid_syslog = time.time() + elif curStatus == STATUS_ABSENT: + # ok -> absent + dev_syslog(MSG_OUT % display_name) + self._peroid_syslog = time.time() + elif self._preDevStatus == STATUS_PRESENT: + # present -> absent + dev_syslog(MSG_OUT % display_name) + self._peroid_syslog = time.time() + else: # not ok + if curStatus == STATUS_OK: + # not ok -> ok + dev_syslog(MSG_RECOVER % display_name) + dev_syslog(MSG_OK % display_name) + else: + # not ok -> absent + dev_syslog(MSG_OUT % display_name) + self._peroid_syslog = time.time() + self._preDevStatus = curStatus + + +class checkSfp(checkBase): + def __init__(self, path, dev_name, display_name, config): + super(checkSfp, self).__init__(path, dev_name, display_name, 'XCVR', config) + + def getPath(self): + super(checkSfp, self).getPath() + return self._path + + def getName(self): + super(checkSfp, self).getName() + return self._name + + def getType(self): + super(checkSfp, self).getType() + return self._type + + +class checkSlot(checkBase): + def __init__(self, path, dev_name, display_name, config): + super(checkSlot, self).__init__(path, dev_name, display_name, 'SLOT', config) + + def getPath(self): + super(checkSlot, self).getPath() + return self._path + + def getName(self): + super(checkSlot, self).getName() + return self._name + + def getType(self): + super(checkSlot, self).getType() + return self._type + + +class checkPSU(checkBase): + def __init__(self, path, dev_name, display_name, config): + super(checkPSU, self).__init__(path, dev_name, display_name, 'PSU', config) + + def getPath(self): + super(checkPSU, self).getPath() + return self._path + + def getName(self): + super(checkPSU, self).getName() + return self._name + + def getType(self): + super(checkPSU, self).getType() + return self._type + + +class checkFAN(checkBase): + def __init__(self, path, dev_name, display_name, config): + super(checkFAN, self).__init__(path, dev_name, display_name, 'FAN', config) + + def getPath(self): + super(checkFAN, self).getPath() + return self._path + + def getName(self): + super(checkFAN, self).getName() + return self._name + + def getType(self): + super(checkFAN, self).getType() + return self._type + + +class platformSyslog(): + def __init__(self): + self.__sfp_checklist = [] + self.__fan_checklist = [] + self.__psu_checklist = [] + self.__slot_checklist = [] + self.__temp_checklist = [] + self.temps_peroid_syslog = {} + self.normal_status = 0 + self.warning_status = 1 + self.critical_status = 2 + self.poweron_flag = 0 + + self.pmon_syslog_config = PMON_SYSLOG_STATUS.copy() + self.__pollingtime = self.pmon_syslog_config.get('polling_time', 3) + + tmpconfig = self.pmon_syslog_config.get('sffs', None) + if tmpconfig is not None: + preset_item = tmpconfig.get("present", {}) + path = preset_item.get("path", []) + for location in path: + if '*' not in location: + pmon_error("sff location config error: %s" % location) + continue + dev_name_index = 0 + loc_split_list = location.split('/') + for i, item in enumerate(loc_split_list): + if '*' in item: + dev_name_index = i + break + locations = glob.glob(location) + for dev_path in locations: + dev_name_list = dev_path.split('/') + # explame:get eth1 from /sys_switch/transceiver/eth1/present + dev_name = dev_name_list[dev_name_index] + dev_name_alias = tmpconfig.get("alias", {}) + display_name = dev_name_alias.get(dev_name, dev_name) + dev = checkSfp(dev_path, dev_name, display_name, tmpconfig) + self.__sfp_checklist.append(dev) + + tmpconfig = self.pmon_syslog_config.get('fans', None) + if tmpconfig is not None: + preset_item = tmpconfig.get("present", {}) + path = preset_item.get("path", []) + for location in path: + if '*' not in location: + pmon_error("fan location config error: %s" % location) + continue + dev_name_index = 0 + loc_split_list = location.split('/') + for i, item in enumerate(loc_split_list): + if '*' in item: + dev_name_index = i + break + locations = glob.glob(location) + for dev_path in locations: + dev_name_list = dev_path.split('/') + dev_name = dev_name_list[dev_name_index] + dev_name_alias = tmpconfig.get("alias", {}) + display_name = dev_name_alias.get(dev_name, dev_name) + dev = checkFAN(dev_path, dev_name, display_name, tmpconfig) + self.__fan_checklist.append(dev) + + tmpconfig = self.pmon_syslog_config.get('psus', None) + if tmpconfig is not None: + preset_item = tmpconfig.get("present", {}) + path = preset_item.get("path", []) + for location in path: + if '*' not in location: + pmon_error("psu location config error: %s" % location) + continue + dev_name_index = 0 + loc_split_list = location.split('/') + for i, item in enumerate(loc_split_list): + if '*' in item: + dev_name_index = i + break + locations = glob.glob(location) + for dev_path in locations: + dev_name_list = dev_path.split('/') + dev_name = dev_name_list[dev_name_index] + dev_name_alias = tmpconfig.get("alias", {}) + display_name = dev_name_alias.get(dev_name, dev_name) + dev = checkPSU(dev_path, dev_name, display_name, tmpconfig) + self.__psu_checklist.append(dev) + + tmpconfig = self.pmon_syslog_config.get('slots', None) + if tmpconfig is not None: + preset_item = tmpconfig.get("present", {}) + path = preset_item.get("path", []) + for location in path: + if '*' not in location: + pmon_error("slot location config error: %s" % location) + continue + dev_name_index = 0 + loc_split_list = location.split('/') + for i, item in enumerate(loc_split_list): + if '*' in item: + dev_name_index = i + break + locations = glob.glob(location) + for dev_path in locations: + dev_name_list = dev_path.split('/') + dev_name = dev_name_list[dev_name_index] + dev_name_alias = tmpconfig.get("alias", {}) + display_name = dev_name_alias.get(dev_name, dev_name) + dev = checkSlot(dev_path, dev_name, display_name, tmpconfig) + self.__slot_checklist.append(dev) + + tmpconfig = self.pmon_syslog_config.get('temps', None) + if tmpconfig is not None: + self.__temp_checklist = tmpconfig.get('temps_list', []) + self.__temps_pollingseconds = tmpconfig.get('over_temps_polling_seconds', None) + + def checkTempStaus(self, temp_item): + temp_name = temp_item.get('name', None) + input_path = temp_item.get('input_path', None) + warning_temp = temp_item.get('warning', None) + critical_temp = temp_item.get('critical', None) + input_accuracy = temp_item.get('input_accuracy', None) + if temp_name is None or input_path is None or warning_temp is None or critical_temp is None: + dev_syslog('%%PMON-5-TEMP_NOTICE: get temperature config parament failed.') + return + try: + locations = glob.glob(input_path) + with open(locations[0], "r") as fd: + input_temp = fd.read() + input_temp = float(input_temp) / float(input_accuracy) + + if 'time' not in temp_item: + temp_item['time'] = time.time() + temp_item['status'] = self.normal_status + if float(input_temp) >= float(warning_temp): + if float(input_temp) >= float(critical_temp): + if time.time() - \ + temp_item['time'] >= self.__temps_pollingseconds or temp_item['status'] != self.critical_status: + dev_syslog('%%PMON-5-TEMP_HIGH: %s temperature %sC is larger than max critical threshold %sC.' + % (temp_name, input_temp, critical_temp)) + temp_item['status'] = self.critical_status + temp_item['time'] = time.time() + else: + if time.time() - \ + temp_item['time'] >= self.__temps_pollingseconds or temp_item['status'] != self.warning_status: + dev_syslog('%%PMON-5-TEMP_HIGH: %s temperature %sC is larger than max warning threshold %sC.' + % (temp_name, input_temp, warning_temp)) + temp_item['status'] = self.warning_status + temp_item['time'] = time.time() + else: + pmon_debug( + "%s temperature %sC is in range [%s, %s]" % + (temp_name, input_temp, warning_temp, critical_temp)) + temp_item['status'] = self.normal_status + temp_item['time'] = time.time() + except Exception as e: + dev_syslog('%%PMON-5-TEMP_NOTICE: Cannot get %s temperature. Exception log: %s' % (temp_name, str(e))) + return + + def sysfs_precondition_check(self, check_module, check_project): + try: + tmpconfig = self.pmon_syslog_config.get(check_module, None) + if tmpconfig is not None: + check_list = tmpconfig.get(check_project, []) + for check_item in check_list: + location = check_item.get("path", None) + ok_val = check_item.get("ok_val", None) + mask = check_item.get("mask", 0xff) + ok_val = ok_val & mask + locations = glob.glob(location) + for power_path in locations: + with open(power_path, "r") as fd: + retval = fd.read() + if int(retval) != ok_val: + return + self.poweron_flag = 1 + except Exception as e: + dev_syslog('%%PMON-5-TEMP_NOTICE: Cannot check power status. Exception log: %s' % str(e)) + return + + def updateSysDeviceStatus(self): + if self.poweron_flag == 1: + for dev in self.__sfp_checklist: + dev.checkStatus() + else: + self.sysfs_precondition_check('sffs', 'power') + + for dev in self.__fan_checklist: + dev.checkStatus() + for dev in self.__psu_checklist: + dev.checkStatus() + for dev in self.__slot_checklist: + dev.checkStatus() + for temp_item in self.__temp_checklist: + self.checkTempStaus(temp_item) + + def getPollingtime(self): + return self.__pollingtime + + def debug_init(self): + global debuglevel + try: + with open(PMON_DEBUG_FILE, "r") as fd: + value = fd.read() + debuglevel = int(value) + except Exception: + debuglevel = 0 + + def doWork(self): + try: + self.debug_init() + self.updateSysDeviceStatus() + except Exception as e: + MSG_EXCEPTION = '%%PMON-5-NOTICE: Exception happened! info:%s' % str(e) + pmon_error(MSG_EXCEPTION % traceback.format_exc()) + + +def run(): + platform = platformSyslog() + while True: + platform.doWork() + time.sleep(platform.getPollingtime()) + + +if __name__ == '__main__': + run() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_cause.py b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_cause.py new file mode 100755 index 000000000000..2f125c5084c2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_cause.py @@ -0,0 +1,183 @@ +#!/usr/bin/python3 +# -*- coding: UTF-8 -*- +import sys +import os +import time +import syslog +from platform_util import get_value, set_value, exec_os_cmd, wb_os_system +from platform_config import REBOOT_CAUSE_PARA + +REBOOT_CAUSE_DEBUG_FILE = "/etc/.reboot_cause_debug" +REBOOT_CAUSE_STARTED_FLAG = "/tmp/.reboot_cause_started_flag" + +debuglevel = 0 + + +def record_syslog_debug(s): + if debuglevel: + syslog.openlog("REBOOT_CAUSE_DEBUG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def record_syslog(s): + syslog.openlog("REBOOT_CAUSE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_WARNING, s) + + +class RebootCause(): + def __init__(self): + self.reboot_cause_para = REBOOT_CAUSE_PARA.copy() + self.reboot_cause_list = self.reboot_cause_para.get('reboot_cause_list', None) + self.other_reboot_cause_record = self.reboot_cause_para.get('other_reboot_cause_record', None) + + def debug_init(self): + global debuglevel + if os.path.exists(REBOOT_CAUSE_DEBUG_FILE): + debuglevel = 1 + else: + debuglevel = 0 + + def monitor_point_check(self, item): + try: + gettype = item.get('gettype', None) + okval = item.get('okval', None) + compare_mode = item.get('compare_mode', "equal") + ret, value = get_value(item) + if ret is True: + if compare_mode == "equal": + if value == okval: + return True + elif compare_mode == "great": + if value > okval: + return True + elif compare_mode == "ignore": + return True + else: + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: compare_mode %s not match error.' % (compare_mode)) + else: + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: base point check type:%s not support.' % gettype) + except Exception as e: + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: base point check error. msg: %s.' % (str(e))) + return False + + def reboot_cause_record(self, item_list): + RET = {"RETURN_KEY1": 0} + try: + for item in item_list: + record_type = item.get('record_type', None) + if record_type == 'file': + file_mode = item.get('mode', None) + file_log = item.get('log', None) + file_path = item.get('path', None) + file_max_size = item.get('file_max_size', 0) + + if file_path is None: + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: record type is file, but path is none.') + continue + + if file_max_size > 0: + file_size = 0 + if os.path.exists(file_path): + file_size = os.path.getsize(file_path) // file_max_size + if file_size >= 1: + reocrd_cmd = "mv %s %s_bak" % (file_path, file_path) + status, output = exec_os_cmd(reocrd_cmd) + if status: + record_syslog( + '%%REBOOT_CAUSE-3-EXCEPTION: exec cmd %s failed, %s' % + (reocrd_cmd, output)) + + if file_mode == 'cover': + operate_cmd = ">" + elif file_mode == 'add': + operate_cmd = ">>" + else: + RET["RETURN_KEY1"] = -1 + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: file record mode:%s not support.' % file_mode) + continue + + create_dir = "mkdir -p %s" % os.path.dirname(file_path) + status, ret_t = wb_os_system(create_dir) + if status != 0: + RET["RETURN_KEY1"] = -1 + record_syslog( + '%%REBOOT_CAUSE-3-EXCEPTION: create %s failed, msg: %s' % + (os.path.dirname(file_path), ret_t)) + continue + + status, date = wb_os_system("date") + if status != 0 or len(date) == 0: + RET["RETURN_KEY1"] = -1 + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: get date failed.') + continue + + reocrd_cmd = "echo %s %s %s %s" % (file_log, date, operate_cmd, file_path) + status, ret_t = wb_os_system(reocrd_cmd) + if status != 0: + RET["RETURN_KEY1"] = -1 + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: get date failed, msg: %s' % ret_t) + continue + wb_os_system('sync') + else: + RET["RETURN_KEY1"] = -1 + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: record_type:%s not support.' % record_type) + continue + except Exception as e: + RET["RETURN_KEY1"] = -1 + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: reboot cause record error. msg: %s.' % (str(e))) + if RET["RETURN_KEY1"] == 0: + return True + return False + + def reboot_cause_check(self): + try: + reboot_cause_flag = False + if self.reboot_cause_list is None: + record_syslog_debug('%%REBOOT_CAUSE-6-DEBUG: reboot cause check config not found') + return + for item in self.reboot_cause_list: + name = item.get('name', None) + monitor_point = item.get('monitor_point', None) + record = item.get('record', None) + finish_operation_list = item.get('finish_operation', []) + if name is None or monitor_point is None or record is None: + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: reboot cause check get config failed.name:%s, monitor_point:%s, record:%s' % + (name, monitor_point, record)) + return + ret = self.monitor_point_check(monitor_point) + if ret is True: + record_syslog_debug('%%REBOOT_CAUSE-6-DEBUG: %s reboot cause is happen' % name) + self.reboot_cause_record(record) + reboot_cause_flag = True + for finish_operation_item in finish_operation_list: + ret, log = set_value(finish_operation_item) + if ret is False: + log = "%%REBOOT_CAUSE-3-EXCEPTION: " + log + record_syslog(log) + + if reboot_cause_flag is False and self.other_reboot_cause_record is not None: + record_syslog_debug('%%REBOOT_CAUSE-6-DEBUG: other reboot cause is happen') + self.reboot_cause_record(self.other_reboot_cause_record) + except Exception as e: + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: reboot cause check error. msg: %s.' % (str(e))) + return + + def run(self): + try: + self.debug_init() + if os.path.exists(REBOOT_CAUSE_STARTED_FLAG): + record_syslog_debug( + '%%REBOOT_CAUSE-6-DEBUG: Reboot cause has been started and will not be started again') + sys.exit(0) + self.reboot_cause_check() + wb_os_system("touch %s" % REBOOT_CAUSE_STARTED_FLAG) + wb_os_system("sync") + time.sleep(5) + sys.exit(0) + except Exception as e: + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: %s.' % (str(e))) + + +if __name__ == '__main__': + reboot_cause = RebootCause() + reboot_cause.run() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_ctrl.py b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_ctrl.py new file mode 100755 index 000000000000..17d3f5902b9d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_ctrl.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +import time +import syslog +import click +from platform_util import write_sysfs, wbi2cset, io_wr, wbi2csetWord +from platform_config import REBOOT_CTRL_PARAM + + +REBOOTCTLDEBUG = 0 + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def rebootctrlwarning(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("REBOOTCTRL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_WARNING, s) + + +def rebootctrlcritical(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("REBOOTCTRL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_CRIT, s) + + +def rebootctrlerror(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("REBOOTCTRL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def rebootctrldebug(s): + # s = s.decode('utf-8').encode('gb2312') + if REBOOTCTLDEBUG == 1: + syslog.openlog("REBOOTCTRL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +class RebootCtrl(): + def __init__(self): + self.config = REBOOT_CTRL_PARAM.copy() + + def set_value(self, config, val): + way = config.get("gettype") + if way == 'sysfs': + loc = config.get("loc") + value = config.get(val) + rebootctrldebug("sysfs type.loc:0x%x, value:0x%x" % (loc, value)) + return write_sysfs(loc, "0x%02x" % value) + if way == "i2c": + bus = config.get("bus") + addr = config.get("loc") + offset = config.get("offset") + value = config.get(val) + rebootctrldebug("i2c type.bus:0x%x, addr:0x%x, offset:0x%x, value:0x%x" % (bus, addr, offset, value)) + return wbi2cset(bus, addr, offset, value) + if way == "io": + io_addr = config.get('io_addr') + value = config.get(val) + rebootctrldebug("io type.io_addr:0x%x, value:0x%x" % (io_addr, value)) + ret = io_wr(io_addr, value) + if ret is not True: + return False, ("write 0x%x failed" % io_addr) + return True, ("write 0x%x success" % io_addr) + if way == 'i2cword': + bus = config.get("bus") + addr = config.get("loc") + offset = config.get("offset") + value = config.get(val) + rebootctrldebug("i2cword type.bus:0x%x, addr:0x%x, offset:0x%x, value:0x%x" % (bus, addr, offset, value)) + return wbi2csetWord(bus, addr, offset, value) + return False, "unsupport way: %s" % way + + def reset_operate(self, config): + ret, log = self.set_value(config, "rst_val") + rst_delay = config.get("rst_delay", 0) + time.sleep(rst_delay) + return ret, log + + def unlock_reset_operate(self, config): + ret, log = self.set_value(config, "unlock_rst_val") + unlock_rst_delay = config.get("unlock_rst_delay", 0) + time.sleep(unlock_rst_delay) + return ret, log + + def do_rebootctrl(self, option): + if self.config is None: + rebootctrlerror("Reset failed, REBOOT_CTRL_PARAM cfg get failed.") + return + try: + name_conf = self.config.get(option, None) + if name_conf is None: + print("Reset %s not support" % option) + return + try: + click.confirm("Are you sure you want to reset " + option + "?", + default=False, abort=True, show_default=True) + except Exception as e: + print("Aborted, msg: %s" % str(e)) + return + print("Reset %s start" % option) + ret, log = self.reset_operate(name_conf) + if ret is False: + rebootctrlerror(log) + print("Reset %s failed" % option) + return + if "unlock_rst_val" in name_conf: + ret, log = self.unlock_reset_operate(name_conf) + if ret is False: + rebootctrlerror(log) + print("%s unlock reset failed" % option) + return + print("Reset %s success" % option) + except Exception: + rebootctrlerror("do_rebootctrl Exception error") + return + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''reboot_ctrl reset [option]''' + + +@main.command() +@click.argument('option', required=True) +def reset(option): + '''reset device''' + rebootctrldebug("reboot ctrl option %s" % option) + rebootctrl = RebootCtrl() + rebootctrl.do_rebootctrl(option) + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/sensors b/platform/broadcom/sonic-platform-modules-micas/common/script/sensors new file mode 100755 index 000000000000..a2c72b123a43 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/sensors @@ -0,0 +1,8 @@ +#!/bin/bash +#docker exec -i pmon sensors "$@" + + +#To probe sensors not part of lm-sensors +if [ -r /usr/local/bin/platform_sensors.py ]; then + python /usr/local/bin/platform_sensors.py +fi diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/set_eth_mac.py b/platform/broadcom/sonic-platform-modules-micas/common/script/set_eth_mac.py new file mode 100755 index 000000000000..3e445a3ac73c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/set_eth_mac.py @@ -0,0 +1,274 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +import syslog +import os +import re +import eepromutil.onietlv as ot +from eepromutil.fru import ipmifru +from platform_config import STARTMODULE, SET_MAC_CONF +from platform_util import byteTostr, dev_file_read, exec_os_cmd + + +STANDARD_MAC_LEN = 12 +SETMAC_DEBUG_FILE = "/etc/.setmac_debug_flag" + +SETMACERROR = 1 +SETMACDEBUG = 2 +debuglevel = 0 + +cfg_prefix = "iface" +mac_prefix = "hwaddress ether" + +def setmac_debug(s): + if SETMACDEBUG & debuglevel: + syslog.openlog("SETMAC", syslog.LOG_PID) + syslog.syslog(syslog.LOG_INFO, s) + + +def setmac_error(s): + if SETMACERROR & debuglevel: + syslog.openlog("SETMAC", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + +def setmac_info(s): + syslog.openlog("SETMAC", syslog.LOG_PID) + syslog.syslog(syslog.LOG_INFO, s) + + +def debug_init(): + global debuglevel + try: + with open(SETMAC_DEBUG_FILE, "r") as fd: + value = fd.read() + debuglevel = int(value) + except Exception: + debuglevel = 0 + + +def decode_mac(encodedata): + if encodedata == None: + return None + ret = ":".join("%02x" % ord(data) for data in encodedata) + return ret.upper() + + +def validate_mac(value): + if value is None: + setmac_error("mac is none") + return False + if value.find('-') != -1: + pattern = re.compile(r"^\s*([0-9a-fA-F]{2,2}-){5,5}[0-9a-fA-F]{2,2}\s*$") + temp_value = value.replace("-", "") + elif value.find(':') != -1: + pattern = re.compile(r"^\s*([0-9a-fA-F]{2,2}:){5,5}[0-9a-fA-F]{2,2}\s*$") + temp_value = value.replace(":", "") + else: + pattern = re.compile(r"^\s*([0-9a-fA-F]{2,2}){5,5}[0-9a-fA-F]{2,2}\s*$") + temp_value = value + if not pattern.match(value): + setmac_error("mac format error") + return False + if len(temp_value) != STANDARD_MAC_LEN: + setmac_error("mac len error len:%d" % len(temp_value)) + return False + if temp_value == "000000000000": + setmac_error("illegal zero mac") + return False + if int(temp_value, 16) >> 40 & 1 == 1: + setmac_error("illegal mac") + return False + setmac_debug("mac validate success") + return True + + +def get_onie_eeprom(eeprom): + try: + onietlv = ot.onie_tlv() + rets = onietlv.decode(eeprom) + setmac_debug("%-20s %-5s %-5s %-20s" % ("TLV name", "Code", "lens", "Value")) + for item in rets: + if item["code"] == 0xfd: + setmac_debug("%-20s 0x%-02X %-5s" % (item["name"], item["code"], item["lens"])) + else: + setmac_debug("%-20s 0x%-02X %-5s %-20s" % (item["name"], item["code"], item["lens"], item["value"])) + except Exception as e: + setmac_error(str(e)) + return False, str(e) + return True, rets + + +def get_fru_eeprom_info(eeprom): + try: + fru = ipmifru() + fru.decodeBin(eeprom) + except Exception as e: + setmac_error(str(e)) + return False, str(e) + return True, fru + + +def get_mac_from_eeprom(eeprom_conf): + name = eeprom_conf.get("name") + e2_type = eeprom_conf.get("e2_type") + e2_path = eeprom_conf.get("e2_path") + e2_size = eeprom_conf.get("e2_size", 256) + mac_location = eeprom_conf.get("mac_location", {}) + e2_mac = None + + support_e2_type = ("fru", "onie_tlv") + if e2_type not in support_e2_type: + msg = "Unsupport e2 type: %s" % e2_type + return False, msg + + setmac_debug("===================%s===================" % name) + ret, binval_bytes = dev_file_read(e2_path, 0, e2_size) + if ret is False: + msg = "eeprom read error, eeprom path: %s, msg: %s" % (e2_path, binval_bytes) + return False, msg + binval = byteTostr(binval_bytes) + + # onie_tlv + if e2_type == "onie_tlv": + status, eeprom_info = get_onie_eeprom(binval) + if status is False: + msg = "get_onie_eeprom failed, msg: %s" % (eeprom_info) + return False, msg + + field = mac_location.get("field", "") + for eeprom_info_item in eeprom_info: + if eeprom_info_item.get("name") == field: + e2_mac = eeprom_info_item.get("value") + break + if e2_mac is None: + msg = "get_onie_eeprom mac address failed, e2_mac is None" + return False, msg + return True, e2_mac + + # fru + status, eeprom_info = get_fru_eeprom_info(binval) + if status is False: + msg = "get_fru_eeprom_info failed, msg: %s" % (eeprom_info) + return False, msg + + area = mac_location.get("area", "") + field = mac_location.get("field", "") + fru_area = getattr(eeprom_info, area, None) + fru_field = getattr(fru_area, field, None) + e2_mac = decode_mac(fru_field) + if e2_mac is None: + msg = "decode_mac failed, area: %s, field: %s, value: %s" % (area, field, fru_field) + return False, msg + return True, e2_mac + + +def read_mac_from_config_file(ifcfg): + ifcfg_file_path = ifcfg.get("ifcfg_file_path") + if not os.path.exists(ifcfg_file_path): + msg = "%s not exist" % ifcfg_file_path + return False, msg + try: + fd = open(ifcfg_file_path, 'r') + for line in reversed(fd.readlines()): + if line.strip().startswith(mac_prefix): + mac = line.strip().replace(mac_prefix, "").strip() + return True, mac + except Exception as e: + setmac_error(str(e)) + return False, str(e) + return False, "mac address not found in %s" % ifcfg_file_path + + +def set_e2_mac_to_config_file(eth_name, mac, ifcfg): + try: + ifcfg_file_path = ifcfg.get("ifcfg_file_path") + cfg_file_dir = os.path.dirname(ifcfg_file_path) + if not os.path.exists(cfg_file_dir): + cmd = "mkdir -p %s" % cfg_file_dir + setmac_info("Create interfaces config directory: %s" % cfg_file_dir) + os.system(cmd) + os.system("sync") + wr_val = cfg_prefix + " %s\n" % eth_name + wr_val += " %s %s\n" % (mac_prefix, mac) + with open(ifcfg_file_path, "w") as fd: + fd.write(wr_val) + os.system("sync") + setmac_info("Create interfaces config: %s with mac address: %s" % (ifcfg_file_path, mac)) + return True + except Exception as e: + setmac_error(str(e)) + return False + +def get_eth_current_mac(eth_name): + get_mac_cmd = "ifconfig %s |grep ether |awk '{print $2}'" % eth_name + status, output = exec_os_cmd(get_mac_cmd) + if status or len(output) == 0: + msg = "get mac exec cmd : %s fail, msg: %s" % (get_mac_cmd, output) + setmac_error(msg) + return False, msg + mac = output.replace("\n", "").upper() + return True, mac + +def set_eth_mac(eth_name, mac): + set_mac_cmd = "ifconfig %s hw ether %s" % (eth_name, mac) + status, output = exec_os_cmd(set_mac_cmd) + if status: + setmac_error("run cmd: %s fail, msg: %s" % (set_mac_cmd, output)) + return False + setmac_info("ifconfig %s with mac address: %s success" % (eth_name, mac)) + return True + + +def doSetmac(): + if STARTMODULE.get('set_eth_mac', 0) == 0: + setmac_debug("set_eth_mac config not set") + return + + try: + if SET_MAC_CONF is None: + setmac_debug("set_mac_conf in none") + return + + if len(SET_MAC_CONF) == 0: + setmac_debug("set_mac_conf list is none") + return + + for setmac_item in SET_MAC_CONF: + eth_name = setmac_item.get("eth_name") + e2_name = setmac_item.get("e2_name", "") + ifcfg = setmac_item.get("ifcfg") + if eth_name is None or ifcfg is None: + setmac_error("set_mac_conf error, eth_name or ifcfg is None") + continue + + # decode mac by eeprom + status, e2_mac = get_mac_from_eeprom(setmac_item) + if status is False: + setmac_error("get mac from %s eeprom fail, msg: %s" % (e2_name, e2_mac)) + continue + status = validate_mac(e2_mac) + if status is False: + setmac_error("e2_mac: %s invalid" % e2_mac) + continue + setmac_debug("get mac from %s eeprom info success, mac: %s" % (e2_name, e2_mac)) + + # read config file mac address + status, cfg_mac = read_mac_from_config_file(ifcfg) + setmac_debug("read_mac_from_config_file, status: %s, cfg_mac: %s" % (status, cfg_mac)) + if status is False or cfg_mac != e2_mac: + set_e2_mac_to_config_file(eth_name, e2_mac, ifcfg) + # check current eth mac + status, current_mac = get_eth_current_mac(eth_name) + if status is False: + setmac_error("get %s current mac fail" % eth_name) + continue + setmac_debug("current_mac:%s len:%d" % (current_mac, len(current_mac))) + if current_mac != e2_mac: + set_eth_mac(eth_name, e2_mac) + except Exception as e: + setmac_error(str(e)) + return + + +if __name__ == '__main__': + debug_init() + doSetmac() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/sfp_highest_temperatue.py b/platform/broadcom/sonic-platform-modules-micas/common/script/sfp_highest_temperatue.py new file mode 100755 index 000000000000..4dd98f3a36b3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/sfp_highest_temperatue.py @@ -0,0 +1,148 @@ +#!/usr/bin/python3 +import os +import importlib.machinery +import time +import syslog +import subprocess +import fcntl + +sfp_temperature_file = "/tmp/highest_sff_temp" + +SFP_TEMP_DEBUG_FILE = "/etc/.sfp_temp_debug_flag" +SFP_TEMP_RECORD_DEBUG = 1 +SFP_TEMP_RECORD_ERROR = 2 +debuglevel = 0 + + +def sfp_temp_debug(s): + if SFP_TEMP_RECORD_DEBUG & debuglevel: + syslog.openlog("SFP_TEMP_DEBUG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def sfp_temp_error(s): + if SFP_TEMP_RECORD_ERROR & debuglevel: + syslog.openlog("SFP_TEMP_ERROR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +pidfile = None + + +def file_rw_lock(): + global pidfile + pidfile = open(sfp_temperature_file, "r") + try: + fcntl.flock(pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB) + sfp_temp_debug("file lock success") + return True + except Exception: + if pidfile is not None: + pidfile.close() + pidfile = None + return False + + +def file_rw_unlock(): + try: + global pidfile + + if pidfile is not None: + fcntl.flock(pidfile, fcntl.LOCK_UN) + pidfile.close() + pidfile = None + sfp_temp_debug("file unlock success") + else: + sfp_temp_debug("pidfile is invalid, do nothing") + return True + except Exception as e: + sfp_temp_error("file unlock err, msg:%s" % (str(e))) + return False + + +def get_sfp_highest_temperature(): + highest_temperature = 0 + platform_sfputil = None + + sfputil_dir = "/usr/share/sonic/device/" + try: + if not os.path.exists(sfputil_dir): + sfputil_dir = "/usr/share/sonic/platform/" + sfputil_path = sfputil_dir + "/plugins/sfputil.py" + else: + cmd = "cat /host/machine.conf | grep onie_build_platform" + ret, output = subprocess.getstatusoutput(cmd) + if ret != 0: + sfp_temp_error("cmd: %s execution fail, output: %s" % (cmd, output)) + + onie_platform = output.split("=")[1] + sfputil_path = sfputil_dir + onie_platform + "/plugins/sfputil.py" + + module = importlib.machinery.SourceFileLoader("sfputil", sfputil_path).load_module() + platform_sfputil_class = getattr(module, "SfpUtil") + platform_sfputil = platform_sfputil_class() + + temperature = platform_sfputil.get_highest_temperature() + highest_temperature = int(temperature) * 1000 + except Exception as e: + sfp_temp_error("get sfp temperature error, msg:%s" % str(e)) + highest_temperature = -9999000 + + return highest_temperature + + +def write_sfp_highest_temperature(temperature): + + loop = 1000 + ret = False + try: + if os.path.exists(sfp_temperature_file) is False: + with open(sfp_temperature_file, 'w') as sfp_f: + pass + for i in range(0, loop): + ret = file_rw_lock() + if ret is True: + break + time.sleep(0.001) + + if ret is False: + sfp_temp_error("take file lock timeout") + return + + with open(sfp_temperature_file, 'w') as sfp_f: + sfp_f.write("%s\n" % str(temperature)) + + file_rw_unlock() + return + except Exception as e: + sfp_temp_error("write sfp temperature error, msg:%s" % str(e)) + file_rw_unlock() + return + + +def debug_init(): + global debuglevel + + try: + with open(SFP_TEMP_DEBUG_FILE, "r") as fd: + value = fd.read() + debuglevel = int(value) + except Exception: + debuglevel = 0 + + +def main(): + while True: + debug_init() + temperature = 0 + try: + temperature = get_sfp_highest_temperature() + write_sfp_highest_temperature(temperature) + except Exception as e: + sfp_temp_error("get/write sfp temperature error, msg:%s" % str(e)) + write_sfp_highest_temperature(-9999000) + time.sleep(5) + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/slot_monitor.py b/platform/broadcom/sonic-platform-modules-micas/common/script/slot_monitor.py new file mode 100755 index 000000000000..0385f50b6f50 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/slot_monitor.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +import time +import syslog +import traceback +import operator +import click +import os +from platform_config import SLOT_MONITOR_PARAM +from platform_util import io_rd, io_wr, wbi2cget, wbi2cset + + +SLOTMONITORDEBUG = 0 +SLOTMONITOR_DEBUG_FILE = "/etc/.slotmonitor_debug_flag" + + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def debug_init(): + global SLOTMONITORDEBUG + if os.path.exists(SLOTMONITOR_DEBUG_FILE): + SLOTMONITORDEBUG = 1 + else: + SLOTMONITORDEBUG = 0 + + +def slotwarninglog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("SLOTMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_WARNING, s) + + +def slotcriticallog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("SLOTMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_CRIT, s) + + +def sloterror(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("SLOTMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def slotinfo(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("SLOTMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_INFO, s) + + +def slotdebuglog(s): + # s = s.decode('utf-8').encode('gb2312') + if SLOTMONITORDEBUG == 1: + syslog.openlog("SLOTMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +class SlotMonitor(): + def __init__(self): + self.preSlotStatus = [] + + def checkslot(self, ret): + slots_conf = SLOT_MONITOR_PARAM.get('slots', None) + + if slots_conf is None: + return False + for item_slot in slots_conf: + totalerr = 0 + try: + ret_t = {} + ret_t["id"] = item_slot.get('name') + ret_t["status"] = "" + presentattr = item_slot.get('present') + gettype = presentattr.get('gettype') + presentbit = presentattr.get('presentbit') + if gettype == "io": + io_addr = presentattr.get('io_addr') + val = io_rd(io_addr) + if val is not None: + retval = val + else: + totalerr -= 1 + sloterror(" %s %s" % (item_slot.get('name'), "lpc read failed")) + else: + bus = presentattr.get('bus') + loc = presentattr.get('loc') + offset = presentattr.get('offset') + ind, val = wbi2cget(bus, loc, offset) + if ind is True: + retval = val + else: + totalerr -= 1 + sloterror(" %s %s" % (item_slot.get('name'), "i2c read failed")) + if totalerr < 0: + ret_t["status"] = "NOT OK" + ret.append(ret_t) + continue + val_t = (int(retval, 16) & (1 << presentbit)) >> presentbit + if val_t != presentattr.get('okval'): + ret_t["status"] = "ABSENT" + else: + ret_t["status"] = "PRESENT" + except Exception as e: + ret_t["status"] = "NOT OK" + totalerr -= 1 + sloterror("checkslot error") + sloterror(str(e)) + slotdebuglog("%s status: %s" % (ret_t["id"], ret_t["status"])) + ret.append(ret_t) + return True + + def dealslotplugin(self, name): + slotdebuglog("enter dealslotplugin %s" % name) + # wait for slot stable + time.sleep(5) + slots_conf = SLOT_MONITOR_PARAM.get('slots', None) + if slots_conf is None: + return False + for item_slot in slots_conf: + try: + slotdebuglog("name %s, item_slot.get('name') %s" % (name, item_slot.get('name'))) + if name == item_slot.get('name'): + actattr = item_slot.get('act') + for item_act in actattr: + gettype = item_act.get('gettype') + if gettype == "io": + io_addr = item_act.get('io_addr') + value = item_act.get('value') + mask = item_act.get('mask') + val = io_rd(io_addr) + if val is None: + sloterror(" %s %s" % (name, "lpc read failed")) + continue + set_val = (int(val, 16) & mask) | value + ret = io_wr(io_addr, set_val) + if ret is not True: + sloterror(" %s %s" % (name, "lpc write failed")) + continue + slotdebuglog("io set io_addr:0x%x value:0x%x success" % (io_addr, set_val)) + elif gettype == "i2c": + bus = item_act.get('bus') + loc = item_act.get('loc') + offset = item_act.get('offset') + value = item_act.get('value') + ret, log = wbi2cset(bus, loc, offset, value) + if ret is not True: + sloterror(" %s %s %s" % (name, "i2c write failed", log)) + continue + slotdebuglog( + "i2c set bus:%d loc:0x%x offset:0x%x value:0x%x success" % + (bus, loc, offset, value)) + else: + sloterror("gettype error") + break + except Exception as e: + sloterror("dealslotplugin failed") + sloterror(str(e)) + return False + return True + + def updateSlotStatus(self): + ''' + Only two status: PRESENT and ABSENT + ''' + curSlotStatus = [] + self.checkslot(curSlotStatus) + slotdebuglog('curSlotStatus: {}\n preSlotStatus: {}'.format(curSlotStatus, self.preSlotStatus)) + if operator.eq(self.preSlotStatus, curSlotStatus) is False: + if len(self.preSlotStatus) == 0: + # first time + for i, item in enumerate(curSlotStatus): + if item['status'] == 'PRESENT': + slotdebuglog('SLOT_PLUG_IN: %s' % (item['id'])) + elif item['status'] == 'ABSENT': + slotdebuglog('SLOT_ABSENT: %s' % (item['id'])) + else: + slotdebuglog('SLOT_FAILED: %s status %s not support yet' % (item['id'], item['status'])) + self.preSlotStatus.append(item) + else: + for i, item in enumerate(curSlotStatus): + if item['status'] == self.preSlotStatus[i]['status']: + continue + if item['status'] == 'PRESENT' and self.preSlotStatus[i]['status'] == 'ABSENT': + self.dealslotplugin(item['id']) + slotinfo('SLOT_PLUG_IN: %s' % (item['id'])) + elif item['status'] == 'ABSENT' and self.preSlotStatus[i]['status'] == 'PRESENT': + slotwarninglog('SLOT_PLUG_OUT: %s' % (item['id'])) + else: + slotwarninglog('SLOT_PLUG_OUT: %s status change from %s to %s not support' % + (item['id'], self.preSlotStatus[i]['status'], item['status'])) + self.preSlotStatus.remove(self.preSlotStatus[i]) + self.preSlotStatus.insert(i, item) + + def slotmonitor(self): + self.updateSlotStatus() + return 0 + + +def doSlotMonitor(slotMonitor): + slotMonitor.slotmonitor() + + +def run(interval, slotMonitor): + # slotMonitor.devattrinit() + while True: + try: + debug_init() + doSlotMonitor(slotMonitor) + except Exception as e: + traceback.print_exc() + sloterror(str(e)) + time.sleep(interval) + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''slot monitor operator''' + + +@main.command() +def start(): + '''start slot monitor''' + slotinfo("slot_monitor start") + slotMonitor = SlotMonitor() + interval = SLOT_MONITOR_PARAM.get('polling_time', 1) + run(interval, slotMonitor) + + +@main.command() +def stop(): + '''stop slot monitor ''' + slotinfo("stop") + + +# device_i2c operation +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/ssdmon b/platform/broadcom/sonic-platform-modules-micas/common/script/ssdmon new file mode 100755 index 000000000000..4290b0a68725 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/ssdmon @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# +# ssdmon +# +# Command-line utility to check SSD health and parameters +# + +try: + import argparse + import os + import sys + + from sonic_py_common import device_info, logger +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + +DEFAULT_DEVICE = "/dev/sda" +SYSLOG_IDENTIFIER = "ssdmon" + +# Global logger instance +log = logger.Logger(SYSLOG_IDENTIFIER) + +def import_ssd_api(diskdev): + """ + Loads platform specific or generic ssd_mon module from source + Raises an ImportError exception if none of above available + + Returns: + Instance of the class with SSD API implementation (vendor or generic) + """ + + # try to load platform specific module + try: + platform_path, _ = device_info.get_paths_to_platform_and_hwsku_dirs() + platform_plugins_path = os.path.join(platform_path, "plugins") + sys.path.append(os.path.abspath(platform_plugins_path)) + from ssd_util import SsdUtil + except ImportError as e: + log.log_warning("Platform specific SsdMon module not found.") + + return SsdUtil(diskdev) + +def is_number(s): + try: + float(s) + return True + except ValueError: + return False + +# ==================== Entry point ==================== +def ssdmon(): + if os.geteuid() != 0: + print("Root privileges are required for this operation") + sys.exit(1) + + parser = argparse.ArgumentParser() + parser.add_argument("-d", "--device", help="Device name to show health info", default=DEFAULT_DEVICE) + parser.add_argument("-t", "--temperature", action="store_true", default=False, help="Show only temperature") + parser.add_argument("-j", "--health", action="store_true", default=False, help="Show only health") + + args = parser.parse_args() + + ssd = import_ssd_api(args.device) + + if args.temperature: + print(ssd.get_temperature()) + return + + if args.health: + print(ssd.get_health()) + return + + print("Device Model : {}".format(ssd.get_model())) + print("Firmware : {}".format(ssd.get_firmware())) + print("Serial : {}".format(ssd.get_serial())) + print("Health : {}{}".format(ssd.get_health(), "%" if is_number(ssd.get_health()) else "")) + print("Remain Life : {}{}".format(ssd.get_remaining_life(), "%" if is_number(ssd.get_remaining_life()) else "")) + print("Temperature : {}{}".format(ssd.get_temperature(), "C" if is_number(ssd.get_temperature()) else "")) + print("SATA Rate : {}".format(ssd.get_sata_rate())) + +if __name__ == '__main__': + ssdmon() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/tty_console.py b/platform/broadcom/sonic-platform-modules-micas/common/script/tty_console.py new file mode 100755 index 000000000000..4fae02f5128e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/tty_console.py @@ -0,0 +1,91 @@ +#!/usr/bin/python3 +# -*- coding: UTF-8 -*- + +import logging.handlers +import subprocess +import shlex +import time +import sys +import os +from platform_util import CompressedRotatingFileHandler, exec_os_cmd + +console_file = "/dev/ttyS1" +console_logfile = "/var/log/bmc-console.log" +MAX_LOG_BYTES = 20 * 1024 * 1024 +BACKUP_COUNT = 9 + +READ_SIZE = 1024 + +logger = logging.getLogger("cpu_monitor_bmc") +logger.setLevel(logging.DEBUG) +fh = CompressedRotatingFileHandler( + console_logfile, + mode='a', + maxBytes=MAX_LOG_BYTES, + backupCount=BACKUP_COUNT, + encoding=None, + delay=0) +fh.setLevel(logging.DEBUG) + +formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") +fh.setFormatter(formatter) +logger.addHandler(fh) + + +def tty_system_cmd(cmd, print_log=True): + if print_log: + logger.debug("command: %s", cmd) + status, output = exec_os_cmd(cmd) + logger.debug("command status %s", status) + logger.debug("command output:\n%s", output) + else: + status, output = exec_os_cmd(cmd) + return status, output + + +if __name__ == '__main__': + try_times = 0 + while try_times < 3: + try_times = try_times + 1 + ret, log = tty_system_cmd("stty -F /dev/ttyS1 | grep 115200", True) + if len(log) != 0 and "115200" in log: + break + tty_system_cmd("stty -F /dev/ttyS1 115200", True) + if try_times > 1: + logger.error("The %d time try to set SONiC /dev/ttyS1 115200", try_times) + + if not os.path.exists(console_file): + logger.error("device %s not exist", console_file) + sys.exit(1) + + nopen = 3 + while nopen > 0: + try: + console_fd = os.open(console_file, os.O_RDONLY) + break + except Exception as e: + logger.error(e) + logger.error("open %s failed", console_file) + nopen = nopen - 1 + time.sleep(1) + if nopen == 0: + sys.exit(1) + + try: + tmp_read = "" + while True: + dev_read = os.read(console_fd, READ_SIZE) + dev_read = str(dev_read, encoding='utf-8') + if len(dev_read) == 1 and dev_read == "\n": + continue + if dev_read[len(dev_read) - 1] == '\n': + tmp_read = tmp_read + dev_read[0:(len(dev_read) - 1)] + logger.info(tmp_read) + tmp_read = "" + else: + tmp_read = tmp_read + dev_read + + except Exception as e: + if console_fd is not None: + os.close(console_fd) + logger.error(e) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/upgrade.py b/platform/broadcom/sonic-platform-modules-micas/common/script/upgrade.py new file mode 100755 index 000000000000..1b2523198ed8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/upgrade.py @@ -0,0 +1,991 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +import sys +import os +import time +import syslog +import signal +import click +from platform_util import get_value, set_value, exec_os_cmd, exec_os_cmd_log +from platform_config import UPGRADE_SUMMARY, WARM_UPGRADE_STARTED_FLAG +from warm_upgrade import WarmBasePlatform + + +############################# Error code defined ############################# +ERR_FW_CHECK_CPLD_UPGRADE = -601 # "Failed to check the device CPLD information" +ERR_FW_CHECK_FPGA_UPGRADE = -602 # "Failed to check the device FPGA information" +ERR_FW_MATCH_CPLD_UPGRADE = -603 # "Not found upgrade CPLD file." +ERR_FW_MATCH_FPGA_UPGRADE = -604 # "Not found upgrade FPGA file." +ERR_FW_SAMEVER_CPLD_UPGRADE = -605 # "The CPLD version in device is same" +ERR_FW_SAMEVER_FPGA_UPGRADE = -606 # "The FPGA version in device is same" +ERR_FW_DO_CPLD_UPGRADE = -607 # "Doing upgrade CPLD is failed." +ERR_FW_DO_FPGA_UPGRADE = -608 # "Doing upgrade FPGA is failed." +ERR_FW_UPGRADE = -609 # "Failed to upgrade firmware" +FIRMWARE_PROGRAM_EXEC_ERR = -610 # "Firmware program run error!" +ERR_FW_FILE_FOUND = -701 # "Failed to find upgrade file" +ERR_FW_HEAD_PARSE = -702 # "Failed to parse upgrade firmware head info" +ERR_FW_CONFIG_FOUND = -703 # "Failed to find config item" +ERR_FW_NOSUPPORT_HOT = -704 # "No support hot upgrade" +ERR_FW_CHECK_SIZE = -705 # "Failed to check file size" +ERR_FW_DEVICE_ACCESS = -706 # "Failed to access device" +ERR_FW_NO_FILE_SUCCESS = -707 # "No files were successfully upgraded" +ERR_FW_CARD_ABSENT = -708 # "The subcard not present" +ERR_FW_HEAD_CHECK = -709 # "Failed to check head info" +ERR_FW_FOOL_PROOF = -710 # "Failed to fool proof verification" +ERR_FW_RAISE_EXCEPTION = -711 # Code raise exception +ERR_FW_INVALID_PARAM = -712 # Invalid parameter +ERR_FW_UNZIP_FAILED = -713 # Unzip firmware failed + +FIRMWARE_SUCCESS = 0 +CHECK_OK = 0 + + +UPGRADE_DEBUG_FILE = "/etc/.upgrade_debug_flag" +UPGRADE_FILE_DIR = "/tmp/firmware/" + +UPGRADEDEBUG = 1 + +debuglevel = 0 + +COLD_UPGRADE = 1 +WARM_UPGRADE = 2 +TEST_UPGRADE = 3 +BMC_UPGRADE = 4 + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def debug_init(): + global debuglevel + if os.path.exists(UPGRADE_DEBUG_FILE): + debuglevel = debuglevel | UPGRADEDEBUG + else: + debuglevel = debuglevel & ~(UPGRADEDEBUG) + + +def upgradewarninglog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("UPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_WARNING, s) + + +def upgradecriticallog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("UPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_CRIT, s) + + +def upgradeerror(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("UPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def upgradedebuglog(s): + # s = s.decode('utf-8').encode('gb2312') + if UPGRADEDEBUG & debuglevel: + syslog.openlog("UPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def signal_init(): + signal.signal(signal.SIGINT, signal.SIG_IGN) # ignore ctrl+c signal + signal.signal(signal.SIGTERM, signal.SIG_IGN) # ignore kill signal + signal.signal(signal.SIGTSTP, signal.SIG_IGN) # ignore ctrl+z signal + + +class BasePlatform(): + + def __init__(self): + self.upgrade_param = UPGRADE_SUMMARY.copy() + self.devtype = self.upgrade_param.get('devtype', None) + self.max_slot_num = self.upgrade_param.get("max_slot_num", 0) + self.head_info_config = {} + self.slot_config = {} + self.cold_chain_config = {} + self.subtype = None + self.chain = None + self.filetype = None + self.DEVTYPE = None + self.SUBTYPE = '0' + self.TYPE = None + self.CHAIN = None + self.CHIPNAME = None + self.VERSION = None + self.FILETYPE = None + self.CRC = None + self.SUBTYPE_LIST = None + + def save_and_set_value(self, cfg_list): + for config in cfg_list: + ret, val = get_value(config) + if ret: + config["save_value"] = val + else: + upgradeerror(val) + return False, "get save value fail" + + set_val = config.get("set_value", None) + if set_val is None: + log = "save_and_set_value lack of set_val config" + upgradeerror(log) + return log + + gettype = config.get("gettype", None) + set_cmd = config.get("set_cmd", None) + if gettype == "cmd": + if set_cmd is None: + log = "save_and_set_value lack of set_cmd config" + upgradeerror(log) + return False, log + config["cmd"] = set_cmd % set_val + upgradedebuglog("save_and_set_value modify set cmd to %s" % config["cmd"]) + else: + config["value"] = set_val + upgradedebuglog("save_and_set_value modify set val to %s" % config["value"]) + + ret, log = set_value(config) + if ret is False: + upgradeerror(log) + return False, log + return True, "save and set value success" + + def recover_save_value(self, cfg_list): + total_err = 0 + for config in cfg_list: + upgradedebuglog("config: %s, recover save value" % config) + val = config.get("save_value", None) + if val is None: + upgradeerror("recover_save_value lack of save_value config") + total_err -= 1 + continue + gettype = config.get("gettype", None) + set_cmd = config.get("set_cmd", None) + if gettype == "cmd": + config["cmd"] = set_cmd % val + upgradedebuglog("recover_save_value modify set cmd to %s" % config["cmd"]) + else: + config["value"] = val + upgradedebuglog("recover_save_value modify set val to %s" % config["value"]) + + ret, log = set_value(config) + if ret is False: + upgradeerror("recover save value write failed, log: %s" % log) + total_err -= 1 + else: + upgradedebuglog("recover save value success") + if total_err < 0: + return False, "recover save value failed" + return True, "recover save value success" + + def check_slot_present(self, slot_present_config): + presentbit = slot_present_config.get('presentbit') + ret, value = get_value(slot_present_config) + if ret is False: + return "NOT OK" + if isinstance(value, str): + val_t = int(value, 16) + else: + val_t = value + val_t = (val_t & (1 << presentbit)) >> presentbit + if val_t != slot_present_config.get('okval'): + status = "ABSENT" + else: + status = "PRESENT" + return status + + def linecard_present_check(self, slot_present_config): + present_status = self.check_slot_present(slot_present_config) + if present_status == "NOT OK": + return ERR_FW_DEVICE_ACCESS, "get slot present status failed." + if present_status == "ABSENT": + return ERR_FW_CARD_ABSENT, "slot absent" + return CHECK_OK, "slot present" + + def subprocess_warm_upgrade(self, config, file, main_type, sub_type, slot): + dev_name = config.get("name", None) + status, output = self.subprocess_firmware_upgrade(config, file, main_type, sub_type, slot) + if status is False: + upgradeerror("%s warm upgrade failed" % dev_name) + return False, output + command = "warm_upgrade.py %s 0x%x 0x%x %s %s %s" % (file, main_type, sub_type, slot, self.filetype, self.chain) + upgradedebuglog("warm upgrade cmd: %s" % command) + if os.path.exists(UPGRADE_DEBUG_FILE): + status, output = exec_os_cmd_log(command) + else: + status, output = exec_os_cmd(command) + if status: + upgradeerror("%s warm upgrade failed" % dev_name) + return False, output + upgradedebuglog("%s warm upgrade success" % dev_name) + return True, "upgrade success" + + def do_fw_upg_init_cmd(self, dev_name, init_cmd_list): + # pre operation + try: + for init_cmd_config in init_cmd_list: + ret, log = set_value(init_cmd_config) + if ret is False: + upgradeerror("%s do init cmd: %s failed, msg: %s" % (dev_name, init_cmd_config, log)) + return False, log + msg = "%s firmware init cmd all set success" % dev_name + upgradedebuglog(msg) + return True, msg + except Exception as e: + return False, str(e) + + def do_fw_upg_finish_cmd(self, dev_name, finish_cmd_list): + # end operation + ret = 0 + for finish_cmd_config in finish_cmd_list: + ret_t, log = set_value(finish_cmd_config) + if ret_t is False: + upgradeerror("%s do finish cmd: %s failed, msg: %s" % (dev_name, finish_cmd_config, log)) + ret = -1 + if ret != 0: + msg = "%s firmware finish cmd exec failed" % dev_name + upgradeerror(msg) + return False, msg + msg = "%s firmware finish cmd all set success" % dev_name + upgradedebuglog(msg) + return True, msg + + def subprocess_firmware_upgrade(self, config, file, main_type, sub_type, slot): + dev_name = config.get("name", None) + init_cmd_list = config.get("init_cmd", []) + finish_cmd_list = config.get("finish_cmd", []) + try: + ret, log = self.do_fw_upg_init_cmd(dev_name, init_cmd_list) + if ret is False: + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, log + time.sleep(0.5) # delay 0.5s after execute init_cmd + command = "firmware_upgrade %s 0x%x 0x%x %s" % (file, main_type, sub_type, slot) + upgradedebuglog("firmware upgrade cmd: %s" % command) + if os.path.exists(UPGRADE_DEBUG_FILE): + status, output = exec_os_cmd_log(command) + else: + status, output = exec_os_cmd(command) + if status: + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + upgradeerror("%s firmware upgrade failed, msg: %s" % (dev_name, output)) + return False, output + upgradedebuglog("%s firmware upgrade success" % dev_name) + ret, log = self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + if ret is False: + return False, log + return True, "upgrade success" + except Exception as e: + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, str(e) + + def subprocess_test_upgrade(self, config, file, main_type, sub_type, slot): + dev_name = config.get("name", None) + init_cmd_list = config.get("init_cmd", []) + finish_cmd_list = config.get("finish_cmd", []) + try: + ret, log = self.do_fw_upg_init_cmd(dev_name, init_cmd_list) + if ret is False: + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, log + time.sleep(0.5) # delay 0.5s after execute init_cmd + command = "firmware_upgrade test %s 0x%x 0x%x %s" % (file, main_type, sub_type, slot) + upgradedebuglog("firmware upgrade cmd: %s" % command) + if os.path.exists(UPGRADE_DEBUG_FILE): + status, output = exec_os_cmd_log(command) + else: + status, output = exec_os_cmd(command) + if status: + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + upgradeerror("%s test upgrade failed, msg: %s" % (dev_name, output)) + return False, output + upgradedebuglog("%s test upgrade success" % dev_name) + ret, log = self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + if ret is False: + return False, log + return True, "upgrade success" + except Exception as e: + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, str(e) + + def subprocess_bmc_upgrade(self, config, file, chip_select, erase_type): + dev_name = config.get("name", None) + init_cmd_list = config.get("init_cmd", []) + finish_cmd_list = config.get("finish_cmd", []) + save_set_reg_list = config.get("save_set_reg", []) + try: + # save and set reg + ret, log = self.save_and_set_value(save_set_reg_list) + if ret is False: + upgradeerror(log) + self.recover_save_value(save_set_reg_list) + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, log + upgradedebuglog("%s save and set cmd all set success" % dev_name) + time.sleep(0.5) # delay 0.5s after execute save and set reg + + # pre operation + ret, log = self.do_fw_upg_init_cmd(dev_name, init_cmd_list) + if ret is False: + self.recover_save_value(save_set_reg_list) + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, log + + upgradedebuglog("%s bmc init cmd all set success" % dev_name) + time.sleep(0.5) # delay 0.5s after execute init_cmd + + command = "fw_upgrade upgrade %s %s %s" % (file, chip_select, erase_type) + upgradedebuglog("fw_upgrade upgrade cmd: %s" % command) + status, output = exec_os_cmd_log(command) + if status: + upgradeerror("%s bmc upgrade failed" % dev_name) + self.recover_save_value(save_set_reg_list) + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, output + upgradedebuglog("%s bmc upgrade success" % dev_name) + + ret1, log1 = self.recover_save_value(save_set_reg_list) + if ret1 is False: + upgradeerror("bmc upgrade recover save value failed, msg: %s" % log1) + ret2, log2 = self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + if ret2 is False: + upgradeerror("bmc upgrade do finish command failed, msg: %s" % log2) + if ret1 is False or ret2 is False: + return False, "bmc upgrade do recover save value or finish command failed" + return True, "upgrade success" + + except Exception as e: + self.recover_save_value(save_set_reg_list) + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, str(e) + + def file_head_param_check(self, head_info_config): + try: + self.DEVTYPE = head_info_config.get('DEVTYPE', None) + self.SUBTYPE = head_info_config.get('SUBTYPE', '0') + self.TYPE = head_info_config.get('TYPE', None) + self.CHAIN = head_info_config.get('CHAIN', None) + self.CHIPNAME = head_info_config.get('CHIPNAME', None) + self.VERSION = head_info_config.get('VERSION', None) + self.FILETYPE = head_info_config.get('FILETYPE', None) + self.CRC = head_info_config.get('CRC', None) + + if self.devtype != int(self.DEVTYPE, 16): + return ERR_FW_HEAD_CHECK, ("no support %s devtype" % self.DEVTYPE) + + if self.SUBTYPE is not None: + self.SUBTYPE_LIST = self.SUBTYPE.split(',') + self.SUBTYPE_LIST = [int(tmp_subtype, base=16) for tmp_subtype in self.SUBTYPE_LIST] + if len(self.SUBTYPE) != 0 and self.subtype not in self.SUBTYPE_LIST: + return ERR_FW_HEAD_CHECK, ("no support %s SUBTYPE" % self.SUBTYPE) + + if len(self.CHAIN) == 0 or len(self.FILETYPE) == 0: + return ERR_FW_HEAD_CHECK, ("CHAIN:%s, FILETYPE:%s get failed" % (self.CHAIN, self.FILETYPE)) + self.chain = int(self.CHAIN) + self.filetype = self.FILETYPE + upgradedebuglog("file head param: devtype:0x%x, subtype:0x%x, chain:%s, filetype:%s" + % (self.devtype, self.subtype, self.chain, self.filetype)) + return CHECK_OK, "SUCCESS" + except Exception as e: + return ERR_FW_RAISE_EXCEPTION, str(e) + + def parse_file_head(self, file): + try: + self.head_info_config = {} + with open(file, 'r', errors='ignore') as fd: + rdbuf = fd.read() + upgradedebuglog("start parse upgrade file head") + file_head_start = rdbuf.index('FILEHEADER(\n') # ponit to F + file_head_start += rdbuf[file_head_start:].index('\n') # ponit to \n + file_head_end = rdbuf.index(')\n') + header_buf = rdbuf[file_head_start + 1: file_head_end - 1] + upgradedebuglog("upgrade file head find FILEHEADER") + for line in header_buf.split('\n'): + head_list = line.split('=', 1) + head_key = head_list[0] + head_val = head_list[1] + self.head_info_config[head_key] = head_val + upgradedebuglog("file: %s head_info_config: %s" % (file, self.head_info_config)) + return CHECK_OK, "SUCCESS" + except Exception as e: + msg = "parse %s head failed, msg: %s" % (file, str(e)) + upgradeerror(msg) + return ERR_FW_RAISE_EXCEPTION, msg + + def get_file_size_k(self, file): + fsize = os.path.getsize(file) + fsize = fsize / float(1024) + return round(fsize, 2) + + def get_device_model(self, conf): + ret, val = get_value(conf) + if ret is False: + msg = "get device model failed, msg: %s" % val + return False, msg + decode_val = conf.get("decode") + if decode_val is None: + return True, val + for k, v in decode_val.items(): + if val == v: + return True, k + msg = "device model decode error, val: %s" % val + return False, msg + + def upgrade_fool_proofing(self, conf): + try: + status, dev_model = self.get_device_model(conf) + if status is False: + msg = "upgrade fool proofing get device model failed, msg: %s" % dev_model + upgradeerror(msg) + return False, msg + upgradedebuglog("get device model success, device model: %s" % dev_model) + if dev_model != self.VERSION: + msg = "upgrade fool proofing failed, device model: %s, upgrade file version: %s" % ( + dev_model, self.VERSION) + upgradedebuglog(msg) + return False, msg + msg = "upgrade fool proofing pass, device model: %s, upgrade file version: %s" % (dev_model, self.VERSION) + upgradedebuglog(msg) + return True, msg + except Exception as e: + upgradeerror(str(e)) + return False, str(e) + + def upgrading(self, config, file, devtype, subtype, slot, option_flag, erase_type=None): + dev_name = config.get("name", None) + if option_flag == COLD_UPGRADE: + status, output = self.subprocess_firmware_upgrade(config, file, devtype, subtype, slot) + elif option_flag == WARM_UPGRADE: + status, output = self.subprocess_warm_upgrade(config, file, devtype, subtype, slot) + elif option_flag == TEST_UPGRADE: + status, output = self.subprocess_test_upgrade(config, file, devtype, subtype, slot) + elif option_flag == BMC_UPGRADE: + status, output = self.subprocess_bmc_upgrade(config, file, slot, erase_type) + else: + log = "%s set error option flag" % dev_name + upgradeerror(log) + return False, log + + if status is False: + upgradeerror("%s upgrade failed" % dev_name) + return False, output + upgradedebuglog("%s upgrade success" % dev_name) + return True, "upgrade success" + + def initial_check(self, file, slot, upg_type): + try: + upgradedebuglog("BasePlatform initial_check, file: %s, slot: %s, upg_type: %s" % + (file, slot, upg_type)) + + upgradedebuglog("do file exist check...") + if not os.path.isfile(file): + msg = "%s not found" % file + upgradedebuglog(msg) + return ERR_FW_FILE_FOUND, msg + upgradedebuglog("file exist check ok") + + slot_name = "slot%d" % slot + slot_config = self.upgrade_param.get(slot_name, {}) + slot_present_config = slot_config.get("present", {}) + if len(slot_present_config) != 0: + upgradedebuglog("do %s present check..." % slot_name) + ret, log = self.linecard_present_check(slot_present_config) + if ret != CHECK_OK: + msg = "check %s present error, msg: %s" % (slot_name, log) + upgradedebuglog(msg) + return ret, msg + upgradedebuglog("%s present check ok" % slot_name) + + upgradedebuglog("do file head parse...") + self.subtype = slot_config.get("subtype", 0) + ret, log = self.parse_file_head(file) + if ret != CHECK_OK: + return ret, log + upgradedebuglog("file head parse success") + + upgradedebuglog("do file head check...") + ret, log = self.file_head_param_check(self.head_info_config) + if ret != CHECK_OK: + msg = "file: %s, head check failed, msg: %s" % (file, log) + upgradedebuglog(msg) + return ret, msg + upgradedebuglog("file head check ok") + + upgradedebuglog("get upgrade chain config...") + filetype_config = slot_config.get(self.filetype, {}) + if len(filetype_config) == 0: + msg = "file: %s filetype: %s no support" % (file, self.filetype) + upgradedebuglog(msg) + return ERR_FW_CONFIG_FOUND, msg + chain_num = "chain%s" % self.chain + chain_config = filetype_config.get(chain_num, {}) + if len(chain_config) == 0: + msg = "file: %s get %s config failed" % (file, chain_num) + upgradedebuglog(msg) + return ERR_FW_CONFIG_FOUND, msg + self.cold_chain_config = chain_config + upgradedebuglog("get %s filetype: %s %s config success" % (slot_name, self.filetype, chain_num)) + + fool_proofing = chain_config.get("fool_proofing") + if fool_proofing is not None: + upgradedebuglog("do fool proofing check...") + status, log = self.upgrade_fool_proofing(fool_proofing) + if status is False: + msg = "upgrade fool proofing check failed, msg: %s" % log + upgradedebuglog(msg) + return ERR_FW_FOOL_PROOF, msg + upgradedebuglog("do fool proofing check ok") + + if upg_type == WARM_UPGRADE: + upgradedebuglog("do support warm upgrade check...") + if chain_config.get("is_support_warm_upg", 0) != 1: + msg = "file: %s %s chain config not support warm upgrade" % (file, slot_name) + upgradedebuglog(msg) + return ERR_FW_NOSUPPORT_HOT, msg + upgradedebuglog("file: %s %s chain config support warm upgrade" % (file, slot_name)) + + filesizecheck = chain_config.get("filesizecheck", 0) + if filesizecheck != 0: + upgradedebuglog("do file size check...") + file_size = self.get_file_size_k(file) + if file_size > filesizecheck: + msg = "file: %s size: %s exceed %s" % (file, file_size, filesizecheck) + upgradedebuglog(msg) + return ERR_FW_CHECK_SIZE, msg + msg = "file: %s size: %s check ok" % (file, file_size) + upgradedebuglog(msg) + + msg = "file: %s slot: %s upgrade type: %s check ok" % (file, slot, upg_type) + upgradedebuglog(msg) + return CHECK_OK, msg + except Exception as e: + return ERR_FW_RAISE_EXCEPTION, str(e) + + def do_upgrade(self, file, slot, upg_type): + try: + ret, log = self.initial_check(file, slot, upg_type) + if ret != CHECK_OK: + return ret, log + + # start upgrading + upgradedebuglog("start upgrading") + ret, log = self.upgrading(self.cold_chain_config, file, self.devtype, self.subtype, slot, upg_type) + if ret is False: + upgradeerror("upgrade failed") + return ERR_FW_UPGRADE, log + upgradedebuglog("upgrade success") + return FIRMWARE_SUCCESS, "SUCCESS" + except Exception as e: + return ERR_FW_RAISE_EXCEPTION, str(e) + + def do_pre_check(self, conf): + ret, val = get_value(conf) + if ret is False: + msg = "pre check get value failed, msg: %s" % val + return False, msg + ok_val = conf.get("ok_val") + if val == ok_val: + msg = "pre check success, ok_val: %s, get value: %s" % (ok_val, val) + return True, msg + msg = "pre check failed, ok_val: %s, get value: %s" % (ok_val, val) + return False, msg + + def do_test(self, device, slot): + try: + # slot present check + slot_name = "slot%d" % slot + slot_config = self.upgrade_param.get(slot_name, {}) + slot_present_config = slot_config.get("present", {}) + if len(slot_present_config) != 0: + ret, log = self.linecard_present_check(slot_present_config) + if ret != CHECK_OK: + msg = "check %s present error, msg: %s" % (slot_name, log) + upgradedebuglog(msg) + return ret, msg + upgradedebuglog("%s present" % slot_name) + + # get list of devices to be tested + test_config = slot_config.get("TEST", {}) + if len(test_config) == 0: + return ERR_FW_CONFIG_FOUND, "test config no found" + device_list = test_config.get(device, []) + if len(device_list) == 0: + return ERR_FW_CONFIG_FOUND, ("logic device %s test config list not found" % device) + + # test_file existence check + for test_config in device_list: + chain_num = test_config.get("chain", None) + test_file = test_config.get("file", None) + display_name = test_config.get("display_name", None) + if chain_num is None or test_file is None or display_name is None: + log = "test_config:%s lack of config" % test_config + upgradeerror(log) + return ERR_FW_CONFIG_FOUND, log + if not os.path.isfile(test_file): + return ERR_FW_FILE_FOUND, ("%s not found" % test_file) + + # start testing + RET = 0 + pre_check_failed = 0 + pre_check_failed_summary = "" + failed_summary = "chain test failed.\ntest fail chain:" + success_summary = "test success chain:" + for test_config in device_list: + chain_num = test_config.get("chain", None) + test_file = test_config.get("file", None) + display_name = test_config.get("display_name", None) + pre_check_conf = test_config.get("pre_check", None) + if pre_check_conf is not None: + status, msg = self.do_pre_check(pre_check_conf) + if status is False: + pre_check_failed += 1 + log = "\nchain:%d, name:%s, pre check failed, msg: %s" % (chain_num, display_name, msg) + upgradedebuglog(log) + pre_check_failed_summary += log + continue + upgradedebuglog("chain:%d, name:%s, pre check ok, msg: %s" % (chain_num, display_name, msg)) + ret, log = self.do_upgrade(test_file, slot, TEST_UPGRADE) + if ret != FIRMWARE_SUCCESS: + RET = -1 + upgradeerror("chain:%d, name:%s test failed" % (chain_num, display_name)) + failed_summary += "\n chain:%d, name:%s;" % (chain_num, display_name) + else: + upgradedebuglog("chain:%d, name:%s test success" % (chain_num, display_name)) + success_summary += "\n chain:%d, name:%s;" % (chain_num, display_name) + if RET != 0: + return ERR_FW_UPGRADE, failed_summary + if pre_check_failed == len(device_list): + return ERR_FW_NO_FILE_SUCCESS, failed_summary + pre_check_failed_summary + return FIRMWARE_SUCCESS, success_summary + except Exception as e: + return ERR_FW_RAISE_EXCEPTION, str(e) + + def do_test_main(self, device, slot): + print("+================================+") + print("|Doing upgrade test, please wait.|") + ret, log = self.do_test(device, slot) + if ret == FIRMWARE_SUCCESS: + print("| test succeeded! |") + print("+================================+") + print(log) + sys.exit(0) + else: + print("| test failed! |") + print("+================================+") + print("FAILED REASON:") + print(log) + sys.exit(1) + + def do_bmc_upgrade_main(self, file, chip_select, erase_type): + bmc_upgrade_config = self.upgrade_param.get("BMC", {}) + ret, log = self.upgrading(bmc_upgrade_config, file, self.devtype, + self.subtype, chip_select, BMC_UPGRADE, erase_type) + if ret is True: + print("===========upgrade succeeded!============") + sys.exit(0) + else: + print("============upgrade failed!==============") + print("FAILED REASON:") + print("%s" % log) + sys.exit(1) + + +class FileUpg(object): + def __init__(self, config, file, devtype, subtype, slot, filetype, chain, upg_type): + self.config = config + self.file = file + self.devtype = devtype + self.subtype = subtype + self.slot = slot + self.filetype = filetype + self.chain = chain + self.upg_type = upg_type + + def __repr__(self): + return "file:%s slot:%d" % (self.file, self.slot) + + +class FwUpg(object): + def __init__(self): + self.upg_platform = BasePlatform() + self.warm_upg_platform = WarmBasePlatform() + self.max_slot_num = self.upg_platform.max_slot_num + self.file_list = [] + + def do_file_refresh(self, fw_upg_instance): + fw_upg_config = fw_upg_instance.config + fw_upg_file = fw_upg_instance.file + fw_upg_devtype = fw_upg_instance.devtype + fw_upg_subype = fw_upg_instance.subtype + fw_upg_slot = fw_upg_instance.slot + fw_upg_filetype = fw_upg_instance.filetype + fw_upg_chain = fw_upg_instance.chain + dev_name = fw_upg_config.get("name", None) + upgradedebuglog("%s start warm upgrade, file: %s, devtype:0x%x, subype: 0x%x, slot: %d, filetype: %s, chain: %d" % + (dev_name, fw_upg_file, fw_upg_devtype, fw_upg_subype, fw_upg_slot, fw_upg_filetype, fw_upg_chain)) + status, output = self.warm_upg_platform.do_warmupgrade(fw_upg_file, fw_upg_devtype, fw_upg_subype, fw_upg_slot, + fw_upg_filetype, fw_upg_chain) + if status is False: + upgradeerror("%s warm upgrade failed, msg: %s" % (dev_name, output)) + return False, output + upgradedebuglog("%s warm upgrade success" % dev_name) + return True, "upgrade success" + + def do_refresh(self): + try: + exec_os_cmd("touch %s" % WARM_UPGRADE_STARTED_FLAG) + exec_os_cmd("sync") + + # stop upper layer services access + ret, log = self.warm_upg_platform.stop_services_access() + if ret is False: + upgradeerror("stop upper layer services access failed") + upgradeerror(log) + return ERR_FW_UPGRADE, log + upgradedebuglog("stop upper layer services access success") + + for file_instance in self.file_list: + file_info = repr(file_instance) + ret, log = self.do_file_refresh(file_instance) + if ret is False: + msg = "%s refresh failed, ret:%s, \n log:%s." % (file_info, ret, log) + upgradeerror(msg) + return ERR_FW_UPGRADE, msg + upgradedebuglog("%s refresh success." % file_info) + msg = "all files refresh success." + return FIRMWARE_SUCCESS, msg + except Exception as e: + msg = "do warm upg exception happend. log:%s" % str(e) + upgradeerror(msg) + return ERR_FW_UPGRADE, msg + finally: + self.warm_upg_platform.start_services_access() + if os.path.isfile(WARM_UPGRADE_STARTED_FLAG): + exec_os_cmd("rm -rf %s" % WARM_UPGRADE_STARTED_FLAG) + exec_os_cmd("sync") + + def do_file_cold_upg(self, fw_upg_instance): + try: + upgradedebuglog("start cold upgrade") + fw_upg_config = fw_upg_instance.config + fw_upg_file = fw_upg_instance.file + fw_upg_devtype = fw_upg_instance.devtype + fw_upg_subype = fw_upg_instance.subtype + fw_upg_slot = fw_upg_instance.slot + ret, log = self.upg_platform.upgrading( + fw_upg_config, fw_upg_file, fw_upg_devtype, fw_upg_subype, fw_upg_slot, COLD_UPGRADE) + if ret is False: + upgradeerror("cold upgrade %s slot%d failed, log:%s" % (fw_upg_file, fw_upg_slot, log)) + return ERR_FW_UPGRADE, log + log = "cold upgrade %s slot%d success" % (fw_upg_file, fw_upg_slot) + upgradedebuglog(log) + return FIRMWARE_SUCCESS, log + except Exception as e: + msg = "do cold upg exception happend. log:%s" % str(e) + upgradeerror(msg) + return ERR_FW_UPGRADE, msg + + def do_file_init_check(self, file_path, slot, upg_type): + upgradedebuglog("do_file_init_check, file_path: %s, slot: %s, upg_type: %s" % (file_path, slot, upg_type)) + + if slot is None: # traverse all slots + for i in range(0, self.max_slot_num + 1): + ret, log = self.upg_platform.initial_check(file_path, i, upg_type) + if ret != CHECK_OK: + upgradedebuglog( + "file: %s, slot%d initial check not ok, ret: %d, msg: %s" % + (file_path, i, ret, log)) + accept_error = (ERR_FW_CARD_ABSENT, ERR_FW_HEAD_CHECK, ERR_FW_FOOL_PROOF) + if ret in accept_error: + msg = "file: %s, slot%d initial check ret: %d, acceptable error." % (file_path, i, ret) + upgradedebuglog(msg) + continue + return ret, log + file_instance = FileUpg(self.upg_platform.cold_chain_config, file_path, self.upg_platform.devtype, + self.upg_platform.subtype, i, self.upg_platform.filetype, self.upg_platform.chain, upg_type) + self.file_list.append(file_instance) + else: + slot = int(slot, 10) + ret, log = self.upg_platform.initial_check(file_path, slot, upg_type) + if ret != CHECK_OK: + msg = "file: %s, slot%d initial check not ok, ret: %d, msg: %s" % (file_path, slot, ret, log) + return ret, msg + file_instance = FileUpg(self.upg_platform.cold_chain_config, file_path, self.upg_platform.devtype, + self.upg_platform.subtype, slot, self.upg_platform.filetype, self.upg_platform.chain, upg_type) + self.file_list.append(file_instance) + msg = "file: %s all slots init check ok" % file_path + return CHECK_OK, msg + + def do_dir_init_check(self, path, slot, upg_type): + for root, dirs, names in os.walk(path): + # root: directory absolute path + # dirs: folder path collection under directory + # names: file path collection under directory + for filename in names: + # file_path is file absolute path + file_path = os.path.join(root, filename) + ret, log = self.do_file_init_check(file_path, slot, upg_type) + if ret != CHECK_OK: + return ret, log + msg = "all files in dir have been check ok" + upgradedebuglog(msg) + return CHECK_OK, msg + + def do_fw_upg(self, path, slot, upg_type): + match_zip_file_flag = False + try: + upgradedebuglog("do_fw_upg, path: %s, slot: %s, upg_type: %s" % (path, slot, upg_type)) + if slot is not None and not slot.isdigit(): + msg = "invalid slot param: %s" % slot + upgradeerror(msg) + return ERR_FW_INVALID_PARAM, msg + + upgradedebuglog("start init check") + if os.path.isfile(path) and path.endswith(".zip"): + upgradedebuglog("firmware upgrade via compressed package: %s" % path) + # remove origin firmware upgrade file + exec_os_cmd("rm -rf %s" % UPGRADE_FILE_DIR) + cmd = "unzip -o %s -d /tmp/" % path + if os.path.exists(UPGRADE_DEBUG_FILE): + status, output = exec_os_cmd_log(cmd) + else: + status, output = exec_os_cmd(cmd) + if status: + msg = "unzip %s failed, log: %s" % (path, output) + upgradeerror(msg) + return ERR_FW_UNZIP_FAILED, msg + match_zip_file_flag = True + path = UPGRADE_FILE_DIR + + if os.path.isdir(path): + ret, msg = self.do_dir_init_check(path, slot, upg_type) + elif os.path.isfile(path): + ret, msg = self.do_file_init_check(path, slot, upg_type) + else: + ret = ERR_FW_FILE_FOUND + msg = "path: %s not found" % path + upgradeerror(msg) + + if ret != CHECK_OK: + return ret, msg + + # self.file_list is a collection of all check ok files + if len(self.file_list) == 0: + msg = "all file upgrade check not be satisfied." + upgradeerror(msg) + return ERR_FW_NO_FILE_SUCCESS, msg + + SUCCUSS_FILE_SUMMARY = "SUCCESS FILE: \n" + # file cold upgrade + upgradedebuglog("start all files cold upgrade") + for file_instance in self.file_list: + file_info = repr(file_instance) + ret, log = self.do_file_cold_upg(file_instance) + if ret != FIRMWARE_SUCCESS: + msg = "%s cold upgrade failed, ret:%d, \n log:\n%s." % (file_info, ret, log) + upgradeerror(msg) + return ret, msg + SUCCUSS_FILE_SUMMARY += "%s \n" % file_info + upgradedebuglog("%s cold upgrade success." % file_info) + + # file refresh upgrade + if upg_type == WARM_UPGRADE: + upgradedebuglog("start all files refresh upgrade") + ret, log = self.do_refresh() + if ret != FIRMWARE_SUCCESS: + return ret, log + + msg = "all file upgrade success" + upgradedebuglog(msg) + return FIRMWARE_SUCCESS, SUCCUSS_FILE_SUMMARY + except Exception as e: + msg = "do dir upgrade exception happend. log: %s" % str(e) + upgradeerror(msg) + return ERR_FW_UPGRADE, msg + finally: + if match_zip_file_flag is True: + exec_os_cmd("rm -rf %s" % UPGRADE_FILE_DIR) + + def fw_upg(self, path, slot, upg_type): + print("+================================+") + print("| Doing upgrade, please wait... |") + ret, log = self.do_fw_upg(path, slot, upg_type) + if ret == FIRMWARE_SUCCESS: + print("| upgrade succeeded! |") + print("+================================+") + print(log) + sys.exit(0) + else: + print("| upgrade failed! |") + print("+================================+") + print("FAILED REASON:") + print("%s" % log) + sys.exit(1) + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''upgrade script''' + + +# cold upgrade +@main.command() +@click.argument('file_name', required=True) +@click.argument('slot_num', required=False, default=None) +def cold(file_name, slot_num): + '''cold upgrade''' + fwupg = FwUpg() + fwupg.fw_upg(file_name, slot_num, COLD_UPGRADE) + + +# warm upgrade +@main.command() +@click.argument('file_name', required=True) +@click.argument('slot_num', required=False, default=None) +def warm(file_name, slot_num): + '''warm upgrade''' + fwupg = FwUpg() + fwupg.fw_upg(file_name, slot_num, WARM_UPGRADE) + + +# test upgrade +@main.command() +@click.argument('device', required=True) +@click.argument('slot_num', required=True) +def test(device, slot_num): + '''upgrade test''' + platform = BasePlatform() + platform.do_test_main(device, int(slot_num)) + + +# BMC upgrade +@main.command() +@click.argument('file_name', required=True) +@click.argument('chip_select', required=False, default="2") +@click.argument('erase_type', required=False, default="full") +def bmc(file_name, chip_select, erase_type): + '''BMC upgrade''' + platform = BasePlatform() + platform.do_bmc_upgrade_main(file_name, chip_select, erase_type) + + +if __name__ == '__main__': + signal_init() + debug_init() + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/warm_upgrade.py b/platform/broadcom/sonic-platform-modules-micas/common/script/warm_upgrade.py new file mode 100755 index 000000000000..69a310faa606 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/warm_upgrade.py @@ -0,0 +1,514 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +import sys +import os +import time +import syslog +import signal +import click +from platform_util import get_value, set_value, exec_os_cmd, exec_os_cmd_log +from platform_config import WARM_UPGRADE_PARAM + + +WARM_UPGRADE_DEBUG_FILE = "/etc/.warm_upgrade_debug_flag" + +WARMUPGRADEDEBUG = 1 + +debuglevel = 0 + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def debug_init(): + global debuglevel + if os.path.exists(WARM_UPGRADE_DEBUG_FILE): + debuglevel = debuglevel | WARMUPGRADEDEBUG + else: + debuglevel = debuglevel & ~(WARMUPGRADEDEBUG) + + +def warmupgradewarninglog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("WARMUPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_WARNING, s) + + +def warmupgradecriticallog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("WARMUPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_CRIT, s) + + +def warmupgradeerror(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("WARMUPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def warmupgradedebuglog(s): + # s = s.decode('utf-8').encode('gb2312') + if WARMUPGRADEDEBUG & debuglevel: + syslog.openlog("WARMUPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def subprocess_warm_upgrade(file, main_type, sub_type, slot): + command = "firmware_upgrade %s 0x%x 0x%x %s" % (file, main_type, sub_type, slot) + warmupgradedebuglog("warm upgrade firmware cmd:%s" % command) + if os.path.exists(WARM_UPGRADE_DEBUG_FILE): + return exec_os_cmd_log(command) + return exec_os_cmd(command) + + +def signal_init(): + signal.signal(signal.SIGINT, signal.SIG_IGN) # ignore ctrl+c signal + signal.signal(signal.SIGTERM, signal.SIG_IGN) # ignore kill signal + signal.signal(signal.SIGTSTP, signal.SIG_IGN) # ignore ctrl+z signal + + +class RefreshUpgradeBase(object): + + def __init__(self, config, slot_num, devtype, subtype): + self._config = config + self._slot_num = slot_num + self._devtype = devtype + self._subtype = subtype + self.device_name = self._config.get("name", None) + self.refresh_file = self._config.get("refresh_file", None) + self.init_cmd_list = self._config.get("init_cmd", []) + self.save_set_reg_list = self._config.get("save_set_reg", []) + self.rw_recover_reg_list = self._config.get("rw_recover_reg", []) + self.after_upgrade_delay = self._config.get("after_upgrade_delay", None) + self.after_upgrade_delay_timeout = self._config.get("after_upgrade_delay_timeout", None) + self.refresh_finish_flag_check_config = self._config.get("refresh_finish_flag_check", None) + self.access_check_reg_config = self._config.get("access_check_reg", {}) + self.time_delay = 0 + self.finish_cmd_list = self._config.get("finish_cmd", []) + + def get_config(self): + pass + + def get_slot_num(self): + pass + + def save_value(self, cfg_list): + for config in cfg_list: + ret, val = get_value(config) + if ret: + config["value"] = val + else: + warmupgradeerror(val) + return False, val + return True, "save value success" + + def save_and_set_value(self, cfg_list): + for config in cfg_list: + ret, val = get_value(config) + if ret: + config["save_value"] = val + else: + warmupgradeerror(val) + return False, "get save value fail" + set_val = config.get("set_value", None) + if set_val is not None: + config["value"] = set_val + else: + warmupgradeerror("save_and_set_value lack of set_val config") + return False, "set value is not config" + ret, log = set_value(config) + if ret is False: + warmupgradeerror(log) + return False, log + return True, "save value success" + + def recover_value(self, cfg_list): + fail_flag = 0 + for config in cfg_list: + ret, log = set_value(config) + if ret is False: + fail_flag = -1 + warmupgradeerror("recover_value set_value failed, log: %s" % log) + if fail_flag != 0: + warmupgradeerror("recover_value write failed") + return False, "recover write failed" + return True, "recover write success" + + def recover_save_value(self, cfg_list): + total_err = 0 + for config in cfg_list: + val = config.get("save_value", None) + if val is None: + warmupgradeerror("recover_save_value lack of save_value config") + total_err -= 1 + continue + config["value"] = val + ret, log = set_value(config) + if ret is False: + total_err -= 1 + warmupgradeerror("recover save value write failed, log: %s" % log) + else: + warmupgradedebuglog("recover save value success") + if total_err < 0: + return False, "recover save value failed" + return True, "recover save value success" + + def do_fw_upg_init_cmd(self, init_cmd_list): + # pre operation + try: + for init_cmd_config in init_cmd_list: + ret, log = set_value(init_cmd_config) + if ret is False: + warmupgradeerror("%s do init cmd: %s failed, msg: %s" % (self.device_name, init_cmd_config, log)) + return False, log + msg = "%s warm upgrade init cmd all set success" % self.device_name + warmupgradedebuglog(msg) + return True, msg + except Exception as e: + return False, str(e) + + def do_fw_upg_finish_cmd(self, finish_cmd_list): + # end operation + total_err = 0 + for finish_cmd_config in finish_cmd_list: + ret_t, log = set_value(finish_cmd_config) + if ret_t is False: + warmupgradeerror("%s do finish cmd: %s failed, msg: %s" % (self.device_name, finish_cmd_config, log)) + total_err -= 1 + if total_err < 0: + msg = "%s warm upgrade finish cmd exec failed" % self.device_name + warmupgradeerror(msg) + return False, msg + msg = "%s warm upgrade finish cmd all set success" % self.device_name + warmupgradedebuglog(msg) + return True, msg + + def access_test(self, config): + # polling execute command + polling_cmd_list = config.get("polling_cmd", []) + for polling_cmd_config in polling_cmd_list: + ret, log = set_value(polling_cmd_config) + if ret is False: + warmupgradeerror(log) + return False + polling_delay = config.get("polling_delay", None) + if polling_delay is not None: + time.sleep(polling_delay) + + # record check val + check_val = config.get("value", None) + # write value + ret, log = set_value(config) + if ret is False: + warmupgradeerror(log) + return False + # read value + ret, val = get_value(config) + if ret is False: + warmupgradeerror(val) + return False + + # compare write and read val + warmupgradedebuglog("check_val:%s" % check_val) + warmupgradedebuglog("get_value:%s" % val) + if val != check_val: + warmupgradeerror("check_val:%s != get_value:%s" % (check_val, val)) + return False + return True + + def check_value(self, config): + # record check val + check_val = config.get("value", None) + ret, val = get_value(config) + if ret is False: + warmupgradeerror(val) + return False + # compare write and read val + warmupgradedebuglog("check_val:%s" % check_val) + warmupgradedebuglog("get_value:%s" % val) + if val != check_val: + warmupgradeerror("check_val:%s != get_value:%s" % (check_val, val)) + return False + return True + + def refresh_file_upgrade(self): + try: + warmupgradedebuglog("start %s warm upgrading" % self.device_name) + + # save and set reg + ret, log = self.save_and_set_value(self.save_set_reg_list) + if ret is False: + warmupgradeerror(log) + self.recover_save_value(self.save_set_reg_list) + self.do_fw_upg_finish_cmd(self.finish_cmd_list) + return False, log + warmupgradedebuglog("%s save and set reg cmd all set success" % self.device_name) + time.sleep(0.5) # delay 0.5s after execute save and set reg + + # pre operation + ret, log = self.do_fw_upg_init_cmd(self.init_cmd_list) + if ret is False: + warmupgradeerror(log) + self.recover_save_value(self.save_set_reg_list) + self.do_fw_upg_finish_cmd(self.finish_cmd_list) + return False, log + time.sleep(0.5) # delay 0.5s after execute init_cmd + + # save reg + ret, log = self.save_value(self.rw_recover_reg_list) + if ret is False: + warmupgradeerror("%s save reg failed" % self.device_name) + self.recover_save_value(self.save_set_reg_list) + self.do_fw_upg_finish_cmd(self.finish_cmd_list) + return False, log + warmupgradedebuglog("%s all reg save success" % self.device_name) + + # upgrade refresh file + if self.refresh_file is not None: + status, output = subprocess_warm_upgrade( + self.refresh_file, self._devtype, self._subtype, self._slot_num) + if status: + log = "%s refresh file upg failed, msg: %s" % (self.device_name, output) + warmupgradeerror(log) + self.recover_save_value(self.save_set_reg_list) + self.do_fw_upg_finish_cmd(self.finish_cmd_list) + return False, log + warmupgradedebuglog("%s refresh file upg success" % self.device_name) + + # delay the preset time after the upgrade is complete + if self.after_upgrade_delay is not None: + time.sleep(self.after_upgrade_delay) + + # check something in the timeout period + if self.after_upgrade_delay_timeout is not None: + while self.time_delay < self.after_upgrade_delay_timeout: + + # check refresh finish flag + if self.refresh_finish_flag_check_config is not None: + ret = self.check_value(self.refresh_finish_flag_check_config) + if ret is False: + time.sleep(1) + self.time_delay = self.time_delay + 1 + warmupgradedebuglog("doing refresh_finish_flag_check, time_delay:%s" % self.time_delay) + continue + warmupgradedebuglog("%s upgrade_finish_flag_check success. self.time_delay:%d" + % (self.device_name, self.time_delay)) + + # doing logic device rw access test + ret = self.access_test(self.access_check_reg_config) + if ret: + warmupgradedebuglog( + "%s rw test success. self.time_delay:%d" % + (self.device_name, self.time_delay)) + break + time.sleep(1) + self.time_delay = self.time_delay + 1 + warmupgradedebuglog("doing access_test, self.time_delay:%s" % self.time_delay) + + if self.time_delay >= self.after_upgrade_delay_timeout: + log = "wait %s access test timeout" % self.device_name + warmupgradeerror(log) + self.recover_save_value(self.save_set_reg_list) + self.do_fw_upg_finish_cmd(self.finish_cmd_list) + return False, log + warmupgradedebuglog("%s access test success" % self.device_name) + + # recover reg + ret, log = self.recover_value(self.rw_recover_reg_list) + if ret is False: + warmupgradeerror("recover %s reg failed" % self.device_name) + self.recover_save_value(self.save_set_reg_list) + self.do_fw_upg_finish_cmd(self.finish_cmd_list) + return False, log + warmupgradedebuglog("recover %s reg success" % self.device_name) + # finally + ret1, log1 = self.recover_save_value(self.save_set_reg_list) + if ret1 is False: + warmupgradeerror("bmc upgrade recover save value failed, msg: %s" % log1) + ret2, log2 = self.do_fw_upg_finish_cmd(self.finish_cmd_list) + if ret2 is False: + warmupgradeerror("bmc upgrade do finish command failed, msg: %s" % log2) + if ret1 is False or ret2 is False: + return False, "upgrading %s recover save value or finish command failed" % self.device_name + return True, "upgrading %s success" % self.device_name + + except Exception as e: + log = "refresh file upgrade Exception happend, error log : %s" % str(e) + self.recover_save_value(self.save_set_reg_list) + self.do_fw_upg_finish_cmd(self.finish_cmd_list) + return False, log + + +class RefreshUpgrade(RefreshUpgradeBase): + + def __init__(self, config, slot_num, devtype, subtype): + super(RefreshUpgrade, self).__init__(config, slot_num, devtype, subtype) + + def get_config(self): + super(RefreshUpgrade, self).get_config() + return self._config + + def get_slot_num(self): + super(RefreshUpgrade, self).get_slot_num() + return self._slot_num + + +class WarmBasePlatform(): + + def __init__(self): + signal_init() + debug_init() + self.warm_upgrade_param = WARM_UPGRADE_PARAM.copy() + self.stop_services_cmd_list = self.warm_upgrade_param.get("stop_services_cmd", []) + self.start_services_cmd_list = self.warm_upgrade_param.get("start_services_cmd", []) + self.__warm_upgrade_config_list = [] + + def execute_command_list(self, cmd_list): + for cmd_item in cmd_list: + warmupgradedebuglog("execute cmd: %s" % cmd_item) + status, output = exec_os_cmd(cmd_item) + if status: + log = "execute %s failed, msg: %s" % (cmd_item, output) + warmupgradeerror(log) + return False, log + return True, "execute success" + + def stop_services_access(self): + return self.execute_command_list(self.stop_services_cmd_list) + + def start_services_access(self): + return self.execute_command_list(self.start_services_cmd_list) + + def check_slot_present(self, slot_present_config): + totalerr = 0 + presentbit = slot_present_config.get('presentbit') + ret, value = get_value(slot_present_config) + if ret is False: + return "NOT OK" + if isinstance(value, str): + val_t = int(value, 16) + else: + val_t = value + val_t = (val_t & (1 << presentbit)) >> presentbit + if val_t != slot_present_config.get('okval'): + status = "ABSENT" + else: + status = "PRESENT" + return status + + def linecard_present_check(self, slot_name, slot_present_config): + present_status = self.check_slot_present(slot_present_config) + present_status_tuple = ("ABSENT", "NOT OK") + if present_status in present_status_tuple: + return False, ("%s not present, warm upgrade exit" % slot_name) + warmupgradedebuglog("%s present" % slot_name) + return True, ("%s present" % slot_name) + + def start_warmupgrade(self): + try: + # start refresh file upgrade process + for dev in self.__warm_upgrade_config_list: + ret, log = dev.refresh_file_upgrade() + if ret is False: + return ret, log + return True, "all success" + except Exception as e: + log = "Exception happend, error log : %s" % str(e) + return False, log + + def do_warmupgrade(self, file, main_type, sub_type, slot, file_type, chain): + try: + # upgrade file existence check + if not os.path.isfile(file): + return False, "%s not found" % file + + # get slot config + slot_name = "slot%d" % slot + slot_config = self.warm_upgrade_param.get(slot_name, {}) + if len(slot_config) == 0: + return False, ("%s config not found" % slot_name) + + # linecard present check + slot_present_config = slot_config.get("present", {}) + if len(slot_present_config) != 0: + ret, log = self.linecard_present_check(slot_name, slot_present_config) + if ret is False: + return False, log + + # match file_type and chain_num get chain_config + file_type_config = slot_config.get(file_type, {}) + chain_name = "chain%d" % chain + chain_list = file_type_config.get(chain_name, []) + self.__warm_upgrade_config_list = [] + for refresh_config in chain_list: + # refresh_file existence check + refresh_file_judge_flag = refresh_config.get("refresh_file_judge_flag", 0) + if refresh_file_judge_flag == 1: + refresh_file = refresh_config.get("refresh_file", None) + if not os.path.isfile(refresh_file): + log = "%s not found" % refresh_file + return False, log + # each refresh_config add as an instance of RefreshUpgrade Class + refresh_instance = RefreshUpgrade(refresh_config, slot, main_type, sub_type) + self.__warm_upgrade_config_list.append(refresh_instance) + + ret, log = self.start_warmupgrade() + if ret is False: + warmupgradeerror("doing warm upgrade failed") + warmupgradeerror(log) + return ret, log + + except Exception as e: + log = "Exception happend, error log : %s" % str(e) + return False, log + return True, "all success" + + def do_warm_upgrade(self, file, main_type, sub_type, slot, file_type, chain): + print("+================================+") + print("|Begin warm upgrade, please wait..|") + ret, log = self.do_warmupgrade(file, main_type, sub_type, slot, file_type, chain) + if ret: + print("| warm upgrade succeeded! |") + print("+================================+") + sys.exit(0) + else: + print("| warm upgrade failed! |") + print("+================================+") + print("FAILED REASON:") + print("%s" % log) + sys.exit(1) + + +@click.group(invoke_without_command=True, context_settings=CONTEXT_SETTINGS) +@click.argument('file', required=True) +@click.argument('main_type', required=True) +@click.argument('sub_type', required=True) +@click.argument('slot', required=True) +@click.argument('file_type', required=True) +@click.argument('chain', required=True) +def main(file, main_type, sub_type, slot, file_type, chain): + '''warm upgrade''' + signal_init() + debug_init() + platform = WarmBasePlatform() + platform.do_warm_upgrade(file, int(main_type, 16), int(sub_type, 16), int(slot), file_type, int(chain)) + + +# warm upgrade +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/service/platform_driver.service b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_driver.service new file mode 100644 index 000000000000..08a49d695c92 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_driver.service @@ -0,0 +1,15 @@ +[Unit] +Description= Global Initialize platform drivers. +After=local-fs.target +Before=pmon.service platform_process.service +#DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/platform_driver.py start +ExecStop=/usr/local/bin/platform_driver.py stop +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/service/platform_process.service b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_process.service new file mode 100644 index 000000000000..13dd778559f2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_process.service @@ -0,0 +1,16 @@ +[Unit] +Description= Global Load process. +After=platform_driver.service +Before=determine-reboot-cause.service pmon.service +Requires=platform_driver.service +#DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/platform_process.py start +ExecStop=/usr/local/bin/platform_process.py stop +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/__init__.py new file mode 100644 index 000000000000..b70995a582fc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = ["platform", "chassis", "sfp", "eeprom", "component", "thermal", "psu", "fan", "fan_drawer", "watchdog"] +from . import platform diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/chassis.py new file mode 100644 index 000000000000..b0ddc8691f2e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/chassis.py @@ -0,0 +1,530 @@ +#!/usr/bin/env python3 + +############################################################################# +# +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + import time + import sys + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.sfp import Sfp + from sonic_platform.psu import Psu + # from sonic_platform.fan import Fan + from sonic_platform.fan_drawer import FanDrawer + from sonic_platform.thermal import Thermal + # from sonic_platform.watchdog import Watchdog + from sonic_platform.component import Component + from sonic_platform.eeprom import Eeprom + from sonic_platform.dcdc import Dcdc + from plat_hal.baseutil import baseutil + + from plat_hal.interface import interface + +except ImportError as error: + raise ImportError(str(error) + "- required module not found")from error + + +class Chassis(ChassisBase): + """ + Platform-specific Chassis class + """ + # List of Dcdc objects representing all dcdc + # available on the chassis + _dcdc_list = None + + STATUS_INSERTED = "1" + STATUS_REMOVED = "0" + STATUS_NORMAL = "0" + STATUS_ABNORMAL = "1" + sfp_present_dict = {} + fan_present_dict = {} + voltage_status_dict = {} + + def __init__(self): + ChassisBase.__init__(self) + self._dcdc_list = [] + self.int_case = interface() + # Initialize SFP list + + # sfp.py will read eeprom contents and retrive the eeprom data. + # It will also provide support sfp controls like reset and setting + # low power mode. + # We pass the eeprom path and sfp control path from chassis.py + # So that sfp.py implementation can be generic to all platforms + try: + self._sfp_list = [] + self.port_num = baseutil.get_config().get("sfps", None).get("port_num", 0) + self.port_start_index = baseutil.get_config().get("sfps", None).get("port_index_start", 0) + # fix problem with first index is 1, we add a fake sfp node + if self.port_start_index == 1: + self._sfp_list.append(Sfp(1)) + + # sfp id always start at 1 + for index in range(1, self.port_num + 1): + self._sfp_list.append(Sfp(index)) + + for i in range(self.port_start_index, self.port_start_index + self.port_num): + self.sfp_present_dict[i] = self.STATUS_REMOVED + + except Exception as err: + print("SFP init error: %s" % str(err)) + + try: + self._eeprom = Eeprom(self.int_case) + except Exception as err: + print("EEPROM INIT ERROR %s" % str(err)) + + # Initialize watchdog + # self._watchdog = Watchdog() + fantray_num = self.int_case.get_fan_total_number() + for index in range(fantray_num): + fandrawer = FanDrawer(self.int_case, index + 1) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + psu_num = self.int_case.get_psu_total_number() + for index in range(psu_num): + psuobj = Psu(self.int_case, index + 1) + self._psu_list.append(psuobj) + + thermal_num = self.int_case.get_temp_id_number() + for index in range(thermal_num): + thermalobj = Thermal(self.int_case, index + 1) + self._thermal_list.append(thermalobj) + + component_num = self.int_case.get_cpld_total_number() + for index in range(component_num): + componentobj = Component(self.int_case, index + 1) + self._component_list.append(componentobj) + + dcdc_num = self.int_case.get_dcdc_total_number() + for index in range(dcdc_num): + dcdcobj = Dcdc(self.int_case, index + 1) + self._dcdc_list.append(dcdcobj) + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + name = '' + sys_eeprom = self.get_eeprom() + if sys_eeprom is None: + return '' + + e = sys_eeprom.read_eeprom() + name = sys_eeprom.modelstr(e) + if name is None: + return '' + return name + + 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 + """ + model = '' + sys_eeprom = self.get_eeprom() + if sys_eeprom is None: + return '' + + e = sys_eeprom.read_eeprom() + model = sys_eeprom.modelnumber(e) + if model is None: + return '' + return model + + def get_serial_number(self): + """ + Retrieves the hardware serial number for the chassis + + Returns: + A string containing the hardware serial number for this chassis. + """ + serial_number = '' + sys_eeprom = self.get_eeprom() + if sys_eeprom is None: + return '' + + e = sys_eeprom.read_eeprom() + serial_number = sys_eeprom.serial_number_str(e) + if serial_number is None: + return '' + + return serial_number + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + device_version = '' + sys_eeprom = self.get_eeprom() + if sys_eeprom is None: + return '' + + e = sys_eeprom.read_eeprom() + device_version = sys_eeprom.deviceversion(e) + if device_version is None: + return '' + + return device_version + + def get_serial(self): + """ + Retrieves the serial number of the chassis (Service tag) + Returns: + string: Serial number of chassis + """ + return self.get_serial_number() + + 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_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 initizalize_system_led(self): + return True + + def set_status_led(self, color): + return False + + 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. + """ + ret, color = self.int_case.get_led_color_by_type('SYS_LED') + if ret is True: + return color + return 'N/A' + + 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' + """ + base_mac = '' + sys_eeprom = self.get_eeprom() + if sys_eeprom is None: + return '' + + e = sys_eeprom.read_eeprom() + base_mac = sys_eeprom.base_mac_addr(e) + if base_mac is None: + return '' + + return base_mac.upper() + + 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. + Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', + '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', + '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} + """ + sys_eeprom = self.get_eeprom() + if sys_eeprom is None: + return {} + return sys_eeprom.system_eeprom_info() + + def get_thermal_manager(self): + """ + Retrieves thermal manager class on this chassis + :return: A class derived from ThermalManagerBase representing the + specified thermal manager. ThermalManagerBase is returned as default + """ + return False + + 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. + """ + reboot_cause_msg = self.int_case.get_cpu_reboot_cause() + if "Power Loss" in reboot_cause_msg: + reboot_cause_type = self.REBOOT_CAUSE_POWER_LOSS + elif "Watchdog" in reboot_cause_msg: + reboot_cause_type = self.REBOOT_CAUSE_WATCHDOG + elif "BMC reboot" in reboot_cause_msg or "BMC powerdown" in reboot_cause_msg: + reboot_cause_type = self.REBOOT_CAUSE_HARDWARE_OTHER + elif "Thermal Overload: ASIC" in reboot_cause_msg: + reboot_cause_type = self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC + elif "Thermal Overload: Other" in reboot_cause_msg: + reboot_cause_type = self.REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER + elif "Other" in reboot_cause_msg: + reboot_cause_type = self.REBOOT_CAUSE_NON_HARDWARE + else: + reboot_cause_type = self.REBOOT_CAUSE_NON_HARDWARE + return (reboot_cause_type, reboot_cause_msg) + + def get_module(self, index): + """ + Retrieves module represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the module to + retrieve + + Returns: + An object dervied from ModuleBase representing the specified + module + """ + module = None + + try: + if self.get_num_modules(): + module = self._module_list[index] + except IndexError: + sys.stderr.write("Module index {} out of range (0-{})\n".format( + index, len(self._module_list) - 1)) + + return module + + def get_fan_drawer(self, index): + """ + Retrieves fan drawers represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the fan drawer to + retrieve + + Returns: + An object dervied from FanDrawerBase representing the specified fan + drawer + """ + fan_drawer = None + + try: + if self.get_num_fan_drawers(): + fan_drawer = self._fan_drawer_list[index] + except IndexError: + sys.stderr.write("Fan drawer index {} out of range (0-{})\n".format( + index, len(self._fan_drawer_list) - 1)) + + return fan_drawer + + 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): + - bool: True if call successful, False if not; + - dict: 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. + The known devices's device_id and device_event was defined as table below. + ----------------------------------------------------------------- + device | device_id | device_event | annotate + ----------------------------------------------------------------- + 'fan' '' '0' Fan removed + '1' Fan inserted + + 'sfp' '' '0' Sfp removed + '1' Sfp inserted + '2' I2C bus stuck + '3' Bad eeprom + '4' Unsupported cable + '5' High Temperature + '6' Bad cable + + 'voltage' '' '0' Vout normal + '1' Vout abnormal + -------------------------------------------------------------------- + Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0', '12':'1'}, + 'voltage':{'U20':'0', 'U21':'1'}} + Indicates that: + fan 0 has been removed, fan 2 has been inserted. + sfp 11 has been removed, sfp 12 has been inserted. + monitored voltage U20 became normal, voltage U21 became abnormal. + Note: For sfp, when event 3-6 happened, the module will not be avalaible, + XCVRD shall stop to read eeprom before SFP recovered from error status. + """ + + change_event_dict = {"fan": {}, "sfp": {}, "voltage": {}} + + start_time = time.time() + forever = False + + if timeout == 0: + forever = True + elif timeout > 0: + timeout = timeout / float(1000) # Convert to secs + else: + print("get_change_event:Invalid timeout value: %s" % timeout) + return False, change_event_dict + + end_time = start_time + timeout + if start_time > end_time: + print("get_change_event:time wrap / invalid timeout value: %s" % timeout) + return False, change_event_dict # Time wrap or possibly incorrect timeout + try: + while timeout >= 0: + # check for sfp + sfp_change_dict = self.get_transceiver_change_event() + # check for fan + fan_change_dict = self.get_fan_change_event() + # check for voltage + voltage_change_dict = self.get_voltage_change_event() + + if sfp_change_dict or fan_change_dict or voltage_change_dict: + change_event_dict["sfp"] = sfp_change_dict + change_event_dict["fan"] = fan_change_dict + change_event_dict["voltage"] = voltage_change_dict + return True, change_event_dict + 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, change_event_dict + except Exception as e: + print(e) + print("get_change_event: Should not reach here.") + return False, change_event_dict + + def get_transceiver_change_event(self): + current_sfp_present_dict = {} + ret_dict = {} + + # Check for OIR events and return ret_dict + for i in range(self.port_start_index, self.port_start_index + self.port_num): + sfp = self._sfp_list[i] + if sfp.get_presence(): + current_sfp_present_dict[i] = self.STATUS_INSERTED + + else: + current_sfp_present_dict[i] = self.STATUS_REMOVED + + # Update reg value + if current_sfp_present_dict == self.sfp_present_dict: + return ret_dict + + for index, status in current_sfp_present_dict.items(): + if self.sfp_present_dict[index] != status: + ret_dict[index] = status + + self.sfp_present_dict = current_sfp_present_dict + + return ret_dict + + def get_fan_change_event(self): + current_fan_present_dict = {} + ret_dict = {} + + # Check for OIR events and return ret_dict + for index, fan in enumerate(self._fan_list): + if fan.get_presence() is True: + current_fan_present_dict[index] = self.STATUS_INSERTED + else: + current_fan_present_dict[index] = self.STATUS_REMOVED + + if len(self.fan_present_dict) == 0: # first time + self.fan_present_dict = current_fan_present_dict + return {} + + if current_fan_present_dict == self.fan_present_dict: + return {} + + # updated fan_present_dict + for index, status in current_fan_present_dict.items(): + if self.fan_present_dict[index] != status: + ret_dict[str(index)] = status + self.fan_present_dict = current_fan_present_dict + return ret_dict + + def get_voltage_change_event(self): + current_voltage_status_dict = {} + ret_dict = {} + + # Check for OIR events and return ret_dict + for index, dcdc in enumerate(self._dcdc_list): + name = dcdc.get_name() + value = dcdc.get_value() + high = dcdc.get_high_threshold() + low = dcdc.get_low_threshold() + if (value is None) or (value > high) or (value < low): + current_voltage_status_dict[name] = self.STATUS_ABNORMAL + else: + current_voltage_status_dict[name] = self.STATUS_NORMAL + + if len(self.voltage_status_dict) == 0: # first time + self.voltage_status_dict = current_voltage_status_dict + return {} + + if current_voltage_status_dict == self.voltage_status_dict: + return {} + + # updated voltage_status_dict + for name, status in current_voltage_status_dict.items(): + if self.voltage_status_dict[name] != status: + ret_dict[name] = status + self.voltage_status_dict = current_voltage_status_dict + return ret_dict + + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/component.py new file mode 100644 index 000000000000..fa674a98a6bf --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/component.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python3 + +######################################################################## +# +# 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 time + import subprocess + import os + from sonic_platform_base.component_base import ComponentBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") from e + + +FIRMWARE_UPDATE_DIR = "/tmp/.firmwareupdate/" + +class Component(ComponentBase): + """Platform-specific Component class""" + + def __init__(self, interface_obj, index): + self.cpld_dict = {} + self.int_case = interface_obj + self.index = index + self.update_time = 0 + self.cpld_id = "CPLD" + str(index) + + def cpld_dict_update(self): + local_time = time.time() + if not self.cpld_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds + self.update_time = local_time + self.cpld_dict = self.int_case.get_cpld_version_by_id(self.cpld_id) + + def get_slot(self): + self.cpld_dict_update() + return self.cpld_dict["Slot"] + + def get_warm_upgrade_flag(self): + self.cpld_dict_update() + return self.cpld_dict["Warm"] + + def get_name(self): + """ + Retrieves the name of the component + + Returns: + A string containing the name of the component + """ + self.cpld_dict_update() + return self.cpld_dict["Name"] + + def get_description(self): + """ + Retrieves the description of the component + + Returns: + A string containing the description of the component + """ + self.cpld_dict_update() + return self.cpld_dict["Desc"] + + def get_firmware_version(self): + """ + Retrieves the firmware version of the component + + Note: the firmware version will be read from HW + + Returns: + A string containing the firmware version of the component + """ + self.cpld_dict_update() + return self.cpld_dict["Version"] + + 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 + """ + raise NotImplementedError + + def get_firmware_update_notification(self, image_path): + """ + Retrieves a notification on what should be done in order to complete + the component firmware update + + Args: + image_path: A string, path to firmware image + + Returns: + A string containing the component firmware update notification if required. + By default 'None' value will be used, which indicates that no actions are required + """ + return None + + def install_firmware(self, image_path): + """ + Installs firmware to the component + + This API performs firmware installation only: this may/may not be the same as firmware update. + 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 must be done manually by user + + Note: in case immediate actions are required to complete the component firmware update + (e.g., reboot, power cycle, etc.) - will be done automatically by API and no return value provided + + Args: + image_path: A string, path to firmware image + + Returns: + A boolean, True if install was successful, False if not + """ + if not os.path.isfile(image_path): + print("ERROR: %s not found" % image_path) + return False + cmdstr = "upgrade.py cold %s %d" % (image_path, self.get_slot()) + status, output = subprocess.getstatusoutput(cmdstr) + if status == 0: + print("INFO: %s firmware install succeeded" % self.get_name()) + return True + print("%s install failed. status:%d, output:\n%s" % (self.get_name(), status, output)) + return False + + 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 + """ + if not os.path.isfile(image_path): + raise RuntimeError("ERROR: %s not found" % image_path) + + if self.get_warm_upgrade_flag() == 1: # use warm upgrade + cmdstr = "upgrade.py warm %s %d" % (image_path, self.get_slot()) + else: + cmdstr = "upgrade.py cold %s %d" % (image_path, self.get_slot()) + status, output = subprocess.getstatusoutput(cmdstr) + if status == 0: + if self.get_warm_upgrade_flag() != 1: # not support warm upgrade, need to cold reboot + print("INFO: %s firmware install succeeded" % self.get_name()) + print("INFO: please cold reboot to make the %s firmware up-to-date" % self.get_name()) + else: + print("INFO: %s firmware update succeeded" % self.get_name()) + print("INFO: %s firmware version up-to-date" % self.get_name()) + return None + raise RuntimeError(output) + + def auto_update_firmware(self, image_path, boot_type): + """ + Updates firmware of the component + + This API performs firmware update automatically based on boot_type: it assumes firmware installation + and/or creating a loading task during the reboot, if needed, 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 during the reboot. + The loading task will be created by API. + + Args: + image_path: A string, path to firmware image + boot_type: A string, reboot type following the upgrade + - none/fast/warm/cold + + Returns: + Output: A return code + return_code: An integer number, status of component firmware auto-update + - return code of a positive number indicates successful auto-update + - status_installed = 1 + - status_updated = 2 + - status_scheduled = 3 + - return_code of a negative number indicates failed auto-update + - status_err_boot_type = -1 + - status_err_image = -2 + - status_err_unknown = -3 + + Raises: + RuntimeError: auto-update failure cause + """ + if not os.path.isfile(image_path): + print("ERROR: %s not found" % image_path) + return -2 + + if not os.path.isdir(FIRMWARE_UPDATE_DIR): + os.mkdir(FIRMWARE_UPDATE_DIR) + + warm_upgrade_flag = self.get_warm_upgrade_flag() + file_name = os.path.basename(image_path) + file_path = os.path.join(FIRMWARE_UPDATE_DIR, file_name) + if os.path.exists(file_path): # firmware already update + if warm_upgrade_flag == 1: + print("INFO: %s firmware update succeeded, firmware version up-to-date" % self.get_name()) + return 2 + print("INFO: %s firmware install succeeded, please cold reboot to make it up-to-date" % self.get_name()) + return 1 + + if warm_upgrade_flag == 1: # use warm upgrade + cmdstr = "upgrade.py warm %s %d" % (image_path, self.get_slot()) + else: + cmdstr = "upgrade.py cold %s %d" % (image_path, self.get_slot()) + status, output = subprocess.getstatusoutput(cmdstr) + if status == 0: + os.mknod(file_path) + if warm_upgrade_flag == 1: + print("INFO: %s firmware update succeeded, firmware version up-to-date" % self.get_name()) + return 2 + print("INFO: %s firmware install succeeded, please cold reboot to make it up-to-date" % self.get_name()) + return 1 + print("%s update failed, status:%d, output:\n%s" % (self.get_name(), status, output)) + return -3 diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/dcdc.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/dcdc.py new file mode 100644 index 000000000000..494d4aa610dc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/dcdc.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 + +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Thermals' information which are available in the platform +# +######################################################################## +import time + + +class Dcdc(object): + + def __init__(self, interface_obj, index): + self.dcdc_dict = {} + self.int_case = interface_obj + self.index = index + self.update_time = 0 + self.dcdc_id = "DCDC" + str(index) + + def dcdc_dict_update(self): + local_time = time.time() + if not self.dcdc_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds + self.update_time = local_time + self.dcdc_dict = self.int_case.get_dcdc_by_id(self.dcdc_id) + + def get_name(self): + """ + Retrieves the name of the sensor + + Returns: + string: The name of the sensor + """ + self.dcdc_dict_update() + return self.dcdc_dict["Name"] + + def get_value(self): + """ + Retrieves current value reading from sensor + """ + self.dcdc_dict_update() + value = self.dcdc_dict["Value"] + if value is None: + value = 0 + return round(float(value), 3) + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature of sensor + """ + self.dcdc_dict_update() + value = self.dcdc_dict["High"] + if value is None: + value = 0 + return round(float(value), 3) + + def get_low_threshold(self): + """ + Retrieves the low threshold temperature of sensor + """ + self.dcdc_dict_update() + value = self.dcdc_dict["Low"] + if value is None: + value = 0 + return round(float(value), 3) + + def get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature of sensor + """ + self.dcdc_dict_update() + value = self.dcdc_dict["Max"] + if value is None: + value = 0 + return round(float(value), 3) + + def get_low_critical_threshold(self): + """ + Retrieves the low critical threshold temperature of sensor + """ + self.dcdc_dict_update() + value = self.dcdc_dict["Min"] + if value is None: + value = 0 + return round(float(value), 3) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/eeprom.py new file mode 100644 index 000000000000..05fcc3c25678 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/eeprom.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +######################################################################## +# +# 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. +# - PSU EEPROM : Contains Serial number, Part number, Service Tag, +# PSU type, Revision. +# - Fan EEPROM : Contains Serial number, Part number, Service Tag, +# Fan type, Number of Fans in Fantray, Revision. +######################################################################## + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError as error: + raise ImportError(str(error) + "- required module not found") from error + + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self, interface_obj): + self.int_case = interface_obj + self.name = "ONIE_E2" + + eeprom_path = self.int_case.get_onie_e2_path(self.name) + if eeprom_path is None: + raise ValueError("get eeprom path failed") + + super().__init__(eeprom_path, 0, "", True) + + def modelnumber(self, e): + ''' + Returns the value field of the model(part) number TLV as a string + ''' + (is_valid, t) = self.get_tlv_field(e, self._TLV_CODE_PART_NUMBER) + if not is_valid: + return super().part_number_str(e) + + return t[2].decode("ascii") + + def deviceversion(self, e): + ''' + Returns the value field of the Device Version as a string + ''' + (is_valid, t) = self.get_tlv_field(e, self._TLV_CODE_DEVICE_VERSION) + if not is_valid: + return "N/A" + + return str(ord(t[2])) + + def 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. + Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', + '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', + '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} + ''' + sys_eeprom_dict = {} + e = self.read_eeprom() + if self._TLV_HDR_ENABLED: + if not self.is_valid_tlvinfo_header(e): + return {} + total_len = (e[9] << 8) | e[10] + tlv_index = self._TLV_INFO_HDR_LEN + tlv_end = self._TLV_INFO_HDR_LEN + total_len + else: + tlv_index = self.eeprom_start + tlv_end = self._TLV_INFO_MAX_LEN + + while (tlv_index + 2) < len(e) and tlv_index < tlv_end: + if not self.is_valid_tlv(e[tlv_index:]): + break + + tlv = e[tlv_index:tlv_index + 2 + e[tlv_index + 1]] + code = "0x%02X" % tlv[0] + name, value = self.decoder(None, tlv) + sys_eeprom_dict[code] = value + + if e[tlv_index] == self._TLV_CODE_QUANTA_CRC or \ + e[tlv_index] == self._TLV_CODE_CRC_32: + break + tlv_index += e[tlv_index + 1] + 2 + + return sys_eeprom_dict diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan.py new file mode 100644 index 000000000000..be1c8ce8f4fd --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan.py @@ -0,0 +1,314 @@ +#!/usr/bin/env python3 +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fans' information which are available in the platform. +# +######################################################################## + +try: + import time + from sonic_platform_base.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") from e + + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, interface_obj, fantray_index, fan_index, psu_fan=False, psu_index=0): + self.fan_dict = {} + self.int_case = interface_obj + self.fantray_index = fantray_index + self.fan_index = fan_index + self.psu_index = psu_index + self.is_psu_fan = psu_fan + self.update_time = 0 + if not self.is_psu_fan: + self.name = "FAN" + str(fantray_index) + else: + self.name = "PSU" + str(psu_index) + + def fan_dict_update(self): + local_time = time.time() + if not self.fan_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds + self.update_time = local_time + if not self.is_psu_fan: + self.fan_dict = self.int_case.get_fan_info(self.name) + else: + self.fan_dict = self.int_case.get_psu_fru_info(self.name) + + def get_name(self): + """ + Retrieves the fan name + Returns: + string: The name of the device + """ + if not self.is_psu_fan: + return "Fantray{}_{}".format(self.fantray_index, self.fan_index) + return "PSU{}_FAN{}".format(self.psu_index, self.fan_index) + + def get_model(self): + """ + Retrieves the part number of the FAN + Returns: + string: Part number of FAN + """ + if not self.is_psu_fan: + self.fan_dict_update() + return self.fan_dict["DisplayName"] + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the FAN + Returns: + string: Serial number of FAN + """ + if not self.is_psu_fan: + self.fan_dict_update() + return self.fan_dict["SN"] + return 'N/A' + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if fan is present, False if not + """ + if not self.is_psu_fan: + return self.int_case.get_fan_presence(self.name) + return self.int_case.get_psu_presence(self.name) + + def get_status(self): + """ + Retrieves the operational status of the FAN + Returns: + bool: True if FAN is operating properly, False if not + """ + if not self.get_presence(): + return False + + if not self.is_psu_fan: + fan_dir = {} + fan_dir = self.int_case.get_fan_info_rotor(self.name) + # get fan rotor pwm + rotor_name = "Rotor" + str(self.fan_index) + value = fan_dir[rotor_name]["Speed"] + min_speed = fan_dir[rotor_name]["SpeedMin"] + max_speed = fan_dir[rotor_name]["SpeedMax"] + tolerance = fan_dir[rotor_name]["Tolerance"] + else: + psu_status_dict = self.int_case.get_psu_status(self.name) + value = psu_status_dict["FanSpeed"]["Value"] + min_speed = psu_status_dict["FanSpeed"]["Min"] + max_speed = psu_status_dict["FanSpeed"]["Max"] + tolerance = psu_status_dict["FanSpeed"]["Tolerance"] + + if isinstance(tolerance, str) or tolerance is None: + tolerance = 30 + + if isinstance(value, str) or value is None: + if self.is_psu_fan: + psu_status_dict = self.int_case.get_psu_status(self.name) + if psu_status_dict["OutputStatus"] is True: + return True + return False + + if value < min_speed: + return False + + speed = int(value * 100 / max_speed) + if speed > 100: + speed = 100 + elif speed < 0: + speed = 0 + target = self.get_target_speed() + + if (speed - target) > target * tolerance / 100: + return False + if (target - speed) > target * tolerance / 100: + return False + + return True + + 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 True + + def get_direction(self): + """ + Retrieves the fan airflow direction + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + + Notes: + - Forward/Exhaust : Air flows from Port side to Fan side. + - Reverse/Intake : Air flows from Fan side to Port side. + """ + self.fan_dict_update() + air_flow = self.fan_dict["AirFlow"] + if air_flow is not None: + return air_flow + return self.FAN_DIRECTION_NOT_APPLICABLE + + def get_speed(self): + """ + Retrieves the speed of fan as a percentage of full speed + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + if not self.get_presence(): + return 0 + + if not self.is_psu_fan: + fan_dir = {} + fan_dir = self.int_case.get_fan_info_rotor(self.name) + # get fan rotor pwm + rotor_name = "Rotor" + str(self.fan_index) + value = fan_dir[rotor_name]["Speed"] + max_speed = fan_dir[rotor_name]["SpeedMax"] + else: + psu_status_dict = self.int_case.get_psu_status(self.name) + value = psu_status_dict["FanSpeed"]["Value"] + max_speed = psu_status_dict["FanSpeed"]["Max"] + + if isinstance(value, str) or value is None: + return None + pwm = value * 100 / max_speed + if pwm > 100: + pwm = 100 + elif pwm < 0: + pwm = 0 + return int(pwm) + + 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 + """ + # The default tolerance value is fixed as 30% + if not self.is_psu_fan: + fan_dir = {} + fan_dir = self.int_case.get_fan_info_rotor(self.name) + # get fan rotor tolerance + rotor_name = "Rotor" + str(self.fan_index) + tolerance = fan_dir[rotor_name]["Tolerance"] + else: + psu_status_dict = self.int_case.get_psu_status(self.name) + tolerance = psu_status_dict["FanSpeed"]["Tolerance"] + + if isinstance(tolerance, str) or tolerance is None: + return 30 + return tolerance + + def fan_set_speed_pwm(self, pwm): + status = self.int_case.set_fan_speed_pwm(self.name, self.fan_index, pwm) + if status == -1: + return False + return True + + 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 not self.is_psu_fan: + return self.fan_set_speed_pwm(speed) + return self.int_case.set_psu_fan_speed_pwm(self.name, int(speed)) + + 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. + """ + # not supported + 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 self.is_psu_fan: + # No LED available for PSU Fan + return 'N/A' + + if not self.get_presence(): + return 'N/A' + + ret, color = self.int_case.get_fan_led(self.name) + if ret is True: + return color + 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) + """ + if not self.is_psu_fan: + # get fan rotor pwm + pwm = int(self.int_case.get_fan_speed_pwm(self.name, self.fan_index)) + else: + psu_status_dict = self.int_case.get_psu_status(self.name) + if psu_status_dict["InputStatus"] is False: + pwm = 0 + else: + pwm = self.get_speed() # target equal to real pwm, to avoid alarm + if pwm is None: + return None + return int(pwm) + + def get_vendor(self): + """ + Retrieves the vendor name of the fan + + Returns: + string: Vendor name of fan + """ + if not self.is_psu_fan: + return "WB" + return 'N/A' + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + if not self.is_psu_fan: + self.fan_dict_update() + return self.fan_dict["HW"] + return 'N/A' diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan_drawer.py new file mode 100644 index 000000000000..f0b039648158 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan_drawer.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 +# +# fan_drawer_base.py +# +# Abstract base class for implementing a platform-specific class with which +# to interact with a fan drawer module in SONiC +# + +try: + import time + from sonic_platform_base.fan_drawer_base import FanDrawerBase + from sonic_platform.fan import Fan +except ImportError as e: + raise ImportError(str(e) + "- required module not found") from e + + +class FanDrawer(FanDrawerBase): + """ + Abstract base class for interfacing with a fan drawer + """ + # Device type definition. Note, this is a constant. + DEVICE_TYPE = "fan_drawer" + + def __init__(self, interface_obj, fantray_index): + FanDrawerBase.__init__(self) + self.fantray_dict = {} + self.fantray_update_time = 0 + self.fantray_index = fantray_index + self.int_case = interface_obj + self.fantrayname = "FAN" + str(fantray_index) + self.num_fans_per_fantray = self.int_case.get_fan_rotor_number(self.fantrayname) + for i in range(self.num_fans_per_fantray): + self._fan_list.append(Fan(interface_obj, fantray_index, i + 1)) + + def fantray_dict_update(self): + local_time = time.time() + # update data every 1 seconds + if not self.fantray_dict or (local_time - self.fantray_update_time) >= 1: + self.fantray_update_time = local_time + self.fantray_dict = self.int_case.get_fan_info(self.fantrayname) + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return "Fantray{}".format(self.fantray_index) + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if fan is present, False if not + """ + return self.int_case.get_fan_presence(self.fantrayname) + + def get_model(self): + """ + Retrieves the part number of the FAN + Returns: + string: Part number of FAN + """ + self.fantray_dict_update() + return self.fantray_dict["NAME"] + + def get_serial(self): + """ + Retrieves the serial number of the FAN + Returns: + string: Serial number of FAN + """ + self.fantray_dict_update() + return self.fantray_dict["SN"] + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + self.fantray_dict_update() + return self.fantray_dict["HW"] + + def get_status(self): + """ + Retrieves the operational status of the FAN + Returns: + bool: True if FAN is operating properly, False if not + """ + for i in range(self.num_fans_per_fantray): + if self._fan_list[i].get_status() is False: + return False + return True + + 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 True + + def get_num_fans(self): + """ + Retrieves the number of fans available on this fan drawer + Returns: + An integer, the number of fan modules available on this fan drawer + """ + return len(self._fan_list) + + def get_all_fans(self): + """ + Retrieves all fan modules available on this fan drawer + Returns: + A list of objects derived from FanBase representing all fan + modules available on this fan drawer + """ + return self._fan_list + + 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 + """ + # not supported + 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' + + ret, color = self.int_case.get_fan_led(self.fantrayname) + if ret is True: + return color + return 'N/A' + + def get_maximum_consumed_power(self): + """ + Retrives the maximum power drawn by Fan Drawer + + Returns: + A float, with value of the maximum consumable power of the + component. + """ + self.fantray_dict_update() + return self.fantray_dict["PowerMax"] diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/pcie.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/pcie.py new file mode 100644 index 000000000000..8ea66f339e96 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/pcie.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +######################################################################## +# +# Module contains a platform specific implementation of SONiC Platform +# Base PCIe class +# +######################################################################## + +try: + from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil +except ImportError as e: + raise ImportError(str(e) + "- required module not found") from e + + +class Pcie(PcieUtil): + """Platform-specific Pcie class""" + + def __init__(self, platform_path): + PcieUtil.__init__(self, platform_path) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/platform.py new file mode 100644 index 000000000000..4d6fe03d93ac --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/platform.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +############################################################################# +# +# 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): + """ + Platform-specific class + """ + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/psu.py new file mode 100644 index 000000000000..2a634ca6b0a8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/psu.py @@ -0,0 +1,359 @@ +#!/usr/bin/env python3 +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs' information which are available in the platform +# +######################################################################## + + +try: + import time + from sonic_platform_base.psu_base import PsuBase + from sonic_platform.fan import Fan +except ImportError as e: + raise ImportError(str(e) + "- required module not found") from e + + +class Psu(PsuBase): + """Platform-specific PSU class""" + + def __init__(self, interface_obj, index): + self.psu_dict = {} + self.psu_status_dict = {} + self.psu_power_dict = {} + self._fan_list = [] + self._thermal_list = [] + self.int_case = interface_obj + self.index = index + self.name = "PSU" + str(index) + + self.psu_dict_update_time = 0 + self.psu_status_dict_update_time = 0 + self.psu_power_dict_update_time = 0 + + self._fan_list.append(Fan(self.int_case, 1, 1, psu_fan=True, psu_index=index)) + + def psu_dict_update(self): + local_time = time.time() + if not self.psu_dict or (local_time - self.psu_dict_update_time) >= 1: # update data every 1 seconds + self.psu_dict_update_time = local_time + self.psu_dict = self.int_case.get_psu_fru_info(self.name) + + def psu_status_dict_update(self): + local_time = time.time() + if not self.psu_status_dict or ( + local_time - self.psu_status_dict_update_time) >= 1: # update data every 1 seconds + self.psu_status_dict_update_time = local_time + self.psu_status_dict = self.int_case.get_psu_status(self.name) + + def psu_power_dict_update(self): + local_time = time.time() + if not self.psu_power_dict or ( + local_time - self.psu_power_dict_update_time) >= 1: # update data every 1 seconds + self.psu_power_dict_update_time = local_time + self.psu_power_dict = self.int_case.get_psu_power_status(self.name) + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return "Psu{}".format(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 + """ + return self.int_case.get_psu_presence(self.name) + + def get_model(self): + """ + Retrieves the part number of the PSU + + Returns: + string: Part number of PSU + """ + self.psu_dict_update() + return self.psu_dict["DisplayName"] + + def get_serial(self): + """ + Retrieves the serial number of the PSU + + Returns: + string: Serial number of PSU + """ + self.psu_dict_update() + return self.psu_dict["SN"] + + def get_status(self): + """ + Retrieves the operational status of the PSU + + Returns: + bool: True if PSU is operating properly, False if not + """ + return self.int_case.get_psu_input_output_status(self.name) + + 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 True + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + self.psu_status_dict_update() + if self.psu_status_dict["OutputStatus"] is False: + value = 0 + else: + self.psu_power_dict_update() + value = self.psu_power_dict["Outputs"]["Voltage"]["Value"] + if value is None: + return None + return round(float(value), 1) + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, electric current in amperes, + e.g. 15.4 + """ + self.psu_status_dict_update() + if self.psu_status_dict["OutputStatus"] is False: + value = 0 + else: + self.psu_power_dict_update() + value = self.psu_power_dict["Outputs"]["Current"]["Value"] + if value is None: + return None + return round(float(value), 1) + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, + e.g. 302.6 + """ + self.psu_status_dict_update() + if self.psu_status_dict["OutputStatus"] is False: + value = 0 + else: + self.psu_power_dict_update() + value = self.psu_power_dict["Outputs"]["Power"]["Value"] + if value is None: + return None + return round(float(value), 1) + + 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 self.int_case.get_psu_input_output_status(self.name) + + 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" + if self.int_case.get_psu_input_output_status(self.name): + return self.STATUS_LED_COLOR_GREEN + return self.STATUS_LED_COLOR_RED + + 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 + """ + # not supported + return False + + def get_temperature(self): + """ + Retrieves current temperature reading from PSU + + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + self.psu_status_dict_update() + value = self.psu_status_dict["Temperature"]["Value"] + if value is None: + return None + return round(float(value), 1) + + def get_temperature_high_threshold(self): + """ + Retrieves the high threshold temperature of PSU + + Returns: + A float number, the high threshold temperature of PSU in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + self.psu_status_dict_update() + value = self.psu_status_dict["Temperature"]["Max"] + if value is None: + return None + return round(float(value), 1) + + 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 + """ + self.psu_power_dict_update() + value = self.psu_power_dict["Outputs"]["Voltage"]["HighAlarm"] + if value is None: + return None + return round(float(value), 1) + + 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 + """ + self.psu_power_dict_update() + value = self.psu_power_dict["Outputs"]["Voltage"]["LowAlarm"] + if value is None: + return None + return round(float(value), 1) + + def get_input_voltage(self): + """ + Get the input voltage of the PSU + + Returns: + A float number, the input voltage in volts, + """ + self.psu_status_dict_update() + if self.psu_status_dict["InputStatus"] is False: + value = 0 + else: + self.psu_power_dict_update() + value = self.psu_power_dict["Inputs"]["Voltage"]["Value"] + if value is None: + return None + return round(float(value), 1) + + def get_input_current(self): + """ + Get the input electric current of the PSU + + Returns: + A float number, the input current in amperes, e.g 220.3 + """ + self.psu_status_dict_update() + if self.psu_status_dict["InputStatus"] is False: + value = 0 + else: + self.psu_power_dict_update() + value = self.psu_power_dict["Inputs"]["Current"]["Value"] + if value is None: + return None + return round(float(value), 1) + + def get_input_power(self): + """ + Get the input current energy of the PSU + + Returns: + A float number, the input power in watts, e.g. 302.6 + """ + self.psu_status_dict_update() + if self.psu_status_dict["InputStatus"] is False: + value = 0 + else: + self.psu_power_dict_update() + value = self.psu_power_dict["Inputs"]["Power"]["Value"] + if value is None: + return None + return round(float(value), 1) + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + self.psu_dict_update() + return self.psu_dict["HW"] + + def get_vendor(self): + """ + Retrieves the vendor name of the psu + + Returns: + string: Vendor name of psu + """ + self.psu_dict_update() + return self.psu_dict["VENDOR"] + + def get_maximum_supplied_power(self): + """ + Retrieves the maximum supplied power by PSU + + Returns: + A float number, the maximum power output in Watts. + e.g. 1200.1 + """ + return False + + def get_thermal(self, index): + """ + Retrieves thermal unit represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the thermal to + retrieve + + Returns: + An object dervied from ThermalBase representing the specified thermal + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/sfp.py new file mode 100644 index 000000000000..3fc22b4b6618 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/sfp.py @@ -0,0 +1,634 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +############################################################################# +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +# +# *_device.py config version instruction: +# ver 1.0 - platform api: +# "presence_cpld": { +# "dev_id": { +# [dev_id]: { +# "offset": { +# [offset]: [port_id] +# } +# } +# } +# } +# "reset_cpld": { +# "dev_id": { +# [dev_id]: { +# "offset": { +# [offset]: [port_id] +# } +# } +# } +# } +# ver 2.0 - wb_plat: +# "presence_path": "/xx/wb_plat/xx[port_id]/present" +# "eeprom_path": "/sys/bus/i2c/devices/i2c-[bus]/[bus]-0050/eeprom" +# "reset_path": "/xx/wb_plat/xx[port_id]/reset" +############################################################################# +import sys +import time +import syslog +import traceback +from abc import abstractmethod + +configfile_pre = "/usr/local/bin/" +sys.path.append(configfile_pre) + +try: + from platform_intf import * + from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase + from plat_hal.baseutil import baseutil + +except ImportError as error: + raise ImportError(str(error) + "- required module not found") from error + +LOG_DEBUG_LEVEL = 1 +LOG_WARNING_LEVEL = 2 +LOG_ERROR_LEVEL = 3 + + +class Sfp(SfpOptoeBase): + + OPTOE_DRV_TYPE1 = 1 + OPTOE_DRV_TYPE2 = 2 + OPTOE_DRV_TYPE3 = 3 + + # index must start at 1 + def __init__(self, index): + SfpOptoeBase.__init__(self) + self.sfp_type = None + sfp_config = baseutil.get_config().get("sfps", None) + self.log_level_config = sfp_config.get("log_level", LOG_WARNING_LEVEL) + # Init instance of SfpCust + ver = sfp_config.get("ver", None) + if ver is None: + self._sfplog(LOG_ERROR_LEVEL, "Get Ver Config Error!") + vers = int(float(ver)) + if vers == 1: + self._sfp_api = SfpV1(index) + elif vers == 2: + self._sfp_api = SfpV2(index) + else: + self._sfplog(LOG_ERROR_LEVEL, "Get SfpVer Error!") + + def get_eeprom_path(self): + return self._sfp_api._get_eeprom_path() + + def read_eeprom(self, offset, num_bytes): + return self._sfp_api.read_eeprom(offset, num_bytes) + + def get_presence(self): + return self._sfp_api.get_presence() + + def get_transceiver_info(self): + # temporary solution for a sonic202111 bug + transceiver_info = super().get_transceiver_info() + try: + if transceiver_info == None: + return None + if transceiver_info['cable_type'] == None: + transceiver_info['cable_type'] = 'N/A' + if transceiver_info["vendor_rev"] is not None: + transceiver_info["hardware_rev"] = transceiver_info["vendor_rev"] + except BaseException: + print(traceback.format_exc()) + return None + return transceiver_info + + def get_reset_status(self): + if self.get_presence() is False: + return False + + if self.sfp_type is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'SFP': + self._sfplog(LOG_ERROR_LEVEL, 'SFP does not support reset') + return False + + ret = self._sfp_api.get_reset_status() + return ret + + def reset(self): + if self.get_presence() is False: + return False + + if self.sfp_type is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'SFP': + self._sfplog(LOG_ERROR_LEVEL, 'SFP does not support reset') + return False + + self._sfplog(LOG_DEBUG_LEVEL, 'resetting...') + ret = self._sfp_api.set_reset(True) + if ret: + time.sleep(0.5) + ret = self._sfp_api.set_reset(False) + + return ret + + def get_lpmode(self): + if self.get_presence() is False: + return False + + if self.sfp_type is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'QSFP' or self.sfp_type == 'QSFP-DD': + return SfpOptoeBase.get_lpmode(self) + + self._sfplog(LOG_WARNING_LEVEL, 'SFP does not support lpmode') + return False + + def set_lpmode(self, lpmode): + if self.get_presence() is False: + return False + + if self.sfp_type is None or self._xcvr_api is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'QSFP-DD' or self.sfp_type == 'QSFP': + return SfpOptoeBase.set_lpmode(self, lpmode) + + self._sfplog(LOG_WARNING_LEVEL, 'SFP does not support lpmode') + return False + + def get_tx_disable(self): + if self.get_presence() is False: + return False + + if self.sfp_type is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'SFP': + return self._sfp_api.get_tx_disable() + + return SfpOptoeBase.get_tx_disable(self) + + def get_tx_disable_channel(self): + if self.get_presence() is False: + return False + + if self.sfp_type is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'SFP': + return self._sfp_api.get_tx_disable_channel() + + return SfpOptoeBase.get_tx_disable_channel(self) + + def tx_disable(self, tx_disable): + if self.get_presence() is False: + return False + + if self.sfp_type is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'SFP': + return self._sfp_api.set_tx_disable(tx_disable) + + return SfpOptoeBase.tx_disable(self, tx_disable) + + def tx_disable_channel(self, channel, disable): + if self.get_presence() is False: + return False + + if self.sfp_type is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'SFP': + self._sfplog(LOG_WARNING_LEVEL, 'SFP does not support tx disable channel') + return False + + return SfpOptoeBase.tx_disable_channel(self, channel, disable) + + def set_optoe_write_max(self, write_max): + """ + This func is declared and implemented by SONiC but we're not supported + so override it as NotImplemented + """ + self._sfplog(LOG_DEBUG_LEVEL, "set_optoe_write_max NotImplemented") + + def refresh_xcvr_api(self): + """ + Updates the XcvrApi associated with this SFP + """ + self._xcvr_api = self._xcvr_api_factory.create_xcvr_api() + class_name = self._xcvr_api.__class__.__name__ + optoe_type = None + # set sfp_type + if 'CmisApi' in class_name: + self.sfp_type = 'QSFP-DD' + optoe_type = self.OPTOE_DRV_TYPE3 + elif 'Sff8472Api' in class_name: + self.sfp_type = 'SFP' + optoe_type = self.OPTOE_DRV_TYPE2 + elif ('Sff8636Api' in class_name or 'Sff8436Api' in class_name): + self.sfp_type = 'QSFP' + optoe_type = self.OPTOE_DRV_TYPE1 + # set optoe driver + if optoe_type is not None: + self._sfp_api.set_optoe_type(optoe_type) + + def _sfplog(self, log_level, msg): + if log_level >= self.log_level_config: + try: + syslog.openlog("Sfp") + if log_level == LOG_DEBUG_LEVEL: + syslog.syslog(syslog.LOG_DEBUG, msg) + elif log_level == LOG_WARNING_LEVEL: + syslog.syslog(syslog.LOG_DEBUG, msg) + elif log_level == LOG_ERROR_LEVEL: + syslog.syslog(syslog.LOG_ERR, msg) + syslog.closelog() + + except BaseException: + print(traceback.format_exc()) + + +class SfpCust(): + def __init__(self, index): + self.eeprom_path = None + self._init_config(index) + + def _init_config(self, index): + sfp_config = baseutil.get_config().get("sfps", None) + self.log_level_config = sfp_config.get("log_level", LOG_WARNING_LEVEL) + self._port_id = index + self.eeprom_retry_times = sfp_config.get("eeprom_retry_times", 0) + self.eeprom_retry_break_sec = sfp_config.get("eeprom_retry_break_sec", 0) + + def _get_eeprom_path(self): + return self.eeprom_path or None + + @abstractmethod + def get_presence(self): + pass + + def read_eeprom(self, offset, num_bytes): + try: + for i in range(self.eeprom_retry_times): + with open(self._get_eeprom_path(), mode='rb', buffering=0) as f: + f.seek(offset) + result = f.read(num_bytes) + # temporary solution for a sonic202111 bug + if len(result) < num_bytes: + result = result[::-1].zfill(num_bytes)[::-1] + if result is not None: + return bytearray(result) + time.sleep(self.eeprom_retry_break_sec) + continue + + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return None + + def write_eeprom(self, offset, num_bytes, write_buffer): + try: + for i in range(self.eeprom_retry_times): + ret = SfpOptoeBase.write_eeprom(self, offset, num_bytes, write_buffer) + if ret is False: + time.sleep(self.eeprom_retry_break_sec) + continue + break + + return ret + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return False + + @abstractmethod + def set_optoe_type(self, optoe_type): + pass + + @abstractmethod + def set_reset(self, reset): + pass + + def _convert_str_range_to_int_arr(self, range_str): + if not range_str: + return [] + + int_range_strs = range_str.split(',') + range_res = [] + for int_range_str in int_range_strs: + if '-' in int_range_str: + range_s = int(int_range_str.split('-')[0]) + range_e = int(int_range_str.split('-')[1]) + 1 + else: + range_s = int(int_range_str) + range_e = int(int_range_str) + 1 + + range_res = range_res + list(range(range_s, range_e)) + + return range_res + + def _sfplog(self, log_level, msg): + if log_level >= self.log_level_config: + try: + syslog.openlog("SfpCust") + if log_level == LOG_DEBUG_LEVEL: + syslog.syslog(syslog.LOG_DEBUG, msg) + elif log_level == LOG_WARNING_LEVEL: + syslog.syslog(syslog.LOG_DEBUG, msg) + elif log_level == LOG_ERROR_LEVEL: + syslog.syslog(syslog.LOG_ERR, msg) + syslog.closelog() + + except BaseException: + print(traceback.format_exc()) + + +class SfpV1(SfpCust): + def _init_config(self, index): + super()._init_config(index) + # init presence path + sfp_config = baseutil.get_config().get("sfps", None) + + eeprom_path_config = sfp_config.get("eeprom_path", None) + eeprom_path_key = sfp_config.get("eeprom_path_key")[self._port_id - 1] + self.eeprom_path = None if eeprom_path_config is None else eeprom_path_config % ( + eeprom_path_key, eeprom_path_key) + self._sfplog(LOG_DEBUG_LEVEL, "Done init eeprom path: %s" % self.eeprom_path) + + self.presence_cpld = sfp_config.get("presence_cpld", None) + self.presence_val_is_present = sfp_config.get("presence_val_is_present", 0) + self._sfplog(LOG_DEBUG_LEVEL, "Done init presence path") + + # init reset path + self.reset_cpld = sfp_config.get("reset_cpld", None) + self.reset_val_is_reset = sfp_config.get("reset_val_is_reset", 0) + self._sfplog(LOG_DEBUG_LEVEL, "Done init cpld path") + + # init tx_disable path + self.txdis_cpld = sfp_config.get("txdis_cpld", None) + self.txdisable_val_is_on = sfp_config.get("txdisable_val_is_on", 0) + self._sfplog(LOG_DEBUG_LEVEL, "Done init cpld tx_disable path") + + def get_presence(self): + if self.presence_cpld is None: + self._sfplog(LOG_ERROR_LEVEL, "presence_cpld is None!") + return False + try: + dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.presence_cpld) + if dev_id == -1: + return False + ret, info = platform_reg_read(0, dev_id, offset, 1) + if (ret is False + or info is None): + return False + return info[0] & (1 << offset_bit) == self.presence_val_is_present + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return False + + def get_reset_status(self): + if self.reset_cpld is None: + self._sfplog(LOG_ERROR_LEVEL, "reset_cpld is None!") + return False + try: + dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.reset_cpld) + if dev_id == -1: + return False + ret, info = platform_reg_read(0, dev_id, offset, 1) + if (ret is False + or info is None): + self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") + return False + + return (info[0] & (1 << offset_bit) == self.reset_val_is_reset) + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return False + + def get_tx_disable(self): + if self.reset_cpld is None: + self._sfplog(LOG_ERROR_LEVEL, "txdis_cpld is None!") + return None + + try: + tx_disable_list = [] + dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.txdis_cpld) + if dev_id == -1: + return False + ret, info = platform_reg_read(0, dev_id, offset, 1) + if (ret is False + or info is None): + self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") + return None + if self.txdisable_val_is_on == 1: + tx_disable_list.append(info[0] & (1 << offset_bit) != 0) + else: + tx_disable_list.append(info[0] & (1 << offset_bit) == 0) + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return None + + return tx_disable_list + + def get_tx_disable_channel(self): + tx_disable_list = [] + tx_disable_list = self.get_tx_disable() + if tx_disable_list is None: + return 0 + + tx_disabled = 0 + for i in range(len(tx_disable_list)): + if tx_disable_list[i]: + tx_disabled |= 1 << i + + return tx_disabled + + def read_eeprom(self, offset, num_bytes): + try: + for i in range(self.eeprom_retry_times): + ret, info = platform_sfp_read(self._port_id, offset, num_bytes) + if (ret is False + or info is None): + time.sleep(self.eeprom_retry_break_sec) + continue + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append(0) + for n in range(0, len(info)): + eeprom_raw[n] = info[n] + # temporary solution for a sonic202111 bug + if len(eeprom_raw) < num_bytes: + eeprom_raw = eeprom_raw[::-1].zfill(num_bytes)[::-1] + return bytearray(eeprom_raw) + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return None + + def set_optoe_type(self, optoe_type): + ret, info = platform_get_optoe_type(self._port_id) + if ret is True and info != optoe_type: + try: + ret, _ = platform_set_optoe_type(self._port_id, optoe_type) + except Exception as err: + self._sfplog(LOG_ERROR_LEVEL, "Set optoe err %s" % err) + + def set_reset(self, reset): + if self.reset_cpld is None: + self._sfplog(LOG_ERROR_LEVEL, "reset_cpld is None!") + return False + try: + val = [] + dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.reset_cpld) + if dev_id == -1: + return False + ret, info = platform_reg_read(0, dev_id, offset, 1) + if (ret is False + or info is None): + self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") + return False + + if self.reset_val_is_reset == 0: + if reset: + val.append(info[0] & (~(1 << offset_bit))) + else: + val.append(info[0] | (1 << offset_bit)) + else: + if reset: + val.append(info[0] | (1 << offset_bit)) + else: + val.append(info[0] & (~(1 << offset_bit))) + + ret, info = platform_reg_write(0, dev_id, offset, val) + if ret is False: + self._sfplog(LOG_ERROR_LEVEL, "platform_reg_write error!") + return False + + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return False + + return True + + def set_tx_disable(self, tx_disable): + if self.txdis_cpld is None: + self._sfplog(LOG_ERROR_LEVEL, "txdis_cpld is None!") + return False + try: + val = [] + dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.txdis_cpld) + if dev_id == -1: + return False + ret, info = platform_reg_read(0, dev_id, offset, 1) + if (ret is False + or info is None): + self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") + return False + + if self.txdisable_val_is_on == 0: + if tx_disable: + val.append(info[0] & (~(1 << offset_bit))) + else: + val.append(info[0] | (1 << offset_bit)) + else: + if tx_disable: + val.append(info[0] | (1 << offset_bit)) + else: + val.append(info[0] & (~(1 << offset_bit))) + + ret, info = platform_reg_write(0, dev_id, offset, val) + if ret is False: + self._sfplog(LOG_ERROR_LEVEL, "platform_reg_write error!") + return False + + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return False + + return True + + def _get_sfp_cpld_info(self, cpld_config): + dev_id = -1 + offset = -1 + offset_bit = -1 + for dev_id_temp in cpld_config["dev_id"]: + for offset_temp in cpld_config["dev_id"][dev_id_temp]["offset"]: + port_range_str = cpld_config["dev_id"][dev_id_temp]["offset"][offset_temp] + port_range_int = self._convert_str_range_to_int_arr(port_range_str) + if self._port_id in port_range_int: + dev_id = dev_id_temp + offset = offset_temp + offset_bit = port_range_int.index(self._port_id) + break + + return dev_id, offset, offset_bit + + +class SfpV2(SfpCust): + def _init_config(self, index): + super()._init_config(index) + # init eeprom path + sfp_config = baseutil.get_config().get("sfps", None) + eeprom_path_config = sfp_config.get("eeprom_path", None) + eeprom_path_key = sfp_config.get("eeprom_path_key")[self._port_id - 1] + self.eeprom_path = None if eeprom_path_config is None else eeprom_path_config % ( + eeprom_path_key, eeprom_path_key) + self._sfplog(LOG_DEBUG_LEVEL, "Done init eeprom path: %s" % self.eeprom_path) + + # init presence path + self.presence_path = None if sfp_config.get("presence_path", + None) is None else sfp_config.get("presence_path") % self._port_id + self.presence_val_is_present = sfp_config.get("presence_val_is_present", 0) + self._sfplog(LOG_DEBUG_LEVEL, "Done init presence path: %s" % self.presence_path) + + # init optoe driver path + optoe_driver_path = sfp_config.get("optoe_driver_path", None) + optoe_driver_key = sfp_config.get("optoe_driver_key")[self._port_id - 1] + self.dev_class_path = None if optoe_driver_path is None else optoe_driver_path % ( + optoe_driver_key, optoe_driver_key) + self._sfplog(LOG_DEBUG_LEVEL, "Done init optoe driver path: %s" % self.dev_class_path) + + # init reset path + self.reset_path = None if sfp_config.get( + "reset_path", + None) is None else sfp_config.get( + "reset_path", + None) % self._port_id + self.reset_val_is_reset = sfp_config.get("reset_val_is_reset", 0) + self._sfplog(LOG_DEBUG_LEVEL, "Done init reset path: %s" % self.reset_path) + + def get_presence(self): + if self.presence_path is None: + self._sfplog(LOG_ERROR_LEVEL, "presence_path is None!") + return False + try: + with open(self.presence_path, "rb") as data: + sysfs_data = data.read(1) + if sysfs_data != "": + result = int(sysfs_data, 16) + return result == self.presence_val_is_present + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return False + + def set_reset(self, reset): + return True + + def set_optoe_type(self, optoe_type): + if self.dev_class_path is None: + self._sfplog(LOG_ERROR_LEVEL, "dev_class_path is None!") + return False + try: + with open(self.dev_class_path, "r+") as dc_file: + dc_file_val = dc_file.read(1) + if int(dc_file_val) != optoe_type: + dc_str = "%s" % str(optoe_type) + dc_file.write(dc_str) + # dc_file.close() + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return False + return True diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/thermal.py new file mode 100644 index 000000000000..4632de3bc1e4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/thermal.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python3 + +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Thermals' information which are available in the platform +# +######################################################################## + + +try: + import time + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") from e + + +class Thermal(ThermalBase): + + def __init__(self, interface_obj, index): + self.temp_dict = {} + self.temperature_list = [] + self.int_case = interface_obj + self.index = index + self.update_time = 0 + self.temp_id = "TEMP" + str(index) + + def temp_dict_update(self): + local_time = time.time() + if not self.temp_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds + self.update_time = local_time + self.temp_dict = self.int_case.get_monitor_temp_by_id(self.temp_id) + + def get_name(self): + """ + Retrieves the name of the thermal + + Returns: + string: The name of the thermal + """ + self.temp_dict_update() + return self.temp_dict["Api_name"] + + def get_presence(self): + """ + Retrieves the presence of the thermal + + Returns: + bool: True if thermal is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the Thermal + + Returns: + string: Model/part number of Thermal + """ + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the Thermal + + Returns: + string: Serial number of Thermal + """ + return "N/A" + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + return "N/A" + + def get_status(self): + """ + Retrieves the operational status of the thermal + + Returns: + A boolean value, True if thermal is operating properly, + False if not + """ + self.temp_dict_update() + if (self.temp_dict["Value"] >= self.temp_dict["High"]) or (self.temp_dict["Value"] <= self.temp_dict["Low"]): + return False + + return True + + 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 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 + """ + self.temp_dict_update() + value = self.temp_dict["Value"] + if value is None or value == self.int_case.error_ret: + return "N/A" + if len(self.temperature_list) >= 1000: + del self.temperature_list[0] + self.temperature_list.append(float(value)) + return round(float(value), 1) + + 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 + """ + self.temp_dict_update() + value = self.temp_dict["High"] + if value is None or value == self.int_case.error_ret: + return "N/A" + return round(float(value), 1) + + 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 + """ + self.temp_dict_update() + value = self.temp_dict["Low"] + if value is None or value == self.int_case.error_ret: + return "N/A" + return round(float(value), 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 + """ + # not supported + return False + + 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 + """ + # not supported + 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 + """ + self.temp_dict_update() + value = self.temp_dict["Max"] + if value is None or value == self.int_case.error_ret: + return "N/A" + return round(float(value), 1) + + def get_low_critical_threshold(self): + """ + Retrieves the low critical threshold temperature of thermal + + Returns: + A float number, the low critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + self.temp_dict_update() + value = self.temp_dict["Min"] + if value is None or value == self.int_case.error_ret: + return "N/A" + return round(float(value), 1) + + def get_minimum_recorded(self): + """ + Retrieves the minimum recorded temperature of thermal + + Returns: + A float number, the minimum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + if len(self.temperature_list) == 0: + return "N/A" + return round(float(min(self.temperature_list)), 1) + + def get_maximum_recorded(self): + """ + Retrieves the maximum recorded temperature of thermal + + Returns: + A float number, the maximum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + if len(self.temperature_list) == 0: + return "N/A" + return round(float(max(self.temperature_list)), 1) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/watchdog.py new file mode 100644 index 000000000000..948337f47a9a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/watchdog.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python3 + +######################################################################## +# +# +# Abstract base class for implementing a platform-specific class with +# which to interact with a hardware watchdog module in SONiC +# +######################################################################## + +import fcntl +import os +import array + +try: + from sonic_platform_base.watchdog_base import WatchdogBase +except ImportError as error: + raise ImportError(str(error) + "- required module not found") from error + + +# ioctl constants +IO_WRITE = 0x40000000 +IO_READ = 0x80000000 +IO_READ_WRITE = 0xC0000000 +IO_SIZE_INT = 0x00040000 +IO_SIZE_40 = 0x00280000 +IO_TYPE_WATCHDOG = ord('W') << 8 + +WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG +WDR_40 = IO_READ | IO_SIZE_40 | IO_TYPE_WATCHDOG +WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG + +# Watchdog ioctl command +WDIOC_GETSUPPORT = 0 | WDR_40 +WDIOC_GETSTATUS = 1 | WDR_INT +WDIOC_GETBOOTSTATUS = 2 | WDR_INT +WDIOC_GETTEMP = 3 | WDR_INT +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 + +WDT_COMMON_ERROR = -1 +WDT_IDENTITY = "CPLD Watchdog" +WDT_SYSFS_PATH = "/sys/class/watchdog/" + +DEFAULT_TIMEOUT = 180 + + +class Watchdog(WatchdogBase): + """ + Abstract base class for interfacing with a hardware watchdog module + """ + + def __init__(self): + self.watchdog, self.wdt_main_dev_name = self._get_wdt() + self.status_path = "/sys/class/watchdog/%s/status" % self.wdt_main_dev_name + self.state_path = "/sys/class/watchdog/%s/state" % self.wdt_main_dev_name + self.timeout_path = "/sys/class/watchdog/%s/timeout" % self.wdt_main_dev_name + # Set default value + self._disable() + self.armed = False + self.timeout = self._gettimeout() + + def _is_wd_main(self, dev): + """ + Checks watchdog identity + """ + identity = self._read_file( + "{}/{}/identity".format(WDT_SYSFS_PATH, dev)) + return identity == WDT_IDENTITY + + def _get_wdt(self): + """ + Retrieves watchdog device + """ + wdt_main_dev_list = [dev for dev in os.listdir( + "/dev/") if dev.startswith("watchdog") and self._is_wd_main(dev)] + if not wdt_main_dev_list: + return None + wdt_main_dev_name = wdt_main_dev_list[0] + watchdog_device_path = "/dev/{}".format(wdt_main_dev_name) + watchdog = os.open(watchdog_device_path, os.O_RDWR) + return watchdog, wdt_main_dev_name + + def _read_file(self, file_path): + """ + Read text file + """ + try: + with open(file_path, "r") as fd: + txt = fd.read() + except IOError: + return WDT_COMMON_ERROR + return txt.strip() + + def _enable(self): + """ + Turn on the watchdog timer + """ + req = array.array('h', [WDIOS_ENABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _disable(self): + """ + Turn off the watchdog timer + """ + req = array.array('h', [WDIOS_DISABLECARD]) + 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 + """ + req = array.array('I', [0]) + fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True) + + return int(req[0]) + + 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): + """ + Arm the hardware watchdog with a timeout of seconds. + If the watchdog is currently armed, calling this function will + simply reset the timer to the provided value. If the underlying + hardware does not support the value provided in , this + method should arm the watchdog with the *next greater* available + value. + + Returns: + An integer specifying the *actual* number of seconds the watchdog + was armed with. On failure returns -1. + """ + ret = WDT_COMMON_ERROR + if seconds < 0: + return ret + + try: + if self.timeout != seconds: + self.timeout = self._settimeout(seconds) + if self.armed: + self._keepalive() + else: + self._settimeout(seconds) + self._enable() + self.armed = True + ret = self.timeout + except IOError: + pass + + return ret + + def disarm(self): + """ + Disarm the hardware watchdog + + Returns: + A boolean, True if watchdog is disarmed successfully, False if not + """ + disarmed = False + if self.is_armed(): + try: + self._disable() + self.armed = False + disarmed = True + except IOError: + pass + + return disarmed + + def is_armed(self): + """ + Retrieves the armed state of the hardware watchdog. + + Returns: + A boolean, True if watchdog is armed, False if not + """ + return self.armed + + def get_remaining_time(self): + """ + If the watchdog is armed, retrieve the number of seconds remaining on + the watchdog timer + + Returns: + An integer specifying the number of seconds remaining on thei + watchdog timer. If the watchdog is not armed, returns -1. + """ + timeleft = WDT_COMMON_ERROR + + if self.armed: + try: + timeleft = self._gettimeleft() + except IOError: + pass + + return timeleft + + def __del__(self): + """ + Close watchdog + """ + os.close(self.watchdog) diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/changelog b/platform/broadcom/sonic-platform-modules-micas/debian/changelog new file mode 100644 index 000000000000..d908208c5e37 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/changelog @@ -0,0 +1,5 @@ +sonic-micas-platform-modules (1.0) unstable; urgency=low + + * Initial release + + -- support Fri, 21 APR 2017 11:11:11 -0800 diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/compat b/platform/broadcom/sonic-platform-modules-micas/debian/compat new file mode 100644 index 000000000000..f599e28b8ab0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/compat @@ -0,0 +1 @@ +10 diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/control b/platform/broadcom/sonic-platform-modules-micas/debian/control new file mode 100644 index 000000000000..55b5837776d5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/control @@ -0,0 +1,9 @@ +Source: sonic-micas-platform-modules +Section: main +Priority: extra +Maintainer: support +Standards-Version: 3.9.3 + +Package: platform-modules-micas-m2-w6510-48v8c +Architecture: amd64 +Description: kernel modules for platform devices such as fan, led, sfp diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/copyright b/platform/broadcom/sonic-platform-modules-micas/debian/copyright new file mode 100644 index 000000000000..676cdeec726b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/copyright @@ -0,0 +1,15 @@ +Copyright (C) 2016 Microsoft, Inc + +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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.install b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.install new file mode 100644 index 000000000000..6f3e9b257f5d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.install @@ -0,0 +1 @@ +m2-w6510-48v8c/modules/sonic_platform-1.0-py3-none-any.whl /usr/share/sonic/device/x86_64-micas_m2-w6510-48v8c-r0 diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.postinst b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.postinst new file mode 100644 index 000000000000..a8132f4f65a9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.postinst @@ -0,0 +1,10 @@ +#!/bin/sh +# postinst + +kernel_version=$(uname -r) + +if [ -e /boot/System.map-${kernel_version} ]; then + depmod -a -F /boot/System.map-${kernel_version} ${kernel_version} || true +fi + +#DEBHELPER# diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/rule.mk b/platform/broadcom/sonic-platform-modules-micas/debian/rule.mk new file mode 100644 index 000000000000..f27bca1d6579 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/rule.mk @@ -0,0 +1,5 @@ +currentdir = $(shell pwd) + +MODULE_DIRS := m2-w6510-48v8c + +export MODULE_DIRS diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/rules b/platform/broadcom/sonic-platform-modules-micas/debian/rules new file mode 100755 index 000000000000..e801ef47f459 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/rules @@ -0,0 +1,92 @@ +#!/usr/bin/make -f +CC=gcc +INSTALL_MOD_DIR:=extra +KVERSION ?= $(shell uname -r) +KERNEL_SRC := /lib/modules/$(KVERSION) +MOD_SRC_DIR:= $(shell pwd) +KBUILD_OUTPUT=$(KERNEL_SRC)/build + +LIB_DIR = usr/lib/python3/dist-packages +CUSTOM_RULES_DIR := $(shell pwd)/debian + +export INSTALL_MOD_DIR top_srcdir KVERSION KERNEL_SRC CC KBUILD_OUTPUT CUSTOM_RULES_DIR + +include $(CUSTOM_RULES_DIR)/rule.mk + +#all product need common +COMPILE_DIRS = $(MODULE_DIRS) + +clean_dirs = $(MODULE_DIRS) +clean_dirs += common + +complie_clean_dirs := $(addprefix _clean_,$(clean_dirs) ) + +%: + dh $@ +build: COMPILE_WHL + @echo "build success" + +$(complie_clean_dirs): + $(MAKE) -C $(patsubst _clean_%,%,$@) clean + +common_build : + $(MAKE) -C $(MOD_SRC_DIR)/common + +$(COMPILE_DIRS): common_build + $(MAKE) -C $(MOD_SRC_DIR)/$@ + dh_testdir + dh_installdirs + cp -r $(MOD_SRC_DIR)/common/build/* debian/platform-modules-micas-$@/; \ + cp -r $(MOD_SRC_DIR)/$@/build/* debian/platform-modules-micas-$@/; \ + +COMPILE_WHL: $(COMPILE_DIRS) + @(for mod in $(MODULE_DIRS); do \ + cd $(MOD_SRC_DIR)/$${mod}; \ + cp -r $(MOD_SRC_DIR)/common/lib/plat_hal $(MOD_SRC_DIR)/$${mod}/; \ + cp -r $(MOD_SRC_DIR)/common/lib/wbutil $(MOD_SRC_DIR)/$${mod}/; \ + cp -r $(MOD_SRC_DIR)/common/lib/eepromutil $(MOD_SRC_DIR)/$${mod}/; \ + cp -r $(MOD_SRC_DIR)/common/sonic_platform $(MOD_SRC_DIR)/$${mod}/; \ + cp $(MOD_SRC_DIR)/common/script/hal_pltfm.py $(MOD_SRC_DIR)/$${mod}/hal_pltfm.py; \ + cp $(MOD_SRC_DIR)/common/script/platform_util.py $(MOD_SRC_DIR)/$${mod}/platform_util.py; \ + cp $(MOD_SRC_DIR)/common/script/platform_intf.py $(MOD_SRC_DIR)/$${mod}/platform_intf.py; \ + python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/plat_hal; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/wbutil; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/eepromutil; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/sonic_platform; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/hal_pltfm.py; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/platform_intf.py; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/platform_util.py; \ + cd $(MOD_SRC_DIR); \ + done) + +binary: binary-indep + @echo "=======================================================" + +binary-indep: + # Resuming debhelper scripts + dh_testroot + dh_install + dh_installchangelogs + dh_installdocs + dh_systemd_enable + dh_installinit + dh_systemd_start + dh_link + dh_fixperms + dh_compress + dh_strip + dh_installdeb + dh_gencontrol + dh_md5sums + dh_builddeb +override_dh_usrlocal: + +override_dh_pysupport: + +clean: $(complie_clean_dirs) + dh_testdir + dh_testroot + dh_clean + +.PHONY: build $(COMPILE_DIRS) binary binary-arch binary-indep clean diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/cpld_test_header.vme b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/cpld_test_header.vme new file mode 100644 index 0000000000000000000000000000000000000000..083fd78f3ea1919d9d3737fe0d8d0c7b8b2ce881 GIT binary patch literal 406 zcmaiu!AgWc7{^Cl9GwWZEU4QY>mrW2O9%#{v#rqDVj^@}T%AMUt^?Upr*1u1&(K43 z?FnqO2k^UmA0NNppMS~gYSXfp);#POTEzEsNrQ-{S16)+_OzzH_2yb`frh&jGzynN zocKiSc%1|*>JQ(XrjPMM;vcLbWx(?lMPV9>2xnduTlc0w*NEL#8!^N-$!~cVJr}!X zU*U-Hx_RHReT%cEsj*`cOSm-1L@17ejCweGWq851n7EkCz1hsO3AQcUK?q#pT+$Q+ zaP`9Ix{m7r0$EYyqaQexPBa5Reu@nVOwPd9@%QJs+)cP9_xx1wT$jWNHKXIBQctQq VsrNb@^ic_@K=0eZ|8`^i#~;mYW4-_Y literal 0 HcmV?d00001 diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/fpga_test_header.bin b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/fpga_test_header.bin new file mode 100644 index 000000000000..bdf9ae2139e2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/fpga_test_header.bin @@ -0,0 +1,10 @@ +fpga_test_header.bin +FILEHEADER( +DEVTYPE=0x404a +TYPE=fpga +CHAIN=3 +CHIPNAME=fpga +VERSION=v0 +FILETYPE=SPI-LOGIC-DEV +CRC=0x00000000 +) diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/Makefile b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/Makefile new file mode 100644 index 000000000000..1b84abef410a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/Makefile @@ -0,0 +1,28 @@ +PWD = $(shell pwd) +DIR_KERNEL_SRC = $(PWD)/modules/driver +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall +SUB_BUILD_DIR = $(PWD)/build +INSTALL_DIR = $(SUB_BUILD_DIR)/$(KERNEL_SRC)/$(INSTALL_MOD_DIR) +INSTALL_SCRIPT_DIR = $(SUB_BUILD_DIR)/usr/local/bin +INSTALL_LIB_DIR = $(SUB_BUILD_DIR)/usr/lib/python3/dist-packages +INSTALL_SYSFS_CFG_DIR = $(SUB_BUILD_DIR)/etc/plat_sysfs_cfg +INSTALL_UPGRADE_TEST_DIR = $(SUB_BUILD_DIR)/etc/.upgrade_test + +all: + $(MAKE) -C $(KBUILD_OUTPUT) M=$(DIR_KERNEL_SRC) modules + @if [ ! -d ${INSTALL_DIR} ]; then mkdir -p ${INSTALL_DIR} ;fi + cp -r $(DIR_KERNEL_SRC)/*.ko $(INSTALL_DIR) + @if [ ! -d ${INSTALL_SCRIPT_DIR} ]; then mkdir -p ${INSTALL_SCRIPT_DIR} ;fi + cp -r $(PWD)/config/* $(INSTALL_SCRIPT_DIR) + @if [ ! -d ${INSTALL_LIB_DIR} ]; then mkdir -p ${INSTALL_LIB_DIR} ;fi + @if [ -d $(PWD)/hal-config/ ]; then cp -r $(PWD)/hal-config/* ${INSTALL_LIB_DIR} ;fi + @if [ ! -d ${INSTALL_SYSFS_CFG_DIR} ]; then mkdir -p ${INSTALL_SYSFS_CFG_DIR} ;fi + @if [ -d $(PWD)/plat_sysfs_cfg/ ]; then cp -r $(PWD)/plat_sysfs_cfg/* ${INSTALL_SYSFS_CFG_DIR} ;fi + @if [ ! -d ${INSTALL_UPGRADE_TEST_DIR} ]; then mkdir -p ${INSTALL_UPGRADE_TEST_DIR} ;fi + @if [ -d $(PWD)/.upgrade_test/ ]; then cp -r $(PWD)/.upgrade_test/* ${INSTALL_UPGRADE_TEST_DIR} ;fi +clean: + rm -f ${DIR_KERNEL_SRC}/*.o ${DIR_KERNEL_SRC}/*.ko ${DIR_KERNEL_SRC}/*.mod.c ${DIR_KERNEL_SRC}/.*.cmd + rm -f ${DIR_KERNEL_SRC}/Module.markers ${DIR_KERNEL_SRC}/Module.symvers ${DIR_KERNEL_SRC}/modules.order + rm -rf ${DIR_KERNEL_SRC}/.tmp_versions + rm -rf $(SUB_BUILD_DIR) diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_config.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_config.py new file mode 100755 index 000000000000..587e303a62cd --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_config.py @@ -0,0 +1,1106 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- +from platform_common import * + +STARTMODULE = { + "hal_fanctrl": 1, + "hal_ledctrl": 1, + "avscontrol": 1, + "dev_monitor": 1, + "pmon_syslog": 1, + "tty_console": 1, + "macledreset": 1, + "sff_temp_polling": 1, + "generate_airflow": 1, + "reboot_cause": 1, +} + +MAC_LED_RESET = {"pcibus": 8, "slot": 0, "fn": 0, "bar": 0, "offset": 64, "reset": 0x98} + +MANUINFO_CONF = { + "bios": { + "key": "BIOS", + "head": True, + "next": "onie" + }, + "bios_vendor": { + "parent": "bios", + "key": "Vendor", + "cmd": "dmidecode -t 0 |grep Vendor", + "pattern": r".*Vendor", + "separator": ":", + "arrt_index": 1, + }, + "bios_version": { + "parent": "bios", + "key": "Version", + "cmd": "dmidecode -t 0 |grep Version", + "pattern": r".*Version", + "separator": ":", + "arrt_index": 2, + }, + "bios_date": { + "parent": "bios", + "key": "Release Date", + "cmd": "dmidecode -t 0 |grep Release", + "pattern": r".*Release Date", + "separator": ":", + "arrt_index": 3, + }, + "onie": { + "key": "ONIE", + "next": "cpu" + }, + "onie_date": { + "parent": "onie", + "key": "Build Date", + "file": "/host/machine.conf", + "pattern": r"^onie_build_date", + "separator": "=", + "arrt_index": 1, + }, + "onie_version": { + "parent": "onie", + "key": "Version", + "file": "/host/machine.conf", + "pattern": r"^onie_version", + "separator": "=", + "arrt_index": 2, + }, + + "cpu": { + "key": "CPU", + "next": "ssd" + }, + "cpu_vendor": { + "parent": "cpu", + "key": "Vendor", + "cmd": "dmidecode --type processor |grep Manufacturer", + "pattern": r".*Manufacturer", + "separator": ":", + "arrt_index": 1, + }, + "cpu_model": { + "parent": "cpu", + "key": "Device Model", + "cmd": "dmidecode --type processor | grep Version", + "pattern": r".*Version", + "separator": ":", + "arrt_index": 2, + }, + "cpu_core": { + "parent": "cpu", + "key": "Core Count", + "cmd": "dmidecode --type processor | grep \"Core Count\"", + "pattern": r".*Core Count", + "separator": ":", + "arrt_index": 3, + }, + "cpu_thread": { + "parent": "cpu", + "key": "Thread Count", + "cmd": "dmidecode --type processor | grep \"Thread Count\"", + "pattern": r".*Thread Count", + "separator": ":", + "arrt_index": 4, + }, + "ssd": { + "key": "SSD", + "next": "cpld" + }, + "ssd_model": { + "parent": "ssd", + "key": "Device Model", + "cmd": "smartctl -i /dev/sda |grep \"Device Model\"", + "pattern": r".*Device Model", + "separator": ":", + "arrt_index": 1, + }, + "ssd_fw": { + "parent": "ssd", + "key": "Firmware Version", + "cmd": "smartctl -i /dev/sda |grep \"Firmware Version\"", + "pattern": r".*Firmware Version", + "separator": ":", + "arrt_index": 2, + }, + "ssd_user_cap": { + "parent": "ssd", + "key": "User Capacity", + "cmd": "smartctl -i /dev/sda |grep \"User Capacity\"", + "pattern": r".*User Capacity", + "separator": ":", + "arrt_index": 3, + }, + + "cpld": { + "key": "CPLD", + "next": "psu" + }, + + "cpld1": { + "key": "CPLD1", + "parent": "cpld", + "arrt_index": 1, + }, + "cpld1_model": { + "key": "Device Model", + "parent": "cpld1", + "config": "LCMXO3LF-2100C-5BG256C", + "arrt_index": 1, + }, + "cpld1_vender": { + "key": "Vendor", + "parent": "cpld1", + "config": "LATTICE", + "arrt_index": 2, + }, + "cpld1_desc": { + "key": "Description", + "parent": "cpld1", + "config": "CPU_CPLD", + "arrt_index": 3, + }, + "cpld1_version": { + "key": "Firmware Version", + "parent": "cpld1", + "reg": { + "loc": "/dev/port", + "offset": 0x700, + "size": 4 + }, + "callback": "cpld_format", + "arrt_index": 4, + }, + + "cpld2": { + "key": "CPLD2", + "parent": "cpld", + "arrt_index": 2, + }, + "cpld2_model": { + "key": "Device Model", + "parent": "cpld2", + "config": "LCMXO3LF-2100C-5BG256C", + "arrt_index": 1, + }, + "cpld2_vender": { + "key": "Vendor", + "parent": "cpld2", + "config": "LATTICE", + "arrt_index": 2, + }, + "cpld2_desc": { + "key": "Description", + "parent": "cpld2", + "config": "CONNECT_CPLD", + "arrt_index": 3, + }, + "cpld2_version": { + "key": "Firmware Version", + "parent": "cpld2", + "reg": { + "loc": "/dev/port", + "offset": 0x900, + "size": 4 + }, + "callback": "cpld_format", + "arrt_index": 4, + }, + + "cpld3": { + "key": "CPLD3", + "parent": "cpld", + "arrt_index": 3, + }, + "cpld3_model": { + "key": "Device Model", + "parent": "cpld3", + "config": "LCMXO3LF-2100C-5BG256C", + "arrt_index": 1, + }, + "cpld3_vender": { + "key": "Vendor", + "parent": "cpld3", + "config": "LATTICE", + "arrt_index": 2, + }, + "cpld3_desc": { + "key": "Description", + "parent": "cpld3", + "config": "CONNECT_CPLD-FAN", + "arrt_index": 3, + }, + "cpld3_version": { + "key": "Firmware Version", + "parent": "cpld3", + "i2c": { + "bus": "2", + "loc": "0x0d", + "offset": 0, + "size": 4 + }, + "callback": "cpld_format", + "arrt_index": 4, + }, + + "cpld4": { + "key": "CPLD4", + "parent": "cpld", + "arrt_index": 4, + }, + "cpld4_model": { + "key": "Device Model", + "parent": "cpld4", + "config": "LCMXO3LF-2100C-5BG256C", + "arrt_index": 1, + }, + "cpld4_vender": { + "key": "Vendor", + "parent": "cpld4", + "config": "LATTICE", + "arrt_index": 2, + }, + "cpld4_desc": { + "key": "Description", + "parent": "cpld4", + "config": "MAC_CPLD1", + "arrt_index": 3, + }, + "cpld4_version": { + "key": "Firmware Version", + "parent": "cpld4", + "i2c": { + "bus": "8", + "loc": "0x30", + "offset": 0, + "size": 4 + }, + "callback": "cpld_format", + "arrt_index": 4, + }, + + "cpld5": { + "key": "CPLD5", + "parent": "cpld", + "arrt_index": 5, + }, + "cpld5_model": { + "key": "Device Model", + "parent": "cpld5", + "config": "LCMXO3LF-2100C-5BG256C", + "arrt_index": 1, + }, + "cpld5_vender": { + "key": "Vendor", + "parent": "cpld5", + "config": "LATTICE", + "arrt_index": 2, + }, + "cpld5_desc": { + "key": "Description", + "parent": "cpld5", + "config": "MAC_CPLD2", + "arrt_index": 3, + }, + "cpld5_version": { + "key": "Firmware Version", + "parent": "cpld5", + "i2c": { + "bus": "8", + "loc": "0x31", + "offset": 0, + "size": 4 + }, + "callback": "cpld_format", + "arrt_index": 4, + }, + + "psu": { + "key": "PSU", + "next": "fan" + }, + + "psu1": { + "parent": "psu", + "key": "PSU1", + "arrt_index": 1, + }, + "psu1_hw_version": { + "key": "Hardware Version", + "parent": "psu1", + "extra": { + "funcname": "getPsu", + "id": "psu1", + "key": "hw_version" + }, + "arrt_index": 1, + }, + "psu1_fw_version": { + "key": "Firmware Version", + "parent": "psu1", + "config": "NA", + "arrt_index": 2, + }, + + "psu2": { + "parent": "psu", + "key": "PSU2", + "arrt_index": 2, + }, + "psu2_hw_version": { + "key": "Hardware Version", + "parent": "psu2", + "extra": { + "funcname": "getPsu", + "id": "psu2", + "key": "hw_version" + }, + "arrt_index": 1, + }, + "psu2_fw_version": { + "key": "Firmware Version", + "parent": "psu2", + "config": "NA", + "arrt_index": 2, + }, + + "fan": { + "key": "FAN", + "next": "i210" + }, + + "fan1": { + "key": "FAN1", + "parent": "fan", + "arrt_index": 1, + }, + "fan1_hw_version": { + "key": "Hardware Version", + "parent": "fan1", + "extra": { + "funcname": "checkFan", + "id": "fan1", + "key": "hw_version" + }, + "arrt_index": 1, + }, + "fan1_fw_version": { + "key": "Firmware Version", + "parent": "fan1", + "config": "NA", + "arrt_index": 2, + }, + + "fan2": { + "key": "FAN2", + "parent": "fan", + "arrt_index": 2, + }, + "fan2_hw_version": { + "key": "Hardware Version", + "parent": "fan2", + "extra": { + "funcname": "checkFan", + "id": "fan2", + "key": "hw_version" + }, + "arrt_index": 1, + }, + "fan2_fw_version": { + "key": "Firmware Version", + "parent": "fan2", + "config": "NA", + "arrt_index": 2, + }, + + "fan3": { + "key": "FAN3", + "parent": "fan", + "arrt_index": 3, + }, + "fan3_hw_version": { + "key": "Hardware Version", + "parent": "fan3", + "extra": { + "funcname": "checkFan", + "id": "fan3", + "key": "hw_version" + }, + "arrt_index": 1, + }, + "fan3_fw_version": { + "key": "Firmware Version", + "parent": "fan3", + "config": "NA", + "arrt_index": 2, + }, + + "fan4": { + "key": "FAN4", + "parent": "fan", + "arrt_index": 4, + }, + "fan4_hw_version": { + "key": "Hardware Version", + "parent": "fan4", + "extra": { + "funcname": "checkFan", + "id": "fan4", + "key": "hw_version" + }, + "arrt_index": 1, + }, + "fan4_fw_version": { + "key": "Firmware Version", + "parent": "fan4", + "config": "NA", + "arrt_index": 2, + }, + + "i210": { + "key": "NIC", + "next": "fpga" + }, + "i210_model": { + "parent": "i210", + "config": "NA", + "key": "Device Model", + "arrt_index": 1, + }, + "i210_vendor": { + "parent": "i210", + "config": "INTEL", + "key": "Vendor", + "arrt_index": 2, + }, + "i210_version": { + "parent": "i210", + "cmd": "ethtool -i eth0", + "pattern": r"firmware-version", + "separator": ":", + "key": "Firmware Version", + "arrt_index": 3, + }, + + "fpga": { + "key": "FPGA", + "next": "asic" + }, + "fpga_model": { + "parent": "fpga", + "config": "XC7A15T-2FGG484C", + "key": "Device Model", + "arrt_index": 1, + }, + "fpga_vendor": { + "parent": "fpga", + "config": "XILINX", + "key": "Vendor", + "arrt_index": 2, + }, + "fpga_desc": { + "parent": "fpga", + "config": "NA", + "key": "Description", + "arrt_index": 3, + }, + "fpga_hw_version": { + "parent": "fpga", + "config": "NA", + "key": "Hardware Version", + "arrt_index": 4, + }, + "fpga_fw_version": { + "parent": "fpga", + "pci": { + "bus": 8, + "slot": 0, + "fn": 0, + "bar": 0, + "offset": 0 + }, + "key": "Firmware Version", + "arrt_index": 5, + }, + "fpga_date": { + "parent": "fpga", + "pci": { + "bus": 8, + "slot": 0, + "fn": 0, + "bar": 0, + "offset": 4 + }, + "key": "Build Date", + "arrt_index": 6, + }, + "asic": { + "key": "ASIC", + }, + "sdk_model": { + "parent": "asic", + "cmd": "bcmcmd -t 1 att", + "pattern": r"^Attach", + "regular": r"(?<=\()[^)]*(?=\))", + "key": "Device Model", + "arrt_index": 1, + }, + "sdk_version": { + "parent": "asic", + "cmd": "bcmcmd -t 1 version | grep Release", + "pattern": r".*Release", + "separator": ":", + "key": "SDK Version", + "arrt_index": 2, + }, + "pci_version": { + "parent": "asic", + "cmd": "bcmcmd -t 1 \"pciephy fw version\" |grep \"PCIe FW version\"", + "pattern": r".*PCIe FW version", + "separator": ":", + "key": "PCIe Firmware Version", + "arrt_index": 3, + }, +} + +PMON_SYSLOG_STATUS = { + "polling_time": 3, + "sffs": { + "present": {"path": ["/sys/wb_plat/sff/*/present"], "ABSENT": 0}, + "nochangedmsgflag": 0, + "nochangedmsgtime": 60, + "noprintfirsttimeflag": 1, + "alias": { + "sff1": "Ethernet1", + "sff2": "Ethernet2", + "sff3": "Ethernet3", + "sff4": "Ethernet4", + "sff5": "Ethernet5", + "sff6": "Ethernet6", + "sff7": "Ethernet7", + "sff8": "Ethernet8", + "sff9": "Ethernet9", + "sff10": "Ethernet10", + "sff11": "Ethernet11", + "sff12": "Ethernet12", + "sff13": "Ethernet13", + "sff14": "Ethernet14", + "sff15": "Ethernet15", + "sff16": "Ethernet16", + "sff17": "Ethernet17", + "sff18": "Ethernet18", + "sff19": "Ethernet19", + "sff20": "Ethernet20", + "sff21": "Ethernet21", + "sff22": "Ethernet22", + "sff23": "Ethernet23", + "sff24": "Ethernet24", + "sff25": "Ethernet25", + "sff26": "Ethernet26", + "sff27": "Ethernet27", + "sff28": "Ethernet28", + "sff29": "Ethernet29", + "sff30": "Ethernet30", + "sff31": "Ethernet31", + "sff32": "Ethernet32", + "sff33": "Ethernet33", + "sff34": "Ethernet34", + "sff35": "Ethernet35", + "sff36": "Ethernet36", + "sff37": "Ethernet37", + "sff38": "Ethernet38", + "sff39": "Ethernet39", + "sff40": "Ethernet40", + "sff41": "Ethernet41", + "sff42": "Ethernet42", + "sff43": "Ethernet43", + "sff44": "Ethernet44", + "sff45": "Ethernet45", + "sff46": "Ethernet46", + "sff47": "Ethernet47", + "sff48": "Ethernet48", + "sff49": "Ethernet49", + "sff50": "Ethernet50", + "sff51": "Ethernet51", + "sff52": "Ethernet52", + "sff53": "Ethernet53", + "sff54": "Ethernet54", + "sff55": "Ethernet55", + "sff56": "Ethernet56", + } + }, + "fans": { + "present": {"path": ["/sys/wb_plat/fan/*/present"], "ABSENT": 0}, + "status": [ + {"path": "/sys/wb_plat/fan/%s/motor0/status", 'okval': 1}, + {"path": "/sys/wb_plat/fan/%s/motor1/status", 'okval': 1}, + ], + "nochangedmsgflag": 1, + "nochangedmsgtime": 60, + "noprintfirsttimeflag": 0, + "alias": { + "fan1": "FAN1", + "fan2": "FAN2", + "fan3": "FAN3", + "fan4": "FAN4" + } + }, + "psus": { + "present": {"path": ["/sys/wb_plat/psu/*/present"], "ABSENT": 0}, + "status": [ + {"path": "/sys/wb_plat/psu/%s/output", "okval": 1}, + {"path": "/sys/wb_plat/psu/%s/alert", "okval": 0}, + ], + "nochangedmsgflag": 1, + "nochangedmsgtime": 60, + "noprintfirsttimeflag": 0, + "alias": { + "psu1": "PSU1", + "psu2": "PSU2" + } + } +} + +##################### MAC Voltage adjust#################################### +MAC_DEFAULT_PARAM = [ + { + "name": "mac_core", # AVS name + "type": 1, # 1: used default value, if rov value not in range. 0: do nothing, if rov value not in range + "default": 0x74, # default value, if rov value not in range + "sdkreg": "TOP_AVS_SEL_REG", # SDK register name + "sdktype": 0, # 0: No shift operation required, 1: shift operation required + "macregloc": 24, # Shift right 24 bits + "mask": 0xff, # Use with macregloc + "rov_source": 1, # 0:get rov value from cpld, 1: get rov value from SDK + "cpld_avs": {"bus": 6, "loc": 0x0d, "offset": 0xc3, "gettype": "i2c"}, + "set_avs": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/avs0_vout", + "gettype": "sysfs", "formula": "int((%f)*1000000)" + }, + "mac_avs_param": { + 0x08: 0.888, + 0x72: 0.900, + 0x73: 0.894, + 0x74: 0.888, + 0x75: 0.882, + 0x76: 0.875, + 0x77: 0.869, + 0x78: 0.863, + 0x79: 0.857, + 0x7a: 0.850, + 0x7b: 0.844, + 0x7c: 0.838, + 0x7d: 0.832, + 0x7e: 0.825, + 0x7f: 0.819, + 0x80: 0.813, + 0x81: 0.807, + 0x82: 0.800, + 0x83: 0.794, + 0x84: 0.788, + 0x85: 0.782, + 0x86: 0.775, + 0x87: 0.769, + 0x88: 0.763, + 0x89: 0.757, + 0x8A: 0.750 + } + } +] + +BLACKLIST_DRIVERS = [ + {"name": "i2c_i801", "delay": 0}, +] + +DRIVERLISTS = [ + {"name": "wb_i2c_i801", "delay": 0}, + {"name": "wb_gpio_d1500", "delay": 0}, + {"name": "i2c_dev", "delay": 0}, + {"name": "wb_i2c_algo_bit", "delay": 0}, + {"name": "wb_i2c_gpio", "delay": 0}, + {"name": "i2c_mux", "delay": 0}, + {"name": "wb_gpio_device", "delay": 0}, + {"name": "wb_i2c_gpio_device gpio_sda=17 gpio_scl=1 gpio_udelay=2", "delay": 0}, + {"name": "platform_common dfd_my_type=0x404a", "delay": 0}, + {"name": "wb_lpc_drv", "delay": 0}, + {"name": "wb_lpc_drv_device", "delay": 0}, + {"name": "wb_io_dev", "delay": 0}, + {"name": "wb_io_dev_device", "delay": 0}, + {"name": "wb_fpga_pcie", "delay": 0}, + {"name": "wb_pcie_dev", "delay": 0}, + {"name": "wb_pcie_dev_device", "delay": 0}, + {"name": "wb_i2c_dev", "delay": 0}, + {"name": "wb_i2c_ocores", "delay": 0}, + {"name": "wb_i2c_ocores_device", "delay": 0}, + {"name": "wb_i2c_mux_pca9641", "delay": 0}, + {"name": "wb_i2c_mux_pca954x", "delay": 0}, + {"name": "wb_i2c_mux_pca954x_device", "delay": 0}, + {"name": "wb_i2c_dev_device", "delay": 0}, + {"name": "wb_lm75", "delay": 0}, + {"name": "wb_optoe", "delay": 0}, + {"name": "wb_at24", "delay": 0}, + {"name": "wb_mac_bsc", "delay": 0}, + {"name": "wb_pmbus_core", "delay": 0}, + {"name": "wb_isl68137", "delay": 0}, + {"name": "wb_csu550", "delay": 0}, + {"name": "wb_ina3221", "delay": 0}, + {"name": "wb_tps53622", "delay": 0}, + {"name": "plat_dfd", "delay": 0}, + {"name": "plat_switch", "delay": 0}, + {"name": "plat_fan", "delay": 0}, + {"name": "plat_psu", "delay": 0}, + {"name": "plat_sff", "delay": 0}, +] + +DEVICE = [ + {"name": "wb_24c02", "bus": 0, "loc": 0x56}, + {"name": "wb_mac_bsc_td3", "bus": 3, "loc": 0x44}, + # fan + {"name": "wb_24c02", "bus": 16, "loc": 0x50}, + {"name": "wb_24c02", "bus": 17, "loc": 0x50}, + {"name": "wb_24c02", "bus": 18, "loc": 0x50}, + {"name": "wb_24c02", "bus": 19, "loc": 0x50}, + # psu + {"name": "wb_24c02", "bus": 24, "loc": 0x50}, + {"name": "wb_dps550", "bus": 24, "loc": 0x58}, + {"name": "wb_24c02", "bus": 25, "loc": 0x50}, + {"name": "wb_dps550", "bus": 25, "loc": 0x58}, + # temp + {"name": "wb_lm75", "bus": 3, "loc": 0x48}, + {"name": "wb_lm75", "bus": 3, "loc": 0x49}, + {"name": "wb_lm75", "bus": 3, "loc": 0x4a}, + {"name": "wb_lm75", "bus": 3, "loc": 0x4b}, + {"name": "wb_lm75", "bus": 3, "loc": 0x4c}, + # dcdc + {"name": "wb_ina3221", "bus": 7, "loc": 0x40}, + {"name": "wb_ina3221", "bus": 7, "loc": 0x41}, + {"name": "wb_ina3221", "bus": 7, "loc": 0x42}, + {"name": "wb_ina3221", "bus": 7, "loc": 0x43}, + {"name": "wb_tps53622", "bus": 7, "loc": 0x60}, + {"name": "wb_tps53622", "bus": 7, "loc": 0x6c}, + {"name": "wb_isl68127", "bus": 7, "loc": 0x64}, +] + +OPTOE = [ + {"name": "wb_optoe2", "startbus": 32, "endbus": 79}, + {"name": "wb_optoe1", "startbus": 80, "endbus": 87}, +] + +DEV_MONITOR_PARAM = { + "polling_time": 10, + "psus": [ + { + "name": "psu1", + "present": {"gettype": "i2c", "bus": 6, "loc": 0x0d, "offset": 0x51, "presentbit": 0, "okval": 0}, + "device": [ + {"id": "psu1pmbus", "name": "wb_dps550", "bus": 24, "loc": 0x58, "attr": "hwmon"}, + {"id": "psu1frue2", "name": "wb_24c02", "bus": 24, "loc": 0x50, "attr": "eeprom"}, + ], + }, + { + "name": "psu2", + "present": {"gettype": "i2c", "bus": 6, "loc": 0x0d, "offset": 0x51, "presentbit": 4, "okval": 0}, + "device": [ + {"id": "psu2pmbus", "name": "wb_dps550", "bus": 25, "loc": 0x58, "attr": "hwmon"}, + {"id": "psu2frue2", "name": "wb_24c02", "bus": 25, "loc": 0x50, "attr": "eeprom"}, + ], + }, + ], + "fans": [ + { + "name": "fan1", + "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 0, "okval": 0}, + "device": [ + {"id": "fan1frue2", "name": "24c02", "bus": 16, "loc": 0x50, "attr": "eeprom"}, + ], + }, + { + "name": "fan2", + "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 1, "okval": 0}, + "device": [ + {"id": "fan2frue2", "name": "24c02", "bus": 17, "loc": 0x50, "attr": "eeprom"}, + ], + }, + { + "name": "fan3", + "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 2, "okval": 0}, + "device": [ + {"id": "fan3frue2", "name": "24c02", "bus": 18, "loc": 0x50, "attr": "eeprom"}, + ], + }, + { + "name": "fan4", + "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 3, "okval": 0}, + "device": [ + {"id": "fan4frue2", "name": "24c02", "bus": 19, "loc": 0x50, "attr": "eeprom"}, + ], + }, + ], + "others": [ + { + "name": "eeprom", + "device": [ + {"id": "eeprom_1", "name": "wb_24c02", "bus": 0, "loc": 0x56, "attr": "eeprom"}, + ], + }, + { + "name": "lm75", + "device": [ + {"id": "lm75_1", "name": "wb_lm75", "bus": 3, "loc": 0x48, "attr": "hwmon"}, + {"id": "lm75_2", "name": "wb_lm75", "bus": 3, "loc": 0x49, "attr": "hwmon"}, + {"id": "lm75_3", "name": "wb_lm75", "bus": 3, "loc": 0x4a, "attr": "hwmon"}, + {"id": "lm75_4", "name": "wb_lm75", "bus": 3, "loc": 0x4b, "attr": "hwmon"}, + {"id": "lm75_5", "name": "wb_lm75", "bus": 3, "loc": 0x4c, "attr": "hwmon"}, + ], + }, + { + "name": "mac_bsc", + "device": [ + {"id": "mac_bsc_1", "name": "wb_mac_bsc_td3", "bus": 3, "loc": 0x44, "attr": "hwmon"}, + ], + }, + { + "name": "ina3221", + "device": [ + {"id": "ina3221_1", "name": "wb_ina3221", "bus": 7, "loc": 0x40, "attr": "hwmon"}, + {"id": "ina3221_2", "name": "wb_ina3221", "bus": 7, "loc": 0x41, "attr": "hwmon"}, + {"id": "ina3221_3", "name": "wb_ina3221", "bus": 7, "loc": 0x42, "attr": "hwmon"}, + {"id": "ina3221_4", "name": "wb_ina3221", "bus": 7, "loc": 0x43, "attr": "hwmon"}, + ], + }, + { + "name": "tps53622", + "device": [ + {"id": "tps53622_1", "name": "wb_tps53622", "bus": 7, "loc": 0x60, "attr": "hwmon"}, + {"id": "tps53622_2", "name": "wb_tps53622", "bus": 7, "loc": 0x6c, "attr": "hwmon"}, + ], + }, + { + "name": "isl68127", + "device": [ + {"id": "isl68127_1", "name": "wb_isl68127", "bus": 7, "loc": 0x64, "attr": "hwmon"}, + ], + } + ], +} + +INIT_PARAM_PRE = [ + {"loc": "7-0064/hwmon/hwmon*/avs0_vout_max", "value": "900000"}, + {"loc": "7-0064/hwmon/hwmon*/avs0_vout_min", "value": "750000"}, +] +INIT_COMMAND_PRE = [ + "i2cset -y -f 6 0x0d 0x91 0x48", + "i2cset -y -f 6 0x0d 0x92 0x01", # MAC_PWR_EN + "i2cset -y -f 6 0x0d 0x94 0x01", # SFF_PWR_EN + "i2cset -y -f 6 0x0d 0xbf 0x01", # enbale tty_console monitor +] + +INIT_PARAM = [] + +INIT_COMMAND = [ + "i2cset -y -f 8 0x30 0x60 0x00", # enable txdis[1~8] + "i2cset -y -f 8 0x30 0x61 0x00", # enable txdis[9~16] + "i2cset -y -f 8 0x30 0x62 0x00", # enable txdis[17~24] + "i2cset -y -f 8 0x31 0x60 0x00", # enable txdis[24~32] + "i2cset -y -f 8 0x31 0x61 0x00", # enable txdis[33~40] + "i2cset -y -f 8 0x31 0x62 0x00", # enable txdis[41~48] +] + +REBOOT_CAUSE_PARA = { + "reboot_cause_list": [ + { + "name": "otp_switch_reboot", + "monitor_point": {"gettype": "file_exist", "judge_file": "/etc/.otp_switch_reboot_flag", "okval": True}, + "record": [ + {"record_type": "file", "mode": "cover", "log": "Thermal Overload: ASIC, ", + "path": "/etc/sonic/.reboot/.previous-reboot-cause.txt"}, + {"record_type": "file", "mode": "add", "log": "Thermal Overload: ASIC, ", + "path": "/etc/sonic/.reboot/.history-reboot-cause.txt", "file_max_size": 1 * 1024 * 1024} + ], + "finish_operation": [ + {"gettype": "cmd", "cmd": "rm -rf /etc/.otp_switch_reboot_flag"}, + ] + }, + { + "name": "otp_other_reboot", + "monitor_point": {"gettype": "file_exist", "judge_file": "/etc/.otp_other_reboot_flag", "okval": True}, + "record": [ + {"record_type": "file", "mode": "cover", "log": "Thermal Overload: Other, ", + "path": "/etc/sonic/.reboot/.previous-reboot-cause.txt"}, + {"record_type": "file", "mode": "add", "log": "Thermal Overload: Other, ", + "path": "/etc/sonic/.reboot/.history-reboot-cause.txt", "file_max_size": 1 * 1024 * 1024} + ], + "finish_operation": [ + {"gettype": "cmd", "cmd": "rm -rf /etc/.otp_other_reboot_flag"}, + ] + }, + ], + "other_reboot_cause_record": [ + {"record_type": "file", "mode": "cover", "log": "Other, ", "path": "/etc/sonic/.reboot/.previous-reboot-cause.txt"}, + {"record_type": "file", "mode": "add", "log": "Other, ", "path": "/etc/sonic/.reboot/.history-reboot-cause.txt"} + ], +} + +UPGRADE_SUMMARY = { + "devtype": 0x404a, + + "slot0": { + "subtype": 0, + "VME": { + "chain1": { + "name": "VME_CPLD", + "is_support_warm_upg": 0, + }, + }, + + "SPI-LOGIC-DEV": { + "chain3": { + "name": "FPGA", + "is_support_warm_upg": 0, + }, + }, + + "MTD": { + "chain2": { + "name": "BIOS", + "is_support_warm_upg": 0, + "filesizecheck": 10240, # bios check file size, Unit: K + "init_cmd": [ + {"io_addr": 0x722, "value": 0x02, "gettype": "io"}, + {"cmd": "modprobe mtd", "gettype": "cmd"}, + {"cmd": "modprobe spi_nor", "gettype": "cmd"}, + {"cmd": "modprobe ofpart", "gettype": "cmd"}, + {"cmd": "modprobe intel_spi writeable=1", "gettype": "cmd"}, + {"cmd": "modprobe intel_spi_platform writeable=1", "gettype": "cmd"}, + ], + "finish_cmd": [ + {"cmd": "rmmod intel_spi_platform", "gettype": "cmd"}, + {"cmd": "rmmod intel_spi", "gettype": "cmd"}, + {"cmd": "rmmod ofpart", "gettype": "cmd"}, + {"cmd": "rmmod spi_nor", "gettype": "cmd"}, + {"cmd": "rmmod mtd", "gettype": "cmd"}, + ], + }, + }, + + "TEST": { + "cpld": [ + {"chain": 1, "file": "/etc/.upgrade_test/cpld_test_header.vme", "display_name": "CPLD"}, + ], + "fpga": [ + { + "chain": 3, + "file": "/etc/.upgrade_test/fpga_test_header.bin", + "display_name": "FPGA", + }, + ], + }, + }, + + "BMC": { + "name": "BMC", + "init_cmd": [ + ], + "finish_cmd": [], + }, +} + + +PLATFORM_E2_CONF = { + "fan": [ + { + "name": "fan1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/16-0050/eeprom", + "e2_decode": [ + { + "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" + }, + { + "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" + }, + ], + }, + { + "name": "fan2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/17-0050/eeprom", + "e2_decode": [ + { + "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" + }, + { + "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" + }, + ], + }, + { + "name": "fan3", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/18-0050/eeprom", + "e2_decode": [ + { + "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" + }, + { + "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" + }, + ], + }, + { + "name": "fan4", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/19-0050/eeprom", + "e2_decode": [ + { + "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" + }, + { + "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" + }, + ], + }, + ], + "psu": [ + {"name": "psu1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/24-0050/eeprom"}, + {"name": "psu2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/25-0050/eeprom"}, + ], + "syseeprom": [ + {"name": "syseeprom", "e2_type": "onie_tlv", "e2_path": "/sys/bus/i2c/devices/0-0056/eeprom"}, + ], +} + +AIR_FLOW_CONF = { + "psu_fan_airflow": { + "intake": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3', 'U1D-D10800-DRB'], + "exhaust": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'] + }, + + "fanairflow": { + "intake": ['M1HFAN III-F'], + "exhaust": ['M1HFAN III-R'] + }, + + "fans": [ + { + "name": "FAN1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/16-0050/eeprom", + "area": "productInfoArea", "field": "productName", "decode": "fanairflow" + }, + { + "name": "FAN2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/17-0050/eeprom", + "area": "productInfoArea", "field": "productName", "decode": "fanairflow" + }, + { + "name": "FAN3", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/18-0050/eeprom", + "area": "productInfoArea", "field": "productName", "decode": "fanairflow" + }, + { + "name": "FAN4", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/19-0050/eeprom", + "area": "productInfoArea", "field": "productName", "decode": "fanairflow" + } + ], + + "psus": [ + { + "name": "PSU1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/24-0050/eeprom", + "area": "productInfoArea", "field": "productPartModelName", "decode": "psu_fan_airflow" + }, + { + "name": "PSU2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/25-0050/eeprom", + "area": "productInfoArea", "field": "productPartModelName", "decode": "psu_fan_airflow" + } + ] +} diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_port_config.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_port_config.py new file mode 100755 index 000000000000..26f92a77a020 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_port_config.py @@ -0,0 +1,7 @@ +#!/usr/bin/python3 +# -*- coding: UTF-8 -*- + +PLATFORM_INTF_OPTOE = { + "port_num": 56, + "optoe_start_bus": 32, +} diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_device.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_device.py new file mode 100755 index 000000000000..c1eb46247086 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_device.py @@ -0,0 +1,1371 @@ +#!/usr/bin/python3 + +psu_fan_airflow = { + "intake": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3', 'U1D-D10800-DRB'], + "exhaust": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'] +} + +fanairflow = { + "intake": ['M1HFAN III-F'], + "exhaust": ['M1HFAN III-R'], +} + +psu_display_name = { + "PA550II-F": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3'], + "PA550II-R": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'], + "PD800I-F": ['U1D-D10800-DRB'] +} + +psutypedecode = { + 0x00: 'N/A', + 0x01: 'AC', + 0x02: 'DC', +} + + +class Unit: + Temperature = "C" + Voltage = "V" + Current = "A" + Power = "W" + Speed = "RPM" + + +PSU_NOT_PRESENT_PWM = 100 + + +class threshold: + PSU_TEMP_MIN = -20 * 1000 + PSU_TEMP_MAX = 60 * 1000 + + PSU_FAN_SPEED_MIN = 2000 + PSU_FAN_SPEED_MAX = 18000 + + PSU_OUTPUT_VOLTAGE_MIN = 11 * 1000 + PSU_OUTPUT_VOLTAGE_MAX = 14 * 1000 + + PSU_AC_INPUT_VOLTAGE_MIN = 200 * 1000 + PSU_AC_INPUT_VOLTAGE_MAX = 240 * 1000 + + PSU_DC_INPUT_VOLTAGE_MIN = 190 * 1000 + PSU_DC_INPUT_VOLTAGE_MAX = 290 * 1000 + + ERR_VALUE = -9999999 + + PSU_OUTPUT_POWER_MIN = 10 * 1000 * 1000 + PSU_OUTPUT_POWER_MAX = 560 * 1000 * 1000 + + PSU_INPUT_POWER_MIN = 10 * 1000 * 1000 + PSU_INPUT_POWER_MAX = 625 * 1000 * 1000 + + PSU_OUTPUT_CURRENT_MIN = 1 * 1000 + PSU_OUTPUT_CURRENT_MAX = 45 * 1000 + + PSU_INPUT_CURRENT_MIN = 0 * 1000 + PSU_INPUT_CURRENT_MAX = 7 * 1000 + + FRONT_FAN_SPEED_MAX = 24000 + REAR_FAN_SPEED_MAX = 22500 + FAN_SPEED_MIN = 5000 + + + ASPOWER_DC_PSU_TEMP_MIN = -10 * 1000 + ASPOWER_DC_PSU_TEMP_MAX = 55 * 1000 + + ASPOWER_DC_PSU_FAN_SPEED_MIN = 800 + ASPOWER_DC_PSU_FAN_SPEED_MAX = 24000 + + ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN = 11.4 * 1000 + ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX = 12.6 * 1000 + + ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN = 36 * 1000 + ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX = 72 * 1000 + + ASPOWER_DC_ERR_VALUE = -9999999 + + ASPOWER_DC_PSU_OUTPUT_POWER_MIN = 5 * 1000 * 1000 + ASPOWER_DC_PSU_OUTPUT_POWER_MAX = 800 * 1000 * 1000 + + ASPOWER_DC_PSU_INPUT_POWER_MIN = 5 * 1000 * 1000 + ASPOWER_DC_PSU_INPUT_POWER_MAX = 880 * 1000 * 1000 + + ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN = 0.5 * 1000 + ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX = 66 * 1000 + + ASPOWER_DC_PSU_INPUT_CURRENT_MIN = 1 * 1000 + ASPOWER_DC_PSU_INPUT_CURRENT_MAX = 28 * 1000 + + +class Description: + CPLD = "Used for managing IO modules, SFP+ modules and system LEDs" + BIOS = "Performs initialization of hardware components during booting" + FPGA = "Platform management controller for on-board temperature monitoring, in-chassis power" + + +devices = { + "onie_e2": [ + { + "name": "ONIE_E2", + "e2loc": {"loc": "/sys/bus/i2c/devices/0-0056/eeprom", "way": "sysfs"}, + "airflow": "intake" + }, + ], + "psus": [ + { + "e2loc": {"loc": "/sys/bus/i2c/devices/24-0050/eeprom", "way": "sysfs"}, + "pmbusloc": {"bus": 24, "addr": 0x58, "way": "i2c"}, + "present": {"loc": "/sys/wb_plat/psu/psu1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "name": "PSU1", + "get_threshold_by_model": 1, + "psu_display_name": psu_display_name, + "airflow": psu_fan_airflow, + "TempStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, + "other": threshold.PSU_TEMP_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, + "other": threshold.PSU_TEMP_MAX, + }, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "FanStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, + "FanSpeed": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, + "other": threshold.PSU_FAN_SPEED_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, + "other": threshold.PSU_FAN_SPEED_MAX, + }, + "Unit": Unit.Speed + }, + "psu_fan_tolerance": 40, + "InputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, + "InputsType": {"bus": 24, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, + "InputsVoltage": { + 'AC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, + "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + + }, + 'DC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + 'other': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.ERR_VALUE, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.ERR_VALUE, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + } + }, + "InputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, + "other": threshold.PSU_INPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, + "other": threshold.PSU_INPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "InputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, + "other": threshold.PSU_INPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, + "other": threshold.PSU_INPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + "OutputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, + "OutputsVoltage": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, + "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, + "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + "OutputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, + "other": threshold.PSU_OUTPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, + "other": threshold.PSU_OUTPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "OutputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, + "other": threshold.PSU_OUTPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, + "other": threshold.PSU_OUTPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + }, + { + "e2loc": {"loc": "/sys/bus/i2c/devices/25-0050/eeprom", "way": "sysfs"}, + "pmbusloc": {"bus": 25, "addr": 0x58, "way": "i2c"}, + "present": {"loc": "/sys/wb_plat/psu/psu2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "name": "PSU2", + "get_threshold_by_model": 1, + "psu_display_name": psu_display_name, + "airflow": psu_fan_airflow, + "TempStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, + "other": threshold.PSU_TEMP_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, + "other": threshold.PSU_TEMP_MAX, + }, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "FanStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, + "FanSpeed": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, + "other": threshold.PSU_FAN_SPEED_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, + "other": threshold.PSU_FAN_SPEED_MAX, + }, + "Unit": Unit.Speed + }, + "psu_fan_tolerance": 40, + "InputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, + "InputsType": {"bus": 25, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, + "InputsVoltage": { + 'AC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, + "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + + }, + 'DC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + 'other': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.ERR_VALUE, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.ERR_VALUE, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + } + }, + "InputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, + "other": threshold.PSU_INPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, + "other": threshold.PSU_INPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "InputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, + "other": threshold.PSU_INPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, + "other": threshold.PSU_INPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + "OutputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, + "OutputsVoltage": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, + "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, + "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + "OutputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, + "other": threshold.PSU_OUTPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, + "other": threshold.PSU_OUTPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "OutputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, + "other": threshold.PSU_OUTPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, + "other": threshold.PSU_OUTPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + } + ], + "temps": [ + { + "name": "SWITCH_TEMP", + "temp_id": "TEMP1", + "api_name": "ASIC_TEMP", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-0044/hwmon/hwmon*/temp99_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 105000, + "Max": 110000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "CPU_TEMP", + "temp_id": "TEMP2", + "Temperature": { + "value": {"loc": "/sys/bus/platform/devices/coretemp.0/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -15000, + "Low": 0, + "High": 100000, + "Max": 102000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "INLET_TEMP", + "temp_id": "TEMP3", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-0048/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 55000, + "Max": 60000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "fix_value": { + "fix_type": "config", + "addend": -3, + } + }, + { + "name": "OUTLET_TEMP", + "temp_id": "TEMP4", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-004c/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 75000, + "Max": 80000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "BOARD_TEMP", + "temp_id": "TEMP5", + "api_name": "MAC_OUT_TEMP", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-004a/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 75000, + "Max": 80000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "MAC_IN_TEMP", + "temp_id": "TEMP6", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-0049/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 75000, + "Max": 80000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "PSU1_TEMP", + "temp_id": "TEMP7", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -20000, + "Low": 0, + "High": 55000, + "Max": 60000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "PSU2_TEMP", + "temp_id": "TEMP8", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -20000, + "Low": 0, + "High": 55000, + "Max": 60000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "SFF_TEMP", + "Temperature": { + "value": {"loc": "/tmp/highest_sff_temp", "way": "sysfs", "flock_path": "/tmp/highest_sff_temp"}, + "Min": -30000, + "Low": 0, + "High": 90000, + "Max": 100000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "invalid": -10000, + "error": -9999, + } + ], + "leds": [ + { + "name": "FRONT_SYS_LED", + "led_type": "SYS_LED", + "led": {"bus": 6, "addr": 0x0d, "offset": 0x72, "way": "i2c"}, + "led_attrs": { + "off": 0x00, "red_flash": 0x01, "red": 0x02, + "green_flash": 0x03, "green": 0x04, "amber_flash": 0x05, + "amber": 0x06, "mask": 0x07 + }, + }, + { + "name": "FRONT_PSU_LED", + "led_type": "PSU_LED", + "led": {"bus": 6, "addr": 0x0d, "offset": 0x73, "way": "i2c"}, + "led_attrs": { + "off": 0x10, "red_flash": 0x11, "red": 0x12, + "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, + "amber": 0x16, "mask": 0x17 + }, + }, + { + "name": "FRONT_FAN_LED", + "led_type": "FAN_LED", + "led": {"bus": 6, "addr": 0x0d, "offset": 0x74, "way": "i2c"}, + "led_attrs": { + "off": 0x10, "red_flash": 0x11, "red": 0x12, + "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, + "amber": 0x16, "mask": 0x17 + }, + }, + ], + "fans": [ + { + "name": "FAN1", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-16/16-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3b, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan1/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan1/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + { + "name": "FAN2", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-17/17-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3c, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan2/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan2/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + { + "name": "FAN3", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-18/18-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan3/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3d, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan3/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan3/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + + { + "name": "FAN4", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-19/19-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan4/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3e, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan4/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan4/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + + ], + "cplds": [ + { + "name": "CPU_CPLD", + "cpld_id": "CPLD1", + "VersionFile": {"loc": "/dev/cpld0", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for system power", + "slot": 0, + "warm": 0, + }, + { + "name": "CONNECT_CPLD", + "cpld_id": "CPLD2", + "VersionFile": {"loc": "/dev/cpld1", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for base functions", + "slot": 0, + "warm": 0, + }, + { + "name": "CONNECT_CPLD-FAN", + "cpld_id": "CPLD3", + "VersionFile": {"loc": "/dev/cpld2", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for fan modules", + "slot": 0, + "warm": 0, + }, + { + "name": "MAC_CPLD1", + "cpld_id": "CPLD4", + "VersionFile": {"loc": "/dev/cpld3", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for sff modules", + "slot": 0, + "warm": 0, + }, + { + "name": "MAC_CPLD2", + "cpld_id": "CPLD5", + "VersionFile": {"loc": "/dev/cpld4", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for sff modules", + "slot": 0, + "warm": 0, + }, + { + "name": "FPGA", + "cpld_id": "CPLD6", + "VersionFile": {"loc": "/dev/fpga0", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for base functions", + "slot": 0, + "format": "little_endian", + "warm": 0, + }, + { + "name": "BIOS", + "cpld_id": "CPLD7", + "VersionFile": {"cmd": "dmidecode -s bios-version", "way": "cmd"}, + "desc": "Performs initialization of hardware components during booting", + "slot": 0, + "type": "str", + "warm": 0, + }, + ], + "dcdc": [ + { + "name": "Switch_ZSFP1_3v3_C", + "dcdc_id": "DCDC1", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 22000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_QSFP1_3v3_C", + "dcdc_id": "DCDC2", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 22000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_5v0_C", + "dcdc_id": "DCDC3", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 1000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_ZSFP1_3v3_V", + "dcdc_id": "DCDC4", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_QSFP1_3v3_V", + "dcdc_id": "DCDC5", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_5v0_V", + "dcdc_id": "DCDC6", + "Min": 4000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 6000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_1v2_C", + "dcdc_id": "DCDC7", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_3v3_C", + "dcdc_id": "DCDC8", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 1000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_Cpld_3v3_C", + "dcdc_id": "DCDC9", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_1v2_V", + "dcdc_id": "DCDC10", + "Min": 960, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1440, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_3v3_V", + "dcdc_id": "DCDC11", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_Cpld_3v3_V", + "dcdc_id": "DCDC12", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_1v2_C", + "dcdc_id": "DCDC13", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 1300, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_3v3_C", + "dcdc_id": "DCDC14", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2800, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_SSD_3v3_C", + "dcdc_id": "DCDC15", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 4500, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_1v2_V", + "dcdc_id": "DCDC16", + "Min": 960, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1440, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_3v3_V", + "dcdc_id": "DCDC17", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_SSD_3v3_V", + "dcdc_id": "DCDC18", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_3v3_C", + "dcdc_id": "DCDC19", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 4686, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_5v_C", + "dcdc_id": "DCDC20", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v7_C", + "dcdc_id": "DCDC21", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_3v3_V", + "dcdc_id": "DCDC22", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_5v_V", + "dcdc_id": "DCDC23", + "Min": 4000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 6000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v7_V", + "dcdc_id": "DCDC24", + "Min": 1360, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 2040, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_CORE_C", + "dcdc_id": "DCDC25", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 47300, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v05_C", + "dcdc_id": "DCDC26", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 15400, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_CORE_V", + "dcdc_id": "DCDC27", + "Min": 1456, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 2184, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v05_V", + "dcdc_id": "DCDC28", + "Min": 840, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1260, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_CORE_C", + "dcdc_id": "DCDC29", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 220000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_ANALOG_C", + "dcdc_id": "DCDC30", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 18000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_CORE_V", + "dcdc_id": "DCDC31", + "Min": 600, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_ANALOG_V", + "dcdc_id": "DCDC32", + "Min": 640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v2_C", + "dcdc_id": "DCDC33", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 9900, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_2v23_C", + "dcdc_id": "DCDC34", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v2_V", + "dcdc_id": "DCDC35", + "Min": 960, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1440, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_2v23_V", + "dcdc_id": "DCDC36", + "Min": 1784, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 2676, + "format": "float(float(%s)/1000)", + }, + ], + "cpu": [ + { + "name": "cpu", + "reboot_cause_path": "/etc/sonic/.reboot/.previous-reboot-cause.txt" + } + ], + "sfps": { + "ver": '1.0', + "port_index_start": 1, + "port_num": 56, + "log_level": 2, + "eeprom_retry_times": 5, + "eeprom_retry_break_sec": 0.2, + "presence_cpld": { + "dev_id": { + 3: { + "offset": { + 0x30: "1-8", + 0x31: "9-16", + 0x32: "17-24", + }, + }, + 4: { + "offset": { + 0x30: "25-32", + 0x31: "33-40", + 0x32: "41-48", + 0x33: "49-56", + }, + }, + }, + }, + "presence_val_is_present": 0, + "eeprom_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/eeprom", + "eeprom_path_key": list(range(32, 88)), + "optoe_driver_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/dev_class", + "optoe_driver_key": list(range(32, 88)), + "txdis_cpld": { + "dev_id": { + 3: { + "offset": { + 0x60: "1-8", + 0x61: "9-16", + 0x62: "17-24", + }, + }, + 4: { + "offset": { + 0x60: "25-32", + 0x61: "33-40", + 0x62: "41-48", + }, + }, + }, + }, + "txdisable_val_is_on": 1, + "reset_cpld": { + "dev_id": { + 4: { + "offset": { + 0xb9: "49-56", + }, + }, + }, + }, + "reset_val_is_reset": 0, + } +} diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_exhaust_device.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_exhaust_device.py new file mode 100755 index 000000000000..c2b857975382 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_exhaust_device.py @@ -0,0 +1,1371 @@ +#!/usr/bin/python3 + +psu_fan_airflow = { + "intake": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3', 'U1D-D10800-DRB'], + "exhaust": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'] +} + +fanairflow = { + "intake": ['M1HFAN III-F'], + "exhaust": ['M1HFAN III-R'], +} + +psu_display_name = { + "PA550II-F": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3'], + "PA550II-R": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'], + "PD800I-F": ['U1D-D10800-DRB'] +} + +psutypedecode = { + 0x00: 'N/A', + 0x01: 'AC', + 0x02: 'DC', +} + + +class Unit: + Temperature = "C" + Voltage = "V" + Current = "A" + Power = "W" + Speed = "RPM" + + +PSU_NOT_PRESENT_PWM = 100 + + +class threshold: + PSU_TEMP_MIN = -20 * 1000 + PSU_TEMP_MAX = 60 * 1000 + + PSU_FAN_SPEED_MIN = 2000 + PSU_FAN_SPEED_MAX = 18000 + + PSU_OUTPUT_VOLTAGE_MIN = 11 * 1000 + PSU_OUTPUT_VOLTAGE_MAX = 14 * 1000 + + PSU_AC_INPUT_VOLTAGE_MIN = 200 * 1000 + PSU_AC_INPUT_VOLTAGE_MAX = 240 * 1000 + + PSU_DC_INPUT_VOLTAGE_MIN = 190 * 1000 + PSU_DC_INPUT_VOLTAGE_MAX = 290 * 1000 + + ERR_VALUE = -9999999 + + PSU_OUTPUT_POWER_MIN = 10 * 1000 * 1000 + PSU_OUTPUT_POWER_MAX = 560 * 1000 * 1000 + + PSU_INPUT_POWER_MIN = 10 * 1000 * 1000 + PSU_INPUT_POWER_MAX = 625 * 1000 * 1000 + + PSU_OUTPUT_CURRENT_MIN = 1 * 1000 + PSU_OUTPUT_CURRENT_MAX = 45 * 1000 + + PSU_INPUT_CURRENT_MIN = 0 * 1000 + PSU_INPUT_CURRENT_MAX = 7 * 1000 + + FRONT_FAN_SPEED_MAX = 24000 + REAR_FAN_SPEED_MAX = 22500 + FAN_SPEED_MIN = 5000 + + + ASPOWER_DC_PSU_TEMP_MIN = -10 * 1000 + ASPOWER_DC_PSU_TEMP_MAX = 55 * 1000 + + ASPOWER_DC_PSU_FAN_SPEED_MIN = 800 + ASPOWER_DC_PSU_FAN_SPEED_MAX = 24000 + + ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN = 11.4 * 1000 + ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX = 12.6 * 1000 + + ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN = 36 * 1000 + ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX = 72 * 1000 + + ASPOWER_DC_ERR_VALUE = -9999999 + + ASPOWER_DC_PSU_OUTPUT_POWER_MIN = 5 * 1000 * 1000 + ASPOWER_DC_PSU_OUTPUT_POWER_MAX = 800 * 1000 * 1000 + + ASPOWER_DC_PSU_INPUT_POWER_MIN = 5 * 1000 * 1000 + ASPOWER_DC_PSU_INPUT_POWER_MAX = 880 * 1000 * 1000 + + ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN = 0.5 * 1000 + ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX = 66 * 1000 + + ASPOWER_DC_PSU_INPUT_CURRENT_MIN = 1 * 1000 + ASPOWER_DC_PSU_INPUT_CURRENT_MAX = 28 * 1000 + + +class Description: + CPLD = "Used for managing IO modules, SFP+ modules and system LEDs" + BIOS = "Performs initialization of hardware components during booting" + FPGA = "Platform management controller for on-board temperature monitoring, in-chassis power" + + +devices = { + "onie_e2": [ + { + "name": "ONIE_E2", + "e2loc": {"loc": "/sys/bus/i2c/devices/0-0056/eeprom", "way": "sysfs"}, + "airflow": "exhaust" + }, + ], + "psus": [ + { + "e2loc": {"loc": "/sys/bus/i2c/devices/24-0050/eeprom", "way": "sysfs"}, + "pmbusloc": {"bus": 24, "addr": 0x58, "way": "i2c"}, + "present": {"loc": "/sys/wb_plat/psu/psu1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "name": "PSU1", + "get_threshold_by_model": 1, + "psu_display_name": psu_display_name, + "airflow": psu_fan_airflow, + "TempStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, + "other": threshold.PSU_TEMP_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, + "other": threshold.PSU_TEMP_MAX, + }, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "FanStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, + "FanSpeed": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, + "other": threshold.PSU_FAN_SPEED_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, + "other": threshold.PSU_FAN_SPEED_MAX, + }, + "Unit": Unit.Speed + }, + "psu_fan_tolerance": 40, + "InputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, + "InputsType": {"bus": 24, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, + "InputsVoltage": { + 'AC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, + "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + + }, + 'DC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + 'other': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.ERR_VALUE, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.ERR_VALUE, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + } + }, + "InputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, + "other": threshold.PSU_INPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, + "other": threshold.PSU_INPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "InputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, + "other": threshold.PSU_INPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, + "other": threshold.PSU_INPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + "OutputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, + "OutputsVoltage": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, + "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, + "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + "OutputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, + "other": threshold.PSU_OUTPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, + "other": threshold.PSU_OUTPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "OutputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, + "other": threshold.PSU_OUTPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, + "other": threshold.PSU_OUTPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + }, + { + "e2loc": {"loc": "/sys/bus/i2c/devices/25-0050/eeprom", "way": "sysfs"}, + "pmbusloc": {"bus": 25, "addr": 0x58, "way": "i2c"}, + "present": {"loc": "/sys/wb_plat/psu/psu2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "name": "PSU2", + "get_threshold_by_model": 1, + "psu_display_name": psu_display_name, + "airflow": psu_fan_airflow, + "TempStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, + "other": threshold.PSU_TEMP_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, + "other": threshold.PSU_TEMP_MAX, + }, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "FanStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, + "FanSpeed": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, + "other": threshold.PSU_FAN_SPEED_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, + "other": threshold.PSU_FAN_SPEED_MAX, + }, + "Unit": Unit.Speed + }, + "psu_fan_tolerance": 40, + "InputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, + "InputsType": {"bus": 25, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, + "InputsVoltage": { + 'AC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, + "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + + }, + 'DC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + 'other': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.ERR_VALUE, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.ERR_VALUE, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + } + }, + "InputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, + "other": threshold.PSU_INPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, + "other": threshold.PSU_INPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "InputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, + "other": threshold.PSU_INPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, + "other": threshold.PSU_INPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + "OutputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, + "OutputsVoltage": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, + "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, + "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + "OutputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, + "other": threshold.PSU_OUTPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, + "other": threshold.PSU_OUTPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "OutputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, + "other": threshold.PSU_OUTPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, + "other": threshold.PSU_OUTPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + } + ], + "temps": [ + { + "name": "SWITCH_TEMP", + "temp_id": "TEMP1", + "api_name": "ASIC_TEMP", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-0044/hwmon/hwmon*/temp99_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 105000, + "Max": 110000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "CPU_TEMP", + "temp_id": "TEMP2", + "Temperature": { + "value": {"loc": "/sys/bus/platform/devices/coretemp.0/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -15000, + "Low": 0, + "High": 100000, + "Max": 102000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "INLET_TEMP", + "temp_id": "TEMP3", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-004c/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 55000, + "Max": 60000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "fix_value": { + "fix_type": "config", + "addend": -3, + } + }, + { + "name": "OUTLET_TEMP", + "temp_id": "TEMP4", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-0048/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 75000, + "Max": 80000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "BOARD_TEMP", + "temp_id": "TEMP5", + "api_name": "MAC_OUT_TEMP", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-0049/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 75000, + "Max": 80000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "MAC_IN_TEMP", + "temp_id": "TEMP6", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-004a/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 75000, + "Max": 80000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "PSU1_TEMP", + "temp_id": "TEMP7", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -20000, + "Low": 0, + "High": 55000, + "Max": 60000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "PSU2_TEMP", + "temp_id": "TEMP8", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -20000, + "Low": 0, + "High": 55000, + "Max": 60000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "SFF_TEMP", + "Temperature": { + "value": {"loc": "/tmp/highest_sff_temp", "way": "sysfs", "flock_path": "/tmp/highest_sff_temp"}, + "Min": -30000, + "Low": 0, + "High": 90000, + "Max": 100000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "invalid": -10000, + "error": -9999, + } + ], + "leds": [ + { + "name": "FRONT_SYS_LED", + "led_type": "SYS_LED", + "led": {"bus": 6, "addr": 0x0d, "offset": 0x72, "way": "i2c"}, + "led_attrs": { + "off": 0x00, "red_flash": 0x01, "red": 0x02, + "green_flash": 0x03, "green": 0x04, "amber_flash": 0x05, + "amber": 0x06, "mask": 0x07 + }, + }, + { + "name": "FRONT_PSU_LED", + "led_type": "PSU_LED", + "led": {"bus": 6, "addr": 0x0d, "offset": 0x73, "way": "i2c"}, + "led_attrs": { + "off": 0x10, "red_flash": 0x11, "red": 0x12, + "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, + "amber": 0x16, "mask": 0x17 + }, + }, + { + "name": "FRONT_FAN_LED", + "led_type": "FAN_LED", + "led": {"bus": 6, "addr": 0x0d, "offset": 0x74, "way": "i2c"}, + "led_attrs": { + "off": 0x10, "red_flash": 0x11, "red": 0x12, + "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, + "amber": 0x16, "mask": 0x17 + }, + }, + ], + "fans": [ + { + "name": "FAN1", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-16/16-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3b, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan1/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan1/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + { + "name": "FAN2", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-17/17-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3c, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan2/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan2/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + { + "name": "FAN3", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-18/18-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan3/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3d, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan3/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan3/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + + { + "name": "FAN4", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-19/19-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan4/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3e, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan4/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan4/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + + ], + "cplds": [ + { + "name": "CPU_CPLD", + "cpld_id": "CPLD1", + "VersionFile": {"loc": "/dev/cpld0", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for system power", + "slot": 0, + "warm": 0, + }, + { + "name": "CONNECT_CPLD", + "cpld_id": "CPLD2", + "VersionFile": {"loc": "/dev/cpld1", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for base functions", + "slot": 0, + "warm": 0, + }, + { + "name": "CONNECT_CPLD-FAN", + "cpld_id": "CPLD3", + "VersionFile": {"loc": "/dev/cpld2", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for fan modules", + "slot": 0, + "warm": 0, + }, + { + "name": "MAC_CPLD1", + "cpld_id": "CPLD4", + "VersionFile": {"loc": "/dev/cpld3", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for sff modules", + "slot": 0, + "warm": 0, + }, + { + "name": "MAC_CPLD2", + "cpld_id": "CPLD5", + "VersionFile": {"loc": "/dev/cpld4", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for sff modules", + "slot": 0, + "warm": 0, + }, + { + "name": "FPGA", + "cpld_id": "CPLD6", + "VersionFile": {"loc": "/dev/fpga0", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for base functions", + "slot": 0, + "format": "little_endian", + "warm": 0, + }, + { + "name": "BIOS", + "cpld_id": "CPLD7", + "VersionFile": {"cmd": "dmidecode -s bios-version", "way": "cmd"}, + "desc": "Performs initialization of hardware components during booting", + "slot": 0, + "type": "str", + "warm": 0, + }, + ], + "dcdc": [ + { + "name": "Switch_ZSFP1_3v3_C", + "dcdc_id": "DCDC1", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 22000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_QSFP1_3v3_C", + "dcdc_id": "DCDC2", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 22000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_5v0_C", + "dcdc_id": "DCDC3", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 1000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_ZSFP1_3v3_V", + "dcdc_id": "DCDC4", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_QSFP1_3v3_V", + "dcdc_id": "DCDC5", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_5v0_V", + "dcdc_id": "DCDC6", + "Min": 4000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 6000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_1v2_C", + "dcdc_id": "DCDC7", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_3v3_C", + "dcdc_id": "DCDC8", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 1000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_Cpld_3v3_C", + "dcdc_id": "DCDC9", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_1v2_V", + "dcdc_id": "DCDC10", + "Min": 960, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1440, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_3v3_V", + "dcdc_id": "DCDC11", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_Cpld_3v3_V", + "dcdc_id": "DCDC12", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_1v2_C", + "dcdc_id": "DCDC13", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 1300, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_3v3_C", + "dcdc_id": "DCDC14", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2800, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_SSD_3v3_C", + "dcdc_id": "DCDC15", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 4500, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_1v2_V", + "dcdc_id": "DCDC16", + "Min": 960, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1440, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_3v3_V", + "dcdc_id": "DCDC17", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_SSD_3v3_V", + "dcdc_id": "DCDC18", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_3v3_C", + "dcdc_id": "DCDC19", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 4686, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_5v_C", + "dcdc_id": "DCDC20", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v7_C", + "dcdc_id": "DCDC21", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_3v3_V", + "dcdc_id": "DCDC22", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_5v_V", + "dcdc_id": "DCDC23", + "Min": 4000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 6000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v7_V", + "dcdc_id": "DCDC24", + "Min": 1360, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 2040, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_CORE_C", + "dcdc_id": "DCDC25", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 47300, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v05_C", + "dcdc_id": "DCDC26", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 15400, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_CORE_V", + "dcdc_id": "DCDC27", + "Min": 1456, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 2184, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v05_V", + "dcdc_id": "DCDC28", + "Min": 840, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1260, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_CORE_C", + "dcdc_id": "DCDC29", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 220000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_ANALOG_C", + "dcdc_id": "DCDC30", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 18000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_CORE_V", + "dcdc_id": "DCDC31", + "Min": 600, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_ANALOG_V", + "dcdc_id": "DCDC32", + "Min": 640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v2_C", + "dcdc_id": "DCDC33", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 9900, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_2v23_C", + "dcdc_id": "DCDC34", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v2_V", + "dcdc_id": "DCDC35", + "Min": 960, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1440, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_2v23_V", + "dcdc_id": "DCDC36", + "Min": 1784, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 2676, + "format": "float(float(%s)/1000)", + }, + ], + "cpu": [ + { + "name": "cpu", + "reboot_cause_path": "/etc/sonic/.reboot/.previous-reboot-cause.txt" + } + ], + "sfps": { + "ver": '1.0', + "port_index_start": 1, + "port_num": 56, + "log_level": 2, + "eeprom_retry_times": 5, + "eeprom_retry_break_sec": 0.2, + "presence_cpld": { + "dev_id": { + 3: { + "offset": { + 0x30: "1-8", + 0x31: "9-16", + 0x32: "17-24", + }, + }, + 4: { + "offset": { + 0x30: "25-32", + 0x31: "33-40", + 0x32: "41-48", + 0x33: "49-56", + }, + }, + }, + }, + "presence_val_is_present": 0, + "eeprom_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/eeprom", + "eeprom_path_key": list(range(32, 88)), + "optoe_driver_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/dev_class", + "optoe_driver_key": list(range(32, 88)), + "txdis_cpld": { + "dev_id": { + 3: { + "offset": { + 0x60: "1-8", + 0x61: "9-16", + 0x62: "17-24", + }, + }, + 4: { + "offset": { + 0x60: "25-32", + 0x61: "33-40", + 0x62: "41-48", + }, + }, + }, + }, + "txdisable_val_is_on": 0, + "reset_cpld": { + "dev_id": { + 4: { + "offset": { + 0xb9: "49-56", + }, + }, + }, + }, + "reset_val_is_reset": 0, + } +} diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_monitor.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_monitor.py new file mode 100755 index 000000000000..aab279a21da2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_monitor.py @@ -0,0 +1,206 @@ +# coding:utf-8 + + +monitor = { + "openloop": { + "linear": { + "name": "linear", + "flag": 0, + "pwm_min": 0x80, + "pwm_max": 0xff, + "K": 11, + "tin_min": 38, + }, + "curve": { + "name": "curve", + "flag": 0, + "pwm_min": 0x5a, + "pwm_max": 0xff, + "a": 0.086, + "b": 0.318, + "c": 28, + "tin_min": 25, + }, + }, + + "pid": { + "CPU_TEMP": { + "name": "CPU_TEMP", + "flag": 1, + "type": "duty", + "pwm_min": 0x80, + "pwm_max": 0xff, + "Kp": 3, + "Ki": 0.5, + "Kd": 0.5, + "target": 89, + "value": [None, None, None], + }, + "SWITCH_TEMP": { + "name": "SWITCH_TEMP", + "flag": 1, + "type": "duty", + "pwm_min": 0x80, + "pwm_max": 0xff, + "Kp": 3, + "Ki": 0.4, + "Kd": 0.4, + "target": 82, + "value": [None, None, None], + }, + "OUTLET_TEMP": { + "name": "OUTLET_TEMP", + "flag": 0, + "type": "duty", + "pwm_min": 0x80, + "pwm_max": 0xff, + "Kp": 2, + "Ki": 0.4, + "Kd": 0.3, + "target": 65, + "value": [None, None, None], + }, + "BOARD_TEMP": { + "name": "BOARD_TEMP", + "flag": 0, + "type": "duty", + "pwm_min": 0x80, + "pwm_max": 0xff, + "Kp": 2, + "Ki": 0.4, + "Kd": 0.3, + "target": 65, + "value": [None, None, None], + }, + "SFF_TEMP": { + "name": "SFF_TEMP", + "flag": 1, + "type": "duty", + "pwm_min": 0x80, + "pwm_max": 0xff, + "Kp": 0.1, + "Ki": 0.4, + "Kd": 0, + "target": 60, + "value": [None, None, None], + }, + }, + + "hyst": { + "INLET_TEMP": { + "name": "INLET_TEMP", + "flag": 1, + "type": "duty", + "hyst_min": 50, # duty + "hyst_max": 100, # duty + "last_hyst_value": 50, # duty + "temp_min": 23, + "temp_max": 40, + "value": [None, None], + "rising": { + 23: 50, + 24: 50, + 25: 50, + 26: 53, + 27: 56, + 28: 59, + 29: 62, + 30: 65, + 31: 68, + 32: 71, + 33: 74, + 34: 77, + 35: 80, + 36: 84, + 37: 88, + 38: 92, + 39: 96, + 40: 100, + }, + "descending": { + 23: 50, + 24: 53, + 25: 56, + 26: 59, + 27: 62, + 28: 65, + 29: 68, + 30: 71, + 31: 74, + 32: 77, + 33: 80, + 34: 84, + 35: 88, + 36: 92, + 37: 96, + 38: 100, + 39: 100, + 40: 100, + }, + } + }, + + "temps_threshold": { + "SWITCH_TEMP": {"name": "SWITCH_TEMP", "warning": 100, "critical": 105}, + "INLET_TEMP": {"name": "INLET_TEMP", "warning": 40, "critical": 50}, + "BOARD_TEMP": {"name": "BOARD_TEMP", "warning": 70, "critical": 80}, + "OUTLET_TEMP": {"name": "OUTLET_TEMP", "warning": 70, "critical": 80}, + "CPU_TEMP": {"name": "CPU_TEMP", "warning": 100, "critical": 102}, + "SFF_TEMP": {"name": "SFF_TEMP", "warning": 999, "critical": 1000, "ignore_threshold": 1, "invalid": -10000, "error": -9999}, + }, + + "fancontrol_para": { + "interval": 5, + "fan_air_flow_monitor": 1, + "psu_air_flow_monitor": 1, + "max_pwm": 0xff, + "min_pwm": 0x80, + "abnormal_pwm": 0xff, + "warning_pwm": 0xff, + "temp_invalid_pid_pwm": 0x80, + "temp_error_pid_pwm": 0x80, + "temp_fail_num": 3, + "check_temp_fail": [ + {"temp_name": "INLET_TEMP"}, + {"temp_name": "SWITCH_TEMP"}, + {"temp_name": "CPU_TEMP"}, + ], + "temp_warning_num": 3, # temp over warning 3 times continuously + "temp_critical_num": 3, # temp over critical 3 times continuously + "temp_warning_countdown": 60, # 5 min warning speed after not warning + "temp_critical_countdown": 60, # 5 min full speed after not critical + "rotor_error_count": 6, # fan rotor error 6 times continuously + "inlet_mac_diff": 999, + "check_crit_reboot_flag": 1, + "check_crit_reboot_num": 3, + "check_crit_sleep_time": 20, + "psu_absent_fullspeed_num": 0xFF, + "fan_absent_fullspeed_num": 1, + "rotor_error_fullspeed_num": 1, + }, + + "ledcontrol_para": { + "interval": 5, + "checkpsu": 0, # 0: sys led don't follow psu led + "checkfan": 0, # 0: sys led don't follow fan led + "psu_amber_num": 1, + "fan_amber_num": 1, + "board_sys_led": [ + {"led_name": "FRONT_SYS_LED"}, + ], + "board_psu_led": [ + {"led_name": "FRONT_PSU_LED"}, + ], + "board_fan_led": [ + {"led_name": "FRONT_FAN_LED"}, + ], + "psu_air_flow_monitor": 1, + "fan_air_flow_monitor": 1, + "psu_air_flow_amber_num": 1, + "fan_air_flow_amber_num": 1, + }, + "otp_reboot_judge_file": { + "otp_switch_reboot_judge_file": "/etc/.otp_switch_reboot_flag", + "otp_other_reboot_judge_file": "/etc/.otp_other_reboot_flag", + }, +} diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/Makefile b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/Makefile new file mode 100755 index 000000000000..2e9c25ae6b7a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/Makefile @@ -0,0 +1,12 @@ +MAKEFILE_FILE_PATH = $(abspath $(lastword $(MAKEFILE_LIST))) +MODULES_DIR = $(abspath $(MAKEFILE_FILE_PATH)/../../../../common/modules) + +EXTRA_CFLAGS+= -I$(MODULES_DIR) +EXTRA_CFLAGS+= -I$(MODULES_DIR)/linux-5.10 + +obj-m := wb_pcie_dev_device.o +obj-m += wb_i2c_mux_pca954x_device.o +obj-m += wb_i2c_ocores_device.o +obj-m += wb_lpc_drv_device.o +obj-m += wb_i2c_dev_device.o +obj-m += wb_io_dev_device.o diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_dev_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_dev_device.c new file mode 100644 index 000000000000..865e7afea44c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_dev_device.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include + +#include + +static int g_wb_i2c_dev_device_debug = 0; +static int g_wb_i2c_dev_device_error = 0; + +module_param(g_wb_i2c_dev_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_i2c_dev_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_I2C_DEV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_i2c_dev_device_debug) { \ + printk(KERN_INFO "[WB_I2C_DEV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_I2C_DEV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_i2c_dev_device_error) { \ + printk(KERN_ERR "[WB_I2C_DEV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static i2c_dev_device_t i2c_dev_device_data0 = { + .i2c_bus = 2, + .i2c_addr = 0x0d, + .i2c_name = "cpld2", + .data_bus_width = 1, + .addr_bus_width = 1, + .per_rd_len = 256, + .per_wr_len = 256, + .i2c_len = 256, +}; + +static i2c_dev_device_t i2c_dev_device_data1 = { + .i2c_bus = 8, + .i2c_addr = 0x30, + .i2c_name = "cpld3", + .data_bus_width = 1, + .addr_bus_width = 1, + .per_rd_len = 256, + .per_wr_len = 256, + .i2c_len = 256, +}; + +static i2c_dev_device_t i2c_dev_device_data2 = { + .i2c_bus = 8, + .i2c_addr = 0x31, + .i2c_name = "cpld4", + .data_bus_width = 1, + .addr_bus_width = 1, + .per_rd_len = 256, + .per_wr_len = 256, + .i2c_len = 256, +}; + +static i2c_dev_device_t i2c_dev_device_data3 = { + .i2c_bus = 6, + .i2c_addr = 0x0d, + .i2c_name = "cpld5", + .data_bus_width = 1, + .addr_bus_width = 1, + .per_rd_len = 256, + .per_wr_len = 256, + .i2c_len = 256, +}; + +struct i2c_board_info i2c_dev_device_info[] = { + { + .type = "wb-i2c-dev", + .platform_data = &i2c_dev_device_data0, + }, + { + .type = "wb-i2c-dev", + .platform_data = &i2c_dev_device_data1, + }, + { + .type = "wb-i2c-dev", + .platform_data = &i2c_dev_device_data2, + }, + { + .type = "wb-i2c-dev", + .platform_data = &i2c_dev_device_data3, + }, +}; + +static int __init wb_i2c_dev_device_init(void) +{ + int i; + struct i2c_adapter *adap; + struct i2c_client *client; + i2c_dev_device_t *i2c_dev_device_data; + + WB_I2C_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = 0; i < ARRAY_SIZE(i2c_dev_device_info); i++) { + i2c_dev_device_data = i2c_dev_device_info[i].platform_data; + i2c_dev_device_info[i].addr = i2c_dev_device_data->i2c_addr; + adap = i2c_get_adapter(i2c_dev_device_data->i2c_bus); + if (adap == NULL) { + i2c_dev_device_data->client = NULL; + printk(KERN_ERR "get i2c bus %d adapter fail.\n", i2c_dev_device_data->i2c_bus); + continue; + } + client = i2c_new_client_device(adap, &i2c_dev_device_info[i]); + if (!client) { + i2c_dev_device_data->client = NULL; + printk(KERN_ERR "Failed to register i2c dev device %d at bus %d!\n", + i2c_dev_device_data->i2c_addr, i2c_dev_device_data->i2c_bus); + } else { + i2c_dev_device_data->client = client; + } + i2c_put_adapter(adap); + } + return 0; +} + +static void __exit wb_i2c_dev_device_exit(void) +{ + int i; + i2c_dev_device_t *i2c_dev_device_data; + + WB_I2C_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = ARRAY_SIZE(i2c_dev_device_info) - 1; i >= 0; i--) { + i2c_dev_device_data = i2c_dev_device_info[i].platform_data; + if (i2c_dev_device_data->client) { + i2c_unregister_device(i2c_dev_device_data->client); + i2c_dev_device_data->client = NULL; + } + } +} + +module_init(wb_i2c_dev_device_init); +module_exit(wb_i2c_dev_device_exit); +MODULE_DESCRIPTION("I2C DEV Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_mux_pca954x_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_mux_pca954x_device.c new file mode 100644 index 000000000000..f12a71013451 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_mux_pca954x_device.c @@ -0,0 +1,296 @@ +#include +#include +#include +#include +#include +#include + +#include + +static int g_wb_i2c_mux_pca954x_device_debug = 0; +static int g_wb_i2c_mux_pca954x_device_error = 0; + +module_param(g_wb_i2c_mux_pca954x_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_i2c_mux_pca954x_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_I2C_MUX_PCA954X_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_i2c_mux_pca954x_device_debug) { \ + printk(KERN_INFO "[WB_I2C_MUX_PCA954X_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_I2C_MUX_PCA954X_DEVICE_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_i2c_mux_pca954x_device_error) { \ + printk(KERN_ERR "[WB_I2C_MUX_PCA954X_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data0 = { + .i2c_bus = 2, + .i2c_addr = 0x77, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 16, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/cpld5", + .file_attr.offset = 0x60, + .file_attr.mask = 0x02, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x02, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data1 = { + .i2c_bus = 4, + .i2c_addr = 0x77, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 24, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/cpld5", + .file_attr.offset = 0x60, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data2 = { + .i2c_bus = 12, + .i2c_addr = 0x70, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 32, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/fpga0", + .file_attr.offset = 0x20, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data3 = { + .i2c_bus = 12, + .i2c_addr = 0x71, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 40, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/fpga0", + .file_attr.offset = 0x20, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data4 = { + .i2c_bus = 12, + .i2c_addr = 0x72, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 48, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/fpga0", + .file_attr.offset = 0x20, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data5 = { + .i2c_bus = 12, + .i2c_addr = 0x73, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 56, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/fpga0", + .file_attr.offset = 0x20, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data6 = { + .i2c_bus = 13, + .i2c_addr = 0x70, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 64, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/fpga0", + .file_attr.offset = 0x20, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data7 = { + .i2c_bus = 13, + .i2c_addr = 0x71, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 72, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/fpga0", + .file_attr.offset = 0x20, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data8 = { + .i2c_bus = 13, + .i2c_addr = 0x72, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 80, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/fpga0", + .file_attr.offset = 0x20, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +struct i2c_board_info i2c_mux_pca954x_device_info[] = { + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data0, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data1, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data2, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data3, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data4, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data5, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data6, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data7, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data8, + }, +}; + +static int __init wb_i2c_mux_pca954x_device_init(void) +{ + int i; + struct i2c_adapter *adap; + struct i2c_client *client; + i2c_mux_pca954x_device_t *i2c_mux_pca954x_device_data; + + WB_I2C_MUX_PCA954X_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = 0; i < ARRAY_SIZE(i2c_mux_pca954x_device_info); i++) { + i2c_mux_pca954x_device_data = i2c_mux_pca954x_device_info[i].platform_data; + i2c_mux_pca954x_device_info[i].addr = i2c_mux_pca954x_device_data->i2c_addr; + adap = i2c_get_adapter(i2c_mux_pca954x_device_data->i2c_bus); + if (adap == NULL) { + i2c_mux_pca954x_device_data->client = NULL; + printk(KERN_ERR "get i2c bus %d adapter fail.\n", i2c_mux_pca954x_device_data->i2c_bus); + continue; + } + client = i2c_new_client_device(adap, &i2c_mux_pca954x_device_info[i]); + if (!client) { + i2c_mux_pca954x_device_data->client = NULL; + printk(KERN_ERR "Failed to register pca954x device %d at bus %d!\n", + i2c_mux_pca954x_device_data->i2c_addr, i2c_mux_pca954x_device_data->i2c_bus); + } else { + i2c_mux_pca954x_device_data->client = client; + } + i2c_put_adapter(adap); + } + return 0; +} + +static void __exit wb_i2c_mux_pca954x_device_exit(void) +{ + int i; + i2c_mux_pca954x_device_t *i2c_mux_pca954x_device_data; + + WB_I2C_MUX_PCA954X_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = ARRAY_SIZE(i2c_mux_pca954x_device_info) - 1; i >= 0; i--) { + i2c_mux_pca954x_device_data = i2c_mux_pca954x_device_info[i].platform_data; + if (i2c_mux_pca954x_device_data->client) { + i2c_unregister_device(i2c_mux_pca954x_device_data->client); + i2c_mux_pca954x_device_data->client = NULL; + } + } +} + +module_init(wb_i2c_mux_pca954x_device_init); +module_exit(wb_i2c_mux_pca954x_device_exit); +MODULE_DESCRIPTION("I2C MUX PCA954X Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_ocores_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_ocores_device.c new file mode 100644 index 000000000000..ff7ba9d26fbc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_ocores_device.c @@ -0,0 +1,423 @@ +#include +#include +#include +#include +#include + +#include + +static int g_wb_i2c_ocores_device_debug = 0; +static int g_wb_i2c_ocores_device_error = 0; + +module_param(g_wb_i2c_ocores_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_i2c_ocores_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_I2C_OCORE_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_i2c_ocores_device_debug) { \ + printk(KERN_INFO "[WB_I2C_OCORE_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_I2C_OCORE_DEVICE_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_i2c_ocores_device_error) { \ + printk(KERN_ERR "[WB_I2C_OCORE_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static i2c_ocores_device_t i2c_ocores_device_data0 = { + .adap_nr = 2, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0800, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 0, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data1 = { + .adap_nr = 3, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0820, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 1, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data2 = { + .adap_nr = 4, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0840, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 2, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data3 = { + .adap_nr = 5, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0860, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 3, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data4 = { + .adap_nr = 6, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0880, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 4, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data5 = { + .adap_nr = 7, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x08a0, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 5, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data6 = { + .adap_nr = 8, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x08c0, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 6, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data7 = { + .adap_nr = 9, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x08e0, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 7, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data8 = { + .adap_nr = 10, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0900, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 8, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data9 = { + .adap_nr = 11, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0920, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 9, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data10 = { + .adap_nr = 12, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0940, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 10, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data11 = { + .adap_nr = 13, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0960, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 11, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data12 = { + .adap_nr = 14, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0980, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 12, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data13 = { + .adap_nr = 15, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x09a0, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 13, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static void wb_i2c_ocores_device_release(struct device *dev) +{ + return; +} + +static struct platform_device i2c_ocores_device[] = { + { + .name = "wb-ocores-i2c", + .id = 1, + .dev = { + .platform_data = &i2c_ocores_device_data0, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 2, + .dev = { + .platform_data = &i2c_ocores_device_data1, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 3, + .dev = { + .platform_data = &i2c_ocores_device_data2, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 4, + .dev = { + .platform_data = &i2c_ocores_device_data3, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 5, + .dev = { + .platform_data = &i2c_ocores_device_data4, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 6, + .dev = { + .platform_data = &i2c_ocores_device_data5, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 7, + .dev = { + .platform_data = &i2c_ocores_device_data6, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 8, + .dev = { + .platform_data = &i2c_ocores_device_data7, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 9, + .dev = { + .platform_data = &i2c_ocores_device_data8, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 10, + .dev = { + .platform_data = &i2c_ocores_device_data9, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 11, + .dev = { + .platform_data = &i2c_ocores_device_data10, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 12, + .dev = { + .platform_data = &i2c_ocores_device_data11, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 13, + .dev = { + .platform_data = &i2c_ocores_device_data12, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 14, + .dev = { + .platform_data = &i2c_ocores_device_data13, + .release = wb_i2c_ocores_device_release, + }, + }, +}; + +static int __init wb_i2c_ocores_device_init(void) +{ + int i; + int ret = 0; + i2c_ocores_device_t *i2c_ocores_device_data; + + WB_I2C_OCORE_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = 0; i < ARRAY_SIZE(i2c_ocores_device); i++) { + i2c_ocores_device_data = i2c_ocores_device[i].dev.platform_data; + ret = platform_device_register(&i2c_ocores_device[i]); + if (ret < 0) { + i2c_ocores_device_data->device_flag = -1; /* device register failed, set flag -1 */ + printk(KERN_ERR "wb-ocores-i2c.%d register failed!\n", i + 1); + } else { + i2c_ocores_device_data->device_flag = 0; /* device register suucess, set flag 0 */ + } + } + return 0; +} + +static void __exit wb_i2c_ocores_device_exit(void) +{ + int i; + i2c_ocores_device_t *i2c_ocores_device_data; + + WB_I2C_OCORE_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = ARRAY_SIZE(i2c_ocores_device) - 1; i >= 0; i--) { + i2c_ocores_device_data = i2c_ocores_device[i].dev.platform_data; + if (i2c_ocores_device_data->device_flag == 0) { /* device register success, need unregister */ + platform_device_unregister(&i2c_ocores_device[i]); + } + } +} + +module_init(wb_i2c_ocores_device_init); +module_exit(wb_i2c_ocores_device_exit); +MODULE_DESCRIPTION("I2C OCORES Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_io_dev_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_io_dev_device.c new file mode 100644 index 000000000000..cc84938fff0e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_io_dev_device.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include + +#include + +static int g_wb_io_dev_device_debug = 0; +static int g_wb_io_dev_device_error = 0; + +module_param(g_wb_io_dev_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_io_dev_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_IO_DEV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_io_dev_device_debug) { \ + printk(KERN_INFO "[WB_IO_DEV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_IO_DEV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_io_dev_device_error) { \ + printk(KERN_ERR "[WB_IO_DEV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static io_dev_device_t io_dev_device_data0 = { + .io_dev_name = "cpld0", + .io_base = 0x700, + .io_len = 0x100, + .indirect_addr = 0, +}; + +static io_dev_device_t io_dev_device_data1 = { + .io_dev_name = "cpld1", + .io_base = 0x900, + .io_len = 0x100, + .indirect_addr = 0, +}; + +static void wb_io_dev_device_release(struct device *dev) +{ + return; +} + +static struct platform_device io_dev_device[] = { + { + .name = "wb-io-dev", + .id = 1, + .dev = { + .platform_data = &io_dev_device_data0, + .release = wb_io_dev_device_release, + }, + }, + { + .name = "wb-io-dev", + .id = 2, + .dev = { + .platform_data = &io_dev_device_data1, + .release = wb_io_dev_device_release, + }, + }, +}; + +static int __init wb_io_dev_device_init(void) +{ + int i; + int ret = 0; + io_dev_device_t *io_dev_device_data; + + WB_IO_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = 0; i < ARRAY_SIZE(io_dev_device); i++) { + io_dev_device_data = io_dev_device[i].dev.platform_data; + ret = platform_device_register(&io_dev_device[i]); + if (ret < 0) { + io_dev_device_data->device_flag = -1; /* device register failed, set flag -1 */ + printk(KERN_ERR "wb-io-dev.%d register failed!\n", i + 1); + } else { + io_dev_device_data->device_flag = 0; /* device register suucess, set flag 0 */ + } + } + return 0; +} + +static void __exit wb_io_dev_device_exit(void) +{ + int i; + io_dev_device_t *io_dev_device_data; + + WB_IO_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = ARRAY_SIZE(io_dev_device) - 1; i >= 0; i--) { + io_dev_device_data = io_dev_device[i].dev.platform_data; + if (io_dev_device_data->device_flag == 0) { /* device register success, need unregister */ + platform_device_unregister(&io_dev_device[i]); + } + } +} + +module_init(wb_io_dev_device_init); +module_exit(wb_io_dev_device_exit); +MODULE_DESCRIPTION("IO DEV Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_lpc_drv_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_lpc_drv_device.c new file mode 100644 index 000000000000..9b6b61a51735 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_lpc_drv_device.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include + +#include + +static int g_wb_lpc_drv_device_debug = 0; +static int g_wb_lpc_drv_device_error = 0; + +module_param(g_wb_lpc_drv_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_lpc_drv_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_LPC_DRV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_lpc_drv_device_debug) { \ + printk(KERN_INFO "[WB_LPC_DRV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_LPC_DRV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_lpc_drv_device_error) { \ + printk(KERN_ERR "[WB_LPC_DRV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static lpc_drv_device_t lpc_drv_device_data_0 = { + .lpc_io_name = "wb_lpc", + .pci_domain = 0x0000, + .pci_bus = 0x00, + .pci_slot = 0x1f, + .pci_fn = 0, + .lpc_io_base = 0x700, + .lpc_io_size = 0x100, + .lpc_gen_dec = 0x84, +}; + +static lpc_drv_device_t lpc_drv_device_data_1 = { + .lpc_io_name = "wb_lpc", + .pci_domain = 0x0000, + .pci_bus = 0x00, + .pci_slot = 0x1f, + .pci_fn = 0, + .lpc_io_base = 0x900, + .lpc_io_size = 0x100, + .lpc_gen_dec = 0x88, +}; + +static lpc_drv_device_t lpc_drv_device_data_2 = { + .lpc_io_name = "wb_lpc", + .pci_domain = 0x0000, + .pci_bus = 0x00, + .pci_slot = 0x1f, + .pci_fn = 0, + .lpc_io_base = 0xb00, + .lpc_io_size = 0x100, + .lpc_gen_dec = 0x90, +}; + +static void wb_lpc_drv_device_release(struct device *dev) +{ + return; +} + +static struct platform_device lpc_drv_device[] = { + { + .name = "wb-lpc", + .id = 1, + .dev = { + .platform_data = &lpc_drv_device_data_0, + .release = wb_lpc_drv_device_release, + }, + }, + { + .name = "wb-lpc", + .id = 2, + .dev = { + .platform_data = &lpc_drv_device_data_1, + .release = wb_lpc_drv_device_release, + }, + }, + { + .name = "wb-lpc", + .id = 3, + .dev = { + .platform_data = &lpc_drv_device_data_2, + .release = wb_lpc_drv_device_release, + }, + }, +}; + +static int __init wb_lpc_drv_device_init(void) +{ + int i; + int ret = 0; + lpc_drv_device_t *lpc_drv_device_data; + + WB_LPC_DRV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = 0; i < ARRAY_SIZE(lpc_drv_device); i++) { + lpc_drv_device_data = lpc_drv_device[i].dev.platform_data; + ret = platform_device_register(&lpc_drv_device[i]); + if (ret < 0) { + lpc_drv_device_data->device_flag = -1; /* device register failed, set flag -1 */ + printk(KERN_ERR "wb-lpc.%d register failed!\n", i + 1); + } else { + lpc_drv_device_data->device_flag = 0; /* device register suucess, set flag 0 */ + } + } + return 0; +} + +static void __exit wb_lpc_drv_device_exit(void) +{ + int i; + lpc_drv_device_t *lpc_drv_device_data; + + WB_LPC_DRV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = ARRAY_SIZE(lpc_drv_device) - 1; i >= 0; i--) { + lpc_drv_device_data = lpc_drv_device[i].dev.platform_data; + if (lpc_drv_device_data->device_flag == 0) { /* device register success, need unregister */ + platform_device_unregister(&lpc_drv_device[i]); + } + } +} + +module_init(wb_lpc_drv_device_init); +module_exit(wb_lpc_drv_device_exit); +MODULE_DESCRIPTION("LPC DRV Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_pcie_dev_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_pcie_dev_device.c new file mode 100644 index 000000000000..f79b29770d29 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_pcie_dev_device.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include + +#include + +static int g_wb_pcie_dev_device_debug = 0; +static int g_wb_pcie_dev_device_error = 0; + +module_param(g_wb_pcie_dev_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_pcie_dev_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_PCIE_DEV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_pcie_dev_device_debug) { \ + printk(KERN_INFO "[WB_PCIE_DEV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_PCIE_DEV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_pcie_dev_device_error) { \ + printk(KERN_ERR "[WB_PCIE_DEV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static pci_dev_device_t pcie_dev_device_data0 = { + .pci_dev_name = "fpga0", + .pci_domain = 0x0000, + .pci_bus = 0x08, + .pci_slot = 0x00, + .pci_fn = 0, + .pci_bar = 0, + .bus_width = 4, + .upg_ctrl_base = 0xa00, + .upg_flash_base = 0x1a0000, +}; + +static void wb_pcie_dev_device_release(struct device *dev) +{ + return; +} + +static struct platform_device pcie_dev_device[] = { + { + .name = "wb-pci-dev", + .id = 1, + .dev = { + .platform_data = &pcie_dev_device_data0, + .release = wb_pcie_dev_device_release, + }, + }, +}; + +static int __init wb_pcie_dev_device_init(void) +{ + int i; + int ret = 0; + pci_dev_device_t *pcie_dev_device_data; + + WB_PCIE_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = 0; i < ARRAY_SIZE(pcie_dev_device); i++) { + pcie_dev_device_data = pcie_dev_device[i].dev.platform_data; + ret = platform_device_register(&pcie_dev_device[i]); + if (ret < 0) { + pcie_dev_device_data->device_flag = -1; /* device register failed, set flag -1 */ + printk(KERN_ERR "wb-pci-dev.%d register failed!\n", i + 1); + } else { + pcie_dev_device_data->device_flag = 0; /* device register suucess, set flag 0 */ + } + } + return 0; +} + +static void __exit wb_pcie_dev_device_exit(void) +{ + int i; + pci_dev_device_t *pcie_dev_device_data; + + WB_PCIE_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = ARRAY_SIZE(pcie_dev_device) - 1; i >= 0; i--) { + pcie_dev_device_data = pcie_dev_device[i].dev.platform_data; + if (pcie_dev_device_data->device_flag == 0) { /* device register success, need unregister */ + platform_device_unregister(&pcie_dev_device[i]); + } + } +} + +module_init(wb_pcie_dev_device_init); +module_exit(wb_pcie_dev_device_exit); +MODULE_DESCRIPTION("PCIE DEV Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_CPLD.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_CPLD.cfg new file mode 100644 index 000000000000..98d1da1750c3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_CPLD.cfg @@ -0,0 +1,41 @@ +# configuration item: I2C address of CPLD +# format: cpld_i2c_dev.bus_[cpld_slot]_[cpld_id] cpld_i2c_dev.addr_[cpld_slot]_[cpld_id] +# cpld_slot: Main card: 0, linear card: start from 1 +# cpld_id: start from 0 +# bus: I2C bus number of CPLD +# addr: I2C address of CPLD +cpld_i2c_dev.bus_0_2=2 +cpld_i2c_dev.addr_0_2=0x0d +cpld_i2c_dev.bus_0_3=8 +cpld_i2c_dev.addr_0_3=0x30 +cpld_i2c_dev.bus_0_4=8 +cpld_i2c_dev.addr_0_4=0x31 +cpld_i2c_dev.bus_0_5=6 +cpld_i2c_dev.addr_0_5=0x0d + + +# configuration item: LPC address of CPLD +# format: cpld_lpc_addr_[cpld_slot]_[cpld_id] +# cpld_slot: Main card: 0, linear card: start from 1 +# cpld_id: start from 0 +cpld_lpc_dev_0_0=0x700 +cpld_lpc_dev_0_1=0x900 + + +# configuration item: CPLD access method, lpc or i2c +# format: mode_cpld_[cpld_slot][cpld_slot]=lpc/i2c +# cpld_slot: Main card: 0, linear card: start from 1 +# cpld_id: start from 0 +mode_cpld_0_0=lpc +mode_cpld_0_1=lpc +mode_cpld_0_2=i2c +mode_cpld_0_3=i2c +mode_cpld_0_4=i2c +mode_cpld_0_5=i2c + + +# configuration item: the number of CPLD +# format: dev_num_[main_dev]_[minor_dev] +# main_dev: CPLD main_dev is 4 +# minor_dev: CPLD minor_dev not exist +dev_num_4_0=6 diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_FAN.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_FAN.cfg new file mode 100644 index 000000000000..2350b74eb8bc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_FAN.cfg @@ -0,0 +1,304 @@ +# configuration item: the number of fans +# format: dev_num_[main_dev]_[minor_dev] +# main_dev: fan main_dev is 1 +# minor_dev: fan minor_dev not exist(0) +dev_num_1_0=4 + + +# configuration item: the number of rotors +# format: dev_num_[main_dev]_[minor_dev] +# main_dev: rotor main_dev is 1 +# minor_dev: rotor minor_dev is 5 +dev_num_1_5=2 + + +# configuration item: fan presence status +# format: dev_present_status_[main_dev_id][fan_index] +# main_dev_id: fan main_dev_id is 1 +# fan_index: start from 1 +dev_present_status.mode_1_1=config +dev_present_status.src_1_1=cpld +dev_present_status.frmt_1_1=bit +dev_present_status.pola_1_1=negative +dev_present_status.addr_1_1=0x00020030 +dev_present_status.len_1_1=1 +dev_present_status.bit_offset_1_1=0 + +dev_present_status.mode_1_2=config +dev_present_status.src_1_2=cpld +dev_present_status.frmt_1_2=bit +dev_present_status.pola_1_2=negative +dev_present_status.addr_1_2=0x00020030 +dev_present_status.len_1_2=1 +dev_present_status.bit_offset_1_2=1 + +dev_present_status.mode_1_3=config +dev_present_status.src_1_3=cpld +dev_present_status.frmt_1_3=bit +dev_present_status.pola_1_3=negative +dev_present_status.addr_1_3=0x00020030 +dev_present_status.len_1_3=1 +dev_present_status.bit_offset_1_3=2 + +dev_present_status.mode_1_4=config +dev_present_status.src_1_4=cpld +dev_present_status.frmt_1_4=bit +dev_present_status.pola_1_4=negative +dev_present_status.addr_1_4=0x00020030 +dev_present_status.len_1_4=1 +dev_present_status.bit_offset_1_4=3 + + +# configuration item: fan rotor status +# format: fan_roll_status_[fan_id]_[motor_id] +# fan_id: start from 1 +# motor_id: start from 0 +fan_roll_status.mode_1_0=config +fan_roll_status.int_cons_1_0= +fan_roll_status.src_1_0=cpld +fan_roll_status.frmt_1_0=bit +fan_roll_status.pola_1_0=positive +fan_roll_status.fpath_1_0= +fan_roll_status.addr_1_0=0x00020031 +fan_roll_status.len_1_0=1 +fan_roll_status.bit_offset_1_0=0 + +fan_roll_status.mode_1_1=config +fan_roll_status.int_cons_1_1= +fan_roll_status.src_1_1=cpld +fan_roll_status.frmt_1_1=bit +fan_roll_status.pola_1_1=positive +fan_roll_status.fpath_1_1= +fan_roll_status.addr_1_1=0x00020034 +fan_roll_status.len_1_1=1 +fan_roll_status.bit_offset_1_1=0 + +fan_roll_status.mode_2_0=config +fan_roll_status.int_cons_2_0= +fan_roll_status.src_2_0=cpld +fan_roll_status.frmt_2_0=bit +fan_roll_status.pola_2_0=positive +fan_roll_status.fpath_2_0= +fan_roll_status.addr_2_0=0x00020031 +fan_roll_status.len_2_0=1 +fan_roll_status.bit_offset_2_0=1 + +fan_roll_status.mode_2_1=config +fan_roll_status.int_cons_2_1= +fan_roll_status.src_2_1=cpld +fan_roll_status.frmt_2_1=bit +fan_roll_status.pola_2_1=positive +fan_roll_status.fpath_2_1= +fan_roll_status.addr_2_1=0x00020034 +fan_roll_status.len_2_1=1 +fan_roll_status.bit_offset_2_1=1 + +fan_roll_status.mode_3_0=config +fan_roll_status.int_cons_3_0= +fan_roll_status.src_3_0=cpld +fan_roll_status.frmt_3_0=bit +fan_roll_status.pola_3_0=positive +fan_roll_status.fpath_3_0= +fan_roll_status.addr_3_0=0x00020031 +fan_roll_status.len_3_0=1 +fan_roll_status.bit_offset_3_0=2 + +fan_roll_status.mode_3_1=config +fan_roll_status.int_cons_3_1= +fan_roll_status.src_3_1=cpld +fan_roll_status.frmt_3_1=bit +fan_roll_status.pola_3_1=positive +fan_roll_status.fpath_3_1= +fan_roll_status.addr_3_1=0x00020034 +fan_roll_status.len_3_1=1 +fan_roll_status.bit_offset_3_1=2 + +fan_roll_status.mode_4_0=config +fan_roll_status.int_cons_4_0= +fan_roll_status.src_4_0=cpld +fan_roll_status.frmt_4_0=bit +fan_roll_status.pola_4_0=positive +fan_roll_status.fpath_4_0= +fan_roll_status.addr_4_0=0x00020031 +fan_roll_status.len_4_0=1 +fan_roll_status.bit_offset_4_0=3 + +fan_roll_status.mode_4_1=config +fan_roll_status.int_cons_4_1= +fan_roll_status.src_4_1=cpld +fan_roll_status.frmt_4_1=bit +fan_roll_status.pola_4_1=positive +fan_roll_status.fpath_4_1= +fan_roll_status.addr_4_1=0x00020034 +fan_roll_status.len_4_1=1 +fan_roll_status.bit_offset_4_1=3 + + +# configuration item: fan speed +# format: fan_speed_[fan_id]_[motor_id] +# fan_id: start from 1 +# motor_id: start from 0 +fan_speed.mode_1_0=config +fan_speed.int_cons_1_0= +fan_speed.src_1_0=cpld +fan_speed.frmt_1_0=num_bytes +fan_speed.pola_1_0=negative +fan_speed.fpath_1_0= +fan_speed.addr_1_0=0x0002001b +fan_speed.len_1_0=2 +fan_speed.bit_offset_1_0= + +fan_speed.mode_1_1=config +fan_speed.int_cons_1_1= +fan_speed.src_1_1=cpld +fan_speed.frmt_1_1=num_bytes +fan_speed.pola_1_1=negative +fan_speed.fpath_1_1= +fan_speed.addr_1_1=0x00020025 +fan_speed.len_1_1=2 +fan_speed.bit_offset_1_1= + +fan_speed.mode_2_0=config +fan_speed.int_cons_2_0= +fan_speed.src_2_0=cpld +fan_speed.frmt_2_0=num_bytes +fan_speed.pola_2_0=negative +fan_speed.fpath_2_0= +fan_speed.addr_2_0=0x0002001d +fan_speed.len_2_0=2 +fan_speed.bit_offset_2_0= + +fan_speed.mode_2_1=config +fan_speed.int_cons_2_1= +fan_speed.src_2_1=cpld +fan_speed.frmt_2_1=num_bytes +fan_speed.pola_2_1=negative +fan_speed.fpath_2_1= +fan_speed.addr_2_1=0x00020027 +fan_speed.len_2_1=2 +fan_speed.bit_offset_2_1= + +fan_speed.mode_3_0=config +fan_speed.int_cons_3_0= +fan_speed.src_3_0=cpld +fan_speed.frmt_3_0=num_bytes +fan_speed.pola_3_0=negative +fan_speed.fpath_3_0= +fan_speed.addr_3_0=0x0002001f +fan_speed.len_3_0=2 +fan_speed.bit_offset_3_0= + +fan_speed.mode_3_1=config +fan_speed.int_cons_3_1= +fan_speed.src_3_1=cpld +fan_speed.frmt_3_1=num_bytes +fan_speed.pola_3_1=negative +fan_speed.fpath_3_1= +fan_speed.addr_3_1=0x00020029 +fan_speed.len_3_1=2 +fan_speed.bit_offset_3_1= + +fan_speed.mode_4_0=config +fan_speed.int_cons_4_0= +fan_speed.src_4_0=cpld +fan_speed.frmt_4_0=num_bytes +fan_speed.pola_4_0=negative +fan_speed.fpath_4_0= +fan_speed.addr_4_0=0x00020021 +fan_speed.len_4_0=2 +fan_speed.bit_offset_4_0= + +fan_speed.mode_4_1=config +fan_speed.int_cons_4_1= +fan_speed.src_4_1=cpld +fan_speed.frmt_4_1=num_bytes +fan_speed.pola_4_1=negative +fan_speed.fpath_4_1= +fan_speed.addr_4_1=0x0002002b +fan_speed.len_4_1=2 +fan_speed.bit_offset_4_1= + + +# configuration item: fan pwm +# format: fan_ratio_[fan_id]_[motor_id] +# fan_id: start from 1 +# motor_id: start from 0 +fan_ratio.mode_1_0=config +fan_ratio.int_cons_1_0= +fan_ratio.src_1_0=cpld +fan_ratio.frmt_1_0=byte +fan_ratio.pola_1_0= +fan_ratio.fpath_1_0= +fan_ratio.addr_1_0=0x00020014 +fan_ratio.len_1_0=1 +fan_ratio.bit_offset_1_0= + +fan_ratio.mode_1_1=config +fan_ratio.int_cons_1_1= +fan_ratio.src_1_1=cpld +fan_ratio.frmt_1_1=byte +fan_ratio.pola_1_1= +fan_ratio.fpath_1_1= +fan_ratio.addr_1_1=0x00020014 +fan_ratio.len_1_1=1 +fan_ratio.bit_offset_1_1= + +fan_ratio.mode_2_0=config +fan_ratio.int_cons_2_0= +fan_ratio.src_2_0=cpld +fan_ratio.frmt_2_0=byte +fan_ratio.pola_2_0= +fan_ratio.fpath_2_0= +fan_ratio.addr_2_0=0x00020015 +fan_ratio.len_2_0=1 +fan_ratio.bit_offset_2_0= + +fan_ratio.mode_2_1=config +fan_ratio.int_cons_2_1= +fan_ratio.src_2_1=cpld +fan_ratio.frmt_2_1=byte +fan_ratio.pola_2_1= +fan_ratio.fpath_2_1= +fan_ratio.addr_2_1=0x00020015 +fan_ratio.len_2_1=1 +fan_ratio.bit_offset_2_1= + +fan_ratio.mode_3_0=config +fan_ratio.int_cons_3_0= +fan_ratio.src_3_0=cpld +fan_ratio.frmt_3_0=byte +fan_ratio.pola_3_0= +fan_ratio.fpath_3_0= +fan_ratio.addr_3_0=0x00020016 +fan_ratio.len_3_0=1 +fan_ratio.bit_offset_3_0= + +fan_ratio.mode_3_1=config +fan_ratio.int_cons_3_1= +fan_ratio.src_3_1=cpld +fan_ratio.frmt_3_1=byte +fan_ratio.pola_3_1= +fan_ratio.fpath_3_1= +fan_ratio.addr_3_1=0x00020016 +fan_ratio.len_3_1=1 +fan_ratio.bit_offset_3_1= + +fan_ratio.mode_4_0=config +fan_ratio.int_cons_4_0= +fan_ratio.src_4_0=cpld +fan_ratio.frmt_4_0=byte +fan_ratio.pola_4_0= +fan_ratio.fpath_4_0= +fan_ratio.addr_4_0=0x00020017 +fan_ratio.len_4_0=1 +fan_ratio.bit_offset_4_0= + +fan_ratio.mode_4_1=config +fan_ratio.int_cons_4_1= +fan_ratio.src_4_1=cpld +fan_ratio.frmt_4_1=byte +fan_ratio.pola_4_1= +fan_ratio.fpath_4_1= +fan_ratio.addr_4_1=0x00020017 +fan_ratio.len_4_1=1 +fan_ratio.bit_offset_4_1= diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_PSU.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_PSU.cfg new file mode 100644 index 000000000000..082ef20fe97f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_PSU.cfg @@ -0,0 +1,64 @@ +# configuration item: the number of psus +# format: dev_num_[main_dev]_[minor_dev] +# main_dev: psu main_dev is 2 +# minor_dev: psu minor_dev not exist(0) +dev_num_2_0=2 + + +# configuration item: psu status +# format: psu_status_[psu_index]_[status_id] +# psu_index: start from 1 +# status_id: 0: presence 1: output 2: alert +# psu1 presence status +psu_status.mode_1_0=config +psu_status.src_1_0=cpld +psu_status.frmt_1_0=bit +psu_status.pola_1_0=negative +psu_status.addr_1_0=0x00050051 +psu_status.len_1_0=1 +psu_status.bit_offset_1_0=0 + +# psu1 output status +psu_status.mode_1_1=config +psu_status.src_1_1=cpld +psu_status.frmt_1_1=bit +psu_status.pola_1_1=positive +psu_status.addr_1_1=0x00050051 +psu_status.len_1_1=1 +psu_status.bit_offset_1_1=1 + +# psu1 alert status +psu_status.mode_1_2=config +psu_status.src_1_2=cpld +psu_status.frmt_1_2=bit +psu_status.pola_1_2=negative +psu_status.addr_1_2=0x00050051 +psu_status.len_1_2=1 +psu_status.bit_offset_1_2=2 + +# psu2 presence status +psu_status.mode_2_0=config +psu_status.src_2_0=cpld +psu_status.frmt_2_0=bit +psu_status.pola_2_0=negative +psu_status.addr_2_0=0x00050051 +psu_status.len_2_0=1 +psu_status.bit_offset_2_0=4 + +# psu2 output status +psu_status.mode_2_1=config +psu_status.src_2_1=cpld +psu_status.frmt_2_1=bit +psu_status.pola_2_1=positive +psu_status.addr_2_1=0x00050051 +psu_status.len_2_1=1 +psu_status.bit_offset_2_1=5 + +# psu2 alert status +psu_status.mode_2_2=config +psu_status.src_2_2=cpld +psu_status.frmt_2_2=bit +psu_status.pola_2_2=negative +psu_status.addr_2_2=0x00050051 +psu_status.len_2_2=1 +psu_status.bit_offset_2_2=6 diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_SFF.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_SFF.cfg new file mode 100644 index 000000000000..7f57dfd93c5b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_SFF.cfg @@ -0,0 +1,521 @@ +# configuration item: the number of sffs +# format: dev_num_[main_dev]_[minor_dev] +# main_dev: sff main_dev is 3 +# minor_dev: sff minor_dev not exist(0) +dev_num_3_0=56 + +# configuration item: The directory name of sff sysfs +# format: sff_dir_name_[sff_index] +# sff_index: start from 1 +sff_dir_name_1 =sff1 +sff_dir_name_2 =sff2 +sff_dir_name_3 =sff3 +sff_dir_name_4 =sff4 +sff_dir_name_5 =sff5 +sff_dir_name_6 =sff6 +sff_dir_name_7 =sff7 +sff_dir_name_8 =sff8 +sff_dir_name_9 =sff9 +sff_dir_name_10 =sff10 +sff_dir_name_11 =sff11 +sff_dir_name_12 =sff12 +sff_dir_name_13 =sff13 +sff_dir_name_14 =sff14 +sff_dir_name_15 =sff15 +sff_dir_name_16 =sff16 +sff_dir_name_17 =sff17 +sff_dir_name_18 =sff18 +sff_dir_name_19 =sff19 +sff_dir_name_20 =sff20 +sff_dir_name_21 =sff21 +sff_dir_name_22 =sff22 +sff_dir_name_23 =sff23 +sff_dir_name_24 =sff24 +sff_dir_name_25 =sff25 +sff_dir_name_26 =sff26 +sff_dir_name_27 =sff27 +sff_dir_name_28 =sff28 +sff_dir_name_29 =sff29 +sff_dir_name_30 =sff30 +sff_dir_name_31 =sff31 +sff_dir_name_32 =sff32 +sff_dir_name_33 =sff33 +sff_dir_name_34 =sff34 +sff_dir_name_35 =sff35 +sff_dir_name_36 =sff36 +sff_dir_name_37 =sff37 +sff_dir_name_38 =sff38 +sff_dir_name_39 =sff39 +sff_dir_name_40 =sff40 +sff_dir_name_41 =sff41 +sff_dir_name_42 =sff42 +sff_dir_name_43 =sff43 +sff_dir_name_44 =sff44 +sff_dir_name_45 =sff45 +sff_dir_name_46 =sff46 +sff_dir_name_47 =sff47 +sff_dir_name_48 =sff48 +sff_dir_name_49 =sff49 +sff_dir_name_50 =sff50 +sff_dir_name_51 =sff51 +sff_dir_name_52 =sff52 +sff_dir_name_53 =sff53 +sff_dir_name_54 =sff54 +sff_dir_name_55 =sff55 +sff_dir_name_56 =sff56 + + +# configuration item: sff cpld register status +# format: sff_cpld_reg_[sff_index]_[cpld_reg] +# sff_index: start from 1 +# cpld_reg: 1: power_on, 2: tx_fault, 3: tx_dis, 4:pre_n, 5:rx_los +# 6: reset, 7: lpmode, 8: module_present, 9: interrupt + +# sff cpld presence status +sff_cpld_reg.mode_1_8=config +sff_cpld_reg.src_1_8=cpld +sff_cpld_reg.frmt_1_8=bit +sff_cpld_reg.pola_1_8=negative +sff_cpld_reg.addr_1_8=0x00030030 +sff_cpld_reg.len_1_8=1 +sff_cpld_reg.bit_offset_1_8=0 + +sff_cpld_reg.mode_2_8=config +sff_cpld_reg.src_2_8=cpld +sff_cpld_reg.frmt_2_8=bit +sff_cpld_reg.pola_2_8=negative +sff_cpld_reg.addr_2_8=0x00030030 +sff_cpld_reg.len_2_8=1 +sff_cpld_reg.bit_offset_2_8=1 + +sff_cpld_reg.mode_3_8=config +sff_cpld_reg.src_3_8=cpld +sff_cpld_reg.frmt_3_8=bit +sff_cpld_reg.pola_3_8=negative +sff_cpld_reg.addr_3_8=0x00030030 +sff_cpld_reg.len_3_8=1 +sff_cpld_reg.bit_offset_3_8=2 + +sff_cpld_reg.mode_4_8=config +sff_cpld_reg.src_4_8=cpld +sff_cpld_reg.frmt_4_8=bit +sff_cpld_reg.pola_4_8=negative +sff_cpld_reg.addr_4_8=0x00030030 +sff_cpld_reg.len_4_8=1 +sff_cpld_reg.bit_offset_4_8=3 + +sff_cpld_reg.mode_5_8=config +sff_cpld_reg.src_5_8=cpld +sff_cpld_reg.frmt_5_8=bit +sff_cpld_reg.pola_5_8=negative +sff_cpld_reg.addr_5_8=0x00030030 +sff_cpld_reg.len_5_8=1 +sff_cpld_reg.bit_offset_5_8=4 + +sff_cpld_reg.mode_6_8=config +sff_cpld_reg.src_6_8=cpld +sff_cpld_reg.frmt_6_8=bit +sff_cpld_reg.pola_6_8=negative +sff_cpld_reg.addr_6_8=0x00030030 +sff_cpld_reg.len_6_8=1 +sff_cpld_reg.bit_offset_6_8=5 + +sff_cpld_reg.mode_7_8=config +sff_cpld_reg.src_7_8=cpld +sff_cpld_reg.frmt_7_8=bit +sff_cpld_reg.pola_7_8=negative +sff_cpld_reg.addr_7_8=0x00030030 +sff_cpld_reg.len_7_8=1 +sff_cpld_reg.bit_offset_7_8=6 + +sff_cpld_reg.mode_8_8=config +sff_cpld_reg.src_8_8=cpld +sff_cpld_reg.frmt_8_8=bit +sff_cpld_reg.pola_8_8=negative +sff_cpld_reg.addr_8_8=0x00030030 +sff_cpld_reg.len_8_8=1 +sff_cpld_reg.bit_offset_8_8=7 + +sff_cpld_reg.mode_9_8=config +sff_cpld_reg.src_9_8=cpld +sff_cpld_reg.frmt_9_8=bit +sff_cpld_reg.pola_9_8=negative +sff_cpld_reg.addr_9_8=0x00030031 +sff_cpld_reg.len_9_8=1 +sff_cpld_reg.bit_offset_9_8=0 + +sff_cpld_reg.mode_10_8=config +sff_cpld_reg.src_10_8=cpld +sff_cpld_reg.frmt_10_8=bit +sff_cpld_reg.pola_10_8=negative +sff_cpld_reg.addr_10_8=0x00030031 +sff_cpld_reg.len_10_8=1 +sff_cpld_reg.bit_offset_10_8=1 + +sff_cpld_reg.mode_11_8=config +sff_cpld_reg.src_11_8=cpld +sff_cpld_reg.frmt_11_8=bit +sff_cpld_reg.pola_11_8=negative +sff_cpld_reg.addr_11_8=0x00030031 +sff_cpld_reg.len_11_8=1 +sff_cpld_reg.bit_offset_11_8=2 + +sff_cpld_reg.mode_12_8=config +sff_cpld_reg.src_12_8=cpld +sff_cpld_reg.frmt_12_8=bit +sff_cpld_reg.pola_12_8=negative +sff_cpld_reg.addr_12_8=0x00030031 +sff_cpld_reg.len_12_8=1 +sff_cpld_reg.bit_offset_12_8=3 + +sff_cpld_reg.mode_13_8=config +sff_cpld_reg.src_13_8=cpld +sff_cpld_reg.frmt_13_8=bit +sff_cpld_reg.pola_13_8=negative +sff_cpld_reg.addr_13_8=0x00030031 +sff_cpld_reg.len_13_8=1 +sff_cpld_reg.bit_offset_13_8=4 + +sff_cpld_reg.mode_14_8=config +sff_cpld_reg.src_14_8=cpld +sff_cpld_reg.frmt_14_8=bit +sff_cpld_reg.pola_14_8=negative +sff_cpld_reg.addr_14_8=0x00030031 +sff_cpld_reg.len_14_8=1 +sff_cpld_reg.bit_offset_14_8=5 + +sff_cpld_reg.mode_15_8=config +sff_cpld_reg.src_15_8=cpld +sff_cpld_reg.frmt_15_8=bit +sff_cpld_reg.pola_15_8=negative +sff_cpld_reg.addr_15_8=0x00030031 +sff_cpld_reg.len_15_8=1 +sff_cpld_reg.bit_offset_15_8=6 + +sff_cpld_reg.mode_16_8=config +sff_cpld_reg.src_16_8=cpld +sff_cpld_reg.frmt_16_8=bit +sff_cpld_reg.pola_16_8=negative +sff_cpld_reg.addr_16_8=0x00030031 +sff_cpld_reg.len_16_8=1 +sff_cpld_reg.bit_offset_16_8=7 + +sff_cpld_reg.mode_17_8=config +sff_cpld_reg.src_17_8=cpld +sff_cpld_reg.frmt_17_8=bit +sff_cpld_reg.pola_17_8=negative +sff_cpld_reg.addr_17_8=0x00030032 +sff_cpld_reg.len_17_8=1 +sff_cpld_reg.bit_offset_17_8=0 + +sff_cpld_reg.mode_18_8=config +sff_cpld_reg.src_18_8=cpld +sff_cpld_reg.frmt_18_8=bit +sff_cpld_reg.pola_18_8=negative +sff_cpld_reg.addr_18_8=0x00030032 +sff_cpld_reg.len_18_8=1 +sff_cpld_reg.bit_offset_18_8=1 + +sff_cpld_reg.mode_19_8=config +sff_cpld_reg.src_19_8=cpld +sff_cpld_reg.frmt_19_8=bit +sff_cpld_reg.pola_19_8=negative +sff_cpld_reg.addr_19_8=0x00030032 +sff_cpld_reg.len_19_8=1 +sff_cpld_reg.bit_offset_19_8=2 + +sff_cpld_reg.mode_20_8=config +sff_cpld_reg.src_20_8=cpld +sff_cpld_reg.frmt_20_8=bit +sff_cpld_reg.pola_20_8=negative +sff_cpld_reg.addr_20_8=0x00030032 +sff_cpld_reg.len_20_8=1 +sff_cpld_reg.bit_offset_20_8=3 + +sff_cpld_reg.mode_21_8=config +sff_cpld_reg.src_21_8=cpld +sff_cpld_reg.frmt_21_8=bit +sff_cpld_reg.pola_21_8=negative +sff_cpld_reg.addr_21_8=0x00030032 +sff_cpld_reg.len_21_8=1 +sff_cpld_reg.bit_offset_21_8=4 + +sff_cpld_reg.mode_22_8=config +sff_cpld_reg.src_22_8=cpld +sff_cpld_reg.frmt_22_8=bit +sff_cpld_reg.pola_22_8=negative +sff_cpld_reg.addr_22_8=0x00030032 +sff_cpld_reg.len_22_8=1 +sff_cpld_reg.bit_offset_22_8=5 + +sff_cpld_reg.mode_23_8=config +sff_cpld_reg.src_23_8=cpld +sff_cpld_reg.frmt_23_8=bit +sff_cpld_reg.pola_23_8=negative +sff_cpld_reg.addr_23_8=0x00030032 +sff_cpld_reg.len_23_8=1 +sff_cpld_reg.bit_offset_23_8=6 + +sff_cpld_reg.mode_24_8=config +sff_cpld_reg.src_24_8=cpld +sff_cpld_reg.frmt_24_8=bit +sff_cpld_reg.pola_24_8=negative +sff_cpld_reg.addr_24_8=0x00030032 +sff_cpld_reg.len_24_8=1 +sff_cpld_reg.bit_offset_24_8=7 + +sff_cpld_reg.mode_25_8=config +sff_cpld_reg.src_25_8=cpld +sff_cpld_reg.frmt_25_8=bit +sff_cpld_reg.pola_25_8=negative +sff_cpld_reg.addr_25_8=0x00040030 +sff_cpld_reg.len_25_8=1 +sff_cpld_reg.bit_offset_25_8=0 + +sff_cpld_reg.mode_26_8=config +sff_cpld_reg.src_26_8=cpld +sff_cpld_reg.frmt_26_8=bit +sff_cpld_reg.pola_26_8=negative +sff_cpld_reg.addr_26_8=0x00040030 +sff_cpld_reg.len_26_8=1 +sff_cpld_reg.bit_offset_26_8=1 + +sff_cpld_reg.mode_27_8=config +sff_cpld_reg.src_27_8=cpld +sff_cpld_reg.frmt_27_8=bit +sff_cpld_reg.pola_27_8=negative +sff_cpld_reg.addr_27_8=0x00040030 +sff_cpld_reg.len_27_8=1 +sff_cpld_reg.bit_offset_27_8=2 + +sff_cpld_reg.mode_28_8=config +sff_cpld_reg.src_28_8=cpld +sff_cpld_reg.frmt_28_8=bit +sff_cpld_reg.pola_28_8=negative +sff_cpld_reg.addr_28_8=0x00040030 +sff_cpld_reg.len_28_8=1 +sff_cpld_reg.bit_offset_28_8=3 + +sff_cpld_reg.mode_29_8=config +sff_cpld_reg.src_29_8=cpld +sff_cpld_reg.frmt_29_8=bit +sff_cpld_reg.pola_29_8=negative +sff_cpld_reg.addr_29_8=0x00040030 +sff_cpld_reg.len_29_8=1 +sff_cpld_reg.bit_offset_29_8=4 + +sff_cpld_reg.mode_30_8=config +sff_cpld_reg.src_30_8=cpld +sff_cpld_reg.frmt_30_8=bit +sff_cpld_reg.pola_30_8=negative +sff_cpld_reg.addr_30_8=0x00040030 +sff_cpld_reg.len_30_8=1 +sff_cpld_reg.bit_offset_30_8=5 + +sff_cpld_reg.mode_31_8=config +sff_cpld_reg.src_31_8=cpld +sff_cpld_reg.frmt_31_8=bit +sff_cpld_reg.pola_31_8=negative +sff_cpld_reg.addr_31_8=0x00040030 +sff_cpld_reg.len_31_8=1 +sff_cpld_reg.bit_offset_31_8=6 + +sff_cpld_reg.mode_32_8=config +sff_cpld_reg.src_32_8=cpld +sff_cpld_reg.frmt_32_8=bit +sff_cpld_reg.pola_32_8=negative +sff_cpld_reg.addr_32_8=0x00040030 +sff_cpld_reg.len_32_8=1 +sff_cpld_reg.bit_offset_32_8=7 + +sff_cpld_reg.mode_33_8=config +sff_cpld_reg.src_33_8=cpld +sff_cpld_reg.frmt_33_8=bit +sff_cpld_reg.pola_33_8=negative +sff_cpld_reg.addr_33_8=0x00040031 +sff_cpld_reg.len_33_8=1 +sff_cpld_reg.bit_offset_33_8=0 + +sff_cpld_reg.mode_34_8=config +sff_cpld_reg.src_34_8=cpld +sff_cpld_reg.frmt_34_8=bit +sff_cpld_reg.pola_34_8=negative +sff_cpld_reg.addr_34_8=0x00040031 +sff_cpld_reg.len_34_8=1 +sff_cpld_reg.bit_offset_34_8=1 + +sff_cpld_reg.mode_35_8=config +sff_cpld_reg.src_35_8=cpld +sff_cpld_reg.frmt_35_8=bit +sff_cpld_reg.pola_35_8=negative +sff_cpld_reg.addr_35_8=0x00040031 +sff_cpld_reg.len_35_8=1 +sff_cpld_reg.bit_offset_35_8=2 + +sff_cpld_reg.mode_36_8=config +sff_cpld_reg.src_36_8=cpld +sff_cpld_reg.frmt_36_8=bit +sff_cpld_reg.pola_36_8=negative +sff_cpld_reg.addr_36_8=0x00040031 +sff_cpld_reg.len_36_8=1 +sff_cpld_reg.bit_offset_36_8=3 + +sff_cpld_reg.mode_37_8=config +sff_cpld_reg.src_37_8=cpld +sff_cpld_reg.frmt_37_8=bit +sff_cpld_reg.pola_37_8=negative +sff_cpld_reg.addr_37_8=0x00040031 +sff_cpld_reg.len_37_8=1 +sff_cpld_reg.bit_offset_37_8=4 + +sff_cpld_reg.mode_38_8=config +sff_cpld_reg.src_38_8=cpld +sff_cpld_reg.frmt_38_8=bit +sff_cpld_reg.pola_38_8=negative +sff_cpld_reg.addr_38_8=0x00040031 +sff_cpld_reg.len_38_8=1 +sff_cpld_reg.bit_offset_38_8=5 + +sff_cpld_reg.mode_39_8=config +sff_cpld_reg.src_39_8=cpld +sff_cpld_reg.frmt_39_8=bit +sff_cpld_reg.pola_39_8=negative +sff_cpld_reg.addr_39_8=0x00040031 +sff_cpld_reg.len_39_8=1 +sff_cpld_reg.bit_offset_39_8=6 + +sff_cpld_reg.mode_40_8=config +sff_cpld_reg.src_40_8=cpld +sff_cpld_reg.frmt_40_8=bit +sff_cpld_reg.pola_40_8=negative +sff_cpld_reg.addr_40_8=0x00040031 +sff_cpld_reg.len_40_8=1 +sff_cpld_reg.bit_offset_40_8=7 + +sff_cpld_reg.mode_41_8=config +sff_cpld_reg.src_41_8=cpld +sff_cpld_reg.frmt_41_8=bit +sff_cpld_reg.pola_41_8=negative +sff_cpld_reg.addr_41_8=0x00040032 +sff_cpld_reg.len_41_8=1 +sff_cpld_reg.bit_offset_41_8=0 + +sff_cpld_reg.mode_42_8=config +sff_cpld_reg.src_42_8=cpld +sff_cpld_reg.frmt_42_8=bit +sff_cpld_reg.pola_42_8=negative +sff_cpld_reg.addr_42_8=0x00040032 +sff_cpld_reg.len_42_8=1 +sff_cpld_reg.bit_offset_42_8=1 + +sff_cpld_reg.mode_43_8=config +sff_cpld_reg.src_43_8=cpld +sff_cpld_reg.frmt_43_8=bit +sff_cpld_reg.pola_43_8=negative +sff_cpld_reg.addr_43_8=0x00040032 +sff_cpld_reg.len_43_8=1 +sff_cpld_reg.bit_offset_43_8=2 + +sff_cpld_reg.mode_44_8=config +sff_cpld_reg.src_44_8=cpld +sff_cpld_reg.frmt_44_8=bit +sff_cpld_reg.pola_44_8=negative +sff_cpld_reg.addr_44_8=0x00040032 +sff_cpld_reg.len_44_8=1 +sff_cpld_reg.bit_offset_44_8=3 + +sff_cpld_reg.mode_45_8=config +sff_cpld_reg.src_45_8=cpld +sff_cpld_reg.frmt_45_8=bit +sff_cpld_reg.pola_45_8=negative +sff_cpld_reg.addr_45_8=0x00040032 +sff_cpld_reg.len_45_8=1 +sff_cpld_reg.bit_offset_45_8=4 + +sff_cpld_reg.mode_46_8=config +sff_cpld_reg.src_46_8=cpld +sff_cpld_reg.frmt_46_8=bit +sff_cpld_reg.pola_46_8=negative +sff_cpld_reg.addr_46_8=0x00040032 +sff_cpld_reg.len_46_8=1 +sff_cpld_reg.bit_offset_46_8=5 + +sff_cpld_reg.mode_47_8=config +sff_cpld_reg.src_47_8=cpld +sff_cpld_reg.frmt_47_8=bit +sff_cpld_reg.pola_47_8=negative +sff_cpld_reg.addr_47_8=0x00040032 +sff_cpld_reg.len_47_8=1 +sff_cpld_reg.bit_offset_47_8=6 + +sff_cpld_reg.mode_48_8=config +sff_cpld_reg.src_48_8=cpld +sff_cpld_reg.frmt_48_8=bit +sff_cpld_reg.pola_48_8=negative +sff_cpld_reg.addr_48_8=0x00040032 +sff_cpld_reg.len_48_8=1 +sff_cpld_reg.bit_offset_48_8=7 + +sff_cpld_reg.mode_49_8=config +sff_cpld_reg.src_49_8=cpld +sff_cpld_reg.frmt_49_8=bit +sff_cpld_reg.pola_49_8=negative +sff_cpld_reg.addr_49_8=0x00040033 +sff_cpld_reg.len_49_8=1 +sff_cpld_reg.bit_offset_49_8=0 + +sff_cpld_reg.mode_50_8=config +sff_cpld_reg.src_50_8=cpld +sff_cpld_reg.frmt_50_8=bit +sff_cpld_reg.pola_50_8=negative +sff_cpld_reg.addr_50_8=0x00040033 +sff_cpld_reg.len_50_8=1 +sff_cpld_reg.bit_offset_50_8=1 + +sff_cpld_reg.mode_51_8=config +sff_cpld_reg.src_51_8=cpld +sff_cpld_reg.frmt_51_8=bit +sff_cpld_reg.pola_51_8=negative +sff_cpld_reg.addr_51_8=0x00040033 +sff_cpld_reg.len_51_8=1 +sff_cpld_reg.bit_offset_51_8=2 + +sff_cpld_reg.mode_52_8=config +sff_cpld_reg.src_52_8=cpld +sff_cpld_reg.frmt_52_8=bit +sff_cpld_reg.pola_52_8=negative +sff_cpld_reg.addr_52_8=0x00040033 +sff_cpld_reg.len_52_8=1 +sff_cpld_reg.bit_offset_52_8=3 + +sff_cpld_reg.mode_53_8=config +sff_cpld_reg.src_53_8=cpld +sff_cpld_reg.frmt_53_8=bit +sff_cpld_reg.pola_53_8=negative +sff_cpld_reg.addr_53_8=0x00040033 +sff_cpld_reg.len_53_8=1 +sff_cpld_reg.bit_offset_53_8=4 + +sff_cpld_reg.mode_54_8=config +sff_cpld_reg.src_54_8=cpld +sff_cpld_reg.frmt_54_8=bit +sff_cpld_reg.pola_54_8=negative +sff_cpld_reg.addr_54_8=0x00040033 +sff_cpld_reg.len_54_8=1 +sff_cpld_reg.bit_offset_54_8=5 + +sff_cpld_reg.mode_55_8=config +sff_cpld_reg.src_55_8=cpld +sff_cpld_reg.frmt_55_8=bit +sff_cpld_reg.pola_55_8=negative +sff_cpld_reg.addr_55_8=0x00040033 +sff_cpld_reg.len_55_8=1 +sff_cpld_reg.bit_offset_55_8=6 + +sff_cpld_reg.mode_56_8=config +sff_cpld_reg.src_56_8=cpld +sff_cpld_reg.frmt_56_8=bit +sff_cpld_reg.pola_56_8=negative +sff_cpld_reg.addr_56_8=0x00040033 +sff_cpld_reg.len_56_8=1 +sff_cpld_reg.bit_offset_56_8=7 diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/cfg_file_name b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/cfg_file_name new file mode 100644 index 000000000000..5f49420441a5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/cfg_file_name @@ -0,0 +1,4 @@ +WB_PLAT_CPLD +WB_PLAT_FAN +WB_PLAT_PSU +WB_PLAT_SFF diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/setup.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/setup.py new file mode 100644 index 000000000000..6c3916921abb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/setup.py @@ -0,0 +1,39 @@ +from setuptools import setup + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation', + license='Apache 2.0', + author='SONiC Team', + author_email='support', + url='', + maintainer='support', + maintainer_email='', + packages=[ + 'sonic_platform', + 'plat_hal', + 'wbutil', + 'eepromutil', + 'hal-config', + 'config', + ], + py_modules=[ + 'hal_pltfm', + 'platform_util', + 'platform_intf', + ], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/src/sonic-device-data/tests/permitted_list b/src/sonic-device-data/tests/permitted_list index 253dfe27c3d9..0bb1998684c0 100644 --- a/src/sonic-device-data/tests/permitted_list +++ b/src/sonic-device-data/tests/permitted_list @@ -336,3 +336,9 @@ hybrid_pfc_deadlock_enable sai_pfc_dlr_init_capability appl_param_nof_ports_per_modid sai_disable_srcmacqedstmac_ctrl +svi_my_station_optimization +warmboot_knet_shutdown_mode +sai_stats_support_mask +oversubscribe_mixed_sister_25_50_enable +sai_fdb_entry_l2_discard_src_enable +sai_pfc_defaults_disable From 574da05af5d14374bfdbd7f322ed7c1483cdbf06 Mon Sep 17 00:00:00 2001 From: Philo <135693886+philo-micas@users.noreply.github.com> Date: Thu, 25 Jan 2024 14:54:48 +0800 Subject: [PATCH 2/2] Delete 0001-Add-new-platform-m2-w6510-48v-on-202305-branch.patch --- ...atform-m2-w6510-48v-on-202305-branch.patch | 91701 ---------------- 1 file changed, 91701 deletions(-) delete mode 100644 0001-Add-new-platform-m2-w6510-48v-on-202305-branch.patch diff --git a/0001-Add-new-platform-m2-w6510-48v-on-202305-branch.patch b/0001-Add-new-platform-m2-w6510-48v-on-202305-branch.patch deleted file mode 100644 index 24698e47beec..000000000000 --- a/0001-Add-new-platform-m2-w6510-48v-on-202305-branch.patch +++ /dev/null @@ -1,91701 +0,0 @@ -From ed74bb454407a5577bfe9c290527741ba48c4bf7 Mon Sep 17 00:00:00 2001 -From: philo -Date: Sun, 21 Jan 2024 19:25:16 -0800 -Subject: [PATCH] Add-new-platform-m2-w6510-48v-on-202305-branch - -Signed-off-by: philo ---- - .gitignore | 2 +- - .../M2-W6510-48V8C/hwsku.json | 172 + - .../M2-W6510-48V8C/port_config.ini | 57 + - .../M2-W6510-48V8C/sai.profile | 1 + - ...d3-m2-w6510-48v8c-48x25G+8x100G.config.bcm | 605 ++++ - .../custom_led.bin | Bin 0 -> 236 bytes - .../default_sku | 1 + - .../x86_64-micas_m2-w6510-48v8c-r0/dev.xml | 420 +++ - .../dev_exhaust.xml | 420 +++ - .../x86_64-micas_m2-w6510-48v8c-r0/fru.py | 961 ++++++ - .../x86_64-micas_m2-w6510-48v8c-r0/hwsku.json | 172 + - .../installer.conf | 2 + - .../led_proc_init.soc | 7 + - .../media_settings.json | 2020 ++++++++++++ - .../x86_64-micas_m2-w6510-48v8c-r0/monitor.py | 402 +++ - .../x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml | 440 +++ - .../platform.json | 819 +++++ - .../platform_asic | 1 + - .../platform_components.json | 37 + - .../plugins/sfputil.py | 243 ++ - .../plugins/ssd_util.py | 311 ++ - .../pmon_daemon_control.json | 3 + - .../system_health_monitoring_config.json | 0 - platform/broadcom/one-image.mk | 1 + - platform/broadcom/platform-modules-micas.dep | 9 + - platform/broadcom/platform-modules-micas.mk | 10 + - platform/broadcom/rules.dep | 1 + - platform/broadcom/rules.mk | 1 + - .../sonic-platform-modules-micas/LICENSE | 14 + - .../common/Makefile | 41 + - .../common/app/Makefile | 25 + - .../common/app/dev_util/Makefile | 30 + - .../common/app/dev_util/dfd_debug.c | 43 + - .../common/app/dev_util/dfd_utest.c | 2121 +++++++++++++ - .../common/app/dev_util/dfd_utest.h | 109 + - .../common/app/fw_upgrade/Makefile | 18 + - .../common/app/fw_upgrade/Rules.mk | 42 + - .../common/app/fw_upgrade/fw_upgrade/Makefile | 39 + - .../app/fw_upgrade/fw_upgrade/fw_upgrade.c | 1632 ++++++++++ - .../fw_upgrade/fw_upgrade/fw_upgrade_debug.c | 51 + - .../fw_upgrade/include/fw_upgrade.h | 230 ++ - .../fw_upgrade/include/fw_upgrade_debug.h | 25 + - .../common/lib/algorithm/__init__.py | 0 - .../common/lib/algorithm/hysteresis.py | 169 + - .../common/lib/algorithm/openloop.py | 104 + - .../common/lib/algorithm/pid.py | 106 + - .../common/lib/eepromutil/__init__.py | 0 - .../common/lib/eepromutil/cust_fru.py | 135 + - .../common/lib/eepromutil/fantlv.py | 192 ++ - .../common/lib/eepromutil/fru.py | 961 ++++++ - .../common/lib/eepromutil/onietlv.py | 441 +++ - .../common/lib/plat_hal/__init__.py | 0 - .../common/lib/plat_hal/baseutil.py | 164 + - .../common/lib/plat_hal/chassisbase.py | 318 ++ - .../common/lib/plat_hal/component.py | 33 + - .../common/lib/plat_hal/cpld.py | 66 + - .../common/lib/plat_hal/cpu.py | 48 + - .../common/lib/plat_hal/dcdc.py | 11 + - .../common/lib/plat_hal/devicebase.py | 351 +++ - .../common/lib/plat_hal/fan.py | 417 +++ - .../common/lib/plat_hal/interface.py | 1334 ++++++++ - .../common/lib/plat_hal/led.py | 52 + - .../common/lib/plat_hal/onie_e2.py | 127 + - .../common/lib/plat_hal/osutil.py | 440 +++ - .../common/lib/plat_hal/psu.py | 701 +++++ - .../common/lib/plat_hal/rotor.py | 149 + - .../common/lib/plat_hal/sensor.py | 274 ++ - .../common/lib/plat_hal/temp.py | 139 + - .../common/lib/wbutil/__init__.py | 0 - .../common/lib/wbutil/baseutil.py | 38 + - .../common/lib/wbutil/smbus.py | 772 +++++ - .../kernel_drivers_blacklist.conf | 7 + - .../common/modules/COPYING | 20 + - .../common/modules/GPL-2.0 | 359 +++ - .../common/modules/Makefile | 62 + - .../common/modules/dfd_tlveeprom.c | 516 +++ - .../common/modules/dfd_tlveeprom.h | 121 + - .../common/modules/fpga_i2c.h | 133 + - .../common/modules/hw_test.c | 608 ++++ - .../common/modules/hw_test.h | 31 + - .../common/modules/intel_spi/Makefile | 22 + - .../modules/intel_spi/include/intel_spi.h | 23 + - .../common/modules/intel_spi/intel_spi.c | 966 ++++++ - .../common/modules/intel_spi/intel_spi_pci.c | 106 + - .../modules/intel_spi/intel_spi_platform.c | 168 + - .../common/modules/linux-5.10/Makefile | 37 + - .../common/modules/linux-5.10/wb_at24.c | 861 +++++ - .../common/modules/linux-5.10/wb_csu550.c | 236 ++ - .../modules/linux-5.10/wb_i2c_algo_bit.c | 725 +++++ - .../common/modules/linux-5.10/wb_i2c_gpio.c | 431 +++ - .../modules/linux-5.10/wb_i2c_gpio_device.c | 133 + - .../common/modules/linux-5.10/wb_i2c_i801.c | 2114 +++++++++++++ - .../common/modules/linux-5.10/wb_i2c_ismt.c | 1105 +++++++ - .../modules/linux-5.10/wb_i2c_mux_pca954x.c | 1332 ++++++++ - .../modules/linux-5.10/wb_i2c_mux_pca954x.h | 67 + - .../modules/linux-5.10/wb_i2c_mux_pca9641.c | 1396 +++++++++ - .../modules/linux-5.10/wb_i2c_mux_pca9641.h | 64 + - .../common/modules/linux-5.10/wb_ina3221.c | 1031 ++++++ - .../common/modules/linux-5.10/wb_isl68137.c | 572 ++++ - .../common/modules/linux-5.10/wb_lm75.c | 992 ++++++ - .../common/modules/linux-5.10/wb_lm75.h | 40 + - .../common/modules/linux-5.10/wb_pmbus.h | 535 ++++ - .../common/modules/linux-5.10/wb_pmbus_core.c | 2780 +++++++++++++++++ - .../common/modules/linux-5.10/wb_tmp401.c | 1010 ++++++ - .../common/modules/linux-5.10/wb_tps53622.c | 265 ++ - .../common/modules/linux-5.10/wb_ucd9000.c | 676 ++++ - .../common/modules/linux-5.10/wb_xdpe12284.c | 495 +++ - .../modules/linux-5.10/wb_xdpe132g5c_pmbus.c | 277 ++ - .../common/modules/phy/Makefile | 23 + - .../common/modules/phy/mdio_bitbang.c | 232 ++ - .../common/modules/phy/mdio_gpio.c | 217 ++ - .../common/modules/phy/wb_mdio_gpio_device.c | 110 + - .../common/modules/pinctrl/Makefile | 17 + - .../common/modules/pinctrl/core.h | 249 ++ - .../common/modules/pinctrl/wb_gpio_c3000.c | 452 +++ - .../modules/pinctrl/wb_gpio_c3000_device.c | 69 + - .../common/modules/pinctrl/wb_pinctrl_intel.c | 1829 +++++++++++ - .../common/modules/pinctrl/wb_pinctrl_intel.h | 275 ++ - .../common/modules/plat_sysfs/Makefile | 20 + - .../modules/plat_sysfs/dev_cfg/Makefile | 25 + - .../modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c | 815 +++++ - .../plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c | 351 +++ - .../plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c | 236 ++ - .../plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c | 771 +++++ - .../plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c | 82 + - .../plat_sysfs/dev_cfg/dfd_fan_driver.c | 201 ++ - .../modules/plat_sysfs/dev_cfg/dfd_module.c | 95 + - .../plat_sysfs/dev_cfg/dfd_psu_driver.c | 70 + - .../plat_sysfs/dev_cfg/dfd_sensors_driver.c | 149 + - .../plat_sysfs/dev_cfg/dfd_sff_driver.c | 56 + - .../plat_sysfs/dev_cfg/dfd_slot_driver.c | 27 + - .../plat_sysfs/dev_cfg/include/dfd_cfg.h | 99 + - .../dev_cfg/include/dfd_cfg_adapter.h | 46 + - .../plat_sysfs/dev_cfg/include/dfd_cfg_file.h | 37 + - .../plat_sysfs/dev_cfg/include/dfd_cfg_info.h | 119 + - .../dev_cfg/include/dfd_cfg_listnode.h | 30 + - .../dev_cfg/include/dfd_fan_driver.h | 18 + - .../plat_sysfs/dev_cfg/include/dfd_module.h | 96 + - .../dev_cfg/include/dfd_psu_driver.h | 10 + - .../dev_cfg/include/dfd_sensors_driver.h | 10 + - .../dev_cfg/include/dfd_sff_driver.h | 8 + - .../dev_cfg/include/dfd_slot_driver.h | 6 + - .../modules/plat_sysfs/dev_sysfs/Makefile | 21 + - .../dev_sysfs/include/plat_switch.h | 86 + - .../dev_sysfs/include/sysfs_common.h | 90 + - .../modules/plat_sysfs/dev_sysfs/plat_fan.c | 501 +++ - .../modules/plat_sysfs/dev_sysfs/plat_psu.c | 426 +++ - .../plat_sysfs/dev_sysfs/plat_sensor.c | 452 +++ - .../modules/plat_sysfs/dev_sysfs/plat_sff.c | 287 ++ - .../modules/plat_sysfs/dev_sysfs/plat_slot.c | 663 ++++ - .../plat_sysfs/dev_sysfs/plat_switch.c | 131 + - .../common/modules/platform_common.h | 74 + - .../common/modules/platform_common_module.c | 210 ++ - .../common/modules/sdhci/Makefile | 18 + - .../common/modules/sdhci/cqhci.h | 242 ++ - .../common/modules/sdhci/sdhci-pci-arasan.c | 331 ++ - .../common/modules/sdhci/sdhci-pci-core.c | 2566 +++++++++++++++ - .../common/modules/sdhci/sdhci-pci-dwc-mshc.c | 84 + - .../common/modules/sdhci/sdhci-pci-gli.c | 865 +++++ - .../common/modules/sdhci/sdhci-pci-o2micro.c | 862 +++++ - .../common/modules/sdhci/sdhci-pci.h | 203 ++ - .../common/modules/sdhci/sdhci.h | 811 +++++ - .../common/modules/spi-bitbang-txrx.h | 107 + - .../common/modules/wb_eeprom_93xx46.c | 558 ++++ - .../common/modules/wb_fpga_i2c_bus_drv.c | 1120 +++++++ - .../common/modules/wb_fpga_pca954x_drv.c | 534 ++++ - .../common/modules/wb_fpga_pcie.c | 164 + - .../common/modules/wb_gpio_d1500.c | 367 +++ - .../common/modules/wb_gpio_device.c | 54 + - .../common/modules/wb_i2c_dev.c | 815 +++++ - .../common/modules/wb_i2c_dev.h | 20 + - .../common/modules/wb_i2c_ocores.c | 1143 +++++++ - .../common/modules/wb_i2c_ocores.h | 28 + - .../common/modules/wb_io_dev.c | 571 ++++ - .../common/modules/wb_io_dev.h | 21 + - .../common/modules/wb_lpc_drv.c | 166 + - .../common/modules/wb_lpc_drv.h | 18 + - .../common/modules/wb_mac_bsc.c | 845 +++++ - .../common/modules/wb_optoe.c | 1192 +++++++ - .../common/modules/wb_pcie_dev.c | 770 +++++ - .../common/modules/wb_pcie_dev.h | 26 + - .../common/modules/wb_platform_i2c_dev.c | 749 +++++ - .../common/modules/wb_platform_i2c_dev.h | 19 + - .../common/modules/wb_spi_93xx46.c | 111 + - .../common/modules/wb_spi_dev.c | 684 ++++ - .../common/modules/wb_spi_dev.h | 17 + - .../common/modules/wb_spi_gpio.c | 477 +++ - .../common/modules/wb_spi_gpio_device.c | 163 + - .../common/modules/wb_spi_nor_device.c | 87 + - .../common/modules/wb_spi_ocores.c | 1025 ++++++ - .../common/modules/wb_spi_ocores.h | 21 + - .../common/modules/wb_uio_irq.c | 282 ++ - .../common/modules/wb_wdt.c | 1187 +++++++ - .../common/modules/wb_wdt.h | 53 + - .../common/modules/wb_xdpe132g5c.c | 574 ++++ - .../common/script/auto_update.py | 196 ++ - .../common/script/avscontrol.py | 203 ++ - .../common/script/dev_monitor.py | 303 ++ - .../common/script/drv_update.py | 152 + - .../common/script/generate_airflow.py | 254 ++ - .../common/script/hal_fanctrl.py | 1135 +++++++ - .../common/script/hal_ledctrl.py | 830 +++++ - .../common/script/hal_pltfm.py | 492 +++ - .../common/script/intelligent_monitor.py | 144 + - .../script/intelligent_monitor/monitor_fan.py | 284 ++ - .../common/script/platform_common.py | 186 ++ - .../common/script/platform_config.py | 192 ++ - .../common/script/platform_driver.py | 258 ++ - .../common/script/platform_e2.py | 439 +++ - .../common/script/platform_intf.py | 384 +++ - .../common/script/platform_ipmi.py | 92 + - .../common/script/platform_manufacturer.py | 562 ++++ - .../common/script/platform_process.py | 413 +++ - .../common/script/platform_sensors.py | 272 ++ - .../common/script/platform_test.py | 142 + - .../common/script/platform_util.py | 838 +++++ - .../common/script/pmon_syslog.py | 519 +++ - .../common/script/reboot_cause.py | 183 ++ - .../common/script/reboot_ctrl.py | 150 + - .../common/script/sensors | 8 + - .../common/script/set_eth_mac.py | 274 ++ - .../common/script/sfp_highest_temperatue.py | 148 + - .../common/script/slot_monitor.py | 253 ++ - .../common/script/ssdmon | 82 + - .../common/script/tty_console.py | 91 + - .../common/script/upgrade.py | 991 ++++++ - .../common/script/warm_upgrade.py | 514 +++ - .../common/service/platform_driver.service | 15 + - .../common/service/platform_process.service | 16 + - .../common/sonic_platform/__init__.py | 2 + - .../common/sonic_platform/chassis.py | 530 ++++ - .../common/sonic_platform/component.py | 226 ++ - .../common/sonic_platform/dcdc.py | 85 + - .../common/sonic_platform/eeprom.py | 92 + - .../common/sonic_platform/fan.py | 314 ++ - .../common/sonic_platform/fan_drawer.py | 167 + - .../common/sonic_platform/pcie.py | 21 + - .../common/sonic_platform/platform.py | 24 + - .../common/sonic_platform/psu.py | 359 +++ - .../common/sonic_platform/sfp.py | 634 ++++ - .../common/sonic_platform/thermal.py | 234 ++ - .../common/sonic_platform/watchdog.py | 236 ++ - .../debian/changelog | 5 + - .../debian/compat | 1 + - .../debian/control | 9 + - .../debian/copyright | 15 + - ...tform-modules-micas-m2-w6510-48v8c.install | 1 + - ...form-modules-micas-m2-w6510-48v8c.postinst | 10 + - .../debian/rule.mk | 5 + - .../sonic-platform-modules-micas/debian/rules | 92 + - .../.upgrade_test/cpld_test_header.vme | Bin 0 -> 406 bytes - .../.upgrade_test/fpga_test_header.bin | 10 + - .../m2-w6510-48v8c/Makefile | 28 + - .../x86_64_micas_m2_w6510_48v8c_r0_config.py | 1106 +++++++ - ..._64_micas_m2_w6510_48v8c_r0_port_config.py | 7 + - .../x86_64_micas_m2_w6510_48v8c_r0_device.py | 1371 ++++++++ - ..._micas_m2_w6510_48v8c_r0_exhaust_device.py | 1371 ++++++++ - .../x86_64_micas_m2_w6510_48v8c_r0_monitor.py | 206 ++ - .../m2-w6510-48v8c/modules/driver/Makefile | 12 + - .../modules/driver/wb_i2c_dev_device.c | 140 + - .../driver/wb_i2c_mux_pca954x_device.c | 296 ++ - .../modules/driver/wb_i2c_ocores_device.c | 423 +++ - .../modules/driver/wb_io_dev_device.c | 103 + - .../modules/driver/wb_lpc_drv_device.c | 130 + - .../modules/driver/wb_pcie_dev_device.c | 93 + - .../plat_sysfs_cfg/WB_PLAT_CPLD.cfg | 41 + - .../plat_sysfs_cfg/WB_PLAT_FAN.cfg | 304 ++ - .../plat_sysfs_cfg/WB_PLAT_PSU.cfg | 64 + - .../plat_sysfs_cfg/WB_PLAT_SFF.cfg | 521 +++ - .../plat_sysfs_cfg/cfg_file_name | 4 + - .../m2-w6510-48v8c/setup.py | 39 + - src/sonic-device-data/tests/permitted_list | 6 + - 272 files changed, 89488 insertions(+), 1 deletion(-) - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/hwsku.json - create mode 100755 device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/port_config.ini - create mode 100755 device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/sai.profile - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/custom_led.bin - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/default_sku - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev.xml - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev_exhaust.xml - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/fru.py - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/hwsku.json - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/installer.conf - create mode 100755 device/micas/x86_64-micas_m2-w6510-48v8c-r0/led_proc_init.soc - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/media_settings.json - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/monitor.py - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform.json - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_asic - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_components.json - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/sfputil.py - create mode 100755 device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/ssd_util.py - create mode 100644 device/micas/x86_64-micas_m2-w6510-48v8c-r0/pmon_daemon_control.json - create mode 100755 device/micas/x86_64-micas_m2-w6510-48v8c-r0/system_health_monitoring_config.json - create mode 100644 platform/broadcom/platform-modules-micas.dep - create mode 100644 platform/broadcom/platform-modules-micas.mk - create mode 100644 platform/broadcom/sonic-platform-modules-micas/LICENSE - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/Makefile - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/Makefile - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/Makefile - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_debug.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Makefile - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Rules.mk - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/Makefile - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade_debug.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade_debug.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/__init__.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/hysteresis.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/openloop.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/pid.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/__init__.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/cust_fru.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fantlv.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fru.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/onietlv.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/__init__.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/baseutil.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/chassisbase.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/component.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpld.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpu.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/dcdc.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/devicebase.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/fan.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/interface.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/led.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/onie_e2.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/osutil.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/psu.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/rotor.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/sensor.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/temp.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/__init__.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/baseutil.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/smbus.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modprobe_conf/kernel_drivers_blacklist.conf - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/COPYING - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/GPL-2.0 - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/Makefile - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/fpga_i2c.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/Makefile - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/include/intel_spi.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_pci.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_platform.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/Makefile - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_at24.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_csu550.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_algo_bit.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio_device.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_i801.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_ismt.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ina3221.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_isl68137.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus_core.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tmp401.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tps53622.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ucd9000.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe12284.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe132g5c_pmbus.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/phy/Makefile - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_bitbang.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_gpio.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/phy/wb_mdio_gpio_device.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/Makefile - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/core.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000_device.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/Makefile - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/Makefile - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_fan_driver.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_module.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_psu_driver.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sensors_driver.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sff_driver.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_slot_driver.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_adapter.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_file.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_info.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_listnode.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_fan_driver.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_module.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_psu_driver.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sensors_driver.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sff_driver.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_slot_driver.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/Makefile - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/plat_switch.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/sysfs_common.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_fan.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_psu.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sensor.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sff.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_slot.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_switch.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common_module.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/Makefile - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/cqhci.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-arasan.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-core.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-dwc-mshc.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-gli.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-o2micro.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/spi-bitbang-txrx.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_eeprom_93xx46.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_i2c_bus_drv.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pca954x_drv.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pcie.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_d1500.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_device.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mac_bsc.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_optoe.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_93xx46.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio_device.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_nor_device.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_uio_irq.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.h - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/modules/wb_xdpe132g5c.c - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/auto_update.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/avscontrol.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/dev_monitor.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/drv_update.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/generate_airflow.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/hal_fanctrl.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/hal_ledctrl.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/hal_pltfm.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor/monitor_fan.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_common.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_config.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_driver.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_e2.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_intf.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_ipmi.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_manufacturer.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_process.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_sensors.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_test.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/platform_util.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/pmon_syslog.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/reboot_cause.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/reboot_ctrl.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/sensors - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/set_eth_mac.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/sfp_highest_temperatue.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/slot_monitor.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/ssdmon - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/tty_console.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/upgrade.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/common/script/warm_upgrade.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/service/platform_driver.service - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/service/platform_process.service - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/__init__.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/chassis.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/component.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/dcdc.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/eeprom.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan_drawer.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/pcie.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/platform.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/psu.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/sfp.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/thermal.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/watchdog.py - create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/changelog - create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/compat - create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/control - create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/copyright - create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.install - create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.postinst - create mode 100644 platform/broadcom/sonic-platform-modules-micas/debian/rule.mk - create mode 100755 platform/broadcom/sonic-platform-modules-micas/debian/rules - create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/cpld_test_header.vme - create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/fpga_test_header.bin - create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/Makefile - create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_config.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_port_config.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_device.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_exhaust_device.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_monitor.py - create mode 100755 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/Makefile - create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_dev_device.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_mux_pca954x_device.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_ocores_device.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_io_dev_device.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_lpc_drv_device.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_pcie_dev_device.c - create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_CPLD.cfg - create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_FAN.cfg - create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_PSU.cfg - create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_SFF.cfg - create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/cfg_file_name - create mode 100644 platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/setup.py - -diff --git a/.gitignore b/.gitignore -index 406b8038d..a23272e12 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -62,7 +62,7 @@ src/**/*.o - platform/**/*.egg-info - platform/**/*-none-any.whl - platform/**/.pybuild --platform/**/debian/* -+#platform/**/debian/* - !platform/**/debian/control - !platform/**/debian/rules - !platform/**/debian/changelog -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/hwsku.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/hwsku.json -new file mode 100644 -index 000000000..9a5a4d2b6 ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/hwsku.json -@@ -0,0 +1,172 @@ -+{ -+ "interfaces": { -+ "Ethernet1": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet2": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet3": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet4": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet5": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet6": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet7": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet8": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet9": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet10": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet11": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet12": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet13": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet14": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet15": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet16": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet17": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet18": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet19": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet20": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet21": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet22": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet23": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet24": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet25": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet26": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet27": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet28": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet29": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet30": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet31": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet32": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet33": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet34": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet35": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet36": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet37": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet38": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet39": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet40": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet41": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet42": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet43": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet44": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet45": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet46": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet47": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet48": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet49": { -+ "default_brkout_mode": "1x100G" -+ }, -+ "Ethernet53": { -+ "default_brkout_mode": "1x100G" -+ }, -+ "Ethernet57": { -+ "default_brkout_mode": "1x100G" -+ }, -+ "Ethernet61": { -+ "default_brkout_mode": "1x100G" -+ }, -+ "Ethernet65": { -+ "default_brkout_mode": "1x100G" -+ }, -+ "Ethernet69": { -+ "default_brkout_mode": "1x100G" -+ }, -+ "Ethernet73": { -+ "default_brkout_mode": "1x100G" -+ }, -+ "Ethernet77": { -+ "default_brkout_mode": "1x100G" -+ } -+ } -+} -\ No newline at end of file -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/port_config.ini b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/port_config.ini -new file mode 100755 -index 000000000..57d6132aa ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/port_config.ini -@@ -0,0 +1,57 @@ -+# name lanes alias index speed admin_status -+Ethernet1 57 twentyfiveGigE0/1 1 25000 up -+Ethernet2 58 twentyfiveGigE0/2 2 25000 up -+Ethernet3 59 twentyfiveGigE0/3 3 25000 up -+Ethernet4 60 twentyfiveGigE0/4 4 25000 up -+Ethernet5 61 twentyfiveGigE0/5 5 25000 up -+Ethernet6 62 twentyfiveGigE0/6 6 25000 up -+Ethernet7 63 twentyfiveGigE0/7 7 25000 up -+Ethernet8 64 twentyfiveGigE0/8 8 25000 up -+Ethernet9 1 twentyfiveGigE0/9 9 25000 up -+Ethernet10 2 twentyfiveGigE0/10 10 25000 up -+Ethernet11 3 twentyfiveGigE0/11 11 25000 up -+Ethernet12 4 twentyfiveGigE0/12 12 25000 up -+Ethernet13 5 twentyfiveGigE0/13 13 25000 up -+Ethernet14 6 twentyfiveGigE0/14 14 25000 up -+Ethernet15 7 twentyfiveGigE0/15 15 25000 up -+Ethernet16 8 twentyfiveGigE0/16 16 25000 up -+Ethernet17 13 twentyfiveGigE0/17 17 25000 up -+Ethernet18 14 twentyfiveGigE0/18 18 25000 up -+Ethernet19 15 twentyfiveGigE0/19 19 25000 up -+Ethernet20 16 twentyfiveGigE0/20 20 25000 up -+Ethernet21 21 twentyfiveGigE0/21 21 25000 up -+Ethernet22 22 twentyfiveGigE0/22 22 25000 up -+Ethernet23 23 twentyfiveGigE0/23 23 25000 up -+Ethernet24 24 twentyfiveGigE0/24 24 25000 up -+Ethernet25 29 twentyfiveGigE0/25 25 25000 up -+Ethernet26 30 twentyfiveGigE0/26 26 25000 up -+Ethernet27 31 twentyfiveGigE0/27 27 25000 up -+Ethernet28 32 twentyfiveGigE0/28 28 25000 up -+Ethernet29 33 twentyfiveGigE0/29 29 25000 up -+Ethernet30 34 twentyfiveGigE0/30 30 25000 up -+Ethernet31 35 twentyfiveGigE0/31 31 25000 up -+Ethernet32 36 twentyfiveGigE0/32 32 25000 up -+Ethernet33 41 twentyfiveGigE0/33 33 25000 up -+Ethernet34 42 twentyfiveGigE0/34 34 25000 up -+Ethernet35 43 twentyfiveGigE0/35 35 25000 up -+Ethernet36 44 twentyfiveGigE0/36 36 25000 up -+Ethernet37 49 twentyfiveGigE0/37 37 25000 up -+Ethernet38 50 twentyfiveGigE0/38 38 25000 up -+Ethernet39 51 twentyfiveGigE0/39 39 25000 up -+Ethernet40 52 twentyfiveGigE0/40 40 25000 up -+Ethernet41 65 twentyfiveGigE0/41 41 25000 up -+Ethernet42 66 twentyfiveGigE0/42 42 25000 up -+Ethernet43 67 twentyfiveGigE0/43 43 25000 up -+Ethernet44 68 twentyfiveGigE0/44 44 25000 up -+Ethernet45 69 twentyfiveGigE0/45 45 25000 up -+Ethernet46 70 twentyfiveGigE0/46 46 25000 up -+Ethernet47 71 twentyfiveGigE0/47 47 25000 up -+Ethernet48 72 twentyfiveGigE0/48 48 25000 up -+Ethernet49 85,86,87,88 hundredGigE0/1 49 100000 up -+Ethernet53 77,78,79,80 hundredGigE0/2 50 100000 up -+Ethernet57 97,98,99,100 hundredGigE0/3 51 100000 up -+Ethernet61 93,94,95,96 hundredGigE0/4 52 100000 up -+Ethernet65 113,114,115,116 hundredGigE0/5 53 100000 up -+Ethernet69 105,106,107,108 hundredGigE0/6 54 100000 up -+Ethernet73 121,122,123,124 hundredGigE0/7 55 100000 up -+Ethernet77 125,126,127,128 hundredGigE0/8 56 100000 up -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/sai.profile b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/sai.profile -new file mode 100755 -index 000000000..9dffa1046 ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/sai.profile -@@ -0,0 +1 @@ -+SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm -new file mode 100644 -index 000000000..559a49f4c ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm -@@ -0,0 +1,605 @@ -+cancun_dir=/usr/share/sonic/platform/cancun/sdk_6.5.16/ -+l2_mem_entries=32768 -+l3_mem_entries=16384 -+l3_alpm_enable=2 -+ipv6_lpm_128b_enable=0x1 -+l2xmsg_mode=0 -+l3_max_ecmp_mode=1 -+svi_my_station_optimization=1 -+sai_nbr_bcast_ifp_optimized=2 -+sai_stats_support_mask=0x1 -+bcm_num_cos=8 -+bcm_stat_interval=2000000 -+cdma_timeout_usec=3000000 -+core_clock_frequency=1525 -+dpp_clock_ratio=2:3 -+help_cli_enable=1 -+ifp_inports_support_enable=1 -+#lpm_scaling_enable=1 -+max_vp_lags=0 -+mem_cache_enable=0 -+memlist_enable=1 -+miim_intr_enable=0 -+module_64ports=1 -+oversubscribe_mode=1 -+oversubscribe_mixed_sister_25_50_enable=1 -+parity_enable=1 -+parity_correction=1 -+pbmp_gport_stack.0=0x0000000000000000000000000000000000000000000000000000000000000000 -+#pbmp_xport_xe.0=0x00000000000000000000000000000000888ffffffffffff9fffffffffffffffe -+pbmp_xport_xe=0xffffffffffffffffffffffffffffffffffffffffe -+port_flex_enable=1 -+phy_chain_tx_lane_map_physical{57.0}=0x0123 -+phy_chain_tx_lane_map_physical{61.0}=0x0123 -+phy_chain_tx_lane_map_physical{1.0}=0x0123 -+phy_chain_tx_lane_map_physical{5.0}=0x0123 -+phy_chain_tx_lane_map_physical{13.0}=0x0123 -+phy_chain_tx_lane_map_physical{21.0}=0x0123 -+phy_chain_tx_lane_map_physical{29.0}=0x0123 -+phy_chain_tx_lane_map_physical{33.0}=0x0123 -+phy_chain_tx_lane_map_physical{41.0}=0x0123 -+phy_chain_tx_lane_map_physical{49.0}=0x0123 -+phy_chain_tx_lane_map_physical{65.0}=0x3210 -+phy_chain_tx_lane_map_physical{69.0}=0x3210 -+phy_chain_tx_lane_map_physical{85.0}=0x3210 -+phy_chain_tx_lane_map_physical{77.0}=0x0213 -+phy_chain_tx_lane_map_physical{97.0}=0x3210 -+phy_chain_tx_lane_map_physical{93.0}=0x0213 -+phy_chain_tx_lane_map_physical{113.0}=0x3210 -+phy_chain_tx_lane_map_physical{105.0}=0x0213 -+phy_chain_tx_lane_map_physical{121.0}=0x3120 -+phy_chain_tx_lane_map_physical{125.0}=0x1203 -+ -+phy_chain_rx_lane_map_physical{57.0}=0x1032 -+phy_chain_rx_lane_map_physical{61.0}=0x1032 -+phy_chain_rx_lane_map_physical{1.0}=0x1032 -+phy_chain_rx_lane_map_physical{5.0}=0x1032 -+phy_chain_rx_lane_map_physical{13.0}=0x1032 -+phy_chain_rx_lane_map_physical{21.0}=0x1032 -+phy_chain_rx_lane_map_physical{29.0}=0x1032 -+phy_chain_rx_lane_map_physical{33.0}=0x1032 -+phy_chain_rx_lane_map_physical{41.0}=0x1032 -+phy_chain_rx_lane_map_physical{49.0}=0x1032 -+phy_chain_rx_lane_map_physical{65.0}=0x2301 -+phy_chain_rx_lane_map_physical{69.0}=0x2301 -+phy_chain_rx_lane_map_physical{85.0}=0x1032 -+phy_chain_rx_lane_map_physical{77.0}=0x1032 -+phy_chain_rx_lane_map_physical{97.0}=0x1032 -+phy_chain_rx_lane_map_physical{93.0}=0x1032 -+phy_chain_rx_lane_map_physical{113.0}=0x1032 -+phy_chain_rx_lane_map_physical{105.0}=0x1032 -+phy_chain_rx_lane_map_physical{121.0}=0x2031 -+phy_chain_rx_lane_map_physical{125.0}=0x1023 -+ -+portmap_57=57:25 -+portmap_58=58:25 -+portmap_59=59:25 -+portmap_60=60:25 -+portmap_61=61:25 -+portmap_62=62:25 -+portmap_63=63:25 -+portmap_64=64:25 -+portmap_1=1:25 -+portmap_2=2:25 -+portmap_3=3:25 -+portmap_4=4:25 -+portmap_5=5:25 -+portmap_6=6:25 -+portmap_7=7:25 -+portmap_8=8:25 -+portmap_13=13:25 -+portmap_14=14:25 -+portmap_15=15:25 -+portmap_16=16:25 -+portmap_21=21:25 -+portmap_22=22:25 -+portmap_23=23:25 -+portmap_24=24:25 -+portmap_29=29:25 -+portmap_30=30:25 -+portmap_31=31:25 -+portmap_32=32:25 -+portmap_33=33:25 -+portmap_34=34:25 -+portmap_35=35:25 -+portmap_36=36:25 -+portmap_41=41:25 -+portmap_42=42:25 -+portmap_43=43:25 -+portmap_44=44:25 -+portmap_49=49:25 -+portmap_50=50:25 -+portmap_51=51:25 -+portmap_52=52:25 -+portmap_67=65:25 -+portmap_68=66:25 -+portmap_69=67:25 -+portmap_70=68:25 -+portmap_71=69:25 -+portmap_72=70:25 -+portmap_73=71:25 -+portmap_74=72:25 -+portmap_87=85:100 -+portmap_79=77:100 -+portmap_99=97:100 -+portmap_95=93:100 -+portmap_115=113:100 -+portmap_107=105:100 -+portmap_123=121:100 -+portmap_127=125:100 -+ -+dport_map_port_57=1 -+dport_map_port_58=2 -+dport_map_port_59=3 -+dport_map_port_60=4 -+dport_map_port_61=5 -+dport_map_port_62=6 -+dport_map_port_63=7 -+dport_map_port_64=8 -+dport_map_port_1=9 -+dport_map_port_2=10 -+dport_map_port_3=11 -+dport_map_port_4=12 -+dport_map_port_5=13 -+dport_map_port_6=14 -+dport_map_port_7=15 -+dport_map_port_8=16 -+dport_map_port_13=17 -+dport_map_port_14=18 -+dport_map_port_15=19 -+dport_map_port_16=20 -+dport_map_port_21=21 -+dport_map_port_22=22 -+dport_map_port_23=23 -+dport_map_port_24=24 -+dport_map_port_29=25 -+dport_map_port_30=26 -+dport_map_port_31=27 -+dport_map_port_32=28 -+dport_map_port_33=29 -+dport_map_port_34=30 -+dport_map_port_35=31 -+dport_map_port_36=32 -+dport_map_port_41=33 -+dport_map_port_42=34 -+dport_map_port_43=35 -+dport_map_port_44=36 -+dport_map_port_49=37 -+dport_map_port_50=38 -+dport_map_port_51=39 -+dport_map_port_52=40 -+dport_map_port_67=41 -+dport_map_port_68=42 -+dport_map_port_69=43 -+dport_map_port_70=44 -+dport_map_port_71=45 -+dport_map_port_72=46 -+dport_map_port_73=47 -+dport_map_port_74=48 -+dport_map_port_87=49 -+dport_map_port_79=50 -+dport_map_port_99=51 -+dport_map_port_95=52 -+dport_map_port_115=53 -+dport_map_port_107=54 -+dport_map_port_123=55 -+dport_map_port_127=56 -+ -+phy_chain_tx_polarity_flip_physical{57.0}=0x1 -+phy_chain_tx_polarity_flip_physical{58.0}=0x0 -+phy_chain_tx_polarity_flip_physical{59.0}=0x1 -+phy_chain_tx_polarity_flip_physical{60.0}=0x0 -+phy_chain_tx_polarity_flip_physical{61.0}=0x1 -+phy_chain_tx_polarity_flip_physical{62.0}=0x0 -+phy_chain_tx_polarity_flip_physical{63.0}=0x1 -+phy_chain_tx_polarity_flip_physical{64.0}=0x0 -+phy_chain_tx_polarity_flip_physical{1.0}=0x0 -+phy_chain_tx_polarity_flip_physical{2.0}=0x0 -+phy_chain_tx_polarity_flip_physical{3.0}=0x0 -+phy_chain_tx_polarity_flip_physical{4.0}=0x0 -+phy_chain_tx_polarity_flip_physical{5.0}=0x0 -+phy_chain_tx_polarity_flip_physical{6.0}=0x0 -+phy_chain_tx_polarity_flip_physical{7.0}=0x0 -+phy_chain_tx_polarity_flip_physical{8.0}=0x0 -+phy_chain_tx_polarity_flip_physical{13.0}=0x0 -+phy_chain_tx_polarity_flip_physical{14.0}=0x0 -+phy_chain_tx_polarity_flip_physical{15.0}=0x0 -+phy_chain_tx_polarity_flip_physical{16.0}=0x0 -+phy_chain_tx_polarity_flip_physical{21.0}=0x0 -+phy_chain_tx_polarity_flip_physical{22.0}=0x0 -+phy_chain_tx_polarity_flip_physical{23.0}=0x0 -+phy_chain_tx_polarity_flip_physical{24.0}=0x0 -+phy_chain_tx_polarity_flip_physical{29.0}=0x0 -+phy_chain_tx_polarity_flip_physical{30.0}=0x0 -+phy_chain_tx_polarity_flip_physical{31.0}=0x0 -+phy_chain_tx_polarity_flip_physical{32.0}=0x0 -+phy_chain_tx_polarity_flip_physical{33.0}=0x0 -+phy_chain_tx_polarity_flip_physical{34.0}=0x0 -+phy_chain_tx_polarity_flip_physical{35.0}=0x0 -+phy_chain_tx_polarity_flip_physical{36.0}=0x0 -+phy_chain_tx_polarity_flip_physical{41.0}=0x0 -+phy_chain_tx_polarity_flip_physical{42.0}=0x0 -+phy_chain_tx_polarity_flip_physical{43.0}=0x0 -+phy_chain_tx_polarity_flip_physical{44.0}=0x0 -+phy_chain_tx_polarity_flip_physical{49.0}=0x0 -+phy_chain_tx_polarity_flip_physical{50.0}=0x0 -+phy_chain_tx_polarity_flip_physical{51.0}=0x0 -+phy_chain_tx_polarity_flip_physical{52.0}=0x0 -+phy_chain_tx_polarity_flip_physical{65.0}=0x0 -+phy_chain_tx_polarity_flip_physical{66.0}=0x0 -+phy_chain_tx_polarity_flip_physical{67.0}=0x0 -+phy_chain_tx_polarity_flip_physical{68.0}=0x0 -+phy_chain_tx_polarity_flip_physical{69.0}=0x0 -+phy_chain_tx_polarity_flip_physical{70.0}=0x0 -+phy_chain_tx_polarity_flip_physical{71.0}=0x0 -+phy_chain_tx_polarity_flip_physical{72.0}=0x0 -+phy_chain_tx_polarity_flip_physical{85.0}=0x0 -+phy_chain_tx_polarity_flip_physical{86.0}=0x0 -+phy_chain_tx_polarity_flip_physical{87.0}=0x1 -+phy_chain_tx_polarity_flip_physical{88.0}=0x0 -+phy_chain_tx_polarity_flip_physical{77.0}=0x1 -+phy_chain_tx_polarity_flip_physical{78.0}=0x0 -+phy_chain_tx_polarity_flip_physical{79.0}=0x1 -+phy_chain_tx_polarity_flip_physical{80.0}=0x0 -+phy_chain_tx_polarity_flip_physical{97.0}=0x0 -+phy_chain_tx_polarity_flip_physical{98.0}=0x0 -+phy_chain_tx_polarity_flip_physical{99.0}=0x1 -+phy_chain_tx_polarity_flip_physical{100.0}=0x0 -+phy_chain_tx_polarity_flip_physical{93.0}=0x0 -+phy_chain_tx_polarity_flip_physical{94.0}=0x1 -+phy_chain_tx_polarity_flip_physical{95.0}=0x1 -+phy_chain_tx_polarity_flip_physical{96.0}=0x0 -+phy_chain_tx_polarity_flip_physical{113.0}=0x0 -+phy_chain_tx_polarity_flip_physical{114.0}=0x0 -+phy_chain_tx_polarity_flip_physical{115.0}=0x1 -+phy_chain_tx_polarity_flip_physical{116.0}=0x0 -+phy_chain_tx_polarity_flip_physical{105.0}=0x0 -+phy_chain_tx_polarity_flip_physical{106.0}=0x1 -+phy_chain_tx_polarity_flip_physical{107.0}=0x1 -+phy_chain_tx_polarity_flip_physical{108.0}=0x0 -+phy_chain_tx_polarity_flip_physical{121.0}=0x1 -+phy_chain_tx_polarity_flip_physical{122.0}=0x0 -+phy_chain_tx_polarity_flip_physical{123.0}=0x1 -+phy_chain_tx_polarity_flip_physical{124.0}=0x0 -+phy_chain_tx_polarity_flip_physical{125.0}=0x1 -+phy_chain_tx_polarity_flip_physical{126.0}=0x0 -+phy_chain_tx_polarity_flip_physical{127.0}=0x1 -+phy_chain_tx_polarity_flip_physical{128.0}=0x1 -+ -+phy_chain_rx_polarity_flip_physical{57.0}=0x0 -+phy_chain_rx_polarity_flip_physical{58.0}=0x0 -+phy_chain_rx_polarity_flip_physical{59.0}=0x0 -+phy_chain_rx_polarity_flip_physical{60.0}=0x0 -+phy_chain_rx_polarity_flip_physical{61.0}=0x1 -+phy_chain_rx_polarity_flip_physical{62.0}=0x1 -+phy_chain_rx_polarity_flip_physical{63.0}=0x1 -+phy_chain_rx_polarity_flip_physical{64.0}=0x1 -+phy_chain_rx_polarity_flip_physical{1.0}=0x1 -+phy_chain_rx_polarity_flip_physical{2.0}=0x1 -+phy_chain_rx_polarity_flip_physical{3.0}=0x1 -+phy_chain_rx_polarity_flip_physical{4.0}=0x1 -+phy_chain_rx_polarity_flip_physical{5.0}=0x0 -+phy_chain_rx_polarity_flip_physical{6.0}=0x0 -+phy_chain_rx_polarity_flip_physical{7.0}=0x0 -+phy_chain_rx_polarity_flip_physical{8.0}=0x0 -+phy_chain_rx_polarity_flip_physical{13.0}=0x0 -+phy_chain_rx_polarity_flip_physical{14.0}=0x0 -+phy_chain_rx_polarity_flip_physical{15.0}=0x0 -+phy_chain_rx_polarity_flip_physical{16.0}=0x0 -+phy_chain_rx_polarity_flip_physical{21.0}=0x0 -+phy_chain_rx_polarity_flip_physical{22.0}=0x0 -+phy_chain_rx_polarity_flip_physical{23.0}=0x0 -+phy_chain_rx_polarity_flip_physical{24.0}=0x0 -+phy_chain_rx_polarity_flip_physical{29.0}=0x0 -+phy_chain_rx_polarity_flip_physical{30.0}=0x1 -+phy_chain_rx_polarity_flip_physical{31.0}=0x0 -+phy_chain_rx_polarity_flip_physical{32.0}=0x0 -+phy_chain_rx_polarity_flip_physical{33.0}=0x1 -+phy_chain_rx_polarity_flip_physical{34.0}=0x1 -+phy_chain_rx_polarity_flip_physical{35.0}=0x1 -+phy_chain_rx_polarity_flip_physical{36.0}=0x1 -+phy_chain_rx_polarity_flip_physical{41.0}=0x1 -+phy_chain_rx_polarity_flip_physical{42.0}=0x1 -+phy_chain_rx_polarity_flip_physical{43.0}=0x1 -+phy_chain_rx_polarity_flip_physical{44.0}=0x1 -+phy_chain_rx_polarity_flip_physical{49.0}=0x1 -+phy_chain_rx_polarity_flip_physical{50.0}=0x1 -+phy_chain_rx_polarity_flip_physical{51.0}=0x1 -+phy_chain_rx_polarity_flip_physical{52.0}=0x1 -+phy_chain_rx_polarity_flip_physical{65.0}=0x1 -+phy_chain_rx_polarity_flip_physical{66.0}=0x1 -+phy_chain_rx_polarity_flip_physical{67.0}=0x1 -+phy_chain_rx_polarity_flip_physical{68.0}=0x1 -+phy_chain_rx_polarity_flip_physical{69.0}=0x0 -+phy_chain_rx_polarity_flip_physical{70.0}=0x0 -+phy_chain_rx_polarity_flip_physical{71.0}=0x0 -+phy_chain_rx_polarity_flip_physical{72.0}=0x0 -+phy_chain_rx_polarity_flip_physical{85.0}=0x1 -+phy_chain_rx_polarity_flip_physical{86.0}=0x1 -+phy_chain_rx_polarity_flip_physical{87.0}=0x1 -+phy_chain_rx_polarity_flip_physical{88.0}=0x1 -+phy_chain_rx_polarity_flip_physical{77.0}=0x0 -+phy_chain_rx_polarity_flip_physical{78.0}=0x0 -+phy_chain_rx_polarity_flip_physical{79.0}=0x0 -+phy_chain_rx_polarity_flip_physical{80.0}=0x0 -+phy_chain_rx_polarity_flip_physical{97.0}=0x0 -+phy_chain_rx_polarity_flip_physical{98.0}=0x0 -+phy_chain_rx_polarity_flip_physical{99.0}=0x0 -+phy_chain_rx_polarity_flip_physical{100.0}=0x0 -+phy_chain_rx_polarity_flip_physical{93.0}=0x0 -+phy_chain_rx_polarity_flip_physical{94.0}=0x0 -+phy_chain_rx_polarity_flip_physical{95.0}=0x0 -+phy_chain_rx_polarity_flip_physical{96.0}=0x0 -+phy_chain_rx_polarity_flip_physical{113.0}=0x1 -+phy_chain_rx_polarity_flip_physical{114.0}=0x1 -+phy_chain_rx_polarity_flip_physical{115.0}=0x1 -+phy_chain_rx_polarity_flip_physical{116.0}=0x1 -+phy_chain_rx_polarity_flip_physical{105.0}=0x0 -+phy_chain_rx_polarity_flip_physical{106.0}=0x0 -+phy_chain_rx_polarity_flip_physical{107.0}=0x0 -+phy_chain_rx_polarity_flip_physical{108.0}=0x0 -+phy_chain_rx_polarity_flip_physical{121.0}=0x1 -+phy_chain_rx_polarity_flip_physical{122.0}=0x1 -+phy_chain_rx_polarity_flip_physical{123.0}=0x0 -+phy_chain_rx_polarity_flip_physical{124.0}=0x1 -+phy_chain_rx_polarity_flip_physical{125.0}=0x1 -+phy_chain_rx_polarity_flip_physical{126.0}=0x0 -+phy_chain_rx_polarity_flip_physical{127.0}=0x0 -+phy_chain_rx_polarity_flip_physical{128.0}=0x0 -+ -+serdes_preemphasis_lane0_57=0x0f480d -+serdes_preemphasis_lane1_57=0x0f480d -+serdes_preemphasis_lane2_57=0x0f480d -+serdes_preemphasis_lane3_57=0x0f480d -+serdes_preemphasis_lane0_58=0x0f480d -+serdes_preemphasis_lane1_58=0x0f480d -+serdes_preemphasis_lane2_58=0x0f480d -+serdes_preemphasis_lane3_58=0x0f480d -+serdes_preemphasis_lane0_59=0x0f480d -+serdes_preemphasis_lane1_59=0x0f480d -+serdes_preemphasis_lane2_59=0x0f480d -+serdes_preemphasis_lane3_59=0x0f480d -+serdes_preemphasis_lane0_60=0x0f480d -+serdes_preemphasis_lane1_60=0x0f480d -+serdes_preemphasis_lane2_60=0x0f480d -+serdes_preemphasis_lane3_60=0x0f480d -+serdes_preemphasis_lane0_61=0x0f480d -+serdes_preemphasis_lane1_61=0x0f480d -+serdes_preemphasis_lane2_61=0x0f480d -+serdes_preemphasis_lane3_61=0x0f480d -+serdes_preemphasis_lane0_62=0x0f480d -+serdes_preemphasis_lane1_62=0x0f480d -+serdes_preemphasis_lane2_62=0x0f480d -+serdes_preemphasis_lane3_62=0x0f480d -+serdes_preemphasis_lane0_63=0x0f480d -+serdes_preemphasis_lane1_63=0x0f480d -+serdes_preemphasis_lane2_63=0x0f480d -+serdes_preemphasis_lane3_63=0x0f480d -+serdes_preemphasis_lane0_64=0x0f480d -+serdes_preemphasis_lane1_64=0x0f480d -+serdes_preemphasis_lane2_64=0x0f480d -+serdes_preemphasis_lane3_64=0x0f480d -+serdes_preemphasis_lane0_1=0x0f480d -+serdes_preemphasis_lane1_1=0x0f480d -+serdes_preemphasis_lane2_1=0x0f480d -+serdes_preemphasis_lane3_1=0x0f480d -+serdes_preemphasis_lane0_2=0x0d4b0c -+serdes_preemphasis_lane1_2=0x0d4b0c -+serdes_preemphasis_lane2_2=0x0d4b0c -+serdes_preemphasis_lane3_2=0x0d4b0c -+serdes_preemphasis_lane0_3=0x0f480d -+serdes_preemphasis_lane1_3=0x0f480d -+serdes_preemphasis_lane2_3=0x0f480d -+serdes_preemphasis_lane3_3=0x0f480d -+serdes_preemphasis_lane0_4=0x0d4b0c -+serdes_preemphasis_lane1_4=0x0d4b0c -+serdes_preemphasis_lane2_4=0x0d4b0c -+serdes_preemphasis_lane3_4=0x0d4b0c -+serdes_preemphasis_lane0_5=0x0f480d -+serdes_preemphasis_lane1_5=0x0f480d -+serdes_preemphasis_lane2_5=0x0f480d -+serdes_preemphasis_lane3_5=0x0f480d -+serdes_preemphasis_lane0_6=0x0d4b0c -+serdes_preemphasis_lane1_6=0x0d4b0c -+serdes_preemphasis_lane2_6=0x0d4b0c -+serdes_preemphasis_lane3_6=0x0d4b0c -+serdes_preemphasis_lane0_7=0x0f480d -+serdes_preemphasis_lane1_7=0x0f480d -+serdes_preemphasis_lane2_7=0x0f480d -+serdes_preemphasis_lane3_7=0x0f480d -+serdes_preemphasis_lane0_8=0x0d4b0c -+serdes_preemphasis_lane1_8=0x0d4b0c -+serdes_preemphasis_lane2_8=0x0d4b0c -+serdes_preemphasis_lane3_8=0x0d4b0c -+serdes_preemphasis_lane0_13=0x0f480d -+serdes_preemphasis_lane1_13=0x0f480d -+serdes_preemphasis_lane2_13=0x0f480d -+serdes_preemphasis_lane3_13=0x0f480d -+serdes_preemphasis_lane0_14=0x0d4b0c -+serdes_preemphasis_lane1_14=0x0d4b0c -+serdes_preemphasis_lane2_14=0x0d4b0c -+serdes_preemphasis_lane3_14=0x0d4b0c -+serdes_preemphasis_lane0_15=0x0f480d -+serdes_preemphasis_lane1_15=0x0f480d -+serdes_preemphasis_lane2_15=0x0f480d -+serdes_preemphasis_lane3_15=0x0f480d -+serdes_preemphasis_lane0_16=0x0d4b0c -+serdes_preemphasis_lane1_16=0x0d4b0c -+serdes_preemphasis_lane2_16=0x0d4b0c -+serdes_preemphasis_lane3_16=0x0d4b0c -+serdes_preemphasis_lane0_21=0x0d4b0c -+serdes_preemphasis_lane1_21=0x0d4b0c -+serdes_preemphasis_lane2_21=0x0d4b0c -+serdes_preemphasis_lane3_21=0x0d4b0c -+serdes_preemphasis_lane0_22=0x0d4b0c -+serdes_preemphasis_lane1_22=0x0d4b0c -+serdes_preemphasis_lane2_22=0x0d4b0c -+serdes_preemphasis_lane3_22=0x0d4b0c -+serdes_preemphasis_lane0_23=0x0d4b0c -+serdes_preemphasis_lane1_23=0x0d4b0c -+serdes_preemphasis_lane2_23=0x0d4b0c -+serdes_preemphasis_lane3_23=0x0d4b0c -+serdes_preemphasis_lane0_24=0x0d4b0c -+serdes_preemphasis_lane1_24=0x0d4b0c -+serdes_preemphasis_lane2_24=0x0d4b0c -+serdes_preemphasis_lane3_24=0x0d4b0c -+serdes_preemphasis_lane0_29=0x0d4b0c -+serdes_preemphasis_lane1_29=0x0d4b0c -+serdes_preemphasis_lane2_29=0x0d4b0c -+serdes_preemphasis_lane3_29=0x0d4b0c -+serdes_preemphasis_lane0_30=0x0d4b0c -+serdes_preemphasis_lane1_30=0x0d4b0c -+serdes_preemphasis_lane2_30=0x0d4b0c -+serdes_preemphasis_lane3_30=0x0d4b0c -+serdes_preemphasis_lane0_31=0x0d4b0c -+serdes_preemphasis_lane1_31=0x0d4b0c -+serdes_preemphasis_lane2_31=0x0d4b0c -+serdes_preemphasis_lane3_31=0x0d4b0c -+serdes_preemphasis_lane0_32=0x0d4b0c -+serdes_preemphasis_lane1_32=0x0d4b0c -+serdes_preemphasis_lane2_32=0x0d4b0c -+serdes_preemphasis_lane3_32=0x0d4b0c -+serdes_preemphasis_lane0_33=0x0d4b0c -+serdes_preemphasis_lane1_33=0x0d4b0c -+serdes_preemphasis_lane2_33=0x0d4b0c -+serdes_preemphasis_lane3_33=0x0d4b0c -+serdes_preemphasis_lane0_34=0x0d4b0c -+serdes_preemphasis_lane1_34=0x0d4b0c -+serdes_preemphasis_lane2_34=0x0d4b0c -+serdes_preemphasis_lane3_34=0x0d4b0c -+serdes_preemphasis_lane0_35=0x0d4b0c -+serdes_preemphasis_lane1_35=0x0d4b0c -+serdes_preemphasis_lane2_35=0x0d4b0c -+serdes_preemphasis_lane3_35=0x0d4b0c -+serdes_preemphasis_lane0_36=0x0d4b0c -+serdes_preemphasis_lane1_36=0x0d4b0c -+serdes_preemphasis_lane2_36=0x0d4b0c -+serdes_preemphasis_lane3_36=0x0d4b0c -+serdes_preemphasis_lane0_41=0x0d4b0c -+serdes_preemphasis_lane1_41=0x0d4b0c -+serdes_preemphasis_lane2_41=0x0d4b0c -+serdes_preemphasis_lane3_41=0x0d4b0c -+serdes_preemphasis_lane0_42=0x0d4b0c -+serdes_preemphasis_lane1_42=0x0d4b0c -+serdes_preemphasis_lane2_42=0x0d4b0c -+serdes_preemphasis_lane3_42=0x0d4b0c -+serdes_preemphasis_lane0_43=0x0d4b0c -+serdes_preemphasis_lane1_43=0x0d4b0c -+serdes_preemphasis_lane2_43=0x0d4b0c -+serdes_preemphasis_lane3_43=0x0d4b0c -+serdes_preemphasis_lane0_44=0x0d4b0c -+serdes_preemphasis_lane1_44=0x0d4b0c -+serdes_preemphasis_lane2_44=0x0d4b0c -+serdes_preemphasis_lane3_44=0x0d4b0c -+serdes_preemphasis_lane0_49=0x0f480d -+serdes_preemphasis_lane1_49=0x0f480d -+serdes_preemphasis_lane2_49=0x0f480d -+serdes_preemphasis_lane3_49=0x0f480d -+serdes_preemphasis_lane0_50=0x0d4b0c -+serdes_preemphasis_lane1_50=0x0d4b0c -+serdes_preemphasis_lane2_50=0x0d4b0c -+serdes_preemphasis_lane3_50=0x0d4b0c -+serdes_preemphasis_lane0_51=0x0f480d -+serdes_preemphasis_lane1_51=0x0f480d -+serdes_preemphasis_lane2_51=0x0f480d -+serdes_preemphasis_lane3_51=0x0f480d -+serdes_preemphasis_lane0_52=0x0d4b0c -+serdes_preemphasis_lane1_52=0x0d4b0c -+serdes_preemphasis_lane2_52=0x0d4b0c -+serdes_preemphasis_lane3_52=0x0d4b0c -+serdes_preemphasis_lane0_67=0x0d4b0c -+serdes_preemphasis_lane1_67=0x0d4b0c -+serdes_preemphasis_lane2_67=0x0d4b0c -+serdes_preemphasis_lane3_67=0x0d4b0c -+serdes_preemphasis_lane0_68=0x0d4b0c -+serdes_preemphasis_lane1_68=0x0d4b0c -+serdes_preemphasis_lane2_68=0x0d4b0c -+serdes_preemphasis_lane3_68=0x0d4b0c -+serdes_preemphasis_lane0_69=0x0d4b0c -+serdes_preemphasis_lane1_69=0x0d4b0c -+serdes_preemphasis_lane2_69=0x0d4b0c -+serdes_preemphasis_lane3_69=0x0d4b0c -+serdes_preemphasis_lane0_70=0x0d4b0c -+serdes_preemphasis_lane1_70=0x0d4b0c -+serdes_preemphasis_lane2_70=0x0d4b0c -+serdes_preemphasis_lane3_70=0x0d4b0c -+serdes_preemphasis_lane0_71=0x0d4b0c -+serdes_preemphasis_lane1_71=0x0d4b0c -+serdes_preemphasis_lane2_71=0x0d4b0c -+serdes_preemphasis_lane3_71=0x0d4b0c -+serdes_preemphasis_lane0_72=0x0d4b0c -+serdes_preemphasis_lane1_72=0x0d4b0c -+serdes_preemphasis_lane2_72=0x0d4b0c -+serdes_preemphasis_lane3_72=0x0d4b0c -+serdes_preemphasis_lane0_73=0x0d4b0c -+serdes_preemphasis_lane1_73=0x0d4b0c -+serdes_preemphasis_lane2_73=0x0d4b0c -+serdes_preemphasis_lane3_73=0x0d4b0c -+serdes_preemphasis_lane0_74=0x0d4b0c -+serdes_preemphasis_lane1_74=0x0d4b0c -+serdes_preemphasis_lane2_74=0x0d4b0c -+serdes_preemphasis_lane3_74=0x0d4b0c -+serdes_preemphasis_lane0_87=0x0d4b0c -+serdes_preemphasis_lane1_87=0x0d4b0c -+serdes_preemphasis_lane2_87=0x0d4b0c -+serdes_preemphasis_lane3_87=0x0d4b0c -+serdes_preemphasis_lane0_79=0x0d4b0c -+serdes_preemphasis_lane1_79=0x0d4b0c -+serdes_preemphasis_lane2_79=0x0d4b0c -+serdes_preemphasis_lane3_79=0x0d4b0c -+serdes_preemphasis_lane0_99=0x0d4b0c -+serdes_preemphasis_lane1_99=0x0d4b0c -+serdes_preemphasis_lane2_99=0x0d4b0c -+serdes_preemphasis_lane3_99=0x0d4b0c -+serdes_preemphasis_lane0_95=0x0d4b0c -+serdes_preemphasis_lane1_95=0x0d4b0c -+serdes_preemphasis_lane2_95=0x0d4b0c -+serdes_preemphasis_lane3_95=0x0d4b0c -+serdes_preemphasis_lane0_115=0x0d4b0c -+serdes_preemphasis_lane1_115=0x0d4b0c -+serdes_preemphasis_lane2_115=0x0d4b0c -+serdes_preemphasis_lane3_115=0x0d4b0c -+serdes_preemphasis_lane0_107=0x0d4b0c -+serdes_preemphasis_lane1_107=0x0d4b0c -+serdes_preemphasis_lane2_107=0x0d4b0c -+serdes_preemphasis_lane3_107=0x0d4b0c -+serdes_preemphasis_lane0_123=0x14460a -+serdes_preemphasis_lane1_123=0x14460a -+serdes_preemphasis_lane2_123=0x14460a -+serdes_preemphasis_lane3_123=0x14460a -+serdes_preemphasis_lane0_127=0x14460a -+serdes_preemphasis_lane1_127=0x14460a -+serdes_preemphasis_lane2_127=0x14460a -+serdes_preemphasis_lane3_127=0x14460a -+ -+ -+reglist_enable=1 -+scache_filename=/var/warmboot/wbscache -+schan_intr_enable=0 -+stable_size=0x55000000 -+stable_location=3 -+warmboot_knet_shutdown_mode=1 -+tdma_timeout_usec=3000000 -+ -+#vxlan flex flow mode -+flow_init_mode=1 -+ -+riot_enable=1 -+riot_overlay_l3_intf_mem_size=4096 -+riot_overlay_l3_egress_mem_size=32768 -+riot_overlay_ecmp_resilient_hash_size=16384 -+ -+l3_ecmp_levels=2 -+ -+use_all_splithorizon_groups=1 -+sai_tunnel_support=1 -+ -+#This property allows to enable L2 FDB entry to discard based on Source Mac -+sai_fdb_entry_l2_discard_src_enable=1 -+ -+#RDMA -+sai_pfc_defaults_disable=1 -+sai_optimized_mmu=1 -+ -+#ACL wb count -+ctr_evict_enable=0 -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/custom_led.bin b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/custom_led.bin -new file mode 100644 -index 0000000000000000000000000000000000000000..e02f94e7ed87ffe60524721f4aec68d661880e7c -GIT binary patch -literal 236 -zcmWN~%}N4M7=YpT%$NoC2ayV4HjWWfZN?-t`f=LVkf$CZeDzh_uF%kr>I`FYKD`eLmXf;U;{tHuD;Ze7>$f@av% -zgCSlz(c*=6Vg!#wxw@UXuqvtQF#P>drO^$pZE}t_Ju@=OS5eW|Q7?+4_%^r@%5rR&XfcQvT1^* -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev_exhaust.xml b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev_exhaust.xml -new file mode 100644 -index 000000000..86851af90 ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev_exhaust.xml -@@ -0,0 +1,420 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/fru.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/fru.py -new file mode 100644 -index 000000000..f95164e03 ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/fru.py -@@ -0,0 +1,961 @@ -+#!/usr/bin/python3 -+import collections -+from datetime import datetime, timedelta -+from bitarray import bitarray -+ -+ -+__DEBUG__ = "N" -+ -+ -+class FruException(Exception): -+ def __init__(self, message='fruerror', code=-100): -+ err = 'errcode: {0} message:{1}'.format(code, message) -+ Exception.__init__(self, err) -+ self.code = code -+ self.message = message -+ -+ -+def e_print(err): -+ print("ERROR: " + err) -+ -+ -+def d_print(debug_info): -+ if __DEBUG__ == "Y": -+ print(debug_info) -+ -+ -+class FruUtil(): -+ @staticmethod -+ def decodeLength(value): -+ a = bitarray(8) -+ a.setall(True) -+ a[0:1] = 0 -+ a[1:2] = 0 -+ x = ord(a.tobytes()) -+ return x & ord(value) -+ -+ @staticmethod -+ def minToData(): -+ starttime = datetime(1996, 1, 1, 0, 0, 0) -+ endtime = datetime.now() -+ seconds = (endtime - starttime).total_seconds() -+ mins = seconds // 60 -+ m = int(round(mins)) -+ return m -+ -+ @staticmethod -+ def getTimeFormat(): -+ return datetime.now().strftime('%Y-%m-%d') -+ -+ @staticmethod -+ def getTypeLength(value): -+ if value is None or len(value) == 0: -+ return 0 -+ a = bitarray(8) -+ a.setall(False) -+ a[0:1] = 1 -+ a[1:2] = 1 -+ x = ord(a.tobytes()) -+ return x | len(value) -+ -+ @staticmethod -+ def checksum(b): -+ result = 0 -+ for item in b: -+ result += ord(item) -+ return (0x100 - (result & 0xff)) & 0xff -+ -+ -+class BaseArea(object): -+ SUGGESTED_SIZE_COMMON_HEADER = 8 -+ SUGGESTED_SIZE_INTERNAL_USE_AREA = 72 -+ SUGGESTED_SIZE_CHASSIS_INFO_AREA = 32 -+ SUGGESTED_SIZE_BOARD_INFO_AREA = 80 -+ SUGGESTED_SIZE_PRODUCT_INFO_AREA = 80 -+ -+ INITVALUE = b'\x00' -+ resultvalue = INITVALUE * 256 -+ COMMON_HEAD_VERSION = b'\x01' -+ __childList = None -+ -+ def __init__(self, name="", size=0, offset=0): -+ self.__childList = [] -+ self._offset = offset -+ self.name = name -+ self._size = size -+ self._isPresent = False -+ self._data = b'\x00' * size -+ -+ @property -+ def childList(self): -+ return self.__childList -+ -+ @childList.setter -+ def childList(self, value): -+ self.__childList = value -+ -+ @property -+ def offset(self): -+ return self._offset -+ -+ @offset.setter -+ def offset(self, value): -+ self._offset = value -+ -+ @property -+ def size(self): -+ return self._size -+ -+ @size.setter -+ def size(self, value): -+ self._size = value -+ -+ @property -+ def data(self): -+ return self._data -+ -+ @data.setter -+ def data(self, value): -+ self._data = value -+ -+ @property -+ def isPresent(self): -+ return self._isPresent -+ -+ @isPresent.setter -+ def isPresent(self, value): -+ self._isPresent = value -+ -+ -+class InternalUseArea(BaseArea): -+ pass -+ -+ -+class ChassisInfoArea(BaseArea): -+ pass -+ -+ -+class BoardInfoArea(BaseArea): -+ _boardTime = None -+ _fields = None -+ _mfg_date = None -+ areaversion = None -+ _boardversion = None -+ _language = None -+ -+ def __str__(self): -+ formatstr = "version : %x\n" \ -+ "length : %d \n" \ -+ "language : %x \n" \ -+ "mfg_date : %s \n" \ -+ "boardManufacturer : %s \n" \ -+ "boardProductName : %s \n" \ -+ "boardSerialNumber : %s \n" \ -+ "boardPartNumber : %s \n" \ -+ "fruFileId : %s \n" -+ -+ tmpstr = formatstr % (ord(self.boardversion), self.size, -+ self.language, self.getMfgRealData(), -+ self.boardManufacturer, self.boardProductName, -+ self.boardSerialNumber, self.boardPartNumber, -+ self.fruFileId) -+ for i in range(1, 11): -+ valtmp = "boardextra%d" % i -+ if hasattr(self, valtmp): -+ valtmpval = getattr(self, valtmp) -+ tmpstr += "boardextra%d : %s \n" % (i, valtmpval) -+ else: -+ break -+ -+ return tmpstr -+ -+ def todict(self): -+ dic = collections.OrderedDict() -+ dic["boardversion"] = ord(self.boardversion) -+ dic["boardlength"] = self.size -+ dic["boardlanguage"] = self.language -+ dic["boardmfg_date"] = self.getMfgRealData() -+ dic["boardManufacturer"] = self.boardManufacturer -+ dic["boardProductName"] = self.boardProductName -+ dic["boardSerialNumber"] = self.boardSerialNumber -+ dic["boardPartNumber"] = self.boardPartNumber -+ dic["boardfruFileId"] = self.fruFileId -+ for i in range(1, 11): -+ valtmp = "boardextra%d" % i -+ if hasattr(self, valtmp): -+ valtmpval = getattr(self, valtmp) -+ dic[valtmp] = valtmpval -+ else: -+ break -+ return dic -+ -+ def decodedata(self): -+ index = 0 -+ self.areaversion = self.data[index] -+ index += 1 -+ d_print("decode length :%d class size:%d" % -+ ((ord(self.data[index]) * 8), self.size)) -+ index += 2 -+ -+ timetmp = self.data[index: index + 3] -+ self.mfg_date = ord(timetmp[0]) | ( -+ ord(timetmp[1]) << 8) | (ord(timetmp[2]) << 16) -+ d_print("decode getMfgRealData :%s" % self.getMfgRealData()) -+ index += 3 -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.boardManufacturer = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode boardManufacturer:%s" % self.boardManufacturer) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.boardProductName = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode boardProductName:%s" % self.boardProductName) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.boardSerialNumber = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode boardSerialNumber:%s" % self.boardSerialNumber) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.boardPartNumber = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode boardPartNumber:%s" % self.boardPartNumber) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.fruFileId = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode fruFileId:%s" % self.fruFileId) -+ -+ for i in range(1, 11): -+ valtmp = "boardextra%d" % i -+ if self.data[index] != chr(0xc1): -+ templen = FruUtil.decodeLength(self.data[index]) -+ tmpval = self.data[index + 1: index + templen + 1] -+ setattr(self, valtmp, tmpval) -+ index += templen + 1 -+ d_print("decode boardextra%d:%s" % (i, tmpval)) -+ else: -+ break -+ -+ def fruSetValue(self, field, value): -+ tmp_field = getattr(self, field, None) -+ if tmp_field is not None: -+ setattr(self, field, value) -+ -+ def recalcute(self): -+ d_print("boardInfoArea version:%x" % ord(self.boardversion)) -+ d_print("boardInfoArea length:%d" % self.size) -+ d_print("boardInfoArea language:%x" % self.language) -+ self.mfg_date = FruUtil.minToData() -+ d_print("boardInfoArea mfg_date:%x" % self.mfg_date) -+ -+ self.data = chr(ord(self.boardversion)) + \ -+ chr(self.size // 8) + chr(self.language) -+ -+ self.data += chr(self.mfg_date & 0xFF) -+ self.data += chr((self.mfg_date >> 8) & 0xFF) -+ self.data += chr((self.mfg_date >> 16) & 0xFF) -+ -+ d_print("boardInfoArea boardManufacturer:%s" % self.boardManufacturer) -+ typelength = FruUtil.getTypeLength(self.boardManufacturer) -+ self.data += chr(typelength) -+ self.data += self.boardManufacturer -+ -+ d_print("boardInfoArea boardProductName:%s" % self.boardProductName) -+ self.data += chr(FruUtil.getTypeLength(self.boardProductName)) -+ self.data += self.boardProductName -+ -+ d_print("boardInfoArea boardSerialNumber:%s" % self.boardSerialNumber) -+ self.data += chr(FruUtil.getTypeLength(self.boardSerialNumber)) -+ self.data += self.boardSerialNumber -+ -+ d_print("boardInfoArea boardPartNumber:%s" % self.boardPartNumber) -+ self.data += chr(FruUtil.getTypeLength(self.boardPartNumber)) -+ self.data += self.boardPartNumber -+ -+ d_print("boardInfoArea fruFileId:%s" % self.fruFileId) -+ self.data += chr(FruUtil.getTypeLength(self.fruFileId)) -+ self.data += self.fruFileId -+ -+ for i in range(1, 11): -+ valtmp = "boardextra%d" % i -+ if hasattr(self, valtmp): -+ valtmpval = getattr(self, valtmp) -+ d_print("boardInfoArea boardextra%d:%s" % (i, valtmpval)) -+ self.data += chr(FruUtil.getTypeLength(valtmpval)) -+ if valtmpval is not None: -+ self.data += valtmpval -+ else: -+ break -+ -+ self.data += chr(0xc1) -+ -+ if len(self.data) > (self.size - 1): -+ incr = (len(self.data) - self.size) // 8 + 1 -+ self.size += incr * 8 -+ -+ self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] -+ d_print("self data:%d" % len(self.data)) -+ d_print("self size:%d" % self.size) -+ d_print("adjust size:%d" % (self.size - len(self.data) - 1)) -+ self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) -+ -+ # checksum -+ checksum = FruUtil.checksum(self.data) -+ d_print("board info checksum:%x" % checksum) -+ self.data += chr(checksum) -+ -+ def getMfgRealData(self): -+ starttime = datetime(1996, 1, 1, 0, 0, 0) -+ mactime = starttime + timedelta(minutes=self.mfg_date) -+ return mactime -+ -+ @property -+ def language(self): -+ self._language = 25 -+ return self._language -+ -+ @property -+ def mfg_date(self): -+ return self._mfg_date -+ -+ @mfg_date.setter -+ def mfg_date(self, val): -+ self._mfg_date = val -+ -+ @property -+ def boardversion(self): -+ self._boardversion = self.COMMON_HEAD_VERSION -+ return self._boardversion -+ -+ @property -+ def fruFileId(self): -+ return self._FRUFileID -+ -+ @fruFileId.setter -+ def fruFileId(self, val): -+ self._FRUFileID = val -+ -+ @property -+ def boardPartNumber(self): -+ return self._boardPartNumber -+ -+ @boardPartNumber.setter -+ def boardPartNumber(self, val): -+ self._boardPartNumber = val -+ -+ @property -+ def boardSerialNumber(self): -+ return self._boardSerialNumber -+ -+ @boardSerialNumber.setter -+ def boardSerialNumber(self, val): -+ self._boardSerialNumber = val -+ -+ @property -+ def boardProductName(self): -+ return self._boradProductName -+ -+ @boardProductName.setter -+ def boardProductName(self, val): -+ self._boradProductName = val -+ -+ @property -+ def boardManufacturer(self): -+ return self._boardManufacturer -+ -+ @boardManufacturer.setter -+ def boardManufacturer(self, val): -+ self._boardManufacturer = val -+ -+ @property -+ def boardTime(self): -+ return self._boardTime -+ -+ @boardTime.setter -+ def boardTime(self, val): -+ self._boardTime = val -+ -+ @property -+ def fields(self): -+ return self._fields -+ -+ @fields.setter -+ def fields(self, val): -+ self._fields = val -+ -+ -+class ProductInfoArea(BaseArea): -+ _productManufacturer = None -+ _productAssetTag = None -+ _FRUFileID = None -+ _language = None -+ -+ def __str__(self): -+ formatstr = "version : %x\n" \ -+ "length : %d \n" \ -+ "language : %x \n" \ -+ "productManufacturer : %s \n" \ -+ "productName : %s \n" \ -+ "productPartModelName: %s \n" \ -+ "productVersion : %s \n" \ -+ "productSerialNumber : %s \n" \ -+ "productAssetTag : %s \n" \ -+ "fruFileId : %s \n" -+ -+ tmpstr = formatstr % (ord(self.areaversion), self.size, -+ self.language, self.productManufacturer, -+ self.productName, self.productPartModelName, -+ self.productVersion, self.productSerialNumber, -+ self.productAssetTag, self.fruFileId) -+ -+ for i in range(1, 11): -+ valtmp = "productextra%d" % i -+ if hasattr(self, valtmp): -+ valtmpval = getattr(self, valtmp) -+ tmpstr += "productextra%d : %s \n" % (i, valtmpval) -+ else: -+ break -+ -+ return tmpstr -+ -+ def todict(self): -+ dic = collections.OrderedDict() -+ dic["productversion"] = ord(self.areaversion) -+ dic["productlength"] = self.size -+ dic["productlanguage"] = self.language -+ dic["productManufacturer"] = self.productManufacturer -+ dic["productName"] = self.productName -+ dic["productPartModelName"] = self.productPartModelName -+ dic["productVersion"] = int(self.productVersion, 16) -+ dic["productSerialNumber"] = self.productSerialNumber -+ dic["productAssetTag"] = self.productAssetTag -+ dic["productfruFileId"] = self.fruFileId -+ for i in range(1, 11): -+ valtmp = "productextra%d" % i -+ if hasattr(self, valtmp): -+ valtmpval = getattr(self, valtmp) -+ dic[valtmp] = valtmpval -+ else: -+ break -+ return dic -+ -+ def decodedata(self): -+ index = 0 -+ self.areaversion = self.data[index] # 0 -+ index += 1 -+ d_print("decode length %d" % (ord(self.data[index]) * 8)) -+ d_print("class size %d" % self.size) -+ index += 2 -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.productManufacturer = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode productManufacturer:%s" % self.productManufacturer) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.productName = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode productName:%s" % self.productName) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.productPartModelName = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode productPartModelName:%s" % self.productPartModelName) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.productVersion = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode productVersion:%s" % self.productVersion) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.productSerialNumber = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode productSerialNumber:%s" % self.productSerialNumber) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.productAssetTag = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode productAssetTag:%s" % self.productAssetTag) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.fruFileId = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode fruFileId:%s" % self.fruFileId) -+ -+ for i in range(1, 11): -+ valtmp = "productextra%d" % i -+ if self.data[index] != chr(0xc1) and index < self.size - 1: -+ templen = FruUtil.decodeLength(self.data[index]) -+ if templen == 0: -+ break -+ tmpval = self.data[index + 1: index + templen + 1] -+ d_print("decode boardextra%d:%s" % (i, tmpval)) -+ setattr(self, valtmp, tmpval) -+ index += templen + 1 -+ else: -+ break -+ -+ @property -+ def productVersion(self): -+ return self._productVersion -+ -+ @productVersion.setter -+ def productVersion(self, name): -+ self._productVersion = name -+ -+ @property -+ def areaversion(self): -+ self._areaversion = self.COMMON_HEAD_VERSION -+ return self._areaversion -+ -+ @areaversion.setter -+ def areaversion(self, name): -+ self._areaversion = name -+ -+ @property -+ def language(self): -+ self._language = 25 -+ return self._language -+ -+ @property -+ def productManufacturer(self): -+ return self._productManufacturer -+ -+ @productManufacturer.setter -+ def productManufacturer(self, name): -+ self._productManufacturer = name -+ -+ @property -+ def productName(self): -+ return self._productName -+ -+ @productName.setter -+ def productName(self, name): -+ self._productName = name -+ -+ @property -+ def productPartModelName(self): -+ return self._productPartModelName -+ -+ @productPartModelName.setter -+ def productPartModelName(self, name): -+ self._productPartModelName = name -+ -+ @property -+ def productSerialNumber(self): -+ return self._productSerialNumber -+ -+ @productSerialNumber.setter -+ def productSerialNumber(self, name): -+ self._productSerialNumber = name -+ -+ @property -+ def productAssetTag(self): -+ return self._productAssetTag -+ -+ @productAssetTag.setter -+ def productAssetTag(self, name): -+ self._productAssetTag = name -+ -+ @property -+ def fruFileId(self): -+ return self._FRUFileID -+ -+ @fruFileId.setter -+ def fruFileId(self, name): -+ self._FRUFileID = name -+ -+ def fruSetValue(self, field, value): -+ tmp_field = getattr(self, field, None) -+ if tmp_field is not None: -+ setattr(self, field, value) -+ -+ def recalcute(self): -+ d_print("product version:%x" % ord(self.areaversion)) -+ d_print("product length:%d" % self.size) -+ d_print("product language:%x" % self.language) -+ self.data = chr(ord(self.areaversion)) + \ -+ chr(self.size // 8) + chr(self.language) -+ -+ typelength = FruUtil.getTypeLength(self.productManufacturer) -+ self.data += chr(typelength) -+ self.data += self.productManufacturer -+ -+ self.data += chr(FruUtil.getTypeLength(self.productName)) -+ self.data += self.productName -+ -+ self.data += chr(FruUtil.getTypeLength(self.productPartModelName)) -+ self.data += self.productPartModelName -+ -+ self.data += chr(FruUtil.getTypeLength(self.productVersion)) -+ self.data += self.productVersion -+ -+ self.data += chr(FruUtil.getTypeLength(self.productSerialNumber)) -+ self.data += self.productSerialNumber -+ -+ self.data += chr(FruUtil.getTypeLength(self.productAssetTag)) -+ if self.productAssetTag is not None: -+ self.data += self.productAssetTag -+ -+ self.data += chr(FruUtil.getTypeLength(self.fruFileId)) -+ self.data += self.fruFileId -+ -+ for i in range(1, 11): -+ valtmp = "productextra%d" % i -+ if hasattr(self, valtmp): -+ valtmpval = getattr(self, valtmp) -+ d_print("boardInfoArea productextra%d:%s" % (i, valtmpval)) -+ self.data += chr(FruUtil.getTypeLength(valtmpval)) -+ if valtmpval is not None: -+ self.data += valtmpval -+ else: -+ break -+ -+ self.data += chr(0xc1) -+ if len(self.data) > (self.size - 1): -+ incr = (len(self.data) - self.size) // 8 + 1 -+ self.size += incr * 8 -+ d_print("self.data:%d" % len(self.data)) -+ d_print("self.size:%d" % self.size) -+ -+ self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] -+ self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) -+ checksum = FruUtil.checksum(self.data) -+ d_print("board info checksum:%x" % checksum) -+ self.data += chr(checksum) -+ -+ -+class MultiRecordArea(BaseArea): -+ pass -+ -+ -+class Field(object): -+ -+ def __init__(self, fieldType="ASCII", fieldData=""): -+ self.fieldData = fieldData -+ self.fieldType = fieldType -+ -+ @property -+ def fieldType(self): -+ return self.fieldType -+ -+ @property -+ def fieldData(self): -+ return self.fieldData -+ -+ -+class ipmifru(BaseArea): -+ _BoardInfoArea = None -+ _ProductInfoArea = None -+ _InternalUseArea = None -+ _ChassisInfoArea = None -+ _multiRecordArea = None -+ _productinfoAreaOffset = BaseArea.INITVALUE -+ _boardInfoAreaOffset = BaseArea.INITVALUE -+ _internalUserAreaOffset = BaseArea.INITVALUE -+ _chassicInfoAreaOffset = BaseArea.INITVALUE -+ _multiRecordAreaOffset = BaseArea.INITVALUE -+ _bindata = None -+ _bodybin = None -+ _version = BaseArea.COMMON_HEAD_VERSION -+ _zeroCheckSum = None -+ _frusize = 256 -+ -+ def __str__(self): -+ tmpstr = "" -+ if self.boardInfoArea.isPresent: -+ tmpstr += "\nboardinfoarea: \n" -+ tmpstr += self.boardInfoArea.__str__() -+ if self.productInfoArea.isPresent: -+ tmpstr += "\nproductinfoarea: \n" -+ tmpstr += self.productInfoArea.__str__() -+ return tmpstr -+ -+ def decodeBin(self, eeprom): -+ commonHead = eeprom[0:8] -+ d_print("decode version %x" % ord(commonHead[0])) -+ if ord(self.COMMON_HEAD_VERSION) != ord(commonHead[0]): -+ raise FruException("HEAD VERSION error,not Fru format!", -10) -+ if FruUtil.checksum(commonHead[0:7]) != ord(commonHead[7]): -+ strtemp = "check header checksum error [cal:%02x data:%02x]" % ( -+ FruUtil.checksum(commonHead[0:7]), ord(commonHead[7])) -+ raise FruException(strtemp, -3) -+ if ord(commonHead[1]) != ord(self.INITVALUE): -+ d_print("Internal Use Area is present") -+ self.internalUseArea = InternalUseArea( -+ name="Internal Use Area", size=self.SUGGESTED_SIZE_INTERNAL_USE_AREA) -+ self.internalUseArea.isPresent = True -+ self.internalUserAreaOffset = ord(commonHead[1]) -+ self.internalUseArea.data = eeprom[self.internalUserAreaOffset * 8: ( -+ self.internalUserAreaOffset * 8 + self.internalUseArea.size)] -+ if ord(commonHead[2]) != ord(self.INITVALUE): -+ d_print("Chassis Info Area is present") -+ self.chassisInfoArea = ChassisInfoArea( -+ name="Chassis Info Area", size=self.SUGGESTED_SIZE_CHASSIS_INFO_AREA) -+ self.chassisInfoArea.isPresent = True -+ self.chassicInfoAreaOffset = ord(commonHead[2]) -+ self.chassisInfoArea.data = eeprom[self.chassicInfoAreaOffset * 8: ( -+ self.chassicInfoAreaOffset * 8 + self.chassisInfoArea.size)] -+ if ord(commonHead[3]) != ord(self.INITVALUE): -+ self.boardInfoArea = BoardInfoArea( -+ name="Board Info Area", size=self.SUGGESTED_SIZE_BOARD_INFO_AREA) -+ self.boardInfoArea.isPresent = True -+ self.boardInfoAreaOffset = ord(commonHead[3]) -+ self.boardInfoArea.size = ord( -+ eeprom[self.boardInfoAreaOffset * 8 + 1]) * 8 -+ d_print("Board Info Area is present size:%d" % -+ (self.boardInfoArea.size)) -+ self.boardInfoArea.data = eeprom[self.boardInfoAreaOffset * 8: ( -+ self.boardInfoAreaOffset * 8 + self.boardInfoArea.size)] -+ if FruUtil.checksum(self.boardInfoArea.data[:-1]) != ord(self.boardInfoArea.data[-1:]): -+ strtmp = "check boardInfoArea checksum error[cal:%02x data:%02x]" % \ -+ (FruUtil.checksum( -+ self.boardInfoArea.data[:-1]), ord(self.boardInfoArea.data[-1:])) -+ raise FruException(strtmp, -3) -+ self.boardInfoArea.decodedata() -+ if ord(commonHead[4]) != ord(self.INITVALUE): -+ d_print("Product Info Area is present") -+ self.productInfoArea = ProductInfoArea( -+ name="Product Info Area ", size=self.SUGGESTED_SIZE_PRODUCT_INFO_AREA) -+ self.productInfoArea.isPresent = True -+ self.productinfoAreaOffset = ord(commonHead[4]) -+ d_print("length offset value: %02x" % -+ ord(eeprom[self.productinfoAreaOffset * 8 + 1])) -+ self.productInfoArea.size = ord( -+ eeprom[self.productinfoAreaOffset * 8 + 1]) * 8 -+ d_print("Product Info Area is present size:%d" % -+ (self.productInfoArea.size)) -+ -+ self.productInfoArea.data = eeprom[self.productinfoAreaOffset * 8: ( -+ self.productinfoAreaOffset * 8 + self.productInfoArea.size)] -+ if FruUtil.checksum(self.productInfoArea.data[:-1]) != ord(self.productInfoArea.data[-1:]): -+ strtmp = "check productInfoArea checksum error [cal:%02x data:%02x]" % ( -+ FruUtil.checksum(self.productInfoArea.data[:-1]), ord(self.productInfoArea.data[-1:])) -+ raise FruException(strtmp, -3) -+ self.productInfoArea.decodedata() -+ if ord(commonHead[5]) != ord(self.INITVALUE): -+ self.multiRecordArea = MultiRecordArea( -+ name="MultiRecord record Area ") -+ d_print("MultiRecord record present") -+ self.multiRecordArea.isPresent = True -+ self.multiRecordAreaOffset = ord(commonHead[5]) -+ self.multiRecordArea.data = eeprom[self.multiRecordAreaOffset * 8: ( -+ self.multiRecordAreaOffset * 8 + self.multiRecordArea.size)] -+ -+ def initDefault(self): -+ self.version = self.COMMON_HEAD_VERSION -+ self.internalUserAreaOffset = self.INITVALUE -+ self.chassicInfoAreaOffset = self.INITVALUE -+ self.boardInfoAreaOffset = self.INITVALUE -+ self.productinfoAreaOffset = self.INITVALUE -+ self.multiRecordAreaOffset = self.INITVALUE -+ self.zeroCheckSum = self.INITVALUE -+ self.offset = self.SUGGESTED_SIZE_COMMON_HEADER -+ self.productInfoArea = None -+ self.internalUseArea = None -+ self.boardInfoArea = None -+ self.chassisInfoArea = None -+ self.multiRecordArea = None -+ # self.recalcute() -+ -+ @property -+ def version(self): -+ return self._version -+ -+ @version.setter -+ def version(self, name): -+ self._version = name -+ -+ @property -+ def internalUserAreaOffset(self): -+ return self._internalUserAreaOffset -+ -+ @internalUserAreaOffset.setter -+ def internalUserAreaOffset(self, obj): -+ self._internalUserAreaOffset = obj -+ -+ @property -+ def chassicInfoAreaOffset(self): -+ return self._chassicInfoAreaOffset -+ -+ @chassicInfoAreaOffset.setter -+ def chassicInfoAreaOffset(self, obj): -+ self._chassicInfoAreaOffset = obj -+ -+ @property -+ def productinfoAreaOffset(self): -+ return self._productinfoAreaOffset -+ -+ @productinfoAreaOffset.setter -+ def productinfoAreaOffset(self, obj): -+ self._productinfoAreaOffset = obj -+ -+ @property -+ def boardInfoAreaOffset(self): -+ return self._boardInfoAreaOffset -+ -+ @boardInfoAreaOffset.setter -+ def boardInfoAreaOffset(self, obj): -+ self._boardInfoAreaOffset = obj -+ -+ @property -+ def multiRecordAreaOffset(self): -+ return self._multiRecordAreaOffset -+ -+ @multiRecordAreaOffset.setter -+ def multiRecordAreaOffset(self, obj): -+ self._multiRecordAreaOffset = obj -+ -+ @property -+ def zeroCheckSum(self): -+ return self._zeroCheckSum -+ -+ @zeroCheckSum.setter -+ def zeroCheckSum(self, obj): -+ self._zeroCheckSum = obj -+ -+ @property -+ def productInfoArea(self): -+ return self._ProductInfoArea -+ -+ @productInfoArea.setter -+ def productInfoArea(self, obj): -+ self._ProductInfoArea = obj -+ -+ @property -+ def internalUseArea(self): -+ return self._InternalUseArea -+ -+ @internalUseArea.setter -+ def internalUseArea(self, obj): -+ self.internalUseArea = obj -+ -+ @property -+ def boardInfoArea(self): -+ return self._BoardInfoArea -+ -+ @boardInfoArea.setter -+ def boardInfoArea(self, obj): -+ self._BoardInfoArea = obj -+ -+ @property -+ def chassisInfoArea(self): -+ return self._ChassisInfoArea -+ -+ @chassisInfoArea.setter -+ def chassisInfoArea(self, obj): -+ self._ChassisInfoArea = obj -+ -+ @property -+ def multiRecordArea(self): -+ return self._multiRecordArea -+ -+ @multiRecordArea.setter -+ def multiRecordArea(self, obj): -+ self._multiRecordArea = obj -+ -+ @property -+ def bindata(self): -+ return self._bindata -+ -+ @bindata.setter -+ def bindata(self, obj): -+ self._bindata = obj -+ -+ @property -+ def bodybin(self): -+ return self._bodybin -+ -+ @bodybin.setter -+ def bodybin(self, obj): -+ self._bodybin = obj -+ -+ def recalcuteCommonHead(self): -+ self.bindata = "" -+ self.offset = self.SUGGESTED_SIZE_COMMON_HEADER -+ d_print("common Header %d" % self.offset) -+ d_print("fru eeprom size %d" % self._frusize) -+ if self.internalUseArea is not None and self.internalUseArea.isPresent: -+ self.internalUserAreaOffset = self.offset // 8 -+ self.offset += self.internalUseArea.size -+ d_print("internalUseArea is present offset:%d" % self.offset) -+ -+ if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: -+ self.chassicInfoAreaOffset = self.offset // 8 -+ self.offset += self.chassisInfoArea.size -+ d_print("chassisInfoArea is present offset:%d" % self.offset) -+ -+ if self.boardInfoArea is not None and self.boardInfoArea.isPresent: -+ self.boardInfoAreaOffset = self.offset // 8 -+ self.offset += self.boardInfoArea.size -+ d_print("boardInfoArea is present offset:%d" % self.offset) -+ d_print("boardInfoArea is present size:%d" % -+ self.boardInfoArea.size) -+ -+ if self.productInfoArea is not None and self.productInfoArea.isPresent: -+ self.productinfoAreaOffset = self.offset // 8 -+ self.offset += self.productInfoArea.size -+ d_print("productInfoArea is present offset:%d" % self.offset) -+ -+ if self.multiRecordArea is not None and self.multiRecordArea.isPresent: -+ self.multiRecordAreaOffset = self.offset // 8 -+ d_print("multiRecordArea is present offset:%d" % self.offset) -+ -+ if self.internalUserAreaOffset == self.INITVALUE: -+ self.internalUserAreaOffset = 0 -+ if self.productinfoAreaOffset == self.INITVALUE: -+ self.productinfoAreaOffset = 0 -+ if self.chassicInfoAreaOffset == self.INITVALUE: -+ self.chassicInfoAreaOffset = 0 -+ if self.boardInfoAreaOffset == self.INITVALUE: -+ self.boardInfoAreaOffset = 0 -+ if self.multiRecordAreaOffset == self.INITVALUE: -+ self.multiRecordAreaOffset = 0 -+ -+ self.zeroCheckSum = (0x100 - ord(self.version) - self.internalUserAreaOffset - self.chassicInfoAreaOffset - self.productinfoAreaOffset -+ - self.boardInfoAreaOffset - self.multiRecordAreaOffset) & 0xff -+ d_print("zerochecksum:%x" % self.zeroCheckSum) -+ self.data = "" -+ self.data += chr(self.version[0]) + chr(self.internalUserAreaOffset) + chr(self.chassicInfoAreaOffset) + chr( -+ self.boardInfoAreaOffset) + chr(self.productinfoAreaOffset) + chr(self.multiRecordAreaOffset) + chr(self.INITVALUE[0]) + chr(self.zeroCheckSum) -+ -+ self.bindata = self.data + self.bodybin -+ totallen = len(self.bindata) -+ d_print("totallen %d" % totallen) -+ if totallen < self._frusize: -+ self.bindata = self.bindata.ljust(self._frusize, chr(self.INITVALUE[0])) -+ else: -+ raise FruException('bin data more than %d' % self._frusize, -2) -+ -+ def recalcutebin(self): -+ self.bodybin = "" -+ if self.internalUseArea is not None and self.internalUseArea.isPresent: -+ d_print("internalUseArea present") -+ self.bodybin += self.internalUseArea.data -+ if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: -+ d_print("chassisInfoArea present") -+ self.bodybin += self.chassisInfoArea.data -+ if self.boardInfoArea is not None and self.boardInfoArea.isPresent: -+ d_print("boardInfoArea present") -+ self.boardInfoArea.recalcute() -+ self.bodybin += self.boardInfoArea.data -+ if self.productInfoArea is not None and self.productInfoArea.isPresent: -+ d_print("productInfoAreapresent") -+ self.productInfoArea.recalcute() -+ self.bodybin += self.productInfoArea.data -+ if self.multiRecordArea is not None and self.multiRecordArea.isPresent: -+ d_print("multiRecordArea present") -+ self.bodybin += self.productInfoArea.data -+ -+ def recalcute(self, fru_eeprom_size=256): -+ self._frusize = fru_eeprom_size -+ self.recalcutebin() -+ self.recalcuteCommonHead() -+ -+ def setValue(self, area, field, value): -+ tmp_area = getattr(self, area, None) -+ if tmp_area is not None: -+ tmp_area.fruSetValue(field, value) -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/hwsku.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/hwsku.json -new file mode 100644 -index 000000000..9a5a4d2b6 ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/hwsku.json -@@ -0,0 +1,172 @@ -+{ -+ "interfaces": { -+ "Ethernet1": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet2": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet3": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet4": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet5": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet6": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet7": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet8": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet9": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet10": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet11": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet12": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet13": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet14": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet15": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet16": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet17": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet18": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet19": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet20": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet21": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet22": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet23": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet24": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet25": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet26": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet27": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet28": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet29": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet30": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet31": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet32": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet33": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet34": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet35": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet36": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet37": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet38": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet39": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet40": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet41": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet42": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet43": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet44": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet45": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet46": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet47": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet48": { -+ "default_brkout_mode": "1x25G" -+ }, -+ "Ethernet49": { -+ "default_brkout_mode": "1x100G" -+ }, -+ "Ethernet53": { -+ "default_brkout_mode": "1x100G" -+ }, -+ "Ethernet57": { -+ "default_brkout_mode": "1x100G" -+ }, -+ "Ethernet61": { -+ "default_brkout_mode": "1x100G" -+ }, -+ "Ethernet65": { -+ "default_brkout_mode": "1x100G" -+ }, -+ "Ethernet69": { -+ "default_brkout_mode": "1x100G" -+ }, -+ "Ethernet73": { -+ "default_brkout_mode": "1x100G" -+ }, -+ "Ethernet77": { -+ "default_brkout_mode": "1x100G" -+ } -+ } -+} -\ No newline at end of file -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/installer.conf b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/installer.conf -new file mode 100644 -index 000000000..7a9fec8cc ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/installer.conf -@@ -0,0 +1,2 @@ -+CONSOLE_SPEED=115200 -+ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="intel_idle.max_cstate=0 idle=poll" -\ No newline at end of file -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/led_proc_init.soc b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/led_proc_init.soc -new file mode 100755 -index 000000000..59238f5cd ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/led_proc_init.soc -@@ -0,0 +1,7 @@ -+m0 load 0 0x3800 /usr/share/sonic/platform/custom_led.bin -+ -+led auto on -+ -+led start -+ -+linkscan SwPortBitMap=xe,ce -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/media_settings.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/media_settings.json -new file mode 100644 -index 000000000..e848307fd ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/media_settings.json -@@ -0,0 +1,2020 @@ -+{ -+ "PORT_MEDIA_SETTINGS": { -+ "49": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C", -+ "lane1": "0x0000000C", -+ "lane2": "0x0000000C", -+ "lane3": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B", -+ "lane1": "0x0000004B", -+ "lane2": "0x0000004B", -+ "lane3": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D", -+ "lane1": "0x0000000D", -+ "lane2": "0x0000000D", -+ "lane3": "0x0000000D" -+ } -+ }, -+ "QSFP+-": { -+ "pre1": { -+ "lane0": "0x00000000", -+ "lane1": "0x00000000", -+ "lane2": "0x00000000", -+ "lane3": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C", -+ "lane1": "0x0000003C", -+ "lane2": "0x0000003C", -+ "lane3": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004", -+ "lane1": "0x00000004", -+ "lane2": "0x00000004", -+ "lane3": "0x00000004" -+ } -+ } -+ }, -+ "50": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C", -+ "lane1": "0x0000000C", -+ "lane2": "0x0000000C", -+ "lane3": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B", -+ "lane1": "0x0000004B", -+ "lane2": "0x0000004B", -+ "lane3": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D", -+ "lane1": "0x0000000D", -+ "lane2": "0x0000000D", -+ "lane3": "0x0000000D" -+ } -+ }, -+ "QSFP+-": { -+ "pre1": { -+ "lane0": "0x00000000", -+ "lane1": "0x00000000", -+ "lane2": "0x00000000", -+ "lane3": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C", -+ "lane1": "0x0000003C", -+ "lane2": "0x0000003C", -+ "lane3": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004", -+ "lane1": "0x00000004", -+ "lane2": "0x00000004", -+ "lane3": "0x00000004" -+ } -+ } -+ }, -+ "51": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C", -+ "lane1": "0x0000000C", -+ "lane2": "0x0000000C", -+ "lane3": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B", -+ "lane1": "0x0000004B", -+ "lane2": "0x0000004B", -+ "lane3": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D", -+ "lane1": "0x0000000D", -+ "lane2": "0x0000000D", -+ "lane3": "0x0000000D" -+ } -+ }, -+ "QSFP+-": { -+ "pre1": { -+ "lane0": "0x00000000", -+ "lane1": "0x00000000", -+ "lane2": "0x00000000", -+ "lane3": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C", -+ "lane1": "0x0000003C", -+ "lane2": "0x0000003C", -+ "lane3": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004", -+ "lane1": "0x00000006", -+ "lane2": "0x00000006", -+ "lane3": "0x00000004" -+ } -+ } -+ }, -+ "52": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C", -+ "lane1": "0x0000000C", -+ "lane2": "0x0000000C", -+ "lane3": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B", -+ "lane1": "0x0000004B", -+ "lane2": "0x0000004B", -+ "lane3": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D", -+ "lane1": "0x0000000D", -+ "lane2": "0x0000000D", -+ "lane3": "0x0000000D" -+ } -+ }, -+ "QSFP+-": { -+ "pre1": { -+ "lane0": "0x00000000", -+ "lane1": "0x00000000", -+ "lane2": "0x00000000", -+ "lane3": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C", -+ "lane1": "0x0000003C", -+ "lane2": "0x0000003C", -+ "lane3": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004", -+ "lane1": "0x00000005", -+ "lane2": "0x00000005", -+ "lane3": "0x00000005" -+ } -+ } -+ }, -+ "53": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C", -+ "lane1": "0x0000000C", -+ "lane2": "0x0000000C", -+ "lane3": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B", -+ "lane1": "0x0000004B", -+ "lane2": "0x0000004B", -+ "lane3": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D", -+ "lane1": "0x0000000D", -+ "lane2": "0x0000000D", -+ "lane3": "0x0000000D" -+ } -+ }, -+ "QSFP+-": { -+ "pre1": { -+ "lane0": "0x00000000", -+ "lane1": "0x00000000", -+ "lane2": "0x00000000", -+ "lane3": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C", -+ "lane1": "0x0000003C", -+ "lane2": "0x0000003C", -+ "lane3": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004", -+ "lane1": "0x00000006", -+ "lane2": "0x00000006", -+ "lane3": "0x00000006" -+ } -+ } -+ }, -+ "54": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C", -+ "lane1": "0x0000000C", -+ "lane2": "0x0000000C", -+ "lane3": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B", -+ "lane1": "0x0000004B", -+ "lane2": "0x0000004B", -+ "lane3": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D", -+ "lane1": "0x0000000D", -+ "lane2": "0x0000000D", -+ "lane3": "0x0000000D" -+ } -+ }, -+ "QSFP+-": { -+ "pre1": { -+ "lane0": "0x00000000", -+ "lane1": "0x00000000", -+ "lane2": "0x00000000", -+ "lane3": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C", -+ "lane1": "0x0000003C", -+ "lane2": "0x0000003C", -+ "lane3": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000005", -+ "lane1": "0x00000005", -+ "lane2": "0x00000005", -+ "lane3": "0x00000005" -+ } -+ } -+ }, -+ "55": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000A", -+ "lane1": "0x0000000A", -+ "lane2": "0x0000000A", -+ "lane3": "0x0000000A" -+ }, -+ "main": { -+ "lane0": "0x00000046", -+ "lane1": "0x00000046", -+ "lane2": "0x00000046", -+ "lane3": "0x00000046" -+ }, -+ "post1": { -+ "lane0": "0x00000014", -+ "lane1": "0x00000014", -+ "lane2": "0x00000014", -+ "lane3": "0x00000014" -+ } -+ }, -+ "QSFP+-": { -+ "pre1": { -+ "lane0": "0x00000000", -+ "lane1": "0x00000000", -+ "lane2": "0x00000001", -+ "lane3": "0x00000001" -+ }, -+ "main": { -+ "lane0": "0x0000003C", -+ "lane1": "0x0000003C", -+ "lane2": "0x0000003C", -+ "lane3": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000006", -+ "lane1": "0x00000006", -+ "lane2": "0x00000006", -+ "lane3": "0x00000006" -+ } -+ } -+ }, -+ "56": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000A", -+ "lane1": "0x0000000A", -+ "lane2": "0x0000000A", -+ "lane3": "0x0000000A" -+ }, -+ "main": { -+ "lane0": "0x00000046", -+ "lane1": "0x00000046", -+ "lane2": "0x00000046", -+ "lane3": "0x00000046" -+ }, -+ "post1": { -+ "lane0": "0x00000014", -+ "lane1": "0x00000014", -+ "lane2": "0x00000014", -+ "lane3": "0x00000014" -+ } -+ }, -+ "QSFP+-": { -+ "pre1": { -+ "lane0": "0x00000000", -+ "lane1": "0x00000000", -+ "lane2": "0x00000000", -+ "lane3": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C", -+ "lane1": "0x0000003C", -+ "lane2": "0x0000003C", -+ "lane3": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000006", -+ "lane1": "0x00000006", -+ "lane2": "0x00000006", -+ "lane3": "0x00000006" -+ } -+ } -+ }, -+ "1": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000006" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "2": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000006" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "3": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000006" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "4": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000005" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "5": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000005" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "6": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000005" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "7": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000005" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "8": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "9": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "10": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "11": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "12": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "13": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "14": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "15": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "16": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "17": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "18": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "19": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "20": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "21": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "22": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "23": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "24": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000002" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "25": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "26": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000002" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "27": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "28": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000002" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "29": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "30": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000002" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "31": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "32": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "33": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "34": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "35": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "36": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "37": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "38": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "39": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000D" -+ }, -+ "main": { -+ "lane0": "0x00000048" -+ }, -+ "post1": { -+ "lane0": "0x0000000F" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "40": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "41": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "42": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "43": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "44": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "45": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "46": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "47": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ }, -+ "48": { -+ "Default": { -+ "pre1": { -+ "lane0": "0x0000000C" -+ }, -+ "main": { -+ "lane0": "0x0000004B" -+ }, -+ "post1": { -+ "lane0": "0x0000000D" -+ } -+ }, -+ "SFP-10G-": { -+ "pre1": { -+ "lane0": "0x00000000" -+ }, -+ "main": { -+ "lane0": "0x0000003C" -+ }, -+ "post1": { -+ "lane0": "0x00000004" -+ } -+ }, -+ "SFP-GB-": { -+ "pre1": { -+ "lane0": "0x00000002" -+ }, -+ "main": { -+ "lane0": "0x0000005F" -+ }, -+ "post1": { -+ "lane0": "0x00000003" -+ } -+ } -+ } -+ } -+} -\ No newline at end of file -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/monitor.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/monitor.py -new file mode 100644 -index 000000000..bdeaf190f ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/monitor.py -@@ -0,0 +1,402 @@ -+#!/usr/bin/python3 -+# * onboard temperature sensors -+# * FAN trays -+# * PSU -+# -+import os -+import xml.etree.ElementTree as ET -+import glob -+import json -+from decimal import Decimal -+from fru import ipmifru -+ -+ -+MAILBOX_DIR = "/sys/bus/i2c/devices/" -+BOARD_ID_PATH = "/sys/module/platform_common/parameters/dfd_my_type" -+BOARD_AIRFLOW_PATH = "/etc/sonic/.airflow" -+ -+ -+CONFIG_NAME = "dev.xml" -+ -+ -+def byteTostr(val): -+ strtmp = '' -+ for value in val: -+ strtmp += chr(value) -+ return strtmp -+ -+ -+def typeTostr(val): -+ if isinstance(val, bytes): -+ strtmp = byteTostr(val) -+ return strtmp -+ return val -+ -+ -+def get_board_id(): -+ if not os.path.exists(BOARD_ID_PATH): -+ return "NA" -+ with open(BOARD_ID_PATH) as fd: -+ id_str = fd.read().strip() -+ return "0x%x" % (int(id_str, 10)) -+ -+ -+def getboardairflow(): -+ if not os.path.exists(BOARD_AIRFLOW_PATH): -+ return "NA" -+ with open(BOARD_AIRFLOW_PATH) as fd: -+ airflow_str = fd.read().strip() -+ data = json.loads(airflow_str) -+ airflow = data.get("board", "NA") -+ return airflow -+ -+ -+boardid = get_board_id() -+boardairflow = getboardairflow() -+ -+ -+DEV_XML_FILE_LIST = [ -+ "dev_" + boardid + "_" + boardairflow + ".xml", -+ "dev_" + boardid + ".xml", -+ "dev_" + boardairflow + ".xml", -+] -+ -+ -+def dev_file_read(path, offset, read_len): -+ retval = "ERR" -+ val_list = [] -+ msg = "" -+ ret = "" -+ fd = -1 -+ -+ if not os.path.exists(path): -+ return False, "%s %s not found" % (retval, path) -+ -+ try: -+ fd = os.open(path, os.O_RDONLY) -+ os.lseek(fd, offset, os.SEEK_SET) -+ ret = os.read(fd, read_len) -+ for item in ret: -+ val_list.append(item) -+ except Exception as e: -+ msg = str(e) -+ return False, "%s %s" % (retval, msg) -+ finally: -+ if fd > 0: -+ os.close(fd) -+ return True, val_list -+ -+ -+def getPMCreg(location): -+ retval = 'ERR' -+ if not os.path.isfile(location): -+ return "%s %s notfound" % (retval, location) -+ try: -+ with open(location, 'r') as fd: -+ retval = fd.read() -+ except Exception as error: -+ return "ERR %s" % str(error) -+ -+ retval = retval.rstrip('\r\n') -+ retval = retval.lstrip(" ") -+ return retval -+ -+ -+# Get a mailbox register -+def get_pmc_register(reg_name): -+ retval = 'ERR' -+ mb_reg_file = reg_name -+ filepath = glob.glob(mb_reg_file) -+ if len(filepath) == 0: -+ return "%s %s notfound" % (retval, mb_reg_file) -+ mb_reg_file = filepath[0] -+ if not os.path.isfile(mb_reg_file): -+ # print mb_reg_file, 'not found !' -+ return "%s %s notfound" % (retval, mb_reg_file) -+ try: -+ with open(mb_reg_file, 'rb') as fd: -+ retval = fd.read() -+ retval = typeTostr(retval) -+ except Exception as error: -+ retval = "%s %s read failed, msg: %s" % (retval, mb_reg_file, str(error)) -+ -+ retval = retval.rstrip('\r\n') -+ retval = retval.lstrip(" ") -+ return retval -+ -+ -+class checktype(): -+ def __init__(self, test1): -+ self.test1 = test1 -+ -+ @staticmethod -+ def getValue(location, bit, data_type, coefficient=1, addend=0): -+ try: -+ value_t = get_pmc_register(location) -+ if value_t.startswith("ERR") or value_t.startswith("NA"): -+ return value_t -+ if data_type == 1: -+ return float('%.1f' % ((float(value_t) / 1000) + addend)) -+ if data_type == 2: -+ return float('%.1f' % (float(value_t) / 100)) -+ if data_type == 3: -+ psu_status = int(value_t, 16) -+ return (psu_status & (1 << bit)) >> bit -+ if data_type == 4: -+ return int(value_t, 10) -+ if data_type == 5: -+ return float('%.1f' % (float(value_t) / 1000 / 1000)) -+ if data_type == 6: -+ return Decimal(float(value_t) * coefficient / 1000).quantize(Decimal('0.000')) -+ return value_t -+ except Exception as e: -+ value_t = "ERR %s" % str(e) -+ return value_t -+ -+ # fanFRU -+ @staticmethod -+ def decodeBinByValue(retval): -+ fru = ipmifru() -+ fru.decodeBin(retval) -+ return fru -+ -+ @staticmethod -+ def getfruValue(prob_t, root, val): -+ try: -+ ret, binval_bytes = dev_file_read(val, 0, 256) -+ if ret is False: -+ return binval_bytes -+ binval = byteTostr(binval_bytes) -+ fanpro = {} -+ ret = checktype.decodeBinByValue(binval) -+ fanpro['fan_type'] = ret.productInfoArea.productName -+ fanpro['hw_version'] = str(int(ret.productInfoArea.productVersion, 16)) -+ fanpro['sn'] = ret.productInfoArea.productSerialNumber -+ fan_display_name_dict = status.getDecodValue(root, "fan_display_name") -+ fan_name = fanpro['fan_type'].strip() -+ if len(fan_display_name_dict) == 0: -+ return fanpro -+ if fan_name not in fan_display_name_dict: -+ prob_t['errcode'] = -1 -+ prob_t['errmsg'] = '%s' % ("ERR fan name: %s not support" % fan_name) -+ else: -+ fanpro['fan_type'] = fan_display_name_dict[fan_name] -+ return fanpro -+ except Exception as error: -+ return "ERR " + str(error) -+ -+ @staticmethod -+ def getslotfruValue(val): -+ try: -+ binval = checktype.getValue(val, 0, 0) -+ if binval.startswith("ERR"): -+ return binval -+ slotpro = {} -+ ret = checktype.decodeBinByValue(binval) -+ slotpro['slot_type'] = ret.boardInfoArea.boardProductName -+ slotpro['hw_version'] = ret.boardInfoArea.boardextra1 -+ slotpro['sn'] = ret.boardInfoArea.boardSerialNumber -+ return slotpro -+ except Exception as error: -+ return "ERR " + str(error) -+ -+ @staticmethod -+ def getpsufruValue(prob_t, root, val): -+ try: -+ psu_match = False -+ binval = checktype.getValue(val, 0, 0) -+ if binval.startswith("ERR"): -+ return binval -+ psupro = {} -+ ret = checktype.decodeBinByValue(binval) -+ psupro['type1'] = ret.productInfoArea.productPartModelName -+ psupro['sn'] = ret.productInfoArea.productSerialNumber -+ psupro['hw_version'] = ret.productInfoArea.productVersion -+ psu_dict = status.getDecodValue(root, "psutype") -+ psupro['type1'] = psupro['type1'].strip() -+ if len(psu_dict) == 0: -+ return psupro -+ for psu_name, display_name in psu_dict.items(): -+ if psu_name.strip() == psupro['type1']: -+ psupro['type1'] = display_name -+ psu_match = True -+ break -+ if psu_match is not True: -+ prob_t['errcode'] = -1 -+ prob_t['errmsg'] = '%s' % ("ERR psu name: %s not support" % psupro['type1']) -+ return psupro -+ except Exception as error: -+ return "ERR " + str(error) -+ -+ -+class status(): -+ def __init__(self, productname): -+ self.productname = productname -+ -+ @staticmethod -+ def getETroot(filename): -+ tree = ET.parse(filename) -+ root = tree.getroot() -+ return root -+ -+ @staticmethod -+ def getDecodValue(collection, decode): -+ decodes = collection.find('decode') -+ testdecode = decodes.find(decode) -+ test = {} -+ if testdecode is None: -+ return test -+ for neighbor in testdecode.iter('code'): -+ test[neighbor.attrib["key"]] = neighbor.attrib["value"] -+ return test -+ -+ @staticmethod -+ def getfileValue(location): -+ return checktype.getValue(location, " ", " ") -+ -+ @staticmethod -+ def getETValue(a, filename, tagname): -+ root = status.getETroot(filename) -+ for neighbor in root.iter(tagname): -+ prob_t = {} -+ prob_t = neighbor.attrib -+ prob_t['errcode'] = 0 -+ prob_t['errmsg'] = '' -+ for pros in neighbor.iter("property"): -+ ret = dict(list(neighbor.attrib.items()) + list(pros.attrib.items())) -+ if ret.get('e2type') == 'fru' and ret.get("name") == "fru": -+ fruval = checktype.getfruValue(prob_t, root, ret["location"]) -+ if isinstance(fruval, str) and fruval.startswith("ERR"): -+ prob_t['errcode'] = -1 -+ prob_t['errmsg'] = fruval -+ break -+ prob_t.update(fruval) -+ continue -+ -+ if ret.get("name") == "psu" and ret.get('e2type') == 'fru': -+ psuval = checktype.getpsufruValue(prob_t, root, ret["location"]) -+ if isinstance(psuval, str) and psuval.startswith("ERR"): -+ prob_t['errcode'] = -1 -+ prob_t['errmsg'] = psuval -+ break -+ prob_t.update(psuval) -+ continue -+ -+ if ret.get("gettype") == "config": -+ prob_t[ret["name"]] = ret["value"] -+ continue -+ -+ if 'type' not in ret.keys(): -+ val = "0" -+ else: -+ val = ret["type"] -+ if 'bit' not in ret.keys(): -+ bit = "0" -+ else: -+ bit = ret["bit"] -+ if 'coefficient' not in ret.keys(): -+ coefficient = 1 -+ else: -+ coefficient = float(ret["coefficient"]) -+ if 'addend' not in ret.keys(): -+ addend = 0 -+ else: -+ addend = float(ret["addend"]) -+ -+ s = checktype.getValue(ret["location"], int(bit), int(val), coefficient, addend) -+ if isinstance(s, str) and s.startswith("ERR"): -+ prob_t['errcode'] = -1 -+ prob_t['errmsg'] = s -+ break -+ if 'default' in ret.keys(): -+ rt = status.getDecodValue(root, ret['decode']) -+ prob_t['errmsg'] = rt[str(s)] -+ if str(s) != ret["default"]: -+ prob_t['errcode'] = -1 -+ break -+ else: -+ if 'decode' in ret.keys(): -+ rt = status.getDecodValue(root, ret['decode']) -+ if (ret['decode'] == "psutype" and s.replace("\x00", "").rstrip() not in rt): -+ prob_t['errcode'] = -1 -+ prob_t['errmsg'] = '%s' % ("ERR psu name: %s not support" % -+ (s.replace("\x00", "").rstrip())) -+ else: -+ s = rt[str(s).replace("\x00", "").rstrip()] -+ name = ret["name"] -+ prob_t[name] = str(s) -+ a.append(prob_t) -+ -+ @staticmethod -+ def getCPUValue(a, filename, tagname): -+ root = status.getETroot(filename) -+ for neighbor in root.iter(tagname): -+ location = neighbor.attrib["location"] -+ L = [] -+ for dirpath, dirnames, filenames in os.walk(location): -+ for file in filenames: -+ if file.endswith("input"): -+ L.append(os.path.join(dirpath, file)) -+ L = sorted(L, reverse=False) -+ for i in range(len(L)): -+ prob_t = {} -+ prob_t["name"] = getPMCreg("%s/temp%d_label" % (location, i + 1)) -+ prob_t["temp"] = float(getPMCreg("%s/temp%d_input" % (location, i + 1))) / 1000 -+ prob_t["alarm"] = float(getPMCreg("%s/temp%d_crit_alarm" % (location, i + 1))) / 1000 -+ prob_t["crit"] = float(getPMCreg("%s/temp%d_crit" % (location, i + 1))) / 1000 -+ prob_t["max"] = float(getPMCreg("%s/temp%d_max" % (location, i + 1))) / 1000 -+ a.append(prob_t) -+ -+ @staticmethod -+ def getFileName(): -+ fpath = os.path.dirname(os.path.realpath(__file__)) -+ for file in DEV_XML_FILE_LIST: -+ xml = fpath + "/" + file -+ if os.path.exists(xml): -+ return xml -+ return fpath + "/" + CONFIG_NAME -+ -+ @staticmethod -+ def checkFan(ret): -+ _filename = status.getFileName() -+ # _filename = "/usr/local/bin/" + status.getFileName() -+ _tagname = "fan" -+ status.getETValue(ret, _filename, _tagname) -+ -+ @staticmethod -+ def getTemp(ret): -+ _filename = status.getFileName() -+ # _filename = "/usr/local/bin/" + status.getFileName() -+ _tagname = "temp" -+ status.getETValue(ret, _filename, _tagname) -+ -+ @staticmethod -+ def getPsu(ret): -+ _filename = status.getFileName() -+ # _filename = "/usr/local/bin/" + status.getFileName() -+ _tagname = "psu" -+ status.getETValue(ret, _filename, _tagname) -+ -+ @staticmethod -+ def getcputemp(ret): -+ _filename = status.getFileName() -+ _tagname = "cpus" -+ status.getCPUValue(ret, _filename, _tagname) -+ -+ @staticmethod -+ def getDcdc(ret): -+ _filename = status.getFileName() -+ _tagname = "dcdc" -+ status.getETValue(ret, _filename, _tagname) -+ -+ @staticmethod -+ def getmactemp(ret): -+ _filename = status.getFileName() -+ _tagname = "mactemp" -+ status.getETValue(ret, _filename, _tagname) -+ -+ @staticmethod -+ def getmacpower(ret): -+ _filename = status.getFileName() -+ _tagname = "macpower" -+ status.getETValue(ret, _filename, _tagname) -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml -new file mode 100644 -index 000000000..7b026cec3 ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml -@@ -0,0 +1,440 @@ -+- bus: '00' -+ dev: '00' -+ fn: '0' -+ id: 6f00 -+ name: 'Host bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DMI2 -+ (rev 03)' -+- bus: '00' -+ dev: '01' -+ fn: '0' -+ id: 6f02 -+ name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI -+ Express Root Port 1 (rev 03)' -+- bus: '00' -+ dev: '01' -+ fn: '1' -+ id: 6f03 -+ name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI -+ Express Root Port 1 (rev 03)' -+- bus: '00' -+ dev: '02' -+ fn: '0' -+ id: 6f04 -+ name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI -+ Express Root Port 2 (rev 03)' -+- bus: '00' -+ dev: '02' -+ fn: '2' -+ id: 6f06 -+ name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI -+ Express Root Port 2 (rev 03)' -+- bus: '00' -+ dev: '03' -+ fn: '0' -+ id: 6f08 -+ name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI -+ Express Root Port 3 (rev 03)' -+- bus: '00' -+ dev: '05' -+ fn: '0' -+ id: 6f28 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Map/VTd_Misc/System Management (rev 03)' -+- bus: '00' -+ dev: '05' -+ fn: '1' -+ id: 6f29 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D IIO Hot Plug (rev 03)' -+- bus: '00' -+ dev: '05' -+ fn: '2' -+ id: 6f2a -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D IIO RAS/Control Status/Global Errors (rev 03)' -+- bus: '00' -+ dev: '05' -+ fn: '4' -+ id: 6f2c -+ name: 'PIC: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D I/O APIC (rev -+ 03)' -+- bus: '00' -+ dev: '14' -+ fn: '0' -+ id: 8c31 -+ name: 'USB controller: Intel Corporation 8 Series/C220 Series Chipset Family USB -+ xHCI (rev 05)' -+- bus: '00' -+ dev: '16' -+ fn: '0' -+ id: 8c3a -+ name: 'Communication controller: Intel Corporation 8 Series/C220 Series Chipset -+ Family MEI Controller #1 (rev 04)' -+- bus: '00' -+ dev: '16' -+ fn: '1' -+ id: 8c3b -+ name: 'Communication controller: Intel Corporation 8 Series/C220 Series Chipset -+ Family MEI Controller #2 (rev 04)' -+- bus: '00' -+ dev: 1c -+ fn: '0' -+ id: 8c10 -+ name: 'PCI bridge: Intel Corporation 8 Series/C220 Series Chipset Family PCI Express -+ Root Port #1 (rev d5)' -+- bus: '00' -+ dev: 1c -+ fn: '1' -+ id: 8c12 -+ name: 'PCI bridge: Intel Corporation 8 Series/C220 Series Chipset Family PCI Express -+ Root Port #2 (rev d5)' -+- bus: '00' -+ dev: 1d -+ fn: '0' -+ id: 8c26 -+ name: 'USB controller: Intel Corporation 8 Series/C220 Series Chipset Family USB -+ EHCI #1 (rev 05)' -+- bus: '00' -+ dev: 1f -+ fn: '0' -+ id: 8c54 -+ name: 'ISA bridge: Intel Corporation C224 Series Chipset Family Server Standard -+ SKU LPC Controller (rev 05)' -+- bus: '00' -+ dev: 1f -+ fn: '2' -+ id: 8c02 -+ name: 'SATA controller: Intel Corporation 8 Series/C220 Series Chipset Family 6-port -+ SATA Controller 1 [AHCI mode] (rev 05)' -+- bus: '00' -+ dev: 1f -+ fn: '3' -+ id: 8c22 -+ name: 'SMBus: Intel Corporation 8 Series/C220 Series Chipset Family SMBus Controller -+ (rev 05)' -+- bus: '01' -+ dev: '00' -+ fn: '0' -+ id: b873 -+ name: 'Ethernet controller: Broadcom Inc. and subsidiaries Device b873 (rev 01)' -+- bus: '03' -+ dev: '00' -+ fn: '0' -+ id: 6f50 -+ name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology -+ Register DMA Channel 0' -+- bus: '03' -+ dev: '00' -+ fn: '1' -+ id: 6f51 -+ name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology -+ Register DMA Channel 1' -+- bus: '03' -+ dev: '00' -+ fn: '2' -+ id: 6f52 -+ name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology -+ Register DMA Channel 2' -+- bus: '03' -+ dev: '00' -+ fn: '3' -+ id: 6f53 -+ name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology -+ Register DMA Channel 3' -+- bus: '04' -+ dev: '00' -+ fn: '0' -+ id: 15ab -+ name: 'Ethernet controller: Intel Corporation Ethernet Connection X552 10 GbE Backplane' -+- bus: '04' -+ dev: '00' -+ fn: '1' -+ id: 15ab -+ name: 'Ethernet controller: Intel Corporation Ethernet Connection X552 10 GbE Backplane' -+- bus: '07' -+ dev: '00' -+ fn: '0' -+ id: '1537' -+ name: 'Ethernet controller: Intel Corporation I210 Gigabit Backplane Connection -+ (rev 03)' -+- bus: 08 -+ dev: '00' -+ fn: '0' -+ id: '7022' -+ name: 'Memory controller: Xilinx Corporation Device 7022' -+- bus: ff -+ dev: 0b -+ fn: '0' -+ id: 6f81 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D R3 QPI Link 0/1 (rev 03)' -+- bus: ff -+ dev: 0b -+ fn: '1' -+ id: 6f36 -+ name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D R3 QPI Link 0/1 (rev 03)' -+- bus: ff -+ dev: 0b -+ fn: '2' -+ id: 6f37 -+ name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D R3 QPI Link 0/1 (rev 03)' -+- bus: ff -+ dev: 0b -+ fn: '3' -+ id: 6f76 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D R3 QPI Link Debug (rev 03)' -+- bus: ff -+ dev: 0c -+ fn: '0' -+ id: 6fe0 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Caching Agent (rev 03)' -+- bus: ff -+ dev: 0c -+ fn: '1' -+ id: 6fe1 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Caching Agent (rev 03)' -+- bus: ff -+ dev: 0c -+ fn: '2' -+ id: 6fe2 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Caching Agent (rev 03)' -+- bus: ff -+ dev: 0c -+ fn: '3' -+ id: 6fe3 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Caching Agent (rev 03)' -+- bus: ff -+ dev: 0f -+ fn: '0' -+ id: 6ff8 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Caching Agent (rev 03)' -+- bus: ff -+ dev: 0f -+ fn: '4' -+ id: 6ffc -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Caching Agent (rev 03)' -+- bus: ff -+ dev: 0f -+ fn: '5' -+ id: 6ffd -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Caching Agent (rev 03)' -+- bus: ff -+ dev: 0f -+ fn: '6' -+ id: 6ffe -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Caching Agent (rev 03)' -+- bus: ff -+ dev: '10' -+ fn: '0' -+ id: 6f1d -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D R2PCIe Agent (rev 03)' -+- bus: ff -+ dev: '10' -+ fn: '1' -+ id: 6f34 -+ name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D R2PCIe Agent (rev 03)' -+- bus: ff -+ dev: '10' -+ fn: '5' -+ id: 6f1e -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Ubox (rev 03)' -+- bus: ff -+ dev: '10' -+ fn: '6' -+ id: 6f7d -+ name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Ubox (rev 03)' -+- bus: ff -+ dev: '10' -+ fn: '7' -+ id: 6f1f -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Ubox (rev 03)' -+- bus: ff -+ dev: '12' -+ fn: '0' -+ id: 6fa0 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Home Agent 0 (rev 03)' -+- bus: ff -+ dev: '12' -+ fn: '1' -+ id: 6f30 -+ name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Home Agent 0 (rev 03)' -+- bus: ff -+ dev: '13' -+ fn: '0' -+ id: 6fa8 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Memory Controller 0 - Target Address/Thermal/RAS (rev 03)' -+- bus: ff -+ dev: '13' -+ fn: '1' -+ id: 6f71 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Memory Controller 0 - Target Address/Thermal/RAS (rev 03)' -+- bus: ff -+ dev: '13' -+ fn: '2' -+ id: 6faa -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Memory Controller 0 - Channel Target Address Decoder (rev 03)' -+- bus: ff -+ dev: '13' -+ fn: '3' -+ id: 6fab -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Memory Controller 0 - Channel Target Address Decoder (rev 03)' -+- bus: ff -+ dev: '13' -+ fn: '4' -+ id: 6fac -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Memory Controller 0 - Channel Target Address Decoder (rev 03)' -+- bus: ff -+ dev: '13' -+ fn: '5' -+ id: 6fad -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Memory Controller 0 - Channel Target Address Decoder (rev 03)' -+- bus: ff -+ dev: '13' -+ fn: '6' -+ id: 6fae -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D DDRIO Channel 0/1 Broadcast (rev 03)' -+- bus: ff -+ dev: '13' -+ fn: '7' -+ id: 6faf -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D DDRIO Global Broadcast (rev 03)' -+- bus: ff -+ dev: '14' -+ fn: '0' -+ id: 6fb0 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Memory Controller 0 - Channel 0 Thermal Control (rev 03)' -+- bus: ff -+ dev: '14' -+ fn: '1' -+ id: 6fb1 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Memory Controller 0 - Channel 1 Thermal Control (rev 03)' -+- bus: ff -+ dev: '14' -+ fn: '2' -+ id: 6fb2 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Memory Controller 0 - Channel 0 Error (rev 03)' -+- bus: ff -+ dev: '14' -+ fn: '3' -+ id: 6fb3 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Memory Controller 0 - Channel 1 Error (rev 03)' -+- bus: ff -+ dev: '14' -+ fn: '4' -+ id: 6fbc -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D DDRIO Channel 0/1 Interface (rev 03)' -+- bus: ff -+ dev: '14' -+ fn: '5' -+ id: 6fbd -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D DDRIO Channel 0/1 Interface (rev 03)' -+- bus: ff -+ dev: '14' -+ fn: '6' -+ id: 6fbe -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D DDRIO Channel 0/1 Interface (rev 03)' -+- bus: ff -+ dev: '14' -+ fn: '7' -+ id: 6fbf -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D DDRIO Channel 0/1 Interface (rev 03)' -+- bus: ff -+ dev: '15' -+ fn: '0' -+ id: 6fb4 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Memory Controller 0 - Channel 2 Thermal Control (rev 03)' -+- bus: ff -+ dev: '15' -+ fn: '1' -+ id: 6fb5 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Memory Controller 0 - Channel 3 Thermal Control (rev 03)' -+- bus: ff -+ dev: '15' -+ fn: '2' -+ id: 6fb6 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Memory Controller 0 - Channel 2 Error (rev 03)' -+- bus: ff -+ dev: '15' -+ fn: '3' -+ id: 6fb7 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Memory Controller 0 - Channel 3 Error (rev 03)' -+- bus: ff -+ dev: 1e -+ fn: '0' -+ id: 6f98 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Power Control Unit (rev 03)' -+- bus: ff -+ dev: 1e -+ fn: '1' -+ id: 6f99 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Power Control Unit (rev 03)' -+- bus: ff -+ dev: 1e -+ fn: '2' -+ id: 6f9a -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Power Control Unit (rev 03)' -+- bus: ff -+ dev: 1e -+ fn: '3' -+ id: 6fc0 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Power Control Unit (rev 03)' -+- bus: ff -+ dev: 1e -+ fn: '4' -+ id: 6f9c -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Power Control Unit (rev 03)' -+- bus: ff -+ dev: 1f -+ fn: '0' -+ id: 6f88 -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Power Control Unit (rev 03)' -+- bus: ff -+ dev: 1f -+ fn: '2' -+ id: 6f8a -+ name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon -+ D Power Control Unit (rev 03)' -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform.json -new file mode 100644 -index 000000000..0fe70dd14 ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform.json -@@ -0,0 +1,819 @@ -+{ -+ "chassis": { -+ "name": "M2-W6510-48V8C", -+ "thermal_manager": false, -+ "status_led": { -+ "controllable": false, -+ "colors": ["green", "blinking_green", "amber", "blinking_amber"] -+ }, -+ "components": [ -+ { -+ "name": "CPU_CPLD" -+ }, -+ { -+ "name": "CONNECT_CPLD" -+ }, -+ { -+ "name": "CONNECT_CPLD-FAN" -+ }, -+ { -+ "name": "MAC_CPLD1" -+ }, -+ { -+ "name": "MAC_CPLD2" -+ }, -+ { -+ "name": "FPGA" -+ }, -+ { -+ "name": "BIOS" -+ } -+ ], -+ "fans": [ -+ { -+ "name": "Fantray1_1", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false, -+ "colors": ["off", "red", "amber", "green"] -+ } -+ }, -+ { -+ "name": "Fantray1_2", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false, -+ "colors": ["off", "red", "amber", "green"] -+ } -+ }, -+ { -+ "name": "Fantray2_1", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false, -+ "colors": ["off", "red", "amber", "green"] -+ } -+ }, -+ { -+ "name": "Fantray2_2", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false, -+ "colors": ["off", "red", "amber", "green"] -+ } -+ }, -+ { -+ "name": "Fantray3_1", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false, -+ "colors": ["off", "red", "amber", "green"] -+ } -+ }, -+ { -+ "name": "Fantray3_2", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false, -+ "colors": ["off", "red", "amber", "green"] -+ } -+ }, -+ { -+ "name": "Fantray4_1", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false, -+ "colors": ["off", "red", "amber", "green"] -+ } -+ }, -+ { -+ "name": "Fantray4_2", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false, -+ "colors": ["off", "red", "amber", "green"] -+ } -+ } -+ ], -+ "fan_drawers":[ -+ { -+ "name": "Fantray1", -+ "num_fans" : 2, -+ "status_led": { -+ "controllable": false, -+ "colors": ["amber", "green", "off"] -+ }, -+ "fans": [ -+ { -+ "name": "Fantray1_1", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false -+ } -+ }, -+ { -+ "name": "Fantray1_2", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false -+ } -+ } -+ ] -+ }, -+ { -+ "name": "Fantray2", -+ "num_fans" : 2, -+ "status_led": { -+ "controllable": false, -+ "colors": ["amber", "green", "off"] -+ }, -+ "fans": [ -+ { -+ "name": "Fantray2_1", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false -+ } -+ }, -+ { -+ "name": "Fantray2_2", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false -+ } -+ } -+ ] -+ }, -+ { -+ "name": "Fantray3", -+ "num_fans" : 2, -+ "status_led": { -+ "controllable": false, -+ "colors": ["amber", "green", "off"] -+ }, -+ "fans": [ -+ { -+ "name": "Fantray3_1", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false -+ } -+ }, -+ { -+ "name": "Fantray3_2", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false -+ } -+ } -+ ] -+ }, -+ { -+ "name": "Fantray4", -+ "num_fans" : 2, -+ "status_led": { -+ "controllable": false, -+ "colors": ["amber", "green", "off"] -+ }, -+ "fans": [ -+ { -+ "name": "Fantray4_1", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false -+ } -+ }, -+ { -+ "name": "Fantray4_2", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false -+ } -+ } -+ ] -+ } -+ ], -+ "psus": [ -+ { -+ "name": "Psu1", -+ "voltage": true, -+ "current": true, -+ "power": true, -+ "max_power": false, -+ "voltage_high_threshold": true, -+ "voltage_low_threshold": true, -+ "temperature": true, -+ "fans_target_speed": true, -+ "status_led": { -+ "controllable": false -+ }, -+ "fans": [ -+ { -+ "name": "PSU1_FAN1", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false -+ } -+ } -+ ] -+ }, -+ { -+ "name": "Psu2", -+ "voltage": true, -+ "current": true, -+ "power": true, -+ "max_power": false, -+ "voltage_high_threshold": true, -+ "voltage_low_threshold": true, -+ "temperature": true, -+ "fans_target_speed": true, -+ "status_led": { -+ "controllable": false -+ }, -+ "fans": [ -+ { -+ "name": "PSU2_FAN1", -+ "speed": { -+ "controllable": true, -+ "minimum": 50, -+ "maximum": 100 -+ }, -+ "status_led": { -+ "available": false -+ } -+ } -+ ] -+ } -+ ], -+ "thermals": [ -+ { -+ "name": "ASIC_TEMP", -+ "controllable": false, -+ "low-crit-threshold": true, -+ "high-crit-threshold": true, -+ "low-threshold": true, -+ "high-threshold": true, -+ "minimum-recorded": true, -+ "maximum-recorded": true -+ }, -+ { -+ "name": "CPU_TEMP", -+ "controllable": false, -+ "low-crit-threshold": true, -+ "high-crit-threshold": true, -+ "low-threshold": true, -+ "high-threshold": true, -+ "minimum-recorded": true, -+ "maximum-recorded": true -+ }, -+ { -+ "name": "INLET_TEMP", -+ "controllable": false, -+ "low-crit-threshold": true, -+ "high-crit-threshold": true, -+ "low-threshold": true, -+ "high-threshold": true, -+ "minimum-recorded": true, -+ "maximum-recorded": true -+ }, -+ { -+ "name": "OUTLET_TEMP", -+ "controllable": false, -+ "low-crit-threshold": true, -+ "high-crit-threshold": true, -+ "low-threshold": true, -+ "high-threshold": true, -+ "minimum-recorded": true, -+ "maximum-recorded": true -+ }, -+ { -+ "name": "MAC_OUT_TEMP", -+ "controllable": false, -+ "low-crit-threshold": true, -+ "high-crit-threshold": true, -+ "low-threshold": true, -+ "high-threshold": true, -+ "minimum-recorded": true, -+ "maximum-recorded": true -+ }, -+ { -+ "name": "MAC_IN_TEMP", -+ "controllable": false, -+ "low-crit-threshold": true, -+ "high-crit-threshold": true, -+ "low-threshold": true, -+ "high-threshold": true, -+ "minimum-recorded": true, -+ "maximum-recorded": true -+ }, -+ { -+ "name": "PSU1_TEMP", -+ "controllable": false, -+ "low-crit-threshold": true, -+ "high-crit-threshold": true, -+ "low-threshold": true, -+ "high-threshold": true, -+ "minimum-recorded": true, -+ "maximum-recorded": true -+ }, -+ { -+ "name": "PSU2_TEMP", -+ "controllable": false, -+ "low-crit-threshold": true, -+ "high-crit-threshold": true, -+ "low-threshold": true, -+ "high-threshold": true, -+ "minimum-recorded": true, -+ "maximum-recorded": true -+ } -+ ], -+ "modules": [], -+ "sfps": [] -+ }, -+ "interfaces": { -+ "Ethernet1": { -+ "index": "1", -+ "lanes": "57", -+ "breakout_modes": { -+ "1x25G": ["Eth1"] -+ } -+ }, -+ "Ethernet2": { -+ "index": "2", -+ "lanes": "58", -+ "breakout_modes": { -+ "1x25G": ["Eth2"] -+ } -+ }, -+ "Ethernet3": { -+ "index": "3", -+ "lanes": "59", -+ "breakout_modes": { -+ "1x25G": ["Eth3"] -+ } -+ }, -+ "Ethernet4": { -+ "index": "4", -+ "lanes": "60", -+ "breakout_modes": { -+ "1x25G": ["Eth4"] -+ } -+ }, -+ "Ethernet5": { -+ "index": "5", -+ "lanes": "61", -+ "breakout_modes": { -+ "1x25G": ["Eth5"] -+ } -+ }, -+ "Ethernet6": { -+ "index": "6", -+ "lanes": "62", -+ "breakout_modes": { -+ "1x25G": ["Eth6"] -+ } -+ }, -+ "Ethernet7": { -+ "index": "7", -+ "lanes": "63", -+ "breakout_modes": { -+ "1x25G": ["Eth7"] -+ } -+ }, -+ "Ethernet8": { -+ "index": "8", -+ "lanes": "64", -+ "breakout_modes": { -+ "1x25G": ["Eth8"] -+ } -+ }, -+ "Ethernet9": { -+ "index": "9", -+ "lanes": "1", -+ "breakout_modes": { -+ "1x25G": ["Eth9"] -+ } -+ }, -+ "Ethernet10": { -+ "index": "10", -+ "lanes": "2", -+ "breakout_modes": { -+ "1x25G": ["Eth10"] -+ } -+ }, -+ "Ethernet11": { -+ "index": "11", -+ "lanes": "3", -+ "breakout_modes": { -+ "1x25G": ["Eth11"] -+ } -+ }, -+ "Ethernet12": { -+ "index": "12", -+ "lanes": "4", -+ "breakout_modes": { -+ "1x25G": ["Eth12"] -+ } -+ }, -+ "Ethernet13": { -+ "index": "13", -+ "lanes": "5", -+ "breakout_modes": { -+ "1x25G": ["Eth13"] -+ } -+ }, -+ "Ethernet14": { -+ "index": "14", -+ "lanes": "6", -+ "breakout_modes": { -+ "1x25G": ["Eth14"] -+ } -+ }, -+ "Ethernet15": { -+ "index": "15", -+ "lanes": "7", -+ "breakout_modes": { -+ "1x25G": ["Eth15"] -+ } -+ }, -+ "Ethernet16": { -+ "index": "16", -+ "lanes": "8", -+ "breakout_modes": { -+ "1x25G": ["Eth16"] -+ } -+ }, -+ "Ethernet17": { -+ "index": "17", -+ "lanes": "13", -+ "breakout_modes": { -+ "1x25G": ["Eth17"] -+ } -+ }, -+ "Ethernet18": { -+ "index": "18", -+ "lanes": "14", -+ "breakout_modes": { -+ "1x25G": ["Eth18"] -+ } -+ }, -+ "Ethernet19": { -+ "index": "19", -+ "lanes": "15", -+ "breakout_modes": { -+ "1x25G": ["Eth19"] -+ } -+ }, -+ "Ethernet20": { -+ "index": "20", -+ "lanes": "16", -+ "breakout_modes": { -+ "1x25G": ["Eth20"] -+ } -+ }, -+ "Ethernet21": { -+ "index": "21", -+ "lanes": "21", -+ "breakout_modes": { -+ "1x25G": ["Eth21"] -+ } -+ }, -+ "Ethernet22": { -+ "index": "22", -+ "lanes": "22", -+ "breakout_modes": { -+ "1x25G": ["Eth22"] -+ } -+ }, -+ "Ethernet23": { -+ "index": "23", -+ "lanes": "23", -+ "breakout_modes": { -+ "1x25G": ["Eth23"] -+ } -+ }, -+ "Ethernet24": { -+ "index": "24", -+ "lanes": "24", -+ "breakout_modes": { -+ "1x25G": ["Eth24"] -+ } -+ }, -+ "Ethernet25": { -+ "index": "25", -+ "lanes": "29", -+ "breakout_modes": { -+ "1x25G": ["Eth25"] -+ } -+ }, -+ "Ethernet26": { -+ "index": "26", -+ "lanes": "30", -+ "breakout_modes": { -+ "1x25G": ["Eth26"] -+ } -+ }, -+ "Ethernet27": { -+ "index": "27", -+ "lanes": "31", -+ "breakout_modes": { -+ "1x25G": ["Eth27"] -+ } -+ }, -+ "Ethernet28": { -+ "index": "28", -+ "lanes": "32", -+ "breakout_modes": { -+ "1x25G": ["Eth28"] -+ } -+ }, -+ "Ethernet29": { -+ "index": "29", -+ "lanes": "33", -+ "breakout_modes": { -+ "1x25G": ["Eth29"] -+ } -+ }, -+ "Ethernet30": { -+ "index": "30", -+ "lanes": "34", -+ "breakout_modes": { -+ "1x25G": ["Eth30"] -+ } -+ }, -+ "Ethernet31": { -+ "index": "31", -+ "lanes": "35", -+ "breakout_modes": { -+ "1x25G": ["Eth31"] -+ } -+ }, -+ "Ethernet32": { -+ "index": "32", -+ "lanes": "36", -+ "breakout_modes": { -+ "1x25G": ["Eth32"] -+ } -+ }, -+ "Ethernet33": { -+ "index": "33", -+ "lanes": "41", -+ "breakout_modes": { -+ "1x25G": ["Eth33"] -+ } -+ }, -+ "Ethernet34": { -+ "index": "34", -+ "lanes": "42", -+ "breakout_modes": { -+ "1x25G": ["Eth34"] -+ } -+ }, -+ "Ethernet35": { -+ "index": "35", -+ "lanes": "43", -+ "breakout_modes": { -+ "1x25G": ["Eth35"] -+ } -+ }, -+ "Ethernet36": { -+ "index": "36", -+ "lanes": "44", -+ "breakout_modes": { -+ "1x25G": ["Eth36"] -+ } -+ }, -+ "Ethernet37": { -+ "index": "37", -+ "lanes": "49", -+ "breakout_modes": { -+ "1x25G": ["Eth37"] -+ } -+ }, -+ "Ethernet38": { -+ "index": "38", -+ "lanes": "50", -+ "breakout_modes": { -+ "1x25G": ["Eth38"] -+ } -+ }, -+ "Ethernet39": { -+ "index": "39", -+ "lanes": "51", -+ "breakout_modes": { -+ "1x25G": ["Eth39"] -+ } -+ }, -+ "Ethernet40": { -+ "index": "40", -+ "lanes": "52", -+ "breakout_modes": { -+ "1x25G": ["Eth40"] -+ } -+ }, -+ "Ethernet41": { -+ "index": "41", -+ "lanes": "65", -+ "breakout_modes": { -+ "1x25G": ["Eth41"] -+ } -+ }, -+ "Ethernet42": { -+ "index": "42", -+ "lanes": "66", -+ "breakout_modes": { -+ "1x25G": ["Eth42"] -+ } -+ }, -+ "Ethernet43": { -+ "index": "43", -+ "lanes": "67", -+ "breakout_modes": { -+ "1x25G": ["Eth43"] -+ } -+ }, -+ "Ethernet44": { -+ "index": "44", -+ "lanes": "68", -+ "breakout_modes": { -+ "1x25G": ["Eth44"] -+ } -+ }, -+ "Ethernet45": { -+ "index": "45", -+ "lanes": "69", -+ "breakout_modes": { -+ "1x25G": ["Eth45"] -+ } -+ }, -+ "Ethernet46": { -+ "index": "46", -+ "lanes": "70", -+ "breakout_modes": { -+ "1x25G": ["Eth46"] -+ } -+ }, -+ "Ethernet47": { -+ "index": "47", -+ "lanes": "71", -+ "breakout_modes": { -+ "1x25G": ["Eth47"] -+ } -+ }, -+ "Ethernet48": { -+ "index": "48", -+ "lanes": "72", -+ "breakout_modes": { -+ "1x25G": ["Eth48"] -+ } -+ }, -+ "Ethernet49": { -+ "index": "49,49,49,49", -+ "lanes": "85,86,87,88", -+ "breakout_modes": { -+ "1x100G": ["Eth49"], -+ "2x50G": ["Eth49/1", "Eth49/2"], -+ "4x25G[10G]": ["Eth49/1", "Eth49/2", "Eth49/3", "Eth49/4"], -+ "4x10G": ["Eth49/1", "Eth49/2", "Eth49/3", "Eth49/4"] -+ } -+ }, -+ "Ethernet53": { -+ "index": "50,50,50,50", -+ "lanes": "77,78,79,80", -+ "breakout_modes": { -+ "1x100G": ["Eth50"], -+ "2x50G": ["Eth50/1", "Eth50/2"], -+ "4x25G[10G]": ["Eth50/1", "Eth50/2", "Eth50/3", "Eth50/4"], -+ "4x10G": ["Eth50/1", "Eth50/2", "Eth50/3", "Eth50/4"] -+ } -+ }, -+ "Ethernet57": { -+ "index": "51,51,51,51", -+ "lanes": "97,98,99,100", -+ "breakout_modes": { -+ "1x100G": ["Eth51"], -+ "2x50G": ["Eth51/1", "Eth51/2"], -+ "4x25G[10G]": ["Eth51/1", "Eth51/2", "Eth51/3", "Eth51/4"], -+ "4x10G": ["Eth51/1", "Eth51/2", "Eth51/3", "Eth51/4"] -+ } -+ }, -+ "Ethernet61": { -+ "index": "52,52,52,52", -+ "lanes": "93,94,95,96", -+ "breakout_modes": { -+ "1x100G": ["Eth52"], -+ "2x50G": ["Eth52/1", "Eth52/2"], -+ "4x25G[10G]": ["Eth52/1", "Eth52/2", "Eth52/3", "Eth52/4"], -+ "4x10G": ["Eth52/1", "Eth52/2", "Eth52/3", "Eth52/4"] -+ } -+ }, -+ "Ethernet65": { -+ "index": "53,53,53,53", -+ "lanes": "113,114,115,116", -+ "breakout_modes": { -+ "1x100G": ["Eth53"], -+ "2x50G": ["Eth53/1", "Eth53/2"], -+ "4x25G[10G]": ["Eth53/1", "Eth53/2", "Eth53/3", "Eth53/4"], -+ "4x10G": ["Eth53/1", "Eth53/2", "Eth53/3", "Eth53/4"] -+ } -+ }, -+ "Ethernet69": { -+ "index": "54,54,54,54", -+ "lanes": "105,106,107,108", -+ "breakout_modes": { -+ "1x100G": ["Eth54"], -+ "2x50G": ["Eth54/1","Eth54/2"], -+ "4x25G[10G]": ["Eth54/1", "Eth54/2", "Eth54/3", "Eth54/4"], -+ "4x10G": ["Eth54/1", "Eth54/2", "Eth54/3", "Eth54/4"] -+ } -+ }, -+ "Ethernet73": { -+ "index": "55,55,55,55", -+ "lanes": "121,122,123,124", -+ "breakout_modes": { -+ "1x100G": ["Eth55"], -+ "2x50G": ["Eth55/1", "Eth55/2"], -+ "4x25G[10G]": ["Eth55/1", "Eth55/2", "Eth55/3", "Eth55/4"], -+ "4x10G": ["Eth55/1", "Eth55/2", "Eth55/3", "Eth55/4"] -+ } -+ }, -+ "Ethernet77": { -+ "index": "56,56,56,56", -+ "lanes": "125,126,127,128", -+ "breakout_modes": { -+ "1x100G": ["Eth56"], -+ "2x50G": ["Eth56/1", "Eth56/2"], -+ "4x25G[10G]": ["Eth56/1", "Eth56/2", "Eth56/3", "Eth56/4"], -+ "4x10G": ["Eth56/1", "Eth56/2", "Eth56/3", "Eth56/4"] -+ } -+ } -+ } -+} -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_asic b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_asic -new file mode 100644 -index 000000000..960467652 ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_asic -@@ -0,0 +1 @@ -+broadcom -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_components.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_components.json -new file mode 100644 -index 000000000..7986fe321 ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_components.json -@@ -0,0 +1,37 @@ -+{ -+ "chassis": { -+ "M2-W6510-48V8C": { -+ "component": { -+ "CPU_CPLD": { -+ "firmware": "", -+ "version": "27190516" -+ }, -+ "CONNECT_CPLD": { -+ "firmware": "", -+ "version": "49191230" -+ }, -+ "CONNECT_CPLD-FAN": { -+ "firmware": "", -+ "version": "49191230" -+ }, -+ "MAC_CPLD1": { -+ "firmware" : "", -+ "version" : "16190108" -+ }, -+ "MAC_CPLD2": { -+ "firmware" : "", -+ "version" : "17200110" -+ }, -+ "FPGA": { -+ "firmware": "", -+ "version": "7a150016" -+ }, -+ "BIOS": { -+ "firmware" : "", -+ "version" : "5.11(3BARB029)" -+ } -+ } -+ } -+ } -+} -+ -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/sfputil.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/sfputil.py -new file mode 100644 -index 000000000..3e195a36f ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/sfputil.py -@@ -0,0 +1,243 @@ -+# sfputil.py -+# -+# Platform-specific SFP transceiver interface for SONiC -+# -+ -+try: -+ import time -+ import os -+ import traceback -+ from sonic_sfp.sfputilbase import SfpUtilBase -+except ImportError as e: -+ raise ImportError("%s - required module not found" % str(e)) -+ -+class SfpUtil(SfpUtilBase): -+ """Platform-specific SfpUtil class""" -+ -+ PORT_START = 1 -+ PORT_END = 56 -+ PORTS_IN_BLOCK = 57 -+ -+ EEPROM_OFFSET = 32 -+ SFP_DEVICE_TYPE = "optoe2" -+ QSFP_DEVICE_TYPE = "optoe1" -+ I2C_MAX_ATTEMPT = 3 -+ -+ _port_to_eeprom_mapping = {} -+ port_to_i2cbus_mapping ={} -+ -+ @property -+ def port_start(self): -+ return self.PORT_START -+ -+ @property -+ def port_end(self): -+ return self.PORT_END -+ -+ @property -+ def qsfp_ports(self): -+ return range(49, self.PORTS_IN_BLOCK) -+ -+ @property -+ def port_to_eeprom_mapping(self): -+ return self._port_to_eeprom_mapping -+ -+ def __init__(self): -+ for x in range(self.PORT_START, self.PORTS_IN_BLOCK): -+ self.port_to_i2cbus_mapping[x] = x + self.EEPROM_OFFSET - 1 -+ SfpUtilBase.__init__(self) -+ -+ def _sfp_read_file_path(self, file_path, offset, num_bytes): -+ attempts = 0 -+ while attempts < self.I2C_MAX_ATTEMPT: -+ try: -+ file_path.seek(offset) -+ read_buf = file_path.read(num_bytes) -+ except Exception: -+ attempts += 1 -+ time.sleep(0.05) -+ return True, read_buf -+ return False, None -+ -+ def _sfp_eeprom_present(self, sysfs_sfp_i2c_client_eeprompath, offset): -+ """Tries to read the eeprom file to determine if the -+ device/sfp is present or not. If sfp present, the read returns -+ valid bytes. If not, read returns error 'Connection timed out""" -+ -+ if not os.path.exists(sysfs_sfp_i2c_client_eeprompath): -+ return False -+ with open(sysfs_sfp_i2c_client_eeprompath, "rb", buffering=0) as sysfsfile: -+ rv, buf = self._sfp_read_file_path(sysfsfile, offset, 1) -+ return rv -+ -+ def _add_new_sfp_device(self, sysfs_sfp_i2c_adapter_path, devaddr, devtype): -+ try: -+ sysfs_nd_path = "%s/new_device" % sysfs_sfp_i2c_adapter_path -+ -+ # Write device address to new_device file -+ nd_str = "%s %s" % (devtype, hex(devaddr)) -+ with open(sysfs_nd_path, "w") as nd_file: -+ nd_file.write(nd_str) -+ -+ except Exception as err: -+ print("Error writing to new device file: %s" % str(err)) -+ return 1 -+ else: -+ return 0 -+ -+ def _get_port_eeprom_path(self, port_num, devid): -+ sysfs_i2c_adapter_base_path = "" -+ -+ if port_num in self.port_to_eeprom_mapping: -+ sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[port_num] -+ else: -+ sysfs_i2c_adapter_base_path = "/sys/class/i2c-adapter" -+ -+ i2c_adapter_id = self._get_port_i2c_adapter_id(port_num) -+ if i2c_adapter_id is None: -+ print("Error getting i2c bus num") -+ return None -+ -+ # Get i2c virtual bus path for the sfp -+ sysfs_sfp_i2c_adapter_path = "%s/i2c-%s" % (sysfs_i2c_adapter_base_path, -+ str(i2c_adapter_id)) -+ -+ # If i2c bus for port does not exist -+ if not os.path.exists(sysfs_sfp_i2c_adapter_path): -+ print("Could not find i2c bus %s. Driver not loaded?" % sysfs_sfp_i2c_adapter_path) -+ return None -+ -+ sysfs_sfp_i2c_client_path = "%s/%s-00%s" % (sysfs_sfp_i2c_adapter_path, -+ str(i2c_adapter_id), -+ hex(devid)[-2:]) -+ -+ # If sfp device is not present on bus, Add it -+ if not os.path.exists(sysfs_sfp_i2c_client_path): -+ if port_num in self.qsfp_ports: -+ ret = self._add_new_sfp_device( -+ sysfs_sfp_i2c_adapter_path, devid, self.QSFP_DEVICE_TYPE) -+ else: -+ ret = self._add_new_sfp_device( -+ sysfs_sfp_i2c_adapter_path, devid, self.SFP_DEVICE_TYPE) -+ if ret != 0: -+ print("Error adding sfp device") -+ return None -+ -+ sysfs_sfp_i2c_client_eeprom_path = "%s/eeprom" % sysfs_sfp_i2c_client_path -+ -+ return sysfs_sfp_i2c_client_eeprom_path -+ -+ def _read_eeprom_specific_bytes(self, sysfsfile_eeprom, offset, num_bytes): -+ eeprom_raw = [] -+ for i in range(0, num_bytes): -+ eeprom_raw.append("0x00") -+ -+ rv, raw = self._sfp_read_file_path(sysfsfile_eeprom, offset, num_bytes) -+ if rv is False: -+ return None -+ -+ try: -+ for n in range(0, num_bytes): -+ eeprom_raw[n] = hex(raw[n])[2:].zfill(2) -+ except Exception: -+ return None -+ -+ return eeprom_raw -+ -+ def get_eeprom_dom_raw(self, port_num): -+ if port_num in self.qsfp_ports: -+ # QSFP DOM EEPROM is also at addr 0x50 and thus also stored in eeprom_ifraw -+ return None -+ # Read dom eeprom at addr 0x51 -+ return self._read_eeprom_devid(port_num, self.IDENTITY_EEPROM_ADDR, 256) -+ -+ def get_presence(self, port_num): -+ # Check for invalid port_num -+ if port_num < self.port_start or port_num > self.port_end: -+ return False -+ -+ presence_path = "/sys/wb_plat/sff/sff%d/present" % port_num -+ -+ try: -+ with open(presence_path, "rb") as data: -+ presence_data = data.read(2) -+ if presence_data == "": -+ return False -+ result = int(presence_data, 16) -+ except IOError: -+ return False -+ -+ if result == 1: -+ return True -+ return False -+ -+ def get_low_power_mode(self, port_num): -+ # Check for invalid port_num -+ -+ return True -+ -+ def set_low_power_mode(self, port_num, lpmode): -+ # Check for invalid port_num -+ -+ return True -+ -+ def reset(self, port_num): -+ # Check for invalid port_num -+ if port_num < self.port_start or port_num > self.port_end: -+ return False -+ -+ return True -+ -+ def get_transceiver_change_event(self, timeout=0): -+ return False, {} -+ -+ def get_highest_temperature(self): -+ offset = 0 -+ hightest_temperature = -9999 -+ -+ presence_flag = False -+ read_eeprom_flag = False -+ temperature_valid_flag = False -+ -+ for port in range(49, self.PORTS_IN_BLOCK): -+ if self.get_presence(port) is False: -+ continue -+ -+ presence_flag = True -+ -+ if port in self.qsfp_ports: -+ offset = 22 -+ else: -+ offset = 96 -+ -+ eeprom_path = self._get_port_eeprom_path(port, 0x50) -+ try: -+ with open(eeprom_path, mode="rb", buffering=0) as eeprom: -+ read_eeprom_flag = True -+ eeprom_raw = self._read_eeprom_specific_bytes(eeprom, offset, 2) -+ msb = int(eeprom_raw[0], 16) -+ lsb = int(eeprom_raw[1], 16) -+ -+ result = (msb << 8) | (lsb & 0xff) -+ result = float(result / 256.0) -+ if -50 <= result <= 200: -+ temperature_valid_flag = True -+ hightest_temperature = max(hightest_temperature, result) -+ except Exception: -+ print(traceback.format_exc()) -+ -+ # all port not presence -+ if presence_flag is False: -+ hightest_temperature = -10000 -+ -+ # all port read eeprom fail -+ elif read_eeprom_flag is False: -+ hightest_temperature = -9999 -+ -+ # all port temperature invalid -+ elif read_eeprom_flag is True and temperature_valid_flag is False: -+ hightest_temperature = -10000 -+ -+ hightest_temperature = round(hightest_temperature, 2) -+ -+ return hightest_temperature -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/ssd_util.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/ssd_util.py -new file mode 100755 -index 000000000..89d3ccd77 ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/ssd_util.py -@@ -0,0 +1,311 @@ -+# -+# ssd_util.py -+# -+# Generic implementation of the SSD health API -+# SSD models supported: -+# - InnoDisk -+# - StorFly -+# - Virtium -+ -+try: -+ import re -+ import os -+ import subprocess -+ from sonic_platform_base.sonic_ssd.ssd_base import SsdBase -+except ImportError as e: -+ raise ImportError (str(e) + "- required module not found") -+ -+SMARTCTL = "smartctl {} -a" -+INNODISK = "iSmart -d {}" -+VIRTIUM = "SmartCmd -m {}" -+DISK_LIST_CMD = "fdisk -l -o Device" -+DISK_FREE_CMD = "df -h" -+MOUNT_CMD = "mount" -+ -+NOT_AVAILABLE = "N/A" -+PE_CYCLE = 3000 -+FAIL_PERCENT = 95 -+ -+# Set Vendor Specific IDs -+INNODISK_HEALTH_ID = 169 -+INNODISK_TEMPERATURE_ID = 194 -+ -+class SsdUtil(SsdBase): -+ """ -+ Generic implementation of the SSD health API -+ """ -+ model = NOT_AVAILABLE -+ serial = NOT_AVAILABLE -+ firmware = NOT_AVAILABLE -+ temperature = NOT_AVAILABLE -+ health = NOT_AVAILABLE -+ remaining_life = NOT_AVAILABLE -+ sata_rate = NOT_AVAILABLE -+ ssd_info = NOT_AVAILABLE -+ vendor_ssd_info = NOT_AVAILABLE -+ -+ def __init__(self, diskdev): -+ self.vendor_ssd_utility = { -+ "Generic" : { "utility" : SMARTCTL, "parser" : self.parse_generic_ssd_info }, -+ "InnoDisk" : { "utility" : INNODISK, "parser" : self.parse_innodisk_info }, -+ "M.2" : { "utility" : INNODISK, "parser" : self.parse_innodisk_info }, -+ "StorFly" : { "utility" : VIRTIUM, "parser" : self.parse_virtium_info }, -+ "Virtium" : { "utility" : VIRTIUM, "parser" : self.parse_virtium_info } -+ } -+ -+ """ -+ The dict model_attr keys relate the vendors -+ LITEON : "ER2-GD","AF2MA31DTDLT" -+ Intel : "SSDSCKKB" -+ SMI : "SM619GXC" -+ samsung: "MZNLH" -+ ADATA : "IM2S3134N" -+ """ -+ self.model_attr = { -+ "ER2-GD" : { "temperature" : "\n190\s+(.+?)\n", "remainingLife" : "\n202\s+(.+?)\n" }, -+ "AF2MA31DTDLT" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n202\s+(.+?)\n" }, -+ "SSDSCK" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n233\s+(.+?)\n" }, -+ "SM619GXC" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n169\s+(.+?)\n" }, -+ "MZNLH" : { "temperature" : "\n190\s+(.+?)\n", "remainingLife" : "\n245\s+(.+?)\n" }, -+ "IM2S3134N" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n231\s+(.+?)\n" } -+ } -+ -+ self.key_list = list(self.model_attr.keys()) -+ self.attr_info_rule = "[\s\S]*SMART Attributes Data Structure revision number: 1|SMART Error Log Version[\s\S]*" -+ self.dev = diskdev -+ # Generic part -+ self.fetch_generic_ssd_info(diskdev) -+ self.parse_generic_ssd_info() -+ self.fetch_vendor_ssd_info(diskdev, "Generic") -+ -+ # Known vendor part -+ if self.model: -+ model_short = self.model.split()[0] -+ if model_short in self.vendor_ssd_utility: -+ self.fetch_vendor_ssd_info(diskdev, model_short) -+ self.parse_vendor_ssd_info(model_short) -+ else: -+ # No handler registered for this disk model -+ pass -+ else: -+ # Failed to get disk model -+ self.model = "Unknown" -+ -+ def _execute_shell(self, cmd): -+ process = subprocess.Popen(cmd.split(), universal_newlines=True, stdout=subprocess.PIPE) -+ output, error = process.communicate() -+ exit_code = process.returncode -+ if exit_code: -+ return None -+ return output -+ -+ def _parse_re(self, pattern, buffer): -+ res_list = re.findall(pattern, str(buffer)) -+ return res_list[0] if res_list else NOT_AVAILABLE -+ -+ def fetch_generic_ssd_info(self, diskdev): -+ self.ssd_info = self._execute_shell(self.vendor_ssd_utility["Generic"]["utility"].format(diskdev)) -+ -+ # Health and temperature values may be overwritten with vendor specific data -+ def parse_generic_ssd_info(self): -+ if "nvme" in self.dev: -+ self.model = self._parse_re('Model Number:\s*(.+?)\n', self.ssd_info) -+ -+ health_raw = self._parse_re('Percentage Used\s*(.+?)\n', self.ssd_info) -+ if health_raw == NOT_AVAILABLE: -+ self.health = NOT_AVAILABLE -+ else: -+ health_raw = health_raw.split()[-1] -+ self.health = 100 - float(health_raw.strip('%')) -+ -+ temp_raw = self._parse_re('Temperature\s*(.+?)\n', self.ssd_info) -+ if temp_raw == NOT_AVAILABLE: -+ self.temperature = NOT_AVAILABLE -+ else: -+ temp_raw = temp_raw.split()[-2] -+ self.temperature = float(temp_raw) -+ else: -+ self.model = self._parse_re('Device Model:\s*(.+?)\n', self.ssd_info) -+ model_key = "" -+ for key in self.key_list: -+ if re.search(key, self.model): -+ model_key = key -+ break -+ if model_key != "": -+ self.remaining_life = self._parse_re(self.model_attr[model_key]["remainingLife"], re.sub(self.attr_info_rule,"",self.ssd_info)).split()[2] -+ self.temperature = self._parse_re(self.model_attr[model_key]["temperature"], re.sub(self.attr_info_rule,"",self.ssd_info)).split()[8] -+ self.health = self.remaining_life -+ # Get the LITEON ssd health value by (PE CYCLE - AVG ERASE CYCLE )/(PE CYCLE) -+ if model_key in ["ER2-GD", "AF2MA31DTDLT"]: -+ avg_erase = int(self._parse_re('\n173\s+(.+?)\n' ,re.sub(self.attr_info_rule,"",self.ssd_info)).split()[-1]) -+ self.health = int(round((PE_CYCLE - avg_erase)/PE_CYCLE*100,0)) -+ if self.remaining_life != NOT_AVAILABLE and int(self.remaining_life) < FAIL_PERCENT: -+ self.remaining_life = "Fail" -+ self.sata_rate = self._parse_re('SATA Version is:.*current: (.+?)\)\n', self.ssd_info) -+ self.serial = self._parse_re('Serial Number:\s*(.+?)\n', self.ssd_info) -+ self.firmware = self._parse_re('Firmware Version:\s*(.+?)\n', self.ssd_info) -+ -+ def parse_innodisk_info(self): -+ if self.vendor_ssd_info: -+ self.health = self._parse_re('Health:\s*(.+?)%', self.vendor_ssd_info) -+ self.temperature = self._parse_re('Temperature\s*\[\s*(.+?)\]', self.vendor_ssd_info) -+ else: -+ if self.health == NOT_AVAILABLE: -+ health_raw = self.parse_id_number(INNODISK_HEALTH_ID) -+ self.health = health_raw.split()[-1] -+ if self.temperature == NOT_AVAILABLE: -+ temp_raw = self.parse_id_number(INNODISK_TEMPERATURE_ID) -+ self.temperature = temp_raw.split()[-6] -+ -+ def parse_virtium_info(self): -+ if self.vendor_ssd_info: -+ self.temperature = self._parse_re('Temperature_Celsius\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info) -+ nand_endurance = self._parse_re('NAND_Endurance\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info) -+ avg_erase_count = self._parse_re('Average_Erase_Count\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info) -+ try: -+ self.health = 100 - (float(avg_erase_count) * 100 / float(nand_endurance)) -+ except (ValueError, ZeroDivisionError): -+ # Invalid avg_erase_count or nand_endurance. -+ pass -+ -+ def fetch_vendor_ssd_info(self, diskdev, model): -+ self.vendor_ssd_info = self._execute_shell(self.vendor_ssd_utility[model]["utility"].format(diskdev)) -+ -+ def parse_vendor_ssd_info(self, model): -+ self.vendor_ssd_utility[model]["parser"]() -+ -+ def check_readonly2(self, partition, filesystem): -+ # parse mount cmd output info -+ mount_info = self._execute_shell(MOUNT_CMD) -+ for line in mount_info.split('\n'): -+ column_list = line.split() -+ if line == '': -+ continue -+ if column_list[0] == partition and column_list[2] == filesystem: -+ if column_list[5].split(',')[0][1:] == "ro": -+ return partition -+ else: -+ return NOT_AVAILABLE -+ return NOT_AVAILABLE -+ -+ def check_readonly(self, partition, filesystem): -+ ret = os.access(filesystem, os.W_OK) -+ if ret == False: -+ return partition -+ else: -+ return NOT_AVAILABLE -+ -+ def get_health(self): -+ """ -+ Retrieves current disk health in percentages -+ -+ Returns: -+ A float number of current ssd health -+ e.g. 83.5 -+ """ -+ return float(self.health) -+ -+ def get_temperature(self): -+ """ -+ Retrieves current disk temperature in Celsius -+ -+ Returns: -+ A float number of current temperature in Celsius -+ e.g. 40.1 -+ """ -+ return float(self.temperature) -+ -+ def get_model(self): -+ """ -+ Retrieves model for the given disk device -+ -+ Returns: -+ A string holding disk model as provided by the manufacturer -+ """ -+ return self.model -+ -+ def get_firmware(self): -+ """ -+ Retrieves firmware version for the given disk device -+ -+ Returns: -+ A string holding disk firmware version as provided by the manufacturer -+ """ -+ return self.firmware -+ -+ def get_serial(self): -+ """ -+ Retrieves serial number for the given disk device -+ -+ Returns: -+ A string holding disk serial number as provided by the manufacturer -+ """ -+ return self.serial -+ def get_sata_rate(self): -+ """ -+ Retrieves SATA rate for the given disk device -+ Returns: -+ A string holding current SATA rate as provided by the manufacturer -+ """ -+ return self.sata_rate -+ def get_remaining_life(self): -+ """ -+ Retrieves remaining life for the given disk device -+ Returns: -+ A string holding disk remaining life as provided by the manufacturer -+ """ -+ return self.remaining_life -+ def get_vendor_output(self): -+ """ -+ Retrieves vendor specific data for the given disk device -+ -+ Returns: -+ A string holding some vendor specific disk information -+ """ -+ return self.vendor_ssd_info -+ -+ def parse_id_number(self, id): -+ return self._parse_re('{}\s*(.+?)\n'.format(id), self.ssd_info) -+ -+ def get_readonly_partition(self): -+ """ -+ Check the partition mount filesystem is readonly status,then output the result. -+ Returns: -+ The readonly partition list -+ """ -+ -+ ro_partition_list = [] -+ partition_list = [] -+ -+ # parse fdisk cmd output info -+ disk_info = self._execute_shell(DISK_LIST_CMD) -+ begin_flag = False -+ for line in disk_info.split('\n'): -+ if line == "Device": -+ begin_flag = True -+ continue -+ if begin_flag: -+ if line != "": -+ partition_list.append(line) -+ else: -+ break -+ -+ # parse df cmd output info -+ disk_free = self._execute_shell(DISK_FREE_CMD) -+ disk_dict = {} -+ line_num = 0 -+ for line in disk_free.split('\n'): -+ line_num = line_num + 1 -+ if line_num == 1 or line == "": -+ continue -+ column_list = line.split() -+ disk_dict[column_list[0]] = column_list[5] -+ -+ # get partition which is readonly -+ for partition in partition_list: -+ if partition in disk_dict: -+ ret = self.check_readonly(partition, disk_dict[partition]) -+ if (ret != NOT_AVAILABLE): -+ ro_partition_list.append(ret) -+ -+ return ro_partition_list -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pmon_daemon_control.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pmon_daemon_control.json -new file mode 100644 -index 000000000..94592fa8c ---- /dev/null -+++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pmon_daemon_control.json -@@ -0,0 +1,3 @@ -+{ -+ "skip_ledd": true -+} -diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/system_health_monitoring_config.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/system_health_monitoring_config.json -new file mode 100755 -index 000000000..e69de29bb -diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk -index 6c668ee68..44a722e47 100755 ---- a/platform/broadcom/one-image.mk -+++ b/platform/broadcom/one-image.mk -@@ -81,6 +81,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ - $(RAGILE_RA_B6910_64C_PLATFORM_MODULE) \ - $(RAGILE_RA_B6510_32C_PLATFORM_MODULE) \ - $(RAGILE_RA_B6920_4S_PLATFORM_MODULE) \ -+ $(MICAS_M2_W6510_48V8C_PLATFORM_MODULE) \ - $(NOKIA_IXR7250_PLATFORM_MODULE) \ - $(TENCENT_TCS8400_PLATFORM_MODULE) \ - $(TENCENT_TCS9400_PLATFORM_MODULE) -diff --git a/platform/broadcom/platform-modules-micas.dep b/platform/broadcom/platform-modules-micas.dep -new file mode 100644 -index 000000000..6ae59a668 ---- /dev/null -+++ b/platform/broadcom/platform-modules-micas.dep -@@ -0,0 +1,9 @@ -+MPATH := $($(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_SRC_PATH) -+DEP_FILES := $(SONIC_COMMON_FILES_LIST) platform/broadcom/platform-modules-micas.mk platform/broadcom/platform-modules-micas.dep -+DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) -+DEP_FILES += $(addprefix $(MPATH)/,$(shell cd $(MPATH) && git ls-files)) -+ -+ -+$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_CACHE_MODE := GIT_CONTENT_SHA -+$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) -+$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_DEP_FILES := $(DEP_FILES) -diff --git a/platform/broadcom/platform-modules-micas.mk b/platform/broadcom/platform-modules-micas.mk -new file mode 100644 -index 000000000..7f2a95cad ---- /dev/null -+++ b/platform/broadcom/platform-modules-micas.mk -@@ -0,0 +1,10 @@ -+## M2-W6510-48V8C -+MICAS_M2_W6510_48V8C_PLATFORM_MODULE_VERSION = 1.0 -+export MICAS_M2_W6510_48V8C_PLATFORM_MODULE_VERSION -+ -+MICAS_M2_W6510_48V8C_PLATFORM_MODULE = platform-modules-micas-m2-w6510-48v8c_$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE_VERSION)_amd64.deb -+$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-micas -+$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) $(PDDF_PLATFORM_MODULE) -+$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_PLATFORM = x86_64-micas_m2-w6510-48v8c-r0 -+SONIC_DPKG_DEBS += $(MICAS_M2_W6510_48V8C_PLATFORM_MODULE) -+SONIC_STRETCH_DEBS += $(MICAS_M2_W6510_48V8C_PLATFORM_MODULE) -diff --git a/platform/broadcom/rules.dep b/platform/broadcom/rules.dep -index 47f7f849e..2c8a29bf4 100644 ---- a/platform/broadcom/rules.dep -+++ b/platform/broadcom/rules.dep -@@ -15,6 +15,7 @@ include $(PLATFORM_PATH)/platform-modules-quanta.dep - include $(PLATFORM_PATH)/platform-modules-juniper.dep - include $(PLATFORM_PATH)/platform-modules-ragile.dep - include $(PLATFORM_PATH)/platform-modules-ruijie.dep -+include $(PLATFORM_PATH)/platform-modules-micas.dep - include $(PLATFORM_PATH)/platform-modules-brcm-xlr-gts.dep - include $(PLATFORM_PATH)/docker-syncd-brcm.dep - include $(PLATFORM_PATH)/docker-syncd-brcm-rpc.dep -diff --git a/platform/broadcom/rules.mk b/platform/broadcom/rules.mk -index 5fa7bfca7..df56a0c8d 100755 ---- a/platform/broadcom/rules.mk -+++ b/platform/broadcom/rules.mk -@@ -17,6 +17,7 @@ include $(PLATFORM_PATH)/platform-modules-juniper.mk - include $(PLATFORM_PATH)/platform-modules-ragile.mk - #include $(PLATFORM_PATH)/platform-modules-tencent.mk - include $(PLATFORM_PATH)/docker-syncd-brcm.mk -+include $(PLATFORM_PATH)/platform-modules-micas.mk - include $(PLATFORM_PATH)/docker-syncd-brcm-rpc.mk - include $(PLATFORM_PATH)/docker-saiserver-brcm.mk - ifeq ($(INCLUDE_PDE), y) -diff --git a/platform/broadcom/sonic-platform-modules-micas/LICENSE b/platform/broadcom/sonic-platform-modules-micas/LICENSE -new file mode 100644 -index 000000000..5681cac34 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/LICENSE -@@ -0,0 +1,14 @@ -+Copyright (C) 2016 Microsoft, Inc -+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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/Makefile -new file mode 100755 -index 000000000..385dae088 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/Makefile -@@ -0,0 +1,41 @@ -+PWD = $(shell pwd) -+CC ?=gcc -+INSTALL_MOD_DIR ?=extra -+KVERSION ?= $(shell uname -r) -+KERNEL_SRC ?= /lib/modules/$(KVERSION) -+EXTRA_CFLAGS:= -I$(M)/include -+EXTRA_CFLAGS+= -Wall -+SUB_BUILD_DIR = $(PWD)/build -+DIR_KERNEL_SRC = $(PWD)/modules -+SCRIPT_DIR = $(PWD)/script -+SERVICE_DIR = $(PWD)/service -+BLACK_DRIVER_CONF_DIR = $(PWD)/modprobe_conf -+ -+app_dir = $(PWD)/app -+app_build_dir = $(app_dir)/build -+modules_build_dir = $(DIR_KERNEL_SRC)/build -+ -+INSTALL_MODULE_DIR = $(SUB_BUILD_DIR)/$(KERNEL_SRC)/$(INSTALL_MOD_DIR) -+INSTALL_SCRIPT_DIR = $(SUB_BUILD_DIR)/usr/local/bin -+INSTALL_SERVICE_DIR = $(SUB_BUILD_DIR)/lib/systemd/system -+INSTALL_LIB_DIR = $(SUB_BUILD_DIR)/usr/lib/python3/dist-packages -+INSTALL_BLACK_DRIVER = $(SUB_BUILD_DIR)/etc/modprobe.d -+ -+all: -+ $(MAKE) -C $(app_dir) -+ $(MAKE) -C $(DIR_KERNEL_SRC) -+ @if [ ! -d ${INSTALL_MODULE_DIR} ]; then mkdir -p ${INSTALL_MODULE_DIR} ;fi -+ @if [ ! -d ${INSTALL_SCRIPT_DIR} ]; then mkdir -p ${INSTALL_SCRIPT_DIR} ;fi -+ @if [ ! -d ${INSTALL_SERVICE_DIR} ]; then mkdir -p ${INSTALL_SERVICE_DIR} ;fi -+ @if [ ! -d ${INSTALL_LIB_DIR} ]; then mkdir -p ${INSTALL_LIB_DIR} ;fi -+ @if [ -d $(PWD)/lib/ ]; then cp -r $(PWD)/lib/* ${INSTALL_LIB_DIR} ;fi -+ @if [ -d $(PWD)/sonic_platform/ ]; then cp -rf $(PWD)/sonic_platform ${INSTALL_LIB_DIR} ;fi -+ cp -r $(modules_build_dir)/*.ko $(INSTALL_MODULE_DIR) -+ cp -r $(app_dir)/build/app/* $(INSTALL_SCRIPT_DIR) -+ cp -r $(SCRIPT_DIR)/* $(INSTALL_SCRIPT_DIR) -+ cp -r $(SERVICE_DIR)/* $(INSTALL_SERVICE_DIR) -+ @if [ -d $(INSTALL_SCRIPT_DIR) ]; then chmod +x $(INSTALL_SCRIPT_DIR)/* ;fi -+ @if [ ! -d ${INSTALL_BLACK_DRIVER} ]; then mkdir -p ${INSTALL_BLACK_DRIVER} ;fi -+ cp -r $(BLACK_DRIVER_CONF_DIR)/* $(INSTALL_BLACK_DRIVER) -+clean: -+ rm -rf $(SUB_BUILD_DIR) -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/Makefile -new file mode 100644 -index 000000000..25ba3c5a9 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/app/Makefile -@@ -0,0 +1,25 @@ -+pes_parent_dir:=$(shell pwd)/$(lastword $(MAKEFILE_LIST)) -+pes_parent_dir:=$(shell dirname $(pes_parent_dir)) -+ -+SUBDIRS=$(shell ls -l | grep ^d | awk '{if($$9 != "build") print $$9}') -+INC = -I./inc -+ -+COMMON_OUT_PUT := $(shell pwd)/build -+common_out_put_dir := $(COMMON_OUT_PUT)/app -+common_module_dir := $(COMMON_OUT_PUT)/module/ -+export common_out_put_dir common_module_dir -+ -+all : CHECK $(SUBDIRS) -+CHECK : -+ @echo $(pes_parent_dir) -+ -+$(SUBDIRS):ECHO -+ #@echo $@ -+ make -C $@ -+ -+ECHO: -+ @echo $(SUBDIRS) -+ -+.PHONY : clean -+clean : -+ -rm -rf $(COMMON_OUT_PUT) -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/Makefile -new file mode 100644 -index 000000000..e4078716e ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/Makefile -@@ -0,0 +1,30 @@ -+top_srcdir:=$(shell pwd) -+#include $(top_srcdir)/Rules.mk -+DIR=$(shell pwd) -+BUILD_OUTPUT=$(DIR)/tmp -+SRCS=$(wildcard *.c) -+OBJS=$(patsubst %.c, $(BUILD_OUTPUT)/%.o, $(SRCS)) -+DEPS=$(patsubst %.o, %.d, $(OBJS)) -+CFLAGS+=-Wall -W -g -I$(DIR)/include -+LDFLAGS= -+PROGRAM=dfd_debug -+ -+.PHONY: all -+ -+all:$(OBJS) -+ $(CC) $(OBJS) $(LDFLAGS) -o $(BUILD_OUTPUT)/$(PROGRAM) -+ @if [ ! -d ${common_out_put_dir} ]; then mkdir -p ${common_out_put_dir} ;fi -+ cp -p $(BUILD_OUTPUT)/$(PROGRAM) $(common_out_put_dir) -+ -+$(OBJS):$(SRCS) -+ @if [ ! -d ${BUILD_OUTPUT} ]; then mkdir -p ${BUILD_OUTPUT} ;fi -+ $(CC) -c $(CFLAGS) $(INCLUDE) $(*F).c -o $@ -+ -+.PHONY: install -+install: -+ @mkdir -p $(common_out_put_dir) -+ cp -p $(BUILD_OUTPUT)/$(PROGRAM) $(common_out_put_dir) -+ -+rebuild: clean all -+clean: -+ @rm -rf $(BUILD_OUTPUT)/* -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_debug.c b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_debug.c -new file mode 100644 -index 000000000..93ed6066e ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_debug.c -@@ -0,0 +1,43 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "dfd_utest.h" -+ -+int g_dfd_debug_sw = 0; -+int g_dfd_debugpp_sw = 0; -+ -+void dfd_debug_set_init(void) -+{ -+ FILE *fp; -+ char buf[10]; -+ -+ mem_clear(buf, sizeof(buf)); -+ fp = fopen(DFD_DEBUGP_DEBUG_FILE, "r"); -+ if (fp != NULL) { -+ -+ g_dfd_debug_sw = 1; -+ fclose(fp); -+ } -+ -+ fp = fopen(DFD_DEBUGPP_DEBUG_FILE, "r"); -+ if (fp != NULL) { -+ -+ g_dfd_debugpp_sw = 1; -+ fclose(fp); -+ } -+ -+ return; -+} -+ -+int main(int argc, char* argv[]) -+{ -+ dfd_debug_set_init(); -+ dfd_utest_cmd_main(argc, argv); -+ -+ return 0; -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.c b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.c -new file mode 100644 -index 000000000..c82b0baad ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.c -@@ -0,0 +1,2121 @@ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "dfd_utest.h" -+ -+#define DFD_UTEST_MAX_RDWR_NUM (256) -+#define DFD_UTEST_DEFAULT_WR_NUM (1) -+ -+#define DEV_MEM_NAME "/dev/mem" -+#define DEV_KMEM_NAME "/dev/kmem" -+ -+#define WIDTH_1Byte (1) -+#define WIDTH_2Byte (2) -+#define WIDTH_4Byte (4) -+#define DFD_UTEST_MAX_BIT_WIDTH (4) -+ -+struct phydev_user_info { -+ int phy_index; -+ uint32_t regnum; -+ uint32_t regval; -+}; -+ -+#define CMD_PHY_LIST _IOR('P', 0, struct phydev_user_info) -+#define CMD_PHY_READ _IOR('P', 1, struct phydev_user_info) -+#define CMD_PHY_WRITE _IOR('P', 2, struct phydev_user_info) -+ -+struct mdio_dev_user_info { -+ int mdio_index; -+ int phyaddr; -+ uint32_t regnum; -+ uint32_t regval; -+}; -+ -+#define CMD_MDIO_LIST _IOR('M', 0, struct mdio_dev_user_info) -+#define CMD_MDIO_READ _IOR('M', 1, struct mdio_dev_user_info) -+#define CMD_MDIO_WRITE _IOR('M', 2, struct mdio_dev_user_info) -+ -+#ifdef DFD_UTEST_ITEM -+#undef DFD_UTEST_ITEM -+#endif -+#define DFD_UTEST_ITEM(_id, _type_str, _help_info, _help_info_detail) {_id, #_type_str, dfd_utest_##_type_str, _help_info, _help_info_detail}, -+static dfd_utest_t g_dfd_unit_test[] = { -+ DFD_UTEST_ITEM_ALL -+}; -+ -+static int g_sys_page_size; -+#define SYS_PAGE_SIZE g_sys_page_size -+#define SYS_PAGE_MASK (~(SYS_PAGE_SIZE - 1)) -+ -+void dfd_utest_print_cmd(int argc, char* argv[]) -+{ -+ int i; -+ -+ for (i = 1; i < argc; i++) { -+ if (i != 1) { -+ printf(" "); -+ } -+ printf("%s", argv[i]); -+ } -+ return; -+} -+ -+void dfd_utest_print_all_help(void) -+{ -+ int i, tbl_size; -+ -+ tbl_size = sizeof(g_dfd_unit_test) / sizeof(g_dfd_unit_test[0]); -+ -+ for (i = 0; i < tbl_size; i++) { -+ printf("%-20s\t\t\t%s\r\n", g_dfd_unit_test[i].type_str, g_dfd_unit_test[i].help_info); -+ } -+ -+ return; -+} -+ -+void dfd_utest_printf_single_help(int utest_type) -+{ -+ int i, tbl_size; -+ -+ tbl_size = sizeof(g_dfd_unit_test) / sizeof(g_dfd_unit_test[0]); -+ for (i = 0; i < tbl_size; i++) { -+ if (g_dfd_unit_test[i].utest_type == utest_type) { -+ printf("%-20s\t\t\t%s\r\n", g_dfd_unit_test[i].type_str, g_dfd_unit_test[i].help_info_detail); -+ return; -+ } -+ } -+ -+ DFD_DEBUG_DBG("type: %d not match.\n", utest_type); -+ return; -+ -+} -+ -+void dfd_utest_printf_reg(uint8_t *buf, int buf_len, uint32_t offset_addr) -+{ -+ int i, j, tmp; -+ -+ j = offset_addr % 16; -+ tmp = j; -+ offset_addr -= j; -+ printf("\n "); -+ -+ for (i = 0; i < 16; i++) { -+ printf("%2x ", i); -+ } -+ -+ for (i = 0; i < buf_len + j; i++) { -+ if ((i % 16) == 0) { -+ printf("\n0x%08x ", offset_addr); -+ offset_addr = offset_addr + 16; -+ } -+ if (tmp) { -+ printf(" "); -+ tmp--; -+ } else { -+ printf("%02x ", buf[i-j]); -+ } -+ } -+ -+ printf("\n"); -+ return; -+} -+ -+#define I2C_RETRIES 0x0701 -+#define I2C_TIMEOUT 0x0702 -+#define I2C_RDWR 0x0707 -+ -+#define I2C_SLAVE 0x0703 /* Use this slave address */ -+ -+#define I2C_SLAVE_FORCE 0x0706 /* Use this slave address, even if it -+ is already in use by a driver! */ -+#define I2C_PEC 0x0708 /* != 0 to use PEC with SMBus */ -+#define I2C_SMBUS 0x0720 /* SMBus transfer */ -+ -+struct i2c_msg -+{ -+ unsigned short addr; -+ unsigned short flags; -+#define I2C_M_TEN 0x0010 -+#define I2C_M_RD 0x0001 -+ unsigned short len; -+ unsigned char *buf; -+}; -+ -+struct i2c_rdwr_ioctl_data -+{ -+ struct i2c_msg *msgs; -+ int nmsgs; -+ -+}; -+ -+#define DFD_I2C_SHORT_ADDR_TYPE 0 -+#define DFD_I2C_RETRY_SLEEP_TIME (10000) /* 10ms */ -+#define DFD_I2C_RETRY_TIME (50000 / DFD_I2C_RETRY_SLEEP_TIME) -+/* i2c_smbus_xfer read or write markers */ -+#define I2C_SMBUS_READ 1 -+#define I2C_SMBUS_WRITE 0 -+ -+/* SMBus transaction types (size parameter in the above functions) -+ Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */ -+#define I2C_SMBUS_QUICK 0 -+#define I2C_SMBUS_BYTE 1 -+#define I2C_SMBUS_BYTE_DATA 2 -+#define I2C_SMBUS_WORD_DATA 3 -+#define I2C_SMBUS_PROC_CALL 4 -+#define I2C_SMBUS_BLOCK_DATA 5 -+#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 -+#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ -+#define I2C_SMBUS_I2C_BLOCK_DATA 8 -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,36) -+/* fix tjm */ -+ -+#ifndef __ASSEMBLY__ -+/* -+ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the -+ * header files exported to user space -+ */ -+typedef __signed__ char __s8; -+typedef unsigned char __u8; -+ -+typedef __signed__ short __s16; -+typedef unsigned short __u16; -+ -+typedef __signed__ int __s32; -+typedef unsigned int __u32; -+ -+typedef __signed__ long __s64; -+typedef unsigned long __u64; -+ -+#endif /* __ASSEMBLY__ */ -+ -+#else -+/* do noting add tjm */ -+#endif -+ -+/* -+ * Data for SMBus Messages -+ */ -+#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ -+union i2c_smbus_data { -+ __u8 byte; -+ __u16 word; -+ __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */ -+ /* and one more for user-space compatibility */ -+}; -+ -+/* This is the structure as used in the I2C_SMBUS ioctl call */ -+struct i2c_smbus_ioctl_data { -+ __u8 read_write; -+ __u8 command; -+ __u32 size; -+ union i2c_smbus_data *data; -+}; -+int32_t dfd_read_port_i2c_one_time_smbus(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, -+ uint8_t *recv_buf, int32_t size, int addr_type) -+{ -+ union i2c_smbus_data data; -+ struct i2c_smbus_ioctl_data ioctl_data; -+ unsigned long addr = dev_addr; -+ int fd; -+ int rc; -+ int rv; -+ int i; -+ -+ mem_clear(&ioctl_data, sizeof(struct i2c_smbus_ioctl_data)); -+ if (i2c_name == NULL || recv_buf == NULL) { -+ DFD_DEBUG_ERROR("i2c_num = NULL, recv_buf = NULL\r\n"); -+ return -1; -+ } -+ -+ DFD_DEBUG_DBG("i2c name: %s, dev_addr: 0x%x, offset_addr: 0x%x, size: %d, addr_type: %d.\n", i2c_name, dev_addr, -+ offset_addr, size, addr_type); -+ -+ rv = 0; -+ fd = open(i2c_name, O_RDWR | O_SYNC); -+ if (fd < 0) { -+ DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); -+ rv = fd; -+ goto err; -+ } -+ if (ioctl(fd, I2C_SLAVE_FORCE , addr) < 0) { -+ DFD_DEBUG_ERROR("ioctl 2C_SLAVE_FORCE %d.\n", errno); -+ rv =-1; -+ goto fail; -+ } -+ for (i = 0 ;i < size; i++) { -+ data.byte = 0; -+ ioctl_data.read_write = I2C_SMBUS_READ; -+ ioctl_data.command = (offset_addr + i); -+ ioctl_data.size = I2C_SMBUS_BYTE_DATA; -+ ioctl_data.data= &data; -+ -+ rc = ioctl(fd, I2C_SMBUS, &ioctl_data); -+ if (rc < 0) { -+ DFD_DEBUG_ERROR("read, I2C_SMBUS failed: %d.\n", errno); -+ rv = -1; -+ goto fail; -+ } -+ *(recv_buf + i) = data.byte; -+ } -+ fail: -+ close(fd); -+ err: -+ return rv; -+ -+} -+ -+int32_t dfd_read_port_i2c_one_time(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, -+ uint8_t *recv_buf, int32_t size, int addr_type) -+{ -+ -+ int32_t fd, rv; -+ struct i2c_rdwr_ioctl_data ioctl_data; -+ struct i2c_msg msgs[2]; -+ uint8_t buf[2]; -+ -+ if (i2c_name == NULL || recv_buf == NULL) { -+ DFD_DEBUG_ERROR("i2c_num = NULL, recv_buf = NULL\r\n"); -+ return -1; -+ } -+ -+ DFD_DEBUG_DBG("i2c name %s, dev_addr 0x%x, offset_addr 0x%x, size %d, addr_type %d.\n", i2c_name, dev_addr, -+ offset_addr, size, addr_type); -+ -+ rv = 0; -+ fd = open(i2c_name, O_RDWR | O_SYNC); -+ if (fd < 0) { -+ DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); -+ return -1; -+ } -+ mem_clear(&ioctl_data, sizeof(ioctl_data)); -+ mem_clear(msgs, sizeof(msgs)); -+ mem_clear(buf, sizeof(buf)); -+ if (ioctl(fd, I2C_SLAVE, dev_addr) < 0) { -+ -+ DFD_DEBUG_ERROR("%s %dioctl fail(ret:%d, errno:%s)!\r\n", __func__ , __LINE__, rv, strerror(errno)); -+ rv = -1; -+ goto fail; -+ } -+ -+ buf[0] = (uint8_t)(offset_addr); -+ msgs[0].addr= dev_addr; -+ msgs[0].len= 2; -+ msgs[0].buf= buf; -+ msgs[1].addr= dev_addr; -+ msgs[1].flags|= I2C_M_RD; -+ msgs[1].len= 1; -+ msgs[1].buf= recv_buf; -+ ioctl_data.nmsgs= 1; -+ ioctl_data.msgs= msgs; -+ -+ rv = ioctl(fd, I2C_RDWR, &ioctl_data); -+ if(rv < 0) { -+ DFD_DEBUG_ERROR("%s %dioctl fail(ret:%d, errno:%s)!\r\n", __func__ , __LINE__, rv, strerror(errno)); -+ goto fail; -+ } -+ ioctl_data.msgs= &msgs[1]; -+ DFD_DEBUG_DBG("ioctlread, return :%d/n", ioctl(fd, I2C_RDWR, &ioctl_data)); -+ DFD_DEBUG_DBG("dfd_read_port_i2c addr: 0x%X, offset: 0x%X, value: 0x%X\n", dev_addr, offset_addr, *recv_buf); -+ fail: -+ close(fd); -+ return rv; -+ -+} -+ -+int32_t dfd_read_port_i2c(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, -+ uint8_t *recv_buf, int32_t size) -+{ -+ int i; -+ int rv; -+ -+ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { -+ rv = dfd_read_port_i2c_one_time_smbus(i2c_name, dev_addr, offset_addr, recv_buf, size, DFD_I2C_SHORT_ADDR_TYPE); -+ if (rv < 0) { -+ DFD_DEBUG_ERROR("(read times %d)i2c name %s, dev_addr 0x%X, offset_addr 0x%X, addr_type %d\n", i, i2c_name, dev_addr, offset_addr, DFD_I2C_SHORT_ADDR_TYPE); -+ usleep(DFD_I2C_RETRY_SLEEP_TIME); -+ continue; -+ } -+ break; -+ } -+ -+ return rv; -+} -+ -+int32_t dfd_write_port_i2c_one_time(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, -+ uint8_t *write_buf, int32_t size,int addr_type) -+{ -+ int32_t fd, rv; -+ int index; -+ struct i2c_smbus_ioctl_data ioctl_data; -+ union i2c_smbus_data data; -+ uint8_t addr_buf[2]; -+ uint8_t write_buf_tmp[256]; -+ -+ if (i2c_name == NULL || write_buf == NULL ) { -+ DFD_DEBUG_ERROR("i2c_num = NULL \r\n"); -+ return -1; -+ } -+ -+ if (size <= 0) { -+ DFD_DEBUG_ERROR("error:size\n"); -+ return -1; -+ } -+ DFD_DEBUG_DBG("i2c name %s, dev_addr 0x%x, offset_addr 0x%x, size %d, addr_type %d\n",i2c_name, dev_addr, -+ offset_addr, size, addr_type); -+ mem_clear(&ioctl_data, sizeof(ioctl_data)); -+ mem_clear(addr_buf, sizeof(addr_buf)); -+ mem_clear(write_buf_tmp, sizeof(write_buf_tmp)); -+ -+ rv = 0; -+ -+ fd = open(i2c_name, O_RDWR | O_SYNC); -+ if (fd < 0) { -+ DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); -+ return -1; -+ } -+ -+ if (ioctl(fd, I2C_SLAVE_FORCE, dev_addr) < 0) { -+ DFD_DEBUG_ERROR("ioctl, I2C_SLAVE failed: %d.\n", errno); -+ rv = -1; -+ goto fail; -+ } -+ -+ for (index = 0; index < size; index++) { -+ data.byte = *(write_buf + index); -+ ioctl_data.read_write = I2C_SMBUS_WRITE; -+ ioctl_data.command = (offset_addr + index); -+ ioctl_data.size = I2C_SMBUS_BYTE_DATA; -+ ioctl_data.data= &data; -+ rv = ioctl(fd, I2C_SMBUS, (unsigned long)&ioctl_data); -+ if(rv < 0) { -+ DFD_DEBUG_ERROR("ioctl fail(ret:%d, errno:%s %d) !\r\n", rv, strerror(errno),errno); -+ break; -+ } -+ DFD_DEBUG_DBG("ret:%d value:0x%02x\n", rv, data.byte); -+ usleep(5000); -+ } -+ -+fail: -+ close(fd); -+ return rv; -+} -+ -+int32_t dfd_write_port_i2c(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, -+ uint8_t *write_buf, int32_t size) -+{ -+ int i; -+ int rv; -+ -+ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { -+ rv = dfd_write_port_i2c_one_time(i2c_name, dev_addr, offset_addr, write_buf,size, DFD_I2C_SHORT_ADDR_TYPE); -+ if (rv < 0) { -+ DFD_DEBUG_ERROR("(write times %d)i2c name %s, dev_addr 0x%X, offset_addr 0x%X, addr_type %d\n", -+ i, i2c_name, dev_addr, offset_addr, DFD_I2C_SHORT_ADDR_TYPE); -+ usleep(DFD_I2C_RETRY_SLEEP_TIME); -+ continue; -+ } -+ break; -+ } -+ -+ return rv; -+} -+ -+static int dfd_read_io_port(uint16_t offset_addr, uint8_t *recv_buf, int32_t size) -+{ -+ int fd; -+ int ret; -+ -+ fd = open("/dev/port", O_RDWR); -+ if (fd < 0) { -+ printf("open failed ret %d.\n", fd); -+ return -1; -+ } -+ -+ ret = lseek(fd, offset_addr, SEEK_SET); -+ if (ret < 0) { -+ printf("lseek failed ret %d.\n", ret); -+ goto exit; -+ } -+ -+ ret = read(fd, recv_buf, size); -+ if (ret != size) { -+ printf("read failed ret %d size %d.\n", ret, size); -+ ret = -1; -+ goto exit; -+ } -+ -+exit: -+ close(fd); -+ return ret; -+} -+ -+static int dfd_write_io_port(uint16_t offset_addr, uint8_t *write_buf, int32_t size) -+{ -+ int fd; -+ int ret; -+ -+ fd = open("/dev/port", O_RDWR); -+ if (fd < 0) { -+ printf("open failed ret %d.\n", fd); -+ return -1; -+ } -+ -+ ret = lseek(fd, offset_addr, SEEK_SET); -+ if (ret < 0) { -+ printf("lseek failed ret %d.\n", ret); -+ goto exit; -+ } -+ -+ ret = write(fd, write_buf, size); -+ if (ret != size) { -+ printf("write failed ret %d size %d.\n", ret, size); -+ ret = -1; -+ goto exit; -+ } -+ -+exit: -+ close(fd); -+ return ret; -+} -+ -+static int dfd_process_mem(char *dev_name, char is_wr, char width, off_t offset, uint8_t *buf, int32_t size) -+{ -+ int mfd, ret = 0; -+ void *base; -+ int i, j; -+ unsigned int val; -+ off_t map_offset; -+ size_t map_size; -+ -+ if (size & (width - 1)) { -+ printf("size %d invalid.\n", size); -+ return -1; -+ } -+ -+ mfd = open(dev_name, O_RDWR); -+ if (mfd < 0) { -+ printf("Cannot open %s.\n", dev_name); -+ return -1; -+ } -+ -+ g_sys_page_size = getpagesize(); -+ map_offset = offset & SYS_PAGE_MASK; -+ map_size = size + offset - map_offset; -+ base = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, mfd, map_offset); -+ if (base == MAP_FAILED) { -+ printf("mmap offset 0x%lx failed error(%s).\n", map_offset, strerror(errno)); -+ close(mfd); -+ return -1; -+ } -+ printf("width %d map_offset 0x%lx, offset 0x%lx, mmap base %p, g_sys_page_size %d\n", -+ width, map_offset, offset, base, g_sys_page_size); -+ -+ if (is_wr) { -+ for (i = 0; i < size; i = i + width) { -+ val = 0; -+ for (j = 0; j < width; j++) { -+ val |= buf[i + j] << (8 * j); -+ } -+ switch (width) { -+ case 1: -+ *((volatile unsigned char*)(base + i + offset - map_offset)) = val; -+ break; -+ case 2: -+ *((volatile unsigned short*)(base + i + offset - map_offset)) = val; -+ break; -+ case 4: -+ *((volatile unsigned int*)(base + i + offset - map_offset)) = val; -+ break; -+ default: -+ ret = -1; -+ printf("Not support width %d.\n", width); -+ goto exit; -+ } -+ } -+ } else { -+ for (i = 0; i < size; i = i + width) { -+ switch (width) { -+ case 1: -+ val = *((volatile unsigned char*)(base + i + offset - map_offset)); -+ break; -+ case 2: -+ val = *((volatile unsigned short*)(base + i + offset - map_offset)); -+ break; -+ case 4: -+ val = *((volatile unsigned int*)(base + i + offset - map_offset)); -+ break; -+ default: -+ ret = -1; -+ printf("Not support width %d.\n", width); -+ goto exit; -+ } -+ for (j = 0; j < width; j++) { -+ buf[i + j] = (val >> (8 * j)) & 0xff; -+ } -+ } -+ } -+exit: -+ munmap(base, map_size); -+ close(mfd); -+ return ret; -+} -+ -+int32_t dfd_i2c_gen_read_one_time(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, -+ uint32_t offset_addr, uint8_t *recv_buf, int32_t rd_len) -+{ -+ int32_t fd, rv, i; -+ struct i2c_rdwr_ioctl_data ioctl_data; -+ struct i2c_msg msgs[2]; -+ uint8_t buf[DFD_UTEST_MAX_BIT_WIDTH]; -+ -+ fd = open(i2c_path, O_RDWR | O_SYNC); -+ if (fd < 0) { -+ DFD_DEBUG_ERROR("i2c open fail fd:%d\n", fd); -+ return -1; -+ } -+ mem_clear(&ioctl_data, sizeof(ioctl_data)); -+ mem_clear(msgs, sizeof(msgs)); -+ mem_clear(buf, sizeof(buf)); -+ -+ i = 0; -+ -+ switch (addr_bitwidth) { -+ case WIDTH_4Byte: -+ buf[i++] = (offset_addr >> 24) & 0xFF; -+ buf[i++] = (offset_addr >> 16) & 0xFF; -+ buf[i++] = (offset_addr >> 8) & 0xFF; -+ buf[i++] = offset_addr & 0xFF; -+ break; -+ case WIDTH_2Byte: -+ buf[i++] = (offset_addr >> 8) & 0xFF; -+ buf[i++] = offset_addr & 0xFF; -+ break; -+ case WIDTH_1Byte: -+ buf[i++] = offset_addr & 0xFF; -+ break; -+ default: -+ DFD_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set %u addr_bitwidth \n", addr_bitwidth); -+ rv = -1; -+ goto fail; -+ } -+ -+ msgs[0].addr = dev_addr; -+ msgs[0].flags = 0; -+ msgs[0].len = addr_bitwidth; -+ msgs[0].buf = buf; -+ msgs[1].addr = dev_addr; -+ msgs[1].flags |= I2C_M_RD; -+ msgs[1].len = rd_len; -+ msgs[1].buf = recv_buf; -+ ioctl_data.nmsgs = 2; -+ ioctl_data.msgs = msgs; -+ -+ rv = ioctl(fd, I2C_RDWR, &ioctl_data); -+ if(rv < 0) { -+ DFD_DEBUG_ERROR("%s %d Error: Sending messages failed:(ret:%d, errno:%s)!\n", __func__ , __LINE__, rv, strerror(errno)); -+ goto fail; -+ } -+ -+fail: -+ close(fd); -+ return rv; -+} -+ -+int32_t dfd_i2c_gen_read(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, -+ uint32_t offset_addr, uint8_t *recv_buf, int32_t rd_len) -+{ -+ int i; -+ int rv; -+ -+ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { -+ rv = dfd_i2c_gen_read_one_time(i2c_path, dev_addr, addr_bitwidth, offset_addr, recv_buf, rd_len); -+ if (rv < 0) { -+ DFD_DEBUG_ERROR("(read times:%d) i2c_path:%s, dev_addr:0x%x, addr_bitwidth:%u, offset_addr:0x%x, rd_len:%u\n", -+ i, i2c_path, dev_addr, addr_bitwidth, offset_addr, rd_len); -+ usleep(DFD_I2C_RETRY_SLEEP_TIME); -+ continue; -+ } -+ break; -+ } -+ -+ return rv; -+} -+ -+int dfd_utest_i2c_gen_rd(int argc, char* argv[]) -+{ -+ int ret; -+ uint32_t i2c_bus, dev_addr, addr_bitwidth, offset_addr, data_bitwidth, rd_len, i, j; -+ char *stopstring; -+ char i2c_path[32]; -+ uint8_t tmp_value[DFD_UTEST_MAX_RDWR_NUM]; -+ uint8_t rd_value[DFD_UTEST_MAX_RDWR_NUM]; -+ -+ if (argc != 8) { -+ DFD_DEBUG_ERROR("params error\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_RD); -+ goto exit; -+ } -+ -+ i2c_bus = strtol(argv[2], &stopstring, 10); -+ dev_addr = strtol(argv[3], &stopstring, 16); -+ addr_bitwidth = strtol(argv[4], &stopstring, 10); -+ offset_addr = strtol(argv[5], &stopstring, 16); -+ data_bitwidth = strtol(argv[6], &stopstring, 10); -+ rd_len = strtol(argv[7], &stopstring, 10); -+ -+ if (rd_len > DFD_UTEST_MAX_RDWR_NUM) { -+ DFD_DEBUG_ERROR("Input num %d exceed max.\n", rd_len); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_RD); -+ goto exit; -+ } -+ -+ dfd_utest_print_cmd(argc, argv); -+ printf(":\n"); -+ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); -+ mem_clear(tmp_value, sizeof(tmp_value)); -+ ret = dfd_i2c_gen_read(i2c_path, dev_addr, addr_bitwidth, offset_addr, tmp_value, rd_len); -+ if (ret < 0) { -+ printf("read failed. ret:%d\n", ret); -+ goto exit; -+ } -+ -+ mem_clear(rd_value, sizeof(rd_value)); -+ if (data_bitwidth == WIDTH_1Byte) { -+ memcpy(rd_value, tmp_value, rd_len); -+ } else { -+ for (i = 0; i < rd_len; i += data_bitwidth) { -+ for (j = 0; (j < data_bitwidth) && (i + j < rd_len); j++) { -+ rd_value[i + data_bitwidth - j - 1] = tmp_value[i + j]; -+ } -+ } -+ } -+ -+ dfd_utest_printf_reg(rd_value, rd_len, offset_addr); -+ -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+} -+ -+int32_t dfd_i2c_gen_write_one_time(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, -+ uint32_t offset_addr, uint8_t *wr_value, uint32_t wr_len) -+{ -+ int32_t fd, rv, i; -+ struct i2c_rdwr_ioctl_data ioctl_data; -+ struct i2c_msg msgs[1]; -+ uint8_t buf[DFD_UTEST_MAX_BIT_WIDTH + DFD_UTEST_MAX_RDWR_NUM]; -+ -+ fd = open(i2c_path, O_RDWR | O_SYNC); -+ if (fd < 0) { -+ DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); -+ return -1; -+ } -+ mem_clear(&ioctl_data, sizeof(ioctl_data)); -+ mem_clear(msgs, sizeof(msgs)); -+ mem_clear(buf, sizeof(buf)); -+ -+ i = 0; -+ -+ switch (addr_bitwidth) { -+ case WIDTH_4Byte: -+ buf[i++] = (offset_addr >> 24) & 0xFF; -+ buf[i++] = (offset_addr >> 16) & 0xFF; -+ buf[i++] = (offset_addr >> 8) & 0xFF; -+ buf[i++] = offset_addr & 0xFF; -+ break; -+ case WIDTH_2Byte: -+ buf[i++] = (offset_addr >> 8) & 0xFF; -+ buf[i++] = offset_addr & 0xFF; -+ break; -+ case WIDTH_1Byte: -+ buf[i++] = offset_addr & 0xFF; -+ break; -+ default: -+ DFD_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set %u addr_bitwidth \r\n", addr_bitwidth); -+ rv = -1; -+ goto fail; -+ } -+ -+ memcpy(buf + addr_bitwidth, wr_value, wr_len); -+ -+ msgs[0].addr= dev_addr; -+ msgs[0].flags = 0; -+ msgs[0].len= addr_bitwidth + wr_len; -+ msgs[0].buf= buf; -+ -+ ioctl_data.nmsgs= 1; -+ ioctl_data.msgs= msgs; -+ -+ rv = ioctl(fd, I2C_RDWR, &ioctl_data); -+ if(rv < 0) { -+ DFD_DEBUG_ERROR("%s %dError: Sending messages failed:(ret:%d, errno:%s)!\n", __func__ , __LINE__, rv, strerror(errno)); -+ goto fail; -+ } else if (rv < ioctl_data.nmsgs) { -+ DFD_DEBUG_ERROR("%s %dWarning: only %d/%d messages were sent\n", __func__ , __LINE__, rv, ioctl_data.nmsgs); -+ } -+ -+fail: -+ close(fd); -+ return rv; -+} -+ -+int32_t dfd_i2c_gen_write(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, -+ uint32_t offset_addr, uint8_t *wr_value, uint32_t wr_len) -+{ -+ int i; -+ int rv; -+ -+ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { -+ rv = dfd_i2c_gen_write_one_time(i2c_path, dev_addr, addr_bitwidth, offset_addr, wr_value, wr_len); -+ if (rv < 0) { -+ DFD_DEBUG_ERROR("(write times:%d)i2c_path:%s, dev_addr:0x%x, addr_bitwidth:%u, offset_addr:0x%x, wr_len:%u\n", -+ i, i2c_path, dev_addr, addr_bitwidth, offset_addr, wr_len); -+ usleep(DFD_I2C_RETRY_SLEEP_TIME); -+ continue; -+ } -+ break; -+ } -+ -+ return rv; -+} -+ -+int dfd_utest_i2c_gen_wr(int argc, char* argv[]) -+{ -+ int ret; -+ uint32_t i2c_bus, dev_addr, addr_bitwidth, offset_addr, data_bitwidth, wr_len, tmp_data, para_len, i, j; -+ char *stopstring; -+ char i2c_path[32]; -+ uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; -+ -+ if (argc < 8) { -+ DFD_DEBUG_ERROR("Input invalid.\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_WR); -+ goto exit; -+ } -+ -+ i2c_bus = strtol(argv[2], &stopstring, 10); -+ dev_addr = strtol(argv[3], &stopstring, 16); -+ addr_bitwidth = strtol(argv[4], &stopstring, 10); -+ offset_addr = strtol(argv[5], &stopstring, 16); -+ data_bitwidth = strtol(argv[6], &stopstring, 10); -+ -+ para_len = argc - 7; -+ wr_len = para_len * data_bitwidth; -+ -+ if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { -+ DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_WR); -+ goto exit; -+ } -+ -+ if (data_bitwidth == WIDTH_1Byte) { -+ for (i = 0; i < para_len; i++) { -+ wr_value[i] = strtol(argv[7 + i], &stopstring, 16); -+ DFD_DEBUG_DBG(" index :%d value 0x%x\n", i , wr_value[i]); -+ } -+ } else { -+ for (i = 0; i < para_len; i++) { -+ tmp_data = strtol(argv[7 + i], &stopstring, 16); -+ DFD_DEBUG_DBG(" index :%d value 0x%x\n", i , tmp_data); -+ for (j = 0; j < data_bitwidth; j++) { -+ tmp_data = strtol(argv[7 + i], &stopstring, 16); -+ wr_value[j + i * data_bitwidth] = (tmp_data >> (24 - 8 * j)) & 0xFF; -+ } -+ } -+ } -+ -+ dfd_utest_print_cmd(argc, argv); -+ -+ printf(":\n"); -+ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); -+ -+ ret = dfd_i2c_gen_write(i2c_path, dev_addr, addr_bitwidth, offset_addr, wr_value, wr_len); -+ if (ret < 0) { -+ printf("write failed. ret:%d\n", ret); -+ } else { -+ printf("write success\n"); -+ } -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+} -+ -+int dfd_utest_i2c_rd(int argc, char* argv[]) -+{ -+ int ret; -+ uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; -+ uint16_t dev_addr, offset_addr; -+ char *stopstring; -+ int num, i2c_bus; -+ char i2c_path[32]; -+ -+ if (argc != 6) { -+ DFD_DEBUG_ERROR("params error\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_RD); -+ goto exit; -+ } -+ -+ i2c_bus = strtol(argv[2], &stopstring, 10); -+ dev_addr = strtol(argv[3], &stopstring, 16); -+ offset_addr = strtol(argv[4], &stopstring, 16); -+ num = strtol(argv[5], &stopstring, 10); -+ -+ if (num > DFD_UTEST_MAX_RDWR_NUM) { -+ DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_RD); -+ goto exit; -+ } -+ -+ dfd_utest_print_cmd(argc, argv); -+ printf(":\n"); -+ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); -+ mem_clear(value, sizeof(value)); -+ ret = dfd_read_port_i2c(i2c_path, dev_addr, offset_addr, value, num); -+ if (ret < 0) { -+ printf("failed ret %d\n", ret); -+ goto exit; -+ } -+ -+ dfd_utest_printf_reg(value, num, offset_addr); -+ -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+ -+} -+ -+int dfd_utest_i2c_wr(int argc, char* argv[]) -+{ -+ int ret; -+ uint16_t dev_addr, offset_addr; -+ char *stopstring; -+ int i2c_bus; -+ char i2c_path[32]; -+ uint8_t wr_len,i; -+ uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; -+ -+ if (argc < 6) { -+ DFD_DEBUG_ERROR("Input invalid.\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_WR); -+ goto exit; -+ } -+ -+ wr_len = argc - 5; -+ i2c_bus = strtol(argv[2], &stopstring, 10); -+ dev_addr = strtol(argv[3], &stopstring, 16); -+ offset_addr = strtol(argv[4], &stopstring, 16); -+ -+ for (i = 0; i < wr_len; i++) { -+ wr_value[i] = strtol(argv[5+i], &stopstring, 16); -+ DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); -+ } -+ -+ dfd_utest_print_cmd(argc, argv); -+ -+ printf(":\n"); -+ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); -+ -+ ret = dfd_write_port_i2c(i2c_path, dev_addr, offset_addr, wr_value, wr_len); -+ if (ret < 0) { -+ printf("failed ret %d\n", ret); -+ } else { -+ printf("success\n"); -+ } -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+} -+ -+int dfd_utest_io_rd(int argc, char* argv[]) -+{ -+ int ret; -+ uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; -+ uint16_t offset_addr; -+ char *stopstring; -+ int num; -+ -+ if (argc != 4) { -+ DFD_DEBUG_ERROR("params error\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_RD); -+ goto exit; -+ } -+ -+ offset_addr = strtol(argv[2], &stopstring, 16); -+ num = strtol(argv[3], &stopstring, 10); -+ -+ if (num > DFD_UTEST_MAX_RDWR_NUM) { -+ DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_RD); -+ goto exit; -+ } -+ -+ dfd_utest_print_cmd(argc, argv); -+ printf(":\n"); -+ mem_clear(value, sizeof(value)); -+ ret = dfd_read_io_port(offset_addr, value, num); -+ if (ret < 0) { -+ printf("failed ret %d\n", ret); -+ goto exit; -+ } -+ -+ dfd_utest_printf_reg(value, num, offset_addr); -+ -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+} -+ -+int dfd_utest_io_wr(int argc, char* argv[]) -+{ -+ int ret; -+ uint16_t offset_addr; -+ char *stopstring; -+ int32_t wr_len,i; -+ uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; -+ -+ if (argc < 4) { -+ DFD_DEBUG_ERROR("Input invalid.\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_WR); -+ goto exit; -+ } -+ -+ wr_len = argc - 3; -+ if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { -+ DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_WR); -+ goto exit; -+ } -+ -+ offset_addr = strtol(argv[2], &stopstring, 16); -+ -+ for (i = 0; i < wr_len; i++) { -+ wr_value[i] = strtol(argv[3 + i], &stopstring, 16); -+ DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); -+ } -+ -+ dfd_utest_print_cmd(argc, argv); -+ -+ printf(":\n"); -+ ret = dfd_write_io_port(offset_addr, wr_value, wr_len); -+ if (ret < 0) { -+ printf("failed ret %d\n", ret); -+ } else { -+ printf("success\n"); -+ } -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+} -+ -+int dfd_utest_phymem_rd(int argc, char* argv[]) -+{ -+ int ret, width; -+ uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; -+ off_t offset_addr; -+ char *stopstring; -+ int num; -+ -+ if (argc != 5) { -+ DFD_DEBUG_ERROR("params error\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_RD); -+ goto exit; -+ } -+ -+ width = strtol(argv[2], &stopstring, 10); -+ offset_addr = strtol(argv[3], &stopstring, 16); -+ num = strtol(argv[4], &stopstring, 10); -+ -+ if (num > DFD_UTEST_MAX_RDWR_NUM) { -+ DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_RD); -+ goto exit; -+ } -+ -+ dfd_utest_print_cmd(argc, argv); -+ printf(":\n"); -+ mem_clear(value, sizeof(value)); -+ ret = dfd_process_mem(DEV_MEM_NAME, 0, width, offset_addr, value, num); -+ if (ret < 0) { -+ printf("failed ret %d\n", ret); -+ goto exit; -+ } -+ -+ dfd_utest_printf_reg(value, num, offset_addr); -+ -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+} -+ -+int dfd_utest_phymem_wr(int argc, char* argv[]) -+{ -+ int ret, width; -+ off_t offset_addr; -+ char *stopstring; -+ int32_t wr_len,i; -+ uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; -+ -+ if (argc < 5) { -+ DFD_DEBUG_ERROR("Input invalid.\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_WR); -+ goto exit; -+ } -+ -+ wr_len = argc - 4; -+ if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { -+ DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_WR); -+ goto exit; -+ } -+ -+ width = strtol(argv[2], &stopstring, 10); -+ offset_addr = strtol(argv[3], &stopstring, 16); -+ -+ for (i = 0; i < wr_len; i++) { -+ wr_value[i] = strtol(argv[4 + i], &stopstring, 16); -+ DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); -+ } -+ -+ dfd_utest_print_cmd(argc, argv); -+ -+ printf(":\n"); -+ ret = dfd_process_mem(DEV_MEM_NAME, 1, width, offset_addr, wr_value, wr_len); -+ if (ret < 0) { -+ printf("failed ret %d\n", ret); -+ } else { -+ printf("success\n"); -+ } -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+} -+ -+int dfd_utest_kmem_rd(int argc, char* argv[]) -+{ -+ int ret, width; -+ uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; -+ uint16_t offset_addr; -+ char *stopstring; -+ int num; -+ -+ if (argc != 5) { -+ DFD_DEBUG_ERROR("params error\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_RD); -+ goto exit; -+ } -+ -+ width = strtol(argv[2], &stopstring, 10); -+ offset_addr = strtol(argv[3], &stopstring, 16); -+ num = strtol(argv[4], &stopstring, 10); -+ -+ if (num > DFD_UTEST_MAX_RDWR_NUM) { -+ DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_RD); -+ goto exit; -+ } -+ -+ dfd_utest_print_cmd(argc, argv); -+ printf(":\n"); -+ mem_clear(value, sizeof(value)); -+ ret = dfd_process_mem(DEV_KMEM_NAME, 0, width, offset_addr, value, num); -+ if (ret < 0) { -+ printf("failed ret %d\n", ret); -+ goto exit; -+ } -+ -+ dfd_utest_printf_reg(value, num, offset_addr); -+ -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+} -+ -+int dfd_utest_kmem_wr(int argc, char* argv[]) -+{ -+ int ret; -+ uint16_t offset_addr, width; -+ char *stopstring; -+ int32_t wr_len,i; -+ uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; -+ -+ if (argc < 5) { -+ DFD_DEBUG_ERROR("Input invalid.\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_WR); -+ goto exit; -+ } -+ -+ wr_len = argc - 4; -+ if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { -+ DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_WR); -+ goto exit; -+ } -+ -+ width = strtol(argv[2], &stopstring, 10); -+ offset_addr = strtol(argv[3], &stopstring, 16); -+ -+ for (i = 0; i < wr_len; i++) { -+ wr_value[i] = strtol(argv[4 + i], &stopstring, 16); -+ DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); -+ } -+ -+ dfd_utest_print_cmd(argc, argv); -+ -+ printf(":\n"); -+ ret = dfd_process_mem(DEV_KMEM_NAME, 1, width, offset_addr, wr_value, wr_len); -+ if (ret < 0) { -+ printf("failed ret %d\n", ret); -+ } else { -+ printf("success\n"); -+ } -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+} -+ -+static unsigned long dfd_utest_get_file_size(const char *path) -+{ -+ unsigned long filesize; -+ struct stat statbuff; -+ -+ if (stat(path, &statbuff) < 0) { -+ filesize = -1; -+ } else { -+ filesize = statbuff.st_size; -+ } -+ -+ return filesize; -+} -+ -+int dfd_utest_i2c_file_wr(int argc, char* argv[]) -+{ -+ int ret; -+ uint16_t dev_addr, offset_addr; -+ char *stopstring; -+ int i2c_bus; -+ char i2c_path[32]; -+ char *file_name; -+ unsigned long filesize; -+ int fd; -+ uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; -+ int len; -+ int bpt; /* byte per times*/ -+ int page_left; -+ -+ if (argc != 7) { -+ printf("Input invalid.\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_FILE_WR); -+ goto exit; -+ } -+ -+ i2c_bus = strtol(argv[2], &stopstring, 10); -+ dev_addr = strtol(argv[3], &stopstring, 16); -+ offset_addr = strtol(argv[4], &stopstring, 16); -+ bpt = strtol(argv[5], &stopstring, 10); -+ file_name = argv[6]; -+ -+ if ((bpt <= 0) || (bpt > DFD_UTEST_MAX_RDWR_NUM)) { -+ bpt = DFD_UTEST_MAX_RDWR_NUM; -+ } -+ -+ if ((bpt & (bpt - 1)) != 0) { -+ printf("Bytes per times %d isn't power of two.\n",bpt); -+ goto exit; -+ } -+ -+ filesize = dfd_utest_get_file_size(file_name); -+ if (filesize <= 0) { -+ printf("Input invalid file %s, filesize %lu.\n", file_name, filesize); -+ goto exit; -+ } -+ -+ fd = open(file_name, O_RDONLY); -+ if (fd < 0) { -+ printf("open file[%s] fail.\n", file_name); -+ goto exit; -+ } -+ -+ dfd_utest_print_cmd(argc, argv); -+ -+ printf(":\n"); -+ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); -+ -+ while (filesize > 0) { -+ mem_clear(wr_buf, DFD_UTEST_MAX_RDWR_NUM); -+ len = bpt; -+ if (offset_addr & (bpt - 1)) { -+ page_left = bpt - (offset_addr & (bpt - 1)); -+ len = len > page_left ? page_left : len; -+ } -+ -+ len = read(fd, wr_buf, len); -+ -+ ret = dfd_write_port_i2c(i2c_path, dev_addr, offset_addr, wr_buf, len); -+ if (ret < 0) { -+ break; -+ } -+ offset_addr += len; -+ filesize -= len; -+ } -+ -+ close(fd); -+ -+ if (ret < 0) { -+ printf("failed ret %d\n", ret); -+ } else { -+ printf("success\n"); -+ } -+ -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+ -+} -+ -+/* compare with sys_flie_wr, One more step is read back verification */ -+int dfd_utest_sysfs_file_upg(int argc, char* argv[]) -+{ -+ int ret = 0; -+ uint32_t offset_addr; -+ char *file_name; -+ char *sysfs_loc; -+ char *stopstring; -+ unsigned long filesize; -+ int fd, file_fd; -+ uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; -+ int len, write_len, per_wr_len; -+ int i; -+ uint8_t reread_buf[DFD_UTEST_MAX_RDWR_NUM]; -+ int reback_len, reread_len; -+ int j = 0; -+ -+ if (argc != 5 && argc != 6) { -+ printf("Input invalid.\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_FILE_UPG); -+ goto exit; -+ } -+ -+ sysfs_loc = argv[2]; -+ offset_addr = strtol(argv[3], &stopstring, 16); -+ file_name = argv[4]; -+ -+ if (argc == 6) { -+ per_wr_len = strtol(argv[5], &stopstring, 10); -+ if (per_wr_len > DFD_UTEST_MAX_RDWR_NUM || per_wr_len <= 0) { -+ printf("per_wr_byte %d invalid, not in range (0, 256]\n", per_wr_len); -+ goto exit; -+ } -+ } else { -+ per_wr_len = DFD_UTEST_DEFAULT_WR_NUM; -+ } -+ DFD_DEBUG_DBG("per_wr_byte: %d\n", per_wr_len); -+ filesize = dfd_utest_get_file_size(file_name); -+ if (filesize <= 0) { -+ printf("Input invalid file %s, filesize %lu.\n", file_name, filesize); -+ goto exit; -+ } -+ -+ fd = open(sysfs_loc, O_RDWR | O_SYNC); -+ if (fd < 0) { -+ printf("open file[%s] fail.\n", sysfs_loc); -+ goto exit; -+ } -+ -+ file_fd = open(file_name, O_RDONLY); -+ if (file_fd < 0) { -+ printf("open file[%s] fail.\n", file_name); -+ goto open_dev_err; -+ } -+ -+ dfd_utest_print_cmd(argc, argv); -+ -+ ret = lseek(fd, offset_addr, SEEK_SET); -+ if (ret < 0) { -+ printf("lseek file[%s offset=%d] fail,\n", sysfs_loc, offset_addr); -+ goto fail; -+ } -+ -+ printf(":\n"); -+ while (filesize > 0) { -+ if (filesize > (unsigned long)per_wr_len) { -+ len = per_wr_len; -+ } else { -+ len = filesize; -+ } -+ -+ mem_clear(wr_buf, DFD_UTEST_MAX_RDWR_NUM); -+ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { -+ len = read(file_fd, wr_buf, len); -+ if (len < 0) { -+ DFD_DEBUG_ERROR("read file[%s] fail, offset = 0x%x retrytimes = %d ret = %d\n", -+ sysfs_loc, offset_addr, i ,len); -+ usleep(DFD_I2C_RETRY_SLEEP_TIME); -+ continue; -+ } -+ break; -+ } -+ if (i == DFD_I2C_RETRY_TIME) { -+ printf("read file[%s] fail, offset = 0x%x, ret = %d\n", sysfs_loc, offset_addr, len); -+ goto fail; -+ } -+ -+ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { -+ write_len = write(fd, wr_buf, len); -+ if (write_len != len) { -+ DFD_DEBUG_ERROR("write file[%s] fail,offset = 0x%x retrytimes = %d len = %d,write_len =%d\n", -+ sysfs_loc, offset_addr, i ,len, write_len); -+ usleep(DFD_I2C_RETRY_SLEEP_TIME); -+ continue; -+ } -+ break; -+ } -+ if (i == DFD_I2C_RETRY_TIME) { -+ printf("write file[%s] fail, offset = 0x%x, len = %d,write_len =%d\n", -+ sysfs_loc, offset_addr, len, write_len); -+ goto fail; -+ } -+ -+ reback_len = write_len; -+ ret = lseek(fd, -reback_len, SEEK_CUR); -+ if (ret < 0) { -+ printf("reread lseek file[%s offset=%d] fail,lseek len=%d\n", -+ sysfs_loc, offset_addr, reback_len); -+ goto fail; -+ } -+ -+ mem_clear(reread_buf, DFD_UTEST_MAX_RDWR_NUM); -+ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { -+ reread_len = read(fd, reread_buf, reback_len); -+ if (reread_len != reback_len) { -+ DFD_DEBUG_ERROR("reread file[%s] fail,offset = 0x%x retrytimes = %d reread_len = %d,reback_len =%d\n", -+ sysfs_loc, offset_addr, i ,reread_len, reback_len); -+ usleep(DFD_I2C_RETRY_SLEEP_TIME); -+ continue; -+ } -+ break; -+ } -+ if (i == DFD_I2C_RETRY_TIME) { -+ printf("reread file[%s] fail, offset = 0x%x, reread_len = %d,reback_len = %d\n", -+ sysfs_loc, offset_addr, reread_len, reback_len); -+ goto fail; -+ } -+ -+ if (memcmp(reread_buf, wr_buf, reread_len) != 0) { -+ if (j < DFD_I2C_RETRY_TIME) { -+ DFD_DEBUG_ERROR("memcmp file[%s] fail,offset = 0x%x retrytimes = %d\n", -+ sysfs_loc, offset_addr, j); -+ j++; -+ ret = lseek(file_fd, -len, SEEK_CUR); -+ if (ret < 0) { -+ printf("retry file_fd lseek fail,lseek len=%d\n", len); -+ goto fail; -+ } -+ ret = lseek(fd, -write_len, SEEK_CUR); -+ if (ret < 0) { -+ printf("retry fd lseek fail,lseek len=%d\n", write_len); -+ goto fail; -+ } -+ continue; -+ } -+ -+ printf("upgrade file[%s] fail, offset = 0x%x.\n", sysfs_loc, offset_addr); -+ printf("want to write buf :\n"); -+ for (i = 0; i < reread_len; i++) { -+ printf("0x%x ", wr_buf[i]); -+ } -+ printf("\n"); -+ -+ printf("actually reread buf :\n"); -+ for (i = 0; i < reread_len; i++) { -+ printf("0x%x ", reread_buf[i]); -+ } -+ printf("\n"); -+ -+ goto fail; -+ } -+ -+ offset_addr += len; -+ filesize -= len; -+ usleep(5000); -+ } -+ -+ printf("success\n"); -+ close(file_fd); -+ close(fd); -+ return DFD_RV_OK; -+ -+fail: -+ close(file_fd); -+open_dev_err: -+ close(fd); -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+} -+ -+int dfd_utest_sysfs_file_wr(int argc, char* argv[]) -+{ -+ int ret = 0; -+ uint32_t offset_addr; -+ char *file_name; -+ char *sysfs_loc; -+ char *stopstring; -+ unsigned long filesize; -+ int fd, file_fd; -+ uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; -+ int len, write_len, per_wr_len; -+ int i; -+ -+ if (argc != 5 && argc != 6) { -+ printf("Input invalid.\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_FILE_WR); -+ goto exit; -+ } -+ -+ sysfs_loc = argv[2]; -+ offset_addr = strtol(argv[3], &stopstring, 16); -+ file_name = argv[4]; -+ -+ if (argc == 6) { -+ per_wr_len = strtol(argv[5], &stopstring, 10); -+ if (per_wr_len > DFD_UTEST_MAX_RDWR_NUM || per_wr_len <= 0) { -+ printf("per_wr_byte %d invalid, not in range (0, 256]\n", per_wr_len); -+ goto exit; -+ } -+ } else { -+ per_wr_len = DFD_UTEST_DEFAULT_WR_NUM; -+ } -+ DFD_DEBUG_DBG("per_wr_byte: %d\n", per_wr_len); -+ filesize = dfd_utest_get_file_size(file_name); -+ if (filesize <= 0) { -+ printf("Input invalid file %s, filesize %lu.\n", file_name, filesize); -+ goto exit; -+ } -+ -+ fd = open(sysfs_loc, O_RDWR | O_SYNC); -+ if (fd < 0) { -+ printf("open file[%s] fail.\n", sysfs_loc); -+ goto exit; -+ } -+ -+ file_fd = open(file_name, O_RDONLY); -+ if (file_fd < 0) { -+ printf("open file[%s] fail.\n", file_name); -+ goto open_dev_err; -+ } -+ -+ dfd_utest_print_cmd(argc, argv); -+ -+ ret = lseek(fd, offset_addr, SEEK_SET); -+ if (ret < 0) { -+ printf("lseek file[%s offset=%d] fail,\n", sysfs_loc, offset_addr); -+ goto fail; -+ } -+ -+ printf(":\n"); -+ while (filesize > 0) { -+ if (filesize > (unsigned long)per_wr_len) { -+ len = per_wr_len; -+ } else { -+ len = filesize; -+ } -+ -+ mem_clear(wr_buf, DFD_UTEST_MAX_RDWR_NUM); -+ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { -+ len = read(file_fd, wr_buf, len); -+ if (len < 0) { -+ DFD_DEBUG_ERROR("read file[%s] fail, offset = 0x%x retrytimes = %d ret = %d\n", -+ sysfs_loc, offset_addr, i ,len); -+ usleep(DFD_I2C_RETRY_SLEEP_TIME); -+ continue; -+ } -+ break; -+ } -+ if (i == DFD_I2C_RETRY_TIME) { -+ printf("read file[%s] fail, offset = 0x%x, ret = %d\n", sysfs_loc, offset_addr, len); -+ goto fail; -+ } -+ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { -+ write_len = write(fd, wr_buf, len); -+ if (write_len != len) { -+ DFD_DEBUG_ERROR("write file[%s] fail,offset = 0x%x retrytimes = %d len = %d,write_len =%d\n", sysfs_loc, offset_addr, i ,len, write_len); -+ usleep(DFD_I2C_RETRY_SLEEP_TIME); -+ continue; -+ } -+ break; -+ } -+ -+ if(i == DFD_I2C_RETRY_TIME) { -+ printf("write file[%s] fail, offset = 0x%x, len = %d,write_len =%d\n", sysfs_loc, offset_addr, len, write_len); -+ ret = -1; -+ goto fail; -+ } -+ offset_addr += len; -+ filesize -= len; -+ usleep(5000); -+ } -+ -+ printf("success\n"); -+ close(file_fd); -+ close(fd); -+ return DFD_RV_OK; -+ -+fail: -+ close(file_fd); -+open_dev_err: -+ close(fd); -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+} -+ -+int dfd_utest_sysfs_file_rd(int argc, char* argv[]) -+{ -+ int ret = 0; -+ uint32_t offset_addr; -+ char *sysfs_loc; -+ char *stopstring; -+ int fd; -+ uint8_t rd_buf[DFD_UTEST_MAX_RDWR_NUM]; -+ int len, read_len;; -+ -+ if (argc != 5) { -+ printf("Input invalid.\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_FILE_RD); -+ goto exit; -+ } -+ -+ sysfs_loc = argv[2]; -+ offset_addr = strtol(argv[3], &stopstring, 16); -+ len = strtol(argv[4], &stopstring, 10); -+ -+ if (len > DFD_UTEST_MAX_RDWR_NUM) { -+ printf("Input num %d exceed max 256.\n", len); -+ goto exit; -+ } -+ -+ fd = open(sysfs_loc, O_RDONLY); -+ if (fd < 0) { -+ printf("open file[%s] fail.\n", sysfs_loc); -+ goto exit; -+ } -+ dfd_utest_print_cmd(argc, argv); -+ -+ printf(":\n"); -+ -+ ret = lseek(fd, offset_addr, SEEK_SET); -+ if (ret < 0) { -+ printf("lseek failed ret %d.\n", ret); -+ goto fail; -+ } -+ -+ mem_clear(rd_buf, DFD_UTEST_MAX_RDWR_NUM); -+ read_len = read(fd, rd_buf, len); -+ if (read_len != len) { -+ printf("read failed read_len %d len %d.\n", read_len, len); -+ goto fail; -+ } -+ dfd_utest_printf_reg(rd_buf, read_len, offset_addr); -+ close(fd); -+ return DFD_RV_OK; -+ -+fail: -+ close(fd); -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+} -+ -+int dfd_utest_msr_rd(int argc, char* argv[]) -+{ -+ int fd; -+ char msr_file_name[64]; -+ uint64_t data; -+ uint64_t read_result; -+ char *stopstring; -+ uint8_t cpu_index, width; -+ uint64_t offset; -+ -+ if (argc != 5) { -+ printf("rdmsr failed: Input invalid.\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_MSR_RD); -+ goto exit; -+ } -+ -+ cpu_index = strtol(argv[2], &stopstring, 10); -+ offset = strtol(argv[3], &stopstring, 16); -+ width = strtol(argv[4], &stopstring, 10); -+ -+ if (width != 8 && width != 16 && width != 32 && width != 64) { -+ printf("rdmsr failed: width:%u Input invalid.only support 8 16 32 64\n", width); -+ goto exit; -+ } -+ -+ mem_clear(msr_file_name, sizeof(msr_file_name)); -+ sprintf(msr_file_name, "/dev/cpu/%u/msr", cpu_index); -+ -+ fd = open(msr_file_name, O_RDONLY); -+ if (fd < 0) { -+ if (errno == ENXIO) { -+ fprintf(stderr, "rdmsr failed: No CPU %u\n", cpu_index); -+ } else if (errno == EIO) { -+ fprintf(stderr, "rdmsr failed: CPU %u doesn't support MSRs\n", cpu_index); -+ } else if (errno == ENOENT) { -+ fprintf(stderr, "rdmsr failed: can't find %s file, Please check if modprobe msr driver already\n", msr_file_name); -+ } else { -+ printf("rdmsr failed: %s open failed. errno:%d\n", msr_file_name, errno); -+ } -+ goto exit; -+ } -+ -+ if (pread(fd, &data, sizeof(data), offset) != sizeof(data)) { -+ fprintf(stderr, "rdmsr failed: CPU:%u offset:0x%lx read failed\n", cpu_index, offset); -+ goto fail; -+ } -+ -+ switch (width) { -+ case 8: -+ read_result = (volatile uint8_t)data; -+ break; -+ case 16: -+ read_result = (volatile uint16_t)data; -+ break; -+ case 32: -+ read_result = (volatile uint32_t)data; -+ break; -+ case 64: -+ read_result = (volatile uint64_t)data; -+ break; -+ default: -+ printf("rdmsr failed: width:%u illegal width.\n", width); -+ goto fail; -+ } -+ -+ printf("0x%lx\n", read_result); -+ close(fd); -+ return DFD_RV_OK; -+ -+fail: -+ close(fd); -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+} -+ -+int dfd_utest_sysfs_data_wr(int argc, char* argv[]) -+{ -+ uint32_t offset; -+ char *sysfs_loc; -+ char *stopstring; -+ uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; -+ int ret, i; -+ int fd, len, write_len, index; -+ -+ if (argc < 5) { -+ DFD_DEBUG_ERROR("Input invalid.\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_DATA_WR); -+ goto exit; -+ } -+ -+ dfd_utest_print_cmd(argc, argv); -+ printf(":\n"); -+ -+ sysfs_loc = argv[2]; -+ offset = strtol(argv[3], &stopstring, 16); -+ len = argc - 4; -+ mem_clear(wr_buf, sizeof(wr_buf)); -+ for (i = 0; i < len; i++) { -+ wr_buf[i] = strtol(argv[4 + i], &stopstring, 16); -+ DFD_DEBUG_DBG("index :%d value %x\n", i , wr_buf[i]); -+ } -+ -+ fd = open(sysfs_loc, O_RDWR | O_SYNC); -+ if (fd < 0) { -+ printf("open file[%s] fail.\n", sysfs_loc); -+ goto exit; -+ } -+ -+ ret = lseek(fd, offset, SEEK_SET); -+ if (ret < 0) { -+ printf("lseek file[%s offset=%d] fail,\n", sysfs_loc, offset); -+ goto fail; -+ } -+ index = 0; -+ while (len > 0) { -+ for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { -+ write_len = write(fd, &wr_buf[index], len); -+ if (write_len < 0) { -+ DFD_DEBUG_ERROR("write file[%s] fail, retrytimes: %d, offset: 0x%x, len: %d, write_len: %d\n", -+ sysfs_loc, offset, i, len, write_len); -+ usleep(DFD_I2C_RETRY_SLEEP_TIME); -+ continue; -+ } -+ if (write_len == 0) { -+ DFD_DEBUG_ERROR("write file[%s] EOF, offset: 0x%x, len: %d, write_len: %d\n", -+ sysfs_loc, offset, len, write_len); -+ goto fail; -+ } -+ break; -+ } -+ if(i == DFD_I2C_RETRY_TIME) { -+ printf("write file[%s] fail, offset: 0x%x, len: %d, write_len: %d\n", -+ sysfs_loc, offset, len, write_len); -+ goto fail; -+ } -+ offset += write_len; -+ index += write_len; -+ len -= write_len; -+ usleep(5000); -+ } -+ printf("success\n"); -+ close(fd); -+ return DFD_RV_OK; -+fail: -+ close(fd); -+exit: -+ return DFD_RV_MODE_NOTSUPPORT; -+} -+ -+static void phy_help(char *name) -+{ -+ fprintf(stderr, -+ "Usage: %s phy_index(dec) regnum(hex) [regval(hex)] \n" -+ " phy_index phydev index \n" -+ " regnum phydev register address \n" -+ " regval phydev register value \n", -+ name); -+ return; -+} -+ -+static void mdio_help(char *name) -+{ -+ fprintf(stderr, -+ "Usage: %s mdio_index(dec) phyaddr(hex) regnum(hex) [regval(hex)] \n" -+ " mdio_index mdiodev index \n" -+ " phyaddr phydev address \n" -+ " regnum phydev register address \n" -+ " regval phydev register value \n", -+ name); -+ return; -+} -+ -+static int phydev_arg_parse(int argc, char* argv[], int *phy_index, uint32_t *regnum, uint32_t *regval, -+ int num_arg) -+{ -+ -+ unsigned long index, regaddr, value; -+ char *end; -+ -+ if (argc != num_arg) { -+ return -EINVAL; -+ } -+ -+ index = strtoul(argv[2], &end, 0); -+ if (*end) { -+ fprintf(stderr, "Error: index invalid!\n"); -+ return -EINVAL; -+ } -+ -+ regaddr = strtoul(argv[3], &end, 0); -+ if (*end || regaddr > 0xffff) { -+ fprintf(stderr, "Error: regaddr invalid!\n"); -+ return -EINVAL; -+ } -+ -+ if (argc > 4) { -+ value = strtoul(argv[4], &end, 0); -+ if (*end || value > 0xffff) { -+ fprintf(stderr, "Error: reg data invalid!\n"); -+ return -EINVAL; -+ } -+ -+ *regval = (uint32_t)value; -+ } -+ -+ *phy_index = (uint32_t)index; -+ *regnum = (uint32_t)regaddr; -+ -+ return 0; -+} -+ -+static int mdiodev_arg_parse(int argc, char* argv[], int *mdio_index, int *phyaddr, uint32_t *regnum, -+ uint32_t *regval, int num_arg) -+{ -+ -+ unsigned long index, addr, regaddr, value; -+ char *end; -+ -+ if (argc != num_arg) { -+ return -EINVAL; -+ } -+ -+ index = strtoul(argv[2], &end, 0); -+ if (*end) { -+ fprintf(stderr, "Error: index invalid!\n"); -+ return -EINVAL; -+ } -+ -+ addr = strtoul(argv[3], &end, 0); -+ if (*end || addr > 0x1f) { -+ fprintf(stderr, "Error: phyaddr invalid!\n"); -+ return -EINVAL; -+ } -+ -+ regaddr = strtoul(argv[4], &end, 0); -+ if (*end || regaddr > 0xffff) { -+ fprintf(stderr, "Error: regaddr invalid!\n"); -+ return -EINVAL; -+ } -+ -+ if (argc > 5) { -+ value = strtoul(argv[5], &end, 0); -+ if (*end || value > 0xffff) { -+ fprintf(stderr, "Error: reg data invalid!\n"); -+ return -EINVAL; -+ } -+ -+ *regval = (uint32_t)value; -+ } -+ -+ *mdio_index = (uint32_t)index; -+ *phyaddr = (int)addr; -+ *regnum = (uint32_t)regaddr; -+ -+ return 0; -+} -+ -+int dfd_utest_phydev_list(int argc, char* argv[]) -+{ -+ int fd; -+ -+ if (argc != 2) { -+ printf("Input invalid.\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYDEV_LIST); -+ return DFD_RV_MODE_NOTSUPPORT; -+ } -+ -+ argv = argv; -+ fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); -+ if (fd < 0) { -+ fprintf(stderr, "Error: Could not open file " -+ "/dev/dram: %s\n", strerror(errno)); -+ return -1; -+ } -+ -+ (void)ioctl(fd, CMD_PHY_LIST, NULL); -+ -+ close(fd); -+ -+ return 0; -+} -+ -+int dfd_utest_phydev_rd(int argc, char* argv[]) -+{ -+ struct phydev_user_info phy_info; -+ int fd; -+ long int ret; -+ -+ ret = phydev_arg_parse(argc, argv, &phy_info.phy_index, &phy_info.regnum, &phy_info.regval, 4); -+ if (ret < 0) { -+ phy_help("phydev_rd"); -+ return -1; -+ } -+ -+ fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); -+ if (fd < 0) { -+ fprintf(stderr, "Error: Could not open file " -+ "/dev/dram: %s\n", strerror(errno)); -+ return -1; -+ } -+ -+ ret = ioctl(fd, CMD_PHY_READ, &phy_info); -+ if (ret < 0) { -+ fprintf(stderr, "Error: phy read error : %s\n", strerror(errno)); -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ -+ printf("Read success --- phydev%d regnum: 0x%x, value: 0x%x\n",phy_info.phy_index, -+ phy_info.regnum, phy_info.regval); -+ -+ return 0; -+} -+ -+int dfd_utest_phydev_wr(int argc, char* argv[]) -+{ -+ struct phydev_user_info phy_info; -+ int fd; -+ long int ret; -+ -+ ret = phydev_arg_parse(argc, argv, &phy_info.phy_index, &phy_info.regnum, &phy_info.regval, 5); -+ if (ret < 0) { -+ phy_help("phydev_wr"); -+ return -1; -+ } -+ -+ fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); -+ if (fd < 0) { -+ fprintf(stderr, "Error: Could not open file " -+ "/dev/dram: %s\n", strerror(errno)); -+ return -1; -+ } -+ -+ ret = ioctl(fd, CMD_PHY_WRITE, &phy_info); -+ if (ret < 0) { -+ fprintf(stderr, "Error: phy write error : %s\n", strerror(errno)); -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ -+ printf("write success --- phydev%d regnum: 0x%x, value: 0x%x\n",phy_info.phy_index, -+ phy_info.regnum, phy_info.regval); -+ -+ return 0; -+} -+ -+int dfd_utest_mdiodev_list(int argc, char* argv[]) -+{ -+ int fd; -+ -+ if (argc != 2) { -+ printf("Input invalid.\n"); -+ dfd_utest_printf_single_help(DFD_UTEST_ITEM_MDIODEV_LIST); -+ return DFD_RV_MODE_NOTSUPPORT; -+ } -+ -+ argv = argv; -+ fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); -+ if (fd < 0) { -+ fprintf(stderr, "Error: Could not open file " -+ "/dev/dram: %s\n", strerror(errno)); -+ return -1; -+ } -+ -+ (void)ioctl(fd, CMD_MDIO_LIST, NULL); -+ -+ close(fd); -+ -+ return 0; -+} -+ -+int dfd_utest_mdiodev_rd(int argc, char* argv[]) -+{ -+ struct mdio_dev_user_info mdio_info; -+ int fd; -+ long int ret; -+ -+ ret = mdiodev_arg_parse(argc, argv, &mdio_info.mdio_index, &mdio_info.phyaddr, -+ &mdio_info.regnum, &mdio_info.regval, 5); -+ if (ret < 0) { -+ mdio_help("mdiodev_rd"); -+ return -1; -+ } -+ -+ fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); -+ if (fd < 0) { -+ fprintf(stderr, "Error: Could not open file " -+ "/dev/dram: %s\n", strerror(errno)); -+ return -1; -+ } -+ -+ ret = ioctl(fd, CMD_MDIO_READ, &mdio_info); -+ if (ret < 0) { -+ fprintf(stderr, "Error: mdio read error : %s\n", strerror(errno)); -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ -+ printf("Read success\n mdio_index phyaddr regnum value\n"); -+ printf(" %-10d %#-10x %#-10x %#-10x\n", mdio_info.mdio_index, mdio_info.phyaddr, -+ mdio_info.regnum, mdio_info.regval); -+ -+ return 0; -+} -+ -+int dfd_utest_mdiodev_wr(int argc, char* argv[]) -+{ -+ struct mdio_dev_user_info mdio_info; -+ int fd; -+ long int ret; -+ -+ ret = mdiodev_arg_parse(argc, argv, &mdio_info.mdio_index, &mdio_info.phyaddr, -+ &mdio_info.regnum, &mdio_info.regval, 6); -+ if (ret < 0) { -+ mdio_help("mdiodev_wr"); -+ return -1; -+ } -+ -+ fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); -+ if (fd < 0) { -+ fprintf(stderr, "Error: Could not open file " -+ "/dev/dram: %s\n", strerror(errno)); -+ return -1; -+ } -+ -+ ret = ioctl(fd, CMD_MDIO_WRITE, &mdio_info); -+ if (ret < 0) { -+ fprintf(stderr, "Error: mdio write error : %s\n", strerror(errno)); -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ -+ printf("write success\n mdio_index phyaddr regnum value\n"); -+ printf(" %-10d %#-10x %#-10x %#-10x\n", mdio_info.mdio_index, mdio_info.phyaddr, -+ mdio_info.regnum, mdio_info.regval); -+ -+ return 0; -+} -+ -+dfd_utest_proc_fun dfd_utest_get_proc_func(char *type_str) -+{ -+ int i, tbl_size; -+ -+ tbl_size = sizeof(g_dfd_unit_test) / sizeof(g_dfd_unit_test[0]); -+ -+ for (i = 0; i < tbl_size; i++) { -+ if (!strncmp(g_dfd_unit_test[i].type_str, type_str, strlen(g_dfd_unit_test[i].type_str))) { -+ return g_dfd_unit_test[i].utest_func; -+ } -+ } -+ DFD_DEBUG_DBG("type: %s not match.\n", type_str); -+ return NULL; -+} -+ -+void dfd_utest_cmd_main(int argc, char* argv[]) -+{ -+ dfd_utest_proc_fun pfunc; -+ int ret; -+ -+ if (argc < 2) { -+ dfd_utest_print_all_help(); -+ return; -+ } -+ -+ pfunc = dfd_utest_get_proc_func(argv[1]); -+ if (pfunc == NULL) { -+ DFD_DEBUG_DBG("utest type %s in not support.\n", argv[1]); -+ dfd_utest_print_all_help(); -+ return; -+ } -+ ret = pfunc(argc, argv); -+ if ((ret != DFD_RV_MODE_NOTSUPPORT) && (ret != DFD_RV_INDEX_INVALID)) { -+ if (ret == DFD_RV_OK) { -+ DFD_DEBUG_DBG(" [SUCCESS]\n"); -+ } else { -+ DFD_DEBUG_DBG(" [FAIL(%d)]\n", ret); -+ } -+ } -+ -+ return; -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.h b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.h -new file mode 100644 -index 000000000..1ae65148e ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.h -@@ -0,0 +1,109 @@ -+/* monitor_utest.h */ -+#ifndef __DFD_UTEST_H__ -+#define __DFD_UTEST_H__ -+ -+#include -+ -+extern int g_dfd_debug_sw; -+extern int g_dfd_debugpp_sw; -+ -+#define DFD_UTEST_TRUE_FALSE_STRING(flag) ((flag == true) ? "true" : "false") -+ -+#define DFD_DEBUG_DBG(fmt, args...) do { \ -+ if (g_dfd_debug_sw) { \ -+ printf("" fmt,\ -+ ##args); \ -+ } \ -+} while (0) -+ -+#define DFD_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_dfd_debugpp_sw) { \ -+ printf("" fmt,\ -+ ##args); \ -+ } \ -+} while (0) -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+ -+typedef enum dfd_rv_s { -+ DFD_RV_OK = 0, -+ DFD_RV_INIT_ERR = 1, -+ DFD_RV_SLOT_INVALID = 2, -+ DFD_RV_MODE_INVALID = 3, -+ DFD_RV_MODE_NOTSUPPORT = 4, -+ DFD_RV_TYPE_ERR = 5, -+ DFD_RV_DEV_NOTSUPPORT = 6, -+ DFD_RV_DEV_FAIL = 7, -+ DFD_RV_INDEX_INVALID = 8, -+ DFD_RV_NO_INTF = 9, -+ DFD_RV_NO_NODE = 10, -+ DFD_RV_NODE_FAIL = 11, -+} dfd_rv_t; -+ -+#define DFD_DEBUG_BUF_LEN (32) -+#define DFD_DEBUGP_DEBUG_FILE "/sbin/.dfd_debugp_flag" -+#define DFD_DEBUGPP_DEBUG_FILE "/sbin/.dfd_debugpp_flag" -+ -+#define DFD_UTEST_MAX_PARA_NUM (4) -+#define DFD_UTEST_TYPE_STRING_LEN (64) -+#define DFD_UTEST_MATCH_STRING_LEN (64) -+#define DFD_UTEST_HELP_STRING_LEN (256) -+#define DFD_UTEST_INVALID_PARA (-1) -+#define DFD_UTEST_BUFF_LEN (64) -+ -+typedef enum dfd_fpga_cpld_flag_e { -+ DFD_CPLD_RW_FLAG = 0x00, -+ DFD_FPGA_RW_FLAG = 0x01, -+} dfd_fpga_cpld_flag_t; -+ -+typedef int (* dfd_utest_proc_fun)(int argc, char* argv[]); -+ -+#define DFD_UTEST_ITEM_ALL \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_RD, i2c_rd, "i2c_rd [i2c_bus] [slave_addr] [offset] [len]", "i2c_rd [i2c_bus] [slave_addr] [offset] [len]") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_WR, i2c_wr, "i2c_wr [i2c_bus] [slave_addr] [offset] [data0] ... [dataN]", "i2c_wr [i2c_bus] [slave_addr] [offset] [data0] ... [dataN]") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_IO_RD, io_rd, "io_rd [offset] [len]", "io_rd [offset] [len]") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_IO_WR, io_wr, "io_wr [offset] [data0]... [dataN]", "io_wr [offset] [data0]... [dataN]") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYMEM_RD, phymem_rd, "phymem_rd [bit_width] [offset] [len]", "phymem_rd [bit_width] [offset] [len]") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYMEM_WR, phymem_wr, "phymem_wr [bit_width] [offset] [data0]... [dataN]", "phymem_wr [bit_width] [offset] [data0]... [dataN]") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_KMEM_RD, kmem_rd, "kmem_rd [bit_width] [offset] [len]", "kmem_rd [bit_width] [offset] [len]") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_KMEM_WR, kmem_wr, "kmem_wr [bit_width][offset] [data0]... [dataN]", "kmem_wr [bit_width] [offset] [data0]... [dataN]") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_FILE_WR, i2c_file_wr, "i2c_file_wr [i2c_bus] [slave_addr] [offset] [bpt] [filename]", "i2c_file_wr [i2c_bus] [slave_addr] [offset] [bpt] [filename]\nbpt:bytes per times") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_FILE_WR, sysfs_file_wr, "sysfs_file_wr [sysfs_loc] [offset] [filename] [per_wr_byte]", "sysfs_file_wr [sysfs_loc] [offset] [filename] [per_wr_byte]") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_FILE_RD, sysfs_file_rd, "sysfs_file_rd [sysfs_loc] [offset] [len]", "sysfs_file_rd [sysfs_loc] [offset] [len]") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_FILE_UPG, sysfs_file_upg, "sysfs_file_upg [sysfs_loc] [offset] [filename] [per_wr_byte]", "sysfs_file_upg [sysfs_loc] [offset] [filename] [per_wr_byte]") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_GEN_RD, i2c_gen_rd, "i2c_gen_rd [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [len]", "i2c_gen_rd [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [len]") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_GEN_WR, i2c_gen_wr, "i2c_gen_wr [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [data0]... [dataN]", "i2c_gen_wr [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [data0]... [dataN]") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_MSR_RD, msr_rd, "msr_rd [cpu_index] [offset] [width]", "msr_rd [cpu_index] [offset] [width]") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_DATA_WR, sysfs_data_wr, "sysfs_data_wr [sysfs_loc] [offset] [data0] ... [dataN]", "sysfs_data_wr [sysfs_loc] [offset] [data0] ... [dataN]]") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYDEV_LIST, phydev_list, "phydev_list", "phydev_list") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYDEV_RD, phydev_rd, "phydev_rd phy_index reg_addr", "phydev_rd phy_index reg_addr") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYDEV_WR, phydev_wr, "phydev_wr phy_index reg_addr reg_data", "phydev_wr phy_index reg_addr reg_data") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_MDIODEV_LIST, mdiodev_list, "mdiodev_list", "mdiodev_list") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_MDIODEV_RD, mdiodev_rd, "mdiodev_rd mdio_index phyaddr reg_addr", "mdiodev_rd mdio_index phyaddr reg_addr") \ -+ DFD_UTEST_ITEM(DFD_UTEST_ITEM_MDIODEV_WR, mdiodev_wr, "mdiodev_wr mdio_index phyaddr reg_addr reg_data", "mdiodev_wr mdio_index phyaddr reg_addr reg_data") \ -+ -+#ifdef DFD_UTEST_ITEM -+#undef DFD_UTEST_ITEM -+#endif -+#define DFD_UTEST_ITEM(_id, _type_str, _help_info, _help_info_detail) _id, -+typedef enum dfd_utest_item_id_s { -+ DFD_UTEST_ITEM_ALL -+} dfd_utest_item_id_t; -+ -+typedef struct { -+ int utest_type; -+ char type_str[DFD_UTEST_TYPE_STRING_LEN]; -+ dfd_utest_proc_fun utest_func; -+ char help_info[DFD_UTEST_HELP_STRING_LEN]; -+ char help_info_detail[DFD_UTEST_HELP_STRING_LEN]; -+} dfd_utest_t; -+ -+void dfd_utest_cmd_main(int argc, char* argv[]); -+ -+#ifdef DFD_UTEST_ITEM -+#undef DFD_UTEST_ITEM -+#endif -+#define DFD_UTEST_ITEM(_id, _type_str, _help_info, _help_info_detail) int dfd_utest_##_type_str(int argc, char* argv[]); -+DFD_UTEST_ITEM_ALL -+ -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Makefile -new file mode 100644 -index 000000000..1701b5f62 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Makefile -@@ -0,0 +1,18 @@ -+top_srcdir:=$(shell pwd) -+include $(top_srcdir)/Rules.mk -+ -+firmware-y:= -+firmware-y += fw_upgrade -+ -+.PHONY: all -+all: build -+ -+.PHONY: build -+build: $(firmware-y) -+$(foreach dir,$(firmware-y),$(eval $(call compile_dirs,$(dir)))) -+ -+.PHONY: rpmpkg -+rpmpkg: -+ifeq ("$(CONFIG_CPLD_UPGRADE_ISPVME)", "y") -+ #$(RPMPKG) $(install_cpld_dir) firmware-cpld-ispvme.spec git -+endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Rules.mk b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Rules.mk -new file mode 100644 -index 000000000..5fb5a09d3 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Rules.mk -@@ -0,0 +1,42 @@ -+CC ?= $(CROSS)gcc -+AR ?= $(CROSS)ar -+AS ?= $(CROSS)as -+LD ?= $(CROSS)ld -+STRIP ?= $(CROSS)strip -+ -+install_root:=${top_srcdir}/images -+ -+install_header_dir:=${install_root}/header -+install_adir:=$(install_root)/lib -+install_symbol_dir:=$(install_root)/symbol -+symbol_files:=$(shell find $(EXPORT_SYMBOL) -name 'Module.symvers') -+# -+# symbol_files += $(shell find $(install_symbol_dir) -name 'Module.symvers') -+# KBUILD_EXTRA_SYMBOLS += $(symbol_files) -+# export KBUILD_EXTRA_SYMBOLS -+ -+# top root: install_rootfs_dir -+install_rootfs_dir:=$(install_root)/rootfs -+ -+install_sodir:=$(install_rootfs_dir)/$(INSTALL_SODIR) -+ -+install_usr_bin_dir:=$(install_rootfs_dir)/usr/bin -+install_sbin_dir:=$(install_rootfs_dir)/sbin -+install_etc_dir:=$(install_rootfs_dir)/etc -+ -+export INSTALL_MOD_PATH:=$(ROOT) -+ -+BUILD_CFLAGS:=$(CFLAGS) -I$(install_header_dir) -+BUILD_LDFLAGS:=$(LDFLAGS) -L/$(install_sodir) -L/$(install_adir) -+ -+define compile_dirs -+.PHONY: $(1) -+$(1): -+ @echo;echo "building $(1)..." -+ @$(MAKE) -C ${1} -+endef -+ -+compile.c = $(CC) $(BUILD_CFLAGS) -d -c -o $@ $< -+%.o: %.c -+ $(compile.c) -+ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/Makefile -new file mode 100644 -index 000000000..8b4bca739 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/Makefile -@@ -0,0 +1,39 @@ -+include ../Rules.mk -+ -+OBJ = fw_upgrade.o fw_upgrade_debug.o -+ -+LIB += $(BUILD_CFALGS) $(BUILD_LDFLAGS) -lpthread -+ifdef ENABLE_GCOV -+ifeq ($(ENABLE_GCOV), y) -+LIB += -fprofile-arcs -+endif -+endif # ENABLE_GCOV -+ -+APP = fw_upgrade -+BUILD_DIR = tmp -+ELF_FILE = $(BUILD_DIR)/$(APP) -+MAP_FILE = $(BUILD_DIR)/$(APP).map.sym -+INCLUDE = -Iinclude -+CFLAGS+=-Wall -W -g -+ -+.PHONY: build -+build:make-dir $(addprefix $(BUILD_DIR)/,$(OBJ)) -+ $(CC) -o $(ELF_FILE) $(addprefix $(BUILD_DIR)/,$(OBJ)) $(LINKFLAGS) $(LIB) -+ -+ cp -p $(ELF_FILE) $(common_out_put_dir) -+ -+.PHONY: make-dir -+make-dir: -+ @mkdir -p $(BUILD_DIR) -+ -+$(BUILD_DIR)/%.o:%.c -+ $(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@ -+ -+.PHONY: install -+install: -+ echo "fw_upgrade install success." -+ cp -p $(ELF_FILE) $(common_out_put_dir) -+ -+.PHONY: clean -+clean: -+ rm -rf $(BUILD_DIR) -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade.c b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade.c -new file mode 100644 -index 000000000..2045608d5 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade.c -@@ -0,0 +1,1632 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "fw_upgrade.h" -+ -+static flash_info_t flash_info[] = { -+ { -+ .flash_name = "M25L6433F", -+ .flash_size = M32, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = MX25L6433F, -+ .block_size = STEP_64, -+ .full_erase = 1, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+ { -+ .flash_name = "S25FL512S", -+ .flash_size = M64, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = S25FL512S, -+ .block_size = STEP_256, -+ .full_erase = 0, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+ { -+ .flash_name = "MX25l512", -+ .flash_size = M64, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = MX25l512, -+ .block_size = STEP_64, -+ .full_erase = 1, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+ { -+ .flash_name = "STM25P64", -+ .flash_size = M12, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = STM25P64, -+ .block_size = STEP_256, -+ .full_erase = 1, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+ { -+ .flash_name = "STM25P128", -+ .flash_size = M16, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = STM25P128, -+ .block_size = STEP_256, -+ .full_erase = 1, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+ { -+ .flash_name = "N25Q256", -+ .flash_size = M16, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = N25Q256, -+ .block_size = STEP_256, -+ .full_erase = 1, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+ { -+ .flash_name = "N25Q512", -+ .flash_size = M16, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = N25Q512, -+ .block_size = STEP_256, -+ .full_erase = 1, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+ { -+ .flash_name = "W25X16", -+ .flash_size = M3, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = W25X16, -+ .block_size = STEP_256, -+ .full_erase = 1, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+ { -+ .flash_name = "W25X64", -+ .flash_size = M12, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = W25X64, -+ .block_size = STEP_256, -+ .full_erase = 1, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+ { -+ .flash_name = "W25Q64BV", -+ .flash_size = M12, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = W25Q64BV, -+ .block_size = STEP_256, -+ .full_erase = 1, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+ { -+ .flash_name = "W25Q128BV", -+ .flash_size = M16, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = W25Q128BV, -+ .block_size = STEP_256, -+ .full_erase = 1, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+ { -+ .flash_name = "W25Q256FV", -+ .flash_size = M16, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = W25Q256FV, -+ .block_size = STEP_256, -+ .full_erase = 1, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+ { -+ .flash_name = "MX25L1605D", -+ .flash_size = M32, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = MX25L1605D, -+ .block_size = STEP_256, -+ .full_erase = 1, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+ { -+ .flash_name = "MX25L12805D", -+ .flash_size = M32, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = MX25L12805D, -+ .block_size = STEP_256, -+ .full_erase = 1, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+ { -+ .flash_name = "MX66L1G45G", -+ .flash_size = M128, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = MX66L1G45G, -+ .block_size = STEP_256, -+ .full_erase = 1, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+ { -+ .flash_name = "GD25Q256", -+ .flash_size = M16, -+ .flash_type = SPI, -+ .page_size = BYTE_256, -+ .flash_id = GD25Q256, -+ .block_size = STEP_256, -+ .full_erase = 1, -+ .erase_block_command = BLOCK_ERASE_64, -+ .page_program = COMMON_PAGE_PROGRAM, -+ }, -+}; -+ -+static int debug_on; -+ -+static void help(void) -+{ -+ printf("------------------------------BMC Upgrade Tool--------------------------------\n"); -+ printf("Program Flash:\n"); -+ printf("\tfw_upgrade upgrade [file name] [chip select: 0 | 1 | 2] "); -+ printf("[erase type: full | block]\n"); -+ printf("\t[file name] if file is not located at /home/admin, path should be added\n"); -+ printf("\t[chip select] 0:master, 1:slave, 2:both\n"); -+ printf("\t[erase type] choose a way to erase chip, full erase would be faster\n"); -+ printf("Read BMC Reg:\n"); -+ printf("\tfw_upgrade rd [address] [length]\n"); -+ printf("\t[address(Hexadecimal)] register address of BMC\n"); -+ printf("\t[length(decimal)] length of read data, should be times of 4\n"); -+ -+ return; -+} -+ -+static int set_ioport_rw_access(void) -+{ -+ -+ if ( iopl(3) < 0) { -+ printf("Can't get access to /dev/port \n"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int get_file_size(char *file_name) -+{ -+ FILE * pFile; -+ int size; -+ -+ pFile = fopen(file_name,"rb"); -+ if (pFile == NULL) { -+ printf("Error opening file\n"); -+ return -1; -+ } -+ fseek (pFile, 0, SEEK_END); -+ size = ftell(pFile); -+ fclose (pFile); -+ return size; -+} -+ -+static uint8_t _read(uint16_t addr) -+{ -+ return inb(addr); -+} -+ -+static void _write(uint16_t addr, uint8_t val) -+{ -+ outb(val, addr); -+ -+ return; -+} -+ -+static void write_addr_port(uint8_t addr_val, uint16_t addr_port) -+{ -+ _write(addr_port, addr_val); -+ -+ return; -+} -+ -+static void write_data_port(uint8_t val, uint16_t data_port) -+{ -+ _write(data_port, val); -+ -+ return; -+} -+ -+static uint8_t read_data_port(uint16_t data_port) -+{ -+ return _read(data_port); -+} -+ -+static void write_ilpc2ahb_addr(uint32_t addr) -+{ -+ int i; -+ -+ for (i = 0; i < 4; i++) { -+ write_addr_port(SUPERIO_REG0 + i, LPC_ADDR_PORT); -+ write_data_port((addr >> (8 * (3 - i))) & MASK, LPC_DATA_PORT); -+ } -+ -+ return; -+} -+ -+static void write_ilpc2ahb_data(uint32_t data) -+{ -+ int i; -+ -+ for (i = 0; i < 4; i++) { -+ write_addr_port(SUPERIO_REG4 + i, LPC_ADDR_PORT); -+ write_data_port((data >> (8 * (3 - i))) & MASK, LPC_DATA_PORT); -+ } -+ -+ return; -+} -+ -+static uint32_t read_ilpc2ahb_data(void) -+{ -+ int i, tmp; -+ uint32_t res; -+ -+ res = 0; -+ for (i = 0; i < 4; i++) { -+ write_addr_port(SUPERIO_REG4 + i, LPC_ADDR_PORT); -+ tmp = read_data_port(LPC_DATA_PORT); -+ res |= (tmp << (8 * (3 - i))); -+ } -+ -+ return res; -+} -+ -+static void trigger_ilpc2ahb_read(void) -+{ -+ write_addr_port(SUPERIO_FE, LPC_ADDR_PORT); -+ read_data_port(LPC_DATA_PORT); -+ -+ return; -+} -+ -+static void trigger_ilpc2ahb_write(void) -+{ -+ write_addr_port(SUPERIO_FE, LPC_ADDR_PORT); -+ write_data_port(TOGGLE_WRITE, LPC_DATA_PORT); -+ -+ return; -+} -+ -+static uint32_t read_bmc_reg(uint32_t addr) -+{ -+ uint32_t res; -+ -+ write_ilpc2ahb_addr(addr); -+ trigger_ilpc2ahb_read(); -+ res = read_ilpc2ahb_data(); -+ -+ return res; -+} -+ -+static void write_bmc_reg(uint32_t addr, uint32_t val) -+{ -+ write_ilpc2ahb_addr(addr); -+ write_ilpc2ahb_data(val); -+ trigger_ilpc2ahb_write(); -+ -+ return; -+} -+ -+static uint32_t read_bmc_flash_data(void) -+{ -+ uint32_t res; -+ -+ trigger_ilpc2ahb_read(); -+ res = read_ilpc2ahb_data(); -+ -+ return res; -+} -+ -+static void write_bmc_flash_data(uint32_t data) -+{ -+ write_ilpc2ahb_data(data); -+ trigger_ilpc2ahb_write(); -+ -+ return; -+} -+ -+static void write_bmc_flash_addr(uint32_t addr) -+{ -+ int i; -+ -+ for (i = 0; i < 4; i++) { -+ write_addr_port(SUPERIO_REG4 + i, LPC_ADDR_PORT); -+ write_data_port((addr >> (8 * i)) & MASK, LPC_DATA_PORT); -+ } -+ -+ trigger_ilpc2ahb_write(); -+ -+ return; -+} -+ -+static void enable_bytes(int byte) -+{ -+ write_addr_port(SUPERIO_REG8, LPC_ADDR_PORT); -+ switch (byte) { -+ case BYTE1: -+ write_data_port(SUPERIO_A0 + BYTE1_VAL, LPC_DATA_PORT); -+ break; -+ case BYTE2: -+ write_data_port(SUPERIO_A0 + BYTE2_VAL, LPC_DATA_PORT); -+ break; -+ case BYTE4: -+ write_data_port(SUPERIO_A0 + BYTE4_VAL, LPC_DATA_PORT); -+ break; -+ default: -+ write_data_port(SUPERIO_A0 + BYTE_RESERVED, LPC_DATA_PORT); -+ break; -+ } -+ -+ return; -+} -+ -+static void pull_ce_down(flash_info_t* info) -+{ -+ write_bmc_reg(info->ce_control_reg, USER_MODE_PULL_CE_DOWN); -+ -+ return; -+} -+ -+static void pull_ce_up(flash_info_t* info) -+{ -+ write_bmc_reg(info->ce_control_reg, USER_MODE_PULL_CE_UP); -+ -+ return; -+} -+ -+static void send_cmd(uint32_t flash_base_addr, int cmd) -+{ -+ write_ilpc2ahb_addr(flash_base_addr); -+ enable_bytes(1); -+ write_addr_port(SUPERIO_REG7, LPC_ADDR_PORT); -+ write_data_port(cmd & MASK, LPC_DATA_PORT); -+ trigger_ilpc2ahb_write(); -+ enable_bytes(4); -+ -+ return; -+} -+ -+static void send_cmd_to_flash(flash_info_t* info, int cmd) -+{ -+ pull_ce_down(info); -+ send_cmd(info->flash_base_addr, cmd); -+ pull_ce_up(info); -+ -+ return; -+} -+ -+static void check_data_length(void) -+{ -+ uint8_t tmp; -+ /* Data length check, 4 bytes */ -+ write_addr_port(SUPERIO_REG8, LPC_ADDR_PORT); -+ tmp = read_data_port(LPC_DATA_PORT); -+ if (tmp != SUPERIO_A2) { -+ write_data_port(SUPERIO_A2, LPC_DATA_PORT); -+ } -+ -+ return; -+} -+ -+static void enable_ilpc2ahb(void) -+{ -+ /* Write 0xAA then write 0xA5 twice to enable super IO*/ -+ write_addr_port(DISABLE_LPC, LPC_ADDR_PORT); -+ write_addr_port(ENABLE_LPC, LPC_ADDR_PORT); -+ write_addr_port(ENABLE_LPC, LPC_ADDR_PORT); -+ -+ /* Enable iLPC2AHB */ -+ write_addr_port(SUPERIO_07, LPC_ADDR_PORT); -+ write_data_port(LPC_TO_AHB, LPC_DATA_PORT); -+ write_addr_port(SUPERIO_30, LPC_ADDR_PORT); -+ write_data_port(ENABLE_LPC_TO_AHB, LPC_DATA_PORT); -+ -+ /* Data length */ -+ check_data_length(); -+ -+ return; -+} -+ -+static void disable_ilpc2ahb(void) -+{ -+ /* disable ilpc2ahb */ -+ write_addr_port(SUPERIO_30, LPC_ADDR_PORT); -+ write_data_port(DISABLE_LPC_TO_AHB, LPC_DATA_PORT); -+ /* disable super IO */ -+ write_addr_port(DISABLE_LPC, LPC_ADDR_PORT); -+ -+ return; -+} -+ -+/* Enable CPU */ -+static void enable_cpu(void) -+{ -+ /* unlock SCU register */ -+ write_bmc_reg(SCU_ADDR, UNLOCK_SCU_KEY); -+ /* enable ARM */ -+ write_bmc_reg(REBOOT_CPU_REGISTER, SET_BMC_CPU_BOOT); -+ /* lock SCU register */ -+ write_bmc_reg(SCU_ADDR, LOCK_SCU_KEY); -+ -+ return; -+} -+ -+/* diasble CPU */ -+static void disable_cpu(void) -+{ -+ uint32_t scu_hw_strap_val; -+ -+ /* unlock SCU register */ -+ write_bmc_reg(SCU_ADDR, UNLOCK_SCU_KEY); -+ /* disable ARM */ -+ scu_hw_strap_val = read_bmc_reg(HARDWARE_STRAP_REGISTER); -+ write_bmc_reg(HARDWARE_STRAP_REGISTER, scu_hw_strap_val |0x01); -+ /* lock SCU register */ -+ write_bmc_reg(SCU_ADDR, LOCK_SCU_KEY); -+ -+ return; -+} -+ -+static void enable_upgrade(void) -+{ -+ -+ enable_ilpc2ahb(); -+ /* diasble CPU */ -+ disable_cpu(); -+ /* init CE control register */ -+ write_bmc_reg(CE0_CONTROL_REGISTER, 0); -+ write_bmc_reg(CE1_CONTROL_REGISTER, 0); -+ /* disable WDT2 */ -+ write_bmc_reg(WATCHDOG2_CONTROL, DISABLE_WATCHDOG); -+ -+ return; -+} -+ -+static void disable_upgrade(void) -+{ -+ enable_cpu(); -+ dbg_print(debug_on, "DEBUG 0x%x\n", read_bmc_reg(HARDWARE_STRAP_REGISTER)); -+ disable_ilpc2ahb(); -+ -+ return; -+} -+ -+static void watchdog_status_debug(void) -+{ -+ uint32_t watchdog_reg; -+ -+ /* Watchdog Control Register */ -+ watchdog_reg = read_bmc_reg(WATCHDOG2_CONTROL); -+ dbg_print(debug_on,"Watchdog Control Register: 0x%x\n", watchdog_reg); -+ dbg_print(debug_on,"Watchdog Enable Signal: 0x%x\n", watchdog_reg & BIT1); -+ dbg_print(debug_on,"Watchdog Reset SyS En: 0x%x\n", (watchdog_reg & BIT2) >> 1); -+ dbg_print(debug_on,"Watchdog Reset Mode: 0x%x\n", (watchdog_reg & (BIT6 | BIT7)) >> 5); -+ switch (watchdog_reg & (BIT6 | BIT7)) { -+ case SOC_SYS: -+ dbg_print(debug_on,"\tReset Mode En: SoC System\n"); -+ break; -+ case FULL_CHIP: -+ dbg_print(debug_on,"\tReset Mode En: Full Chip\n"); -+ break; -+ case ARM_CPU: -+ dbg_print(debug_on,"\tReset Mode En: ARM Cpu\n"); -+ break; -+ default: -+ break; -+ } -+ -+ /* Watchdog Timeout Status Register */ -+ watchdog_reg = read_bmc_reg(WATCHDOG2_TSR); -+ dbg_print(debug_on,"Watchdog Timeout Occur: 0x%x\n", watchdog_reg & BIT1); -+ dbg_print(debug_on,"Watchdog Boot from: CD%d\n", watchdog_reg & BIT2); -+ dbg_print(debug_on,"Watchdog Interrupt Occur: 0x%x\n", watchdog_reg & BIT3); -+ -+ return; -+} -+ -+/* CE Type Setting Register */ -+static void ce_type_setting_debug(void) -+{ -+ uint32_t fmc_reg; -+ -+ fmc_reg = read_bmc_reg(FMC_CE_TYPE_SETTING_REG); -+ if ((fmc_reg & CE0_SPI_TYPE) == SPI) { -+ dbg_print(debug_on,"CE0 Type Seeting: 0x%x, Type: SPI\n", fmc_reg & CE0_SPI_TYPE); -+ } else { -+ dbg_print(debug_on,"CE0 Type Seeting: 0x%x, Type: Unknown\n", fmc_reg & CE0_SPI_TYPE); -+ } -+ if (((fmc_reg & CE1_SPI_TYPE) >> BIT2) == SPI) { -+ dbg_print(debug_on,"CE1 Type Seeting: 0x%x, Type: SPI\n", (fmc_reg & CE1_SPI_TYPE) >> BIT2); -+ } else { -+ dbg_print(debug_on,"CE1 Type Seeting: 0x%x, Type: Unknown\n", (fmc_reg & CE1_SPI_TYPE) >> BIT2); -+ } -+ -+ return; -+} -+/* CE Control Register */ -+static void ce_control_debug(void) -+{ -+ uint32_t fmc_reg; -+ -+ fmc_reg = read_bmc_reg(CE_CONTROL_REGISTER); -+ dbg_print(debug_on,"CE0 Address Mode: 0x%x, Mode: %d Bytes\n", -+ fmc_reg & BIT1, (fmc_reg & BIT1) + 3); -+ dbg_print(debug_on,"CE1 Address Mode: 0x%x, Mode: %d Bytes\n", -+ (fmc_reg & BIT2) >> 1, ((fmc_reg & BIT2) >> 1) + 3); -+ -+ return; -+} -+ -+/* Interrupt Control & Status Register */ -+static void irq_control_status_debug(void) -+{ -+ uint32_t fmc_reg; -+ -+ fmc_reg = read_bmc_reg(INR_STATUS_CONTROL_REGISTER); -+ dbg_print(debug_on,"SPI Write Address Protected Interrupt EN: 0x%x\n", fmc_reg & BIT2); -+ dbg_print(debug_on,"SPI Command Abort Interrupt EN: 0x%x\n", fmc_reg & BIT3); -+ dbg_print(debug_on,"SPI Write Address Protected Status: 0x%x, Status: %s\n", -+ RIGHT_SHIFT_8(fmc_reg) & BIT2, (RIGHT_SHIFT_8(fmc_reg) & BIT2) == BIT2 ? "Occur" : "Normal"); -+ dbg_print(debug_on,"SPI Command Abort Status: 0x%x, Status: %s\n", -+ RIGHT_SHIFT_8(fmc_reg) & BIT3, (RIGHT_SHIFT_8(fmc_reg) & BIT3) == BIT3 ? "Occur" : "Normal"); -+ /*Clear Abnormal Status*/ -+ if ((RIGHT_SHIFT_8(fmc_reg) & BIT3) || (RIGHT_SHIFT_8(fmc_reg) & BIT2)) { -+ write_bmc_reg(INR_STATUS_CONTROL_REGISTER, CLEAR_INR_STATUS_CONTROL); -+ } -+ -+ return; -+} -+ -+/* Command Control Register */ -+static void command_control_debug(void) -+{ -+ uint32_t fmc_reg; -+ -+ fmc_reg = read_bmc_reg(COMMAND_CONTROL_REGISTER); -+ dbg_print(debug_on,"Data Byte Line 0: %s\n", ((fmc_reg & BIT4) != 0) ? "Disable" : "Enable"); -+ dbg_print(debug_on,"Data Byte Line 1: %s\n", ((fmc_reg & BIT3) != 0) ? "Disable" : "Enable"); -+ dbg_print(debug_on,"Data Byte Line 2: %s\n", ((fmc_reg & BIT2) != 0) ? "Disable" : "Enable"); -+ dbg_print(debug_on,"Data Byte Line 3: %s\n", ((fmc_reg & BIT1) != 0) ? "Disable" : "Enable"); -+ -+ dbg_print(debug_on,"Address Byte Line 0: %s\n", ((fmc_reg & BIT8) != 0) ? "Disable" : "Enable"); -+ dbg_print(debug_on,"Address Byte Line 1: %s\n", ((fmc_reg & BIT7) != 0) ? "Disable" : "Enable"); -+ dbg_print(debug_on,"Address Byte Line 2: %s\n", ((fmc_reg & BIT6) != 0) ? "Disable" : "Enable"); -+ dbg_print(debug_on,"Address Byte Line 3: %s\n", ((fmc_reg & BIT5) != 0) ? "Disable" : "Enable"); -+ -+ return; -+} -+ -+static void ce_control_reg_debug(void) -+{ -+ uint32_t fmc_reg; -+ -+ /* CE0 Control Register */ -+ fmc_reg = read_bmc_reg(CE0_CONTROL_REGISTER); -+ switch (fmc_reg & (BIT1 | BIT2)){ -+ case NORMAL_READ: -+ dbg_print(debug_on,"CE0 Command Mode: Normal Read\n"); -+ break; -+ case READ_MODE: -+ dbg_print(debug_on,"CE0 Command Mode: Read Command\n"); -+ break; -+ case WRITE_MODE: -+ dbg_print(debug_on,"CE0 Command Mode: Write Command\n"); -+ break; -+ case USER_MODE: -+ dbg_print(debug_on,"CE0 Command Mode: User Mode\n"); -+ break; -+ default: -+ break; -+ } -+ switch((RIGHT_SHIFT_24(fmc_reg) & (BIT5 | BIT6 | BIT7))){ -+ case 0: -+ dbg_print(debug_on,"CE0 IO Mode: Single Mode\n"); -+ break; -+ case 2: -+ case 3: -+ dbg_print(debug_on,"CE0 IO Mode: Dual Mode\n"); -+ break; -+ default: -+ break; -+ } -+ -+ dbg_print(debug_on,"CE0 Inactive Pulse Width: %d HCLK\n", -+ DEFAULT_WIDTH - (RIGHT_SHIFT_24(fmc_reg) & (BIT1 | BIT2 | BIT3 | BIT4))); -+ dbg_print(debug_on,"CE0 Data Input Mode: %s Mode\n", (fmc_reg & BIT4) == 0 ? "Single" : "Dual"); -+ dbg_print(debug_on,"CE0 MSB | LSB: %s First\n", (fmc_reg & BIT6) == 0 ? "MSB" : "LSB"); -+ -+ /* CE1 Control Register */ -+ fmc_reg = read_bmc_reg(CE1_CONTROL_REGISTER); -+ switch (fmc_reg & (BIT1 | BIT2)){ -+ case NORMAL_READ: -+ dbg_print(debug_on,"CE1 Command Mode: Normal Read\n"); -+ break; -+ case READ_MODE: -+ dbg_print(debug_on,"CE1 Command Mode: Read Command\n"); -+ break; -+ case WRITE_MODE: -+ dbg_print(debug_on,"CE1 Command Mode: Write Command\n"); -+ break; -+ case USER_MODE: -+ dbg_print(debug_on,"CE1 Command Mode: User Mode\n"); -+ break; -+ default: -+ break; -+ } -+ switch((RIGHT_SHIFT_24(fmc_reg) & (BIT5 | BIT6 | BIT7))){ -+ case 0: -+ dbg_print(debug_on,"CE1 IO Mode: Single Mode\n"); -+ break; -+ case 2: -+ case 3: -+ dbg_print(debug_on,"CE1 IO Mode: Dual Mode\n"); -+ break; -+ default: -+ break; -+ } -+ -+ dbg_print(debug_on,"CE1 Inactive Pulse Width: %d HCLK\n", -+ DEFAULT_WIDTH - (RIGHT_SHIFT_24(fmc_reg) & (BIT1 | BIT2 | BIT3 | BIT4))); -+ dbg_print(debug_on,"CE1 Data Input Mode: %s Mode\n", (fmc_reg & BIT4) == 0 ? "Single" : "Dual"); -+ dbg_print(debug_on,"CE1 MSB | LSB: %s First\n", (fmc_reg & BIT6) == 0 ? "MSB" : "LSB"); -+ -+ return; -+} -+ -+static void fmc_debug(void) -+{ -+ ce_type_setting_debug(); -+ ce_control_debug(); -+ irq_control_status_debug(); -+ command_control_debug(); -+ ce_control_reg_debug(); -+ -+ return; -+} -+ -+/* Enable WatchDog to reset BMC*/ -+static void enable_watchdog(int cs) -+{ -+ uint32_t enable_watch_cmd; -+ -+ enable_watch_cmd = (cs == CE0) ? ENABLE_WATCHDOG : ENABLE_WATCHDOG | BOOT_DEFAULT_MASK; -+ write_bmc_reg(WATCHDOG2_CLEAR_STATUS, CLEAR_WATCHDOG_STATUS); -+ write_bmc_reg(WATCHDOG2_RESET_FUN_MASK, WATCHDOG_GATEMASK); -+ write_bmc_reg(WATCHDOG2_RELOAD_VALUE, WATCHDOG_NEW_COUNT); -+ write_bmc_reg(WATCHDOG2_COUNTER_RST, WATCHDOG_RELOAD_COUNTER); -+ write_bmc_reg(WATCHDOG2_CONTROL, enable_watch_cmd); -+ -+ return; -+} -+ -+static void bmc_reboot(int cs) -+{ -+ enable_watchdog(cs); -+ watchdog_status_debug(); -+ disable_upgrade(); -+ printf("Upgrade-Complete, BMC rebooting...\n"); -+ -+ return; -+} -+ -+static int get_current_bmc(void) -+{ -+ return (read_bmc_reg(WATCHDOG2_TSR) & 0x02) >> 1; -+} -+ -+static void get_flash_base_and_ce_ctrl(int current_bmc, int cs, uint32_t *flash_base_addr, uint32_t *ce_ctrl_addr) -+{ -+ uint32_t ce0_addr_range_reg_val, ce0_decode_addr; -+ uint32_t ce1_addr_range_reg_val, ce1_decode_addr; -+ -+ ce0_addr_range_reg_val = read_bmc_reg(CE0_ADDRESS_RANGE_REGISTER); -+ ce0_decode_addr = SEGMENT_ADDR_START(ce0_addr_range_reg_val); -+ ce1_addr_range_reg_val = read_bmc_reg(CE1_ADDRESS_RANGE_REGISTER); -+ ce1_decode_addr = SEGMENT_ADDR_START(ce1_addr_range_reg_val); -+ dbg_print(debug_on,"CE0 addr decode range reg value:0x%08x, decode addr:0x%08x.\n", -+ ce0_addr_range_reg_val, ce0_decode_addr); -+ dbg_print(debug_on,"CE1 addr decode range reg value:0x%08x, decode addr:0x%08x.\n", -+ ce1_addr_range_reg_val, ce1_decode_addr); -+ -+ if (((current_bmc == CURRENT_MASTER) && (cs ==CE0)) || ((current_bmc == CURRENT_SLAVE) && (cs ==CE1))) { -+ *ce_ctrl_addr = CE0_CONTROL_REGISTER; -+ *flash_base_addr = ce0_decode_addr; -+ } else { -+ *ce_ctrl_addr = CE1_CONTROL_REGISTER; -+ *flash_base_addr = ce1_decode_addr; -+ } -+ -+ return; -+} -+ -+static int get_flash_id(uint32_t flash_base_addr, uint32_t ce_ctrl_addr) -+{ -+ uint32_t origin_flash_id, flash_id; -+ -+ write_bmc_reg(ce_ctrl_addr, USER_MODE_PULL_CE_DOWN); -+ send_cmd(flash_base_addr, READID); -+ origin_flash_id = read_bmc_flash_data(); -+ write_bmc_reg(ce_ctrl_addr, USER_MODE_PULL_CE_UP); -+ flash_id = origin_flash_id & 0xFFFFFF; -+ dbg_print(debug_on,"origin flash id:0x%x, flash id:0x%x\n", origin_flash_id, flash_id); -+ -+ return flash_id; -+} -+ -+static uint8_t get_flash_status(flash_info_t* info) -+{ -+ uint8_t flash_status; -+ -+ pull_ce_down(info); -+ -+ send_cmd(info->flash_base_addr, READ_FLASH_STATUS); -+ -+ flash_status = read_bmc_flash_data() & MASK; -+ pull_ce_up(info); -+ -+ dbg_print(debug_on,"get_flash_status:0x%x\n", flash_status); -+ return flash_status; -+} -+ -+static int check_flash_write_enable(flash_info_t* info) -+{ -+ uint8_t flash_status; -+ int i, count; -+ -+ count = FLASH_WEL_TIMEOUT / FLASH_WEL_SLEEP_TIME; -+ for (i = 0; i <= count; i++) { -+ flash_status = get_flash_status(info); -+ if ((flash_status & FLASH_WRITE_ENABLE_MASK) != FLASH_WRITE_ENABLE_MASK) { -+ usleep(FLASH_WEL_SLEEP_TIME); -+ } else { -+ dbg_print(debug_on,"Check flash WEL success, RDSR:0x%x\n", flash_status); -+ return 0; -+ } -+ } -+ printf("Check flash WEL timeout, RDSR:0x%x\n", flash_status); -+ return -1; -+} -+ -+static int check_flash_write_process(flash_info_t* info, int timeout, int sleep_time) -+{ -+ int i, count; -+ uint8_t flash_status; -+ -+ count = timeout / sleep_time; -+ for (i = 0; i <= count; i++) { -+ flash_status = get_flash_status(info); -+ if ((flash_status & FLASH_WIP_MASK) != 0) { -+ usleep(sleep_time); -+ } else { -+ dbg_print(debug_on,"Check flash WIP success, RDSR:0x%x\n", flash_status); -+ return 0; -+ } -+ } -+ printf("Check flash WIP timeout, RDSR:0x%x.\n", flash_status); -+ return -1; -+} -+ -+static int flash_write_enable(flash_info_t* info) -+{ -+ int ret; -+ -+ send_cmd_to_flash(info, WRITE_ENABLE_FLASH); -+ ret = check_flash_write_enable(info); -+ if (ret < 0) { -+ return -1; -+ } -+ return 0; -+} -+ -+static void send_block_erase_cmd(flash_info_t* info, uint32_t block_addr) -+{ -+ pull_ce_down(info); -+ send_cmd(info->flash_base_addr, info->erase_block_command); -+ write_bmc_flash_addr(block_addr); /* Erase Block addr */ -+ pull_ce_up(info); -+ -+ return; -+} -+ -+static void send_chip_erase_cmd(flash_info_t* info) -+{ -+ send_cmd_to_flash(info, CHIP_ERASE_FLASH); -+ -+ return; -+} -+ -+static int write_bmc_flash_page(flash_info_t* info, uint32_t page_addr, uint8_t *p, int len) -+{ -+ int pos; -+ -+ if (len % 4) { -+ printf("Page size %d invalid.\n", len); -+ return -1; -+ } -+ -+ pos = 0; -+ pull_ce_down(info); -+ send_cmd(info->flash_base_addr, info->page_program); -+ write_bmc_flash_addr(page_addr); /* page address */ -+ while (len) { -+ write_bmc_flash_data((*(uint32_t *)(p + pos))); -+ pos += 4; -+ len -= 4; -+ } -+ pull_ce_up(info); -+ -+ return 0; -+} -+ -+static int erase_chip_full(flash_info_t* info) -+{ -+ time_t timep; -+ int ret; -+ -+ if (info->full_erase == 0) { -+ printf("Flash not support full erase function.\n"); -+ return -1; -+ } -+ -+ ret = flash_write_enable(info); -+ if(ret < 0) { -+ printf("Chip erase, enable flash write error.\n"); -+ return -1; -+ } -+ -+ time(&timep); -+ printf("Full chip erasing, please wait...\n"); -+ dbg_print(debug_on,"Erase Start-%s\n",asctime(gmtime(&timep))); -+ send_chip_erase_cmd(info); -+ ret = check_flash_write_process(info, CHIP_ERASE_TIMEOUT, CHIP_ERASE_SLEEP_TIME); -+ if (ret < 0) { -+ printf("Chip erase timeout.\n"); -+ return -1; -+ } -+ time(&timep); -+ dbg_print(debug_on,"Erase Finish-%s\n",asctime(gmtime(&timep))); -+ printf("Erase Finish\n"); -+ printf("=========================================\n"); -+ return 0; -+} -+ -+static int erase_chip_block(flash_info_t* info) -+{ -+ uint32_t block_addr, end_addr; -+ time_t timep; -+ int ret; -+ -+ printf("Block erasing...\n"); -+ time (&timep); -+ dbg_print(debug_on,"Erase-Start-%s\n", asctime(gmtime(&timep))); -+ end_addr = info->flash_base_addr + info->flash_size; -+ block_addr = info->flash_base_addr; -+ while (1) { -+ /* Enable write */ -+ ret = flash_write_enable(info); -+ if(ret < 0) { -+ printf("Block erase, enable flash write error, block addr:0x%x\n", block_addr); -+ return -1; -+ } -+ -+ send_block_erase_cmd(info, block_addr); -+ /* Erase Block(64KB) MAX time 650ms*/ -+ ret = check_flash_write_process(info, BLOCK_ERASE_TIMEOUT, BLOCK_ERASE_SLEEP_TIME); -+ if (ret < 0) { -+ printf("Block erase, check write status error, block addr:0x%x\n", block_addr); -+ return -1; -+ } -+ printf("\r0x%x", block_addr); -+ fflush(stdout); -+ if (block_addr >= end_addr) { -+ time(&timep); -+ printf("\r\nErase Finish\n"); -+ printf("=========================================\n"); -+ dbg_print(debug_on,"\nEnd-Earse-%s\n",asctime(gmtime(&timep))); -+ break; -+ } -+ block_addr += info->block_size; -+ } -+ return 0; -+} -+ -+static int program_chip(uint32_t file_size, uint8_t *p, flash_info_t* info) -+{ -+ time_t timep; -+ uint32_t page_addr, end_addr; -+ int ret, page_size; -+ -+ page_addr = info->flash_base_addr; -+ page_size = info->page_size; -+ end_addr = file_size + info->flash_base_addr; -+ time (&timep); -+ printf("Programming...\n"); -+ dbg_print(debug_on,"Program Start-%s\n",asctime(gmtime(&timep))); -+ /* Debug info */ -+ fmc_debug(); -+ while (1) { -+ /* Write enable */ -+ ret = flash_write_enable(info); -+ if(ret < 0) { -+ printf("Page program, enable flash write error, page addr:0x%x\n", page_addr); -+ return -1; -+ } -+ ret = write_bmc_flash_page(info, page_addr, p, page_size); -+ if (ret < 0) { -+ printf("Page program, write bmc flash page error, page addr:0x%x\n", page_addr); -+ return -1; -+ } -+ /* page program MAX time 1.5ms */ -+ ret = check_flash_write_process(info, PAGE_PROGRAM_TIMEOUT, PAGE_PROGRAM_SLEEP_TIME); -+ if (ret < 0) { -+ printf("Page program, check write status error, page addr:0x%x\n", page_addr); -+ return -1; -+ } -+ page_addr += page_size; -+ p += page_size; -+ if ((page_addr % 0x10000) == 0) { -+ printf("\r0x%x", page_addr); -+ fflush(stdout); -+ } -+ -+ if (page_addr >= end_addr) { -+ printf("\nProgram Finish\n"); -+ printf("=========================================\n"); -+ time(&timep); -+ dbg_print(debug_on,"\nProgram-End-%s\n",asctime(gmtime(&timep))); -+ break; -+ } -+ } /* End of while (1) */ -+ return 0; -+} -+ -+static int check_chip(uint32_t file_size, uint8_t *p, flash_info_t* info) -+{ -+ time_t timep; -+ uint32_t offset_addr, rd_val, end_addr; -+ int pos; -+ -+ offset_addr = info->flash_base_addr; -+ end_addr = file_size + info->flash_base_addr; -+ pos=0; -+ /* Checking */ -+ time(&timep); -+ printf("Checking...\n"); -+ dbg_print(debug_on,"Checking-Start-%s\n",asctime(gmtime(&timep))); -+ -+ pull_ce_down(info); -+ send_cmd(info->flash_base_addr, COMMON_FLASH_READ); -+ write_bmc_flash_addr(info->flash_base_addr); -+ while (1) { -+ if (offset_addr >= end_addr) { -+ break; -+ } -+ rd_val = read_bmc_flash_data(); -+ if (rd_val != (*(uint32_t *)(p + pos))) { -+ printf("Check Error at 0x%08x\n", offset_addr); -+ printf("READ:0x%08x VALUE:0x%08x\n", rd_val, (*(uint32_t *)(p + pos))); -+ pull_ce_up(info); -+ return -1; -+ } -+ if ((offset_addr % 0x10000) == 0) { -+ printf("\r0x%x ", offset_addr); -+ fflush(stdout); -+ } -+ offset_addr += 4; -+ pos += 4; -+ } -+ pull_ce_up(info); -+ printf("\r\nFlash Checked\n"); -+ printf("=========================================\n"); -+ time(&timep); -+ dbg_print(debug_on,"Checking-End-%s\n",asctime(gmtime(&timep))); -+ return 0; -+} -+ -+flash_info_t* get_flash_info(int current_bmc, int cs) -+{ -+ int i, size; -+ uint32_t flash_base_addr, ce_ctrl_addr, flash_id; -+ -+ get_flash_base_and_ce_ctrl(current_bmc, cs, &flash_base_addr, &ce_ctrl_addr); -+ -+ size = (sizeof(flash_info) / sizeof((flash_info)[0])); -+ -+ flash_id = get_flash_id(flash_base_addr, ce_ctrl_addr); -+ for (i = 0; i < size; i++) { -+ if (flash_info[i].flash_id == flash_id) { -+ flash_info[i].flash_base_addr = flash_base_addr; -+ flash_info[i].ce_control_reg = ce_ctrl_addr; -+ flash_info[i].cs = cs; -+ return &flash_info[i]; -+ } -+ } -+ printf("Cannot get flash info, cs:%d, flash base addr:0x%x, ce control addr:0x%x, flash_id:0x%x.\n", -+ cs, flash_base_addr, ce_ctrl_addr, flash_id); -+ return NULL; -+} -+ -+static void init_flash(flash_info_t* info) -+{ -+ send_cmd_to_flash(info, RSTEN); -+ send_cmd_to_flash(info, RST); -+ send_cmd_to_flash(info, EXIT_OTP); -+ send_cmd_to_flash(info, ENABLE_BYTE4); -+ -+ return; -+} -+ -+static int upgrade_bmc_core(char *file_name, int erase_type, flash_info_t* info) -+{ -+ int file_size, fp, ret; -+ uint8_t *p; -+ -+ file_size = get_file_size(file_name); -+ if (file_size < 0) { -+ printf("file size %d Error\n", file_size); -+ return -1; -+ } -+ -+ fp = open(file_name, O_RDWR); -+ if (fp < 0) { -+ printf("Cannot open %s.\n", file_name); -+ return -1; -+ } -+ -+ p = mmap(NULL, file_size, PROT_READ, MAP_SHARED, fp, 0); -+ if (p == MAP_FAILED) { -+ printf("Could not mmap %s, error(%s).\n", file_name, strerror(errno)); -+ close(fp); -+ return -1; -+ } -+ -+ printf("* CE%d FLASH TYPE: SPI FLASH\n", info->cs); -+ printf("* FLASH NAME: %s\n", info->flash_name); -+ printf("* File Size:%d, 0x%x\n", file_size, file_size); -+ printf("=========================================\n"); -+ -+ /* Select erase type */ -+ switch (erase_type) { -+ case FULL_ERASE: -+ ret = erase_chip_full(info); -+ break; -+ case BLOCK_ERASE: -+ ret = erase_chip_block(info); -+ break; -+ default: -+ printf("Unsupport earse type:%d\n", erase_type); -+ goto exit; -+ break; -+ } -+ -+ if (ret < 0) { -+ printf("Erase Chip Error\n"); -+ goto exit; -+ } -+ -+ /* Program the flash */ -+ ret = program_chip(file_size, p, info); -+ if(ret < 0) { -+ printf("Program Chip Error\n"); -+ goto exit; -+ } -+ /* Check */ -+ ret = check_chip(file_size, p, info); -+ if(ret < 0) { -+ printf("Check Chip Error\n"); -+ goto exit; -+ } -+ -+ munmap(p, file_size); -+ close(fp); -+ return 0; -+exit: -+ munmap(p, file_size); -+ close(fp); -+ return -1; -+} -+ -+static int upgrade_bmc_flash(char *filename, int current_bmc, int cs, int erase_type) -+{ -+ int ret; -+ flash_info_t* info; -+ -+ info = get_flash_info(current_bmc, cs); -+ if(info == NULL) { -+ return -1; -+ } -+ -+ init_flash(info); -+ -+ ret = upgrade_bmc_core(filename, erase_type, info); -+ -+ return ret; -+} -+ -+static int upgrade_both_flash(char *filename, int erase_type) -+{ -+ int ret, current_bmc; -+ -+ enable_upgrade(); -+ -+ current_bmc = get_current_bmc(); -+ if (current_bmc == CURRENT_MASTER) { -+ printf("* Current Bmc Default Boot: CE0\n"); -+ } else { -+ printf("* Current Bmc Default Boot: CE1\n"); -+ } -+ -+ ret = upgrade_bmc_flash(filename, current_bmc, CE0, erase_type); -+ if (ret < 0) { -+ printf("Upgrade master bmc flash failed, stop upgrade.\n"); -+ goto err; -+ } -+ printf("Upgrade master bmc flash success.\n"); -+ -+ ret = upgrade_bmc_flash(filename, current_bmc, CE1, erase_type); -+ if (ret < 0) { -+ printf("Upgrade slave bmc flash failed.\n"); -+ goto err; -+ } -+ printf("Upgrade slave bmc flash success.\n"); -+ -+ bmc_reboot(CE0); -+ return 0; -+err: -+ disable_upgrade(); -+ return -1; -+} -+ -+static int upgrade_single_flash(char *filename, int cs, int erase_type) -+{ -+ int ret, current_bmc; -+ -+ enable_upgrade(); -+ -+ current_bmc = get_current_bmc(); -+ if (current_bmc == CURRENT_MASTER) { -+ printf("* Current Bmc Default Boot: CE0\n"); -+ } else { -+ printf("* Current Bmc Default Boot: CE1\n"); -+ } -+ -+ ret = upgrade_bmc_flash(filename, current_bmc, cs, erase_type); -+ if (ret < 0) { -+ printf("Upgrade %s bmc flash failed.\n", cs == 0 ? "master":"slave"); -+ goto err; -+ } -+ printf("Upgrade %s bmc flash success.\n", cs == 0 ? "master":"slave"); -+ -+ bmc_reboot(cs); -+ return 0; -+err: -+ disable_upgrade(); -+ return -1; -+} -+ -+static int upgrade_bmc(char *filename, int cs, int erase_type) -+{ -+ int ret; -+ -+ if (access(filename, F_OK) < 0) { -+ printf("Can't find file\n"); -+ help(); -+ return -1; -+ } -+ -+ ret = set_ioport_rw_access(); -+ if (ret < 0) { -+ printf("IO ERROR\n"); -+ return -1; -+ } -+ -+ switch(cs) { -+ /* Single */ -+ case CE0: -+ case CE1: -+ ret = upgrade_single_flash(filename, cs, erase_type); -+ break; -+ /* Both */ -+ case BOTHFLASH: -+ ret = upgrade_both_flash(filename, erase_type); -+ break; -+ default: -+ ret = -1; -+ printf("Unsupport cs:%d\n", cs); -+ break; -+ } -+ -+ return ret; -+} -+ -+static int read_single_bmc_flash(flash_info_t* info, uint32_t start_addr, int read_size, int is_print) -+{ -+ uint32_t res, flash_start_addr, flash_end_addr; -+ char filename[MAX_FILENAME_LENGTH]; -+ int fd, ret; -+ -+ flash_start_addr = info->flash_base_addr + start_addr; -+ flash_end_addr = flash_start_addr + read_size; -+ ret = 0; -+ fd = 0; -+ if (!is_print) { -+ mem_clear(filename, MAX_FILENAME_LENGTH); -+ snprintf(filename, MAX_FILENAME_LENGTH, "/tmp/image-bmc%d", info->cs); -+ fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRWXG|S_IRWXU|S_IRWXO); -+ if (fd < 0) { -+ printf("open file %s fail(err:%d)!\r\n", filename, errno); -+ return -1; -+ } -+ } -+ -+ printf("* CE%d FLASH TYPE: SPI FLASH\n", info->cs); -+ printf("* FLASH NAME: %s\n", info->flash_name); -+ printf("* Read flash addr:0x%x, size:0x%x\n", flash_start_addr, read_size); -+ printf("=========================================\n"); -+ printf("Reading...\n"); -+ -+ pull_ce_down(info); -+ send_cmd(info->flash_base_addr, COMMON_FLASH_READ); -+ write_bmc_flash_addr(flash_start_addr); -+ while (1) { -+ if (flash_start_addr >= flash_end_addr) { -+ break; -+ } -+ res = read_bmc_flash_data(); -+ if (is_print) { -+ printf("addr:0x%08x, val:0x%08x\n", flash_start_addr, res); -+ } else { -+ ret = write(fd, &res, sizeof(res)); -+ if (ret < 0) { -+ printf("write failed (errno: %d).\n", errno); -+ ret = -1; -+ goto exit; -+ } -+ } -+ if (((flash_start_addr % 0x10000) == 0) && (!is_print)) { -+ printf("\r0x%x ", flash_start_addr); -+ fflush(stdout); -+ } -+ flash_start_addr += 4; -+ } -+ printf("\r\nRead Finish\n"); -+ printf("=========================================\n"); -+exit: -+ pull_ce_up(info); -+ if (fd > 0) { -+ close(fd); -+ } -+ return ret; -+} -+ -+static int read_bmc_flash(int cs, uint32_t start_addr, int read_size, int is_print) -+{ -+ int ret, current_bmc; -+ flash_info_t* info; -+ -+ ret = set_ioport_rw_access(); -+ if (ret < 0) { -+ printf("IO ERROR\n"); -+ return -1; -+ } -+ -+ enable_upgrade(); -+ -+ current_bmc = get_current_bmc(); -+ if (current_bmc == CURRENT_MASTER) { -+ printf("* Current Bmc Default Boot: CE0\n"); -+ } else { -+ printf("* Current Bmc Default Boot: CE1\n"); -+ } -+ -+ info = get_flash_info(current_bmc, cs); -+ if(info == NULL) { -+ goto err; -+ } -+ -+ if (start_addr >= info->flash_size) { -+ printf("start_addr 0x%x out of range.\n", start_addr); -+ goto err; -+ } -+ -+ if ((start_addr + read_size) > info->flash_size) { -+ printf("read size %d exceed flash size.\n", read_size); -+ read_size = info->flash_size - start_addr; -+ } -+ -+ init_flash(info); -+ -+ ret = read_single_bmc_flash(info, start_addr, read_size, is_print); -+ if (ret < 0) { -+ printf("Read %s bmc flash failed.\n", cs == 0 ? "master" : "slave"); -+ goto err; -+ } -+ disable_upgrade(); -+ return 0; -+err: -+ disable_upgrade(); -+ return -1; -+} -+ -+static int read_bmc_reg_main(int argc, char* argv[]) -+{ -+ uint32_t start_addr, read_val; -+ int read_size, ret; -+ char *stopstring; -+ -+ if (argc != 4) { -+ printf("Input invalid.\n"); -+ help(); -+ return -1; -+ } -+ -+ start_addr = strtoul(argv[2], &stopstring, 16); -+ read_size = strtol(argv[3], &stopstring, 10); -+ -+ if (read_size <= 0) { -+ printf("read length %d invalid\n", read_size); -+ return -1; -+ } -+ -+ if (((start_addr % 4) != 0) || ((read_size % 4) != 0)) { -+ printf("Params invalid, start_addr:0x%08x, read_size:%d\n", start_addr, read_size); -+ printf("Please input address/length times of 4\n"); -+ return -1; -+ } -+ -+ ret = set_ioport_rw_access(); -+ if (ret < 0) { -+ printf("IO ERROR\n"); -+ return -1; -+ } -+ -+ enable_ilpc2ahb(); -+ -+ printf("read bcm reg, start_addr:0x%08x, read length:%d\n", start_addr, read_size); -+ printf("===Addr=== | ===Cont===\n"); -+ while (read_size) { -+ read_val = read_bmc_reg(start_addr); -+ printf("0x%08x | 0x%08x\n", start_addr, read_val); -+ start_addr += 4; -+ read_size -= 4; -+ } -+ -+ disable_ilpc2ahb(); -+ return 0; -+} -+ -+static int write_bmc_reg_main(int argc, char* argv[]) -+{ -+ uint32_t addr, wr_val; -+ int ret; -+ char *stopstring; -+ -+ if (argc != 4) { -+ printf("Input invalid.\n"); -+ help(); -+ return -1; -+ } -+ -+ addr = strtoul(argv[2], &stopstring, 16); -+ wr_val = strtoul(argv[3], &stopstring, 16); -+ -+ if (((addr & MASK_BYTE) != REGISTER_HEAD) || ((addr % 4) != 0)) { -+ printf("Address[0x%08x] invalid, address should be register address and times of 4.\n", addr); -+ return -1; -+ } -+ -+ ret = set_ioport_rw_access(); -+ if (ret < 0) { -+ printf("IO ERROR\n"); -+ return -1; -+ } -+ -+ printf("write bcm reg, addr:0x%08x, val:0x%08x\n", addr, wr_val); -+ -+ enable_ilpc2ahb(); -+ write_bmc_reg(addr, wr_val); -+ disable_ilpc2ahb(); -+ -+ return 0; -+} -+ -+static int get_fmc_info_main(void) -+{ -+ int ret; -+ -+ ret = set_ioport_rw_access(); -+ if (ret < 0) { -+ printf("IO ERROR\n"); -+ return -1; -+ } -+ -+ enable_ilpc2ahb(); -+ -+ debug_on = 3; -+ fmc_debug(); -+ debug_on = 0; -+ -+ disable_ilpc2ahb(); -+ return 0; -+} -+ -+static int program_flash_main(int argc, char* argv[]) -+{ -+ int cs, erase_way, ret; -+ char *stopstring; -+ char tmp[128]; -+ -+ if (argc != 5) { -+ printf("Input invalid.\n"); -+ help(); -+ return -1; -+ } -+ -+ cs = strtol(argv[3], &stopstring, 10); -+ if ((strlen(stopstring) != 0) || cs < 0 || cs > 2) { -+ snprintf(tmp, sizeof(tmp), "%s", argv[3]); -+ printf("Incorrect chip select %s\n", tmp); -+ help(); -+ return -1; -+ } -+ -+ if (strcmp(argv[4], "full") == 0) { -+ erase_way = FULL_ERASE; -+ } else if (strcmp(argv[4], "block") == 0) { -+ erase_way = BLOCK_ERASE; -+ } else { -+ snprintf(tmp, sizeof(tmp), "%s", argv[4]); -+ printf("Incorrect erase type %s\n", tmp); -+ help(); -+ return -1; -+ } -+ -+ printf("============BMC Upgrade Tool=============\n"); -+ ret = upgrade_bmc(argv[2], cs, erase_way); -+ return ret; -+} -+ -+static int read_bmc_flash_main(int argc, char* argv[]) -+{ -+ int cs, ret, read_size, is_print; -+ uint32_t start_addr; -+ char *stopstring; -+ char tmp[128]; -+ -+ if (argc != 6) { -+ printf("Input invalid.\n"); -+ help(); -+ return -1; -+ } -+ -+ cs = strtol(argv[2], &stopstring, 10); -+ if ((strlen(stopstring) != 0) || cs < 0 || cs > 1) { -+ snprintf(tmp, sizeof(tmp), "%s", argv[2]); -+ printf("Incorrect chip select %s\n", tmp); -+ help(); -+ return -1; -+ } -+ -+ start_addr = strtoul(argv[3], &stopstring, 16); -+ read_size = strtol(argv[4], &stopstring, 10); -+ -+ if (read_size <= 0) { -+ printf("read length %d invalid\n", read_size); -+ return -1; -+ } -+ -+ if (((start_addr % 4) != 0) || ((read_size % 4) != 0)) { -+ printf("Params invalid, start_addr:0x%08x, read_size:%d\n", start_addr, read_size); -+ printf("Please input address/length times of 4\n"); -+ return -1; -+ } -+ -+ if (strcmp(argv[5], "print") == 0) { -+ is_print = 1; -+ } else { -+ is_print = 0; -+ } -+ -+ printf("============READ BMC FLASH=============\n"); -+ ret = read_bmc_flash(cs, start_addr, read_size, is_print); -+ return ret; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int ret; -+ -+ debug_on = fw_upgrade_debug(); -+ -+ if (argc < 2) { -+ help(); -+ return -1; -+ } -+ -+ if (argc == 2) { -+ if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { -+ help(); -+ return 0; -+ } -+ } -+ -+ if (strcmp(argv[1], "rd") == 0) { -+ ret = read_bmc_reg_main(argc, argv); -+ if (ret < 0) { -+ printf("Read Failed\n"); -+ } -+ return ret; -+ } -+ -+ if (strcmp(argv[1], "wr") == 0 && debug_on == 3) { -+ ret = write_bmc_reg_main(argc, argv); -+ if (ret < 0) { -+ printf("Write Failed\n"); -+ } -+ return ret; -+ } -+ -+ if (strcmp(argv[1], "info") == 0) { -+ ret = get_fmc_info_main(); -+ if (ret < 0) { -+ printf("Get fmc info Failed\n"); -+ } -+ return ret; -+ } -+ -+ if (strcmp(argv[1], "upgrade") == 0) { -+ ret = program_flash_main(argc, argv); -+ if (ret < 0) { -+ printf("Upgrade BMC failed.\n"); -+ } -+ return ret; -+ } -+ -+ if (strcmp(argv[1], "read_bmc_flash") == 0) { -+ ret = read_bmc_flash_main(argc, argv); -+ if (ret < 0) { -+ printf("Read BMC flash failed.\n"); -+ } -+ return ret; -+ } -+ -+ printf("Input invalid.\n"); -+ help(); -+ -+ return -1; -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade_debug.c b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade_debug.c -new file mode 100644 -index 000000000..a7a78d011 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade_debug.c -@@ -0,0 +1,51 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "fw_upgrade_debug.h" -+ -+int fw_upgrade_debug(void) -+{ -+ int size; -+ FILE *fp; -+ char debug_info[DEBUG_INFO_LEN]; -+ -+ fp = fopen(DEBUG_FILE, "r"); -+ if (fp == NULL) { -+ return DEBUG_IGNORE; -+ } -+ -+ mem_clear(debug_info, DEBUG_INFO_LEN); -+ size = fread(debug_info, DEBUG_INFO_LEN - 1, 1, fp); -+ if (size < 0) { -+ fclose(fp); -+ return DEBUG_IGNORE; -+ } -+ -+ if (strncmp(debug_info, DEBUG_ON_INFO, 1) == 0) { -+ fclose(fp); -+ return DEBUG_APP_ON; -+ } -+ -+ if (strncmp(debug_info, DEBUG_ON_KERN, 1) == 0) { -+ fclose(fp); -+ return DEBUG_KERN_ON; -+ } -+ -+ if (strncmp(debug_info, DEBUG_ON_ALL, 1) == 0) { -+ fclose(fp); -+ return DEBUG_ALL_ON; -+ } -+ -+ if (strncmp(debug_info, DEBUG_OFF_INFO, 1) == 0) { -+ fclose(fp); -+ return DEBUG_OFF; -+ } -+ -+ fclose(fp); -+ return DEBUG_IGNORE; -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade.h b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade.h -new file mode 100644 -index 000000000..bd806a94b ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade.h -@@ -0,0 +1,230 @@ -+#ifndef _FW_UPGRADE_H_ -+#define _FW_UPGRADE_H_ -+ -+#include "fw_upgrade_debug.h" -+ -+#define dbg_print(debug, fmt, arg...) \ -+ if (debug == DEBUG_APP_ON || debug == DEBUG_ALL_ON) \ -+ { do{printf(fmt,##arg);} while(0); } -+ -+/* LPC Interface */ -+#define LPC_ADDR_PORT (0x4E) -+#define LPC_DATA_PORT (0x4F) -+ -+/* FMC REGISTER ADDR */ -+#define FMC_BASE_ADDR (0x1E620000) -+#define FMC_CE_TYPE_SETTING_REG (FMC_BASE_ADDR + 0x00) -+#define CE_CONTROL_REGISTER (FMC_BASE_ADDR + 0x04) -+#define INR_STATUS_CONTROL_REGISTER (FMC_BASE_ADDR + 0x08) -+#define COMMAND_CONTROL_REGISTER (FMC_BASE_ADDR + 0x0C) -+#define CE0_CONTROL_REGISTER (FMC_BASE_ADDR + 0x10) -+#define CE1_CONTROL_REGISTER (FMC_BASE_ADDR + 0x14) -+#define CE0_ADDRESS_RANGE_REGISTER (FMC_BASE_ADDR + 0x30) -+#define CE1_ADDRESS_RANGE_REGISTER (FMC_BASE_ADDR + 0x34) -+ -+/* SCU REGISTER ADDR */ -+#define SCU_ADDR (0x1E6E2000) -+#define HARDWARE_STRAP_REGISTER (SCU_ADDR + 0x70) -+#define REBOOT_CPU_REGISTER (SCU_ADDR + 0x7C) -+ -+/* SCU KEY */ -+#define UNLOCK_SCU_KEY (0x1688A8A8) -+#define LOCK_SCU_KEY (0x11111111) -+ -+/* WATCHDOG REGISTER ADDR */ -+#define WATCHDOG_ADDR (0x1E785000) -+#define WATCHDOG1_RELOAD_VALUE (WATCHDOG_ADDR + 0x04) -+#define WATCHDOG1_COUNTER_RST (WATCHDOG_ADDR + 0x08) -+#define WATCHDOG1_CONTROL (WATCHDOG_ADDR + 0x0C) -+#define WATCHDOG1_TSR (WATCHDOG_ADDR + 0x10) -+#define WATCHDOG1_CLEAR_STATUS (WATCHDOG_ADDR + 0x14) -+#define WATCHDOG1_RESET_FUN_MASK (WATCHDOG_ADDR + 0x1C) -+ -+#define WATCHDOG2_RELOAD_VALUE (WATCHDOG_ADDR + 0x24) -+#define WATCHDOG2_COUNTER_RST (WATCHDOG_ADDR + 0x28) -+#define WATCHDOG2_CONTROL (WATCHDOG_ADDR + 0x2C) -+#define WATCHDOG2_TSR (WATCHDOG_ADDR + 0x30) -+#define WATCHDOG2_CLEAR_STATUS (WATCHDOG_ADDR + 0x34) -+#define WATCHDOG2_RESET_FUN_MASK (WATCHDOG_ADDR + 0x3C) -+ -+/* User Mode Command */ -+#define WRITE_STATUS (0x01) -+#define COMMON_PAGE_PROGRAM (0x02) -+#define COMMON_FLASH_READ (0x03) -+#define WRITE_DISABLE_FLASH (0x04) -+#define READ_FLASH_STATUS (0x05) -+#define WRITE_ENABLE_FLASH (0x06) -+#define PAGE_PROGRAM_FLASH (0x12) -+#define SECTOR_ERASE (0x20) -+#define CLEAR_FLAG (0x50) -+#define SUBBLOCK_ERASE (0x52) -+#define CHIP_ERASE_FLASH (0x60) -+#define BLOCK_ERASE_64 (0xD8) -+#define READID (0x9F) -+#define ENABLE_BYTE4 (0xB7) -+#define EXIT_OTP (0xC1) -+#define RSTEN (0x66) -+#define RST (0x99) -+ -+#define BIT1 (0x01) -+#define BIT2 (0x02) -+#define BIT3 (0x04) -+#define BIT4 (0x08) -+#define BIT5 (0x10) -+#define BIT6 (0x20) -+#define BIT7 (0x40) -+#define BIT8 (0x80) -+#define RIGHT_SHIFT_8(reg) (reg >> 8) -+#define RIGHT_SHIFT_16(reg) (reg >> 16) -+#define RIGHT_SHIFT_24(reg) (reg >> 24) -+#define MASK (0xFF) -+#define FLASH_TYPE_MASK (BIT1 | BIT2) -+#define BOOT_DEFAULT_MASK (BIT8) -+#define HEAD_MASK (0x00FFFF00) -+#define MASK_BYTE (0xFF000000) -+#define BYTE1 (1) -+#define BYTE2 (2) -+#define BYTE4 (4) -+#define BYTE1_VAL (0) -+#define BYTE2_VAL (1) -+#define BYTE4_VAL (2) -+#define BYTE_RESERVED (3) -+ -+/* SuperIO */ -+#define SUPERIO_07 (0x07) -+#define SUPERIO_30 (0x30) -+#define SUPERIO_A0 (0xA0) -+#define SUPERIO_A2 (0xA2) -+#define SUPERIO_REG0 (0xF0) -+#define SUPERIO_REG1 (0xF1) -+#define SUPERIO_REG2 (0xF2) -+#define SUPERIO_REG3 (0xF3) -+#define SUPERIO_REG4 (0xF4) -+#define SUPERIO_REG5 (0xF5) -+#define SUPERIO_REG6 (0xF6) -+#define SUPERIO_REG7 (0xF7) -+#define SUPERIO_REG8 (0xF8) -+#define SUPERIO_FE (0xFE) -+ -+/* SPI Command */ -+#define HIGH_CLOCK (0x00000000) -+#define NORMAL_READ (0x00000000) -+#define READ_MODE (0x00000001) -+#define WRITE_MODE (0x00000002) -+#define USER_MODE (0x00000003) -+#define PULL_DOWN (0x00000000) -+#define PULL_UP (0x00000004) -+ -+#define CHIP_ERASE_TIME (60) -+#define CHIP_ERASE_TIMEOUT (300 * 1000 * 1000) -+#define CHIP_ERASE_SLEEP_TIME (5 * 1000 * 1000) -+#define BLOCK_ERASE_TIMEOUT (10 * 1000 * 1000) -+#define BLOCK_ERASE_SLEEP_TIME (100 * 1000) -+#define PAGE_PROGRAM_TIMEOUT (100 * 1000) -+#define PAGE_PROGRAM_SLEEP_TIME (1000) -+#define FLASH_WEL_TIMEOUT (100 * 1000) -+#define FLASH_WEL_SLEEP_TIME (1000) -+#define FLASH_WIP_MASK (0x00000001) -+#define FLASH_WRITE_ENABLE_MASK (0x00000002) -+ -+#define DATA_LENGTH_MASK (0xA2) -+#define TOGGLE_WRITE (0xCF) -+#define DISABLE_LPC (0xAA) -+#define ENABLE_LPC (0xA5) -+#define LPC_TO_AHB (0x0D) -+#define ENABLE_LPC_TO_AHB (0x01) -+#define DISABLE_LPC_TO_AHB (0x00) -+#define ENABLE_BMC_CPU_BOOT (0xF10BD286) -+#define DISABLE_BMC_CPU_BOOT (0xF10BD287) -+#define SET_BMC_CPU_BOOT (0x01) -+#define CLEAR_WATCHDOG_STATUS (0x01) -+#define DISABLE_WATCHDOG (0x00000030) -+#define ENABLE_WATCHDOG (0x00000033) -+#define WATCHDOG_GATEMASK (0x033FFFF3) -+#define WATCHDOG_NEW_COUNT (0x00050000) -+#define WATCHDOG_RELOAD_COUNTER (0x4755) -+ -+#define CE0_SPI_TYPE (0x00000002) -+#define CE1_SPI_TYPE (0x00000008) -+#define ERROR_COMMAND (0x00000400) -+#define ADDRESS_PROTECT (0x00000200) -+#define CLEAR_INR_STATUS_CONTROL (ERROR_COMMAND | ADDRESS_PROTECT) -+#define USER_MODE_PULL_CE_DOWN (HIGH_CLOCK | USER_MODE | PULL_DOWN) -+#define USER_MODE_PULL_CE_UP (HIGH_CLOCK | USER_MODE | PULL_UP) -+ -+#define STEP_64 (64 * 1024) -+#define STEP_256 (256 * 1024) -+#define BYTE_256 (256) -+ -+#define CE0 (0) -+#define CE1 (1) -+#define BOTHFLASH (2) -+#define SOC_SYS (0) -+#define FULL_CHIP (1) -+#define ARM_CPU (2) -+#define FULL_ERASE (0) -+#define BLOCK_ERASE (1) -+#define READ_ALL (2) -+#define CURRENT_SLAVE (1) -+#define CURRENT_MASTER (0) -+#define REGISTER_HEAD (0x1e000000) -+#define DEFAULT_WIDTH (16) -+#define MAX_FILENAME_LENGTH (64) -+#define SEGMENT_ADDR_START(_r) ((((_r) >> 16) & 0xFF) << 23) -+ -+typedef struct flash_info { -+ uint32_t flash_size; -+ int cs; -+ int flash_type; -+ uint32_t flash_id; -+ int page_size; -+ char flash_name[64]; -+ int erase_block_command; -+ int page_program; -+ int block_size; -+ int full_erase; -+ uint32_t ce_control_reg; -+ uint32_t flash_base_addr; -+} flash_info_t; -+ -+typedef enum flash_id { -+ MX25L6433F = 0x1920c2, -+ S25FL512S = 0x200201, -+ MX25l512 = 0x1a20c2, -+ STM25P64 = 0x172020, -+ STM25P128 = 0x182020, -+ N25Q256 = 0x19ba20, -+ N25Q512 = 0x20ba20, -+ W25X16 = 0x1530ef, -+ W25X64 = 0x1730ef, -+ W25Q64BV = 0x1740ef, -+ W25Q128BV = 0x1840ef, -+ W25Q256FV = 0x1940ef, -+ MX25L1605D = 0x1520C2, -+ MX25L12805D = 0x1820C2, -+ MX66L1G45G = 0x1B20C2, -+ SST25VF016B = 0x4125bf, -+ SST25VF064C = 0x4b25bf, -+ SST25VF040B = 0x8d25bf, -+ AT25DF161 = 0x02461F, -+ AT25DF321 = 0x01471F, -+ GD25Q256 = 0X1940c8, -+} flash_id_t; -+ -+typedef enum flash_type { -+ NOR = 0, -+ SPI = 2, -+} flash_type_t; -+ -+typedef enum flash_size { -+ M1 = 0x00080000, -+ M3 = 0x00200000, /* 3M */ -+ M6 = 0x00400000, /* 6M */ -+ M12 = 0x00800000, /* 12M */ -+ M16 = 0x01000000, /* 16M */ -+ M32 = 0x02000000, /* 32M */ -+ M64 = 0x04000000, /* 64M */ -+ M128 = 0x08000000, /* 128M */ -+} flash_size_t; -+ -+#endif /*_FW_UPGRADE_H_*/ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade_debug.h b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade_debug.h -new file mode 100644 -index 000000000..05911da62 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade_debug.h -@@ -0,0 +1,25 @@ -+#ifndef __FW_UPGRADE_DEBUG_H__ -+#define __FW_UPGRADE_DEBUG_H__ -+ -+#include -+ -+#define DEBUG_INFO_LEN 20 -+#define DEBUG_FILE "/tmp/.fw_upgrade_debug" -+#define DEBUG_ON_ALL "3" -+#define DEBUG_ON_KERN "2" -+#define DEBUG_ON_INFO "1" -+#define DEBUG_OFF_INFO "0" -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+ -+enum debug_s { -+ DEBUG_OFF = 0, -+ DEBUG_APP_ON, -+ DEBUG_KERN_ON, -+ DEBUG_ALL_ON, -+ DEBUG_IGNORE, -+}; -+ -+extern int fw_upgrade_debug(void); -+ -+#endif /* End of __FW_UPGRADE_DEBUG_H__ */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/__init__.py -new file mode 100644 -index 000000000..e69de29bb -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/hysteresis.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/hysteresis.py -new file mode 100644 -index 000000000..81fd596e7 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/hysteresis.py -@@ -0,0 +1,169 @@ -+#!/usr/bin/env python3 -+import os -+import syslog -+import copy -+ -+from plat_hal.baseutil import baseutil -+ -+HYST_DEBUG_FILE = "/etc/.hysteresis_debug_flag" -+ -+HYSTERROR = 1 -+HYSTDEBUG = 2 -+ -+debuglevel = 0 -+ -+ -+def hyst_debug(s): -+ if HYSTDEBUG & debuglevel: -+ syslog.openlog("FANCONTROL-HYST", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def hyst_error(s): -+ if HYSTERROR & debuglevel: -+ syslog.openlog("FANCONTROL-HYST", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+class hysteresis(object): -+ __config = None -+ __hyst_config = None -+ -+ def __init__(self): -+ self.__config = baseutil.get_monitor_config() -+ self.__hyst_config = copy.deepcopy(self.__config.get("hyst", {})) -+ # init check -+ errcnt = 0 -+ errmsg = "" -+ self.debug_init() -+ for temp_hyst_conf in self.__hyst_config.values(): -+ if temp_hyst_conf["flag"] == 0: -+ continue -+ for i in range(temp_hyst_conf["temp_min"], temp_hyst_conf["temp_max"] + 1): -+ if i not in temp_hyst_conf["rising"]: -+ errcnt -= 1 -+ msg = "%s hyst config error, temp value %d not in rising curve;" % (temp_hyst_conf["name"], i) -+ hyst_error(msg) -+ errmsg += msg -+ if i not in temp_hyst_conf["descending"]: -+ errcnt -= 1 -+ msg = "%s hyst config error, temp value %d not in descending curve;" % (temp_hyst_conf["name"], i) -+ hyst_error(msg) -+ errmsg += msg -+ if errcnt < 0: -+ raise KeyError(errmsg) -+ -+ def debug_init(self): -+ global debuglevel -+ if os.path.exists(HYST_DEBUG_FILE): -+ debuglevel = debuglevel | HYSTDEBUG | HYSTERROR -+ else: -+ debuglevel = debuglevel & ~(HYSTDEBUG | HYSTERROR) -+ -+ def get_temp_hyst_conf(self, temp_name): -+ temp_hyst_conf = self.__hyst_config.get(temp_name) -+ return temp_hyst_conf -+ -+ def get_temp_update(self, hyst_para, current_temp): -+ temp = hyst_para["value"] -+ if temp is None: -+ return None -+ temp.append(current_temp) -+ del temp[0] -+ return temp -+ -+ def duty_to_pwm(self, duty): -+ pwm = int(round(float(duty) * 255 / 100)) -+ return pwm -+ -+ def pwm_to_duty(self, pwm): -+ duty = int(round(float(pwm) * 100 / 255)) -+ return duty -+ -+ def calc_hyst_val(self, temp_name, temp_list): -+ -+ temp_hyst_conf = self.get_temp_hyst_conf(temp_name) -+ hyst_min = temp_hyst_conf["hyst_min"] -+ hyst_max = temp_hyst_conf["hyst_max"] -+ temp_min = temp_hyst_conf["temp_min"] -+ temp_max = temp_hyst_conf["temp_max"] -+ rising = temp_hyst_conf["rising"] -+ descending = temp_hyst_conf["descending"] -+ last_hyst_value = temp_hyst_conf["last_hyst_value"] -+ current_temp = temp_list[1] -+ last_temp = temp_list[0] -+ -+ hyst_debug("calc_hyst_val, temp_name: %s, current_temp: %s, last_temp: %s, last_hyst_value: %s" % -+ (temp_name, current_temp, last_temp, last_hyst_value)) -+ -+ if current_temp < temp_min: -+ hyst_debug("%s current_temp %s less than temp_min %s, set min hyst value: %s" % -+ (temp_name, current_temp, temp_min, hyst_min)) -+ return hyst_min -+ -+ if current_temp > temp_max: -+ hyst_debug("%s current_temp %s more than temp_max %s, set max hyst value: %s" % -+ (temp_name, current_temp, temp_max, hyst_max)) -+ return hyst_max -+ -+ if last_temp is None: # first time -+ hyst_value = rising[current_temp] -+ hyst_debug("last_temp is None, it's first hysteresis, using rising hyst value: %s" % hyst_value) -+ return hyst_value -+ -+ if current_temp == last_temp: # temp unchanging -+ hyst_debug("current_temp equal last_temp, keep last hyst value: %s" % last_hyst_value) -+ return last_hyst_value -+ -+ if current_temp > last_temp: -+ calc_hyst_value = rising[current_temp] -+ if calc_hyst_value < last_hyst_value: -+ hyst_value = last_hyst_value -+ else: -+ hyst_value = calc_hyst_value -+ hyst_debug("temp rising, last_hyst_value: %s, calc_hyst_value: %s, set hyst value: %s" % -+ (last_hyst_value, calc_hyst_value, hyst_value)) -+ return hyst_value -+ -+ calc_hyst_value = descending[current_temp] -+ if calc_hyst_value > last_hyst_value: -+ hyst_value = last_hyst_value -+ else: -+ hyst_value = calc_hyst_value -+ hyst_debug("temp descending, last_hyst_value: %s, calc_hyst_value: %s, set hyst value: %s" % -+ (last_hyst_value, calc_hyst_value, hyst_value)) -+ return hyst_value -+ -+ def cacl(self, temp_name, current_temp): -+ self.debug_init() -+ try: -+ temp_hyst_conf = self.get_temp_hyst_conf(temp_name) -+ if temp_hyst_conf is None: -+ hyst_debug("get %s hysteresis config failed" % temp_name) -+ return None -+ -+ flag = temp_hyst_conf["flag"] -+ if flag != 1: -+ hyst_debug("%s hysteresis flag == 0, skip" % temp_name) -+ return None -+ -+ temp = self.get_temp_update(temp_hyst_conf, current_temp) -+ if temp is None: -+ hyst_debug("get %s update failed" % temp_name) -+ return None -+ -+ value = self.calc_hyst_val(temp_name, temp) -+ -+ temp_hyst_conf["last_hyst_value"] = value -+ -+ speed_type = temp_hyst_conf["type"] -+ if speed_type == "duty": -+ pwm = self.duty_to_pwm(value) -+ else: -+ pwm = value -+ -+ hyst_debug("temp_name: %s, current_temp: %s, set pwm 0x%x" % (temp_name, current_temp, pwm)) -+ return pwm -+ except Exception as e: -+ hyst_error("temp_name: %s calc hysteresis pwm error, msg: %s" % (temp_name, str(e))) -+ return None -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/openloop.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/openloop.py -new file mode 100644 -index 000000000..6ff731fa7 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/openloop.py -@@ -0,0 +1,104 @@ -+#!/usr/bin/env python3 -+import os -+import syslog -+ -+from plat_hal.baseutil import baseutil -+ -+OPENLOOP_DEBUG_FILE = "/etc/.openloop_debug_flag" -+ -+OPENLOOPERROR = 1 -+OPENLOOPDEBUG = 2 -+ -+debuglevel = 0 -+ -+ -+def openloop_debug(s): -+ if OPENLOOPDEBUG & debuglevel: -+ syslog.openlog("FANCONTROL-OPENLOOP", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def openloop_error(s): -+ if OPENLOOPERROR & debuglevel: -+ syslog.openlog("FANCONTROL-OPENLOOP", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+class openloop(object): -+ __config = None -+ __openloop_config = None -+ -+ def __init__(self): -+ self.__config = baseutil.get_monitor_config() -+ self.__openloop_config = self.__config["openloop"] -+ -+ def debug_init(self): -+ global debuglevel -+ if os.path.exists(OPENLOOP_DEBUG_FILE): -+ debuglevel = debuglevel | OPENLOOPDEBUG | OPENLOOPERROR -+ else: -+ debuglevel = debuglevel & ~(OPENLOOPDEBUG | OPENLOOPERROR) -+ -+ def get_para(self, t): -+ para = self.__openloop_config.get(t) -+ return para -+ -+ def linear_cacl(self, temp): -+ self.debug_init() -+ openloop_para = self.get_para("linear") -+ if openloop_para is None: -+ openloop_debug("linear openloop: get para failed") -+ return None -+ -+ K = openloop_para["K"] -+ tin_min = openloop_para["tin_min"] -+ pwm_min = openloop_para["pwm_min"] -+ pwm_max = openloop_para["pwm_max"] -+ flag = openloop_para["flag"] -+ -+ if flag != 1: -+ openloop_debug("linear openloop: flag == 0") -+ return None -+ -+ if temp <= tin_min: -+ openloop_debug("linear openloop: temp = %d less than tin_min[%d]" % (temp, tin_min)) -+ return pwm_min -+ -+ pwm = int(pwm_min + (temp - tin_min) * K) -+ openloop_debug("linear openloop: cacl_pwm = 0x%x" % pwm) -+ -+ pwm = min(pwm, pwm_max) -+ pwm = max(pwm, pwm_min) -+ openloop_debug("linear openloop: temp = %d, pwm = 0x%x" % (temp, pwm)) -+ return pwm -+ -+ def curve_cacl(self, temp): -+ self.debug_init() -+ openloop_para = self.get_para("curve") -+ if openloop_para is None: -+ openloop_debug("curve openloop: get para failed") -+ return None -+ -+ a = openloop_para["a"] -+ b = openloop_para["b"] -+ c = openloop_para["c"] -+ tin_min = openloop_para["tin_min"] -+ pwm_min = openloop_para["pwm_min"] -+ pwm_max = openloop_para["pwm_max"] -+ flag = openloop_para["flag"] -+ -+ if flag != 1: -+ openloop_debug("curve openloop: flag == 0") -+ return None -+ -+ if temp <= tin_min: -+ openloop_debug("curve openloop: temp = %d less than tin_min[%d]" % (temp, tin_min)) -+ return pwm_min -+ -+ pwm = int(a * temp * temp + b * temp + c) -+ openloop_debug("curve openloop: cacl_pwm = 0x%x" % pwm) -+ -+ pwm = min(pwm, pwm_max) -+ pwm = max(pwm, pwm_min) -+ openloop_debug("curve openloop: temp = %d, pwm = 0x%x" % (temp, pwm)) -+ return pwm -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/pid.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/pid.py -new file mode 100644 -index 000000000..c33c1df33 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/pid.py -@@ -0,0 +1,106 @@ -+#!/usr/bin/env python3 -+import os -+import syslog -+import copy -+ -+from plat_hal.baseutil import baseutil -+ -+PID_DEBUG_FILE = "/etc/.pid_debug_flag" -+ -+PIDERROR = 1 -+PIDDEBUG = 2 -+ -+debuglevel = 0 -+ -+ -+def pid_debug(s): -+ if PIDDEBUG & debuglevel: -+ syslog.openlog("FANCONTROL-PID", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def pid_error(s): -+ if PIDERROR & debuglevel: -+ syslog.openlog("FANCONTROL-PID", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+class pid(object): -+ __config = None -+ __pid_config = None -+ -+ def __init__(self): -+ self.__config = baseutil.get_monitor_config() -+ self.__pid_config = copy.deepcopy(self.__config["pid"]) -+ -+ def debug_init(self): -+ global debuglevel -+ if os.path.exists(PID_DEBUG_FILE): -+ debuglevel = debuglevel | PIDDEBUG | PIDERROR -+ else: -+ debuglevel = debuglevel & ~(PIDDEBUG | PIDERROR) -+ -+ def get_para(self, name): -+ para = self.__pid_config.get(name) -+ return para -+ -+ def get_temp_update(self, pid_para, current_temp): -+ temp = pid_para["value"] -+ if temp is None: -+ return None -+ temp.append(current_temp) -+ del temp[0] -+ return temp -+ -+ def cacl(self, last_pwm, name, current_temp): -+ delta_pwm = 0 -+ self.debug_init() -+ pid_debug("last_pwm = %d" % last_pwm) -+ -+ pid_para = self.get_para(name) -+ if pid_para is None: -+ pid_debug("get %s pid para failed" % name) -+ return None -+ -+ temp = self.get_temp_update(pid_para, current_temp) -+ if temp is None: -+ pid_debug("get %s update failed" % name) -+ return None -+ -+ speed_type = pid_para["type"] -+ Kp = pid_para["Kp"] -+ Ki = pid_para["Ki"] -+ Kd = pid_para["Kd"] -+ target = pid_para["target"] -+ pwm_min = pid_para["pwm_min"] -+ pwm_max = pid_para["pwm_max"] -+ flag = pid_para["flag"] -+ -+ if flag != 1: -+ pid_debug("%s pid flag == 0" % name) -+ return None -+ -+ if speed_type == "duty": -+ current_pwm = round(last_pwm * 100 / 255) -+ else: -+ current_pwm = last_pwm -+ -+ if temp[2] is None: -+ tmp_pwm = current_pwm -+ elif ((temp[0] is None) or (temp[1] is None)): -+ delta_pwm = Ki * (temp[2] - target) -+ tmp_pwm = current_pwm + delta_pwm -+ else: -+ delta_pwm = Kp * (temp[2] - temp[1]) + Ki * (temp[2] - target) + Kd * (temp[2] - 2 * temp[1] + temp[0]) -+ tmp_pwm = current_pwm + delta_pwm -+ -+ pid_debug("delta_pwm = %d" % delta_pwm) -+ if speed_type == "duty": -+ pwm = round(tmp_pwm * 255 / 100) -+ else: -+ pwm = int(tmp_pwm) -+ -+ pwm = min(pwm, pwm_max) -+ pwm = max(pwm, pwm_min) -+ pid_debug("last_pwm = 0x%x, pwm = 0x%x" % (last_pwm, pwm)) -+ return pwm -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/__init__.py -new file mode 100644 -index 000000000..e69de29bb -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/cust_fru.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/cust_fru.py -new file mode 100644 -index 000000000..940c722ce ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/cust_fru.py -@@ -0,0 +1,135 @@ -+#!/usr/bin/python -+# -*- coding: utf-8 -*- -+import sys -+import os -+ -+ -+class CustFruException(Exception): -+ def __init__(self, message='custfrueerror', code=-100): -+ err = 'errcode: {0} message:{1}'.format(code, message) -+ Exception.__init__(self, err) -+ self.code = code -+ self.message = message -+ -+ -+class CustFru(): -+ MAGIC_HEAD_INFO = 0x7a -+ -+ _CUST_MAGIC_OFFSET = 0 -+ _CUST_MAGIC_LEN = 1 -+ _CUST_VERSION_OFFSET = 1 -+ _CUST_VERSION_LEN = 6 -+ _CUST_CRC_OFFSET = 7 -+ _CUST_CRC_LEN = 1 -+ _CUST_PRODUCT_NAME_OFFSET = 10 -+ _CUST_PRODUCT_NAME_LEN = 17 -+ _CUST_MANUFACTURER_OFFSET = 27 -+ _CUST_MANUFACTURER_LEN = 7 -+ _CUST_SERIAL_NUMBER_OFFSET = 34 -+ _CUST_SERIAL_NUMBER_LEN = 25 -+ _CUST_INPUT_TYPE_OFFSET = 78 -+ _CUST_INPUT_TYPE_LEN = 2 -+ _CUST_INPUT_OFFSET = 86 -+ _CUST_INPUT_LEN = 15 -+ _CUST_OUTPUT_OFFSET = 108 -+ _CUST_OUTPUT_LEN = 11 -+ _CUST_POWER_OFFSET = 200 -+ _CUST_POWER_LEN = 10 -+ _CUST_MANUFACTURER_DATE_OFFSET = 210 -+ _CUST_MANUFACTURER_DATE_LEN = 3 -+ -+ def __init__(self): -+ self.magic = "" -+ self.version = "" -+ self.crc = "" -+ self.product_name = "" -+ self.manufacturer = "" -+ self.serial_number = "" -+ self.input_type = "" -+ self.input = "" -+ self.output = "" -+ self.power = "" -+ self.manufacturer_date = "" -+ -+ def checksum(self, v): -+ result = 0 -+ for item in v: -+ result += ord(item) -+ return (result & 0xff) -+ -+ def decode(self, e2): -+ # header -+ e2_index = 0 -+ head = ord(e2[0]) -+ if head != self.MAGIC_HEAD_INFO: -+ raise CustFruException("Customization fru eeprom head info error, head:0x%x" % head, -10) -+ self.magic = "0x%02x" % self.MAGIC_HEAD_INFO -+ -+ # version -+ version = "%s" % (e2[self._CUST_VERSION_OFFSET:self._CUST_VERSION_OFFSET + self._CUST_VERSION_LEN]) -+ self.version = version.replace("\xff", "").strip() -+ -+ # crc -+ crc_calc = self.checksum(e2[0:self._CUST_CRC_OFFSET]) -+ if crc_calc != ord(e2[self._CUST_CRC_OFFSET]): -+ raise CustFruException("Customization fru eeprom crc check error, calc: 0x%x, read: 0x%x" % (crc_calc, ord(e2[self._CUST_CRC_OFFSET])), -10) -+ self.crc = crc_calc -+ -+ # Product Name -+ product_name = "%s" % (e2[self._CUST_PRODUCT_NAME_OFFSET:self._CUST_PRODUCT_NAME_OFFSET + self._CUST_PRODUCT_NAME_LEN]) -+ self.product_name = product_name.replace("\xff", "").strip() -+ -+ # manufacturer -+ manufacturer = "%s" % (e2[self._CUST_MANUFACTURER_OFFSET:self._CUST_MANUFACTURER_OFFSET + self._CUST_MANUFACTURER_LEN]) -+ self.manufacturer = manufacturer.strip() -+ -+ # serial_number -+ serial_number = "%s" % (e2[self._CUST_SERIAL_NUMBER_OFFSET:self._CUST_SERIAL_NUMBER_OFFSET + self._CUST_SERIAL_NUMBER_LEN]) -+ self.serial_number = serial_number.strip() -+ -+ # input_type -+ input_type = "%s" % (e2[self._CUST_INPUT_TYPE_OFFSET:self._CUST_INPUT_TYPE_OFFSET + self._CUST_INPUT_TYPE_LEN]) -+ self.input_type = input_type.strip() -+ -+ # input -+ input = "%s" % (e2[self._CUST_INPUT_OFFSET:self._CUST_INPUT_OFFSET + self._CUST_INPUT_LEN]) -+ self.input = input.strip() -+ -+ # output -+ output = "%s" % (e2[self._CUST_OUTPUT_OFFSET:self._CUST_OUTPUT_OFFSET + self._CUST_OUTPUT_LEN]) -+ self.output = output.strip() -+ -+ # power -+ power = "%s" % (e2[self._CUST_POWER_OFFSET:self._CUST_POWER_OFFSET + self._CUST_POWER_LEN]) -+ self.power = power.replace("\xff", "").strip() -+ -+ # manufacturer_date -+ manufacturer_year = ord(e2[self._CUST_MANUFACTURER_DATE_OFFSET]) + 2000 -+ manufacturer_month = ord(e2[self._CUST_MANUFACTURER_DATE_OFFSET + 1]) -+ manufacturer_day = ord(e2[self._CUST_MANUFACTURER_DATE_OFFSET + 2]) -+ self.manufacturer_date = "%04d-%02d-%02d" % (manufacturer_year, manufacturer_month, manufacturer_day) -+ -+ return -+ -+ -+ def __str__(self): -+ formatstr = "Version : %s \n" \ -+ "Product Name : %s \n" \ -+ "Manufacturer : %s \n" \ -+ "Serial Number : %s \n" \ -+ "AC/DC Power Module : %s \n" \ -+ "INPUT : %s \n" \ -+ "OUTPUT : %s \n" \ -+ "POWER : %s \n" \ -+ "Manufacturer Date : %s \n" -+ str_tmp = formatstr % (self.version, -+ self.product_name, -+ self.manufacturer, -+ self.serial_number, -+ self.input_type, -+ self.input, -+ self.output, -+ self.power, -+ self.manufacturer_date) -+ return str_tmp.replace("\x00","") -+ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fantlv.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fantlv.py -new file mode 100644 -index 000000000..4be78e7fd ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fantlv.py -@@ -0,0 +1,192 @@ -+#!/usr/bin/python3 -+# -*- coding: utf-8 -*- -+ -+class FantlvException(Exception): -+ def __init__(self, message='fantlverror', code=-100): -+ err = 'errcode: {0} message:{1}'.format(code, message) -+ Exception.__init__(self, err) -+ self.code = code -+ self.message = message -+ -+ -+class fan_tlv(): -+ HEAD_INFO = "\x01\x7e\x01\xf1" -+ VERSION = 0x01 -+ FLAG = 0x7E -+ HW_VER = 0X01 -+ TYPE = 0xf1 -+ TLV_LEN = 00 -+ _FAN_TLV_HDR_LEN = 6 -+ _FAN_TLV_CRC_LEN = 2 -+ -+ _FAN_TLV_TYPE_NAME = 0x02 -+ _FAN_TLV_TYPE_SN = 0x03 -+ _FAN_TLV_TYPE_HW_INFO = 0x05 -+ _FAN_TLV_TYPE_DEV_TYPE = 0x06 -+ -+ @property -+ def dstatus(self): -+ return self._dstatus -+ -+ @property -+ def typename(self): -+ return self._typename -+ -+ @property -+ def typesn(self): -+ return self._typesn -+ -+ @property -+ def typehwinfo(self): -+ return self._typehwinfo -+ -+ @property -+ def typedevtype(self): -+ return self._typedevtype -+ -+ def __init__(self): -+ self._typename = "" -+ self._typesn = "" -+ self._typehwinfo = "" -+ self._typedevtype = "" -+ self._dstatus = 0 -+ -+ def strtoarr(self, val): -+ s = [] -+ if not isinstance(val, str): -+ return s -+ for index in val: -+ s.append(index) -+ return s -+ -+ def hex_to_str(self, s): -+ len_t = len(s) -+ if len_t % 2 != 0: -+ return 0 -+ ret = "" -+ for t in range(0, len_t / 2): -+ ret += chr(int(s[2 * t:2 * t + 2], 16)) -+ return ret -+ -+ def generate_fan_value(self): -+ bin_buffer = [chr(0xff)] * 256 -+ bin_buffer[0] = chr(self.VERSION) -+ bin_buffer[1] = chr(self.FLAG) -+ bin_buffer[2] = chr(self.HW_VER) -+ bin_buffer[3] = chr(self.TYPE) -+ -+ temp_t = "%08x" % self.typedevtype -+ typedevtype_t = self.hex_to_str(temp_t) -+ total_len = len(self.typename) + len(self.typesn) + \ -+ len(self.typehwinfo) + len(typedevtype_t) + 8 -+ -+ bin_buffer[4] = chr(total_len >> 8) -+ bin_buffer[5] = chr(total_len & 0x00FF) -+ -+ index_start = 6 -+ bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_NAME) -+ bin_buffer[index_start + 1] = chr(len(self.typename)) -+ bin_buffer[index_start + 2: index_start + 2 + -+ len(self.typename)] = self.strtoarr(self.typename) -+ index_start = index_start + 2 + len(self.typename) -+ -+ bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_SN) -+ bin_buffer[index_start + 1] = chr(len(self.typesn)) -+ bin_buffer[index_start + 2:index_start + 2 + -+ len(self.typesn)] = self.strtoarr(self.typesn) -+ index_start = index_start + 2 + len(self.typesn) -+ -+ bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_HW_INFO) -+ bin_buffer[index_start + 1] = chr(len(self.typehwinfo)) -+ bin_buffer[index_start + 2:index_start + 2 + -+ len(self.typehwinfo)] = self.strtoarr(self.typehwinfo) -+ index_start = index_start + 2 + len(self.typehwinfo) -+ -+ bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_DEV_TYPE) -+ bin_buffer[index_start + 1] = chr(len(typedevtype_t)) -+ bin_buffer[index_start + 2:index_start + 2 + -+ len(typedevtype_t)] = self.strtoarr(typedevtype_t) -+ index_start = index_start + 2 + len(typedevtype_t) -+ -+ crcs = fan_tlv.fancrc(''.join(bin_buffer[0:index_start])) -+ bin_buffer[index_start] = chr(crcs >> 8) -+ bin_buffer[index_start + 1] = chr(crcs & 0x00ff) -+ return bin_buffer -+ -+ def decode(self, e2): -+ if e2[0:4] != self.HEAD_INFO: -+ raise FantlvException("Fan tlv head info error,not fan tlv type", -10) -+ ret = [] -+ self.VERSION = ord(e2[0]) -+ self.FLAG = ord(e2[1]) -+ self.HW_VER = ord(e2[2]) -+ self.TYPE = ord(e2[3]) -+ self.TLV_LEN = (ord(e2[4]) << 8) | ord(e2[5]) -+ -+ tlv_index = self._FAN_TLV_HDR_LEN -+ tlv_end = self._FAN_TLV_HDR_LEN + self.TLV_LEN -+ -+ if len(e2) < self._FAN_TLV_HDR_LEN + self.TLV_LEN + 2: -+ raise FantlvException("Fan tlv eeprom len error!", -2) -+ sumcrc = fan_tlv.fancrc(e2[0:self._FAN_TLV_HDR_LEN + self.TLV_LEN]) -+ readcrc = ord(e2[self._FAN_TLV_HDR_LEN + self.TLV_LEN] -+ ) << 8 | ord(e2[self._FAN_TLV_HDR_LEN + self.TLV_LEN + 1]) -+ if sumcrc != readcrc: -+ raise FantlvException("Fan tlv eeprom checksum error!", -1) -+ self._dstatus = 0 -+ while (tlv_index + 2) < len(e2) and tlv_index < tlv_end: -+ s = self.decoder( -+ e2[tlv_index:tlv_index + 2 + ord(e2[tlv_index + 1])]) -+ tlv_index += ord(e2[tlv_index + 1]) + 2 -+ ret.append(s) -+ -+ return ret -+ -+ @staticmethod -+ def fancrc(t): -+ crc = 0 -+ for item in t: -+ crc += ord(item) -+ return crc -+ -+ def decoder(self, t): -+ try: -+ name = "" -+ value = "" -+ _len = 0 -+ if ord(t[0]) == self._FAN_TLV_TYPE_NAME: -+ name = "Product Name" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._typename = value -+ elif ord(t[0]) == self._FAN_TLV_TYPE_SN: -+ name = "serial Number" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._typesn = value -+ elif ord(t[0]) == self._FAN_TLV_TYPE_HW_INFO: -+ name = "hardware info" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._typehwinfo = value -+ elif ord(t[0]) == self._FAN_TLV_TYPE_DEV_TYPE: -+ name = "dev type" -+ _len = ord(t[1]) -+ value = "0x" -+ for c in t[2:2 + ord(t[1])]: -+ value += "%02X" % (ord(c),) -+ self._typedevtype = int(value, 16) -+ except Exception as e: -+ print(e) -+ return {"name": name, "code": ord(t[0]), "value": value, "lens": _len} -+ -+ def __str__(self): -+ formatstr = "VERSION : 0x%02x \n" \ -+ " FLAG : 0x%02x \n" \ -+ " HW_VER : 0x%02x \n" \ -+ " TYPE : 0x%02x \n" \ -+ "typename : %s \n" \ -+ "typesn : %s \n" \ -+ "typehwinfo : %s \n" -+ return formatstr % (self.VERSION, self.FLAG, self.HW_VER, self.TYPE, -+ self.typename, self.typesn, self.typehwinfo) -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fru.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fru.py -new file mode 100644 -index 000000000..f95164e03 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fru.py -@@ -0,0 +1,961 @@ -+#!/usr/bin/python3 -+import collections -+from datetime import datetime, timedelta -+from bitarray import bitarray -+ -+ -+__DEBUG__ = "N" -+ -+ -+class FruException(Exception): -+ def __init__(self, message='fruerror', code=-100): -+ err = 'errcode: {0} message:{1}'.format(code, message) -+ Exception.__init__(self, err) -+ self.code = code -+ self.message = message -+ -+ -+def e_print(err): -+ print("ERROR: " + err) -+ -+ -+def d_print(debug_info): -+ if __DEBUG__ == "Y": -+ print(debug_info) -+ -+ -+class FruUtil(): -+ @staticmethod -+ def decodeLength(value): -+ a = bitarray(8) -+ a.setall(True) -+ a[0:1] = 0 -+ a[1:2] = 0 -+ x = ord(a.tobytes()) -+ return x & ord(value) -+ -+ @staticmethod -+ def minToData(): -+ starttime = datetime(1996, 1, 1, 0, 0, 0) -+ endtime = datetime.now() -+ seconds = (endtime - starttime).total_seconds() -+ mins = seconds // 60 -+ m = int(round(mins)) -+ return m -+ -+ @staticmethod -+ def getTimeFormat(): -+ return datetime.now().strftime('%Y-%m-%d') -+ -+ @staticmethod -+ def getTypeLength(value): -+ if value is None or len(value) == 0: -+ return 0 -+ a = bitarray(8) -+ a.setall(False) -+ a[0:1] = 1 -+ a[1:2] = 1 -+ x = ord(a.tobytes()) -+ return x | len(value) -+ -+ @staticmethod -+ def checksum(b): -+ result = 0 -+ for item in b: -+ result += ord(item) -+ return (0x100 - (result & 0xff)) & 0xff -+ -+ -+class BaseArea(object): -+ SUGGESTED_SIZE_COMMON_HEADER = 8 -+ SUGGESTED_SIZE_INTERNAL_USE_AREA = 72 -+ SUGGESTED_SIZE_CHASSIS_INFO_AREA = 32 -+ SUGGESTED_SIZE_BOARD_INFO_AREA = 80 -+ SUGGESTED_SIZE_PRODUCT_INFO_AREA = 80 -+ -+ INITVALUE = b'\x00' -+ resultvalue = INITVALUE * 256 -+ COMMON_HEAD_VERSION = b'\x01' -+ __childList = None -+ -+ def __init__(self, name="", size=0, offset=0): -+ self.__childList = [] -+ self._offset = offset -+ self.name = name -+ self._size = size -+ self._isPresent = False -+ self._data = b'\x00' * size -+ -+ @property -+ def childList(self): -+ return self.__childList -+ -+ @childList.setter -+ def childList(self, value): -+ self.__childList = value -+ -+ @property -+ def offset(self): -+ return self._offset -+ -+ @offset.setter -+ def offset(self, value): -+ self._offset = value -+ -+ @property -+ def size(self): -+ return self._size -+ -+ @size.setter -+ def size(self, value): -+ self._size = value -+ -+ @property -+ def data(self): -+ return self._data -+ -+ @data.setter -+ def data(self, value): -+ self._data = value -+ -+ @property -+ def isPresent(self): -+ return self._isPresent -+ -+ @isPresent.setter -+ def isPresent(self, value): -+ self._isPresent = value -+ -+ -+class InternalUseArea(BaseArea): -+ pass -+ -+ -+class ChassisInfoArea(BaseArea): -+ pass -+ -+ -+class BoardInfoArea(BaseArea): -+ _boardTime = None -+ _fields = None -+ _mfg_date = None -+ areaversion = None -+ _boardversion = None -+ _language = None -+ -+ def __str__(self): -+ formatstr = "version : %x\n" \ -+ "length : %d \n" \ -+ "language : %x \n" \ -+ "mfg_date : %s \n" \ -+ "boardManufacturer : %s \n" \ -+ "boardProductName : %s \n" \ -+ "boardSerialNumber : %s \n" \ -+ "boardPartNumber : %s \n" \ -+ "fruFileId : %s \n" -+ -+ tmpstr = formatstr % (ord(self.boardversion), self.size, -+ self.language, self.getMfgRealData(), -+ self.boardManufacturer, self.boardProductName, -+ self.boardSerialNumber, self.boardPartNumber, -+ self.fruFileId) -+ for i in range(1, 11): -+ valtmp = "boardextra%d" % i -+ if hasattr(self, valtmp): -+ valtmpval = getattr(self, valtmp) -+ tmpstr += "boardextra%d : %s \n" % (i, valtmpval) -+ else: -+ break -+ -+ return tmpstr -+ -+ def todict(self): -+ dic = collections.OrderedDict() -+ dic["boardversion"] = ord(self.boardversion) -+ dic["boardlength"] = self.size -+ dic["boardlanguage"] = self.language -+ dic["boardmfg_date"] = self.getMfgRealData() -+ dic["boardManufacturer"] = self.boardManufacturer -+ dic["boardProductName"] = self.boardProductName -+ dic["boardSerialNumber"] = self.boardSerialNumber -+ dic["boardPartNumber"] = self.boardPartNumber -+ dic["boardfruFileId"] = self.fruFileId -+ for i in range(1, 11): -+ valtmp = "boardextra%d" % i -+ if hasattr(self, valtmp): -+ valtmpval = getattr(self, valtmp) -+ dic[valtmp] = valtmpval -+ else: -+ break -+ return dic -+ -+ def decodedata(self): -+ index = 0 -+ self.areaversion = self.data[index] -+ index += 1 -+ d_print("decode length :%d class size:%d" % -+ ((ord(self.data[index]) * 8), self.size)) -+ index += 2 -+ -+ timetmp = self.data[index: index + 3] -+ self.mfg_date = ord(timetmp[0]) | ( -+ ord(timetmp[1]) << 8) | (ord(timetmp[2]) << 16) -+ d_print("decode getMfgRealData :%s" % self.getMfgRealData()) -+ index += 3 -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.boardManufacturer = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode boardManufacturer:%s" % self.boardManufacturer) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.boardProductName = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode boardProductName:%s" % self.boardProductName) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.boardSerialNumber = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode boardSerialNumber:%s" % self.boardSerialNumber) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.boardPartNumber = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode boardPartNumber:%s" % self.boardPartNumber) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.fruFileId = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode fruFileId:%s" % self.fruFileId) -+ -+ for i in range(1, 11): -+ valtmp = "boardextra%d" % i -+ if self.data[index] != chr(0xc1): -+ templen = FruUtil.decodeLength(self.data[index]) -+ tmpval = self.data[index + 1: index + templen + 1] -+ setattr(self, valtmp, tmpval) -+ index += templen + 1 -+ d_print("decode boardextra%d:%s" % (i, tmpval)) -+ else: -+ break -+ -+ def fruSetValue(self, field, value): -+ tmp_field = getattr(self, field, None) -+ if tmp_field is not None: -+ setattr(self, field, value) -+ -+ def recalcute(self): -+ d_print("boardInfoArea version:%x" % ord(self.boardversion)) -+ d_print("boardInfoArea length:%d" % self.size) -+ d_print("boardInfoArea language:%x" % self.language) -+ self.mfg_date = FruUtil.minToData() -+ d_print("boardInfoArea mfg_date:%x" % self.mfg_date) -+ -+ self.data = chr(ord(self.boardversion)) + \ -+ chr(self.size // 8) + chr(self.language) -+ -+ self.data += chr(self.mfg_date & 0xFF) -+ self.data += chr((self.mfg_date >> 8) & 0xFF) -+ self.data += chr((self.mfg_date >> 16) & 0xFF) -+ -+ d_print("boardInfoArea boardManufacturer:%s" % self.boardManufacturer) -+ typelength = FruUtil.getTypeLength(self.boardManufacturer) -+ self.data += chr(typelength) -+ self.data += self.boardManufacturer -+ -+ d_print("boardInfoArea boardProductName:%s" % self.boardProductName) -+ self.data += chr(FruUtil.getTypeLength(self.boardProductName)) -+ self.data += self.boardProductName -+ -+ d_print("boardInfoArea boardSerialNumber:%s" % self.boardSerialNumber) -+ self.data += chr(FruUtil.getTypeLength(self.boardSerialNumber)) -+ self.data += self.boardSerialNumber -+ -+ d_print("boardInfoArea boardPartNumber:%s" % self.boardPartNumber) -+ self.data += chr(FruUtil.getTypeLength(self.boardPartNumber)) -+ self.data += self.boardPartNumber -+ -+ d_print("boardInfoArea fruFileId:%s" % self.fruFileId) -+ self.data += chr(FruUtil.getTypeLength(self.fruFileId)) -+ self.data += self.fruFileId -+ -+ for i in range(1, 11): -+ valtmp = "boardextra%d" % i -+ if hasattr(self, valtmp): -+ valtmpval = getattr(self, valtmp) -+ d_print("boardInfoArea boardextra%d:%s" % (i, valtmpval)) -+ self.data += chr(FruUtil.getTypeLength(valtmpval)) -+ if valtmpval is not None: -+ self.data += valtmpval -+ else: -+ break -+ -+ self.data += chr(0xc1) -+ -+ if len(self.data) > (self.size - 1): -+ incr = (len(self.data) - self.size) // 8 + 1 -+ self.size += incr * 8 -+ -+ self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] -+ d_print("self data:%d" % len(self.data)) -+ d_print("self size:%d" % self.size) -+ d_print("adjust size:%d" % (self.size - len(self.data) - 1)) -+ self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) -+ -+ # checksum -+ checksum = FruUtil.checksum(self.data) -+ d_print("board info checksum:%x" % checksum) -+ self.data += chr(checksum) -+ -+ def getMfgRealData(self): -+ starttime = datetime(1996, 1, 1, 0, 0, 0) -+ mactime = starttime + timedelta(minutes=self.mfg_date) -+ return mactime -+ -+ @property -+ def language(self): -+ self._language = 25 -+ return self._language -+ -+ @property -+ def mfg_date(self): -+ return self._mfg_date -+ -+ @mfg_date.setter -+ def mfg_date(self, val): -+ self._mfg_date = val -+ -+ @property -+ def boardversion(self): -+ self._boardversion = self.COMMON_HEAD_VERSION -+ return self._boardversion -+ -+ @property -+ def fruFileId(self): -+ return self._FRUFileID -+ -+ @fruFileId.setter -+ def fruFileId(self, val): -+ self._FRUFileID = val -+ -+ @property -+ def boardPartNumber(self): -+ return self._boardPartNumber -+ -+ @boardPartNumber.setter -+ def boardPartNumber(self, val): -+ self._boardPartNumber = val -+ -+ @property -+ def boardSerialNumber(self): -+ return self._boardSerialNumber -+ -+ @boardSerialNumber.setter -+ def boardSerialNumber(self, val): -+ self._boardSerialNumber = val -+ -+ @property -+ def boardProductName(self): -+ return self._boradProductName -+ -+ @boardProductName.setter -+ def boardProductName(self, val): -+ self._boradProductName = val -+ -+ @property -+ def boardManufacturer(self): -+ return self._boardManufacturer -+ -+ @boardManufacturer.setter -+ def boardManufacturer(self, val): -+ self._boardManufacturer = val -+ -+ @property -+ def boardTime(self): -+ return self._boardTime -+ -+ @boardTime.setter -+ def boardTime(self, val): -+ self._boardTime = val -+ -+ @property -+ def fields(self): -+ return self._fields -+ -+ @fields.setter -+ def fields(self, val): -+ self._fields = val -+ -+ -+class ProductInfoArea(BaseArea): -+ _productManufacturer = None -+ _productAssetTag = None -+ _FRUFileID = None -+ _language = None -+ -+ def __str__(self): -+ formatstr = "version : %x\n" \ -+ "length : %d \n" \ -+ "language : %x \n" \ -+ "productManufacturer : %s \n" \ -+ "productName : %s \n" \ -+ "productPartModelName: %s \n" \ -+ "productVersion : %s \n" \ -+ "productSerialNumber : %s \n" \ -+ "productAssetTag : %s \n" \ -+ "fruFileId : %s \n" -+ -+ tmpstr = formatstr % (ord(self.areaversion), self.size, -+ self.language, self.productManufacturer, -+ self.productName, self.productPartModelName, -+ self.productVersion, self.productSerialNumber, -+ self.productAssetTag, self.fruFileId) -+ -+ for i in range(1, 11): -+ valtmp = "productextra%d" % i -+ if hasattr(self, valtmp): -+ valtmpval = getattr(self, valtmp) -+ tmpstr += "productextra%d : %s \n" % (i, valtmpval) -+ else: -+ break -+ -+ return tmpstr -+ -+ def todict(self): -+ dic = collections.OrderedDict() -+ dic["productversion"] = ord(self.areaversion) -+ dic["productlength"] = self.size -+ dic["productlanguage"] = self.language -+ dic["productManufacturer"] = self.productManufacturer -+ dic["productName"] = self.productName -+ dic["productPartModelName"] = self.productPartModelName -+ dic["productVersion"] = int(self.productVersion, 16) -+ dic["productSerialNumber"] = self.productSerialNumber -+ dic["productAssetTag"] = self.productAssetTag -+ dic["productfruFileId"] = self.fruFileId -+ for i in range(1, 11): -+ valtmp = "productextra%d" % i -+ if hasattr(self, valtmp): -+ valtmpval = getattr(self, valtmp) -+ dic[valtmp] = valtmpval -+ else: -+ break -+ return dic -+ -+ def decodedata(self): -+ index = 0 -+ self.areaversion = self.data[index] # 0 -+ index += 1 -+ d_print("decode length %d" % (ord(self.data[index]) * 8)) -+ d_print("class size %d" % self.size) -+ index += 2 -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.productManufacturer = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode productManufacturer:%s" % self.productManufacturer) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.productName = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode productName:%s" % self.productName) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.productPartModelName = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode productPartModelName:%s" % self.productPartModelName) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.productVersion = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode productVersion:%s" % self.productVersion) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.productSerialNumber = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode productSerialNumber:%s" % self.productSerialNumber) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.productAssetTag = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode productAssetTag:%s" % self.productAssetTag) -+ -+ templen = FruUtil.decodeLength(self.data[index]) -+ self.fruFileId = self.data[index + 1: index + templen + 1] -+ index += templen + 1 -+ d_print("decode fruFileId:%s" % self.fruFileId) -+ -+ for i in range(1, 11): -+ valtmp = "productextra%d" % i -+ if self.data[index] != chr(0xc1) and index < self.size - 1: -+ templen = FruUtil.decodeLength(self.data[index]) -+ if templen == 0: -+ break -+ tmpval = self.data[index + 1: index + templen + 1] -+ d_print("decode boardextra%d:%s" % (i, tmpval)) -+ setattr(self, valtmp, tmpval) -+ index += templen + 1 -+ else: -+ break -+ -+ @property -+ def productVersion(self): -+ return self._productVersion -+ -+ @productVersion.setter -+ def productVersion(self, name): -+ self._productVersion = name -+ -+ @property -+ def areaversion(self): -+ self._areaversion = self.COMMON_HEAD_VERSION -+ return self._areaversion -+ -+ @areaversion.setter -+ def areaversion(self, name): -+ self._areaversion = name -+ -+ @property -+ def language(self): -+ self._language = 25 -+ return self._language -+ -+ @property -+ def productManufacturer(self): -+ return self._productManufacturer -+ -+ @productManufacturer.setter -+ def productManufacturer(self, name): -+ self._productManufacturer = name -+ -+ @property -+ def productName(self): -+ return self._productName -+ -+ @productName.setter -+ def productName(self, name): -+ self._productName = name -+ -+ @property -+ def productPartModelName(self): -+ return self._productPartModelName -+ -+ @productPartModelName.setter -+ def productPartModelName(self, name): -+ self._productPartModelName = name -+ -+ @property -+ def productSerialNumber(self): -+ return self._productSerialNumber -+ -+ @productSerialNumber.setter -+ def productSerialNumber(self, name): -+ self._productSerialNumber = name -+ -+ @property -+ def productAssetTag(self): -+ return self._productAssetTag -+ -+ @productAssetTag.setter -+ def productAssetTag(self, name): -+ self._productAssetTag = name -+ -+ @property -+ def fruFileId(self): -+ return self._FRUFileID -+ -+ @fruFileId.setter -+ def fruFileId(self, name): -+ self._FRUFileID = name -+ -+ def fruSetValue(self, field, value): -+ tmp_field = getattr(self, field, None) -+ if tmp_field is not None: -+ setattr(self, field, value) -+ -+ def recalcute(self): -+ d_print("product version:%x" % ord(self.areaversion)) -+ d_print("product length:%d" % self.size) -+ d_print("product language:%x" % self.language) -+ self.data = chr(ord(self.areaversion)) + \ -+ chr(self.size // 8) + chr(self.language) -+ -+ typelength = FruUtil.getTypeLength(self.productManufacturer) -+ self.data += chr(typelength) -+ self.data += self.productManufacturer -+ -+ self.data += chr(FruUtil.getTypeLength(self.productName)) -+ self.data += self.productName -+ -+ self.data += chr(FruUtil.getTypeLength(self.productPartModelName)) -+ self.data += self.productPartModelName -+ -+ self.data += chr(FruUtil.getTypeLength(self.productVersion)) -+ self.data += self.productVersion -+ -+ self.data += chr(FruUtil.getTypeLength(self.productSerialNumber)) -+ self.data += self.productSerialNumber -+ -+ self.data += chr(FruUtil.getTypeLength(self.productAssetTag)) -+ if self.productAssetTag is not None: -+ self.data += self.productAssetTag -+ -+ self.data += chr(FruUtil.getTypeLength(self.fruFileId)) -+ self.data += self.fruFileId -+ -+ for i in range(1, 11): -+ valtmp = "productextra%d" % i -+ if hasattr(self, valtmp): -+ valtmpval = getattr(self, valtmp) -+ d_print("boardInfoArea productextra%d:%s" % (i, valtmpval)) -+ self.data += chr(FruUtil.getTypeLength(valtmpval)) -+ if valtmpval is not None: -+ self.data += valtmpval -+ else: -+ break -+ -+ self.data += chr(0xc1) -+ if len(self.data) > (self.size - 1): -+ incr = (len(self.data) - self.size) // 8 + 1 -+ self.size += incr * 8 -+ d_print("self.data:%d" % len(self.data)) -+ d_print("self.size:%d" % self.size) -+ -+ self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] -+ self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) -+ checksum = FruUtil.checksum(self.data) -+ d_print("board info checksum:%x" % checksum) -+ self.data += chr(checksum) -+ -+ -+class MultiRecordArea(BaseArea): -+ pass -+ -+ -+class Field(object): -+ -+ def __init__(self, fieldType="ASCII", fieldData=""): -+ self.fieldData = fieldData -+ self.fieldType = fieldType -+ -+ @property -+ def fieldType(self): -+ return self.fieldType -+ -+ @property -+ def fieldData(self): -+ return self.fieldData -+ -+ -+class ipmifru(BaseArea): -+ _BoardInfoArea = None -+ _ProductInfoArea = None -+ _InternalUseArea = None -+ _ChassisInfoArea = None -+ _multiRecordArea = None -+ _productinfoAreaOffset = BaseArea.INITVALUE -+ _boardInfoAreaOffset = BaseArea.INITVALUE -+ _internalUserAreaOffset = BaseArea.INITVALUE -+ _chassicInfoAreaOffset = BaseArea.INITVALUE -+ _multiRecordAreaOffset = BaseArea.INITVALUE -+ _bindata = None -+ _bodybin = None -+ _version = BaseArea.COMMON_HEAD_VERSION -+ _zeroCheckSum = None -+ _frusize = 256 -+ -+ def __str__(self): -+ tmpstr = "" -+ if self.boardInfoArea.isPresent: -+ tmpstr += "\nboardinfoarea: \n" -+ tmpstr += self.boardInfoArea.__str__() -+ if self.productInfoArea.isPresent: -+ tmpstr += "\nproductinfoarea: \n" -+ tmpstr += self.productInfoArea.__str__() -+ return tmpstr -+ -+ def decodeBin(self, eeprom): -+ commonHead = eeprom[0:8] -+ d_print("decode version %x" % ord(commonHead[0])) -+ if ord(self.COMMON_HEAD_VERSION) != ord(commonHead[0]): -+ raise FruException("HEAD VERSION error,not Fru format!", -10) -+ if FruUtil.checksum(commonHead[0:7]) != ord(commonHead[7]): -+ strtemp = "check header checksum error [cal:%02x data:%02x]" % ( -+ FruUtil.checksum(commonHead[0:7]), ord(commonHead[7])) -+ raise FruException(strtemp, -3) -+ if ord(commonHead[1]) != ord(self.INITVALUE): -+ d_print("Internal Use Area is present") -+ self.internalUseArea = InternalUseArea( -+ name="Internal Use Area", size=self.SUGGESTED_SIZE_INTERNAL_USE_AREA) -+ self.internalUseArea.isPresent = True -+ self.internalUserAreaOffset = ord(commonHead[1]) -+ self.internalUseArea.data = eeprom[self.internalUserAreaOffset * 8: ( -+ self.internalUserAreaOffset * 8 + self.internalUseArea.size)] -+ if ord(commonHead[2]) != ord(self.INITVALUE): -+ d_print("Chassis Info Area is present") -+ self.chassisInfoArea = ChassisInfoArea( -+ name="Chassis Info Area", size=self.SUGGESTED_SIZE_CHASSIS_INFO_AREA) -+ self.chassisInfoArea.isPresent = True -+ self.chassicInfoAreaOffset = ord(commonHead[2]) -+ self.chassisInfoArea.data = eeprom[self.chassicInfoAreaOffset * 8: ( -+ self.chassicInfoAreaOffset * 8 + self.chassisInfoArea.size)] -+ if ord(commonHead[3]) != ord(self.INITVALUE): -+ self.boardInfoArea = BoardInfoArea( -+ name="Board Info Area", size=self.SUGGESTED_SIZE_BOARD_INFO_AREA) -+ self.boardInfoArea.isPresent = True -+ self.boardInfoAreaOffset = ord(commonHead[3]) -+ self.boardInfoArea.size = ord( -+ eeprom[self.boardInfoAreaOffset * 8 + 1]) * 8 -+ d_print("Board Info Area is present size:%d" % -+ (self.boardInfoArea.size)) -+ self.boardInfoArea.data = eeprom[self.boardInfoAreaOffset * 8: ( -+ self.boardInfoAreaOffset * 8 + self.boardInfoArea.size)] -+ if FruUtil.checksum(self.boardInfoArea.data[:-1]) != ord(self.boardInfoArea.data[-1:]): -+ strtmp = "check boardInfoArea checksum error[cal:%02x data:%02x]" % \ -+ (FruUtil.checksum( -+ self.boardInfoArea.data[:-1]), ord(self.boardInfoArea.data[-1:])) -+ raise FruException(strtmp, -3) -+ self.boardInfoArea.decodedata() -+ if ord(commonHead[4]) != ord(self.INITVALUE): -+ d_print("Product Info Area is present") -+ self.productInfoArea = ProductInfoArea( -+ name="Product Info Area ", size=self.SUGGESTED_SIZE_PRODUCT_INFO_AREA) -+ self.productInfoArea.isPresent = True -+ self.productinfoAreaOffset = ord(commonHead[4]) -+ d_print("length offset value: %02x" % -+ ord(eeprom[self.productinfoAreaOffset * 8 + 1])) -+ self.productInfoArea.size = ord( -+ eeprom[self.productinfoAreaOffset * 8 + 1]) * 8 -+ d_print("Product Info Area is present size:%d" % -+ (self.productInfoArea.size)) -+ -+ self.productInfoArea.data = eeprom[self.productinfoAreaOffset * 8: ( -+ self.productinfoAreaOffset * 8 + self.productInfoArea.size)] -+ if FruUtil.checksum(self.productInfoArea.data[:-1]) != ord(self.productInfoArea.data[-1:]): -+ strtmp = "check productInfoArea checksum error [cal:%02x data:%02x]" % ( -+ FruUtil.checksum(self.productInfoArea.data[:-1]), ord(self.productInfoArea.data[-1:])) -+ raise FruException(strtmp, -3) -+ self.productInfoArea.decodedata() -+ if ord(commonHead[5]) != ord(self.INITVALUE): -+ self.multiRecordArea = MultiRecordArea( -+ name="MultiRecord record Area ") -+ d_print("MultiRecord record present") -+ self.multiRecordArea.isPresent = True -+ self.multiRecordAreaOffset = ord(commonHead[5]) -+ self.multiRecordArea.data = eeprom[self.multiRecordAreaOffset * 8: ( -+ self.multiRecordAreaOffset * 8 + self.multiRecordArea.size)] -+ -+ def initDefault(self): -+ self.version = self.COMMON_HEAD_VERSION -+ self.internalUserAreaOffset = self.INITVALUE -+ self.chassicInfoAreaOffset = self.INITVALUE -+ self.boardInfoAreaOffset = self.INITVALUE -+ self.productinfoAreaOffset = self.INITVALUE -+ self.multiRecordAreaOffset = self.INITVALUE -+ self.zeroCheckSum = self.INITVALUE -+ self.offset = self.SUGGESTED_SIZE_COMMON_HEADER -+ self.productInfoArea = None -+ self.internalUseArea = None -+ self.boardInfoArea = None -+ self.chassisInfoArea = None -+ self.multiRecordArea = None -+ # self.recalcute() -+ -+ @property -+ def version(self): -+ return self._version -+ -+ @version.setter -+ def version(self, name): -+ self._version = name -+ -+ @property -+ def internalUserAreaOffset(self): -+ return self._internalUserAreaOffset -+ -+ @internalUserAreaOffset.setter -+ def internalUserAreaOffset(self, obj): -+ self._internalUserAreaOffset = obj -+ -+ @property -+ def chassicInfoAreaOffset(self): -+ return self._chassicInfoAreaOffset -+ -+ @chassicInfoAreaOffset.setter -+ def chassicInfoAreaOffset(self, obj): -+ self._chassicInfoAreaOffset = obj -+ -+ @property -+ def productinfoAreaOffset(self): -+ return self._productinfoAreaOffset -+ -+ @productinfoAreaOffset.setter -+ def productinfoAreaOffset(self, obj): -+ self._productinfoAreaOffset = obj -+ -+ @property -+ def boardInfoAreaOffset(self): -+ return self._boardInfoAreaOffset -+ -+ @boardInfoAreaOffset.setter -+ def boardInfoAreaOffset(self, obj): -+ self._boardInfoAreaOffset = obj -+ -+ @property -+ def multiRecordAreaOffset(self): -+ return self._multiRecordAreaOffset -+ -+ @multiRecordAreaOffset.setter -+ def multiRecordAreaOffset(self, obj): -+ self._multiRecordAreaOffset = obj -+ -+ @property -+ def zeroCheckSum(self): -+ return self._zeroCheckSum -+ -+ @zeroCheckSum.setter -+ def zeroCheckSum(self, obj): -+ self._zeroCheckSum = obj -+ -+ @property -+ def productInfoArea(self): -+ return self._ProductInfoArea -+ -+ @productInfoArea.setter -+ def productInfoArea(self, obj): -+ self._ProductInfoArea = obj -+ -+ @property -+ def internalUseArea(self): -+ return self._InternalUseArea -+ -+ @internalUseArea.setter -+ def internalUseArea(self, obj): -+ self.internalUseArea = obj -+ -+ @property -+ def boardInfoArea(self): -+ return self._BoardInfoArea -+ -+ @boardInfoArea.setter -+ def boardInfoArea(self, obj): -+ self._BoardInfoArea = obj -+ -+ @property -+ def chassisInfoArea(self): -+ return self._ChassisInfoArea -+ -+ @chassisInfoArea.setter -+ def chassisInfoArea(self, obj): -+ self._ChassisInfoArea = obj -+ -+ @property -+ def multiRecordArea(self): -+ return self._multiRecordArea -+ -+ @multiRecordArea.setter -+ def multiRecordArea(self, obj): -+ self._multiRecordArea = obj -+ -+ @property -+ def bindata(self): -+ return self._bindata -+ -+ @bindata.setter -+ def bindata(self, obj): -+ self._bindata = obj -+ -+ @property -+ def bodybin(self): -+ return self._bodybin -+ -+ @bodybin.setter -+ def bodybin(self, obj): -+ self._bodybin = obj -+ -+ def recalcuteCommonHead(self): -+ self.bindata = "" -+ self.offset = self.SUGGESTED_SIZE_COMMON_HEADER -+ d_print("common Header %d" % self.offset) -+ d_print("fru eeprom size %d" % self._frusize) -+ if self.internalUseArea is not None and self.internalUseArea.isPresent: -+ self.internalUserAreaOffset = self.offset // 8 -+ self.offset += self.internalUseArea.size -+ d_print("internalUseArea is present offset:%d" % self.offset) -+ -+ if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: -+ self.chassicInfoAreaOffset = self.offset // 8 -+ self.offset += self.chassisInfoArea.size -+ d_print("chassisInfoArea is present offset:%d" % self.offset) -+ -+ if self.boardInfoArea is not None and self.boardInfoArea.isPresent: -+ self.boardInfoAreaOffset = self.offset // 8 -+ self.offset += self.boardInfoArea.size -+ d_print("boardInfoArea is present offset:%d" % self.offset) -+ d_print("boardInfoArea is present size:%d" % -+ self.boardInfoArea.size) -+ -+ if self.productInfoArea is not None and self.productInfoArea.isPresent: -+ self.productinfoAreaOffset = self.offset // 8 -+ self.offset += self.productInfoArea.size -+ d_print("productInfoArea is present offset:%d" % self.offset) -+ -+ if self.multiRecordArea is not None and self.multiRecordArea.isPresent: -+ self.multiRecordAreaOffset = self.offset // 8 -+ d_print("multiRecordArea is present offset:%d" % self.offset) -+ -+ if self.internalUserAreaOffset == self.INITVALUE: -+ self.internalUserAreaOffset = 0 -+ if self.productinfoAreaOffset == self.INITVALUE: -+ self.productinfoAreaOffset = 0 -+ if self.chassicInfoAreaOffset == self.INITVALUE: -+ self.chassicInfoAreaOffset = 0 -+ if self.boardInfoAreaOffset == self.INITVALUE: -+ self.boardInfoAreaOffset = 0 -+ if self.multiRecordAreaOffset == self.INITVALUE: -+ self.multiRecordAreaOffset = 0 -+ -+ self.zeroCheckSum = (0x100 - ord(self.version) - self.internalUserAreaOffset - self.chassicInfoAreaOffset - self.productinfoAreaOffset -+ - self.boardInfoAreaOffset - self.multiRecordAreaOffset) & 0xff -+ d_print("zerochecksum:%x" % self.zeroCheckSum) -+ self.data = "" -+ self.data += chr(self.version[0]) + chr(self.internalUserAreaOffset) + chr(self.chassicInfoAreaOffset) + chr( -+ self.boardInfoAreaOffset) + chr(self.productinfoAreaOffset) + chr(self.multiRecordAreaOffset) + chr(self.INITVALUE[0]) + chr(self.zeroCheckSum) -+ -+ self.bindata = self.data + self.bodybin -+ totallen = len(self.bindata) -+ d_print("totallen %d" % totallen) -+ if totallen < self._frusize: -+ self.bindata = self.bindata.ljust(self._frusize, chr(self.INITVALUE[0])) -+ else: -+ raise FruException('bin data more than %d' % self._frusize, -2) -+ -+ def recalcutebin(self): -+ self.bodybin = "" -+ if self.internalUseArea is not None and self.internalUseArea.isPresent: -+ d_print("internalUseArea present") -+ self.bodybin += self.internalUseArea.data -+ if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: -+ d_print("chassisInfoArea present") -+ self.bodybin += self.chassisInfoArea.data -+ if self.boardInfoArea is not None and self.boardInfoArea.isPresent: -+ d_print("boardInfoArea present") -+ self.boardInfoArea.recalcute() -+ self.bodybin += self.boardInfoArea.data -+ if self.productInfoArea is not None and self.productInfoArea.isPresent: -+ d_print("productInfoAreapresent") -+ self.productInfoArea.recalcute() -+ self.bodybin += self.productInfoArea.data -+ if self.multiRecordArea is not None and self.multiRecordArea.isPresent: -+ d_print("multiRecordArea present") -+ self.bodybin += self.productInfoArea.data -+ -+ def recalcute(self, fru_eeprom_size=256): -+ self._frusize = fru_eeprom_size -+ self.recalcutebin() -+ self.recalcuteCommonHead() -+ -+ def setValue(self, area, field, value): -+ tmp_area = getattr(self, area, None) -+ if tmp_area is not None: -+ tmp_area.fruSetValue(field, value) -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/onietlv.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/onietlv.py -new file mode 100644 -index 000000000..a90f8f845 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/onietlv.py -@@ -0,0 +1,441 @@ -+#!/usr/bin/python3 -+import binascii -+ -+ -+class OnietlvException(Exception): -+ def __init__(self, message='onietlverror', code=-100): -+ err = 'errcode: {0} message:{1}'.format(code, message) -+ Exception.__init__(self, err) -+ self.code = code -+ self.message = message -+ -+ -+class onie_tlv(object): -+ TLV_INFO_ID_STRING = "TlvInfo\x00" -+ TLV_INFO_INIA_ID = "\x00\x00\x13\x11" -+ TLV_INFO_VERSION = 0x01 -+ TLV_INFO_LENGTH = 0x00 -+ TLV_INFO_LENGTH_VALUE = 0xba -+ -+ TLV_CODE_PRODUCT_NAME = 0x21 -+ TLV_CODE_PART_NUMBER = 0x22 -+ TLV_CODE_SERIAL_NUMBER = 0x23 -+ TLV_CODE_MAC_BASE = 0x24 -+ TLV_CODE_MANUF_DATE = 0x25 -+ TLV_CODE_DEVICE_VERSION = 0x26 -+ TLV_CODE_LABEL_REVISION = 0x27 -+ TLV_CODE_PLATFORM_NAME = 0x28 -+ TLV_CODE_ONIE_VERSION = 0x29 -+ TLV_CODE_MAC_SIZE = 0x2A -+ TLV_CODE_MANUF_NAME = 0x2B -+ TLV_CODE_MANUF_COUNTRY = 0x2C -+ TLV_CODE_VENDOR_NAME = 0x2D -+ TLV_CODE_DIAG_VERSION = 0x2E -+ TLV_CODE_SERVICE_TAG = 0x2F -+ TLV_CODE_VENDOR_EXT = 0xFD -+ TLV_CODE_CRC_32 = 0xFE -+ _TLV_DISPLAY_VENDOR_EXT = 1 -+ TLV_CODE_WB_CARID = 0x01 -+ _TLV_INFO_HDR_LEN = 11 -+ TLV_CODE_PRODUCT_ID = 0x40 -+ TLV_CODE_HW_VERSION = 0x41 -+ TLV_CODE_MAIN_FILENAME = 0x42 -+ TLV_CODE_DTS_FINENAME = 0x43 -+ TLV_CODE_SY_SERIAL0 = 0x44 -+ TLV_CODE_SY_SERIAL1 = 0x45 -+ TLV_CODE_SY_SERIAL2 = 0x46 -+ TLV_CODE_SY_SERIAL3 = 0x47 -+ TLV_CODE_PROJECT_ID = 0x48 -+ TLV_CODE_SETMAC_VERSION = 0x49 -+ TLV_CODE_EEPROM_TYPE = 0x4A -+ -+ @property -+ def dstatus(self): -+ return self._dstatus -+ -+ @property -+ def cardid(self): -+ return self._cardid -+ -+ @property -+ def productname(self): -+ return self._productname -+ -+ @property -+ def partnum(self): -+ return self._partnum -+ -+ @property -+ def serialnum(self): -+ return self._serialnum -+ -+ @property -+ def macbase(self): -+ return self._macbase -+ -+ @property -+ def manufdate(self): -+ return self._manufdate -+ -+ @property -+ def deviceversion(self): -+ return self._deviceversion -+ -+ @property -+ def labelrevision(self): -+ return self._labelrevision -+ -+ @property -+ def platformname(self): -+ return self._platformname -+ -+ @property -+ def onieversion(self): -+ return self._onieversion -+ -+ @property -+ def macsize(self): -+ return self._macsize -+ -+ @property -+ def manufname(self): -+ return self._manufname -+ -+ @property -+ def manufcountry(self): -+ return self._manufcountry -+ -+ @property -+ def vendorname(self): -+ return self._vendorname -+ -+ @property -+ def diagname(self): -+ return self._diagname -+ -+ @property -+ def servicetag(self): -+ return self._servicetag -+ -+ @property -+ def vendorext(self): -+ return self._vendorext -+ -+ def __init__(self): -+ self._cardid = "" -+ self._productname = "" -+ self._partnum = "" -+ self._serialnum = "" -+ self._macbase = "" -+ self._manufdate = "" -+ self._deviceversion = "" -+ self._labelrevision = "" -+ self._platformname = "" -+ self._onieversion = "" -+ self._macsize = "" -+ self._manufname = "" -+ self._manufcountry = "" -+ self._vendorname = "" -+ self._diagname = "" -+ self._servicetag = "" -+ self._vendorext = "" -+ self._productid = "" -+ self._hwversion = "" -+ self._mainfilename = "" -+ self._dtsfilename = "" -+ self._syserial0 = "" -+ self._syserial1 = "" -+ self._syserial2 = "" -+ self._syserial3 = "" -+ self._projectid = "" -+ self._setmacversion = "" -+ self._eepromtype = "" -+ self._crc32 = "" -+ self._dstatus = 0 -+ -+ def oniecrc32(self, v): -+ data_array = bytearray() -+ for x in v: -+ data_array.append(ord(x)) -+ return '0x%08x' % (binascii.crc32(bytes(data_array)) & 0xffffffff) -+ -+ def getTLV_BODY(self, tlv_type, value): -+ x = [] -+ temp_t = "" -+ if tlv_type == self.TLV_CODE_MAC_BASE: -+ arr = value.split(':') -+ for tt in arr: -+ temp_t += chr(int(tt, 16)) -+ elif tlv_type == self.TLV_CODE_DEVICE_VERSION: -+ temp_t = chr(value) -+ elif tlv_type == self.TLV_CODE_MAC_SIZE: -+ temp_t = chr(value >> 8) + chr(value & 0x00ff) -+ else: -+ temp_t = value -+ x.append(chr(tlv_type)) -+ x.append(chr(len(temp_t))) -+ for i in temp_t: -+ x.append(i) -+ return x -+ -+ def generate_ext(self, cardid): -+ s = "%08x" % cardid -+ ret = "" -+ for t in range(0, 4): -+ ret += chr(int(s[2 * t:2 * t + 2], 16)) -+ ret = chr(0x01) + chr(len(ret)) + ret -+ return ret -+ -+ def generate_value(self, _t): -+ ret = [] -+ for i in self.TLV_INFO_ID_STRING: -+ ret.append(i) -+ ret.append(chr(self.TLV_INFO_VERSION)) -+ ret.append(chr(self.TLV_INFO_LENGTH)) -+ ret.append(chr(self.TLV_INFO_LENGTH_VALUE)) -+ -+ total_len = 0 -+ for key in _t: -+ x = self.getTLV_BODY(key, _t[key]) -+ ret += x -+ total_len += len(x) -+ ret[10] = chr(total_len + 6) -+ -+ ret.append(chr(0xFE)) -+ ret.append(chr(0x04)) -+ s = self.oniecrc32(''.join(ret)) -+ for t in range(0, 4): -+ ret.append(chr(int(s[2 * t + 2:2 * t + 4], 16))) -+ totallen = len(ret) -+ if totallen < 256: -+ for left_t in range(0, 256 - totallen): -+ ret.append(chr(0x00)) -+ return (ret, True) -+ -+ def decode_tlv(self, e): -+ tlv_index = 0 -+ tlv_end = len(e) -+ ret = [] -+ while tlv_index < tlv_end and (tlv_index + 2 + ord(e[tlv_index + 1])) <= len(e): -+ rt = self.decoder(e[tlv_index:tlv_index + 2 + ord(e[tlv_index + 1])]) -+ ret.append(rt) -+ if ord(e[tlv_index]) == self.TLV_CODE_CRC_32: -+ break -+ tlv_index += ord(e[tlv_index + 1]) + 2 -+ return ret -+ -+ def decode(self, e): -+ if e[0:8] != self.TLV_INFO_ID_STRING: -+ raise OnietlvException("ONIE tlv head info error,not onie tlv type", -1) -+ total_len = (ord(e[9]) << 8) | ord(e[10]) -+ tlv_index = self._TLV_INFO_HDR_LEN -+ tlv_end = self._TLV_INFO_HDR_LEN + total_len -+ if tlv_end > len(e): -+ raise OnietlvException("ONIE tlv length error", -2) -+ ret = [] -+ ret = self.decode_tlv(e[tlv_index:tlv_end]) -+ for item in ret: -+ if item['code'] == self.TLV_CODE_VENDOR_EXT: -+ if item["value"][0:4] == self.TLV_INFO_INIA_ID: -+ rt = self.decode_tlv(item["value"][4:]) -+ else: -+ rt = self.decode_tlv(item["value"][0:]) -+ ret.extend(rt) -+ return ret -+ -+ def decoder(self, t): -+ if ord(t[0]) == self.TLV_CODE_PRODUCT_NAME: -+ name = "Product Name" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._productname = value -+ elif ord(t[0]) == self.TLV_CODE_PART_NUMBER: -+ name = "Part Number" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._partnum = value -+ elif ord(t[0]) == self.TLV_CODE_SERIAL_NUMBER: -+ name = "Serial Number" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._serialnum = value -+ elif ord(t[0]) == self.TLV_CODE_MAC_BASE: -+ name = "Base MAC Address" -+ _len = ord(t[1]) -+ value = ":".join(['%02X' % ord(T) for T in t[2:8]]).upper() -+ self._macbase = value -+ elif ord(t[0]) == self.TLV_CODE_MANUF_DATE: -+ name = "Manufacture Date" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._manufdate = value -+ elif ord(t[0]) == self.TLV_CODE_DEVICE_VERSION: -+ name = "Device Version" -+ _len = ord(t[1]) -+ value = ord(t[2]) -+ self._deviceversion = value -+ elif ord(t[0]) == self.TLV_CODE_LABEL_REVISION: -+ name = "Label Revision" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._labelrevision = value -+ elif ord(t[0]) == self.TLV_CODE_PLATFORM_NAME: -+ name = "Platform Name" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._platformname = value -+ elif ord(t[0]) == self.TLV_CODE_ONIE_VERSION: -+ name = "ONIE Version" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._onieversion = value -+ elif ord(t[0]) == self.TLV_CODE_MAC_SIZE: -+ name = "MAC Addresses" -+ _len = ord(t[1]) -+ value = str((ord(t[2]) << 8) | ord(t[3])) -+ self._macsize = value -+ elif ord(t[0]) == self.TLV_CODE_MANUF_NAME: -+ name = "Manufacturer" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._manufname = value -+ elif ord(t[0]) == self.TLV_CODE_MANUF_COUNTRY: -+ name = "Manufacture Country" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._manufcountry = value -+ elif ord(t[0]) == self.TLV_CODE_VENDOR_NAME: -+ name = "Vendor Name" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._vendorname = value -+ elif ord(t[0]) == self.TLV_CODE_DIAG_VERSION: -+ name = "Diag Version" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._diagname = value -+ elif ord(t[0]) == self.TLV_CODE_SERVICE_TAG: -+ name = "Service Tag" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._servicetag = value -+ elif ord(t[0]) == self.TLV_CODE_VENDOR_EXT: -+ name = "Vendor Extension" -+ _len = ord(t[1]) -+ value = "" -+ if self._TLV_DISPLAY_VENDOR_EXT: -+ value = t[2:2 + ord(t[1])] -+ self._vendorext = value -+ elif ord(t[0]) == self.TLV_CODE_CRC_32 and len(t) == 6: -+ name = "CRC-32" -+ _len = ord(t[1]) -+ value = "0x%08X" % (((ord(t[2]) << 24) | ( -+ ord(t[3]) << 16) | (ord(t[4]) << 8) | ord(t[5])),) -+ self._crc32 = value -+ elif ord(t[0]) == self.TLV_CODE_WB_CARID: -+ name = "Card id" -+ _len = ord(t[1]) -+ value = "" -+ for c in t[2:2 + ord(t[1])]: -+ value += "%02X" % (ord(c),) -+ self._cardid = value -+ elif ord(t[0]) == self.TLV_CODE_PRODUCT_ID: -+ name = "Product id" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._productid = value -+ elif ord(t[0]) == self.TLV_CODE_HW_VERSION: -+ name = "Hardware Version" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._hwversion = value -+ elif ord(t[0]) == self.TLV_CODE_MAIN_FILENAME: -+ name = "Main File Name" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._mainfilename = value -+ elif ord(t[0]) == self.TLV_CODE_DTS_FINENAME: -+ name = "DTS File Name" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._dtsfilename = value -+ elif ord(t[0]) == self.TLV_CODE_SY_SERIAL0: -+ name = "SY Serial 0" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._syserial0 = value -+ elif ord(t[0]) == self.TLV_CODE_SY_SERIAL1: -+ name = "SY Serial 1" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._syserial1 = value -+ elif ord(t[0]) == self.TLV_CODE_SY_SERIAL2: -+ name = "SY Serial 2" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._syserial2 = value -+ elif ord(t[0]) == self.TLV_CODE_SY_SERIAL3: -+ name = "SY Serial 3" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._syserial3 = value -+ elif ord(t[0]) == self.TLV_CODE_PROJECT_ID: -+ name = "Project id" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._projectid = value -+ elif ord(t[0]) == self.TLV_CODE_SETMAC_VERSION: -+ name = "Setmac Version" -+ _len = ord(t[1]) -+ value = t[2:2 + ord(t[1])] -+ self._setmacversion = value -+ elif ord(t[0]) == self.TLV_CODE_EEPROM_TYPE: -+ name = "EEPROM Type" -+ _len = ord(t[1]) -+ value = "" -+ for c in t[2:2 + ord(t[1])]: -+ value += "%02X" % (ord(c),) -+ self._eepromtype = value -+ else: -+ name = "Unknown" -+ _len = ord(t[1]) -+ value = "" -+ for c in t[2:2 + ord(t[1])]: -+ value += "0x%02X " % (ord(c),) -+ return {"name": name, "code": ord(t[0]), "value": value, "lens": _len} -+ -+ def __str__(self): -+ formatstr = "Card id : %s \n" \ -+ "Product Name : %s \n" \ -+ "Part Number : %s \n" \ -+ "Serial Number : %s \n" \ -+ "Base MAC Address : %s \n" \ -+ "Manufacture Date : %s \n" \ -+ "Device Version : %s \n" \ -+ "Label Revision : %s \n" \ -+ "Platform Name : %s \n" \ -+ "ONIE Version : %s \n" \ -+ "MAC Addresses : %s \n" \ -+ "Manufacturer : %s \n" \ -+ "Manufacture Country : %s \n" \ -+ "Vendor Name : %s \n" \ -+ "Diag Version : %s \n" \ -+ "Service Tag : %s \n" \ -+ "CRC-32 : %s \n" -+ return formatstr % (self._cardid, -+ self._productname, -+ self._partnum, -+ self._serialnum, -+ self._macbase, -+ self._manufdate, -+ self._deviceversion, -+ self._labelrevision, -+ self._platformname, -+ self._onieversion, -+ self._macsize, -+ self._manufname, -+ self._manufcountry, -+ self._vendorname, -+ self._diagname, -+ self._servicetag, -+ self._crc32) -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/__init__.py -new file mode 100644 -index 000000000..e69de29bb -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/baseutil.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/baseutil.py -new file mode 100644 -index 000000000..5260107c9 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/baseutil.py -@@ -0,0 +1,164 @@ -+#!/usr/bin/env python3 -+####################################################### -+# -+# baseutil.py -+# Python implementation of the Class baseutil -+# -+####################################################### -+import importlib.machinery -+import os -+import syslog -+import json -+from plat_hal.osutil import osutil -+ -+SYSLOG_IDENTIFIER = "HAL" -+ -+CONFIG_DB_PATH = "/etc/sonic/config_db.json" -+BOARD_ID_PATH = "/sys/module/platform_common/parameters/dfd_my_type" -+BOARD_AIRFLOW_PATH = "/etc/sonic/.airflow" -+ -+ -+def getonieplatform(path): -+ if not os.path.isfile(path): -+ return "" -+ machine_vars = {} -+ with open(path) as machine_file: -+ for line in machine_file: -+ tokens = line.split('=') -+ if len(tokens) < 2: -+ continue -+ machine_vars[tokens[0]] = tokens[1].strip() -+ return machine_vars.get("onie_platform") -+ -+ -+def getboardid(): -+ if not os.path.exists(BOARD_ID_PATH): -+ return "NA" -+ with open(BOARD_ID_PATH) as fd: -+ id_str = fd.read().strip() -+ return "0x%x" % (int(id_str, 10)) -+ -+ -+def getboardairflow(): -+ if not os.path.exists(BOARD_AIRFLOW_PATH): -+ return "NA" -+ with open(BOARD_AIRFLOW_PATH) as fd: -+ airflow_str = fd.read().strip() -+ data = json.loads(airflow_str) -+ airflow = data.get("board", "NA") -+ return airflow -+ -+ -+def getplatform_config_db(): -+ if not os.path.isfile(CONFIG_DB_PATH): -+ return "" -+ val = os.popen("sonic-cfggen -j %s -v DEVICE_METADATA.localhost.platform" % CONFIG_DB_PATH).read().strip() -+ if len(val) <= 0: -+ return "" -+ return val -+ -+ -+def getplatform_name(): -+ if os.path.isfile('/host/machine.conf'): -+ return getonieplatform('/host/machine.conf') -+ if os.path.isfile('/etc/sonic/machine.conf'): -+ return getonieplatform('/etc/sonic/machine.conf') -+ return getplatform_config_db() -+ -+ -+platform = (getplatform_name()).replace("-", "_") -+boardid = getboardid() -+boardairflow = getboardairflow() -+ -+ -+CONFIG_FILE_PATH_LIST = [ -+ "/usr/local/bin/", -+ "/usr/lib/python3/dist-packages/", -+ "/usr/local/lib/python3.7/dist-packages/hal-config/", -+ "/usr/local/lib/python3.9/dist-packages/hal-config/" -+] -+ -+ -+DEVICE_CONFIG_FILE_LIST = [ -+ platform + "_" + boardid + "_" + boardairflow + "_device.py", -+ platform + "_" + boardid + "_device.py", -+ platform + "_" + boardairflow + "_device.py", -+ platform + "_device.py" -+] -+ -+ -+MONITOR_CONFIG_FILE_LIST = [ -+ platform + "_" + boardid + "_" + boardairflow + "_monitor.py", -+ platform + "_" + boardid + "_monitor.py", -+ platform + "_" + boardairflow + "_monitor.py", -+ platform + "_monitor.py" -+] -+ -+ -+class baseutil: -+ -+ CONFIG_NAME = 'devices' -+ MONITOR_CONFIG_NAME = 'monitor' -+ UBOOT_ENV_URL = '/etc/device/uboot_env' -+ -+ @staticmethod -+ def get_config(): -+ real_path = None -+ for configfile_path in CONFIG_FILE_PATH_LIST: -+ for config_file in DEVICE_CONFIG_FILE_LIST: -+ file = configfile_path + config_file -+ if os.path.exists(file): -+ real_path = file -+ break -+ if real_path is not None: -+ break -+ -+ if real_path is None: -+ raise Exception("get hal device config error") -+ devices = importlib.machinery.SourceFileLoader(baseutil.CONFIG_NAME, real_path).load_module() -+ return devices.devices -+ -+ @staticmethod -+ def get_monitor_config(): -+ real_path = None -+ for configfile_path in CONFIG_FILE_PATH_LIST: -+ for config_file in MONITOR_CONFIG_FILE_LIST: -+ file = configfile_path + config_file -+ if os.path.exists(file): -+ real_path = file -+ break -+ if real_path is not None: -+ break -+ -+ if real_path is None: -+ raise Exception("get hal monitor config error") -+ monitor = importlib.machinery.SourceFileLoader(baseutil.MONITOR_CONFIG_NAME, real_path).load_module() -+ return monitor.monitor -+ -+ @staticmethod -+ def get_productname(): -+ ret, val = osutil.command("cat %s |grep productname | awk -F\"=\" '{print $2;}'" % baseutil.UBOOT_ENV_URL) -+ tmp = val.lower().replace('-', '_') -+ if ret != 0 or len(val) <= 0: -+ raise Exception("get productname error") -+ return tmp -+ -+ @staticmethod -+ def get_platform(): -+ ret, val = osutil.command("cat %s |grep conffitname | awk -F\"=\" '{print $2;}'" % baseutil.UBOOT_ENV_URL) -+ if ret != 0 or len(val) <= 0: -+ raise Exception("get platform error") -+ return val -+ -+ @staticmethod -+ def get_product_fullname(): -+ ret, val = osutil.command("cat %s |grep productname | awk -F\"=\" '{print $2;}'" % baseutil.UBOOT_ENV_URL) -+ if ret != 0 or len(val) <= 0: -+ raise Exception("get productname error") -+ return val -+ -+ @staticmethod -+ def logger_debug(msg): -+ syslog.openlog(SYSLOG_IDENTIFIER) -+ syslog.syslog(syslog.LOG_DEBUG, msg) -+ syslog.closelog() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/chassisbase.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/chassisbase.py -new file mode 100644 -index 000000000..767d6da34 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/chassisbase.py -@@ -0,0 +1,318 @@ -+#!/usr/bin/env python3 -+####################################################### -+# -+# chassisbase.py -+# Python implementation of the Class chassisbase -+# -+####################################################### -+from plat_hal.dcdc import dcdc -+from plat_hal.onie_e2 import onie_e2 -+from plat_hal.psu import psu -+from plat_hal.led import led -+from plat_hal.temp import temp -+from plat_hal.fan import fan -+from plat_hal.cpld import cpld -+from plat_hal.component import component -+from plat_hal.cpu import cpu -+from plat_hal.baseutil import baseutil -+ -+ -+class chassisbase(object): -+ __onie_e2_list = [] -+ __psu_list = [] -+ __led_list = [] -+ __temp_list = [] -+ __fan_list = [] -+ __card_list = [] -+ __sensor_list = [] -+ __dcdc_list = [] -+ __cpld_list = [] -+ __comp_list = [] -+ __bios_list = [] -+ __bmc_list = [] -+ __cpu = None -+ -+ def __init__(self, conftype=0, conf=None): -+ # type: (object, object, object) -> object -+ """ -+ init chassisbase as order -+ -+ type = 0 use default conf, maybe auto find by platform -+ type = 1 use given conf, conf is not None -+ -+ BITMAP -+ bit 16 -+ bit 0 PSU -+ bit 1 LED -+ bit 2 TEMP -+ bit 3 fan -+ bit 4 card -+ bit 5 sensor -+ """ -+ __confTemp = None -+ -+ if conftype == 0: -+ # user -+ __confTemp = baseutil.get_config() -+ elif conftype == 1: -+ __confTemp = conf -+ -+ # onie_e2 -+ onie_e2temp = [] -+ onie_e2config = __confTemp.get('onie_e2', []) -+ for item in onie_e2config: -+ onie_e2_1 = onie_e2(item) -+ onie_e2temp.append(onie_e2_1) -+ self.onie_e2_list = onie_e2temp -+ -+ # psu -+ psutemp = [] -+ psuconfig = __confTemp.get('psus', []) -+ for item in psuconfig: -+ psu1 = psu(item) -+ psutemp.append(psu1) -+ self.psu_list = psutemp -+ -+ # led -+ ledtemp = [] -+ ledconfig = __confTemp.get('leds', []) -+ for item in ledconfig: -+ led1 = led(item) -+ ledtemp.append(led1) -+ self.led_list = ledtemp -+ -+ # temp -+ temptemp = [] -+ tempconfig = __confTemp.get('temps', []) -+ for item in tempconfig: -+ temp1 = temp(item) -+ temptemp.append(temp1) -+ self.temp_list = temptemp -+ -+ # fan -+ fantemp = [] -+ fanconfig = __confTemp.get('fans', []) -+ for item in fanconfig: -+ fan1 = fan(item) -+ fantemp.append(fan1) -+ self.fan_list = fantemp -+ -+ # dcdc -+ dcdctemp = [] -+ dcdcconfig = __confTemp.get('dcdc', []) -+ for item in dcdcconfig: -+ dcdc1 = dcdc(item) -+ dcdctemp.append(dcdc1) -+ self.dcdc_list = dcdctemp -+ -+ # cpld -+ cpldtemp = [] -+ cpldconfig = __confTemp.get('cplds', []) -+ for item in cpldconfig: -+ cpld1 = cpld(item) -+ cpldtemp.append(cpld1) -+ self.cpld_list = cpldtemp -+ -+ # compoment: cpld/fpga/bios -+ comptemp = [] -+ compconfig = __confTemp.get('comp_cpld', []) -+ for item in compconfig: -+ comp1 = component(item) -+ comptemp.append(comp1) -+ self.comp_list = comptemp -+ -+ compconfig = __confTemp.get('comp_fpga', []) -+ for item in compconfig: -+ comp1 = component(item) -+ self.comp_list.append(comp1) -+ -+ compconfig = __confTemp.get('comp_bios', []) -+ for item in compconfig: -+ comp1 = component(item) -+ self.comp_list.append(comp1) -+ -+ # cpu -+ cpuconfig = __confTemp.get('cpu', []) -+ if len(cpuconfig): -+ self.cpu = cpu(cpuconfig[0]) -+ -+ # dcdc -+ @property -+ def dcdc_list(self): -+ return self.__dcdc_list -+ -+ @dcdc_list.setter -+ def dcdc_list(self, val): -+ self.__dcdc_list = val -+ -+ # sensor -+ @property -+ def sensor_list(self): -+ return self.__sensor_list -+ -+ @sensor_list.setter -+ def sensor_list(self, val): -+ self.__sensor_list = val -+ -+ def get_sensor_byname(self, name): -+ tmp = self.sensor_list -+ for item in tmp: -+ if name == item.name: -+ return item -+ return None -+ -+ # onie_e2 -+ @property -+ def onie_e2_list(self): -+ return self.__onie_e2_list -+ -+ @onie_e2_list.setter -+ def onie_e2_list(self, val): -+ self.__onie_e2_list = val -+ -+ def get_onie_e2_byname(self, name): -+ tmp = self.onie_e2_list -+ for item in tmp: -+ if name == item.name: -+ return item -+ return None -+ -+ # psu -+ @property -+ def psu_list(self): -+ return self.__psu_list -+ -+ @psu_list.setter -+ def psu_list(self, val): -+ self.__psu_list = val -+ -+ def get_psu_byname(self, name): -+ tmp = self.psu_list -+ for item in tmp: -+ if name == item.name: -+ return item -+ return None -+ -+ # fan -+ @property -+ def fan_list(self): -+ return self.__fan_list -+ -+ @fan_list.setter -+ def fan_list(self, val): -+ self.__fan_list = val -+ -+ def get_fan_byname(self, name): -+ tmp = self.fan_list -+ for item in tmp: -+ if name == item.name: -+ return item -+ return None -+ -+ # led -+ -+ @property -+ def led_list(self): -+ return self.__led_list -+ -+ @led_list.setter -+ def led_list(self, val): -+ self.__led_list = val -+ -+ def get_led_byname(self, name): -+ tmp = self.led_list -+ for item in tmp: -+ if name == item.name: -+ return item -+ return None -+ -+ # temp -+ @property -+ def temp_list(self): -+ return self.__temp_list -+ -+ @temp_list.setter -+ def temp_list(self, val): -+ self.__temp_list = val -+ -+ def get_temp_byname(self, name): -+ tmp = self.temp_list -+ for item in tmp: -+ if name == item.name: -+ return item -+ return None -+ -+ # cpld -+ @property -+ def cpld_list(self): -+ return self.__cpld_list -+ -+ @cpld_list.setter -+ def cpld_list(self, val): -+ self.__cpld_list = val -+ -+ def get_cpld_byname(self, name): -+ tmp = self.cpld_list -+ for item in tmp: -+ if name == item.name: -+ return item -+ return None -+ -+ @property -+ def comp_list(self): -+ return self.__comp_list -+ -+ @comp_list.setter -+ def comp_list(self, val): -+ self.__comp_list = val -+ -+ def get_comp_byname(self, name): -+ tmp = self.comp_list -+ for item in tmp: -+ if name == item.name: -+ return item -+ return None -+ -+ # bios -+ @property -+ def bios_list(self): -+ return self.__bios_list -+ -+ @bios_list.setter -+ def bios_list(self, val): -+ self.__bios_list = val -+ -+ def get_bios_byname(self, name): -+ tmp = self.bios_list -+ for item in tmp: -+ if name == item.name: -+ return item -+ return None -+ -+ # bmc -+ @property -+ def bmc_list(self): -+ return self.__bmc_list -+ -+ @bmc_list.setter -+ def bmc_list(self, val): -+ self.__bmc_list = val -+ -+ def get_bmc_byname(self, name): -+ tmp = self.bmc_list -+ for item in tmp: -+ if name == item.name: -+ return item -+ return None -+ -+ # cpu -+ @property -+ def cpu(self): -+ return self.__cpu -+ -+ @cpu.setter -+ def cpu(self, val): -+ self.__cpu = val -+ -+ def get_cpu_byname(self, name): -+ return self.cpu -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/component.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/component.py -new file mode 100644 -index 000000000..0f2ad2167 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/component.py -@@ -0,0 +1,33 @@ -+#!/usr/bin/env python3 -+####################################################### -+# -+# component.py -+# Python implementation of the Class fan -+# -+####################################################### -+from plat_hal.devicebase import devicebase -+from plat_hal.osutil import osutil -+ -+ -+class component(devicebase): -+ __user_reg = None -+ -+ def __init__(self, conf=None): -+ if conf is not None: -+ self.name = conf.get('name', None) -+ self.version_file = conf.get('VersionFile', None) -+ self.comp_id = conf.get("comp_id", None) -+ self.desc = conf.get("desc", None) -+ self.slot = conf.get("slot", None) -+ -+ def get_version(self): -+ version = "NA" -+ try: -+ ret, version = self.get_value(self.version_file) -+ if ret is False: -+ return version -+ pattern = self.version_file.get('pattern', None) -+ version = osutil.std_match(version, pattern) -+ except Exception: -+ return version -+ return version -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpld.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpld.py -new file mode 100644 -index 000000000..09eed5f97 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpld.py -@@ -0,0 +1,66 @@ -+#!/usr/bin/env python3 -+####################################################### -+# -+# fan.py -+# Python implementation of the Class fan -+# -+####################################################### -+from plat_hal.devicebase import devicebase -+ -+ -+class cpld(devicebase): -+ __user_reg = None -+ -+ def __init__(self, conf=None): -+ if conf is not None: -+ self.name = conf.get('name', None) -+ self.user_reg = conf.get('UserReg', None) -+ self.console_reg = conf.get('ConsoleReg', None) -+ self.console_reg_attrs = conf.get('ConsoleRegAttrs', None) -+ self.version_file = conf.get('VersionFile', None) -+ self.cpld_id = conf.get("cpld_id", None) -+ self.desc = conf.get("desc", None) -+ self.slot = conf.get("slot", None) -+ self.format = conf.get("format", "big_endian") -+ self.warm = conf.get("warm", None) -+ self.type = conf.get("type", None) -+ -+ def get_user_reg(self): -+ if self.user_reg is None: -+ return False -+ ret, val = self.get_value(self.user_reg) -+ return val -+ -+ def set_user_reg(self, value): -+ if self.user_reg is None: -+ return False -+ byte = value & 0xFF -+ ret, val = self.set_value(self.user_reg, byte) -+ return ret -+ -+ def set_console_owner(self, owner): -+ ret = False -+ -+ if self.console_reg is None: -+ return False -+ tmpattr = self.console_reg_attrs.get(owner, None) -+ if tmpattr is not None: -+ ret, val = self.set_value(self.console_reg, tmpattr) -+ return ret -+ -+ def get_version(self): -+ ret, val = self.get_value(self.version_file) -+ if ret is False: -+ val = "N/A" -+ return val -+ if self.type == "str": -+ return val.strip('\n') -+ val = val.strip('\n').split(" ") -+ if len(val) < 4: -+ val = "N/A" -+ return val -+ if self.format == "little_endian": -+ cpld_version = "%s%s%s%s" % (val[3], val[2], val[1], val[0]) -+ else: -+ cpld_version = "%s%s%s%s" % (val[0], val[1], val[2], val[3]) -+ return cpld_version -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpu.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpu.py -new file mode 100644 -index 000000000..c6bec1abd ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpu.py -@@ -0,0 +1,48 @@ -+#!/usr/bin/env python3 -+############################################################################### -+# -+# Hardware Abstraction Layer APIs -- CPU APIs. -+# -+############################################################################### -+from plat_hal.devicebase import devicebase -+ -+ -+class cpu(devicebase): -+ -+ def __init__(self, conf=None): -+ if conf is not None: -+ self.name = conf.get('name', None) -+ self.cpu_reset_cnt_reg = conf.get('CpuResetCntReg', None) -+ self.reboot_cause_path = conf.get('reboot_cause_path', "/etc/sonic/.reboot/.previous-reboot-cause.txt") -+ -+ def get_cpu_reset_num(self): -+ """ -+ get cpu reset num. -+ @return cpu reset number, -1 for failure -+ """ -+ ret = -1 -+ if self.cpu_reset_cnt_reg is None: -+ self.logger_debug("ERR: no support get cpu reset num") -+ return ret -+ ret, reset_num = self.get_value(self.cpu_reset_cnt_reg) -+ if ret is False or reset_num is None: -+ self.logger_debug("ERR: i2c read cpu_reset_cnt_reg,result:%s" % reset_num) -+ else: -+ if isinstance(reset_num, str): -+ ret = int(reset_num, 16) -+ else: -+ ret = reset_num -+ return ret -+ -+ def get_cpu_reboot_cause(self): -+ """ -+ get_cpu_reboot_cause -+ @return cpu reset number, -1 for failure -+ """ -+ try: -+ with open(self.reboot_cause_path) as fd: -+ reboot_cause = fd.read().strip() -+ return reboot_cause -+ except Exception: -+ return "Unknown reboot cause" -+ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/dcdc.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/dcdc.py -new file mode 100644 -index 000000000..ba6049950 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/dcdc.py -@@ -0,0 +1,11 @@ -+#!/usr/bin/env python3 -+from plat_hal.devicebase import devicebase -+from plat_hal.sensor import sensor -+ -+ -+class dcdc(devicebase): -+ def __init__(self, conf=None): -+ if conf is not None: -+ self.name = conf.get('name', None) -+ self.dcdc_id = conf.get("dcdc_id", None) -+ self.sensor = sensor(conf) -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/devicebase.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/devicebase.py -new file mode 100644 -index 000000000..001b4ee23 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/devicebase.py -@@ -0,0 +1,351 @@ -+#!/usr/bin/env python3 -+####################################################### -+# -+# devicebase.py -+# Python implementation of the Class devicebase -+# -+####################################################### -+import subprocess -+import shlex -+import ast -+from plat_hal.osutil import osutil -+from plat_hal.baseutil import baseutil -+ -+class CodeVisitor(ast.NodeVisitor): -+ -+ def __init__(self): -+ self.value = None -+ -+ def get_value(self): -+ return self.value -+ -+ def get_op_value(self, node): -+ if isinstance(node, ast.Call): # node is func call -+ value = self.visit_Call(node) -+ elif isinstance(node, ast.BinOp): # node is BinOp -+ value = self.visit_BinOp(node) -+ elif isinstance(node, ast.UnaryOp): # node is UnaryOp -+ value = self.visit_UnaryOp(node) -+ elif isinstance(node, ast.Num): # node is Num Constant -+ value = node.n -+ elif isinstance(node, ast.Str): # node is Str Constant -+ value = node.s -+ else: -+ raise NotImplementedError("Unsupport operand type: %s" % type(node)) -+ return value -+ -+ def visit_UnaryOp(self, node): -+ ''' -+ node.op: operand type, only support ast.UAdd/ast.USub -+ node.operand: only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.UnaryOp -+ ''' -+ -+ operand_value = self.get_op_value(node.operand) -+ if isinstance(node.op, ast.UAdd): -+ self.value = operand_value -+ elif isinstance(node.op, ast.USub): -+ self.value = 0 - operand_value -+ else: -+ raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) -+ return self.value -+ -+ def visit_BinOp(self, node): -+ ''' -+ node.left: left operand, only support ast.Call/ast.Constant(ast.Num)/ast.BinOp -+ node.op: operand type, only support ast.Add/ast.Sub/ast.Mult/ast.Div -+ node.right: right operan, only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp -+ ''' -+ left_value = self.get_op_value(node.left) -+ right_value = self.get_op_value(node.right) -+ -+ if isinstance(node.op, ast.Add): -+ self.value = left_value + right_value -+ elif isinstance(node.op, ast.Sub): -+ self.value = left_value - right_value -+ elif isinstance(node.op, ast.Mult): -+ self.value = left_value * right_value -+ elif isinstance(node.op, ast.Div): -+ self.value = left_value / right_value -+ else: -+ raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) -+ return self.value -+ -+ def visit_Call(self, node): -+ ''' -+ node.func.id: func name, only support 'float', 'int', 'str' -+ node.args: func args list,only support ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.Call -+ str/float only support one parameter, eg: float(XXX), str(xxx) -+ int support one or two parameters, eg: int(xxx) or int(xxx, 16) -+ xxx can be ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp -+ ''' -+ calc_tuple = ("float", "int", "str") -+ -+ if node.func.id not in calc_tuple: -+ raise NotImplementedError("Unsupport function call type: %s" % node.func.id) -+ -+ args_val_list = [] -+ for item in node.args: -+ ret = self.get_op_value(item) -+ args_val_list.append(ret) -+ -+ if node.func.id == "str": -+ if len(args_val_list) != 1: -+ raise TypeError("str() takes 1 positional argument but %s were given" % len(args_val_list)) -+ value = str(args_val_list[0]) -+ self.value = value -+ return value -+ -+ if node.func.id == "float": -+ if len(args_val_list) != 1: -+ raise TypeError("float() takes 1 positional argument but %s were given" % len(args_val_list)) -+ value = float(args_val_list[0]) -+ self.value = value -+ return value -+ # int -+ if len(args_val_list) == 1: -+ value = int(args_val_list[0]) -+ self.value = value -+ return value -+ if len(args_val_list) == 2: -+ value = int(args_val_list[0], args_val_list[1]) -+ self.value = value -+ return value -+ raise TypeError("int() takes 1 or 2 arguments (%s given)" % len(args_val_list)) -+ -+ -+class devicebase(object): -+ _name = None -+ __error_ret = -99999 -+ -+ @property -+ def name(self): -+ return self._name -+ -+ @name.setter -+ def name(self, val): -+ self._name = val -+ -+ def dumpValueByI2c(self, bus, loc): -+ value = "" -+ for i in range(256): -+ ret, val = self.get_i2c(bus, loc, i) -+ value += chr(val) -+ return value -+ -+ def byteTostr(self, val): -+ strtmp = '' -+ for value in val: -+ strtmp += chr(value) -+ return strtmp -+ -+ def get_eeprom_info(self, conf): -+ eeprom = "" -+ if conf.get('way') == 'sysfs': -+ ret, eeprom = self.get_value(conf) -+ if ret is False: -+ return None -+ elif conf.get('way') == 'devfile': -+ ret, eeprom_list = self.get_value(conf) -+ if ret is False: -+ return None -+ for item in eeprom_list: -+ eeprom += chr(item) -+ else: -+ eeprom = self.dumpValueByI2c(conf.get('bus'), conf.get('addr')) -+ return eeprom -+ -+ def exec_os_cmd(self, cmd): -+ status, output = subprocess.getstatusoutput(cmd) -+ return status, output -+ -+ def get_value(self, config): -+ ''' -+ get value by config way -+ way i2c/sysfs/lpc -+ ''' -+ way = config.get("way") -+ if way == 'sysfs': -+ return self.get_sysfs(config.get("loc"), config.get("flock_path")) -+ if way == "i2c": -+ bus = config.get("bus") -+ addr = config.get("addr") -+ offset = config.get("offset") -+ return self.get_i2c(bus, addr, offset) -+ if way == "io": -+ io_addr = config.get('io_addr') -+ read_len = config.get('read_len', 1) -+ return self.get_io(io_addr, read_len) -+ if way == "i2cword": -+ bus = config.get("bus") -+ addr = config.get("addr") -+ offset = config.get("offset") -+ return self.get_i2cword(bus, addr, offset) -+ if way == "devmem": -+ addr = config.get("addr") -+ digit = config.get("digit") -+ mask = config.get("mask", None) -+ return self.get_devmem(addr, digit, mask) -+ if way == "sdk": -+ get_type = config.get("type") -+ if get_type == "bcm_temp": -+ return self.getbcmtemp() -+ if get_type == "bcm_reg": -+ reg = config.get("reg") -+ return self.getbcmreg(reg) -+ raise Exception("cannot found sdk type deal") -+ if way == "devfile": -+ loc = config.get("loc") -+ offset = config.get("offset") -+ length = config.get("len") -+ ret, val_list = self.devfile_read(loc, offset, length) -+ if ret is True: -+ if length == 1: -+ val = val_list[0] -+ return True, val -+ return True, val_list -+ return False, ("devfile read failed. path:%s, offset:0x%x, read_len:%d" % (loc, offset, length)) -+ if way == "devfile_ascii": -+ loc = config.get("loc") -+ offset = config.get("offset") -+ length = config.get("len") -+ return self.devfile_read_ascii(loc, offset, length) -+ if way == 'cmd': -+ cmd = config.get("cmd") -+ ret, log = self.exec_os_cmd(cmd) -+ if ret: -+ return False, ("cmd write exec %s failed, log: %s" % (cmd, log)) -+ return True, log -+ if way == 'config': -+ value = config.get("value") -+ return True, value -+ raise Exception("cannot found way deal") -+ -+ def devfile_read(self, loc, offset, length): -+ return osutil.readdevfile(loc, offset, length) -+ -+ def devfile_read_ascii(self, loc, offset, length): -+ return osutil.readdevfile_ascii(loc, offset, length) -+ -+ def get_sysfs(self, loc, flock_path=None): -+ return self.getsysfs(loc, flock_path) -+ -+ def getsysfs(self, loc, flock_path=None): -+ ret, val = osutil.readsysfs(loc, flock_path) -+ return ret, val -+ -+ def get_devmem(self, addr, digit, mask): -+ return osutil.getdevmem(addr, digit, mask) -+ -+ def get_i2cword(self, bus, addr, offset): -+ return self.geti2cword(bus, addr, offset) -+ -+ def geti2cword(self, bus, addr, offset): -+ ret, val = osutil.geti2cword(bus, addr, offset) -+ return ret, val -+ -+ def get_io(self, reg_addr, read_len): -+ return self.getio(reg_addr, read_len) -+ -+ def getio(self, reg_addr, read_len): -+ ret, val = osutil.io_rd(reg_addr, read_len) -+ return ret, val -+ -+ def get_i2c(self, bus, addr, offset): -+ return self.geti2c(bus, addr, offset) -+ -+ def geti2c(self, bus, addr, offset): -+ ret, val = osutil.wbi2cget(bus, addr, offset) -+ return ret, val -+ -+ def set_value(self, config, val): -+ ''' -+ get value by config way -+ way i2c/sysfs/lpc -+ ''' -+ way = config.get("way") -+ if way == 'sysfs': -+ return self.set_sysfs(config.get("loc"), "0x%02x" % val) -+ if way == "i2c": -+ bus = config.get("bus") -+ addr = config.get("addr") -+ offset = config.get("offset") -+ return self.set_i2c(bus, addr, offset, val) -+ if way == "i2cpec": -+ bus = config.get("bus") -+ addr = config.get("addr") -+ offset = config.get("offset") -+ return self.seti2c_byte_pec(bus, addr, offset, val) -+ if way == 'i2cword': -+ bus = config.get("bus") -+ addr = config.get("addr") -+ offset = config.get("offset") -+ return self.set_i2cword(bus, addr, offset, val) -+ if way == "i2cwordpec": -+ bus = config.get("bus") -+ addr = config.get("addr") -+ offset = config.get("offset") -+ return self.set_i2cwordpec(bus, addr, offset, val) -+ if way == "devfile": -+ loc = config.get("loc") -+ offset = config.get("offset") -+ return self.devfile_write(loc, offset, val) -+ return False, "unsupport way: %s" % way -+ -+ def set_sysfs(self, loc, value): -+ return self.setsysfs(loc, value) -+ -+ def setsysfs(self, loc, value): -+ return osutil.writesysfs(loc, value) -+ -+ def set_i2cword(self, bus, addr, offset, byte): -+ return self.seti2cword(bus, addr, offset, byte) -+ -+ def seti2cword(self, bus, addr, offset, byte): -+ return osutil.seti2cword(bus, addr, offset, byte) -+ -+ def set_i2cwordpec(self, bus, addr, offset, val): -+ return osutil.seti2cwordpec(bus, addr, offset, val) -+ -+ def seti2c_byte_pec(self, bus, addr, offset, val): -+ return osutil.seti2c_byte_pec(bus, addr, offset, val) -+ -+ def set_i2c(self, bus, addr, offset, byte): -+ return self.seti2c(bus, addr, offset, byte) -+ -+ def seti2c(self, bus, addr, offset, byte): -+ ret, val = osutil.wbi2cset(bus, addr, offset, byte) -+ return ret, val -+ -+ def devfile_write(self, loc, offset, val): -+ ret, val = osutil.writedevfile(loc, offset, val) -+ return ret, val -+ -+ def getbcmtemp(self): -+ try: -+ sta, ret = osutil.getmactemp() -+ if sta is True: -+ mac_aver = float(ret.get("average", self.__error_ret)) -+ mac_aver = mac_aver * 1000 -+ else: -+ return False, ret -+ except AttributeError as e: -+ return False, str(e) -+ return True, mac_aver -+ -+ def getbcmreg(self, reg): -+ ret, val = osutil.getsdkreg(reg) -+ return ret, val -+ -+ def logger_debug(self, msg): -+ baseutil.logger_debug(msg) -+ -+ def command(self, cmd): -+ ret, output = osutil.command(cmd) -+ return ret, output -+ -+ def get_format_value(self, format_str): -+ ast_obj = ast.parse(format_str, mode='eval') -+ visitor = CodeVisitor() -+ visitor.visit(ast_obj) -+ ret = visitor.get_value() -+ return ret -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/fan.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/fan.py -new file mode 100644 -index 000000000..1424c14a4 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/fan.py -@@ -0,0 +1,417 @@ -+#!/usr/bin/env python3 -+####################################################### -+# -+# fan.py -+# Python implementation of the Class fan -+# -+####################################################### -+from eepromutil.fru import ipmifru -+from eepromutil.fantlv import fan_tlv -+from plat_hal.devicebase import devicebase -+from plat_hal.rotor import rotor -+ -+ -+class fan(devicebase): -+ __rotor_list = [] -+ __pn = None -+ __raweeprom = None -+ __sn = None -+ __hw_version = None -+ __e2loc = None -+ __rotors = None -+ __AirFlow = None -+ __SpeedMin = None -+ __SpeedMax = None -+ __PowerMax = None -+ __productName = None -+ __productSerialNumber = None -+ __WatchdogStatus = None -+ __led_attrs_config = None -+ __led_config = None -+ __WatchdogStatus_config = None -+ __AirFlowconifg = None -+ __EnableWatchdogConf = None -+ __Rotor_config = None -+ __fan_display_name = None # 'N/A' -+ __fan_display_name_conifg = None -+ -+ def __init__(self, conf=None): -+ if conf is not None: -+ self.name = conf.get('name', None) -+ self.sn = conf.get('sn', None) -+ self.present = conf.get('present', None) -+ self.e2loc = conf.get('e2loc', None) -+ self.e2_type = conf.get('e2_type', "fru") -+ self.SpeedMin = conf.get('SpeedMin', None) -+ self.SpeedMax = conf.get('SpeedMax', None) -+ self.PowerMax = conf.get('PowerMax', None) -+ self.AirFlowconifg = conf.get("airflow", None) -+ self.WatchdogStatus_config = conf.get('WatchdogStatus', None) -+ self.EnableWatchdogConf = conf.get('EnableWatchdogConf', None) -+ self.led_attrs_config = conf.get('led_attrs', None) -+ self.led_config = conf.get('led', None) -+ self.Rotor_config = conf.get('Rotor', None) -+ self.fan_display_name_conifg = conf.get("fan_display_name", None) -+ rotor_tmp = [] -+ for value in self.Rotor_config.values(): -+ rotor_tmp.append(rotor(value)) -+ rotor_tmp.sort(key=lambda x: x.name, reverse=False) -+ self.rotor_list = rotor_tmp -+ self.rotors = len(self.rotor_list) -+ -+ @property -+ def EnableWatchdogConf(self): -+ return self.__EnableWatchdogConf -+ -+ @EnableWatchdogConf.setter -+ def EnableWatchdogConf(self, val): -+ self.__EnableWatchdogConf = val -+ -+ @property -+ def rotor_list(self): -+ return self.__rotor_list -+ -+ @rotor_list.setter -+ def rotor_list(self, val): -+ self.__rotor_list = val -+ -+ @property -+ def Rotor_config(self): -+ return self.__Rotor_config -+ -+ @Rotor_config.setter -+ def Rotor_config(self, val): -+ self.__Rotor_config = val -+ -+ @property -+ def productName(self): -+ return self.__productName -+ -+ @productName.setter -+ def productName(self, val): -+ self.__productName = val -+ -+ @property -+ def productSerialNumber(self): -+ return self.__productSerialNumber -+ -+ @productSerialNumber.setter -+ def productSerialNumber(self, val): -+ self.__productSerialNumber = val -+ -+ @property -+ def hw_version(self): -+ return self.__hw_version -+ -+ @hw_version.setter -+ def hw_version(self, val): -+ self.__hw_version = val -+ -+ @property -+ def sn(self): -+ return self.__sn -+ -+ @sn.setter -+ def sn(self, val): -+ self.__sn = val -+ -+ @property -+ def pn(self): -+ return self.__pn -+ -+ @pn.setter -+ def pn(self, val): -+ self.__pn = val -+ -+ @property -+ def raweeprom(self): -+ return self.__raweeprom -+ -+ @raweeprom.setter -+ def raweeprom(self, val): -+ self.__raweeprom = val -+ -+ @property -+ def SpeedMax(self): -+ return self.__SpeedMax -+ -+ @SpeedMax.setter -+ def SpeedMax(self, val): -+ self.__SpeedMax = val -+ -+ @property -+ def SpeedMin(self): -+ return self.__SpeedMin -+ -+ @SpeedMin.setter -+ def SpeedMin(self, val): -+ self.__SpeedMin = val -+ -+ @property -+ def PowerMax(self): -+ return self.__PowerMax -+ -+ @PowerMax.setter -+ def PowerMax(self, val): -+ self.__PowerMax = val -+ -+ @property -+ def rotors(self): -+ return self.__rotors -+ -+ @property -+ def AirFlow(self): -+ return self.__AirFlow -+ -+ @AirFlow.setter -+ def AirFlow(self, val): -+ self.__AirFlow = val -+ -+ @rotors.setter -+ def rotors(self, val): -+ self.__rotors = val -+ -+ @property -+ def fan_display_name_conifg(self): -+ return self.__fan_display_name_conifg -+ -+ @fan_display_name_conifg.setter -+ def fan_display_name_conifg(self, val): -+ self.__fan_display_name_conifg = val -+ -+ @property -+ def fan_display_name(self): -+ return self.__fan_display_name -+ -+ @fan_display_name.setter -+ def fan_display_name(self, val): -+ self.__fan_display_name = val -+ -+ def getspeed(self, conf): -+ tmp = None -+ if conf is None: -+ return -1 -+ ret, val = self.get_value(conf) -+ if ret is True: -+ tmp = int(str(val), 10) -+ else: -+ val = None -+ if val is not None: -+ return int(15000000 / tmp) -+ return -1 -+ -+ def get_speed(self, rotor_index): -+ rotor_item = self.get_rotor_index(rotor_index) -+ if rotor_item is None: -+ return None -+ speed = rotor_item.rotor_Speed.Value -+ if speed is None: -+ return None -+ return int(speed) -+ -+ def set_led(self, color): -+ status = self.led_attrs_config.get(color, None) -+ if status is None: -+ return False -+ -+ mask = self.led_attrs_config.get('mask', 0xff) -+ ret, value = self.get_value(self.led_config) -+ if ret is False or value is None: -+ return False -+ setval = (int(value) & ~mask) | (status) -+ ret, val = self.set_value(self.led_config, setval) -+ return ret -+ -+ def get_led(self): -+ mask = self.led_attrs_config.get('mask', 0xff) -+ ret, value = self.get_value(self.led_config) -+ if ret is False or value is None: -+ return False, 'N/A' -+ ledval = int(value) & mask -+ for key, val in self.led_attrs_config.items(): -+ if (ledval == val) and (key != "mask"): -+ return True, key -+ return False, 'N/A' -+ -+ def set_speed(self, rotor_index, level): -+ if level > 255 or level < 0: -+ return False -+ rotor_item = self.get_rotor_index(rotor_index) -+ if rotor_item is None: -+ return False -+ ret, val = self.set_value(rotor_item.Speedconfig, int(level)) -+ return ret -+ -+ def get_rotor_index(self, rotor_index): -+ if rotor_index > len(self.rotor_list): -+ return None -+ rotor_item = self.rotor_list[rotor_index - 1] -+ return rotor_item -+ -+ def get_rotor_byname(self, rotor_index): -+ for rotor_item in self.rotor_list: -+ if rotor_item.name == rotor_index: -+ return rotor_item -+ return None -+ -+ def get_presence(self): -+ ret, val = self.get_value(self.present) -+ if ret is False or val is None: -+ return -1 -+ if isinstance(val, str): -+ value = int(val, 16) -+ else: -+ value = val -+ mask = self.present.get("mask") -+ flag = value & mask -+ okval = self.present.get("okval", 0) -+ if flag == okval: -+ return True -+ return False -+ -+ def get_speed_pwm(self, rotor_index): -+ rotor_item = self.get_rotor_index(rotor_index) -+ if rotor_item is None: -+ return False -+ if rotor_item.i2c_speed is None: -+ return False -+ val = round(rotor_item.i2c_speed * 100 / 255) -+ return val -+ -+ def feed_watchdog(self): -+ ret = False -+ for rotor_item in self.rotor_list: -+ ret, val = rotor_item.feed_watchdog() -+ if ret is False: -+ return ret -+ return ret -+ -+ def get_fru_info(self): -+ try: -+ if self.get_presence() is False: -+ raise Exception("%s: not present" % self.name) -+ eeprom = self.get_eeprom_info(self.e2loc) -+ if eeprom is None: -+ raise Exception("%s: value is none" % self.name) -+ fru = ipmifru() -+ if isinstance(eeprom, bytes): -+ eeprom = self.byteTostr(eeprom) -+ fru.decodeBin(eeprom) -+ self.productName = fru.productInfoArea.productName.strip() # PN -+ self.productSerialNumber = fru.productInfoArea.productSerialNumber.strip() # SN -+ self.hw_version = fru.productInfoArea.productVersion.strip() # HW -+ except Exception: -+ self.productName = None -+ self.productSerialNumber = None -+ self.hw_version = None -+ return False -+ return True -+ -+ def get_tlv_info(self): -+ try: -+ if self.get_presence() is False: -+ raise Exception("%s: not present" % self.name) -+ eeprom = self.get_eeprom_info(self.e2loc) -+ if eeprom is None: -+ raise Exception("%s: value is none" % self.name) -+ tlv = fan_tlv() -+ rets = tlv.decode(eeprom) -+ for item in rets: -+ if item["name"] == "Product Name": -+ self.productName = item["value"].replace("\x00", "").strip() -+ elif item["name"] == "serial Number": -+ self.productSerialNumber = item["value"].replace("\x00", "").strip() -+ elif item["name"] == "hardware info": -+ self.hw_version = item["value"].replace("\x00", "").strip() -+ except Exception: -+ self.productName = None -+ self.productSerialNumber = None -+ self.hw_version = None -+ return False -+ return True -+ -+ def decode_eeprom_info(self): -+ '''get fan name, hw version, sn''' -+ if self.e2_type == "fru": -+ return self.get_fru_info() -+ -+ if self.e2_type == "fantlv": -+ return self.get_tlv_info() -+ -+ return False -+ -+ def get_AirFlow(self): -+ if self.productName is None: -+ ret = self.decode_eeprom_info() -+ if ret is False: -+ self.AirFlow = None -+ return False -+ if self.AirFlowconifg is None: -+ self.AirFlow = None -+ return False -+ for i in self.AirFlowconifg: -+ if self.productName in self.AirFlowconifg[i]: -+ self.AirFlow = i -+ return True -+ self.AirFlow = None -+ return False -+ -+ def enable_watchdog(self, enable): -+ ret = False -+ if enable is True: -+ byte = self.EnableWatchdogConf.get("enable_byte", None) -+ ret, val = self.set_value(self.EnableWatchdogConf, byte) -+ elif enable is False: -+ byte = self.EnableWatchdogConf.get("disable_byte", None) -+ ret, val = self.set_value(self.EnableWatchdogConf, byte) -+ return ret -+ -+ def get_watchdog_status(self): -+ dic = {"support": None, "open": None, "work_full": None, "work_allow_set": None} -+ if self.WatchdogStatus_config is None: -+ return None -+ ret, val = self.get_value(self.WatchdogStatus_config) -+ if ret is False or val is None: -+ return None -+ support_watchdog_off = self.WatchdogStatus_config.get("support_watchdog_off", None) -+ is_open_off = self.WatchdogStatus_config.get("is_open_off", None) -+ full_running_off = self.WatchdogStatus_config.get("full_running_off", None) -+ running_setting_off = self.WatchdogStatus_config.get("running_setting_off", None) -+ if support_watchdog_off is not None: -+ if support_watchdog_off & val == self.WatchdogStatus_config.get("support_watchdog_mask", None): -+ dic["support"] = True -+ else: -+ dic["support"] = False -+ return dic -+ if is_open_off is not None: -+ if is_open_off & val == self.WatchdogStatus_config.get("is_open_mask", None): -+ dic["open"] = True -+ else: -+ dic["open"] = False -+ if full_running_off is not None: -+ if full_running_off & val == self.WatchdogStatus_config.get("full_running_mask", None): -+ dic["work_full"] = True -+ else: -+ dic["work_full"] = False -+ if running_setting_off is not None: -+ if running_setting_off & val == self.WatchdogStatus_config.get("running_setting_mask", None): -+ dic["work_allow_set"] = True -+ else: -+ dic["work_allow_set"] = False -+ return dic -+ -+ def get_fan_display_name(self): -+ if self.productName is None: -+ ret = self.decode_eeprom_info() -+ if ret is False: -+ self.fan_display_name = None -+ return False -+ if self.fan_display_name_conifg is None: -+ self.fan_display_name = self.productName -+ return False -+ for i in self.fan_display_name_conifg: -+ if self.productName in self.fan_display_name_conifg[i]: -+ self.fan_display_name = i -+ return True -+ self.fan_display_name = self.productName -+ return False -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/interface.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/interface.py -new file mode 100644 -index 000000000..7092f555c ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/interface.py -@@ -0,0 +1,1334 @@ -+#!/usr/bin/env python3 -+####################################################### -+# -+# interface.py -+# Python implementation of the Class interface -+# -+####################################################### -+import collections -+from plat_hal.chassisbase import chassisbase -+from plat_hal.baseutil import baseutil -+from plat_hal.osutil import osutil -+ -+ -+def Singleton(cls): -+ _instance = {} -+ -+ def _singleton(*args, **kargs): -+ if cls not in _instance: -+ _instance[cls] = cls(*args, **kargs) -+ return _instance[cls] -+ -+ return _singleton -+ -+ -+@Singleton -+class interface(object): -+ __chas = None -+ __error_ret = None -+ -+ def __init__(self): -+ self.chas = chassisbase() -+ self.__error_ret = -99999 -+ self.__na_ret = 'N/A' -+ -+ @property -+ def na_ret(self): -+ return self.__na_ret -+ -+ @na_ret.setter -+ def na_ret(self, val): -+ self.__na_ret = val -+ -+ @property -+ def error_ret(self): -+ return self.__error_ret -+ -+ @error_ret.setter -+ def error_ret(self, val): -+ self.__error_ret = val -+ -+ @property -+ def chas(self): -+ return self.__chas -+ -+ @chas.setter -+ def chas(self, val): -+ self.__chas = val -+ -+ # onie_e2 -+ def get_onie_e2(self): -+ onie_e2_list = self.chas.onie_e2_list -+ return onie_e2_list -+ -+ def get_onie_e2_path(self, name): -+ onie_e2 = self.chas.get_onie_e2_byname(name) -+ if onie_e2 is None: -+ return None -+ return onie_e2.e2_path -+ -+ def get_device_airflow(self, name): -+ onie_e2 = self.chas.get_onie_e2_byname(name) -+ if onie_e2 is None: -+ return None -+ return onie_e2.airflow -+ -+ def get_onie_e2_obj(self, name): -+ onie_e2 = self.chas.get_onie_e2_byname(name) -+ if onie_e2 is None: -+ return None -+ onie_e2.get_onie_e2_info() -+ return onie_e2 -+ -+ # temp -+ def get_temps(self): -+ templist = self.chas.temp_list -+ return templist -+ -+ def get_temp_total_number(self): -+ templist = self.chas.temp_list -+ return len(templist) -+ -+ def check_temp_id_exist(self, temp_id): -+ templist = self.chas.temp_list -+ for temp in templist: -+ if temp.temp_id == temp_id: -+ return True -+ return False -+ -+ def get_temp_id_number(self): -+ templist = self.chas.temp_list -+ temp_num = 0 -+ for i in range(len(templist)): -+ temp_id = "TEMP" + str(i + 1) -+ ret = self.check_temp_id_exist(temp_id) -+ if ret is True: -+ temp_num = temp_num + 1 -+ else: -+ return temp_num -+ return temp_num -+ -+ def get_temp_location(self, temp_name): -+ temp = self.chas.get_temp_byname(temp_name) -+ return temp.get_location() -+ -+ def set_temp_location(self, temp_name, location): -+ temp = self.chas.get_temp_byname(temp_name) -+ return temp.set_location(location) -+ -+ def set_temp_name(self, temp_name, name): -+ temp = self.chas.get_temp_byname(temp_name) -+ return temp.set_name(name) -+ -+ def get_appoint_temp(self, temp_name): -+ temp = self.chas.get_led_byname(temp_name) -+ return temp.get_temp() -+ -+ def set_appoint_temp(self, temp_name, val): -+ temp = self.chas.get_temp_byname(temp_name) -+ return temp.set_temp(val) -+ -+ def get_temp_mintemp(self, temp_name): -+ temp = self.chas.get_temp_byname(temp_name) -+ return temp.get_mintemp() -+ -+ def set_temp_mintemp(self, temp_name, val): -+ temp = self.chas.get_temp_byname(temp_name) -+ return temp.set_mintemp(val) -+ -+ # led -+ def get_leds(self): -+ ledlist = self.chas.led_list -+ return ledlist -+ -+ def get_led_total_number(self): -+ ledlist = self.chas.led_list -+ return len(ledlist) -+ -+ def get_led_color(self, led_name): -+ led = self.chas.get_led_byname(led_name) -+ if led is None: -+ return -1 -+ return led.get_color() -+ -+ def get_led_color_by_type(self, led_type): -+ ledlist = self.chas.led_list -+ ledtmp = None -+ for temp in ledlist: -+ if temp.led_type == led_type: -+ ledtmp = temp -+ break -+ if ledtmp is None: -+ return -1 -+ return ledtmp.get_color() -+ -+ def set_led_color(self, led_name, color): -+ led = self.chas.get_led_byname(led_name) -+ if led is None: -+ return -1 -+ return led.set_color(color) -+ -+ # psu -+ def get_psu_total_number(self): -+ psulist = self.chas.psu_list -+ if psulist is None: -+ return -1 -+ return len(psulist) -+ -+ def get_psus(self): -+ psulist = self.chas.psu_list -+ return psulist -+ -+ def get_psu_presence(self, psu_name): -+ psu = self.chas.get_psu_byname(psu_name) -+ if psu is None: -+ return -1 -+ return psu.present -+ -+ def get_psu_fru_info(self, psu_name): -+ ''' -+ { -+ "Name": "PSU1", -+ "SN": "serial_number_example", # 'N/A' -+ "PN": "part_number_example", # 'N/A' -+ "AirFlow": "B2F" # 'N/A' -+ } -+ ''' -+ psu = self.chas.get_psu_byname(psu_name) -+ if psu is None: -+ return -1 -+ psu.get_fru_info() -+ psu.get_AirFlow() -+ psu.get_psu_display_name() -+ -+ dic = collections.OrderedDict() -+ dic["Name"] = psu.name -+ dic["SN"] = psu.productSerialNumber if (psu.productSerialNumber is not None) else self.na_ret -+ dic["PN"] = psu.productPartModelName if (psu.productPartModelName is not None) else self.na_ret -+ dic["DisplayName"] = psu.psu_display_name if (psu.psu_display_name is not None) else self.na_ret -+ dic["VENDOR"] = psu.productManufacturer if (psu.productManufacturer is not None) else self.na_ret -+ dic["HW"] = psu.productVersion if (psu.productVersion is not None) else self.na_ret -+ dic["AirFlow"] = psu.AirFlow if (psu.AirFlow is not None) else self.na_ret -+ return dic -+ -+ def get_psu_input_output_status(self, psu_name): -+ psu = self.chas.get_psu_byname(psu_name) -+ if psu is None: -+ return -1 -+ psu.InputsCurrent.Value # just for clear faults -+ if psu.InputStatus is True and psu.OutputStatus is True: -+ return True -+ # only has outputstatus -+ if psu.InputStatus is None and psu.OutputStatus is True: -+ return True -+ return False -+ -+ def get_psu_status(self, psu_name): -+ """ -+ Get status of a specific PSU -+ @return dict of the specific PSU's status, None for failure -+ Example return value(all keys are mandatory) -+ { -+ "Name": "PSU1", -+ "InputType": "DC", # "AC" or 'N/A' -+ "InputStatus": True, # H/W status bit -+ "OutputStatus": True # H/W status bit -+ "FanSpeed": { -+ "Value": 4000, # -99999 -+ "Min": 2000, # -99999 -+ "Max": 10000 # -99999 -+ }, -+ "Temperature": { -+ "Value": 40.0, # -99999.0 -+ "Min": -30.0, # -99999.0 -+ "Max": 50.0 # -99999.0 -+ } -+ } -+ """ -+ psu = self.chas.get_psu_byname(psu_name) -+ if psu is None: -+ return -1 -+ -+ if psu.get_threshold_by_model == 1: -+ psu.get_fru_info() -+ -+ dic = collections.OrderedDict() -+ # psu.get_Temperature() -+ temp_dict = collections.OrderedDict() -+ temp_dict['Min'] = psu.Temperature.Min -+ temp_dict['Max'] = psu.Temperature.Max -+ temp_dict['Value'] = psu.Temperature.Value -+ temp_dict['Unit'] = psu.Temperature.Unit -+ dic["Temperature"] = temp_dict -+ -+ # psu.get_FanSpeed() -+ fan_speed_dict = collections.OrderedDict() -+ fan_speed_dict['Min'] = psu.FanSpeed.Min -+ fan_speed_dict['Max'] = psu.FanSpeed.Max -+ fan_speed_dict['Tolerance'] = psu.FanSpeedTolerance -+ fan_speed_dict['Value'] = psu.FanSpeed.Value -+ fan_speed_dict['Unit'] = psu.FanSpeed.Unit -+ dic["FanSpeed"] = fan_speed_dict -+ -+ dic["Name"] = psu.name -+ dic["InputType"] = psu.InputsType -+ dic["InputStatus"] = psu.InputStatus -+ dic["OutputStatus"] = psu.OutputStatus -+ dic["TempStatus"] = psu.TempStatus -+ dic["FanStatus"] = psu.FanStatus -+ return dic -+ -+ def get_psu_power_status(self, psu_name): -+ """ -+ Get power status of a specific PSU -+ @return dict of the specific PSU's power status, None for failure -+ Example return value -+ { -+ "Name": "PSU1", -+ "Inputs": { -+ "Status": True, # H/W status bit -+ "Type": "DC", # or "AC" or "N/A" -+ "Voltage": { -+ "Value": 220, # -1 -+ "LowAlarm": 200, # -1 -+ "HighAlarm": 240, # -1 -+ "Unit": "V" -+ }, -+ "Current": { -+ "Value": 6.0, # -99999.0 -+ "LowAlarm": 0.2, # -99999.0 -+ "HighAlarm": 7.0, # -99999.0 -+ "Unit": "A" -+ }, -+ "Power": { -+ "Value": 1000, # -99999 -+ "LowAlarm": -1, # -99999 -+ "HighAlarm": 1400, # -99999 -+ "Unit": "W" -+ } -+ }, -+ "Outputs": { -+ "Status": True, -+ "Voltage": { -+ "Value": 220, -+ "LowAlarm": 200, -+ "HighAlarm": 240, -+ "Unit": "V" -+ }, -+ "Current": { -+ "Value": 6.0, -+ "LowAlarm": 0.2, -+ "HighAlarm": 7.0, -+ "Unit": "A" -+ }, -+ "Power": { -+ "Value": 1000, -+ "LowAlarm": -1, # Don't care -+ "HighAlarm": 1400, -+ "Unit": "W" -+ } -+ } -+ } -+ """ -+ psu = self.chas.get_psu_byname(psu_name) -+ if psu is None: -+ return -1 -+ if psu.get_threshold_by_model == 1: -+ psu.get_fru_info() -+ dic = collections.OrderedDict() -+ inputdic = collections.OrderedDict() -+ Outputsdic = collections.OrderedDict() -+ dic["Name"] = psu.name -+ inputdic["Status"] = psu.InputStatus -+ inputdic["Type"] = psu.InputsType -+ -+ # psu.get_InputsVoltage() -+ inputdic_voltage = collections.OrderedDict() -+ -+ inputdic_voltage["Value"] = psu.InputsVoltage.Value -+ inputdic_voltage["LowAlarm"] = psu.InputsVoltage.Min -+ inputdic_voltage["HighAlarm"] = psu.InputsVoltage.Max -+ inputdic_voltage["Unit"] = psu.InputsVoltage.Unit -+ -+ inputdic["Voltage"] = inputdic_voltage -+ inputdic_current = collections.OrderedDict() -+ inputdic_current["Value"] = psu.InputsCurrent.Value -+ inputdic_current["LowAlarm"] = psu.InputsCurrent.Min -+ inputdic_current["HighAlarm"] = psu.InputsCurrent.Max -+ inputdic_current["Unit"] = psu.InputsCurrent.Unit -+ inputdic["Current"] = inputdic_current -+ -+ inputdic_power = collections.OrderedDict() -+ inputdic_power["Value"] = psu.InputsPower.Value -+ inputdic_power["LowAlarm"] = psu.InputsPower.Min -+ inputdic_power["HighAlarm"] = psu.InputsPower.Max -+ inputdic_power["Unit"] = psu.InputsPower.Unit -+ inputdic["Power"] = inputdic_power -+ Outputsdic["Status"] = psu.InputStatus -+ -+ outputdic_voltage = collections.OrderedDict() -+ outputdic_current = collections.OrderedDict() -+ outputdic_power = collections.OrderedDict() -+ -+ outputdic_voltage["Value"] = psu.OutputsVoltage.Value -+ outputdic_voltage["LowAlarm"] = psu.OutputsVoltage.Min -+ outputdic_voltage["HighAlarm"] = psu.OutputsVoltage.Max -+ outputdic_voltage["Unit"] = psu.OutputsVoltage.Unit -+ -+ outputdic_current["Value"] = psu.OutputsCurrent.Value -+ outputdic_current["LowAlarm"] = psu.OutputsCurrent.Min -+ outputdic_current["HighAlarm"] = psu.OutputsCurrent.Max -+ outputdic_current["Unit"] = psu.OutputsCurrent.Unit -+ -+ outputdic_power["Value"] = psu.OutputsPower.Value -+ outputdic_power["LowAlarm"] = psu.OutputsPower.Min -+ outputdic_power["HighAlarm"] = psu.OutputsPower.Max -+ outputdic_power["Unit"] = psu.OutputsPower.Unit -+ -+ Outputsdic["Voltage"] = outputdic_voltage -+ Outputsdic["Current"] = outputdic_current -+ Outputsdic["Power"] = outputdic_power -+ -+ dic["Inputs"] = inputdic -+ dic["Outputs"] = Outputsdic -+ -+ return dic -+ -+ def set_psu_fan_speed_pwm(self, psu_name, pwm): -+ psu = self.chas.get_psu_byname(psu_name) -+ if psu is None: -+ return -1 -+ return psu.set_fan_speed_pwm(pwm) -+ -+ def get_psu_fan_speed_pwm(self, psu_name): -+ psu = self.chas.get_psu_byname(psu_name) -+ if psu is None: -+ return -1 -+ return psu.get_fan_speed_pwm() -+ -+ def get_psu_info_all(self): -+ """ -+ { -+ "Number": 2, -+ "PSU1": { -+ "SN": "serial_number_example", # 'N/A' -+ "PN": "part_number_example", # 'N/A' -+ "AirFlow": "intake", # 'N/A' -+ -+ "FanSpeed": { -+ "Value": 4000, -+ "Min": 2000, -+ "Max": 30000 -+ }, -+ "Temperature": { -+ "Value": 35.0, -+ "Min": -20.0, -+ "Max": 45.0 -+ }, -+ "Inputs": { -+ "Status": True, # H/W status bit -+ "Type": "DC", # or "AC" -+ "Voltage": { -+ "Value": 220, -+ "LowAlarm": 200, -+ "HighAlarm": 240, -+ "Unit": "V" -+ }, -+ "Current": { -+ "Value": 6.0, -+ "LowAlarm": 0.2, -+ "HighAlarm": 7.0, -+ "Unit": "A" -+ }, -+ "Power": { -+ "Value": 1000, -+ "LowAlarm": -1, -+ "HighAlarm": 1400, -+ "Unit": "W" -+ } -+ }, -+ "Outputs": { -+ "Status": True, -+ "Voltage": { -+ "Value": 220, -+ "LowAlarm": 200, -+ "HighAlarm": 240, -+ "Unit": "V" -+ }, -+ "Current": { -+ "Value": 6.0, -+ "LowAlarm": 0.2, -+ "HighAlarm": 7.0, -+ "Unit": "A" -+ }, -+ "Power": { -+ "Value": 1000, -+ "LowAlarm": -1, # Don't care -+ "HighAlarm": 1400, -+ "Unit": "W" -+ } -+ } -+ } -+ } -+ """ -+ -+ psus = self.get_psus() -+ psu_dict = collections.OrderedDict() -+ psu_dict['Number'] = len(psus) -+ for psu in psus: -+ dicttmp = self.get_psu_fru_info(psu.name) -+ dicttmp.update(self.get_psu_status(psu.name)) -+ dicttmp.update(self.get_psu_power_status(psu.name)) -+ if self.get_psu_presence(psu.name) is True: -+ dicttmp['Present'] = 'yes' -+ else: -+ dicttmp['Present'] = 'no' -+ psu_dict[psu.name] = dicttmp -+ return psu_dict -+ -+ def get_fans(self): -+ fanlist = self.chas.fan_list -+ return fanlist -+ -+ # fan -+ def get_fan_total_number(self): -+ fanlist = self.chas.fan_list -+ if fanlist is None: -+ return -1 -+ return len(fanlist) -+ -+ def get_fan_rotor_number(self, fan_name): -+ fan = self.chas.get_fan_byname(fan_name) -+ if fan is None: -+ return -1 -+ ret = fan.rotors -+ if ret is None: -+ return -1 -+ return ret -+ -+ def get_fan_speed(self, fan_name, rotor_index): -+ fan = self.chas.get_fan_byname(fan_name) -+ if fan is None: -+ return -1 -+ ret = fan.get_speed(rotor_index) -+ if ret is None: -+ return -1 -+ return ret -+ -+ def fan_speed_set_level(self, fan_name, rotor_index, level): -+ fan = self.chas.get_fan_byname(fan_name) -+ if fan is None: -+ return -1 -+ ret = fan.set_speed(rotor_index, level) -+ if ret is True: -+ return 0 -+ return -1 -+ -+ def get_fan_speed_pwm(self, fan_name, rotor_index): -+ fan = self.chas.get_fan_byname(fan_name) -+ if fan is None: -+ return -1 -+ val = fan.get_speed_pwm(rotor_index) -+ if val is False: -+ return -1 -+ return val -+ -+ def set_fan_speed_pwm(self, fan_name, rotor_index, pwm): -+ fan = self.chas.get_fan_byname(fan_name) -+ if fan is None: -+ return -1 -+ if isinstance(pwm, str): -+ rate = float(pwm.strip('%s')) -+ speed = round(rate * 255 / 100) -+ elif isinstance(pwm, int): -+ speed = round(pwm * 255 / 100) -+ elif isinstance(pwm, float): -+ speed = round(pwm * 255 / 100) -+ else: -+ return -1 -+ ret = self.fan_speed_set_level(fan.name, rotor_index, speed) -+ if ret == 0: -+ return 0 -+ return -1 -+ -+ def get_fan_watchdog_status(self): -+ fan = self.chas.fan_list[0] -+ dic = fan.get_watchdog_status() -+ if dic is None or dic["support"] is False: -+ return self.na_ret -+ if dic["open"] is False or dic["work_allow_set"] is True: -+ return "Normal" -+ if dic["work_full"] is True: -+ return "Abnormal" -+ return "Abnormal" -+ -+ def enable_fan_watchdog(self, enable=True): -+ fan = self.chas.fan_list[0] -+ ret = fan.enable_watchdog(enable) -+ if ret is True: -+ return 0 -+ return -1 -+ -+ def feed_fan_watchdog(self): -+ fan_list = self.chas.fan_list -+ if fan_list is None: -+ return -1 -+ for fan in fan_list: -+ ret = fan.feed_watchdog() -+ if ret is False: -+ return -1 -+ return 0 -+ -+ def set_fan_led(self, fan_name, color): -+ fan = self.chas.get_fan_byname(fan_name) -+ if fan is None: -+ return -1 -+ ret = fan.set_led(color) -+ if ret is True: -+ return 0 -+ return -1 -+ -+ def get_fan_led(self, fan_name): -+ fan = self.chas.get_fan_byname(fan_name) -+ if fan is None: -+ return False, 'N/A' -+ return fan.get_led() -+ -+ def get_fan_presence(self, fan_name): -+ fan = self.chas.get_fan_byname(fan_name) -+ if fan is None: -+ return -1 -+ return fan.get_presence() -+ -+ def get_fan_fru_info(self, fan_name): -+ """ -+ Get specific fan's information -+ # Properties -+ "Name": "FAN1", -+ "SN": "serial_number_example", # 'N/A' -+ "PN": "part_number_exampple", # 'N/A' -+ "Rotors": 2, # -1 -+ "AirFlow": "intake", # 'N/A' -+ "SpeedMin": 2000, # -1 -+ "SpeedMax": 30000 # -1 -+ """ -+ fan = self.chas.get_fan_byname(fan_name) -+ fan.decode_eeprom_info() -+ fan.get_AirFlow() -+ fan.get_fan_display_name() -+ -+ dic = collections.OrderedDict() -+ dic["Name"] = fan.name -+ dic["SN"] = fan.productSerialNumber -+ if dic["SN"] is None: -+ dic["SN"] = self.na_ret -+ dic["PN"] = fan.productName -+ if dic["PN"] is None: -+ dic["PN"] = self.na_ret -+ dic["DisplayName"] = fan.fan_display_name -+ if dic["DisplayName"] is None: -+ dic["DisplayName"] = self.na_ret -+ -+ dic["Rotors"] = fan.rotors -+ dic["AirFlow"] = fan.AirFlow -+ if dic["AirFlow"] is None: -+ dic["AirFlow"] = self.na_ret -+ dic["SpeedMin"] = fan.SpeedMin -+ dic["SpeedMax"] = fan.SpeedMax -+ return dic -+ -+ def get_fan_eeprom_info(self, fan_name): -+ """ -+ Get specific fan's information -+ # Properties -+ "Name": "M6510-FAN-F", # 'N/A' -+ "SN": "serial_number_example", # 'N/A' -+ "HW": "hw_version_exampple", # 'N/A' -+ """ -+ fan = self.chas.get_fan_byname(fan_name) -+ fan.decode_eeprom_info() -+ fan.get_fan_display_name() -+ dic = collections.OrderedDict() -+ dic["NAME"] = fan.productName -+ if dic["NAME"] is None: -+ dic["NAME"] = self.na_ret -+ dic["SN"] = fan.productSerialNumber -+ if dic["SN"] is None: -+ dic["SN"] = self.na_ret -+ dic["HW"] = fan.hw_version -+ if dic["HW"] is None: -+ dic["HW"] = self.na_ret -+ dic["DisplayName"] = fan.fan_display_name -+ if dic["DisplayName"] is None: -+ dic["DisplayName"] = self.na_ret -+ return dic -+ -+ def get_product_fullname(self): -+ return baseutil.get_product_fullname() -+ -+ def get_fan_status(self, fan_name): -+ fan = self.chas.get_fan_byname(fan_name) -+ if fan is None: -+ return -1 -+ rotorlist = fan.rotor_list -+ dic = collections.OrderedDict() -+ for rotor in rotorlist: -+ dic_val = collections.OrderedDict() -+ if rotor.rotor_Running is True: -+ dic_val['Running'] = 'yes' -+ else: -+ dic_val['Running'] = 'no' -+ if rotor.rotor_HwAlarm is True: -+ dic_val['HwAlarm'] = 'yes' -+ else: -+ dic_val['HwAlarm'] = 'no' -+ dic_val['Speed'] = int(rotor.rotor_Speed.Value) -+ dic[rotor.name] = dic_val -+ return dic -+ -+ def get_fan_rotor_status(self, fan_name, rotor_name): -+ fan = self.chas.get_fan_byname(fan_name) -+ if fan is None: -+ return -1 -+ rotorlist = fan.rotor_list -+ for rotor in rotorlist: -+ if rotor_name == rotor.name: -+ if rotor.rotor_Running is True: -+ return True -+ return False -+ return -1 -+ -+ def get_fan_roll_status(self, fan_name, rotor_index): -+ fan = self.chas.get_fan_byname(fan_name) -+ if fan is None: -+ return -1 -+ rotor = fan.get_rotor_index(rotor_index) -+ if rotor is None: -+ return -1 -+ if rotor.rotor_Running is True: -+ return True -+ return False -+ -+ def get_fan_info_fru(self, fan_name): -+ fan = self.chas.get_fan_byname(fan_name) -+ fan.get_fru_info() -+ fan.get_AirFlow() -+ dic = collections.OrderedDict() -+ dic["Name"] = fan.name -+ dic["SN"] = fan.productSerialNumber -+ if dic["SN"] is None: -+ dic["SN"] = self.na_ret -+ dic["PN"] = fan.productPartModelName -+ if dic["PN"] is None: -+ dic["PN"] = self.na_ret -+ flag = self.get_fan_presence(fan_name) -+ if flag is True: -+ dic["Present"] = "yes" -+ elif flag is False: -+ dic["Present"] = "no" -+ else: -+ dic["Present"] = self.na_ret -+ dic["Rotors"] = fan.rotors -+ dic["AirFlow"] = fan.AirFlow -+ if dic["AirFlow"] is None: -+ dic["AirFlow"] = self.na_ret -+ return dic -+ -+ # support TLV and FRU FAN E2 -+ def get_fan_info(self, fan_name): -+ fan = self.chas.get_fan_byname(fan_name) -+ if fan is None: -+ return None -+ fan.get_AirFlow() -+ dic = self.get_fan_eeprom_info(fan_name) -+ flag = self.get_fan_presence(fan_name) -+ if flag is True: -+ dic["Present"] = "yes" -+ elif flag is False: -+ dic["Present"] = "no" -+ else: -+ dic["Present"] = self.na_ret -+ dic["Rotors"] = fan.rotors -+ dic["AirFlow"] = fan.AirFlow -+ if dic["AirFlow"] is None: -+ dic["AirFlow"] = self.na_ret -+ dic["PowerMax"] = fan.PowerMax -+ if dic["PowerMax"] is None: -+ dic["PowerMax"] = self.na_ret -+ return dic -+ -+ def get_fan_info_rotor(self, fan_name): -+ fan = self.chas.get_fan_byname(fan_name) -+ if fan is None: -+ return -1 -+ rotorlist = fan.rotor_list -+ dic = collections.OrderedDict() -+ for rotor in rotorlist: -+ dic_val = collections.OrderedDict() -+ if rotor.rotor_Running is True: -+ dic_val['Running'] = 'yes' -+ else: -+ dic_val['Running'] = 'no' -+ if rotor.rotor_HwAlarm is True: -+ dic_val['HwAlarm'] = 'yes' -+ else: -+ dic_val['HwAlarm'] = 'no' -+ speed_value = rotor.rotor_Speed.Value -+ if speed_value is None: -+ dic_val['Speed'] = self.error_ret -+ else: -+ dic_val['Speed'] = int(speed_value) -+ if rotor.SpeedMin is None: -+ dic_val['SpeedMin'] = self.error_ret -+ else: -+ dic_val['SpeedMin'] = rotor.SpeedMin -+ if rotor.SpeedMax is None: -+ dic_val['SpeedMax'] = self.error_ret -+ else: -+ dic_val['SpeedMax'] = rotor.SpeedMax -+ if rotor.Tolerance is None: -+ dic_val['Tolerance'] = self.error_ret -+ else: -+ dic_val['Tolerance'] = rotor.Tolerance -+ -+ dic[rotor.name] = dic_val -+ return dic -+ -+ def get_fan_info_all(self): -+ fanlist = self.chas.fan_list -+ dic = collections.OrderedDict() -+ dic['Number'] = len(fanlist) -+ dic['WatchdogStatus'] = self.get_fan_watchdog_status() -+ for fan in fanlist: -+ dic[fan.name] = self.get_fan_info(fan.name) -+ dic[fan.name].update(self.get_fan_info_rotor(fan.name)) -+ return dic -+ -+ def temp_test(self): -+ templist = self.chas.temp_list -+ dicret = collections.OrderedDict() -+ -+ for temp in templist: -+ dic = collections.OrderedDict() -+ temp_value = temp.Value -+ dic["Value"] = temp_value if (temp_value is not None) else self.error_ret -+ dic["LowAlarm"] = temp.Min -+ dic["HighAlarm"] = temp.Max -+ dicret[temp.name] = dic -+ return dicret -+ -+ # dcdc -+ def get_dcdc_total_number(self): -+ dcdclist = self.chas.dcdc_list -+ if dcdclist is None: -+ return -1 -+ return len(dcdclist) -+ -+ def get_dcdc_by_id(self, dcdc_id): -+ dcdclist = self.chas.dcdc_list -+ dcdctmp = None -+ for dcdc in dcdclist: -+ if dcdc.dcdc_id == dcdc_id: -+ dcdctmp = dcdc -+ dic = collections.OrderedDict() -+ if dcdctmp is None: -+ dic["Name"] = self.error_ret -+ dic["Min"] = self.error_ret -+ dic["Max"] = self.error_ret -+ dic["Low"] = self.error_ret -+ dic["High"] = self.error_ret -+ dic["Value"] = self.error_ret -+ dic["Unit"] = self.error_ret -+ else: -+ dic["Name"] = dcdctmp.name -+ dic["Min"] = dcdctmp.sensor.Min -+ dic["Max"] = dcdctmp.sensor.Max -+ dic["Low"] = dcdctmp.sensor.Low -+ dic["High"] = dcdctmp.sensor.High -+ tmp = dcdctmp.sensor.Value -+ if tmp is not None: -+ dic['Value'] = tmp -+ else: -+ dic['Value'] = self.error_ret -+ dic["Unit"] = dcdctmp.sensor.Unit -+ return dic -+ -+ def get_dcdc_all_info(self): -+ val_list = collections.OrderedDict() -+ dcdclist = self.chas.dcdc_list -+ for dcdc in dcdclist: -+ dicttmp = {} -+ sensorname = "%s" % (dcdc.name) -+ dicttmp['Min'] = dcdc.sensor.Min -+ dicttmp['Max'] = dcdc.sensor.Max -+ tmp = dcdc.sensor.Value -+ if tmp is not None: -+ dicttmp['Value'] = tmp -+ else: -+ dicttmp['Value'] = self.error_ret -+ dicttmp['Unit'] = dcdc.sensor.Unit -+ val_list[sensorname] = dicttmp -+ return val_list -+ -+ # sensors -+ def get_monitor_temp(self, name): -+ templist = self.chas.temp_list -+ temptmp = None -+ for temp in templist: -+ if temp.name == name: -+ temptmp = temp -+ -+ dic = collections.OrderedDict() -+ if temptmp is None: -+ dic["Min"] = self.error_ret -+ dic["Max"] = self.error_ret -+ dic["Value"] = self.error_ret -+ dic["Unit"] = self.error_ret -+ else: -+ dic["Min"] = temptmp.Min -+ dic["Max"] = temptmp.Max -+ temp_value = temptmp.Value -+ dic["Value"] = temp_value if (temp_value is not None) else self.error_ret -+ dic["Unit"] = temptmp.Unit -+ return dic -+ -+ def get_monitor_temp_by_id(self, temp_id): -+ templist = self.chas.temp_list -+ temptmp = None -+ for temp in templist: -+ if temp.temp_id == temp_id: -+ temptmp = temp -+ -+ dic = collections.OrderedDict() -+ if temptmp is None: -+ dic["Name"] = self.error_ret -+ dic["Api_name"] = self.error_ret -+ dic["Min"] = self.error_ret -+ dic["Max"] = self.error_ret -+ dic["Low"] = self.error_ret -+ dic["High"] = self.error_ret -+ dic["Value"] = self.error_ret -+ dic["Unit"] = self.error_ret -+ else: -+ dic["Name"] = temptmp.name -+ dic["Api_name"] = temptmp.api_name -+ dic["Min"] = temptmp.Min -+ dic["Max"] = temptmp.Max -+ dic["Low"] = temptmp.Low -+ dic["High"] = temptmp.High -+ temp_value = temptmp.Value -+ dic["Value"] = temp_value if (temp_value is not None) else self.error_ret -+ dic["Unit"] = temptmp.Unit -+ return dic -+ -+ def get_temp_info(self): -+ val_list = collections.OrderedDict() -+ # temp -+ templist = self.chas.temp_list -+ for temp in templist: -+ dic = collections.OrderedDict() -+ dic["Min"] = temp.Min -+ dic["Max"] = temp.Max -+ dic["Low"] = temp.Low -+ dic["High"] = temp.High -+ temp_value = temp.Value -+ dic["Value"] = temp_value if (temp_value is not None) else self.error_ret -+ dic["Unit"] = temp.Unit -+ val_list[temp.name] = dic -+ return val_list -+ -+ def get_sensor_info(self): -+ val_list = collections.OrderedDict() -+ # temp -+ templist = self.chas.temp_list -+ for temp in templist: -+ dic = collections.OrderedDict() -+ dic["Min"] = temp.Min -+ dic["Max"] = temp.Max -+ dic["Low"] = temp.Low -+ dic["High"] = temp.High -+ temp_value = temp.Value -+ dic["Value"] = temp_value if (temp_value is not None) else self.error_ret -+ dic["Unit"] = temp.Unit -+ val_list[temp.name] = dic -+ # fan -+ fanlist = self.chas.fan_list -+ for fan in fanlist: -+ for rotor in fan.rotor_list: -+ sensorname = "%s%s" % (fan.name, rotor.name) -+ speed = collections.OrderedDict() -+ speed['Min'] = rotor.rotor_Speed.Min -+ speed['Max'] = rotor.rotor_Speed.Max -+ rotor_speed_Value = rotor.rotor_Speed.Value -+ speed['Value'] = rotor_speed_Value if (rotor_speed_Value is not None) else self.error_ret -+ speed['Unit'] = rotor.rotor_Speed.Unit -+ val_list[sensorname] = speed -+ -+ val_list.update(self.get_dcdc_all_info()) -+ -+ # psu -+ psulist = self.chas.psu_list -+ for psu in psulist: -+ inputdic_voltage = collections.OrderedDict() -+ inputdic_current = collections.OrderedDict() -+ inputdic_power = collections.OrderedDict() -+ outputdic_voltage = collections.OrderedDict() -+ outputdic_current = collections.OrderedDict() -+ outputdic_power = collections.OrderedDict() -+ temperature = collections.OrderedDict() -+ fanspeed = collections.OrderedDict() -+ -+ psu_temp_value = psu.Temperature.Value -+ temperature["Value"] = psu_temp_value if (psu_temp_value is not None) else self.error_ret -+ temperature["Min"] = psu.Temperature.Min -+ temperature["Max"] = psu.Temperature.Max -+ temperature["Unit"] = psu.Temperature.Unit -+ -+ fanspeed["Value"] = psu.FanSpeed.Value -+ fanspeed["Min"] = psu.FanSpeed.Min -+ fanspeed["Max"] = psu.FanSpeed.Max -+ fanspeed["Unit"] = psu.FanSpeed.Unit -+ -+ psu_inputvoltage_value = psu.InputsVoltage.Value -+ inputdic_voltage["Value"] = psu_inputvoltage_value if ( -+ psu_inputvoltage_value is not None) else self.error_ret -+ inputdic_voltage["Min"] = psu.InputsVoltage.Min -+ inputdic_voltage["Max"] = psu.InputsVoltage.Max -+ inputdic_voltage["Unit"] = psu.InputsVoltage.Unit -+ -+ psu_inputcurrent_value = psu.InputsCurrent.Value -+ inputdic_current["Value"] = psu_inputcurrent_value if ( -+ psu_inputcurrent_value is not None) else self.error_ret -+ inputdic_current["Min"] = psu.InputsCurrent.Min -+ inputdic_current["Max"] = psu.InputsCurrent.Max -+ inputdic_current["Unit"] = psu.InputsCurrent.Unit -+ -+ psu_inputpower_value = psu.InputsPower.Value -+ inputdic_power["Value"] = psu_inputpower_value if (psu_inputpower_value is not None) else self.error_ret -+ inputdic_power["Min"] = psu.InputsPower.Min -+ inputdic_power["Max"] = psu.InputsPower.Max -+ inputdic_power["Unit"] = psu.InputsPower.Unit -+ -+ psu_outputvoltage_value = psu.OutputsVoltage.Value -+ outputdic_voltage["Value"] = psu_outputvoltage_value if ( -+ psu_outputvoltage_value is not None) else self.error_ret -+ outputdic_voltage["Min"] = psu.OutputsVoltage.Min -+ outputdic_voltage["Max"] = psu.OutputsVoltage.Max -+ outputdic_voltage["Unit"] = psu.OutputsVoltage.Unit -+ -+ psu_outputcurrent_value = psu.OutputsCurrent.Value -+ outputdic_current["Value"] = psu_outputcurrent_value if ( -+ psu_outputcurrent_value is not None) else self.error_ret -+ outputdic_current["Min"] = psu.OutputsCurrent.Min -+ outputdic_current["Max"] = psu.OutputsCurrent.Max -+ outputdic_current["Unit"] = psu.OutputsCurrent.Unit -+ -+ psu_outputpower_value = psu.OutputsPower.Value -+ outputdic_power["Value"] = psu_outputpower_value if ( -+ psu_outputpower_value is not None) else self.error_ret -+ outputdic_power["Min"] = psu.OutputsPower.Min -+ outputdic_power["Max"] = psu.OutputsPower.Max -+ outputdic_power["Unit"] = psu.OutputsPower.Unit -+ -+ val_list["%s%s" % (psu.name, "Vol_I")] = inputdic_voltage -+ val_list["%s%s" % (psu.name, "Curr_I")] = inputdic_current -+ val_list["%s%s" % (psu.name, "Power_I")] = inputdic_power -+ val_list["%s%s" % (psu.name, "Vol_O")] = outputdic_voltage -+ val_list["%s%s" % (psu.name, "Curr_O")] = outputdic_current -+ val_list["%s%s" % (psu.name, "Power_O")] = outputdic_power -+ val_list["%s%s" % (psu.name, "Fan")] = fanspeed -+ val_list["%s%s" % (psu.name, "Temp")] = temperature -+ -+ return val_list -+ -+ # cpld -+ def get_cpld_total_number(self): -+ cpldlist = self.chas.cpld_list -+ return len(cpldlist) -+ -+ def get_cpld_user_reg(self): -+ cpld = self.chas.get_cpld_byname("BASE_CPLD") -+ if cpld is None: -+ return None -+ return cpld.get_user_reg() -+ -+ def set_cpld_user_reg(self, value): -+ if isinstance(value, int) is False: -+ baseutil.logger_debug("value must int %s" % type(value)) -+ return -1 -+ if (int(value) < 0 or int(value) > 255): -+ baseutil.logger_debug("value must [0 - 255]") -+ return -1 -+ cpld = self.chas.get_cpld_byname("BASE_CPLD") -+ if cpld is None: -+ baseutil.logger_debug("name BASE_CPLD not find") -+ return -1 -+ if cpld.set_user_reg(value) is True: -+ return 0 -+ return -1 -+ -+ def set_cpld_console_owner(self, owner): -+ """ -+ Set console I/O owner -+ -+ @param owner I/O owner of the console, either "cpu" or "bmc" -+ -+ @return 0 for success, -1 for failure -+ """ -+ if owner is None: -+ baseutil.logger_debug("owner is None") -+ return -1 -+ owner_tuple = ("cpu", "bmc") -+ if owner not in owner_tuple: -+ baseutil.logger_debug("owner is %s, must cpu or bmc" % owner) -+ return -1 -+ cpld = self.chas.get_cpld_byname("BASE_CPLD") -+ if cpld is None: -+ baseutil.logger_debug("name BASE_CPLD not find") -+ return -1 -+ if cpld.set_console_owner(owner) is True: -+ return 0 -+ return -1 -+ -+ def get_cpld_version_by_id(self, cpld_id): -+ cpldlist = self.chas.cpld_list -+ cpldtmp = None -+ for cpld in cpldlist: -+ if cpld.cpld_id == cpld_id: -+ cpldtmp = cpld -+ -+ dic = collections.OrderedDict() -+ if cpldtmp is None: -+ dic["Name"] = self.na_ret -+ dic["Version"] = self.na_ret -+ dic["Desc"] = self.na_ret -+ dic["Slot"] = None -+ dic["Warm"] = None -+ else: -+ dic["Name"] = cpldtmp.name -+ dic["Version"] = cpldtmp.get_version() -+ dic["Desc"] = cpldtmp.desc -+ dic["Slot"] = cpldtmp.slot -+ dic["Warm"] = cpldtmp.warm -+ return dic -+ -+ def get_cpld_all_version(self): -+ """ -+ Get version of all CPLDs' that can be read from BMC -+ -+ @return dict of CPLDs' version or None for failure. -+ example outputs: -+ { -+ "BASE_CPLD": "0.1", # or "N/A" for read failure -+ "FAN_CPLD": "0.2" -+ } -+ """ -+ cpld_version = { -+ "BASE_CPLD": "N/A", -+ "FAN_CPLD": "N/A" -+ } -+ for cpld_name in cpld_version: -+ cpld = self.chas.get_cpld_byname(cpld_name) -+ if cpld is None: -+ baseutil.logger_debug("name %s not find" % cpld_name) -+ continue -+ cpld_version[cpld_name] = cpld.get_version() -+ return cpld_version -+ -+ # comp -+ def get_comp_total_number(self): -+ complist = self.chas.comp_list -+ return len(complist) -+ -+ def get_comp_list(self): -+ return self.chas.comp_list -+ -+ def get_comp_id(self, comp): -+ return comp.comp_id -+ -+ def get_comp_version_by_id(self, comp_id): -+ comp_list = self.chas.comp_list -+ comptmp = None -+ for comp in comp_list: -+ if comp.comp_id == comp_id: -+ comptmp = comp -+ break -+ -+ dic = collections.OrderedDict() -+ if comptmp is None: -+ dic["Name"] = self.na_ret -+ dic["Version"] = self.na_ret -+ dic["Desc"] = self.na_ret -+ dic["Slot"] = None -+ else: -+ dic["Name"] = comptmp.name -+ dic["Version"] = comptmp.get_version() -+ dic["Desc"] = comptmp.desc -+ dic["Slot"] = comptmp.slot -+ return dic -+ -+ def get_bmc_productname(self): -+ """ -+ Get product name -+ -+ @return product name string, e.g. $(device name)-F-$(VENDOR_NAME), if error return "N/A" -+ """ -+ bmc = self.chas.get_bmc_byname("master") -+ if bmc is None: -+ baseutil.logger_debug("name bmc(master) not find") -+ return self.na_ret -+ return bmc.get_productname() -+ -+ def call_bmc_diagcmd(self, cmdstr): -+ """ -+ Call BMC diag comman func -+ -+ @return ret: 0 sucess , -1 fail -+ outmsg: if success is out msg, or fail is err msg -+ """ -+ if (cmdstr is None or cmdstr == ""): -+ outmsg = "cmdstr is empty" -+ baseutil.logger_debug(outmsg) -+ return -1, outmsg -+ bmc = self.chas.get_bmc_byname("master") -+ if bmc is None: -+ outmsg = "name bmc(master) not find" -+ baseutil.logger_debug(outmsg) -+ return -1, outmsg -+ baseutil.logger_debug("call cmdstr %s" % cmdstr) -+ return bmc.call_diagcmd(cmdstr) -+ -+ def write_bios_version(self, flash, version): -+ bios = self.chas.get_bios_byname("master") -+ if bios is None: -+ baseutil.logger_debug("name bios(master) not find") -+ return -1 -+ return bios.set_bios_version(flash, version) -+ -+ def get_bios_version(self): -+ bios = self.chas.get_bios_byname("master") -+ if bios is None: -+ baseutil.logger_debug("name bios(master) not find") -+ return -1 -+ return bios.get_bios_version() -+ -+ def get_bios_status(self): -+ bios = self.chas.get_bios_byname("master") -+ if bios is None: -+ baseutil.logger_debug("name bios(master) not find") -+ return -1 -+ return bios.get_bios_boot_status() -+ -+ def get_bmc_mac_rov(self): -+ """ -+ Get BMC mac rov -+ -+ @return ret: 0 sucess , -1 fail -+ outmsg: if success is out msg, or fail is err msg -+ """ -+ bmc = self.chas.get_bmc_byname("master") -+ if bmc is None: -+ msg = "name master not find" -+ baseutil.logger_debug(msg) -+ return -1, msg -+ return bmc.get_mac_rov() -+ -+ def get_bmc_next_boot(self): -+ """ -+ Get next booting flash of BMC -+ -+ @return 'master'/'slave' on success, "N/A" for failure -+ """ -+ bmc = self.chas.get_bmc_byname("master") -+ if bmc is None: -+ baseutil.logger_debug("name master not find") -+ return self.na_ret -+ return bmc.get_next_boot() -+ -+ def set_bmc_next_boot(self, flash): -+ """ -+ Set flash from which next BMC boot -+ -+ @param flash Booting flash of BMC, "master" or "slave" -+ -+ @return 0 on success, -1 for failure -+ """ -+ flash_status = ("master", "slave") -+ if flash is None or flash not in flash_status: -+ baseutil.logger_debug("parameter flash illegal, should be [master|slave]") -+ return -1 -+ bmc = self.chas.get_bmc_byname("master") -+ if bmc is None: -+ baseutil.logger_debug("name master not find") -+ return -1 -+ return bmc.set_next_boot(flash) -+ -+ def reboot_bmc(self): -+ """ -+ Reboot running BMC -+ """ -+ bmc = self.chas.get_bmc_byname("master") -+ if bmc is None: -+ baseutil.logger_debug("name master not find") -+ return -1 -+ return bmc.reboot() -+ -+ def get_bmc_info(self): -+ """ -+ Get BMC info -+ -+ @return dict of BMC info or None for failure -+ "Version": "1.1.1", # "N/A" -+ "Flash": "master", # "N/A" -+ "Next": "master" # "N/A" -+ """ -+ bmc = self.chas.get_bmc_byname("master") -+ if bmc is None: -+ baseutil.logger_debug("name master not find") -+ return self.na_ret -+ return bmc.get_info() -+ -+ def get_bmc_version_all(self): -+ """ -+ @return dict of BMCs -+ { -+ "MasterVersion": "1.1.1", # "N/A" -+ "SlaveVersion": "1.1.1" # "N/A" -+ } -+ """ -+ bmc = self.chas.get_bmc_byname("master") -+ if bmc is None: -+ baseutil.logger_debug("name master not find") -+ return self.na_ret -+ return bmc.get_version_all() -+ -+ def bmc_execute_command(self, cmd_str): -+ ret, output = osutil.command(cmd_str) -+ if ret: -+ baseutil.logger_debug("execute %s command failed" % (cmd_str)) -+ return ret, output -+ -+ def get_cpu_reset_num(self): -+ """ -+ Get CPU reset num -+ @return CPU reset num on success, -1 for failure -+ """ -+ cpu = self.chas.get_cpu_byname("cpu") -+ if cpu is None: -+ msg = "name cpu not find" -+ baseutil.logger_debug(msg) -+ return -1 -+ return cpu.get_cpu_reset_num() -+ -+ def get_cpu_reboot_cause(self): -+ """ -+ Get CPU reboot cause -+ @return string of cpu reboot reason -+ """ -+ cpu = self.chas.get_cpu_byname("cpu") -+ if cpu is None: -+ msg = "name cpu not find" -+ baseutil.logger_debug(msg) -+ return "Unknown reboot cause" -+ return cpu.get_cpu_reboot_cause() -+ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/led.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/led.py -new file mode 100644 -index 000000000..7fb869c74 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/led.py -@@ -0,0 +1,52 @@ -+#!/usr/bin/env python3 -+####################################################### -+# -+# led.py -+# Python implementation of the Class led -+# -+####################################################### -+from plat_hal.devicebase import devicebase -+ -+ -+class led(devicebase): -+ def __init__(self, conf=None): -+ if conf is not None: -+ self.name = conf.get('name', None) -+ self.led_type = conf.get('led_type', None) -+ self.led_attrs_config = conf.get('led_attrs', None) -+ self.led_config = conf.get('led', None) -+ -+ def set_color(self, color): -+ status = self.led_attrs_config.get(color, None) -+ if status is None: -+ return False -+ -+ mask = self.led_attrs_config.get('mask', 0xff) -+ -+ if isinstance(self.led_config, list): -+ for led_config_index in self.led_config: -+ ret, value = self.get_value(led_config_index) -+ if (ret is False) or (value is None): -+ return False -+ setval = (int(value) & ~mask) | (status) -+ ret, val = self.set_value(led_config_index, setval) -+ if ret is False: -+ return ret -+ else: -+ ret, value = self.get_value(self.led_config) -+ if (ret is False) or (value is None): -+ return False -+ setval = (int(value) & ~mask) | (status) -+ ret, val = self.set_value(self.led_config, setval) -+ return ret -+ -+ def get_color(self): -+ mask = self.led_attrs_config.get('mask', 0xff) -+ ret, value = self.get_value(self.led_config) -+ if ret is False or value is None: -+ return False, 'N/A' -+ ledval = int(value) & mask -+ for key, val in self.led_attrs_config.items(): -+ if (ledval == val) and (key != "mask"): -+ return True, key -+ return False, 'N/A' -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/onie_e2.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/onie_e2.py -new file mode 100644 -index 000000000..9ac32cace ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/onie_e2.py -@@ -0,0 +1,127 @@ -+#!/usr/bin/env python3 -+####################################################### -+# -+# onie_e2.py -+# Python implementation of the Class onie_e2 -+# -+####################################################### -+from plat_hal.devicebase import devicebase -+from eepromutil.onietlv import onie_tlv -+ -+ -+class onie_e2(devicebase): -+ -+ def __init__(self, conf=None): -+ self._cardid = "" -+ self._productname = "" -+ self._partnum = "" -+ self._serialnum = "" -+ self._macbase = "" -+ self._manufdate = "" -+ self._deviceversion = "" -+ self._labelrevision = "" -+ self._platformname = "" -+ self._onieversion = "" -+ self._macsize = "" -+ self._manufname = "" -+ self._manufcountry = "" -+ self._vendorname = "" -+ self._diagname = "" -+ self._servicetag = "" -+ -+ if conf is not None: -+ self.name = conf.get('name', None) -+ self.e2loc = conf.get('e2loc', None) -+ self.e2_path = self.e2loc.get('loc', None) -+ self.airflow = conf.get('airflow', "intake") -+ -+ @property -+ def cardid(self): -+ return self._cardid -+ -+ @property -+ def productname(self): -+ return self._productname -+ -+ @property -+ def partnum(self): -+ return self._partnum -+ -+ @property -+ def serialnum(self): -+ return self._serialnum -+ -+ @property -+ def macbase(self): -+ return self._macbase -+ -+ @property -+ def manufdate(self): -+ return self._manufdate -+ -+ @property -+ def deviceversion(self): -+ return self._deviceversion -+ -+ @property -+ def labelrevision(self): -+ return self._labelrevision -+ -+ @property -+ def platformname(self): -+ return self._platformname -+ -+ @property -+ def onieversion(self): -+ return self._onieversion -+ -+ @property -+ def macsize(self): -+ return self._macsize -+ -+ @property -+ def manufname(self): -+ return self._manufname -+ -+ @property -+ def manufcountry(self): -+ return self._manufcountry -+ -+ @property -+ def vendorname(self): -+ return self._vendorname -+ -+ @property -+ def diagname(self): -+ return self._diagname -+ -+ @property -+ def servicetag(self): -+ return self._servicetag -+ -+ def get_onie_e2_info(self): -+ try: -+ eeprom = self.get_eeprom_info(self.e2loc) -+ if eeprom is None: -+ raise Exception("%s: value is none" % self.name) -+ onietlv = onie_tlv() -+ onietlv.decode(eeprom) -+ self._cardid = onietlv.cardid -+ self._productname = onietlv.productname -+ self._partnum = onietlv.partnum -+ self._serialnum = onietlv.serialnum -+ self._macbase = onietlv.macbase -+ self._manufdate = onietlv.manufdate -+ self._deviceversion = onietlv.deviceversion -+ self._labelrevision = onietlv.labelrevision -+ self._platformname = onietlv.platformname -+ self._onieversion = onietlv.onieversion -+ self._macsize = onietlv.macsize -+ self._manufname = onietlv.manufname -+ self._manufcountry = onietlv.manufcountry -+ self._vendorname = onietlv.vendorname -+ self._diagname = onietlv.diagname -+ self._servicetag = onietlv.servicetag -+ except Exception: -+ return False -+ return True -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/osutil.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/osutil.py -new file mode 100644 -index 000000000..684e26bb9 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/osutil.py -@@ -0,0 +1,440 @@ -+#!/usr/bin/env python3 -+####################################################### -+# -+# osutil.py -+# Python implementation of the Class osutil -+# -+####################################################### -+ -+import os -+import glob -+import re -+import time -+import subprocess -+import fcntl -+import syslog -+from functools import wraps -+from wbutil.smbus import SMBus -+ -+ -+PLATFORM_HAL_DEBUG_FILE = "/etc/.platform_hal_debug_flag" -+ -+ -+def platform_hal_debug(s): -+ if os.path.exists(PLATFORM_HAL_DEBUG_FILE): -+ syslog.openlog("PLATFORM_HAL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def retry(maxretry=6, delay=0.01): -+ ''' -+ maxretry: max retry times -+ delay : interval after last retry -+ ''' -+ def decorator(f): -+ @wraps(f) -+ def wrapper(*args, **kwargs): -+ time_retry = maxretry -+ time_delay = delay -+ result_msg = "" -+ while time_retry: -+ try: -+ val, result_msg = f(*args, **kwargs) -+ if val is True: -+ return val, result_msg -+ time_retry -= 1 -+ time.sleep(time_delay) -+ except Exception as e: -+ time_retry -= 1 -+ result_msg = str(e) -+ time.sleep(time_delay) -+ return False, "max time retry last errmsg is {}".format(result_msg) -+ return wrapper -+ return decorator -+ -+ -+pidfile = None -+ -+ -+def file_rw_lock(file_path): -+ global pidfile -+ pidfile = open(file_path, "r") -+ try: -+ fcntl.flock(pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB) -+ platform_hal_debug("file_rw_lock success") -+ return True -+ except Exception: -+ if pidfile is not None: -+ pidfile.close() -+ pidfile = None -+ return False -+ -+ -+def file_rw_unlock(): -+ try: -+ global pidfile -+ -+ if pidfile is not None: -+ fcntl.flock(pidfile, fcntl.LOCK_UN) -+ pidfile.close() -+ pidfile = None -+ platform_hal_debug("file_rw_unlock success") -+ else: -+ platform_hal_debug("pidfile is invalid, do nothing") -+ return True -+ except Exception as e: -+ platform_hal_debug("file_rw_unlock err, msg: %s" % (str(e))) -+ return False -+ -+ -+def take_file_rw_lock(file_path): -+ loop = 1000 -+ ret = False -+ for i in range(0, loop): -+ ret = file_rw_lock(file_path) -+ if ret is True: -+ break -+ time.sleep(0.001) -+ return ret -+ -+ -+class osutil(object): -+ """ -+ osutil -+ """ -+ -+ @staticmethod -+ @retry(maxretry=6) -+ def wbi2cget_python(bus, addr, reg): -+ with SMBus(bus) as y: -+ val, ind = y.read_byte_data(addr, reg, True) -+ return val, ind -+ -+ @staticmethod -+ @retry(maxretry=6) -+ def wbi2cset_python(bus, addr, reg, value): -+ with SMBus(bus) as y: -+ val, ind = y.write_byte_data(addr, reg, value, True) -+ return val, ind -+ -+ @staticmethod -+ @retry(maxretry=6) -+ def wbi2cgetword_python(bus, addr, reg): -+ with SMBus(bus) as y: -+ val, ind = y.read_word_data(addr, reg, True) -+ return val, ind -+ -+ @staticmethod -+ @retry(maxretry=6) -+ def wbi2csetword_python(bus, addr, reg, value): -+ with SMBus(bus) as y: -+ val, ind = y.write_word_data(addr, reg, value, True) -+ return val, ind -+ -+ @staticmethod -+ @retry(maxretry=6) -+ def wbi2csetwordpec_python(bus, addr, reg, value): -+ with SMBus(bus) as y: -+ val, ind = y.write_word_data_pec(addr, reg, value, True) -+ return val, ind -+ -+ @staticmethod -+ @retry(maxretry=6) -+ def wbi2cset_byte_pec_python(bus, addr, reg, value): -+ with SMBus(bus) as y: -+ val, ind = y.write_byte_data_pec(addr, reg, value, True) -+ return val, ind -+ -+ @staticmethod -+ def command(cmdstr): -+ retcode, output = subprocess.getstatusoutput(cmdstr) -+ return retcode, output -+ -+ @staticmethod -+ def geti2cword_i2ctool(bus, addr, offset): -+ command_line = "i2cget -f -y %d 0x%02x 0x%02x wp" % (bus, addr, offset) -+ retrytime = 6 -+ ret_t = "" -+ for i in range(retrytime): -+ ret, ret_t = osutil.command(command_line) -+ if ret == 0: -+ return True, int(ret_t, 16) -+ time.sleep(0.1) -+ return False, ret_t -+ -+ @staticmethod -+ def seti2cword_i2ctool(bus, addr, offset, val): -+ command_line = "i2cset -f -y %d 0x%02x 0x%0x 0x%04x wp" % (bus, addr, offset, val) -+ retrytime = 6 -+ ret_t = "" -+ for i in range(retrytime): -+ ret, ret_t = osutil.command(command_line) -+ if ret == 0: -+ return True, ret_t -+ time.sleep(0.1) -+ return False, ret_t -+ -+ @staticmethod -+ def wbi2cget_i2ctool(bus, devno, address): -+ command_line = "i2cget -f -y %d 0x%02x 0x%02x " % (bus, devno, address) -+ retrytime = 6 -+ ret_t = "" -+ for i in range(retrytime): -+ ret, ret_t = osutil.command(command_line) -+ if ret == 0: -+ return True, int(ret_t, 16) -+ time.sleep(0.1) -+ return False, ret_t -+ -+ @staticmethod -+ def wbi2cset_i2ctool(bus, devno, address, byte): -+ command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x" % ( -+ bus, devno, address, byte) -+ retrytime = 6 -+ ret_t = "" -+ for i in range(retrytime): -+ ret, ret_t = osutil.command(command_line) -+ if ret == 0: -+ return True, ret_t -+ return False, ret_t -+ -+ @staticmethod -+ def geti2cword(bus, addr, offset): -+ return osutil.wbi2cgetword_python(bus, addr, offset) -+ -+ @staticmethod -+ def seti2cword(bus, addr, offset, val): -+ return osutil.wbi2csetword_python(bus, addr, offset, val) -+ -+ @staticmethod -+ def seti2cwordpec(bus, addr, offset, val): -+ return osutil.wbi2csetwordpec_python(bus, addr, offset, val) -+ -+ @staticmethod -+ def seti2c_byte_pec(bus, addr, offset, val): -+ return osutil.wbi2cset_byte_pec_python(bus, addr, offset, val) -+ -+ @staticmethod -+ def wbi2cget(bus, devno, address): -+ return osutil.wbi2cget_python(bus, devno, address) -+ -+ @staticmethod -+ def wbi2cset(bus, devno, address, byte): -+ return osutil.wbi2cset_python(bus, devno, address, byte) -+ -+ @staticmethod -+ def byteTostr(val): -+ strtmp = '' -+ for value in val: -+ strtmp += chr(value) -+ return strtmp -+ -+ @staticmethod -+ def io_rd(reg_addr, read_len=1): -+ try: -+ regaddr = 0 -+ if isinstance(reg_addr, int): -+ regaddr = reg_addr -+ else: -+ regaddr = int(reg_addr, 16) -+ devfile = "/dev/port" -+ fd = os.open(devfile, os.O_RDWR | os.O_CREAT) -+ os.lseek(fd, regaddr, os.SEEK_SET) -+ val = os.read(fd, read_len) -+ return True, "".join(["%02x" % item for item in val]) -+ except ValueError as e: -+ return False, str(e) -+ except Exception as e: -+ return False, str(e) -+ finally: -+ os.close(fd) -+ -+ @staticmethod -+ def readsysfs(location, flock_path=None): -+ flock_path_tmp = None -+ platform_hal_debug("readsysfs, location:%s, flock_path:%s" % (location, flock_path)) -+ try: -+ if flock_path is not None: -+ flock_paths = glob.glob(flock_path) -+ if len(flock_paths) != 0: -+ flock_path_tmp = flock_paths[0] -+ platform_hal_debug("try to get file lock, path:%s" % flock_path_tmp) -+ ret = take_file_rw_lock(flock_path_tmp) -+ if ret is False: -+ platform_hal_debug("take file lock timeout, path:%s" % flock_path_tmp) -+ return False, ("take file rw lock timeout, path:%s" % flock_path_tmp) -+ else: -+ platform_hal_debug("config error, can't find flock_path:%s" % flock_path) -+ -+ locations = glob.glob(location) -+ with open(locations[0], 'rb') as fd1: -+ retval = fd1.read() -+ retval = osutil.byteTostr(retval) -+ if flock_path_tmp is not None: -+ file_rw_unlock() -+ -+ retval = retval.rstrip('\r\n') -+ retval = retval.lstrip(" ") -+ except Exception as e: -+ if flock_path_tmp is not None: -+ file_rw_unlock() -+ platform_hal_debug("readsysfs error, msg:%s" % str(e)) -+ return False, (str(e) + " location[%s]" % location) -+ return True, retval -+ -+ @staticmethod -+ def writesysfs(location, value): -+ try: -+ if not os.path.isfile(location): -+ print(location, 'not found !') -+ return False, ("location[%s] not found !" % location) -+ with open(location, 'w') as fd1: -+ fd1.write(value) -+ except Exception as e: -+ return False, (str(e) + " location[%s]" % location) -+ return True, ("set location[%s] %s success !" % (location, value)) -+ -+ @staticmethod -+ def getdevmem(addr, digit, mask): -+ command_line = "devmem 0x%02x %d" % (addr, digit) -+ retrytime = 6 -+ ret_t = "" -+ for i in range(retrytime): -+ ret, ret_t = osutil.command(command_line) -+ if ret == 0: -+ if mask is not None: -+ ret_t = str(int(ret_t, 16) & mask) -+ return True, ret_t -+ return False, ret_t -+ -+ @staticmethod -+ def readdevfile_ascii(path, offset, length): -+ msg = "" -+ ret = "" -+ joinstr = '' -+ fd = -1 -+ -+ if not os.path.exists(path): -+ msg = path + " not found !" -+ return False, msg -+ -+ try: -+ fd = os.open(path, os.O_RDONLY) -+ os.lseek(fd, offset, os.SEEK_SET) -+ ret = os.read(fd, length) -+ for item in ret: -+ joinstr += '%02x ' % item # like sysfs, display in hex -+ except Exception as e: -+ msg = str(e) -+ return False, msg -+ finally: -+ if fd > 0: -+ os.close(fd) -+ return True, joinstr -+ -+ @staticmethod -+ def readdevfile(path, offset, length): -+ msg = "" -+ ret = "" -+ fd = -1 -+ val_list = [] -+ -+ if not os.path.exists(path): -+ msg = path + " not found !" -+ return False, msg -+ -+ try: -+ fd = os.open(path, os.O_RDONLY) -+ os.lseek(fd, offset, os.SEEK_SET) -+ ret = os.read(fd, length) -+ for item in ret: -+ val_list.append(item) -+ except Exception as e: -+ msg = str(e) -+ return False, msg -+ finally: -+ if fd > 0: -+ os.close(fd) -+ return True, val_list -+ -+ @staticmethod -+ def writedevfile(path, offset, buf): -+ msg = "" -+ fd = -1 -+ -+ if not os.path.exists(path): -+ msg = path + " not found !" -+ return False, msg -+ -+ if isinstance(buf, list): -+ if len(buf) == 0: -+ msg = "buf:%s is NONE !" % buf -+ return False, msg -+ elif isinstance(buf, int): -+ buf = [buf] -+ else: -+ msg = "buf:%s is not list type or not int type !" % buf -+ return False, msg -+ -+ try: -+ fd = os.open(path, os.O_WRONLY) -+ os.lseek(fd, offset, os.SEEK_SET) -+ ret = os.write(fd, bytes(buf)) -+ except Exception as e: -+ msg = str(e) -+ return False, msg -+ finally: -+ if fd > 0: -+ os.close(fd) -+ -+ return True, ret -+ -+ @staticmethod -+ def wb_os_system(cmd): -+ status, output = subprocess.getstatusoutput(cmd) -+ return status, output -+ -+ @staticmethod -+ def getsdkreg(reg): -+ try: -+ cmd = "bcmcmd -t 1 'getr %s ' < /dev/null" % reg -+ ret, result = osutil.wb_os_system(cmd) -+ result_t = result.strip().replace("\r", "").replace("\n", "") -+ if ret != 0 or "Error:" in result_t: -+ return False, result -+ patt = r"%s.(.*):(.*)>drivshell" % reg -+ rt = re.findall(patt, result_t, re.S) -+ test = re.findall("=(.*)", rt[0][0])[0] -+ except Exception as e: -+ return False, 'get sdk register error, msg: %s' % str(e) -+ return True, test -+ -+ @staticmethod -+ def getmactemp(): -+ try: -+ result = {} -+ # need to exec twice -+ osutil.wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") -+ ret, log = osutil.wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") -+ if ret: -+ return False, result -+ logs = log.splitlines() -+ for line in logs: -+ if "average" in line: -+ b = re.findall(r'\d+.\d+', line) -+ result["average"] = b[0] -+ elif "maximum" in line: -+ b = re.findall(r'\d+.\d+', line) -+ result["maximum"] = b[0] -+ except Exception as e: -+ return False, str(e) -+ return True, result -+ -+ @staticmethod -+ def std_match(stdout, pattern): -+ if pattern is None: -+ return stdout.strip() -+ for line in stdout.splitlines(): -+ if re.match(pattern, line): -+ return line.strip() -+ return None -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/psu.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/psu.py -new file mode 100644 -index 000000000..a5fc3bf77 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/psu.py -@@ -0,0 +1,701 @@ -+#!/usr/bin/env python3 -+####################################################### -+# -+# psu.py -+# Python implementation of the Class psu -+# -+####################################################### -+from eepromutil.fru import ipmifru -+from eepromutil.cust_fru import CustFru -+from plat_hal.devicebase import devicebase -+from plat_hal.sensor import sensor -+ -+ -+class psu(devicebase): -+ __pmbus = None -+ __e2loc = None -+ __productManufacturer = None # : ARTESYN -+ __productName = None # : CRPS550W -+ __productPartModelName = None # : CSU550AP-3-300 -+ __productVersion = None # : AB -+ __productSerialNumber = None # : M623UZ00JYABL -+ __AirFlow = None # 'N/A' -+ __AirFlowconifg = None -+ __psu_display_name = None # 'N/A' -+ __psu_display_name_conifg = None -+ __psu_not_present_pwm = None -+ __InputStatus_config = None -+ __OutputStatus_config = None -+ __FanSpeed_config = None -+ __Temperature_config = None -+ __InputStatus = None -+ __OutputStatus = None -+ __FanSpeed = None -+ __Temperature = None -+ __FanSpeedMin = None -+ __FanSpeedMax = None -+ __FanSpeedTolerance = None -+ __InputsVoltage_config = None -+ __InputsCurrent_config = None -+ __InputsPower_config = None -+ __OutputsVoltage_config = None -+ __OutputsCurrent_config = None -+ __OutputsPower_config = None -+ __InputsVoltage = {} -+ __InputsCurrent = None -+ __InputsPower = None -+ __OutputsVoltage = None -+ __OutputsCurrent = None -+ __OutputsPower = None -+ __InputsType_config = None -+ __InputsType = None -+ __psu_sn_config = None -+ __psu_hw_config = None -+ __psu_pn_config = None -+ __psu_vendor_config = None -+ __TempStatus_config = None -+ __FanStatus_config = None -+ __TempStatus = None -+ __FanStatus = None -+ -+ def __init__(self, conf=None): -+ self.pmbus = conf.get("pmbusloc", None) -+ self.e2loc = conf.get("e2loc", None) -+ self.e2_type = conf.get('e2_type', "fru") -+ self.__presentconfig = conf.get("present", None) -+ self.name = conf.get("name", None) -+ self.get_threshold_by_model = conf.get("get_threshold_by_model", 0) -+ self.AirFlowconifg = conf.get("airflow", None) -+ self.psu_display_name_conifg = conf.get("psu_display_name", None) -+ self.psu_not_present_pwm = conf.get("psu_not_present_pwm", 100) -+ self.Temperature_config = conf.get("Temperature", None) -+ self.Temperature = sensor(self.Temperature_config, self.get_psu_model) -+ -+ self.FanSpeedTolerance = conf.get('psu_fan_tolerance', 30) -+ self.FanSpeed_config = conf.get("FanSpeed", None) -+ self.FanSpeed = sensor(self.FanSpeed_config, self.get_psu_model) -+ -+ self.__InputsVoltage_config = conf.get("InputsVoltage", None) -+ self.generate_psu_input_vol(self.__InputsVoltage_config) -+ self.__InputsCurrent_config = conf.get("InputsCurrent", None) -+ self.InputsCurrent = sensor(self.__InputsCurrent_config, self.get_psu_model) -+ self.__InputsPower_config = conf.get("InputsPower", None) -+ self.InputsPower = sensor(self.__InputsPower_config, self.get_psu_model) -+ self.__OutputsVoltage_config = conf.get("OutputsVoltage", None) -+ self.OutputsVoltage = sensor(self.__OutputsVoltage_config, self.get_psu_model) -+ self.__OutputsCurrent_config = conf.get("OutputsCurrent", None) -+ self.OutputsCurrent = sensor(self.__OutputsCurrent_config, self.get_psu_model) -+ self.__OutputsPower_config = conf.get("OutputsPower", None) -+ self.OutputsPower = sensor(self.__OutputsPower_config, self.get_psu_model) -+ -+ self.__InputStatus_config = conf.get("InputsStatus", None) -+ self.__OutputStatus_config = conf.get("OutputsStatus", None) -+ self.__InputsType_config = conf.get('InputsType', None) -+ self.__psu_sn_config = conf.get('psu_sn', None) -+ self.__psu_hw_config = conf.get('psu_hw', None) -+ self.__psu_pn_config = conf.get('psu_pn', None) -+ self.__psu_vendor_config = conf.get('psu_vendor', None) -+ self.__TempStatus_config = conf.get("TempStatus", None) -+ self.__FanStatus_config = conf.get("FanStatus", None) -+ -+ def get_psu_model(self): -+ if self.productPartModelName is None: -+ ret = self.get_fru_info() -+ if ret is False: -+ return None -+ return self.productPartModelName -+ -+ def generate_psu_input_vol(self, config): -+ tmp = {} -+ for (key, item) in config.items(): -+ tmp.setdefault(key, sensor(item, self.get_psu_model)) -+ self.__InputsVoltage = tmp -+ -+ def get_psu_sensor_by_name(self, psutype): -+ return self.__InputsVoltage.get(psutype) or self.__InputsVoltage.get('other') -+ -+ @property -+ def InputsVoltage(self): -+ psutype = self.InputsType -+ input_sensor = self.get_psu_sensor_by_name(psutype) -+ if input_sensor is None: -+ return None -+ return input_sensor -+ -+ @InputsVoltage.setter -+ def InputsVoltage(self, val): -+ self.__InputsVoltage = val -+ -+ @property -+ def InputsCurrent(self): -+ return self.__InputsCurrent -+ -+ @InputsCurrent.setter -+ def InputsCurrent(self, val): -+ self.__InputsCurrent = val -+ -+ @property -+ def InputsPower(self): -+ return self.__InputsPower -+ -+ @InputsPower.setter -+ def InputsPower(self, val): -+ self.__InputsPower = val -+ -+ @property -+ def OutputsVoltage(self): -+ return self.__OutputsVoltage -+ -+ @OutputsVoltage.setter -+ def OutputsVoltage(self, val): -+ self.__OutputsVoltage = val -+ -+ @property -+ def OutputsCurrent(self): -+ return self.__OutputsCurrent -+ -+ @OutputsCurrent.setter -+ def OutputsCurrent(self, val): -+ self.__OutputsCurrent = val -+ -+ @property -+ def OutputsPower(self): -+ return self.__OutputsPower -+ -+ @OutputsPower.setter -+ def OutputsPower(self, val): -+ self.__OutputsPower = val -+ -+ @property -+ def InputStatus(self): -+ if self.__InputStatus_config is None: -+ return None -+ if self.present is False: -+ self.__InputStatus = False -+ else: -+ ret, val = self.get_value(self.__InputStatus_config) -+ mask = self.__InputStatus_config.get("mask") -+ if ret is True: -+ if isinstance(val, str): -+ value = int(val, 16) -+ else: -+ value = val -+ ttt = value & mask -+ okval = self.__InputStatus_config.get("okval", 0) -+ if ttt == okval: -+ self.__InputStatus = True -+ else: -+ self.__InputStatus = False -+ else: -+ self.__InputStatus = False -+ return self.__InputStatus -+ -+ @InputStatus.setter -+ def InputStatus(self, val): -+ self.__InputStatus = val -+ -+ @property -+ def TempStatus(self): -+ if self.__TempStatus_config is None: -+ return None -+ if self.present is False: -+ self.__TempStatus = False -+ else: -+ ret, val = self.get_value(self.__TempStatus_config) -+ mask = self.__TempStatus_config.get("mask") -+ if ret is True: -+ if isinstance(val, str): -+ value = int(val, 16) -+ else: -+ value = val -+ ttt = value & mask -+ okval = self.__TempStatus_config.get("okval", 0) -+ if ttt == okval: -+ self.__TempStatus = True -+ else: -+ self.__TempStatus = False -+ else: -+ self.__TempStatus = False -+ return self.__TempStatus -+ -+ @TempStatus.setter -+ def TempStatus(self, val): -+ self.__TempStatus = val -+ -+ @property -+ def FanStatus(self): -+ if self.__FanStatus_config is None: -+ return None -+ if self.present is False: -+ self.__FanStatus = False -+ else: -+ ret, val = self.get_value(self.__FanStatus_config) -+ mask = self.__FanStatus_config.get("mask") -+ if ret is True: -+ if isinstance(val, str): -+ value = int(val, 16) -+ else: -+ value = val -+ ttt = value & mask -+ okval = self.__FanStatus_config.get("okval", 0) -+ if ttt == okval: -+ self.__FanStatus = True -+ else: -+ self.__FanStatus = False -+ else: -+ self.__FanStatus = False -+ return self.__FanStatus -+ -+ @FanStatus.setter -+ def FanStatus(self, val): -+ self.__FanStatus = val -+ -+ def get_input_type_pmbus(self): -+ psutypedecode = self.__InputsType_config.get('psutypedecode', {}) -+ if self.present is False: -+ self.__InputsType = psutypedecode.get(0x00) -+ else: -+ ret, val = self.get_value(self.__InputsType_config) -+ self.__InputsType = self.__InputsType_config.get(val, None) -+ if self.__InputsType is not None: -+ return self.__InputsType -+ if ret is True and val in psutypedecode: -+ self.__InputsType = psutypedecode.get(val) -+ else: -+ self.__InputsType = psutypedecode.get(0x00) -+ return self.__InputsType -+ -+ def get_input_type_fru(self): -+ self.__InputsType = 'N/A' -+ if self.productPartModelName is None: -+ ret = self.get_fru_info() -+ if ret is False: -+ return self.__InputsType -+ psutypedecode = self.__InputsType_config.get('psutypedecode', {}) -+ for key, value in psutypedecode.items(): -+ if self.productPartModelName in value: -+ self.__InputsType = key -+ return self.__InputsType -+ -+ @property -+ def InputsType(self): -+ gettype = self.__InputsType_config.get('gettype', "pmbus") -+ if gettype == "pmbus": -+ return self.get_input_type_pmbus() -+ -+ if gettype == "fru": -+ return self.get_input_type_fru() -+ -+ self.__InputsType = 'N/A' -+ return self.__InputsType -+ -+ @InputsType.setter -+ def InputsType(self, val): -+ self.__InputsType = val -+ -+ @property -+ def FanSpeedMin(self): -+ return self.__FanSpeedMin -+ -+ @FanSpeedMin.setter -+ def FanSpeedMin(self, val): -+ self.__FanSpeedMin = val -+ -+ @property -+ def FanSpeedMax(self): -+ return self.__FanSpeedMax -+ -+ @FanSpeedMax.setter -+ def FanSpeedMax(self, val): -+ self.__FanSpeedMax = val -+ -+ @property -+ def FanSpeedTolerance(self): -+ return self.__FanSpeedTolerance -+ -+ @FanSpeedTolerance.setter -+ def FanSpeedTolerance(self, val): -+ self.__FanSpeedTolerance = val -+ -+ @property -+ def OutputStatus(self): -+ if self.__OutputStatus_config is None: -+ return None -+ if self.present is False: -+ self.__OutputStatus = False -+ else: -+ ret, val = self.get_value(self.__OutputStatus_config) -+ mask = self.__OutputStatus_config.get("mask") -+ if ret is True: -+ if isinstance(val, str): -+ value = int(val, 16) -+ else: -+ value = val -+ ttt = value & mask -+ okval = self.__OutputStatus_config.get("okval", 0) -+ if ttt == okval: -+ self.__OutputStatus = True -+ else: -+ self.__OutputStatus = False -+ else: -+ self.__OutputStatus = False -+ return self.__OutputStatus -+ -+ @OutputStatus.setter -+ def OutputStatus(self, val): -+ self.__OutputStatus = val -+ -+ @property -+ def FanSpeed(self): -+ return self.__FanSpeed -+ -+ @FanSpeed.setter -+ def FanSpeed(self, val): -+ self.__FanSpeed = val -+ -+ @property -+ def Temperature(self): -+ return self.__Temperature -+ -+ @Temperature.setter -+ def Temperature(self, val): -+ self.__Temperature = val -+ -+ @property -+ def Temperature_config(self): -+ return self.__Temperature_config -+ -+ @Temperature_config.setter -+ def Temperature_config(self, val): -+ self.__Temperature_config = val -+ -+ @property -+ def AirFlowconifg(self): -+ return self.__AirFlowconifg -+ -+ @AirFlowconifg.setter -+ def AirFlowconifg(self, val): -+ self.__AirFlowconifg = val -+ -+ @property -+ def psu_display_name_conifg(self): -+ return self.__psu_display_name_conifg -+ -+ @psu_display_name_conifg.setter -+ def psu_display_name_conifg(self, val): -+ self.__psu_display_name_conifg = val -+ -+ @property -+ def pmbus(self): -+ return self.__pmbus -+ -+ @pmbus.setter -+ def pmbus(self, val): -+ self.__pmbus = val -+ -+ @property -+ def e2loc(self): -+ return self.__e2loc -+ -+ @e2loc.setter -+ def e2loc(self, val): -+ self.__e2loc = val -+ -+ @property -+ def AirFlow(self): -+ return self.__AirFlow -+ -+ @AirFlow.setter -+ def AirFlow(self, val): -+ self.__AirFlow = val -+ -+ @property -+ def psu_display_name(self): -+ return self.__psu_display_name -+ -+ @psu_display_name.setter -+ def psu_display_name(self, val): -+ self.__psu_display_name = val -+ -+ @property -+ def psu_not_present_pwm(self): -+ return self.__psu_not_present_pwm -+ -+ @psu_not_present_pwm.setter -+ def psu_not_present_pwm(self, val): -+ self.__psu_not_present_pwm = val -+ -+ @property -+ def present(self): -+ ret, val = self.get_value(self.__presentconfig) -+ if ret is False or val is None: -+ return False -+ mask = self.__presentconfig.get("mask") -+ if isinstance(val, str): -+ value = int(val, 16) -+ else: -+ value = val -+ ttt = value & mask -+ okval = self.__presentconfig.get("okval", 0) -+ if ttt == okval: -+ return True -+ return False -+ -+ @property -+ def productManufacturer(self): -+ return self.__productManufacturer -+ -+ @productManufacturer.setter -+ def productManufacturer(self, val): -+ self.__productManufacturer = val -+ -+ @property -+ def productName(self): -+ return self.__productName -+ -+ @productName.setter -+ def productName(self, val): -+ self.__productName = val -+ -+ @property -+ def productPartModelName(self): -+ return self.__productPartModelName -+ -+ @productPartModelName.setter -+ def productPartModelName(self, val): -+ self.__productPartModelName = val -+ -+ @property -+ def productVersion(self): -+ return self.__productVersion -+ -+ @productVersion.setter -+ def productVersion(self, val): -+ self.__productVersion = val -+ -+ @property -+ def productSerialNumber(self): -+ return self.__productSerialNumber -+ -+ @productSerialNumber.setter -+ def productSerialNumber(self, val): -+ self.__productSerialNumber = val -+ -+ @property -+ def psu_sn_sysfs(self): -+ if self.__psu_sn_config is None: -+ return None -+ ret, val = self.get_value(self.__psu_sn_config) -+ if ret is False or val is None: -+ return None -+ return val -+ -+ @property -+ def psu_hw_sysfs(self): -+ if self.__psu_hw_config is None: -+ return None -+ ret, val = self.get_value(self.__psu_hw_config) -+ if ret is False or val is None: -+ return None -+ return val -+ -+ @property -+ def psu_pn_sysfs(self): -+ if self.__psu_pn_config is None: -+ return None -+ ret, val = self.get_value(self.__psu_pn_config) -+ if ret is False or val is None: -+ return None -+ return val -+ -+ @property -+ def psu_vendor_sysfs(self): -+ if self.__psu_vendor_config is None: -+ return None -+ ret, val = self.get_value(self.__psu_vendor_config) -+ if ret is False or val is None: -+ return None -+ return val -+ -+ def __str__(self): -+ formatstr = \ -+ "name : %s \n" \ -+ "productManufacturer : %s \n" \ -+ "productName : %s \n" \ -+ "productPartModelName: %s \n" \ -+ "productVersion : %s \n" \ -+ "productSerialNumber : %s \n" \ -+ "AirFlow : %s \n" \ -+ -+ tmpstr = formatstr % (self.name, self.productManufacturer, -+ self.productName, self.productPartModelName, -+ self.productVersion, self.productSerialNumber, self.AirFlow) -+ return tmpstr -+ -+ def get_fan_speed_pwm(self): -+ if self.pmbus is None: -+ return None -+ if self.present is False: -+ return self.psu_not_present_pwm -+ selfconfig = {} -+ selfconfig['bus'] = self.pmbus['bus'] -+ selfconfig['addr'] = self.pmbus['addr'] -+ selfconfig['way'] = 'i2cword' -+ selfconfig['offset'] = 0x3b -+ ret, val = self.get_value(selfconfig) -+ if ret is True: -+ return val -+ return None -+ -+ def set_fan_speed_pwm(self, pwm): -+ ''' -+ pmbus -+ if duty: -+ i2cset -f -y 0x3b 0x0064 wp -+ ''' -+ if self.present is False: -+ return None -+ -+ if self.pmbus is None: -+ return None -+ -+ if 0 <= pwm <= 100: -+ # enable duty first -+ selfconfig = {} -+ -+ selfconfig['bus'] = self.pmbus['bus'] -+ selfconfig['addr'] = self.pmbus['addr'] -+ selfconfig['way'] = 'i2cpec' -+ selfconfig['offset'] = 0x3a -+ self.set_value(selfconfig, 0x80) -+ -+ selfconfig['way'] = 'i2cwordpec' -+ selfconfig['offset'] = 0x3b -+ bytetmp = pwm -+ ret, val = self.set_value(selfconfig, int(bytetmp)) -+ if ret is True: -+ return True -+ return None -+ raise Exception("pwm not in range [0,100]") -+ -+ def get_fru_info_by_sysfs(self): -+ try: -+ psu_sn = self.psu_sn_sysfs -+ psu_hw = self.psu_hw_sysfs -+ psu_pn = self.psu_pn_sysfs -+ psu_vendor = self.psu_vendor_sysfs -+ if psu_sn is None or psu_hw is None or psu_pn is None or psu_vendor is None: -+ return False -+ self.productSerialNumber = psu_sn.strip().replace(chr(0), "") -+ self.productVersion = psu_hw.strip() -+ self.productPartModelName = psu_pn.strip() -+ self.productManufacturer = psu_vendor.strip().replace(chr(0), "") -+ except Exception: -+ self.productSerialNumber = None -+ self.productVersion = None -+ self.productPartModelName = None -+ self.productManufacturer = None -+ return False -+ return True -+ -+ def get_fru_info_by_decode(self): -+ try: -+ eeprom = self.get_eeprom_info(self.e2loc) -+ if eeprom is None: -+ raise Exception("%s:value is none" % self.name) -+ fru = ipmifru() -+ if isinstance(eeprom, bytes): -+ eeprom = self.byteTostr(eeprom) -+ fru.decodeBin(eeprom) -+ if fru.productInfoArea is not None: -+ self.productManufacturer = fru.productInfoArea.productManufacturer.strip() -+ self.productName = fru.productInfoArea.productName.strip() -+ self.productPartModelName = fru.productInfoArea.productPartModelName.strip() -+ self.productVersion = fru.productInfoArea.productVersion.strip() -+ self.productSerialNumber = fru.productInfoArea.productSerialNumber.strip().replace(chr(0), "") -+ except Exception: -+ self.productManufacturer = None -+ self.productName = None -+ self.productPartModelName = None -+ self.productVersion = None -+ self.productSerialNumber = None -+ return False -+ return True -+ -+ def get_custfru_info_by_decode(self): -+ try: -+ eeprom = self.get_eeprom_info(self.e2loc) -+ if eeprom is None: -+ raise Exception("%s:value is none" % self.name) -+ custfru = CustFru() -+ if isinstance(eeprom, bytes): -+ eeprom = self.byteTostr(eeprom) -+ custfru.decode(eeprom) -+ self.productManufacturer = custfru.manufacturer.strip() -+ self.productName = custfru.product_name.strip() -+ self.productPartModelName = custfru.product_name.strip() -+ self.productVersion = custfru.version.strip() -+ self.productSerialNumber = custfru.serial_number.strip().replace(chr(0), "") -+ except Exception: -+ self.productManufacturer = None -+ self.productName = None -+ self.productPartModelName = None -+ self.productVersion = None -+ self.productSerialNumber = None -+ return False -+ return True -+ -+ def get_fru_info(self): -+ try: -+ if self.present is not True: -+ raise Exception("%s: not present" % self.name) -+ -+ if self.get_fru_info_by_sysfs() is True: -+ return True -+ -+ if self.e2_type == "fru": -+ return self.get_fru_info_by_decode() -+ -+ if self.e2_type == "custfru": -+ return self.get_custfru_info_by_decode() -+ -+ raise Exception("%s: unsupport e2_type: %s" % (self.name, self.e2_type)) -+ except Exception: -+ self.productManufacturer = None -+ self.productName = None -+ self.productPartModelName = None -+ self.productVersion = None -+ self.productSerialNumber = None -+ return False -+ -+ def get_AirFlow(self): -+ if self.productPartModelName is None: -+ ret = self.get_fru_info() -+ if ret is False: -+ self.AirFlow = None -+ return False -+ if self.AirFlowconifg is None: -+ self.AirFlow = None -+ return False -+ for i in self.AirFlowconifg: -+ if self.productPartModelName in self.AirFlowconifg[i]: -+ self.AirFlow = i -+ return True -+ self.AirFlow = None -+ return False -+ -+ def get_psu_display_name(self): -+ if self.productPartModelName is None: -+ ret = self.get_fru_info() -+ if ret is False: -+ self.psu_display_name = None -+ return False -+ if self.psu_display_name_conifg is None: -+ self.psu_display_name = self.productPartModelName -+ return False -+ for i in self.psu_display_name_conifg: -+ if self.productPartModelName in self.psu_display_name_conifg[i]: -+ self.psu_display_name = i -+ return True -+ self.psu_display_name = self.productPartModelName -+ return False -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/rotor.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/rotor.py -new file mode 100644 -index 000000000..2b4e4ffd5 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/rotor.py -@@ -0,0 +1,149 @@ -+#!/usr/bin/env python3 -+####################################################### -+# -+# rotor.py -+# Python implementation of the Class rotor -+# -+####################################################### -+from plat_hal.devicebase import devicebase -+from plat_hal.sensor import sensor -+ -+ -+class rotor(devicebase): -+ __rotor_Running = None -+ __rotor_HwAlarm_conf = None -+ __rotor_Speed = None -+ __rotor_run_conf = None -+ __Speedconfig = None -+ __i2c_speed = None -+ __SpeedMin = None -+ __SpeedMax = None -+ __SpeedTolerance = None -+ -+ def __init__(self, conf=None): -+ self.name = conf.get('name', None) -+ self.rotor_HwAlarm_conf = conf.get('HwAlarm', None) -+ self.rotor_run_conf = conf.get('Running', None) -+ self.SpeedMin = conf.get('SpeedMin', None) -+ self.SpeedMax = conf.get('SpeedMax', None) -+ self.Tolerance = conf.get('tolerance', 30) -+ self.rotor_Speed = sensor(conf.get('Speed', None)) -+ self.Speedconfig = conf.get('Set_speed', None) -+ -+ def getRunning(self): -+ ret, val = self.get_value(self.rotor_run_conf) -+ if ret is False or val is None: -+ return False -+ if isinstance(val, str): -+ value = int(val, 16) -+ else: -+ value = val -+ mask = self.rotor_run_conf.get("mask") -+ is_runing_value = self.rotor_run_conf.get("is_runing") -+ flag = value & mask -+ if flag == is_runing_value: -+ return True -+ return False -+ -+ @property -+ def SpeedMin(self): -+ return self.__SpeedMin -+ -+ @SpeedMin.setter -+ def SpeedMin(self, val): -+ self.__SpeedMin = val -+ -+ @property -+ def SpeedMax(self): -+ return self.__SpeedMax -+ -+ @SpeedMax.setter -+ def SpeedMax(self, val): -+ self.__SpeedMax = val -+ -+ @property -+ def Tolerance(self): -+ return self.__SpeedTolerance -+ -+ @Tolerance.setter -+ def Tolerance(self, val): -+ self.__SpeedTolerance = val -+ -+ @property -+ def i2c_speed(self): -+ ret, val = self.get_value(self.Speedconfig) -+ if ret is False: -+ return None -+ if val is not None: -+ self.__i2c_speed = val -+ return self.__i2c_speed -+ -+ def feed_watchdog(self): -+ ret, val = self.get_value(self.Speedconfig) -+ if ret is False: -+ return False, None -+ if val is not None: -+ ret, val = self.set_value(self.Speedconfig, val) -+ return ret, val -+ return False, None -+ -+ @i2c_speed.setter -+ def i2c_speed(self, val): -+ self.__i2c_speed = val -+ -+ @property -+ def Speedconfig(self): -+ return self.__Speedconfig -+ -+ @Speedconfig.setter -+ def Speedconfig(self, val): -+ self.__Speedconfig = val -+ -+ @property -+ def rotor_run_conf(self): -+ return self.__rotor_run_conf -+ -+ @rotor_run_conf.setter -+ def rotor_run_conf(self, val): -+ self.__rotor_run_conf = val -+ -+ @property -+ def rotor_Speed(self): -+ return self.__rotor_Speed -+ -+ @rotor_Speed.setter -+ def rotor_Speed(self, val): -+ self.__rotor_Speed = val -+ -+ @property -+ def rotor_HwAlarm(self): -+ ret, val = self.get_value(self.rotor_HwAlarm_conf) -+ mask = self.rotor_HwAlarm_conf.get("mask") -+ no_alarm_value = self.rotor_HwAlarm_conf.get("no_alarm") -+ if ret is False or val is None: -+ return False -+ if isinstance(val, str): -+ value = int(val, 16) -+ else: -+ value = val -+ flag = value & mask -+ if flag == no_alarm_value: -+ return False -+ return True -+ -+ @property -+ def rotor_HwAlarm_conf(self): -+ return self.__rotor_HwAlarm_conf -+ -+ @rotor_HwAlarm_conf.setter -+ def rotor_HwAlarm_conf(self, val): -+ self.__rotor_HwAlarm_conf = val -+ -+ @property -+ def rotor_Running(self): -+ self.__rotor_Running = self.getRunning() -+ return self.__rotor_Running -+ -+ @rotor_Running.setter -+ def rotor_Running(self, val): -+ self.__rotor_Running = val -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/sensor.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/sensor.py -new file mode 100644 -index 000000000..af2a5384b ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/sensor.py -@@ -0,0 +1,274 @@ -+#!/usr/bin/env python3 -+####################################################### -+# -+# sensor.py -+# Python implementation of the Class sensor -+# -+####################################################### -+import time -+from plat_hal.devicebase import devicebase -+ -+ -+class sensor(devicebase): -+ -+ __Value = None -+ __Min = None -+ __Max = None -+ __Low = None -+ __High = None -+ __ValueConfig = None -+ __Flag = None -+ __Unit = None -+ __format = None -+ __read_times = None -+ -+ __Min_config = None -+ __Max_config = None -+ __Low_config = None -+ __High_config = None -+ -+ @property -+ def Min_config(self): -+ return self.__Min_config -+ -+ @Min_config.setter -+ def Min_config(self, val): -+ self.__Min_config = val -+ -+ @property -+ def Max_config(self): -+ return self.__Max_config -+ -+ @Max_config.setter -+ def Max_config(self, val): -+ self.__Max_config = val -+ -+ @property -+ def Low_config(self): -+ return self.__Low_config -+ -+ @Low_config.setter -+ def Low_config(self, val): -+ self.__Low_config = val -+ -+ @property -+ def High_config(self): -+ return self.__High_config -+ -+ @High_config.setter -+ def High_config(self, val): -+ self.__High_config = val -+ -+ @property -+ def Unit(self): -+ return self.__Unit -+ -+ @Unit.setter -+ def Unit(self, val): -+ self.__Unit = val -+ -+ @property -+ def format(self): -+ return self.__format -+ -+ @format.setter -+ def format(self, val): -+ self.__format = val -+ -+ @property -+ def read_times(self): -+ return self.__read_times -+ -+ @read_times.setter -+ def read_times(self, val): -+ self.__read_times = val -+ -+ @property -+ def ValueConfig(self): -+ return self.__ValueConfig -+ -+ @ValueConfig.setter -+ def ValueConfig(self, val): -+ self.__ValueConfig = val -+ -+ @property -+ def Flag(self): -+ return self.__Flag -+ -+ @Flag.setter -+ def Flag(self, val): -+ self.__Flag = val -+ -+ def get_median(self, value_config, read_times): -+ val_list = [] -+ for i in range(0, read_times): -+ ret, real_value = self.get_value(value_config) -+ if i != (read_times - 1): -+ time.sleep(0.01) -+ if ret is False or real_value is None: -+ continue -+ val_list.append(real_value) -+ val_list.sort() -+ if val_list: -+ return True, val_list[int((len(val_list) - 1) / 2)] -+ return False, None -+ -+ @property -+ def Value(self): -+ try: -+ ret, val = self.get_median(self.ValueConfig, self.read_times) -+ if ret is False or val is None: -+ return None -+ if self.format is None: -+ self.__Value = int(val) -+ else: -+ self.__Value = self.get_format_value(self.format % val) -+ self.__Value = round(float(self.__Value), 3) -+ except Exception: -+ return None -+ return self.__Value -+ -+ @Value.setter -+ def Value(self, val): -+ self.__Value = val -+ -+ @property -+ def Min(self): -+ try: -+ if isinstance(self.Min_config, dict): -+ if self.call_back is None: -+ self.__Min = self.Min_config.get("other") -+ else: -+ ret = self.call_back() -+ if ret not in self.Min_config: -+ self.__Min = self.Min_config.get("other") -+ else: -+ self.__Min = self.Min_config[ret] -+ else: -+ self.__Min = self.Min_config -+ -+ if self.__Min is None: -+ return None -+ -+ if self.format is not None: -+ self.__Min = self.get_format_value(self.format % self.__Min) -+ self.__Min = round(float(self.__Min), 3) -+ except Exception: -+ return None -+ return self.__Min -+ -+ @Min.setter -+ def Min(self, val): -+ self.__Min = val -+ -+ @property -+ def Max(self): -+ try: -+ if isinstance(self.Max_config, dict): -+ if self.call_back is None: -+ self.__Max = self.Max_config.get("other") -+ else: -+ ret = self.call_back() -+ if ret not in self.Max_config: -+ self.__Max = self.Max_config.get("other") -+ else: -+ self.__Max = self.Max_config[ret] -+ else: -+ self.__Max = self.Max_config -+ -+ if self.__Max is None: -+ return None -+ -+ if self.format is not None: -+ self.__Max = self.get_format_value(self.format % self.__Max) -+ self.__Max = round(float(self.__Max), 3) -+ except Exception: -+ return None -+ return self.__Max -+ -+ @Max.setter -+ def Max(self, val): -+ self.__Max = val -+ -+ @property -+ def Low(self): -+ try: -+ if isinstance(self.Low_config, dict): -+ if self.call_back is None: -+ self.__Low = self.Low_config.get("other") -+ else: -+ ret = self.call_back() -+ if ret not in self.Low_config: -+ self.__Low = self.Low_config.get("other") -+ else: -+ self.__Low = self.Low_config[ret] -+ else: -+ self.__Low = self.Low_config -+ -+ if self.__Low is None: -+ return None -+ -+ if self.format is not None: -+ self.__Low = self.get_format_value(self.format % self.__Low) -+ self.__Low = round(float(self.__Low), 3) -+ except Exception: -+ return None -+ return self.__Low -+ -+ @Low.setter -+ def Low(self, val): -+ self.__Low = val -+ -+ @property -+ def High(self): -+ try: -+ if isinstance(self.High_config, dict): -+ if self.call_back is None: -+ self.__High = self.High_config.get("other") -+ else: -+ ret = self.call_back() -+ if ret not in self.High_config: -+ self.__High = self.High_config.get("other") -+ else: -+ self.__High = self.High_config[ret] -+ else: -+ self.__High = self.High_config -+ -+ if self.__High is None: -+ return None -+ -+ if self.format is not None: -+ self.__High = self.get_format_value(self.format % self.__High) -+ self.__High = round(float(self.__High), 3) -+ except Exception: -+ return None -+ return self.__High -+ -+ @High.setter -+ def High(self, val): -+ self.__High = val -+ -+ def __init__(self, conf=None, call_back=None): -+ self.ValueConfig = conf.get("value", None) -+ self.Flag = conf.get("flag", None) -+ self.Min_config = conf.get("Min", None) -+ self.Max_config = conf.get("Max", None) -+ self.Low_config = conf.get("Low", None) -+ self.High_config = conf.get("High", None) -+ self.Unit = conf.get('Unit', None) -+ self.format = conf.get('format', None) -+ self.read_times = conf.get('read_times', 1) -+ self.call_back = call_back -+ -+ def __str__(self): -+ formatstr = \ -+ "ValueConfig: : %s \n" \ -+ "Min : %s \n" \ -+ "Max : %s \n" \ -+ "Unit : %s \n" \ -+ "format: : %s \n" -+ -+ tmpstr = formatstr % (self.ValueConfig, self.Min, -+ self.Max, self.Unit, -+ self.format) -+ return tmpstr -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/temp.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/temp.py -new file mode 100644 -index 000000000..a202c2033 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/temp.py -@@ -0,0 +1,139 @@ -+#!/usr/bin/env python3 -+####################################################### -+# -+# temp.py -+# Python implementation of the Class temp -+# -+####################################################### -+import os -+import syslog -+from plat_hal.sensor import sensor -+ -+ -+PLATFORM_HAL_TEMP_DEBUG_FILE = "/etc/.platform_hal_temp_debug_flag" -+ -+ -+def platform_hal_temp_debug(s): -+ if os.path.exists(PLATFORM_HAL_TEMP_DEBUG_FILE): -+ syslog.openlog("PLATFORM_HAL_TEPM", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+class temp(sensor): -+ def __init__(self, conf=None): -+ super(temp, self).__init__(conf.get('Temperature', None)) -+ self.name = conf.get("name", None) -+ self.temp_id = conf.get("temp_id", None) -+ self.api_name = conf.get("api_name", self.name) -+ self.fix_value = conf.get("fix_value", None) -+ self.temp_invalid = conf.get("invalid", None) -+ self.temp_error = conf.get("error", None) -+ -+ def temp_cali_by_fan_pwm(self, param, origin_value): -+ fan_pwm_conf = param.get("fan_pwm") -+ temp_fix_list = param.get("temp_fix_list") -+ -+ ret, val = self.get_value(fan_pwm_conf) -+ if ret is False or val is None: -+ platform_hal_temp_debug("temp calibration get fan pwm failed, msg: %s, return None" % (val)) -+ return None -+ -+ fan_pwm = int(val) -+ for item in temp_fix_list: -+ if item["min"] <= fan_pwm <= item["max"]: -+ fix_value = origin_value + item["fix"] -+ platform_hal_temp_debug("temp calibration by fan pwm, origin_value: %s, pwm: %s, fix_value: %s" % -+ (origin_value, fan_pwm, fix_value)) -+ return fix_value -+ platform_hal_temp_debug("temp calibration by fan pwm, origin_value: %s, pwm: %s, not match return None" % -+ (origin_value, fan_pwm)) -+ return None -+ -+ def fix_temp_value(self, origin_value): -+ try: -+ fix_type = self.fix_value.get("fix_type") -+ -+ if fix_type == "func": -+ func_name = self.fix_value.get("func_name") -+ func_param = self.fix_value.get("func_param") -+ func = getattr(self, func_name) -+ if func is None: -+ platform_hal_temp_debug("function %s, not defined" % func_name) -+ return None -+ value = func(func_param, origin_value) -+ return value -+ -+ if fix_type == "config": -+ coefficient = self.fix_value.get("coefficient", 1) -+ addend = self.fix_value.get("addend", 0) -+ value = (origin_value + addend) * coefficient -+ platform_hal_temp_debug("temp calibration by config, coefficient: %s, addend: %s, origin_value: %s, fix_value: %s" % -+ (coefficient, addend, origin_value, value)) -+ return value -+ -+ platform_hal_temp_debug("unsupport fix type: %s, return origin value: %s" % (fix_type, origin_value)) -+ return origin_value -+ except Exception as e: -+ platform_hal_temp_debug("fix_temp_value raise exception, msg: %s" % (str(e))) -+ return None -+ -+ def get_max_value(self, conf): -+ try: -+ ret, val = self.get_value(conf) -+ if ret is False or val is None: -+ return None -+ return val -+ except Exception: -+ return None -+ -+ def check_flag(self): -+ try: -+ okbit = self.Flag.get('okbit') -+ okval = self.Flag.get('okval') -+ ret, val = self.get_value(self.Flag) -+ if (ret is False) or (val is None): -+ return False -+ val_t = (int(val) & (1 << okbit)) >> okbit -+ if val_t != okval: -+ return False -+ except Exception: -+ return False -+ return True -+ -+ @property -+ def Value(self): -+ try: -+ if self.Flag is not None: -+ if self.check_flag() is False: -+ return None -+ if isinstance(self.ValueConfig, list): -+ max_val = None -+ for i in self.ValueConfig: -+ tmp = self.get_max_value(i) -+ if tmp is None: -+ continue -+ if max_val is None or max_val < tmp: -+ max_val = tmp -+ if max_val is None: -+ return None -+ if self.format is None: -+ self.__Value = int(max_val) -+ else: -+ self.__Value = self.get_format_value(self.format % max_val) -+ else: -+ ret, val = self.get_value(self.ValueConfig) -+ if ret is False or val is None: -+ return None -+ if self.format is None: -+ self.__Value = int(val) -+ else: -+ self.__Value = self.get_format_value(self.format % val) -+ except Exception: -+ return None -+ if self.fix_value is not None and self.__Value != self.temp_invalid and self.__Value != self.temp_error: -+ self.__Value = self.fix_temp_value(self.__Value) -+ return self.__Value -+ -+ @Value.setter -+ def Value(self, val): -+ self.__Value = val -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/__init__.py -new file mode 100644 -index 000000000..e69de29bb -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/baseutil.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/baseutil.py -new file mode 100644 -index 000000000..340a1f7a7 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/baseutil.py -@@ -0,0 +1,38 @@ -+#!/usr/bin/env python3 -+import os -+ -+ -+def get_machine_info(): -+ if not os.path.isfile('/host/machine.conf'): -+ return None -+ machine_vars = {} -+ with open('/host/machine.conf') as machine_file: -+ for line in machine_file: -+ tokens = line.split('=') -+ if len(tokens) < 2: -+ continue -+ machine_vars[tokens[0]] = tokens[1].strip() -+ return machine_vars -+ -+ -+def get_platform_info(machine_info): -+ if machine_info is not None: -+ if 'onie_platform' in machine_info: -+ return machine_info['onie_platform'] -+ if 'aboot_platform' in machine_info: -+ return machine_info['aboot_platform'] -+ return None -+ -+ -+def get_board_id(machine_info): -+ if machine_info is not None: -+ if 'onie_board_id' in machine_info: -+ return machine_info['onie_board_id'].lower() -+ return "NA" -+ -+ -+def get_onie_machine(machine_info): -+ if machine_info is not None: -+ if 'onie_machine' in machine_info: -+ return machine_info['onie_machine'] -+ return None -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/smbus.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/smbus.py -new file mode 100644 -index 000000000..5f1659b3b ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/smbus.py -@@ -0,0 +1,772 @@ -+#!/usr/bin/env python3 -+# smbus2 - A drop-in replacement for smbus-cffi/smbus-python -+# The MIT License (MIT) -+# Copyright (c) 2017 Karl-Petter Lindegaard -+# -+# Permission is hereby granted, free of charge, to any person obtaining a copy -+# of this software and associated documentation files (the "Software"), to deal -+# in the Software without restriction, including without limitation the rights -+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+# copies of the Software, and to permit persons to whom the Software is -+# furnished to do so, subject to the following conditions: -+# -+# The above copyright notice and this permission notice shall be included in all -+# copies or substantial portions of the Software. -+# -+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -+# SOFTWARE. -+ -+import os -+import sys -+from fcntl import ioctl -+from ctypes import c_uint32, c_uint8, c_uint16, c_char, POINTER, Structure, Array, Union, create_string_buffer, string_at -+ -+ -+# Commands from uapi/linux/i2c-dev.h -+I2C_SLAVE = 0x0703 # Use this slave address -+I2C_SLAVE_FORCE = 0x0706 # Use this slave address, even if it is already in use by a driver! -+I2C_FUNCS = 0x0705 # Get the adapter functionality mask -+I2C_RDWR = 0x0707 # Combined R/W transfer (one STOP only) -+I2C_SMBUS = 0x0720 # SMBus transfer. Takes pointer to i2c_smbus_ioctl_data -+I2C_PEC = 0x0708 -+ -+# SMBus transfer read or write markers from uapi/linux/i2c.h -+I2C_SMBUS_WRITE = 0 -+I2C_SMBUS_READ = 1 -+ -+# Size identifiers uapi/linux/i2c.h -+I2C_SMBUS_QUICK = 0 -+I2C_SMBUS_BYTE = 1 -+I2C_SMBUS_BYTE_DATA = 2 -+I2C_SMBUS_WORD_DATA = 3 -+I2C_SMBUS_PROC_CALL = 4 -+# This isn't supported by Pure-I2C drivers with SMBUS emulation, like those in RaspberryPi, OrangePi, etc :( -+I2C_SMBUS_BLOCK_DATA = 5 -+I2C_SMBUS_BLOCK_PROC_CALL = 7 # Like I2C_SMBUS_BLOCK_DATA, it isn't supported by Pure-I2C drivers either. -+I2C_SMBUS_I2C_BLOCK_DATA = 8 -+I2C_SMBUS_BLOCK_MAX = 32 -+ -+# To determine what functionality is present (uapi/linux/i2c.h) -+try: -+ from enum import IntFlag -+except ImportError: -+ IntFlag = int -+ -+ -+class I2cFunc(IntFlag): -+ """ -+ These flags identify the operations supported by an I2C/SMBus device. -+ -+ You can test these flags on your `smbus.funcs` -+ -+ On newer python versions, I2cFunc is an IntFlag enum, but it -+ falls back to class with a bunch of int constants on older releases. -+ """ -+ I2C = 0x00000001 -+ ADDR_10BIT = 0x00000002 -+ PROTOCOL_MANGLING = 0x00000004 # I2C_M_IGNORE_NAK etc. -+ SMBUS_PEC = 0x00000008 -+ NOSTART = 0x00000010 # I2C_M_NOSTART -+ SLAVE = 0x00000020 -+ SMBUS_BLOCK_PROC_CALL = 0x00008000 # SMBus 2.0 -+ SMBUS_QUICK = 0x00010000 -+ SMBUS_READ_BYTE = 0x00020000 -+ SMBUS_WRITE_BYTE = 0x00040000 -+ SMBUS_READ_BYTE_DATA = 0x00080000 -+ SMBUS_WRITE_BYTE_DATA = 0x00100000 -+ SMBUS_READ_WORD_DATA = 0x00200000 -+ SMBUS_WRITE_WORD_DATA = 0x00400000 -+ SMBUS_PROC_CALL = 0x00800000 -+ SMBUS_READ_BLOCK_DATA = 0x01000000 -+ SMBUS_WRITE_BLOCK_DATA = 0x02000000 -+ SMBUS_READ_I2C_BLOCK = 0x04000000 # I2C-like block xfer -+ SMBUS_WRITE_I2C_BLOCK = 0x08000000 # w/ 1-byte reg. addr. -+ SMBUS_HOST_NOTIFY = 0x10000000 -+ -+ SMBUS_BYTE = 0x00060000 -+ SMBUS_BYTE_DATA = 0x00180000 -+ SMBUS_WORD_DATA = 0x00600000 -+ SMBUS_BLOCK_DATA = 0x03000000 -+ SMBUS_I2C_BLOCK = 0x0c000000 -+ SMBUS_EMUL = 0x0eff0008 -+ -+ -+# i2c_msg flags from uapi/linux/i2c.h -+I2C_M_RD = 0x0001 -+ -+# Pointer definitions -+LP_c_uint8 = POINTER(c_uint8) -+LP_c_uint16 = POINTER(c_uint16) -+LP_c_uint32 = POINTER(c_uint32) -+ -+ -+############################################################# -+# Type definitions as in i2c.h -+ -+ -+class i2c_smbus_data(Array): -+ """ -+ Adaptation of the i2c_smbus_data union in ``i2c.h``. -+ -+ Data for SMBus messages. -+ """ -+ _length_ = I2C_SMBUS_BLOCK_MAX + 2 -+ _type_ = c_uint8 -+ -+ -+class union_i2c_smbus_data(Union): -+ _fields_ = [ -+ ("byte", c_uint8), -+ ("word", c_uint16), -+ ("block", i2c_smbus_data) -+ ] -+ -+ -+union_pointer_type = POINTER(union_i2c_smbus_data) -+ -+ -+class i2c_smbus_ioctl_data(Structure): -+ """ -+ As defined in ``i2c-dev.h``. -+ """ -+ _fields_ = [ -+ ('read_write', c_uint8), -+ ('command', c_uint8), -+ ('size', c_uint32), -+ ('data', union_pointer_type)] -+ __slots__ = [name for name, type in _fields_] -+ -+ @staticmethod -+ def create(read_write=I2C_SMBUS_READ, command=0, size=I2C_SMBUS_BYTE_DATA): -+ u = union_i2c_smbus_data() -+ return i2c_smbus_ioctl_data( -+ read_write=read_write, command=command, size=size, -+ data=union_pointer_type(u)) -+ -+ -+############################################################# -+# Type definitions for i2c_rdwr combined transactions -+ -+ -+class i2c_msg(Structure): -+ """ -+ As defined in ``i2c.h``. -+ """ -+ _fields_ = [ -+ ('addr', c_uint16), -+ ('flags', c_uint16), -+ ('len', c_uint16), -+ ('buf', POINTER(c_char))] -+ -+ def __iter__(self): -+ """ Iterator / Generator -+ -+ :return: iterates over :py:attr:`buf` -+ :rtype: :py:class:`generator` which returns int values -+ """ -+ idx = 0 -+ while idx < self.len: -+ yield ord(self.buf[idx]) -+ idx += 1 -+ -+ def __len__(self): -+ return self.len -+ -+ def __bytes__(self): -+ return string_at(self.buf, self.len) -+ -+ def __repr__(self): -+ return 'i2c_msg(%d,%d,%r)' % (self.addr, self.flags, self.__bytes__()) -+ -+ def __str__(self): -+ s = self.__bytes__() -+ if sys.version_info.major >= 3: -+ s = ''.join(map(chr, s)) -+ return s -+ -+ @staticmethod -+ def read(address, length): -+ """ -+ Prepares an i2c read transaction. -+ -+ :param address: Slave address. -+ :type: address: int -+ :param length: Number of bytes to read. -+ :type: length: int -+ :return: New :py:class:`i2c_msg` instance for read operation. -+ :rtype: :py:class:`i2c_msg` -+ """ -+ arr = create_string_buffer(length) -+ return i2c_msg( -+ addr=address, flags=I2C_M_RD, len=length, -+ buf=arr) -+ -+ @staticmethod -+ def write(address, buf): -+ """ -+ Prepares an i2c write transaction. -+ -+ :param address: Slave address. -+ :type address: int -+ :param buf: Bytes to write. Either list of values or str. -+ :type buf: list -+ :return: New :py:class:`i2c_msg` instance for write operation. -+ :rtype: :py:class:`i2c_msg` -+ """ -+ if sys.version_info.major >= 3: -+ if isinstance(buf, str): -+ buf = bytes(map(ord, buf)) -+ else: -+ buf = bytes(buf) -+ else: -+ if not isinstance(buf, str): -+ buf = ''.join([chr(x) for x in buf]) -+ arr = create_string_buffer(buf, len(buf)) -+ return i2c_msg( -+ addr=address, flags=0, len=len(arr), -+ buf=arr) -+ -+ -+class i2c_rdwr_ioctl_data(Structure): -+ """ -+ As defined in ``i2c-dev.h``. -+ """ -+ _fields_ = [ -+ ('msgs', POINTER(i2c_msg)), -+ ('nmsgs', c_uint32) -+ ] -+ __slots__ = [name for name, type in _fields_] -+ -+ @staticmethod -+ def create(*i2c_msg_instances): -+ """ -+ Factory method for creating a i2c_rdwr_ioctl_data struct that can -+ be called with ``ioctl(fd, I2C_RDWR, data)``. -+ -+ :param i2c_msg_instances: Up to 42 i2c_msg instances -+ :rtype: i2c_rdwr_ioctl_data -+ """ -+ n_msg = len(i2c_msg_instances) -+ msg_array = (i2c_msg * n_msg)(*i2c_msg_instances) -+ return i2c_rdwr_ioctl_data( -+ msgs=msg_array, -+ nmsgs=n_msg -+ ) -+ -+ -+############################################################# -+ -+ -+class SMBus(object): -+ -+ def __init__(self, bus=None, force=False): -+ """ -+ Initialize and (optionally) open an i2c bus connection. -+ -+ :param bus: i2c bus number (e.g. 0 or 1) -+ or an absolute file path (e.g. `/dev/i2c-42`). -+ If not given, a subsequent call to ``open()`` is required. -+ :type bus: int or str -+ :param force: force using the slave address even when driver is -+ already using it. -+ :type force: boolean -+ """ -+ self.fd = None -+ self.funcs = I2cFunc(0) -+ if bus is not None: -+ self.open(bus) -+ self.address = None -+ self.force = force -+ self._force_last = None -+ -+ def __enter__(self): -+ """Enter handler.""" -+ return self -+ -+ def __exit__(self, exc_type, exc_val, exc_tb): -+ """Exit handler.""" -+ self.close() -+ -+ def open(self, bus): -+ """ -+ Open a given i2c bus. -+ -+ :param bus: i2c bus number (e.g. 0 or 1) -+ or an absolute file path (e.g. '/dev/i2c-42'). -+ :type bus: int or str -+ :raise TypeError: if type(bus) is not in (int, str) -+ """ -+ if isinstance(bus, int): -+ filepath = "/dev/i2c-{}".format(bus) -+ elif isinstance(bus, str): -+ filepath = bus -+ else: -+ raise TypeError("Unexpected type(bus)={}".format(type(bus))) -+ -+ self.fd = os.open(filepath, os.O_RDWR) -+ self.funcs = self._get_funcs() -+ -+ def close(self): -+ """ -+ Close the i2c connection. -+ """ -+ if self.fd: -+ os.close(self.fd) -+ self.fd = None -+ -+ def _set_address(self, address, force=None): -+ """ -+ Set i2c slave address to use for subsequent calls. -+ -+ :param address: -+ :type address: int -+ :param force: -+ :type force: Boolean -+ """ -+ force = force if force is not None else self.force -+ if self.address != address or self._force_last != force: -+ if force is True: -+ ioctl(self.fd, I2C_SLAVE_FORCE, address) -+ else: -+ ioctl(self.fd, I2C_SLAVE, address) -+ self.address = address -+ self._force_last = force -+ -+ def _get_funcs(self): -+ """ -+ Returns a 32-bit value stating supported I2C functions. -+ -+ :rtype: int -+ """ -+ f = c_uint32() -+ ioctl(self.fd, I2C_FUNCS, f) -+ return f.value -+ -+ def write_quick(self, i2c_addr, force=None): -+ """ -+ Perform quick transaction. Throws IOError if unsuccessful. -+ :param i2c_addr: i2c address -+ :type i2c_addr: int -+ :param force: -+ :type force: Boolean -+ """ -+ self._set_address(i2c_addr, force=force) -+ msg = i2c_smbus_ioctl_data.create( -+ read_write=I2C_SMBUS_WRITE, command=0, size=I2C_SMBUS_QUICK) -+ ioctl(self.fd, I2C_SMBUS, msg) -+ -+ def read_byte(self, i2c_addr, force=None): -+ """ -+ Read a single byte from a device. -+ -+ :rtype: int -+ :param i2c_addr: i2c address -+ :type i2c_addr: int -+ :param force: -+ :type force: Boolean -+ :return: Read byte value -+ """ -+ self._set_address(i2c_addr, force=force) -+ msg = i2c_smbus_ioctl_data.create( -+ read_write=I2C_SMBUS_READ, command=0, size=I2C_SMBUS_BYTE -+ ) -+ ioctl(self.fd, I2C_SMBUS, msg) -+ return msg.data.contents.byte -+ -+ def write_byte(self, i2c_addr, value, force=None): -+ """ -+ Write a single byte to a device. -+ -+ :param i2c_addr: i2c address -+ :type i2c_addr: int -+ :param value: value to write -+ :type value: int -+ :param force: -+ :type force: Boolean -+ """ -+ self._set_address(i2c_addr, force=force) -+ msg = i2c_smbus_ioctl_data.create( -+ read_write=I2C_SMBUS_WRITE, command=value, size=I2C_SMBUS_BYTE -+ ) -+ ioctl(self.fd, I2C_SMBUS, msg) -+ -+ def read_byte_data(self, i2c_addr, register, force=None): -+ """ -+ Read a single byte from a designated register. -+ -+ :param i2c_addr: i2c address -+ :type i2c_addr: int -+ :param register: Register to read -+ :type register: int -+ :param force: -+ :type force: Boolean -+ :return: Read byte value -+ :rtype: int -+ """ -+ val_t = -1 -+ returnmsg = "" -+ try: -+ self._set_address(i2c_addr, force=force) -+ msg = i2c_smbus_ioctl_data.create( -+ read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_BYTE_DATA -+ ) -+ val_t = ioctl(self.fd, I2C_SMBUS, msg) -+ except Exception as e: -+ self.close() -+ returnmsg = str(e) -+ if val_t < 0: -+ return False, returnmsg -+ return True, msg.data.contents.byte -+ -+ def write_byte_data(self, i2c_addr, register, value, force=None): -+ """ -+ Write a byte to a given register. -+ -+ :param i2c_addr: i2c address -+ :type i2c_addr: int -+ :param register: Register to write to -+ :type register: int -+ :param value: Byte value to transmit -+ :type value: int -+ :param force: -+ :type force: Boolean -+ :rtype: None -+ """ -+ val_t = -1 -+ returnmsg = "" -+ try: -+ self._set_address(i2c_addr, force=force) -+ msg = i2c_smbus_ioctl_data.create( -+ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BYTE_DATA -+ ) -+ msg.data.contents.byte = value -+ val_t = ioctl(self.fd, I2C_SMBUS, msg) -+ except Exception as e: -+ returnmsg = str(e) -+ self.close() -+ if val_t < 0: -+ return False, returnmsg or "" -+ return True, "" -+ -+ def write_byte_data_pec(self, i2c_addr, register, value, force=None): -+ """ -+ Write a byte to a given register. -+ -+ :param i2c_addr: i2c address -+ :type i2c_addr: int -+ :param register: Register to write to -+ :type register: int -+ :param value: Byte value to transmit -+ :type value: int -+ :param force: -+ :type force: Boolean -+ :rtype: None -+ """ -+ val_t = -1 -+ returnmsg = "" -+ try: -+ val_t = ioctl(self.fd, I2C_PEC, 1) -+ if val_t < 0: -+ raise Exception("set pec mod error") -+ self._set_address(i2c_addr, force=force) -+ msg = i2c_smbus_ioctl_data.create( -+ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BYTE_DATA -+ ) -+ msg.data.contents.byte = value -+ val_t = ioctl(self.fd, I2C_SMBUS, msg) -+ except Exception as e: -+ returnmsg = str(e) -+ self.close() -+ if val_t < 0: -+ return False, returnmsg or "" -+ return True, "" -+ -+ def read_word_data(self, i2c_addr, register, force=None): -+ """ -+ Read a single word (2 bytes) from a given register. -+ -+ :param i2c_addr: i2c address -+ :type i2c_addr: int -+ :param register: Register to read -+ :type register: int -+ :param force: -+ :type force: Boolean -+ :return: 2-byte word -+ :rtype: int -+ """ -+ val_t = -1 -+ returnmsg = "" -+ try: -+ self._set_address(i2c_addr, force=force) -+ msg = i2c_smbus_ioctl_data.create( -+ read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_WORD_DATA -+ ) -+ val_t = ioctl(self.fd, I2C_SMBUS, msg) -+ except Exception as e: -+ returnmsg = str(e) -+ self.close() -+ if val_t < 0: -+ return False, returnmsg or "" -+ return True, msg.data.contents.word -+ -+ def write_word_data_pec(self, i2c_addr, register, value, force=None): -+ """ -+ Write a byte to a given register. -+ -+ :param i2c_addr: i2c address -+ :type i2c_addr: int -+ :param register: Register to write to -+ :type register: int -+ :param value: Word value to transmit -+ :type value: int -+ :param force: -+ :type force: Boolean -+ :rtype: None -+ """ -+ val_t = -1 -+ returnmsg = "" -+ try: -+ val_t = ioctl(self.fd, I2C_PEC, 1) -+ if val_t < 0: -+ raise Exception("set pec mod error") -+ self._set_address(i2c_addr, force=force) -+ msg = i2c_smbus_ioctl_data.create( -+ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_WORD_DATA -+ ) -+ msg.data.contents.word = value -+ val_t = ioctl(self.fd, I2C_SMBUS, msg) -+ except Exception as e: -+ returnmsg = str(e) -+ self.close() -+ if val_t < 0: -+ return False, returnmsg or "" -+ return True, "" -+ -+ def write_word_data(self, i2c_addr, register, value, force=None): -+ """ -+ Write a byte to a given register. -+ -+ :param i2c_addr: i2c address -+ :type i2c_addr: int -+ :param register: Register to write to -+ :type register: int -+ :param value: Word value to transmit -+ :type value: int -+ :param force: -+ :type force: Boolean -+ :rtype: None -+ """ -+ val_t = -1 -+ returnmsg = "" -+ try: -+ self._set_address(i2c_addr, force=force) -+ msg = i2c_smbus_ioctl_data.create( -+ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_WORD_DATA -+ ) -+ msg.data.contents.word = value -+ val_t = ioctl(self.fd, I2C_SMBUS, msg) -+ except Exception as e: -+ returnmsg = str(e) -+ self.close() -+ if val_t < 0: -+ return False, returnmsg or "" -+ return True, "" -+ -+ def process_call(self, i2c_addr, register, value, force=None): -+ """ -+ Executes a SMBus Process Call, sending a 16-bit value and receiving a 16-bit response -+ -+ :param i2c_addr: i2c address -+ :type i2c_addr: int -+ :param register: Register to read/write to -+ :type register: int -+ :param value: Word value to transmit -+ :type value: int -+ :param force: -+ :type force: Boolean -+ :rtype: int -+ """ -+ self._set_address(i2c_addr, force=force) -+ msg = i2c_smbus_ioctl_data.create( -+ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_PROC_CALL -+ ) -+ msg.data.contents.word = value -+ ioctl(self.fd, I2C_SMBUS, msg) -+ return msg.data.contents.word -+ -+ def read_block_data(self, i2c_addr, register, force=None): -+ """ -+ Read a block of up to 32-bytes from a given register. -+ -+ :param i2c_addr: i2c address -+ :type i2c_addr: int -+ :param register: Start register -+ :type register: int -+ :param force: -+ :type force: Boolean -+ :return: List of bytes -+ :rtype: list -+ """ -+ self._set_address(i2c_addr, force=force) -+ msg = i2c_smbus_ioctl_data.create( -+ read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_BLOCK_DATA -+ ) -+ ioctl(self.fd, I2C_SMBUS, msg) -+ length = msg.data.contents.block[0] -+ return msg.data.contents.block[1:length + 1] -+ -+ def write_block_data(self, i2c_addr, register, data, force=None): -+ """ -+ Write a block of byte data to a given register. -+ -+ :param i2c_addr: i2c address -+ :type i2c_addr: int -+ :param register: Start register -+ :type register: int -+ :param data: List of bytes -+ :type data: list -+ :param force: -+ :type force: Boolean -+ :rtype: None -+ """ -+ length = len(data) -+ if length > I2C_SMBUS_BLOCK_MAX: -+ raise ValueError("Data length cannot exceed %d bytes" % I2C_SMBUS_BLOCK_MAX) -+ self._set_address(i2c_addr, force=force) -+ msg = i2c_smbus_ioctl_data.create( -+ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BLOCK_DATA -+ ) -+ msg.data.contents.block[0] = length -+ msg.data.contents.block[1:length + 1] = data -+ ioctl(self.fd, I2C_SMBUS, msg) -+ -+ def block_process_call(self, i2c_addr, register, data, force=None): -+ """ -+ Executes a SMBus Block Process Call, sending a variable-size data -+ block and receiving another variable-size response -+ -+ :param i2c_addr: i2c address -+ :type i2c_addr: int -+ :param register: Register to read/write to -+ :type register: int -+ :param data: List of bytes -+ :type data: list -+ :param force: -+ :type force: Boolean -+ :return: List of bytes -+ :rtype: list -+ """ -+ length = len(data) -+ if length > I2C_SMBUS_BLOCK_MAX: -+ raise ValueError("Data length cannot exceed %d bytes" % I2C_SMBUS_BLOCK_MAX) -+ self._set_address(i2c_addr, force=force) -+ msg = i2c_smbus_ioctl_data.create( -+ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BLOCK_PROC_CALL -+ ) -+ msg.data.contents.block[0] = length -+ msg.data.contents.block[1:length + 1] = data -+ ioctl(self.fd, I2C_SMBUS, msg) -+ length = msg.data.contents.block[0] -+ return msg.data.contents.block[1:length + 1] -+ -+ def read_i2c_block_data(self, i2c_addr, register, length, force=None): -+ """ -+ Read a block of byte data from a given register. -+ -+ :param i2c_addr: i2c address -+ :type i2c_addr: int -+ :param register: Start register -+ :type register: int -+ :param length: Desired block length -+ :type length: int -+ :param force: -+ :type force: Boolean -+ :return: List of bytes -+ :rtype: list -+ """ -+ if length > I2C_SMBUS_BLOCK_MAX: -+ raise ValueError("Desired block length over %d bytes" % I2C_SMBUS_BLOCK_MAX) -+ self._set_address(i2c_addr, force=force) -+ msg = i2c_smbus_ioctl_data.create( -+ read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_I2C_BLOCK_DATA -+ ) -+ msg.data.contents.byte = length -+ ioctl(self.fd, I2C_SMBUS, msg) -+ return msg.data.contents.block[1:length + 1] -+ -+ def write_i2c_block_data(self, i2c_addr, register, data, force=None): -+ """ -+ Write a block of byte data to a given register. -+ -+ :param i2c_addr: i2c address -+ :type i2c_addr: int -+ :param register: Start register -+ :type register: int -+ :param data: List of bytes -+ :type data: list -+ :param force: -+ :type force: Boolean -+ :rtype: None -+ """ -+ length = len(data) -+ if length > I2C_SMBUS_BLOCK_MAX: -+ raise ValueError("Data length cannot exceed %d bytes" % I2C_SMBUS_BLOCK_MAX) -+ self._set_address(i2c_addr, force=force) -+ msg = i2c_smbus_ioctl_data.create( -+ read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_I2C_BLOCK_DATA -+ ) -+ msg.data.contents.block[0] = length -+ msg.data.contents.block[1:length + 1] = data -+ ioctl(self.fd, I2C_SMBUS, msg) -+ -+ def i2c_rdwr(self, *i2c_msgs): -+ """ -+ Combine a series of i2c read and write operations in a single -+ transaction (with repeated start bits but no stop bits in between). -+ -+ This method takes i2c_msg instances as input, which must be created -+ first with :py:meth:`i2c_msg.read` or :py:meth:`i2c_msg.write`. -+ -+ :param i2c_msgs: One or more i2c_msg class instances. -+ :type i2c_msgs: i2c_msg -+ :rtype: None -+ """ -+ ioctl_data = i2c_rdwr_ioctl_data.create(*i2c_msgs) -+ ioctl(self.fd, I2C_RDWR, ioctl_data) -+ -+ -+class SMBusWrapper: -+ """ -+ Wrapper class around the SMBus. -+ Deprecated as of version 0.3.0. Please replace with :py:class:`SMBus`. -+ -+ Enables the user to wrap access to the :py:class:`SMBus` class in a -+ "with" statement. If auto_cleanup is True (default), the -+ :py:class:`SMBus` handle will be automatically closed -+ upon exit of the ``with`` block. -+ """ -+ -+ def __init__(self, bus_number=0, auto_cleanup=True, force=False): -+ """ -+ :param auto_cleanup: Close bus when leaving scope. -+ :type auto_cleanup: Boolean -+ :param force: Force using the slave address even when driver is already using it. -+ :type force: Boolean -+ """ -+ self.bus_number = bus_number -+ self.auto_cleanup = auto_cleanup -+ self.force = force -+ self.bus = None -+ -+ def __enter__(self): -+ self.bus = SMBus(bus=self.bus_number, force=self.force) -+ return self.bus -+ -+ def __exit__(self, exc_type, exc_val, exc_tb): -+ if self.auto_cleanup: -+ self.bus.close() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modprobe_conf/kernel_drivers_blacklist.conf b/platform/broadcom/sonic-platform-modules-micas/common/modprobe_conf/kernel_drivers_blacklist.conf -new file mode 100644 -index 000000000..39d56582b ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modprobe_conf/kernel_drivers_blacklist.conf -@@ -0,0 +1,7 @@ -+blacklist wb_fpga_pcie -+blacklist wb_i2c_i801 -+blacklist wb_spi_gpio -+blacklist intel_spi -+blacklist intel_spi_platform -+blacklist wb_i2c_ismt -+blacklist intel_spi_pci -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/COPYING b/platform/broadcom/sonic-platform-modules-micas/common/modules/COPYING -new file mode 100644 -index 000000000..a635a38ef ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/COPYING -@@ -0,0 +1,20 @@ -+The Linux Kernel is provided under: -+ -+ SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note -+ -+Being under the terms of the GNU General Public License version 2 only, -+according with: -+ -+ LICENSES/preferred/GPL-2.0 -+ -+With an explicit syscall exception, as stated at: -+ -+ LICENSES/exceptions/Linux-syscall-note -+ -+In addition, other licenses may also apply. Please see: -+ -+ Documentation/process/license-rules.rst -+ -+for more details. -+ -+All contributions to the Linux Kernel are subject to this COPYING file. -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/GPL-2.0 b/platform/broadcom/sonic-platform-modules-micas/common/modules/GPL-2.0 -new file mode 100644 -index 000000000..ff0812fd8 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/GPL-2.0 -@@ -0,0 +1,359 @@ -+Valid-License-Identifier: GPL-2.0 -+Valid-License-Identifier: GPL-2.0-only -+Valid-License-Identifier: GPL-2.0+ -+Valid-License-Identifier: GPL-2.0-or-later -+SPDX-URL: https://spdx.org/licenses/GPL-2.0.html -+Usage-Guide: -+ To use this license in source code, put one of the following SPDX -+ tag/value pairs into a comment according to the placement -+ guidelines in the licensing rules documentation. -+ For 'GNU General Public License (GPL) version 2 only' use: -+ SPDX-License-Identifier: GPL-2.0 -+ or -+ SPDX-License-Identifier: GPL-2.0-only -+ For 'GNU General Public License (GPL) version 2 or any later version' use: -+ SPDX-License-Identifier: GPL-2.0+ -+ or -+ SPDX-License-Identifier: GPL-2.0-or-later -+License-Text: -+ -+ GNU GENERAL PUBLIC LICENSE -+ Version 2, June 1991 -+ -+ Copyright (C) 1989, 1991 Free Software Foundation, Inc. -+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ Everyone is permitted to copy and distribute verbatim copies -+ of this license document, but changing it is not allowed. -+ -+ Preamble -+ -+ The licenses for most software are designed to take away your -+freedom to share and change it. By contrast, the GNU General Public -+License is intended to guarantee your freedom to share and change free -+software--to make sure the software is free for all its users. This -+General Public License applies to most of the Free Software -+Foundation's software and to any other program whose authors commit to -+using it. (Some other Free Software Foundation software is covered by -+the GNU Library General Public License instead.) You can apply it to -+your programs, too. -+ -+ When we speak of free software, we are referring to freedom, not -+price. Our General Public Licenses are designed to make sure that you -+have the freedom to distribute copies of free software (and charge for -+this service if you wish), that you receive source code or can get it -+if you want it, that you can change the software or use pieces of it -+in new free programs; and that you know you can do these things. -+ -+ To protect your rights, we need to make restrictions that forbid -+anyone to deny you these rights or to ask you to surrender the rights. -+These restrictions translate to certain responsibilities for you if you -+distribute copies of the software, or if you modify it. -+ -+ For example, if you distribute copies of such a program, whether -+gratis or for a fee, you must give the recipients all the rights that -+you have. You must make sure that they, too, receive or can get the -+source code. And you must show them these terms so they know their -+rights. -+ -+ We protect your rights with two steps: (1) copyright the software, and -+(2) offer you this license which gives you legal permission to copy, -+distribute and/or modify the software. -+ -+ Also, for each author's protection and ours, we want to make certain -+that everyone understands that there is no warranty for this free -+software. If the software is modified by someone else and passed on, we -+want its recipients to know that what they have is not the original, so -+that any problems introduced by others will not reflect on the original -+authors' reputations. -+ -+ Finally, any free program is threatened constantly by software -+patents. We wish to avoid the danger that redistributors of a free -+program will individually obtain patent licenses, in effect making the -+program proprietary. To prevent this, we have made it clear that any -+patent must be licensed for everyone's free use or not licensed at all. -+ -+ The precise terms and conditions for copying, distribution and -+modification follow. -+ -+ GNU GENERAL PUBLIC LICENSE -+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -+ -+ 0. This License applies to any program or other work which contains -+a notice placed by the copyright holder saying it may be distributed -+under the terms of this General Public License. The "Program", below, -+refers to any such program or work, and a "work based on the Program" -+means either the Program or any derivative work under copyright law: -+that is to say, a work containing the Program or a portion of it, -+either verbatim or with modifications and/or translated into another -+language. (Hereinafter, translation is included without limitation in -+the term "modification".) Each licensee is addressed as "you". -+ -+Activities other than copying, distribution and modification are not -+covered by this License; they are outside its scope. The act of -+running the Program is not restricted, and the output from the Program -+is covered only if its contents constitute a work based on the -+Program (independent of having been made by running the Program). -+Whether that is true depends on what the Program does. -+ -+ 1. You may copy and distribute verbatim copies of the Program's -+source code as you receive it, in any medium, provided that you -+conspicuously and appropriately publish on each copy an appropriate -+copyright notice and disclaimer of warranty; keep intact all the -+notices that refer to this License and to the absence of any warranty; -+and give any other recipients of the Program a copy of this License -+along with the Program. -+ -+You may charge a fee for the physical act of transferring a copy, and -+you may at your option offer warranty protection in exchange for a fee. -+ -+ 2. You may modify your copy or copies of the Program or any portion -+of it, thus forming a work based on the Program, and copy and -+distribute such modifications or work under the terms of Section 1 -+above, provided that you also meet all of these conditions: -+ -+ a) You must cause the modified files to carry prominent notices -+ stating that you changed the files and the date of any change. -+ -+ b) You must cause any work that you distribute or publish, that in -+ whole or in part contains or is derived from the Program or any -+ part thereof, to be licensed as a whole at no charge to all third -+ parties under the terms of this License. -+ -+ c) If the modified program normally reads commands interactively -+ when run, you must cause it, when started running for such -+ interactive use in the most ordinary way, to print or display an -+ announcement including an appropriate copyright notice and a -+ notice that there is no warranty (or else, saying that you provide -+ a warranty) and that users may redistribute the program under -+ these conditions, and telling the user how to view a copy of this -+ License. (Exception: if the Program itself is interactive but -+ does not normally print such an announcement, your work based on -+ the Program is not required to print an announcement.) -+ -+These requirements apply to the modified work as a whole. If -+identifiable sections of that work are not derived from the Program, -+and can be reasonably considered independent and separate works in -+themselves, then this License, and its terms, do not apply to those -+sections when you distribute them as separate works. But when you -+distribute the same sections as part of a whole which is a work based -+on the Program, the distribution of the whole must be on the terms of -+this License, whose permissions for other licensees extend to the -+entire whole, and thus to each and every part regardless of who wrote it. -+ -+Thus, it is not the intent of this section to claim rights or contest -+your rights to work written entirely by you; rather, the intent is to -+exercise the right to control the distribution of derivative or -+collective works based on the Program. -+ -+In addition, mere aggregation of another work not based on the Program -+with the Program (or with a work based on the Program) on a volume of -+a storage or distribution medium does not bring the other work under -+the scope of this License. -+ -+ 3. You may copy and distribute the Program (or a work based on it, -+under Section 2) in object code or executable form under the terms of -+Sections 1 and 2 above provided that you also do one of the following: -+ -+ a) Accompany it with the complete corresponding machine-readable -+ source code, which must be distributed under the terms of Sections -+ 1 and 2 above on a medium customarily used for software interchange; or, -+ -+ b) Accompany it with a written offer, valid for at least three -+ years, to give any third party, for a charge no more than your -+ cost of physically performing source distribution, a complete -+ machine-readable copy of the corresponding source code, to be -+ distributed under the terms of Sections 1 and 2 above on a medium -+ customarily used for software interchange; or, -+ -+ c) Accompany it with the information you received as to the offer -+ to distribute corresponding source code. (This alternative is -+ allowed only for noncommercial distribution and only if you -+ received the program in object code or executable form with such -+ an offer, in accord with Subsection b above.) -+ -+The source code for a work means the preferred form of the work for -+making modifications to it. For an executable work, complete source -+code means all the source code for all modules it contains, plus any -+associated interface definition files, plus the scripts used to -+control compilation and installation of the executable. However, as a -+special exception, the source code distributed need not include -+anything that is normally distributed (in either source or binary -+form) with the major components (compiler, kernel, and so on) of the -+operating system on which the executable runs, unless that component -+itself accompanies the executable. -+ -+If distribution of executable or object code is made by offering -+access to copy from a designated place, then offering equivalent -+access to copy the source code from the same place counts as -+distribution of the source code, even though third parties are not -+compelled to copy the source along with the object code. -+ -+ 4. You may not copy, modify, sublicense, or distribute the Program -+except as expressly provided under this License. Any attempt -+otherwise to copy, modify, sublicense or distribute the Program is -+void, and will automatically terminate your rights under this License. -+However, parties who have received copies, or rights, from you under -+this License will not have their licenses terminated so long as such -+parties remain in full compliance. -+ -+ 5. You are not required to accept this License, since you have not -+signed it. However, nothing else grants you permission to modify or -+distribute the Program or its derivative works. These actions are -+prohibited by law if you do not accept this License. Therefore, by -+modifying or distributing the Program (or any work based on the -+Program), you indicate your acceptance of this License to do so, and -+all its terms and conditions for copying, distributing or modifying -+the Program or works based on it. -+ -+ 6. Each time you redistribute the Program (or any work based on the -+Program), the recipient automatically receives a license from the -+original licensor to copy, distribute or modify the Program subject to -+these terms and conditions. You may not impose any further -+restrictions on the recipients' exercise of the rights granted herein. -+You are not responsible for enforcing compliance by third parties to -+this License. -+ -+ 7. If, as a consequence of a court judgment or allegation of patent -+infringement or for any other reason (not limited to patent issues), -+conditions are imposed on you (whether by court order, agreement or -+otherwise) that contradict the conditions of this License, they do not -+excuse you from the conditions of this License. If you cannot -+distribute so as to satisfy simultaneously your obligations under this -+License and any other pertinent obligations, then as a consequence you -+may not distribute the Program at all. For example, if a patent -+license would not permit royalty-free redistribution of the Program by -+all those who receive copies directly or indirectly through you, then -+the only way you could satisfy both it and this License would be to -+refrain entirely from distribution of the Program. -+ -+If any portion of this section is held invalid or unenforceable under -+any particular circumstance, the balance of the section is intended to -+apply and the section as a whole is intended to apply in other -+circumstances. -+ -+It is not the purpose of this section to induce you to infringe any -+patents or other property right claims or to contest validity of any -+such claims; this section has the sole purpose of protecting the -+integrity of the free software distribution system, which is -+implemented by public license practices. Many people have made -+generous contributions to the wide range of software distributed -+through that system in reliance on consistent application of that -+system; it is up to the author/donor to decide if he or she is willing -+to distribute software through any other system and a licensee cannot -+impose that choice. -+ -+This section is intended to make thoroughly clear what is believed to -+be a consequence of the rest of this License. -+ -+ 8. If the distribution and/or use of the Program is restricted in -+certain countries either by patents or by copyrighted interfaces, the -+original copyright holder who places the Program under this License -+may add an explicit geographical distribution limitation excluding -+those countries, so that distribution is permitted only in or among -+countries not thus excluded. In such case, this License incorporates -+the limitation as if written in the body of this License. -+ -+ 9. The Free Software Foundation may publish revised and/or new versions -+of the General Public License from time to time. Such new versions will -+be similar in spirit to the present version, but may differ in detail to -+address new problems or concerns. -+ -+Each version is given a distinguishing version number. If the Program -+specifies a version number of this License which applies to it and "any -+later version", you have the option of following the terms and conditions -+either of that version or of any later version published by the Free -+Software Foundation. If the Program does not specify a version number of -+this License, you may choose any version ever published by the Free Software -+Foundation. -+ -+ 10. If you wish to incorporate parts of the Program into other free -+programs whose distribution conditions are different, write to the author -+to ask for permission. For software which is copyrighted by the Free -+Software Foundation, write to the Free Software Foundation; we sometimes -+make exceptions for this. Our decision will be guided by the two goals -+of preserving the free status of all derivatives of our free software and -+of promoting the sharing and reuse of software generally. -+ -+ NO WARRANTY -+ -+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -+REPAIR OR CORRECTION. -+ -+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -+POSSIBILITY OF SUCH DAMAGES. -+ -+ END OF TERMS AND CONDITIONS -+ -+ How to Apply These Terms to Your New Programs -+ -+ If you develop a new program, and you want it to be of the greatest -+possible use to the public, the best way to achieve this is to make it -+free software which everyone can redistribute and change under these terms. -+ -+ To do so, attach the following notices to the program. It is safest -+to attach them to the start of each source file to most effectively -+convey the exclusion of warranty; and each file should have at least -+the "copyright" line and a pointer to where the full notice is found. -+ -+ -+ Copyright (C) -+ -+ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ -+ -+Also add information on how to contact you by electronic and paper mail. -+ -+If the program is interactive, make it output a short notice like this -+when it starts in an interactive mode: -+ -+ Gnomovision version 69, Copyright (C) year name of author -+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. -+ This is free software, and you are welcome to redistribute it -+ under certain conditions; type `show c' for details. -+ -+The hypothetical commands `show w' and `show c' should show the appropriate -+parts of the General Public License. Of course, the commands you use may -+be called something other than `show w' and `show c'; they could even be -+mouse-clicks or menu items--whatever suits your program. -+ -+You should also get your employer (if you work as a programmer) or your -+school, if any, to sign a "copyright disclaimer" for the program, if -+necessary. Here is a sample; alter the names: -+ -+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program -+ `Gnomovision' (which makes passes at compilers) written by James Hacker. -+ -+ , 1 April 1989 -+ Ty Coon, President of Vice -+ -+This General Public License does not permit incorporating your program into -+proprietary programs. If your program is a subroutine library, you may -+consider it more useful to permit linking proprietary applications with the -+library. If this is what you want to do, use the GNU Library General -+Public License instead of this License. -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/Makefile -new file mode 100644 -index 000000000..293750591 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/Makefile -@@ -0,0 +1,62 @@ -+PWD = $(shell pwd) -+EXTRA_CFLAGS:= -I$(M)/include -+EXTRA_CFLAGS+= -Wall -+KVERSION ?= $(shell uname -r) -+KERNEL_SRC ?= /lib/modules/$(KVERSION) -+ -+module_out_put_dir := $(PWD)/build -+export module_out_put_dir -+ -+KERNEL_MODULES_SRC = $(PWD)/linux-5.10 -+ -+PLAT_SYSFS_DIR = $(PWD)/plat_sysfs -+INTEL_SPI = $(PWD)/intel_spi -+PHY = $(PWD)/phy -+PINCTRL = $(PWD)/pinctrl -+SDHCI = $(PWD)/sdhci -+ -+export PLAT_SYSFS_DIR -+ -+platform_common-objs := platform_common_module.o dfd_tlveeprom.o -+obj-m += platform_common.o -+obj-m += wb_mac_bsc.o -+obj-m += wb_fpga_pcie.o -+obj-m += wb_pcie_dev.o -+obj-m += wb_fpga_i2c_bus_drv.o -+obj-m += wb_fpga_pca954x_drv.o -+obj-m += wb_lpc_drv.o -+obj-m += wb_i2c_dev.o -+obj-m += wb_platform_i2c_dev.o -+obj-m += wb_io_dev.o -+obj-m += wb_eeprom_93xx46.o -+obj-m += wb_spi_93xx46.o -+obj-m += wb_gpio_d1500.o -+obj-m += wb_gpio_device.o -+obj-m += wb_i2c_ocores.o -+obj-m += wb_spi_ocores.o -+obj-m += wb_spi_dev.o -+obj-m += wb_wdt.o -+obj-m += wb_optoe.o -+obj-m += wb_spi_gpio.o -+obj-m += wb_spi_gpio_device.o -+obj-m += wb_spi_nor_device.o -+obj-m += wb_xdpe132g5c.o -+obj-m += wb_uio_irq.o -+obj-m += hw_test.o -+ -+all : -+ $(MAKE) -C $(KERNEL_MODULES_SRC) -+ $(MAKE) -C $(PLAT_SYSFS_DIR) -+ $(MAKE) -C $(INTEL_SPI) -+ $(MAKE) -C $(PHY) -+ $(MAKE) -C $(PINCTRL) -+ $(MAKE) -C $(SDHCI) -+ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules -+ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi -+ cp -p $(PWD)/*.ko $(module_out_put_dir) -+ -+clean : -+ rm -rf $(module_out_put_dir) -+ rm -f ${PWD}/*.o ${PWD}/*.ko ${PWD}/*.mod.c ${PWD}/.*.cmd ${PWD}/.*.o.d ${PWD}/*.mod -+ rm -f ${PWD}/Module.markers ${PWD}/Module.symvers ${PWD}/modules.order -+ rm -rf ${PWD}/.tmp_versions -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.c -new file mode 100644 -index 000000000..0d6f38ecc ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.c -@@ -0,0 +1,516 @@ -+/* -+ * Copyright (C) 2003-2014 FreeIPMI Core Team -+ * -+ * 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 -+ * (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, see . -+ * -+ */ -+/*****************************************************************************\ -+ * Copyright (C) 2007-2014 Lawrence Livermore National Security, LLC. -+ * Copyright (C) 2007 The Regents of the University of California. -+ * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). -+ * Written by Albert Chu -+ * UCRL-CODE-232183 -+ * -+ * This file is part of Ipmi-fru, a tool used for retrieving -+ * motherboard field replaceable unit (FRU) information. For details, -+ * see http://www.llnl.gov/linux/. -+ * -+ * Ipmi-fru 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 (at your -+ * option) any later version. -+ * -+ * Ipmi-fru 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 Ipmi-fru. If not, see . -+\*****************************************************************************/ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "platform_common.h" -+#include "dfd_tlveeprom.h" -+ -+/* using in is_valid_tlvinfo_header */ -+static u_int32_t eeprom_size; -+ -+/* -+ * List of TLV codes and names. -+ */ -+static const struct tlv_code_desc tlv_code_list[] = { -+ { TLV_CODE_PRODUCT_NAME , "Product Name"}, -+ { TLV_CODE_PART_NUMBER , "Part Number"}, -+ { TLV_CODE_SERIAL_NUMBER , "Serial Number"}, -+ { TLV_CODE_MAC_BASE , "Base MAC Address"}, -+ { TLV_CODE_MANUF_DATE , "Manufacture Date"}, -+ { TLV_CODE_DEVICE_VERSION , "Device Version"}, -+ { TLV_CODE_LABEL_REVISION , "Label Revision"}, -+ { TLV_CODE_PLATFORM_NAME , "Platform Name"}, -+ { TLV_CODE_ONIE_VERSION , "ONIE Version"}, -+ { TLV_CODE_MAC_SIZE , "MAC Addresses"}, -+ { TLV_CODE_MANUF_NAME , "Manufacturer"}, -+ { TLV_CODE_MANUF_COUNTRY , "Country Code"}, -+ { TLV_CODE_VENDOR_NAME , "Vendor Name"}, -+ { TLV_CODE_DIAG_VERSION , "Diag Version"}, -+ { TLV_CODE_SERVICE_TAG , "Service Tag"}, -+ { TLV_CODE_VENDOR_EXT , "Vendor Extension"}, -+ { TLV_CODE_CRC_32 , "CRC-32"}, -+}; -+ -+#if 0 -+#define OPENBMC_VPD_KEY_INVAIL_VAL 0 -+ -+static const tlv_code_map_t tlv_code_map[] = { -+ { TLV_CODE_PRODUCT_NAME , OPENBMC_VPD_KEY_PRODUCT_NAME}, -+ { TLV_CODE_PART_NUMBER , OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM}, -+ { TLV_CODE_SERIAL_NUMBER , OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM}, -+ { TLV_CODE_MAC_BASE , OPENBMC_VPD_KEY_INVAIL_VAL}, -+ { TLV_CODE_MANUF_DATE , OPENBMC_VPD_KEY_BOARD_MFG_DATE}, -+ { TLV_CODE_DEVICE_VERSION , OPENBMC_VPD_KEY_PRODUCT_VER}, -+ { TLV_CODE_LABEL_REVISION , OPENBMC_VPD_KEY_PRODUCT_CUSTOM7}, -+ { TLV_CODE_PLATFORM_NAME , OPENBMC_VPD_KEY_PRODUCT_CUSTOM1}, -+ { TLV_CODE_ONIE_VERSION , OPENBMC_VPD_KEY_PRODUCT_CUSTOM2}, -+ { TLV_CODE_MAC_SIZE , OPENBMC_VPD_KEY_INVAIL_VAL}, -+ { TLV_CODE_MANUF_NAME , OPENBMC_VPD_KEY_PRODUCT_MFR}, -+ { TLV_CODE_MANUF_COUNTRY , OPENBMC_VPD_KEY_PRODUCT_CUSTOM3}, -+ { TLV_CODE_VENDOR_NAME , OPENBMC_VPD_KEY_PRODUCT_CUSTOM4}, -+ { TLV_CODE_DIAG_VERSION , OPENBMC_VPD_KEY_PRODUCT_CUSTOM8}, -+ { TLV_CODE_SERVICE_TAG , OPENBMC_VPD_KEY_PRODUCT_CUSTOM5}, -+ { TLV_CODE_VENDOR_EXT , OPENBMC_VPD_KEY_PRODUCT_CUSTOM6}, -+ { TLV_CODE_CRC_32 , OPENBMC_VPD_KEY_INVAIL_VAL}, -+}; -+#endif -+ -+#define TLV_CODE_NUM (sizeof(tlv_code_list) / sizeof(tlv_code_list[0])) -+ -+#if 0 -+#define TLV_CODE_MAP_NUM (sizeof(tlv_code_map) / sizeof(tlv_code_map[0])) -+#endif -+ -+const unsigned long crc_table[] = { -+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, -+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, -+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, -+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, -+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, -+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, -+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, -+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, -+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, -+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, -+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, -+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, -+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, -+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, -+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, -+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, -+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, -+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, -+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, -+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, -+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, -+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, -+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, -+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, -+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, -+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, -+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, -+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, -+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, -+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, -+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, -+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, -+}; -+ -+static unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned len) -+{ -+ unsigned i; -+ if (len < 1) -+ return 0xffffffff; -+ -+ for (i = 0; i != len; ++i) -+ { -+ crc = crc_table[(crc ^ buf[i]) & 0xff] ^ (crc >> 8); -+ } -+ -+ crc = crc ^ 0xffffffff; -+ -+ return crc; -+} -+ -+/* -+ * is_valid_tlv -+ * -+ * Perform basic sanity checks on a TLV field. The TLV is pointed to -+ * by the parameter provided. -+ * 1. The type code is not reserved (0x00 or 0xFF) -+ */ -+static inline bool is_valid_tlv(tlvinfo_tlv_t *tlv) -+{ -+ return ((tlv->type != 0x00) && (tlv->type != 0xFF)); -+} -+ -+/* -+ * is_valid_tlvinfo_header -+ * -+ * Perform sanity checks on the first 11 bytes of the TlvInfo EEPROM -+ * data pointed to by the parameter: -+ * 1. First 8 bytes contain null-terminated ASCII string "TlvInfo" -+ * 2. Version byte is 1 -+ * 3. Total length bytes contain value which is less than or equal -+ * to the allowed maximum (2048-11) -+ * -+ */ -+static inline bool is_valid_tlvinfo_header(tlvinfo_header_t *hdr) -+{ -+ int max_size = eeprom_size; -+ return((strcmp(hdr->signature, TLV_INFO_ID_STRING) == 0) && -+ (hdr->version == TLV_INFO_VERSION) && -+ (be16_to_cpu(hdr->totallen) <= max_size) ); -+} -+ -+/* -+ * decode_tlv_value -+ * -+ * Decode a single TLV value into a string. -+ -+ * The validity of EEPROM contents and the TLV field have been verified -+ * prior to calling this function. -+ */ -+static void decode_tlv_value(tlvinfo_tlv_t *tlv, tlv_decode_value_t *decode_value) -+{ -+ int i; -+ char *value; -+ u_int32_t length; -+ -+ value = (char *)decode_value->value; -+ -+ switch (tlv->type) { -+ case TLV_CODE_PRODUCT_NAME: -+ case TLV_CODE_PART_NUMBER: -+ case TLV_CODE_SERIAL_NUMBER: -+ case TLV_CODE_MANUF_DATE: -+ case TLV_CODE_LABEL_REVISION: -+ case TLV_CODE_PLATFORM_NAME: -+ case TLV_CODE_ONIE_VERSION: -+ case TLV_CODE_MANUF_NAME: -+ case TLV_CODE_MANUF_COUNTRY: -+ case TLV_CODE_VENDOR_NAME: -+ case TLV_CODE_DIAG_VERSION: -+ case TLV_CODE_SERVICE_TAG: -+ case TLV_CODE_VENDOR_EXT: -+ memcpy(value, tlv->value, tlv->length); -+ value[tlv->length] = 0; -+ length = tlv->length; -+ break; -+ case TLV_CODE_MAC_BASE: -+ length = sprintf(value, "%02X:%02X:%02X:%02X:%02X:%02X", -+ tlv->value[0], tlv->value[1], tlv->value[2], -+ tlv->value[3], tlv->value[4], tlv->value[5]); -+ break; -+ case TLV_CODE_DEVICE_VERSION: -+ length = sprintf(value, "%u", tlv->value[0]); -+ break; -+ case TLV_CODE_MAC_SIZE: -+ length = sprintf(value, "%u", (tlv->value[0] << 8) | tlv->value[1]); -+ break; -+ #if 0 -+ case TLV_CODE_VENDOR_EXT: -+ value[0] = 0; -+ length = 0; -+ for (i = 0; (i < (TLV_DECODE_VALUE_MAX_LEN/5)) && (i < tlv->length); i++) { -+ length += sprintf(value, "%s 0x%02X", value, tlv->value[i]); -+ } -+ break; -+ #endif -+ case TLV_CODE_CRC_32: -+ length = sprintf(value, "0x%02X%02X%02X%02X", tlv->value[0], -+ tlv->value[1], tlv->value[2], tlv->value[3]); -+ break; -+ default: -+ value[0] = 0; -+ length = 0; -+ for (i = 0; (i < (TLV_DECODE_VALUE_MAX_LEN/5)) && (i < tlv->length); i++) { -+ length += sprintf(value, "%s 0x%02X", value, tlv->value[i]); -+ } -+ break; -+ } -+ -+ decode_value->length = length; -+} -+ -+/* -+ * is_checksum_valid -+ * -+ * Validate the checksum in the provided TlvInfo EEPROM data. First, -+ * verify that the TlvInfo header is valid, then make sure the last -+ * TLV is a CRC-32 TLV. Then calculate the CRC over the EEPROM data -+ * and compare it to the value stored in the EEPROM CRC-32 TLV. -+ */ -+static bool is_checksum_valid(u_int8_t *eeprom) -+{ -+ tlvinfo_header_t *eeprom_hdr; -+ tlvinfo_tlv_t *eeprom_crc; -+ unsigned int calc_crc; -+ unsigned int stored_crc; -+ -+ eeprom_hdr = (tlvinfo_header_t *) eeprom; -+ -+ // Is the eeprom header valid? -+ if (!is_valid_tlvinfo_header(eeprom_hdr)) { -+ return false; -+ } -+ -+ // Is the last TLV a CRC? -+ eeprom_crc = (tlvinfo_tlv_t *) &eeprom[sizeof(tlvinfo_header_t) + -+ be16_to_cpu(eeprom_hdr->totallen) - (sizeof(tlvinfo_tlv_t) + 4)]; -+ if ((eeprom_crc->type != TLV_CODE_CRC_32) || (eeprom_crc->length != 4)) { -+ return false; -+ } -+ -+ // Calculate the checksum -+ calc_crc = crc32(0xffffffffL, (const unsigned char *)eeprom, sizeof(tlvinfo_header_t) + -+ be16_to_cpu(eeprom_hdr->totallen) - 4); -+ stored_crc = ((eeprom_crc->value[0] << 24) | (eeprom_crc->value[1] << 16) | -+ (eeprom_crc->value[2] << 8) | eeprom_crc->value[3]); -+ -+ return (calc_crc == stored_crc); -+} -+ -+/* -+ * tlvinfo_find_tlv -+ * -+ * This function finds the TLV with the supplied code in the EERPOM. -+ * An offset from the beginning of the EEPROM is returned in the -+ * eeprom_index parameter if the TLV is found. -+ */ -+static bool tlvinfo_find_tlv(u_int8_t *eeprom, u_int8_t tcode, int *eeprom_index) -+{ -+ tlvinfo_header_t *eeprom_hdr; -+ tlvinfo_tlv_t *eeprom_tlv; -+ int eeprom_end; -+ -+ eeprom_hdr = (tlvinfo_header_t *) eeprom; -+ -+ // Search through the TLVs, looking for the first one which matches the -+ // supplied type code. -+ *eeprom_index = sizeof(tlvinfo_header_t); -+ eeprom_end = sizeof(tlvinfo_header_t) + be16_to_cpu(eeprom_hdr->totallen); -+ while (*eeprom_index < eeprom_end) { -+ eeprom_tlv = (tlvinfo_tlv_t *) &eeprom[*eeprom_index]; -+ if (!is_valid_tlv(eeprom_tlv)) { -+ return false; -+ } -+ -+ if (eeprom_tlv->type == tcode) { -+ return true; -+ } -+ -+ *eeprom_index += sizeof(tlvinfo_tlv_t) + eeprom_tlv->length; -+ } -+ -+ return false; -+} -+ -+/* -+ * tlvinfo_decode_tlv -+ * -+ * This function finds the TLV with the supplied code in the EERPOM -+ * and decodes the value into the buffer provided. -+ */ -+static bool tlvinfo_decode_tlv(u_int8_t *eeprom, u_int8_t tcode, tlv_decode_value_t *decode_value) -+{ -+ int eeprom_index; -+ tlvinfo_tlv_t *eeprom_tlv; -+ -+ // Find the TLV and then decode it -+ if (tlvinfo_find_tlv(eeprom, tcode, &eeprom_index)) { -+ eeprom_tlv = (tlvinfo_tlv_t *) &eeprom[eeprom_index]; -+ decode_tlv_value(eeprom_tlv, decode_value); -+ return true; -+ } -+ -+ return false; -+} -+ -+/* -+ * parse_tlv_eeprom -+ * -+ * parse the EEPROM into memory, if it hasn't already been read. -+ */ -+int parse_tlv_eeprom(u_int8_t *eeprom, u_int32_t size) -+{ -+ unsigned int i; -+ bool ret; -+ tlvinfo_header_t *eeprom_hdr; -+ //tlv_info_vec_t tlv_info; -+ tlv_decode_value_t decode_value; -+ int j; -+ -+ eeprom_hdr = (tlvinfo_header_t *) eeprom; -+ eeprom_size = size; /* eeprom real size */ -+ -+ if (!is_valid_tlvinfo_header(eeprom_hdr)) { -+ DBG_ERROR("Failed to check tlv header.\n"); -+ return -1; -+ } -+ -+ if (!is_checksum_valid(eeprom)) { -+ DBG_ERROR("Failed to check tlv crc.\n"); -+ return -1; -+ } -+ -+ for (i = 0; i < TLV_CODE_NUM; i++) { -+ mem_clear((void *)&decode_value, sizeof(tlv_decode_value_t)); -+ ret = tlvinfo_decode_tlv(eeprom, tlv_code_list[i].m_code, &decode_value); -+ if (!ret) { -+ DBG_ERROR("No found type: %s\n", tlv_code_list[i].m_name); -+ continue; -+ } -+ -+ DBG_DEBUG("i: %d,Found type: %s tlv[%d]:%s\n", i, tlv_code_list[i].m_name, tlv_code_list[i].m_code, -+ decode_value.value); -+ for (j = 0; j < decode_value.length; j++) { -+ if ((j % 16) == 0) { -+ DBG_DEBUG("\n"); -+ } -+ DBG_DEBUG("%02x ", decode_value.value[j]); -+ } -+ DBG_DEBUG("\n\n"); -+ } -+ return 0; -+} -+static int dfd_parse_tlv_eeprom(u_int8_t *eeprom, u_int32_t size, u_int8_t main_type, tlv_decode_value_t *decode_value) -+{ -+ bool ret; -+ tlvinfo_header_t *eeprom_hdr; -+ //tlv_info_vec_t tlv_info; -+ int j; -+ -+ eeprom_hdr = (tlvinfo_header_t *) eeprom; -+ eeprom_size = size; /* eeprom real size */ -+ -+ if (!is_valid_tlvinfo_header(eeprom_hdr)) { -+ DBG_ERROR("Failed to check tlv header.\n"); -+ return -1; -+ } -+ -+ if (!is_checksum_valid(eeprom)) { -+ DBG_ERROR("Failed to check tlv crc.\n"); -+ return -1; -+ } -+ -+ ret = tlvinfo_decode_tlv(eeprom, main_type, decode_value); -+ if (!ret) { -+ DBG_ERROR("No found type: %d\n", main_type); -+ return -1; -+ } -+ -+ DBG_DEBUG("Found type: %d, value: %s\n", main_type,decode_value->value); -+ for (j = 0; j < decode_value->length; j++) { -+ if ((j % 16) == 0) { -+ DBG_DEBUG("\n"); -+ } -+ DBG_DEBUG("%02x ", decode_value->value[j]); -+ } -+ DBG_DEBUG("\n\n"); -+ -+ return 0; -+} -+ -+static int tlvinfo_find_wb_ext_tlv(tlv_decode_value_t *ext_tlv_value, u_int8_t ext_type, -+ u_int8_t *buf, u_int8_t *buf_len) -+{ -+ tlvinfo_tlv_t *eeprom_tlv; -+ int eeprom_end, eeprom_index; -+ -+ // Search through the TLVs, looking for the first one which matches the -+ // supplied type code. -+ DBG_DEBUG("ext_tlv_value->length: %d.\n", ext_tlv_value->length); -+ for (eeprom_index = 0; eeprom_index < ext_tlv_value->length; eeprom_index++) { -+ if ((eeprom_index % 16) == 0) { -+ DBG_DEBUG("\n"); -+ } -+ DBG_DEBUG("%02x ", ext_tlv_value->value[eeprom_index]); -+ } -+ -+ DBG_DEBUG("\n"); -+ -+ eeprom_index = 0; -+ eeprom_end = ext_tlv_value->length; -+ while (eeprom_index < eeprom_end) { -+ eeprom_tlv = (tlvinfo_tlv_t *) &(ext_tlv_value->value[eeprom_index]); -+ if (!is_valid_tlv(eeprom_tlv)) { -+ DBG_ERROR("tlv is not valid, eeprom_tlv->type 0x%x.\n", eeprom_tlv->type); -+ return -1; -+ } -+ -+ DBG_DEBUG("eeprom_tlv->length %d.\n", eeprom_tlv->length); -+ if (eeprom_tlv->type == ext_type) { -+ if (*buf_len >= eeprom_tlv->length) { -+ memcpy(buf, eeprom_tlv->value, eeprom_tlv->length); -+ DBG_DEBUG("eeprom_tlv->length %d.\n", eeprom_tlv->length); -+ *buf_len = eeprom_tlv->length; -+ return 0; -+ } -+ DBG_ERROR("buf_len %d small than info_len %d.\n", *buf_len, eeprom_tlv->length); -+ return -1; -+ } -+ -+ eeprom_index += sizeof(tlvinfo_tlv_t) + eeprom_tlv->length; -+ } -+ -+ DBG_ERROR("ext_type %d: tlv is not found.\n", ext_type); -+ return -1; -+} -+ -+int dfd_tlvinfo_get_e2prom_info(u_int8_t *eeprom, u_int32_t size, dfd_tlv_type_t *tlv_type, u_int8_t* buf, u_int8_t *buf_len) -+{ -+ tlv_decode_value_t decode_value; -+ int ret; -+ -+ if (eeprom == NULL || tlv_type == NULL || buf == NULL) { -+ DBG_ERROR("Input para invalid.\n"); -+ return -1; -+ } -+ -+ mem_clear((void *)&decode_value, sizeof(tlv_decode_value_t)); -+ ret = dfd_parse_tlv_eeprom(eeprom, size, tlv_type->main_type, &decode_value); -+ if (ret) { -+ DBG_ERROR("dfd_parse_tlv_eeprom failed ret %d.\n", ret); -+ return ret; -+ } -+ -+ if (tlv_type->main_type != TLV_CODE_VENDOR_EXT) { -+ if (*buf_len >= decode_value.length) { -+ memcpy(buf, decode_value.value, decode_value.length); -+ *buf_len = decode_value.length; -+ return 0; -+ } -+ DBG_ERROR("buf_len %d small than info_len %d.\n", *buf_len, decode_value.length); -+ return -1; -+ } -+ DBG_DEBUG("info_len %d.\n", decode_value.length); -+ -+ return tlvinfo_find_wb_ext_tlv(&decode_value, tlv_type->ext_type, buf, buf_len); -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.h -new file mode 100644 -index 000000000..6eaac5848 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.h -@@ -0,0 +1,121 @@ -+#ifndef DFD_OPENBMC_TLVEEPROM_H -+#define DFD_OPENBMC_TLVEEPROM_H -+ -+#ifndef u_int8_t -+#define u_int8_t unsigned char -+#endif -+ -+#ifndef u_int16_t -+#define u_int16_t unsigned short -+#endif -+ -+#ifndef u_int32_t -+#define u_int32_t unsigned int -+#endif -+ -+#ifndef be16_to_cpu -+#define be16_to_cpu(x) ntohs(x) -+#endif -+ -+#ifndef cpu_to_be16 -+#define cpu_to_be16(x) htons(x) -+#endif -+ -+/** -+ * The TLV Types. -+ * -+ * Keep these in sync with tlv_code_list in cmd_sys_eeprom.c -+ */ -+#define TLV_CODE_PRODUCT_NAME 0x21 -+#define TLV_CODE_PART_NUMBER 0x22 -+#define TLV_CODE_SERIAL_NUMBER 0x23 -+#define TLV_CODE_MAC_BASE 0x24 -+#define TLV_CODE_MANUF_DATE 0x25 -+#define TLV_CODE_DEVICE_VERSION 0x26 -+#define TLV_CODE_LABEL_REVISION 0x27 -+#define TLV_CODE_PLATFORM_NAME 0x28 -+#define TLV_CODE_ONIE_VERSION 0x29 -+#define TLV_CODE_MAC_SIZE 0x2A -+#define TLV_CODE_MANUF_NAME 0x2B -+#define TLV_CODE_MANUF_COUNTRY 0x2C -+#define TLV_CODE_VENDOR_NAME 0x2D -+#define TLV_CODE_DIAG_VERSION 0x2E -+#define TLV_CODE_SERVICE_TAG 0x2F -+#define TLV_CODE_VENDOR_EXT 0xFD -+#define TLV_CODE_CRC_32 0xFE -+ -+#define TLV_CODE_NAME_LEN 64 -+/* -+ * Struct for displaying the TLV codes and names. -+ */ -+struct tlv_code_desc { -+ u_int8_t m_code; -+ char m_name[TLV_CODE_NAME_LEN]; -+}; -+ -+typedef struct dfd_tlv_type_s { -+ u_int8_t main_type; -+ u_int8_t ext_type; -+} dfd_tlv_type_t; -+ -+// Header Field Constants -+#define TLV_INFO_ID_STRING "TlvInfo" -+#define TLV_INFO_VERSION 0x01 -+/*#define TLV_TOTAL_LEN_MAX (XXXXXXXX - sizeof(tlvinfo_header_t))*/ -+ -+struct __attribute__ ((__packed__)) tlvinfo_header_s { -+ char signature[8]; /* 0x00 - 0x07 EEPROM Tag "TlvInfo" */ -+ u_int8_t version; /* 0x08 Structure version */ -+ u_int16_t totallen; /* 0x09 - 0x0A Length of all data which follows */ -+}; -+typedef struct tlvinfo_header_s tlvinfo_header_t; -+ -+/* -+ * TlvInfo TLV: Layout of a TLV field -+ */ -+struct __attribute__ ((__packed__)) tlvinfo_tlv_s { -+ u_int8_t type; -+ u_int8_t length; -+ u_int8_t value[0]; -+}; -+typedef struct tlvinfo_tlv_s tlvinfo_tlv_t; -+ -+#define TLV_VALUE_MAX_LEN 255 -+/* -+ * The max decode value is currently for the 'raw' type or the 'vendor -+ * extension' type, both of which have the same decode format. The -+ * max decode string size is computed as follows: -+ * -+ * strlen(" 0xFF") * TLV_VALUE_MAX_LEN + 1 -+ * -+ */ -+#define TLV_DECODE_VALUE_MAX_LEN ((5 * TLV_VALUE_MAX_LEN) + 1) -+ -+typedef struct tlv_decode_value_s { -+ u_int8_t value[TLV_DECODE_VALUE_MAX_LEN]; -+ u_int32_t length; -+} tlv_decode_value_t; -+ -+typedef enum dfd_tlvinfo_ext_tlv_type_e { -+ DFD_TLVINFO_EXT_TLV_TYPE_DEV_TYPE = 1, -+} dfd_tlvinfo_ext_tlv_type_t; -+ -+#if 0 -+#define TLV_TIME_LEN 64 -+ -+int ipmi_tlv_validate_fru_area(const uint8_t fruid, const char *fru_file_name, -+ sd_bus *bus_type, const bool bmc_fru); -+ -+extern const char *get_vpd_key_names(int key_id); -+extern std::string getService(sdbusplus::bus::bus& bus, -+ const std::string& intf, -+ const std::string& path); -+extern std::string getFRUValue(const std::string& section, -+ const std::string& key, -+ const std::string& delimiter, -+ IPMIFruInfo& fruData); -+#endif -+ -+int dfd_tlvinfo_get_e2prom_info(u_int8_t *eeprom, u_int32_t size, dfd_tlv_type_t *tlv_type, u_int8_t* buf, u_int8_t *buf_len); -+ -+#endif /* endif DFD_OPENBMC_TLVEEPROM_H */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/fpga_i2c.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/fpga_i2c.h -new file mode 100644 -index 000000000..649a8452d ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/fpga_i2c.h -@@ -0,0 +1,133 @@ -+#ifndef _FPGA_I2C_H -+#define _FPGA_I2C_H -+ -+#include -+#include -+#include -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+ -+#if 0 -+ -+#define FPGA_I2C_EXT_9548_ADDR (0x00) -+#define FPGA_I2C_EXT_9548_CHAN (0x04) -+#define FPGA_I2C_DEV_SLAVE_ADDR (0x08) -+#define FPGA_I2C_DEV_REG_ADDR (0x0C) -+#define FPGA_I2C_DEV_RDWR_LEN (0x10) -+#define FPGA_I2C_CTRL_REG (0x14) -+#define FPGA_I2C_STATUS_REG (0x18) -+#define FPGA_I2C_SCALE_REG (0x1C) -+#define FPGA_I2C_FILTER_REG (0x20) -+#define FPGA_I2C_STRETCH_REG (0x24) -+#define FPGA_I2C_EXT_9548_EXITS_FLAG (0x28) -+#define FPGA_I2C_INTERNAL_9548_CHAN (0x2C) -+#define FPGA_I2C_RDWR_DATA_BUF (0x80) -+#endif -+#define FPGA_I2C_RDWR_MAX_LEN_DEFAULT (128) -+#define I2C_REG_MAX_WIDTH (16) -+ -+#define DEV_NAME_MAX_LEN (64) -+ -+#define FPGA_I2C_MAX_TIMES (10) -+#define FPGA_I2C_XFER_TIME_OUT (100000) -+#define FPGA_I2C_SLEEP_TIME (40) -+ -+typedef struct fpga_i2c_reg_s { -+ uint32_t i2c_scale; -+ uint32_t i2c_filter; -+ uint32_t i2c_stretch; -+ uint32_t i2c_ext_9548_exits_flag; -+ uint32_t i2c_ext_9548_addr; -+ uint32_t i2c_ext_9548_chan; -+ uint32_t i2c_in_9548_chan; -+ uint32_t i2c_slave; -+ uint32_t i2c_reg; -+ uint32_t i2c_reg_len; -+ uint32_t i2c_data_len; -+ uint32_t i2c_ctrl; -+ uint32_t i2c_status; -+ uint32_t i2c_err_vec; -+ uint32_t i2c_data_buf; -+ uint32_t i2c_data_buf_len; -+} fpga_i2c_reg_t; -+ -+typedef struct fpga_i2c_reset_cfg_s { -+ uint32_t i2c_adap_reset_flag; -+ uint32_t reset_addr; -+ uint32_t reset_on; -+ uint32_t reset_off; -+ uint32_t reset_delay_b; -+ uint32_t reset_delay; -+ uint32_t reset_delay_a; -+} fpga_i2c_reset_cfg_t; -+ -+typedef struct fpga_i2c_reg_addr_s { -+ uint8_t reg_addr_len; -+ uint8_t read_reg_addr[I2C_REG_MAX_WIDTH]; -+} fpga_i2c_reg_addr_t; -+ -+typedef struct fpga_i2c_dev_s { -+ fpga_i2c_reg_t reg; -+ fpga_i2c_reset_cfg_t reset_cfg; -+ fpga_i2c_reg_addr_t i2c_addr_desc; -+ const char *dev_name; -+ uint32_t i2c_scale_value; -+ uint32_t i2c_filter_value; -+ uint32_t i2c_stretch_value; -+ uint32_t i2c_timeout; -+ uint32_t i2c_func_mode; -+ wait_queue_head_t queue; -+ struct i2c_adapter adap; -+ int adap_nr; -+ struct device *dev; -+ bool i2c_params_check; -+} fpga_i2c_dev_t; -+ -+typedef struct fpga_i2c_bus_device_s { -+ int i2c_timeout; -+ int i2c_scale; -+ int i2c_filter; -+ int i2c_stretch; -+ int i2c_ext_9548_exits_flag; -+ int i2c_ext_9548_addr; -+ int i2c_ext_9548_chan; -+ int i2c_in_9548_chan; -+ int i2c_slave; -+ int i2c_reg; -+ int i2c_reg_len; -+ int i2c_data_len; -+ int i2c_ctrl; -+ int i2c_status; -+ int i2c_err_vec; -+ int i2c_data_buf; -+ int i2c_data_buf_len; -+ char dev_name[DEV_NAME_MAX_LEN]; -+ int adap_nr; -+ int i2c_scale_value; -+ int i2c_filter_value; -+ int i2c_stretch_value; -+ int i2c_func_mode; -+ int i2c_adap_reset_flag; -+ int i2c_reset_addr; -+ int i2c_reset_on; -+ int i2c_reset_off; -+ int i2c_rst_delay_b; /* delay time before reset(us) */ -+ int i2c_rst_delay; /* reset time(us) */ -+ int i2c_rst_delay_a; /* delay time after reset(us) */ -+ int device_flag; -+ bool i2c_params_check; -+ int i2c_data_buf_len_reg; -+ int i2c_offset_reg; -+} fpga_i2c_bus_device_t; -+ -+typedef struct fpga_pca954x_device_s { -+ struct i2c_client *client; -+ uint32_t i2c_bus; -+ uint32_t i2c_addr; -+ uint32_t fpga_9548_flag; -+ uint32_t fpga_9548_reset_flag; -+ uint32_t pca9548_base_nr; -+} fpga_pca954x_device_t; -+ -+#endif /* _FPGA_I2C_H */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.c -new file mode 100644 -index 000000000..e74f4e800 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.c -@@ -0,0 +1,608 @@ -+/* -+ * hw_test.c -+ * Original Author : support, 2020-10-15 -+ * -+ * History -+ * v1.0 support 2020-10-15 Initial version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "hw_test.h" -+ -+extern struct bus_type mdio_bus_type; -+ -+struct board_mdio_dev { -+ struct list_head list; -+ struct mii_bus *mdio_bus; -+ int mdio_index; -+}; -+ -+struct board_phy_dev { -+ struct list_head list; -+ struct phy_device *phydev; -+ int phy_index; -+}; -+ -+static LIST_HEAD(mdio_dev_list); -+static LIST_HEAD(phydev_list); -+static struct class *class_mdio_bus = NULL; -+ -+#define PRINT_BUF_SIZE (256) -+#define INVALID_PHY_ADDR (0xFF) -+#define MAX_MDIO_DEVICE_NUMS (1000) -+#define MAX_PHY_DEVICE_NUMS (1000) -+ -+#define dram_debug(fmt, ...) \ -+ printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__) -+ -+static ssize_t dram_dev_read (struct file *file, char __user *buf, size_t count, -+ loff_t *offset) -+{ -+ u8 value8; -+ u16 value16; -+ u32 value32; -+ -+ if (file->private_data != NULL) { -+ return -EINVAL; -+ } -+ -+ file->private_data = ioremap(file->f_pos, count); -+ -+ if (!file->private_data) { -+ pr_notice("%s, %d\n", __FUNCTION__, __LINE__); -+ return -ENODEV; -+ } -+ -+ rmb(); -+ switch (count) { -+ case 1: -+ value8 = readb(file->private_data); -+ if (copy_to_user(buf, &value8, sizeof(u8))) { -+ return -EFAULT; -+ } -+ break; -+ case 2: -+ value16 = readw(file->private_data); -+ if (copy_to_user(buf, &value16, sizeof(u16))) { -+ return -EFAULT; -+ } -+ break; -+ case 4: -+ value32 = readl(file->private_data); -+ if (copy_to_user(buf, &value32, sizeof(u32))) { -+ return -EFAULT; -+ } -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ iounmap(file->private_data); -+ file->private_data = NULL; -+ return count; -+ -+} -+ -+static ssize_t dram_dev_write (struct file *file, const char __user *buf, size_t count, -+ loff_t *offset) -+{ -+ u8 value8; -+ u16 value16; -+ u32 value32; -+ -+ if (file->private_data != NULL) { -+ return -EINVAL; -+ } -+ -+ file->private_data = ioremap(file->f_pos, count); -+ -+ if (!file->private_data) { -+ pr_err("%s, %d\n", __FUNCTION__, __LINE__); -+ return -ENODEV; -+ } -+ -+ switch (count) { -+ case 1: -+ if (copy_from_user(&value8, buf, sizeof(u8))) { -+ return -EFAULT; -+ } -+ writeb(value8, file->private_data); -+ break; -+ case 2: -+ if (copy_from_user(&value16, buf, sizeof(u16))) { -+ return -EFAULT; -+ } -+ writew(value16, file->private_data); -+ break; -+ case 4: -+ if (copy_from_user(&value32, buf, sizeof(u32))) { -+ return -EFAULT; -+ } -+ writel(value32, file->private_data); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ wmb(); -+ iounmap(file->private_data); -+ file->private_data = NULL; -+ return count; -+} -+ -+static loff_t dram_dev_llseek(struct file *file, loff_t offset, int origin) -+{ -+ loff_t ret; -+ -+ switch (origin) { -+ case 0: -+ file->f_pos = offset; -+ ret = file->f_pos; -+ break; -+ case 1: -+ file->f_pos += offset; -+ ret = file->f_pos; -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ return ret; -+} -+ -+static int temp_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum) -+{ -+ return 0; -+} -+ -+static int temp_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value) -+{ -+ return 0; -+} -+ -+static int init_class_mdio_bus(void) -+{ -+ struct mii_bus *bus; -+ int err = 0; -+ -+ bus = mdiobus_alloc(); -+ -+ bus->name = "temp_mdio_bus"; -+ snprintf(bus->id, MII_BUS_ID_SIZE, "temp_mdio_bus0"); -+ bus->read = temp_mdiobus_read; -+ bus->write = temp_mdiobus_write; -+ -+ err = mdiobus_register(bus); -+ if (err) { -+ printk(KERN_ERR "temp mdio bus register fail\n"); -+ return -1; -+ } -+ -+ class_mdio_bus = bus->dev.class; -+ mdiobus_unregister(bus); -+ -+ return 0; -+} -+ -+static int mdio_match_success(struct device *dev, const void * data) -+{ -+ -+ return 1; -+} -+ -+static int add_all_mdio_devices_to_list(void) -+{ -+ struct device *dev, *dev_start = NULL; -+ struct board_mdio_dev *mdio_dev = NULL; -+ int i = 0; -+ struct class *bus_class = class_mdio_bus; -+ -+ for (i = 0; i < MAX_MDIO_DEVICE_NUMS; i++) { -+ dev = class_find_device(bus_class, dev_start, NULL, mdio_match_success); -+ if (dev != NULL) { -+ mdio_dev = kzalloc(sizeof(struct board_mdio_dev), GFP_KERNEL); -+ if (mdio_dev == NULL) { -+ printk(KERN_ERR "%s: alloc fail\n", __func__); -+ return -EFAULT; -+ } -+ -+ mdio_dev->mdio_index = i; -+ mdio_dev->mdio_bus = to_mii_bus(dev); -+ list_add_tail(&mdio_dev->list, &mdio_dev_list); -+ -+ dev_start = dev; -+ } else { -+ break; -+ } -+ } -+ -+ printk(KERN_INFO "mdio dev numbers = %d\n", i); -+ -+ return 0; -+} -+ -+static void delete_all_mdio_devices_from_list(void) -+{ -+ struct list_head *n, *pos; -+ struct board_mdio_dev *mdio_dev; -+ -+ list_for_each_safe(pos, n, &mdio_dev_list) { -+ list_del(pos); -+ mdio_dev = list_entry(pos, struct board_mdio_dev, list); -+ kfree(mdio_dev); -+ } -+ -+ return; -+} -+ -+void list_all_mdio_devices_info(void) -+{ -+ struct board_mdio_dev *mdio_dev; -+ unsigned char phyaddr[PHY_MAX_ADDR]; -+ int i = 0, j = 0; -+ int phydev_num = 0; -+ char buf[PRINT_BUF_SIZE]; -+ int len = 0; -+ -+ printk(KERN_INFO "all the mdio devs info:\n"); -+ printk(KERN_INFO "index busid name phy_num phyaddr \n"); -+ list_for_each_entry(mdio_dev, &mdio_dev_list, list) { -+ i = 0; -+ j = 0; -+ phydev_num = 0; -+ mem_clear(phyaddr, INVALID_PHY_ADDR, sizeof(phyaddr)); -+ mem_clear(buf, 0, sizeof(buf)); -+ -+ for (i = 0; i < PHY_MAX_ADDR; i++) { -+ if (mdio_dev->mdio_bus->mdio_map[i]) { -+ phydev_num++; -+ phyaddr[j] = (unsigned char)i; -+ j++; -+ } -+ } -+ -+ len = snprintf(buf, sizeof(buf), " %-10d %-20s %-20s %-10d ", mdio_dev->mdio_index, -+ mdio_dev->mdio_bus->id, mdio_dev->mdio_bus->name, phydev_num); -+ -+ for (i = 0; i < PHY_MAX_ADDR; i++) { -+ if (phyaddr[i] == INVALID_PHY_ADDR) { -+ break; -+ } -+ -+ len += snprintf(&buf[len], sizeof(buf) - len, " %#x", phyaddr[i]); -+ } -+ -+ printk(KERN_INFO "%s\n", buf); -+ } -+ -+ return; -+} -+ -+static struct mii_bus *get_mdio_dev_according_to_index(int mdio_index) -+{ -+ struct board_mdio_dev *mdio_dev; -+ list_for_each_entry(mdio_dev, &mdio_dev_list, list) { -+ if (mdio_dev->mdio_index == mdio_index) { -+ return mdio_dev->mdio_bus; -+ } -+ } -+ -+ printk(KERN_ERR "no exist the mdio dev it's mdio_index = %d, please exec cmd [hw_test.bin mdiodev_list] to view mdiodev info\n", -+ mdio_index); -+ -+ return NULL; -+} -+ -+int board_mdio_read(int mdio_index, int phyaddr, u32 regnum) -+{ -+ struct mii_bus *bus; -+ int reg_val; -+ -+ bus = get_mdio_dev_according_to_index(mdio_index); -+ if (bus == NULL) { -+ return -1; -+ } -+ -+ reg_val = mdiobus_read(bus, phyaddr, regnum); -+ -+ return reg_val; -+} -+ -+int board_mdio_write(int mdio_index, int phyaddr, u32 regnum, u16 val) -+{ -+ struct mii_bus *bus; -+ int ret; -+ -+ bus = get_mdio_dev_according_to_index(mdio_index); -+ if (bus == NULL) { -+ return -1; -+ } -+ -+ ret = mdiobus_write(bus, phyaddr, regnum, val); -+ -+ return ret; -+} -+ -+static int phy_match_success(struct device *dev, const void * data) -+{ -+ -+ return 1; -+} -+ -+static int add_all_phydevs_to_list(void) -+{ -+ struct device *dev, *dev_start = NULL; -+ struct board_phy_dev *board_phydev = NULL; -+ int i = 0; -+ -+ for (i = 0; i < MAX_PHY_DEVICE_NUMS; i++) { -+ dev = bus_find_device(&mdio_bus_type, dev_start, NULL, phy_match_success); -+ if (dev != NULL) { -+ board_phydev = kzalloc(sizeof(struct board_phy_dev), GFP_KERNEL); -+ if (board_phydev == NULL) { -+ printk(KERN_ERR "%s: alloc fail\n", __func__); -+ return -EFAULT; -+ } -+ -+ board_phydev->phy_index = i; -+ board_phydev->phydev = to_phy_device(dev); -+ list_add_tail(&board_phydev->list, &phydev_list); -+ -+ dev_start = dev; -+ } else { -+ break; -+ } -+ } -+ -+ printk(KERN_INFO "phydev num = %d\n", i); -+ -+ return 0; -+} -+ -+static void delete_all_phydevs_from_list(void) -+{ -+ struct list_head *n, *pos; -+ struct board_phy_dev *board_phydev; -+ -+ list_for_each_safe(pos, n, &phydev_list) { -+ list_del(pos); -+ board_phydev = list_entry(pos, struct board_phy_dev, list); -+ kfree(board_phydev); -+ } -+ -+ return; -+} -+ -+void list_all_phydevs_info(void) -+{ -+ struct board_phy_dev *board_phydev; -+ -+ printk(KERN_INFO "all the phydevs info:\n"); -+ printk(KERN_INFO "index phyaddr phyId phydev_name\n"); -+ list_for_each_entry(board_phydev, &phydev_list, list) { -+ printk(KERN_INFO " %-10d %#-10x %#-10x %-20s\n", board_phydev->phy_index, board_phydev->phydev->mdio.addr,\ -+ board_phydev->phydev->phy_id, dev_name(&board_phydev->phydev->mdio.dev)); -+ } -+ -+ return; -+} -+ -+static struct phy_device *get_phy_dev_according_to_index(int phy_index) -+{ -+ struct board_phy_dev *board_phydev; -+ list_for_each_entry(board_phydev, &phydev_list, list) { -+ if (board_phydev->phy_index == phy_index) { -+ return board_phydev->phydev; -+ } -+ } -+ -+ printk(KERN_ERR "no exist the phydev it's phy_index = %d, please exec cmd [hw_test.bin phydev_list] to view phydev info\n", phy_index); -+ -+ return NULL; -+} -+ -+int board_phy_read(int phy_index, u32 regnum) -+{ -+ struct phy_device *phydev; -+ int reg_val; -+ -+ phydev = get_phy_dev_according_to_index(phy_index); -+ if (phydev == NULL) { -+ return -1; -+ } -+ -+ reg_val = phy_read(phydev, regnum); -+ -+ return reg_val; -+} -+ -+int board_phy_write(int phy_index, u32 regnum, u16 val) -+{ -+ struct phy_device *phydev; -+ int ret; -+ -+ phydev = get_phy_dev_according_to_index(phy_index); -+ if (phydev == NULL) { -+ return -1; -+ } -+ -+ ret = phy_write(phydev, regnum, val); -+ -+ return ret; -+} -+ -+static long dram_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ void __user *argp = (void __user *)arg; -+ int ret = 0; -+ struct phydev_user_info phy_user_info; -+ struct mdio_dev_user_info mdio_user_info; -+ -+ switch (cmd) { -+ case CMD_PHY_LIST: -+ list_all_phydevs_info(); -+ break; -+ -+ case CMD_PHY_READ: -+ if (copy_from_user(&phy_user_info, argp, sizeof(struct phydev_user_info))) -+ return -EFAULT; -+ -+ ret = board_phy_read(phy_user_info.phy_index, phy_user_info.regnum); -+ if (ret < 0) { -+ return -EFAULT; -+ } -+ -+ phy_user_info.regval = (u32)ret; -+ -+ if (copy_to_user(argp, &phy_user_info, sizeof(struct phydev_user_info))) -+ return -EFAULT; -+ -+ break; -+ -+ case CMD_PHY_WRITE: -+ if (copy_from_user(&phy_user_info, argp, sizeof(struct phydev_user_info))) -+ return -EFAULT; -+ -+ ret = board_phy_write(phy_user_info.phy_index, phy_user_info.regnum, (u16)phy_user_info.regval); -+ if (ret < 0) { -+ return -EFAULT; -+ } -+ -+ break; -+ -+ case CMD_MDIO_LIST: -+ list_all_mdio_devices_info(); -+ break; -+ -+ case CMD_MDIO_READ: -+ if (copy_from_user(&mdio_user_info, argp, sizeof(struct mdio_dev_user_info))) -+ return -EFAULT; -+ -+ ret = board_mdio_read(mdio_user_info.mdio_index, mdio_user_info.phyaddr, mdio_user_info.regnum); -+ if (ret < 0) { -+ return -EFAULT; -+ } -+ -+ mdio_user_info.regval = (u32)ret; -+ -+ if (copy_to_user(argp, &mdio_user_info, sizeof(struct mdio_dev_user_info))) -+ return -EFAULT; -+ -+ break; -+ -+ case CMD_MDIO_WRITE: -+ if (copy_from_user(&mdio_user_info, argp, sizeof(struct mdio_dev_user_info))) -+ return -EFAULT; -+ -+ ret = board_mdio_write(mdio_user_info.mdio_index, mdio_user_info.phyaddr, mdio_user_info.regnum, (u16)mdio_user_info.regval); -+ if (ret < 0) { -+ return -EFAULT; -+ } -+ -+ break; -+ -+ default: -+ printk("unknown ioctl cmd\n"); -+ break; -+ } -+ -+ return 0; -+} -+ -+static int dram_dev_open(struct inode *inode, struct file *file) -+{ -+ file->private_data = NULL; -+ file->f_pos = 0; -+ return 0; -+ -+} -+ -+static int dram_dev_release(struct inode *inode, struct file *file) -+{ -+ if (file->private_data) { -+ iounmap(file->private_data); -+ } -+ return 0; -+} -+ -+static const struct file_operations dram_dev_fops = { -+ .owner = THIS_MODULE, -+ .llseek = dram_dev_llseek, -+ .read = dram_dev_read, -+ .write = dram_dev_write, -+ .unlocked_ioctl = dram_dev_ioctl, -+ .open = dram_dev_open, -+ .release = dram_dev_release, -+}; -+ -+static struct miscdevice dram_dev = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "dram_test", -+ .fops = &dram_dev_fops, -+}; -+ -+static int __init dram_init(void) -+{ -+ if (add_all_phydevs_to_list() != 0) { -+ printk(KERN_ERR "add all phydev to list fail\n"); -+ delete_all_phydevs_from_list(); -+ return -ENXIO; -+ } -+ -+ if (init_class_mdio_bus() == 0) { -+ if (add_all_mdio_devices_to_list() == -EFAULT) { -+ printk(KERN_ERR "add all mdiodev to list fail\n"); -+ delete_all_mdio_devices_from_list(); -+ delete_all_phydevs_from_list(); -+ return -ENXIO; -+ } -+ } -+ -+ if (misc_register(&dram_dev) != 0) { -+ pr_notice("Register %s failed.\n", dram_dev.name); -+ delete_all_mdio_devices_from_list(); -+ delete_all_phydevs_from_list(); -+ return -ENXIO; -+ } -+ -+ return 0; -+} -+ -+static void __exit dram_exit(void) -+{ -+ misc_deregister(&dram_dev); -+ -+ delete_all_mdio_devices_from_list(); -+ delete_all_phydevs_from_list(); -+} -+ -+module_init(dram_init); -+module_exit(dram_exit); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.h -new file mode 100644 -index 000000000..695fa336c ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.h -@@ -0,0 +1,31 @@ -+ -+#ifndef _LINUX_DRAM_DRIVER_H -+#define _LINUX_DRAM_DRIVER_H -+ -+#include -+#include -+ -+#define mem_clear(data, val, size) memset((data), val, (size)) -+ -+struct phydev_user_info { -+ int phy_index; -+ u32 regnum; -+ u32 regval; -+}; -+ -+#define CMD_PHY_LIST _IOR('P', 0, struct phydev_user_info) -+#define CMD_PHY_READ _IOR('P', 1, struct phydev_user_info) -+#define CMD_PHY_WRITE _IOR('P', 2, struct phydev_user_info) -+ -+struct mdio_dev_user_info { -+ int mdio_index; -+ int phyaddr; -+ u32 regnum; -+ u32 regval; -+}; -+ -+#define CMD_MDIO_LIST _IOR('M', 0, struct mdio_dev_user_info) -+#define CMD_MDIO_READ _IOR('M', 1, struct mdio_dev_user_info) -+#define CMD_MDIO_WRITE _IOR('M', 2, struct mdio_dev_user_info) -+ -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/Makefile -new file mode 100644 -index 000000000..b84963167 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/Makefile -@@ -0,0 +1,22 @@ -+PWD = $(shell pwd) -+ -+EXTRA_CFLAGS:= -I$(M)/include -+EXTRA_CFLAGS+= -Wall -+#ifdef ENABLE_GCOV -+#ifeq ($(ENABLE_GCOV), y) -+#EXTRA_CFLAGS+= -fprofile-arcs -ftest-coverage -lgcov -+#endif -+#endif # ENABLE_GCOV -+ -+obj-m := intel_spi.o -+obj-m += intel_spi_platform.o -+obj-m += intel_spi_pci.o -+ -+all: -+ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules -+ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi -+ cp -p $(PWD)/*.ko $(module_out_put_dir) -+clean: -+ rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd -+ rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order -+ rm -rf $(PWD)/.tmp_versions -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/include/intel_spi.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/include/intel_spi.h -new file mode 100644 -index 000000000..d0a570b1f ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/include/intel_spi.h -@@ -0,0 +1,23 @@ -+/* SPDX-License-Identifier: GPL-2.0-only */ -+/* -+ * Intel PCH/PCU SPI flash driver. -+ * -+ * Copyright (C) 2016, Intel Corporation -+ * Author: Mika Westerberg -+ */ -+ -+#ifndef INTEL_SPI_H -+#define INTEL_SPI_H -+ -+#include -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+struct intel_spi; -+struct resource; -+ -+struct intel_spi *intel_spi_probe(struct device *dev, -+ struct resource *mem, const struct intel_spi_boardinfo *info); -+int intel_spi_remove(struct intel_spi *ispi); -+ -+#endif /* INTEL_SPI_H */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi.c -new file mode 100644 -index 000000000..a111d5221 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi.c -@@ -0,0 +1,966 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Intel PCH/PCU SPI flash driver. -+ * -+ * Copyright (C) 2016, Intel Corporation -+ * Author: Mika Westerberg -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "intel_spi.h" -+ -+/* Offsets are from @ispi->base */ -+#define BFPREG 0x00 -+ -+#define HSFSTS_CTL 0x04 -+#define HSFSTS_CTL_FSMIE BIT(31) -+#define HSFSTS_CTL_FDBC_SHIFT 24 -+#define HSFSTS_CTL_FDBC_MASK (0x3f << HSFSTS_CTL_FDBC_SHIFT) -+ -+#define HSFSTS_CTL_FCYCLE_SHIFT 17 -+#define HSFSTS_CTL_FCYCLE_MASK (0x0f << HSFSTS_CTL_FCYCLE_SHIFT) -+/* HW sequencer opcodes */ -+#define HSFSTS_CTL_FCYCLE_READ (0x00 << HSFSTS_CTL_FCYCLE_SHIFT) -+#define HSFSTS_CTL_FCYCLE_WRITE (0x02 << HSFSTS_CTL_FCYCLE_SHIFT) -+#define HSFSTS_CTL_FCYCLE_ERASE (0x03 << HSFSTS_CTL_FCYCLE_SHIFT) -+#define HSFSTS_CTL_FCYCLE_ERASE_64K (0x04 << HSFSTS_CTL_FCYCLE_SHIFT) -+#define HSFSTS_CTL_FCYCLE_RDID (0x06 << HSFSTS_CTL_FCYCLE_SHIFT) -+#define HSFSTS_CTL_FCYCLE_WRSR (0x07 << HSFSTS_CTL_FCYCLE_SHIFT) -+#define HSFSTS_CTL_FCYCLE_RDSR (0x08 << HSFSTS_CTL_FCYCLE_SHIFT) -+ -+#define HSFSTS_CTL_FGO BIT(16) -+#define HSFSTS_CTL_FLOCKDN BIT(15) -+#define HSFSTS_CTL_FDV BIT(14) -+#define HSFSTS_CTL_SCIP BIT(5) -+#define HSFSTS_CTL_AEL BIT(2) -+#define HSFSTS_CTL_FCERR BIT(1) -+#define HSFSTS_CTL_FDONE BIT(0) -+ -+#define FADDR 0x08 -+#define DLOCK 0x0c -+#define FDATA(n) (0x10 + ((n) * 4)) -+ -+#define FRACC 0x50 -+ -+#define FREG(n) (0x54 + ((n) * 4)) -+#define FREG_BASE_MASK GENMASK(14, 0) -+#define FREG_LIMIT_SHIFT 16 -+#define FREG_LIMIT_MASK GENMASK(30, 16) -+ -+/* Offset is from @ispi->pregs */ -+#define PR(n) ((n) * 4) -+#define PR_WPE BIT(31) -+#define PR_LIMIT_SHIFT 16 -+#define PR_LIMIT_MASK GENMASK(30, 16) -+#define PR_RPE BIT(15) -+#define PR_BASE_MASK GENMASK(14, 0) -+ -+/* Offsets are from @ispi->sregs */ -+#define SSFSTS_CTL 0x00 -+#define SSFSTS_CTL_FSMIE BIT(23) -+#define SSFSTS_CTL_DS BIT(22) -+#define SSFSTS_CTL_DBC_SHIFT 16 -+#define SSFSTS_CTL_SPOP BIT(11) -+#define SSFSTS_CTL_ACS BIT(10) -+#define SSFSTS_CTL_SCGO BIT(9) -+#define SSFSTS_CTL_COP_SHIFT 12 -+#define SSFSTS_CTL_FRS BIT(7) -+#define SSFSTS_CTL_DOFRS BIT(6) -+#define SSFSTS_CTL_AEL BIT(4) -+#define SSFSTS_CTL_FCERR BIT(3) -+#define SSFSTS_CTL_FDONE BIT(2) -+#define SSFSTS_CTL_SCIP BIT(0) -+ -+#define PREOP_OPTYPE 0x04 -+#define OPMENU0 0x08 -+#define OPMENU1 0x0c -+ -+#define OPTYPE_READ_NO_ADDR 0 -+#define OPTYPE_WRITE_NO_ADDR 1 -+#define OPTYPE_READ_WITH_ADDR 2 -+#define OPTYPE_WRITE_WITH_ADDR 3 -+ -+/* CPU specifics */ -+#define BYT_PR 0x74 -+#define BYT_SSFSTS_CTL 0x90 -+#define BYT_BCR 0xfc -+#define BYT_BCR_WPD BIT(0) -+#define BYT_FREG_NUM 5 -+#define BYT_PR_NUM 5 -+ -+#define LPT_PR 0x74 -+#define LPT_SSFSTS_CTL 0x90 -+#define LPT_FREG_NUM 5 -+#define LPT_PR_NUM 5 -+ -+#define BXT_PR 0x84 -+#define BXT_SSFSTS_CTL 0xa0 -+#define BXT_FREG_NUM 12 -+#define BXT_PR_NUM 6 -+ -+#define CNL_PR 0x84 -+#define CNL_FREG_NUM 6 -+#define CNL_PR_NUM 5 -+ -+#define LVSCC 0xc4 -+#define UVSCC 0xc8 -+#define ERASE_OPCODE_SHIFT 8 -+#define ERASE_OPCODE_MASK (0xff << ERASE_OPCODE_SHIFT) -+#define ERASE_64K_OPCODE_SHIFT 16 -+#define ERASE_64K_OPCODE_MASK (0xff << ERASE_64K_OPCODE_SHIFT) -+ -+#define INTEL_SPI_TIMEOUT 5000 /* ms */ -+#define INTEL_SPI_FIFO_SZ 64 -+ -+/** -+ * struct intel_spi - Driver private data -+ * @dev: Device pointer -+ * @info: Pointer to board specific info -+ * @nor: SPI NOR layer structure -+ * @base: Beginning of MMIO space -+ * @pregs: Start of protection registers -+ * @sregs: Start of software sequencer registers -+ * @nregions: Maximum number of regions -+ * @pr_num: Maximum number of protected range registers -+ * @locked: Is SPI setting locked -+ * @swseq_reg: Use SW sequencer in register reads/writes -+ * @swseq_erase: Use SW sequencer in erase operation -+ * @erase_64k: 64k erase supported -+ * @atomic_preopcode: Holds preopcode when atomic sequence is requested -+ * @opcodes: Opcodes which are supported. This are programmed by BIOS -+ * before it locks down the controller. -+ */ -+struct intel_spi { -+ struct device *dev; -+ const struct intel_spi_boardinfo *info; -+ struct spi_nor nor; -+ void __iomem *base; -+ void __iomem *pregs; -+ void __iomem *sregs; -+ size_t nregions; -+ size_t pr_num; -+ bool locked; -+ bool swseq_reg; -+ bool swseq_erase; -+ bool erase_64k; -+ u8 atomic_preopcode; -+ u8 opcodes[8]; -+}; -+ -+static bool writeable; -+module_param(writeable, bool, 0); -+MODULE_PARM_DESC(writeable, "Enable write access to SPI flash chip (default=0)"); -+ -+static void intel_spi_dump_regs(struct intel_spi *ispi) -+{ -+ u32 value; -+ int i; -+ -+ dev_dbg(ispi->dev, "BFPREG=0x%08x\n", readl(ispi->base + BFPREG)); -+ -+ value = readl(ispi->base + HSFSTS_CTL); -+ dev_dbg(ispi->dev, "HSFSTS_CTL=0x%08x\n", value); -+ if (value & HSFSTS_CTL_FLOCKDN) -+ dev_dbg(ispi->dev, "-> Locked\n"); -+ -+ dev_dbg(ispi->dev, "FADDR=0x%08x\n", readl(ispi->base + FADDR)); -+ dev_dbg(ispi->dev, "DLOCK=0x%08x\n", readl(ispi->base + DLOCK)); -+ -+ for (i = 0; i < 16; i++) -+ dev_dbg(ispi->dev, "FDATA(%d)=0x%08x\n", -+ i, readl(ispi->base + FDATA(i))); -+ -+ dev_dbg(ispi->dev, "FRACC=0x%08x\n", readl(ispi->base + FRACC)); -+ -+ for (i = 0; i < ispi->nregions; i++) -+ dev_dbg(ispi->dev, "FREG(%d)=0x%08x\n", i, -+ readl(ispi->base + FREG(i))); -+ for (i = 0; i < ispi->pr_num; i++) -+ dev_dbg(ispi->dev, "PR(%d)=0x%08x\n", i, -+ readl(ispi->pregs + PR(i))); -+ -+ if (ispi->sregs) { -+ value = readl(ispi->sregs + SSFSTS_CTL); -+ dev_dbg(ispi->dev, "SSFSTS_CTL=0x%08x\n", value); -+ dev_dbg(ispi->dev, "PREOP_OPTYPE=0x%08x\n", -+ readl(ispi->sregs + PREOP_OPTYPE)); -+ dev_dbg(ispi->dev, "OPMENU0=0x%08x\n", -+ readl(ispi->sregs + OPMENU0)); -+ dev_dbg(ispi->dev, "OPMENU1=0x%08x\n", -+ readl(ispi->sregs + OPMENU1)); -+ } -+ -+ if (ispi->info->type == INTEL_SPI_BYT) -+ dev_dbg(ispi->dev, "BCR=0x%08x\n", readl(ispi->base + BYT_BCR)); -+ -+ dev_dbg(ispi->dev, "LVSCC=0x%08x\n", readl(ispi->base + LVSCC)); -+ dev_dbg(ispi->dev, "UVSCC=0x%08x\n", readl(ispi->base + UVSCC)); -+ -+ dev_dbg(ispi->dev, "Protected regions:\n"); -+ for (i = 0; i < ispi->pr_num; i++) { -+ u32 base, limit; -+ -+ value = readl(ispi->pregs + PR(i)); -+ if (!(value & (PR_WPE | PR_RPE))) -+ continue; -+ -+ limit = (value & PR_LIMIT_MASK) >> PR_LIMIT_SHIFT; -+ base = value & PR_BASE_MASK; -+ -+ dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x [%c%c]\n", -+ i, base << 12, (limit << 12) | 0xfff, -+ value & PR_WPE ? 'W' : '.', -+ value & PR_RPE ? 'R' : '.'); -+ } -+ -+ dev_dbg(ispi->dev, "Flash regions:\n"); -+ for (i = 0; i < ispi->nregions; i++) { -+ u32 region, base, limit; -+ -+ region = readl(ispi->base + FREG(i)); -+ base = region & FREG_BASE_MASK; -+ limit = (region & FREG_LIMIT_MASK) >> FREG_LIMIT_SHIFT; -+ -+ if (base >= limit || (i > 0 && limit == 0)) -+ dev_dbg(ispi->dev, " %02d disabled\n", i); -+ else -+ dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x\n", -+ i, base << 12, (limit << 12) | 0xfff); -+ } -+ -+ dev_dbg(ispi->dev, "Using %cW sequencer for register access\n", -+ ispi->swseq_reg ? 'S' : 'H'); -+ dev_dbg(ispi->dev, "Using %cW sequencer for erase operation\n", -+ ispi->swseq_erase ? 'S' : 'H'); -+} -+ -+/* Reads max INTEL_SPI_FIFO_SZ bytes from the device fifo */ -+static int intel_spi_read_block(struct intel_spi *ispi, void *buf, size_t size) -+{ -+ size_t bytes; -+ int i = 0; -+ -+ if (size > INTEL_SPI_FIFO_SZ) -+ return -EINVAL; -+ -+ while (size > 0) { -+ bytes = min_t(size_t, size, 4); -+ memcpy_fromio(buf, ispi->base + FDATA(i), bytes); -+ size -= bytes; -+ buf += bytes; -+ i++; -+ } -+ -+ return 0; -+} -+ -+/* Writes max INTEL_SPI_FIFO_SZ bytes to the device fifo */ -+static int intel_spi_write_block(struct intel_spi *ispi, const void *buf, -+ size_t size) -+{ -+ size_t bytes; -+ int i = 0; -+ -+ if (size > INTEL_SPI_FIFO_SZ) -+ return -EINVAL; -+ -+ while (size > 0) { -+ bytes = min_t(size_t, size, 4); -+ memcpy_toio(ispi->base + FDATA(i), buf, bytes); -+ size -= bytes; -+ buf += bytes; -+ i++; -+ } -+ -+ return 0; -+} -+ -+static int intel_spi_wait_hw_busy(struct intel_spi *ispi) -+{ -+ u32 val; -+ -+ return readl_poll_timeout(ispi->base + HSFSTS_CTL, val, -+ !(val & HSFSTS_CTL_SCIP), 0, -+ INTEL_SPI_TIMEOUT * 1000); -+} -+ -+static int intel_spi_wait_sw_busy(struct intel_spi *ispi) -+{ -+ u32 val; -+ -+ return readl_poll_timeout(ispi->sregs + SSFSTS_CTL, val, -+ !(val & SSFSTS_CTL_SCIP), 0, -+ INTEL_SPI_TIMEOUT * 1000); -+} -+ -+static bool intel_spi_set_writeable(struct intel_spi *ispi) -+{ -+ if (!ispi->info->set_writeable) -+ return false; -+ -+ return ispi->info->set_writeable(ispi->base, ispi->info->data); -+} -+ -+static int intel_spi_init(struct intel_spi *ispi) -+{ -+ u32 opmenu0, opmenu1, lvscc, uvscc, val; -+ int i; -+ -+ switch (ispi->info->type) { -+ case INTEL_SPI_BYT: -+ ispi->sregs = ispi->base + BYT_SSFSTS_CTL; -+ ispi->pregs = ispi->base + BYT_PR; -+ ispi->nregions = BYT_FREG_NUM; -+ ispi->pr_num = BYT_PR_NUM; -+ ispi->swseq_reg = true; -+ break; -+ -+ case INTEL_SPI_LPT: -+ ispi->sregs = ispi->base + LPT_SSFSTS_CTL; -+ ispi->pregs = ispi->base + LPT_PR; -+ ispi->nregions = LPT_FREG_NUM; -+ ispi->pr_num = LPT_PR_NUM; -+ ispi->swseq_reg = true; -+ break; -+ -+ case INTEL_SPI_BXT: -+ ispi->sregs = ispi->base + BXT_SSFSTS_CTL; -+ ispi->pregs = ispi->base + BXT_PR; -+ ispi->nregions = BXT_FREG_NUM; -+ ispi->pr_num = BXT_PR_NUM; -+ ispi->erase_64k = true; -+ break; -+ -+ case INTEL_SPI_CNL: -+ ispi->sregs = NULL; -+ ispi->pregs = ispi->base + CNL_PR; -+ ispi->nregions = CNL_FREG_NUM; -+ ispi->pr_num = CNL_PR_NUM; -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ -+ /* Try to disable write protection if user asked to do so */ -+ if (writeable && !intel_spi_set_writeable(ispi)) { -+ dev_warn(ispi->dev, "can't disable chip write protection\n"); -+ writeable = false; -+ } -+ -+ /* Disable #SMI generation from HW sequencer */ -+ val = readl(ispi->base + HSFSTS_CTL); -+ val &= ~HSFSTS_CTL_FSMIE; -+ writel(val, ispi->base + HSFSTS_CTL); -+ -+ /* -+ * Determine whether erase operation should use HW or SW sequencer. -+ * -+ * The HW sequencer has a predefined list of opcodes, with only the -+ * erase opcode being programmable in LVSCC and UVSCC registers. -+ * If these registers don't contain a valid erase opcode, erase -+ * cannot be done using HW sequencer. -+ */ -+ lvscc = readl(ispi->base + LVSCC); -+ uvscc = readl(ispi->base + UVSCC); -+ if (!(lvscc & ERASE_OPCODE_MASK) || !(uvscc & ERASE_OPCODE_MASK)) -+ ispi->swseq_erase = true; -+ /* SPI controller on Intel BXT supports 64K erase opcode */ -+ if (ispi->info->type == INTEL_SPI_BXT && !ispi->swseq_erase) -+ if (!(lvscc & ERASE_64K_OPCODE_MASK) || -+ !(uvscc & ERASE_64K_OPCODE_MASK)) -+ ispi->erase_64k = false; -+ -+ if (ispi->sregs == NULL && (ispi->swseq_reg || ispi->swseq_erase)) { -+ dev_err(ispi->dev, "software sequencer not supported, but required\n"); -+ return -EINVAL; -+ } -+ -+ /* -+ * Some controllers can only do basic operations using hardware -+ * sequencer. All other operations are supposed to be carried out -+ * using software sequencer. -+ */ -+ if (ispi->swseq_reg) { -+ /* Disable #SMI generation from SW sequencer */ -+ val = readl(ispi->sregs + SSFSTS_CTL); -+ val &= ~SSFSTS_CTL_FSMIE; -+ writel(val, ispi->sregs + SSFSTS_CTL); -+ } -+ -+ /* Check controller's lock status */ -+ val = readl(ispi->base + HSFSTS_CTL); -+ ispi->locked = !!(val & HSFSTS_CTL_FLOCKDN); -+ -+ if (ispi->locked && ispi->sregs) { -+ /* -+ * BIOS programs allowed opcodes and then locks down the -+ * register. So read back what opcodes it decided to support. -+ * That's the set we are going to support as well. -+ */ -+ opmenu0 = readl(ispi->sregs + OPMENU0); -+ opmenu1 = readl(ispi->sregs + OPMENU1); -+ -+ if (opmenu0 && opmenu1) { -+ for (i = 0; i < ARRAY_SIZE(ispi->opcodes) / 2; i++) { -+ ispi->opcodes[i] = opmenu0 >> i * 8; -+ ispi->opcodes[i + 4] = opmenu1 >> i * 8; -+ } -+ } -+ } -+ -+ intel_spi_dump_regs(ispi); -+ -+ return 0; -+} -+ -+static int intel_spi_opcode_index(struct intel_spi *ispi, u8 opcode, int optype) -+{ -+ int i; -+ int preop; -+ -+ if (ispi->locked) { -+ for (i = 0; i < ARRAY_SIZE(ispi->opcodes); i++) -+ if (ispi->opcodes[i] == opcode) -+ return i; -+ -+ return -EINVAL; -+ } -+ -+ /* The lock is off, so just use index 0 */ -+ writel(opcode, ispi->sregs + OPMENU0); -+ preop = readw(ispi->sregs + PREOP_OPTYPE); -+ writel(optype << 16 | preop, ispi->sregs + PREOP_OPTYPE); -+ -+ return 0; -+} -+ -+static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, size_t len) -+{ -+ u32 val, status; -+ int ret; -+ -+ val = readl(ispi->base + HSFSTS_CTL); -+ val &= ~(HSFSTS_CTL_FCYCLE_MASK | HSFSTS_CTL_FDBC_MASK); -+ -+ switch (opcode) { -+ case SPINOR_OP_RDID: -+ val |= HSFSTS_CTL_FCYCLE_RDID; -+ break; -+ case SPINOR_OP_WRSR: -+ val |= HSFSTS_CTL_FCYCLE_WRSR; -+ break; -+ case SPINOR_OP_RDSR: -+ val |= HSFSTS_CTL_FCYCLE_RDSR; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (len > INTEL_SPI_FIFO_SZ) -+ return -EINVAL; -+ -+ val |= (len - 1) << HSFSTS_CTL_FDBC_SHIFT; -+ val |= HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; -+ val |= HSFSTS_CTL_FGO; -+ writel(val, ispi->base + HSFSTS_CTL); -+ -+ ret = intel_spi_wait_hw_busy(ispi); -+ if (ret) -+ return ret; -+ -+ status = readl(ispi->base + HSFSTS_CTL); -+ if (status & HSFSTS_CTL_FCERR) -+ return -EIO; -+ else if (status & HSFSTS_CTL_AEL) -+ return -EACCES; -+ -+ return 0; -+} -+ -+static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, size_t len, -+ int optype) -+{ -+ u32 val = 0, status; -+ u8 atomic_preopcode; -+ int ret; -+ -+ ret = intel_spi_opcode_index(ispi, opcode, optype); -+ if (ret < 0) -+ return ret; -+ -+ if (len > INTEL_SPI_FIFO_SZ) -+ return -EINVAL; -+ -+ /* -+ * Always clear it after each SW sequencer operation regardless -+ * of whether it is successful or not. -+ */ -+ atomic_preopcode = ispi->atomic_preopcode; -+ ispi->atomic_preopcode = 0; -+ -+ /* Only mark 'Data Cycle' bit when there is data to be transferred */ -+ if (len > 0) -+ val = ((len - 1) << SSFSTS_CTL_DBC_SHIFT) | SSFSTS_CTL_DS; -+ val |= ret << SSFSTS_CTL_COP_SHIFT; -+ val |= SSFSTS_CTL_FCERR | SSFSTS_CTL_FDONE; -+ val |= SSFSTS_CTL_SCGO; -+ if (atomic_preopcode) { -+ u16 preop; -+ -+ switch (optype) { -+ case OPTYPE_WRITE_NO_ADDR: -+ case OPTYPE_WRITE_WITH_ADDR: -+ /* Pick matching preopcode for the atomic sequence */ -+ preop = readw(ispi->sregs + PREOP_OPTYPE); -+ if ((preop & 0xff) == atomic_preopcode) -+ ; /* Do nothing */ -+ else if ((preop >> 8) == atomic_preopcode) -+ val |= SSFSTS_CTL_SPOP; -+ else -+ return -EINVAL; -+ -+ /* Enable atomic sequence */ -+ val |= SSFSTS_CTL_ACS; -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ -+ } -+ writel(val, ispi->sregs + SSFSTS_CTL); -+ -+ ret = intel_spi_wait_sw_busy(ispi); -+ if (ret) -+ return ret; -+ -+ status = readl(ispi->sregs + SSFSTS_CTL); -+ if (status & SSFSTS_CTL_FCERR) -+ return -EIO; -+ else if (status & SSFSTS_CTL_AEL) -+ return -EACCES; -+ -+ return 0; -+} -+ -+static int intel_spi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, -+ size_t len) -+{ -+ struct intel_spi *ispi = nor->priv; -+ int ret; -+ -+ /* Address of the first chip */ -+ writel(0, ispi->base + FADDR); -+ -+ if (ispi->swseq_reg) -+ ret = intel_spi_sw_cycle(ispi, opcode, len, -+ OPTYPE_READ_NO_ADDR); -+ else -+ ret = intel_spi_hw_cycle(ispi, opcode, len); -+ -+ if (ret) -+ return ret; -+ -+ return intel_spi_read_block(ispi, buf, len); -+} -+ -+static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf, -+ size_t len) -+{ -+ struct intel_spi *ispi = nor->priv; -+ int ret; -+ -+ /* -+ * This is handled with atomic operation and preop code in Intel -+ * controller so we only verify that it is available. If the -+ * controller is not locked, program the opcode to the PREOP -+ * register for later use. -+ * -+ * When hardware sequencer is used there is no need to program -+ * any opcodes (it handles them automatically as part of a command). -+ */ -+ if (opcode == SPINOR_OP_WREN) { -+ u16 preop; -+ -+ if (!ispi->swseq_reg) -+ return 0; -+ -+ preop = readw(ispi->sregs + PREOP_OPTYPE); -+ if ((preop & 0xff) != opcode && (preop >> 8) != opcode) { -+ if (ispi->locked) -+ return -EINVAL; -+ writel(opcode, ispi->sregs + PREOP_OPTYPE); -+ } -+ -+ /* -+ * This enables atomic sequence on next SW sycle. Will -+ * be cleared after next operation. -+ */ -+ ispi->atomic_preopcode = opcode; -+ return 0; -+ } -+ -+ /* -+ * We hope that HW sequencer will do the right thing automatically and -+ * with the SW sequencer we cannot use preopcode anyway, so just ignore -+ * the Write Disable operation and pretend it was completed -+ * successfully. -+ */ -+ if (opcode == SPINOR_OP_WRDI) -+ return 0; -+ -+ writel(0, ispi->base + FADDR); -+ -+ /* Write the value beforehand */ -+ ret = intel_spi_write_block(ispi, buf, len); -+ if (ret) -+ return ret; -+ -+ if (ispi->swseq_reg) -+ return intel_spi_sw_cycle(ispi, opcode, len, -+ OPTYPE_WRITE_NO_ADDR); -+ return intel_spi_hw_cycle(ispi, opcode, len); -+} -+ -+static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len, -+ u_char *read_buf) -+{ -+ struct intel_spi *ispi = nor->priv; -+ size_t block_size, retlen = 0; -+ u32 val, status; -+ ssize_t ret; -+ -+ /* -+ * Atomic sequence is not expected with HW sequencer reads. Make -+ * sure it is cleared regardless. -+ */ -+ if (WARN_ON_ONCE(ispi->atomic_preopcode)) -+ ispi->atomic_preopcode = 0; -+ -+ switch (nor->read_opcode) { -+ case SPINOR_OP_READ: -+ case SPINOR_OP_READ_FAST: -+ case SPINOR_OP_READ_4B: -+ case SPINOR_OP_READ_FAST_4B: -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ while (len > 0) { -+ block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ); -+ -+ /* Read cannot cross 4K boundary */ -+ block_size = min_t(loff_t, from + block_size, -+ round_up(from + 1, SZ_4K)) - from; -+ -+ writel(from, ispi->base + FADDR); -+ -+ val = readl(ispi->base + HSFSTS_CTL); -+ val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); -+ val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; -+ val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT; -+ val |= HSFSTS_CTL_FCYCLE_READ; -+ val |= HSFSTS_CTL_FGO; -+ writel(val, ispi->base + HSFSTS_CTL); -+ -+ ret = intel_spi_wait_hw_busy(ispi); -+ if (ret) -+ return ret; -+ -+ status = readl(ispi->base + HSFSTS_CTL); -+ if (status & HSFSTS_CTL_FCERR) -+ ret = -EIO; -+ else if (status & HSFSTS_CTL_AEL) -+ ret = -EACCES; -+ -+ if (ret < 0) { -+ dev_err(ispi->dev, "read error: %llx: %#x\n", from, -+ status); -+ return ret; -+ } -+ -+ ret = intel_spi_read_block(ispi, read_buf, block_size); -+ if (ret) -+ return ret; -+ -+ len -= block_size; -+ from += block_size; -+ retlen += block_size; -+ read_buf += block_size; -+ } -+ -+ return retlen; -+} -+ -+static ssize_t intel_spi_write(struct spi_nor *nor, loff_t to, size_t len, -+ const u_char *write_buf) -+{ -+ struct intel_spi *ispi = nor->priv; -+ size_t block_size, retlen = 0; -+ u32 val, status; -+ ssize_t ret; -+ -+ /* Not needed with HW sequencer write, make sure it is cleared */ -+ ispi->atomic_preopcode = 0; -+ -+ while (len > 0) { -+ block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ); -+ -+ /* Write cannot cross 4K boundary */ -+ block_size = min_t(loff_t, to + block_size, -+ round_up(to + 1, SZ_4K)) - to; -+ -+ writel(to, ispi->base + FADDR); -+ -+ val = readl(ispi->base + HSFSTS_CTL); -+ val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); -+ val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; -+ val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT; -+ val |= HSFSTS_CTL_FCYCLE_WRITE; -+ -+ ret = intel_spi_write_block(ispi, write_buf, block_size); -+ if (ret) { -+ dev_err(ispi->dev, "failed to write block\n"); -+ return ret; -+ } -+ -+ /* Start the write now */ -+ val |= HSFSTS_CTL_FGO; -+ writel(val, ispi->base + HSFSTS_CTL); -+ -+ ret = intel_spi_wait_hw_busy(ispi); -+ if (ret) { -+ dev_err(ispi->dev, "timeout\n"); -+ return ret; -+ } -+ -+ status = readl(ispi->base + HSFSTS_CTL); -+ if (status & HSFSTS_CTL_FCERR) -+ ret = -EIO; -+ else if (status & HSFSTS_CTL_AEL) -+ ret = -EACCES; -+ -+ if (ret < 0) { -+ dev_err(ispi->dev, "write error: %llx: %#x\n", to, -+ status); -+ return ret; -+ } -+ -+ len -= block_size; -+ to += block_size; -+ retlen += block_size; -+ write_buf += block_size; -+ } -+ -+ return retlen; -+} -+ -+static int intel_spi_erase(struct spi_nor *nor, loff_t offs) -+{ -+ size_t erase_size, len = nor->mtd.erasesize; -+ struct intel_spi *ispi = nor->priv; -+ u32 val, status, cmd; -+ int ret; -+ -+ /* If the hardware can do 64k erase use that when possible */ -+ if (len >= SZ_64K && ispi->erase_64k) { -+ cmd = HSFSTS_CTL_FCYCLE_ERASE_64K; -+ erase_size = SZ_64K; -+ } else { -+ cmd = HSFSTS_CTL_FCYCLE_ERASE; -+ erase_size = SZ_4K; -+ } -+ -+ if (ispi->swseq_erase) { -+ while (len > 0) { -+ writel(offs, ispi->base + FADDR); -+ -+ ret = intel_spi_sw_cycle(ispi, nor->erase_opcode, -+ 0, OPTYPE_WRITE_WITH_ADDR); -+ if (ret) -+ return ret; -+ -+ offs += erase_size; -+ len -= erase_size; -+ } -+ -+ return 0; -+ } -+ -+ /* Not needed with HW sequencer erase, make sure it is cleared */ -+ ispi->atomic_preopcode = 0; -+ -+ while (len > 0) { -+ writel(offs, ispi->base + FADDR); -+ -+ val = readl(ispi->base + HSFSTS_CTL); -+ val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); -+ val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; -+ val |= cmd; -+ val |= HSFSTS_CTL_FGO; -+ writel(val, ispi->base + HSFSTS_CTL); -+ -+ ret = intel_spi_wait_hw_busy(ispi); -+ if (ret) -+ return ret; -+ -+ status = readl(ispi->base + HSFSTS_CTL); -+ if (status & HSFSTS_CTL_FCERR) -+ return -EIO; -+ else if (status & HSFSTS_CTL_AEL) -+ return -EACCES; -+ -+ offs += erase_size; -+ len -= erase_size; -+ } -+ -+ return 0; -+} -+ -+static bool intel_spi_is_protected(const struct intel_spi *ispi, -+ unsigned int base, unsigned int limit) -+{ -+ int i; -+ -+ for (i = 0; i < ispi->pr_num; i++) { -+ u32 pr_base, pr_limit, pr_value; -+ -+ pr_value = readl(ispi->pregs + PR(i)); -+ if (!(pr_value & (PR_WPE | PR_RPE))) -+ continue; -+ -+ pr_limit = (pr_value & PR_LIMIT_MASK) >> PR_LIMIT_SHIFT; -+ pr_base = pr_value & PR_BASE_MASK; -+ -+ if (pr_base >= base && pr_limit <= limit) -+ return true; -+ } -+ -+ return false; -+} -+ -+/* -+ * There will be a single partition holding all enabled flash regions. We -+ * call this "BIOS". -+ */ -+static void intel_spi_fill_partition(struct intel_spi *ispi, -+ struct mtd_partition *part) -+{ -+ u64 end; -+ int i; -+ -+ mem_clear(part, sizeof(*part)); -+ -+ /* Start from the mandatory descriptor region */ -+ part->size = 4096; -+ part->name = "BIOS"; -+ -+ /* -+ * Now try to find where this partition ends based on the flash -+ * region registers. -+ */ -+ for (i = 1; i < ispi->nregions; i++) { -+ u32 region, base, limit; -+ -+ region = readl(ispi->base + FREG(i)); -+ base = region & FREG_BASE_MASK; -+ limit = (region & FREG_LIMIT_MASK) >> FREG_LIMIT_SHIFT; -+ -+ if (base >= limit || limit == 0) -+ continue; -+ -+ /* -+ * If any of the regions have protection bits set, make the -+ * whole partition read-only to be on the safe side. -+ * -+ * Also if the user did not ask the chip to be writeable -+ * mask the bit too. -+ */ -+ if (!writeable || intel_spi_is_protected(ispi, base, limit)) -+ part->mask_flags |= MTD_WRITEABLE; -+ -+ end = (limit << 12) + 4096; -+ if (end > part->size) -+ part->size = end; -+ } -+} -+ -+static const struct spi_nor_controller_ops intel_spi_controller_ops = { -+ .read_reg = intel_spi_read_reg, -+ .write_reg = intel_spi_write_reg, -+ .read = intel_spi_read, -+ .write = intel_spi_write, -+ .erase = intel_spi_erase, -+}; -+ -+struct intel_spi *intel_spi_probe(struct device *dev, -+ struct resource *mem, const struct intel_spi_boardinfo *info) -+{ -+ const struct spi_nor_hwcaps hwcaps = { -+ .mask = SNOR_HWCAPS_READ | -+ SNOR_HWCAPS_READ_FAST | -+ SNOR_HWCAPS_PP, -+ }; -+ struct mtd_partition part; -+ struct intel_spi *ispi; -+ int ret; -+ -+ if (!info || !mem) -+ return ERR_PTR(-EINVAL); -+ -+ ispi = devm_kzalloc(dev, sizeof(*ispi), GFP_KERNEL); -+ if (!ispi) -+ return ERR_PTR(-ENOMEM); -+ -+ ispi->base = devm_ioremap_resource(dev, mem); -+ if (IS_ERR(ispi->base)) -+ return ERR_CAST(ispi->base); -+ -+ ispi->dev = dev; -+ ispi->info = info; -+ -+ ret = intel_spi_init(ispi); -+ if (ret) -+ return ERR_PTR(ret); -+ -+ ispi->nor.dev = ispi->dev; -+ ispi->nor.priv = ispi; -+ ispi->nor.controller_ops = &intel_spi_controller_ops; -+ -+ ret = spi_nor_scan(&ispi->nor, NULL, &hwcaps); -+ if (ret) { -+ dev_info(dev, "failed to locate the chip\n"); -+ return ERR_PTR(ret); -+ } -+ -+ intel_spi_fill_partition(ispi, &part); -+ -+ ret = mtd_device_register(&ispi->nor.mtd, &part, 1); -+ if (ret) -+ return ERR_PTR(ret); -+ -+ return ispi; -+} -+EXPORT_SYMBOL_GPL(intel_spi_probe); -+ -+int intel_spi_remove(struct intel_spi *ispi) -+{ -+ return mtd_device_unregister(&ispi->nor.mtd); -+} -+EXPORT_SYMBOL_GPL(intel_spi_remove); -+ -+MODULE_DESCRIPTION("Intel PCH/PCU SPI flash core driver"); -+MODULE_AUTHOR("support"); -+MODULE_LICENSE("GPL v2"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_pci.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_pci.c -new file mode 100644 -index 000000000..a89050b8a ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_pci.c -@@ -0,0 +1,106 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Intel PCH/PCU SPI flash PCI driver. -+ * -+ * Copyright (C) 2016, Intel Corporation -+ * Author: Mika Westerberg -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "intel_spi.h" -+ -+#define BCR 0xdc -+#define BCR_WPD BIT(0) -+ -+static bool intel_spi_pci_set_writeable(void __iomem *base, void *data) -+{ -+ struct pci_dev *pdev = data; -+ u32 bcr; -+ -+ /* Try to make the chip read/write */ -+ pci_read_config_dword(pdev, BCR, &bcr); -+ if (!(bcr & BCR_WPD)) { -+ bcr |= BCR_WPD; -+ pci_write_config_dword(pdev, BCR, bcr); -+ pci_read_config_dword(pdev, BCR, &bcr); -+ } -+ -+ return bcr & BCR_WPD; -+} -+ -+static const struct intel_spi_boardinfo bxt_info = { -+ .type = INTEL_SPI_BXT, -+ .set_writeable = intel_spi_pci_set_writeable, -+}; -+ -+static const struct intel_spi_boardinfo cnl_info = { -+ .type = INTEL_SPI_CNL, -+ .set_writeable = intel_spi_pci_set_writeable, -+}; -+ -+static int intel_spi_pci_probe(struct pci_dev *pdev, -+ const struct pci_device_id *id) -+{ -+ struct intel_spi_boardinfo *info; -+ struct intel_spi *ispi; -+ int ret; -+ -+ ret = pcim_enable_device(pdev); -+ if (ret) -+ return ret; -+ -+ info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info), -+ GFP_KERNEL); -+ if (!info) -+ return -ENOMEM; -+ -+ info->data = pdev; -+ ispi = intel_spi_probe(&pdev->dev, &pdev->resource[0], info); -+ if (IS_ERR(ispi)) -+ return PTR_ERR(ispi); -+ -+ pci_set_drvdata(pdev, ispi); -+ return 0; -+} -+ -+static void intel_spi_pci_remove(struct pci_dev *pdev) -+{ -+ intel_spi_remove(pci_get_drvdata(pdev)); -+} -+ -+static const struct pci_device_id intel_spi_pci_ids[] = { -+ { PCI_VDEVICE(INTEL, 0x02a4), (unsigned long)&bxt_info }, -+ { PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&bxt_info }, -+ { PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info }, -+ { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info }, -+ { PCI_VDEVICE(INTEL, 0x1bca), (unsigned long)&bxt_info }, -+ { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info }, -+ { PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info }, -+ { PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info }, -+ { PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info }, -+ { PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info }, -+ { PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info }, -+ { PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info }, -+ { PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info }, -+ { PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info }, -+ { PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&bxt_info }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids); -+ -+static struct pci_driver intel_spi_pci_driver = { -+ .name = "intel-spi", -+ .id_table = intel_spi_pci_ids, -+ .probe = intel_spi_pci_probe, -+ .remove = intel_spi_pci_remove, -+}; -+ -+module_pci_driver(intel_spi_pci_driver); -+ -+MODULE_DESCRIPTION("Intel PCH/PCU SPI flash PCI driver"); -+MODULE_AUTHOR("support"); -+MODULE_LICENSE("GPL v2"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_platform.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_platform.c -new file mode 100644 -index 000000000..489716d4d ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/intel_spi/intel_spi_platform.c -@@ -0,0 +1,168 @@ -+/* -+ * Intel PCH/PCU SPI flash platform driver. -+ * -+ * Copyright (C) 2016, Intel Corporation -+ * Author: Mika Westerberg -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "intel_spi.h" -+ -+#define PCI_VENDOR_ID_D1527_LPC (0x8c54) -+ -+#define BIOS_CNTL (0xdc) -+#define BIOS_CNTL_SRC_SHIFT 2 -+#define BIOS_CNTL_WN BIT(0) -+#define BIOS_CNTL_BLE BIT(1) -+#define BIOS_CNTL_SMM_BMP BIT(5) -+ -+#define RCBABASE 0xf0 -+ -+int intel_spi_platform_debug = 0; -+module_param(intel_spi_platform_debug, int, S_IRUGO | S_IWUSR); -+int intel_spi_platform_error = 0; -+module_param(intel_spi_platform_error, int, S_IRUGO | S_IWUSR); -+ -+static bool writeable; -+module_param(writeable, bool, 0); -+MODULE_PARM_DESC(writeable, "Enable write access to BIOS (default=0)"); -+ -+#define INTEL_SPI_PLATFORM_VERBOSE(fmt, args...) do { \ -+ if (intel_spi_platform_debug) { \ -+ printk(KERN_INFO "[INTEL_SPI_PLATFORM][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+ } while (0) -+ -+#define INTEL_SPI_PLATFORM_ERROR(fmt, args...) do { \ -+ if (intel_spi_platform_error) { \ -+ printk(KERN_ERR "[INTEL_SPI_PLATFORM][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+ } while (0) -+ -+static void intel_spi_enable_bios_write(struct pci_dev *pci_dev, struct intel_spi_boardinfo *info, int *writeable_flag) -+{ -+ u8 bios_cntl, value, want, new; -+ -+ if (writeable) { -+ pci_read_config_byte(pci_dev, BIOS_CNTL, &bios_cntl); -+ want = bios_cntl; -+ value = (bios_cntl >> BIOS_CNTL_SRC_SHIFT) & 0x3 ; -+ if (value == 0x3) { -+ INTEL_SPI_PLATFORM_VERBOSE("invalid prefetching/caching settings, "); -+ } else { -+ INTEL_SPI_PLATFORM_VERBOSE("prefetching %sabled, caching %sabled, ", -+ (value & 0x2) ? "en" : "dis", -+ (value & 0x1) ? "dis" : "en"); -+ } -+ -+ /* writeable regardless */ -+ want &= ~BIOS_CNTL_SMM_BMP; -+ /* write enable */ -+ want |= BIOS_CNTL_WN; -+ /* BIOS lock disabled */ -+ want &= ~BIOS_CNTL_BLE; -+ INTEL_SPI_PLATFORM_VERBOSE("bios cntl is:0x%x, want is:0x%x\n", bios_cntl, want); -+ pci_write_config_byte(pci_dev, BIOS_CNTL, want); -+ pci_read_config_byte(pci_dev, BIOS_CNTL, &new); -+ INTEL_SPI_PLATFORM_VERBOSE("\nBIOS_CNTL = 0x%02x: ", new); -+ INTEL_SPI_PLATFORM_VERBOSE("BIOS Lock Enable: %sabled, ", (new & BIOS_CNTL_BLE) ? "en" : "dis"); -+ INTEL_SPI_PLATFORM_VERBOSE("BIOS Write Enable: %sabled\n", (new & BIOS_CNTL_WN) ? "en" : "dis"); -+ -+ if (new & BIOS_CNTL_SMM_BMP) { -+ INTEL_SPI_PLATFORM_VERBOSE("BIOS region SMM protection is enabled!\n"); -+ } -+ -+ if (new != want) { -+ INTEL_SPI_PLATFORM_VERBOSE("Warning: Setting Bios Control at 0x%x from 0x%02x to 0x%02x failed.\n" -+ "New value is 0x%02x.\n", BIOS_CNTL, value, want, new); -+ } else { -+ *writeable_flag = !!(new & BIOS_CNTL_WN); -+ } -+ INTEL_SPI_PLATFORM_VERBOSE("Bios Control is 0x%x\n", new); -+ } else { -+ INTEL_SPI_PLATFORM_VERBOSE("Bios don't write\n"); -+ } -+ -+ return ; -+} -+ -+static int intel_spi_platform_probe(struct platform_device *pdev) -+{ -+ struct intel_spi_boardinfo *info; -+ struct intel_spi *ispi; -+ struct resource *mem; -+ struct pci_dev *pci_dev = NULL; -+ u32 rcba; -+ int writeable_flag = 0; -+ -+ info = dev_get_platdata(&pdev->dev); -+ if (!info) -+ return -EINVAL; -+ -+ pci_dev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_VENDOR_ID_D1527_LPC, pci_dev); -+ if (!pci_dev) { -+ INTEL_SPI_PLATFORM_ERROR("pci_get_device(0x8086, 0x8c54) failed!\n"); -+ return -1; -+ } -+ -+ switch (info->type) { -+ case INTEL_SPI_LPT: -+ pci_read_config_dword(pci_dev, RCBABASE, &rcba); -+ if (rcba & 1) { -+ intel_spi_enable_bios_write(pci_dev, info, &writeable_flag); -+ } -+ break; -+ default: -+ INTEL_SPI_PLATFORM_ERROR("info type[%d] not need set writeable.\n",info->type); -+ break; -+ } -+ INTEL_SPI_PLATFORM_VERBOSE("intel spi boardinfo writeable is %sabled\n", -+ writeable_flag ? "en" : "dis"); -+ -+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ ispi = intel_spi_probe(&pdev->dev, mem, info); -+ if (IS_ERR(ispi)) -+ return PTR_ERR(ispi); -+ -+ platform_set_drvdata(pdev, ispi); -+ return 0; -+} -+ -+static int intel_spi_platform_remove(struct platform_device *pdev) -+{ -+ struct intel_spi *ispi = platform_get_drvdata(pdev); -+ -+ return intel_spi_remove(ispi); -+} -+ -+static struct of_device_id intel_spi_match[] = { -+ { -+ .compatible = "spi-c224", -+ }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, intel_spi_match); -+ -+static struct platform_driver intel_spi_platform_driver = { -+ .probe = intel_spi_platform_probe, -+ .remove = intel_spi_platform_remove, -+ .driver = { -+ .name = "intel-spi", -+ .of_match_table = intel_spi_match, -+ }, -+}; -+ -+module_platform_driver(intel_spi_platform_driver); -+ -+MODULE_DESCRIPTION("Intel PCH/PCU SPI flash platform driver"); -+MODULE_AUTHOR("support"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:intel-spi"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/Makefile -new file mode 100644 -index 000000000..02d659d6c ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/Makefile -@@ -0,0 +1,37 @@ -+PWD = $(shell pwd) -+ -+EXTRA_CFLAGS:= -I$(M)/include -+EXTRA_CFLAGS+= -Wall -+#ifdef ENABLE_GCOV -+#ifeq ($(ENABLE_GCOV), y) -+#EXTRA_CFLAGS+= -fprofile-arcs -ftest-coverage -lgcov -+#endif -+#endif # ENABLE_GCOV -+ -+obj-m := wb_lm75.o -+obj-m += wb_tmp401.o -+obj-m += wb_i2c_mux_pca9641.o -+obj-m += wb_i2c_mux_pca954x.o -+obj-m += wb_i2c_i801.o -+obj-m += wb_i2c_algo_bit.o -+obj-m += wb_i2c_gpio.o -+obj-m += wb_i2c_gpio_device.o -+obj-m += wb_at24.o -+obj-m += wb_pmbus_core.o -+obj-m += wb_csu550.o -+obj-m += wb_ina3221.o -+obj-m += wb_isl68137.o -+obj-m += wb_tps53622.o -+obj-m += wb_ucd9000.o -+obj-m += wb_xdpe12284.o -+obj-m += wb_xdpe132g5c_pmbus.o -+obj-m += wb_i2c_ismt.o -+ -+all: -+ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules -+ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi -+ cp -p $(PWD)/*.ko $(module_out_put_dir) -+clean: -+ rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/*.mod -+ rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order -+ rm -rf $(PWD)/.tmp_versions -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_at24.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_at24.c -new file mode 100644 -index 000000000..1075e6ef1 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_at24.c -@@ -0,0 +1,861 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * at24.c - handle most I2C EEPROMs -+ * -+ * Copyright (C) 2005-2007 David Brownell -+ * Copyright (C) 2008 Wolfram Sang, Pengutronix -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* Address pointer is 16 bit. */ -+#define AT24_FLAG_ADDR16 BIT(7) -+/* sysfs-entry will be read-only. */ -+#define AT24_FLAG_READONLY BIT(6) -+/* sysfs-entry will be world-readable. */ -+#define AT24_FLAG_IRUGO BIT(5) -+/* Take always 8 addresses (24c00). */ -+#define AT24_FLAG_TAKE8ADDR BIT(4) -+/* Factory-programmed serial number. */ -+#define AT24_FLAG_SERIAL BIT(3) -+/* Factory-programmed mac address. */ -+#define AT24_FLAG_MAC BIT(2) -+/* Does not auto-rollover reads to the next slave address. */ -+#define AT24_FLAG_NO_RDROL BIT(1) -+ -+/* -+ * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable. -+ * Differences between different vendor product lines (like Atmel AT24C or -+ * MicroChip 24LC, etc) won't much matter for typical read/write access. -+ * There are also I2C RAM chips, likewise interchangeable. One example -+ * would be the PCF8570, which acts like a 24c02 EEPROM (256 bytes). -+ * -+ * However, misconfiguration can lose data. "Set 16-bit memory address" -+ * to a part with 8-bit addressing will overwrite data. Writing with too -+ * big a page size also loses data. And it's not safe to assume that the -+ * conventional addresses 0x50..0x57 only hold eeproms; a PCF8563 RTC -+ * uses 0x51, for just one example. -+ * -+ * Accordingly, explicit board-specific configuration data should be used -+ * in almost all cases. (One partial exception is an SMBus used to access -+ * "SPD" data for DRAM sticks. Those only use 24c02 EEPROMs.) -+ * -+ * So this driver uses "new style" I2C driver binding, expecting to be -+ * told what devices exist. That may be in arch/X/mach-Y/board-Z.c or -+ * similar kernel-resident tables; or, configuration data coming from -+ * a bootloader. -+ * -+ * Other than binding model, current differences from "eeprom" driver are -+ * that this one handles write access and isn't restricted to 24c02 devices. -+ * It also handles larger devices (32 kbit and up) with two-byte addresses, -+ * which won't work on pure SMBus systems. -+ */ -+ -+struct at24_client { -+ struct i2c_client *client; -+ struct regmap *regmap; -+}; -+ -+struct at24_data { -+ /* -+ * Lock protects against activities from other Linux tasks, -+ * but not from changes by other I2C masters. -+ */ -+ struct mutex lock; -+ -+ unsigned int write_max; -+ unsigned int num_addresses; -+ unsigned int offset_adj; -+ -+ u32 byte_len; -+ u16 page_size; -+ u8 flags; -+ -+ struct nvmem_device *nvmem; -+ struct regulator *vcc_reg; -+ void (*read_post)(unsigned int off, char *buf, size_t count); -+ -+ /* -+ * Some chips tie up multiple I2C addresses; dummy devices reserve -+ * them for us, and we'll use them with SMBus calls. -+ */ -+ struct at24_client client[]; -+}; -+ -+/* -+ * This parameter is to help this driver avoid blocking other drivers out -+ * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C -+ * clock, one 256 byte read takes about 1/43 second which is excessive; -+ * but the 1/170 second it takes at 400 kHz may be quite reasonable; and -+ * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible. -+ * -+ * This value is forced to be a power of two so that writes align on pages. -+ */ -+static unsigned int at24_io_limit = 128; -+module_param_named(io_limit, at24_io_limit, uint, 0); -+MODULE_PARM_DESC(at24_io_limit, "Maximum bytes per I/O (default 128)"); -+ -+/* -+ * Specs often allow 5 msec for a page write, sometimes 20 msec; -+ * it's important to recover from write timeouts. -+ */ -+static unsigned int at24_write_timeout = 25; -+module_param_named(write_timeout, at24_write_timeout, uint, 0); -+MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)"); -+ -+struct at24_chip_data { -+ u32 byte_len; -+ u8 flags; -+ void (*read_post)(unsigned int off, char *buf, size_t count); -+}; -+ -+#define AT24_CHIP_DATA(_name, _len, _flags) \ -+ static const struct at24_chip_data _name = { \ -+ .byte_len = _len, .flags = _flags, \ -+ } -+ -+#define AT24_CHIP_DATA_CB(_name, _len, _flags, _read_post) \ -+ static const struct at24_chip_data _name = { \ -+ .byte_len = _len, .flags = _flags, \ -+ .read_post = _read_post, \ -+ } -+ -+static void at24_read_post_vaio(unsigned int off, char *buf, size_t count) -+{ -+ int i; -+ -+ if (capable(CAP_SYS_ADMIN)) -+ return; -+ -+ /* -+ * Hide VAIO private settings to regular users: -+ * - BIOS passwords: bytes 0x00 to 0x0f -+ * - UUID: bytes 0x10 to 0x1f -+ * - Serial number: 0xc0 to 0xdf -+ */ -+ for (i = 0; i < count; i++) { -+ if ((off + i <= 0x1f) || -+ (off + i >= 0xc0 && off + i <= 0xdf)) -+ buf[i] = 0; -+ } -+} -+ -+/* needs 8 addresses as A0-A2 are ignored */ -+AT24_CHIP_DATA(at24_data_24c00, 128 / 8, AT24_FLAG_TAKE8ADDR); -+/* old variants can't be handled with this generic entry! */ -+AT24_CHIP_DATA(at24_data_24c01, 1024 / 8, 0); -+AT24_CHIP_DATA(at24_data_24cs01, 16, -+ AT24_FLAG_SERIAL | AT24_FLAG_READONLY); -+AT24_CHIP_DATA(at24_data_24c02, 2048 / 8, AT24_FLAG_IRUGO); -+AT24_CHIP_DATA(at24_data_24cs02, 16, -+ AT24_FLAG_SERIAL | AT24_FLAG_READONLY); -+AT24_CHIP_DATA(at24_data_24mac402, 48 / 8, -+ AT24_FLAG_MAC | AT24_FLAG_READONLY); -+AT24_CHIP_DATA(at24_data_24mac602, 64 / 8, -+ AT24_FLAG_MAC | AT24_FLAG_READONLY); -+/* spd is a 24c02 in memory DIMMs */ -+AT24_CHIP_DATA(at24_data_spd, 2048 / 8, -+ AT24_FLAG_READONLY | AT24_FLAG_IRUGO); -+/* 24c02_vaio is a 24c02 on some Sony laptops */ -+AT24_CHIP_DATA_CB(at24_data_24c02_vaio, 2048 / 8, -+ AT24_FLAG_READONLY | AT24_FLAG_IRUGO, -+ at24_read_post_vaio); -+AT24_CHIP_DATA(at24_data_24c04, 4096 / 8, 0); -+AT24_CHIP_DATA(at24_data_24cs04, 16, -+ AT24_FLAG_SERIAL | AT24_FLAG_READONLY); -+/* 24rf08 quirk is handled at i2c-core */ -+AT24_CHIP_DATA(at24_data_24c08, 8192 / 8, 0); -+AT24_CHIP_DATA(at24_data_24cs08, 16, -+ AT24_FLAG_SERIAL | AT24_FLAG_READONLY); -+AT24_CHIP_DATA(at24_data_24c16, 16384 / 8, 0); -+AT24_CHIP_DATA(at24_data_24cs16, 16, -+ AT24_FLAG_SERIAL | AT24_FLAG_READONLY); -+AT24_CHIP_DATA(at24_data_24c32, 32768 / 8, AT24_FLAG_ADDR16); -+AT24_CHIP_DATA(at24_data_24cs32, 16, -+ AT24_FLAG_ADDR16 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY); -+AT24_CHIP_DATA(at24_data_24c64, 65536 / 8, AT24_FLAG_ADDR16 | AT24_FLAG_IRUGO); -+AT24_CHIP_DATA(at24_data_24cs64, 16, -+ AT24_FLAG_ADDR16 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY); -+AT24_CHIP_DATA(at24_data_24c128, 131072 / 8, AT24_FLAG_ADDR16); -+AT24_CHIP_DATA(at24_data_24c256, 262144 / 8, AT24_FLAG_ADDR16); -+AT24_CHIP_DATA(at24_data_24c512, 524288 / 8, AT24_FLAG_ADDR16); -+AT24_CHIP_DATA(at24_data_24c1024, 1048576 / 8, AT24_FLAG_ADDR16); -+AT24_CHIP_DATA(at24_data_24c2048, 2097152 / 8, AT24_FLAG_ADDR16); -+/* identical to 24c08 ? */ -+AT24_CHIP_DATA(at24_data_INT3499, 8192 / 8, 0); -+ -+static const struct i2c_device_id at24_ids[] = { -+ { "wb_24c00", (kernel_ulong_t)&at24_data_24c00 }, -+ { "wb_24c01", (kernel_ulong_t)&at24_data_24c01 }, -+ { "wb_24cs01", (kernel_ulong_t)&at24_data_24cs01 }, -+ { "wb_24c02", (kernel_ulong_t)&at24_data_24c02 }, -+ { "wb_24cs02", (kernel_ulong_t)&at24_data_24cs02 }, -+ { "wb_24mac402", (kernel_ulong_t)&at24_data_24mac402 }, -+ { "wb_24mac602", (kernel_ulong_t)&at24_data_24mac602 }, -+ { "wb_spd", (kernel_ulong_t)&at24_data_spd }, -+ { "wb_24c02-vaio", (kernel_ulong_t)&at24_data_24c02_vaio }, -+ { "wb_24c04", (kernel_ulong_t)&at24_data_24c04 }, -+ { "wb_24cs04", (kernel_ulong_t)&at24_data_24cs04 }, -+ { "wb_24c08", (kernel_ulong_t)&at24_data_24c08 }, -+ { "wb_24cs08", (kernel_ulong_t)&at24_data_24cs08 }, -+ { "wb_24c16", (kernel_ulong_t)&at24_data_24c16 }, -+ { "wb_24cs16", (kernel_ulong_t)&at24_data_24cs16 }, -+ { "wb_24c32", (kernel_ulong_t)&at24_data_24c32 }, -+ { "wb_24cs32", (kernel_ulong_t)&at24_data_24cs32 }, -+ { "wb_24c64", (kernel_ulong_t)&at24_data_24c64 }, -+ { "wb_24cs64", (kernel_ulong_t)&at24_data_24cs64 }, -+ { "wb_24c128", (kernel_ulong_t)&at24_data_24c128 }, -+ { "wb_24c256", (kernel_ulong_t)&at24_data_24c256 }, -+ { "wb_24c512", (kernel_ulong_t)&at24_data_24c512 }, -+ { "wb_24c1024", (kernel_ulong_t)&at24_data_24c1024 }, -+ { "wb_24c2048", (kernel_ulong_t)&at24_data_24c2048 }, -+ { "wb_at24", 0 }, -+ { /* END OF LIST */ } -+}; -+MODULE_DEVICE_TABLE(i2c, at24_ids); -+ -+static const struct of_device_id at24_of_match[] = { -+ { .compatible = "atmel,24c00", .data = &at24_data_24c00 }, -+ { .compatible = "atmel,24c01", .data = &at24_data_24c01 }, -+ { .compatible = "atmel,24cs01", .data = &at24_data_24cs01 }, -+ { .compatible = "atmel,24c02", .data = &at24_data_24c02 }, -+ { .compatible = "atmel,24cs02", .data = &at24_data_24cs02 }, -+ { .compatible = "atmel,24mac402", .data = &at24_data_24mac402 }, -+ { .compatible = "atmel,24mac602", .data = &at24_data_24mac602 }, -+ { .compatible = "atmel,spd", .data = &at24_data_spd }, -+ { .compatible = "atmel,24c04", .data = &at24_data_24c04 }, -+ { .compatible = "atmel,24cs04", .data = &at24_data_24cs04 }, -+ { .compatible = "atmel,24c08", .data = &at24_data_24c08 }, -+ { .compatible = "atmel,24cs08", .data = &at24_data_24cs08 }, -+ { .compatible = "atmel,24c16", .data = &at24_data_24c16 }, -+ { .compatible = "atmel,24cs16", .data = &at24_data_24cs16 }, -+ { .compatible = "atmel,24c32", .data = &at24_data_24c32 }, -+ { .compatible = "atmel,24cs32", .data = &at24_data_24cs32 }, -+ { .compatible = "atmel,24c64", .data = &at24_data_24c64 }, -+ { .compatible = "atmel,24cs64", .data = &at24_data_24cs64 }, -+ { .compatible = "atmel,24c128", .data = &at24_data_24c128 }, -+ { .compatible = "atmel,24c256", .data = &at24_data_24c256 }, -+ { .compatible = "atmel,24c512", .data = &at24_data_24c512 }, -+ { .compatible = "atmel,24c1024", .data = &at24_data_24c1024 }, -+ { .compatible = "atmel,24c2048", .data = &at24_data_24c2048 }, -+ { /* END OF LIST */ }, -+}; -+MODULE_DEVICE_TABLE(of, at24_of_match); -+ -+static const struct acpi_device_id __maybe_unused at24_acpi_ids[] = { -+ { "INT3499", (kernel_ulong_t)&at24_data_INT3499 }, -+ { "TPF0001", (kernel_ulong_t)&at24_data_24c1024 }, -+ { /* END OF LIST */ } -+}; -+MODULE_DEVICE_TABLE(acpi, at24_acpi_ids); -+ -+/* -+ * This routine supports chips which consume multiple I2C addresses. It -+ * computes the addressing information to be used for a given r/w request. -+ * Assumes that sanity checks for offset happened at sysfs-layer. -+ * -+ * Slave address and byte offset derive from the offset. Always -+ * set the byte address; on a multi-master board, another master -+ * may have changed the chip's "current" address pointer. -+ */ -+static struct at24_client *at24_translate_offset(struct at24_data *at24, -+ unsigned int *offset) -+{ -+ unsigned int i; -+ -+ if (at24->flags & AT24_FLAG_ADDR16) { -+ i = *offset >> 16; -+ *offset &= 0xffff; -+ } else { -+ i = *offset >> 8; -+ *offset &= 0xff; -+ } -+ -+ return &at24->client[i]; -+} -+ -+static struct device *at24_base_client_dev(struct at24_data *at24) -+{ -+ return &at24->client[0].client->dev; -+} -+ -+static size_t at24_adjust_read_count(struct at24_data *at24, -+ unsigned int offset, size_t count) -+{ -+ unsigned int bits; -+ size_t remainder; -+ -+ /* -+ * In case of multi-address chips that don't rollover reads to -+ * the next slave address: truncate the count to the slave boundary, -+ * so that the read never straddles slaves. -+ */ -+ if (at24->flags & AT24_FLAG_NO_RDROL) { -+ bits = (at24->flags & AT24_FLAG_ADDR16) ? 16 : 8; -+ remainder = BIT(bits) - offset; -+ if (count > remainder) -+ count = remainder; -+ } -+ -+ if (count > at24_io_limit) -+ count = at24_io_limit; -+ -+ return count; -+} -+ -+static ssize_t at24_regmap_read(struct at24_data *at24, char *buf, -+ unsigned int offset, size_t count) -+{ -+ unsigned long timeout, read_time; -+ struct at24_client *at24_client; -+ struct i2c_client *client; -+ struct regmap *regmap; -+ int ret; -+ -+ at24_client = at24_translate_offset(at24, &offset); -+ regmap = at24_client->regmap; -+ client = at24_client->client; -+ count = at24_adjust_read_count(at24, offset, count); -+ -+ /* adjust offset for mac and serial read ops */ -+ offset += at24->offset_adj; -+ -+ timeout = jiffies + msecs_to_jiffies(at24_write_timeout); -+ do { -+ /* -+ * The timestamp shall be taken before the actual operation -+ * to avoid a premature timeout in case of high CPU load. -+ */ -+ read_time = jiffies; -+ -+ ret = regmap_bulk_read(regmap, offset, buf, count); -+ dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n", -+ count, offset, ret, jiffies); -+ if (!ret) -+ return count; -+ -+ usleep_range(1000, 1500); -+ } while (time_before(read_time, timeout)); -+ -+ return -ETIMEDOUT; -+} -+ -+/* -+ * Note that if the hardware write-protect pin is pulled high, the whole -+ * chip is normally write protected. But there are plenty of product -+ * variants here, including OTP fuses and partial chip protect. -+ * -+ * We only use page mode writes; the alternative is sloooow. These routines -+ * write at most one page. -+ */ -+ -+static size_t at24_adjust_write_count(struct at24_data *at24, -+ unsigned int offset, size_t count) -+{ -+ unsigned int next_page; -+ -+ /* write_max is at most a page */ -+ if (count > at24->write_max) -+ count = at24->write_max; -+ -+ /* Never roll over backwards, to the start of this page */ -+ next_page = roundup(offset + 1, at24->page_size); -+ if (offset + count > next_page) -+ count = next_page - offset; -+ -+ return count; -+} -+ -+static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf, -+ unsigned int offset, size_t count) -+{ -+ unsigned long timeout, write_time; -+ struct at24_client *at24_client; -+ struct i2c_client *client; -+ struct regmap *regmap; -+ int ret; -+ -+ at24_client = at24_translate_offset(at24, &offset); -+ regmap = at24_client->regmap; -+ client = at24_client->client; -+ count = at24_adjust_write_count(at24, offset, count); -+ timeout = jiffies + msecs_to_jiffies(at24_write_timeout); -+ -+ do { -+ /* -+ * The timestamp shall be taken before the actual operation -+ * to avoid a premature timeout in case of high CPU load. -+ */ -+ write_time = jiffies; -+ -+ ret = regmap_bulk_write(regmap, offset, buf, count); -+ dev_dbg(&client->dev, "write %zu@%d --> %d (%ld)\n", -+ count, offset, ret, jiffies); -+ if (!ret) -+ return count; -+ -+ usleep_range(1000, 1500); -+ } while (time_before(write_time, timeout)); -+ -+ return -ETIMEDOUT; -+} -+ -+static int at24_read(void *priv, unsigned int off, void *val, size_t count) -+{ -+ struct at24_data *at24; -+ struct device *dev; -+ char *buf = val; -+ int i, ret; -+ -+ at24 = priv; -+ dev = at24_base_client_dev(at24); -+ -+ if (unlikely(!count)) -+ return count; -+ -+ if (off + count > at24->byte_len) -+ return -EINVAL; -+ -+ ret = pm_runtime_get_sync(dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(dev); -+ return ret; -+ } -+ -+ /* -+ * Read data from chip, protecting against concurrent updates -+ * from this host, but not from other I2C masters. -+ */ -+ mutex_lock(&at24->lock); -+ -+ for (i = 0; count; i += ret, count -= ret) { -+ ret = at24_regmap_read(at24, buf + i, off + i, count); -+ if (ret < 0) { -+ mutex_unlock(&at24->lock); -+ pm_runtime_put(dev); -+ return ret; -+ } -+ } -+ -+ mutex_unlock(&at24->lock); -+ -+ pm_runtime_put(dev); -+ -+ if (unlikely(at24->read_post)) -+ at24->read_post(off, buf, i); -+ -+ return 0; -+} -+ -+static int at24_write(void *priv, unsigned int off, void *val, size_t count) -+{ -+ struct at24_data *at24; -+ struct device *dev; -+ char *buf = val; -+ int ret; -+ -+ at24 = priv; -+ dev = at24_base_client_dev(at24); -+ -+ if (unlikely(!count)) -+ return -EINVAL; -+ -+ if (off + count > at24->byte_len) -+ return -EINVAL; -+ -+ ret = pm_runtime_get_sync(dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(dev); -+ return ret; -+ } -+ -+ /* -+ * Write data to chip, protecting against concurrent updates -+ * from this host, but not from other I2C masters. -+ */ -+ mutex_lock(&at24->lock); -+ -+ while (count) { -+ ret = at24_regmap_write(at24, buf, off, count); -+ if (ret < 0) { -+ mutex_unlock(&at24->lock); -+ pm_runtime_put(dev); -+ return ret; -+ } -+ buf += ret; -+ off += ret; -+ count -= ret; -+ } -+ -+ mutex_unlock(&at24->lock); -+ -+ pm_runtime_put(dev); -+ -+ return 0; -+} -+ -+static const struct at24_chip_data *at24_get_chip_data(struct device *dev) -+{ -+ struct device_node *of_node = dev->of_node; -+ const struct at24_chip_data *cdata; -+ const struct i2c_device_id *id; -+ -+ id = i2c_match_id(at24_ids, to_i2c_client(dev)); -+ -+ /* -+ * The I2C core allows OF nodes compatibles to match against the -+ * I2C device ID table as a fallback, so check not only if an OF -+ * node is present but also if it matches an OF device ID entry. -+ */ -+ if (of_node && of_match_device(at24_of_match, dev)) -+ cdata = of_device_get_match_data(dev); -+ else if (id) -+ cdata = (void *)id->driver_data; -+ else -+ cdata = acpi_device_get_match_data(dev); -+ -+ if (!cdata) -+ return ERR_PTR(-ENODEV); -+ -+ return cdata; -+} -+ -+static int at24_make_dummy_client(struct at24_data *at24, unsigned int index, -+ struct regmap_config *regmap_config) -+{ -+ struct i2c_client *base_client, *dummy_client; -+ struct regmap *regmap; -+ struct device *dev; -+ -+ base_client = at24->client[0].client; -+ dev = &base_client->dev; -+ -+ dummy_client = devm_i2c_new_dummy_device(dev, base_client->adapter, -+ base_client->addr + index); -+ if (IS_ERR(dummy_client)) -+ return PTR_ERR(dummy_client); -+ -+ regmap = devm_regmap_init_i2c(dummy_client, regmap_config); -+ if (IS_ERR(regmap)) -+ return PTR_ERR(regmap); -+ -+ at24->client[index].client = dummy_client; -+ at24->client[index].regmap = regmap; -+ -+ return 0; -+} -+ -+static unsigned int at24_get_offset_adj(u8 flags, unsigned int byte_len) -+{ -+ if (flags & AT24_FLAG_MAC) { -+ /* EUI-48 starts from 0x9a, EUI-64 from 0x98 */ -+ return 0xa0 - byte_len; -+ } else if (flags & AT24_FLAG_SERIAL && flags & AT24_FLAG_ADDR16) { -+ /* -+ * For 16 bit address pointers, the word address must contain -+ * a '10' sequence in bits 11 and 10 regardless of the -+ * intended position of the address pointer. -+ */ -+ return 0x0800; -+ } else if (flags & AT24_FLAG_SERIAL) { -+ /* -+ * Otherwise the word address must begin with a '10' sequence, -+ * regardless of the intended address. -+ */ -+ return 0x0080; -+ } else { -+ return 0; -+ } -+} -+ -+static int at24_probe(struct i2c_client *client) -+{ -+ struct regmap_config regmap_config = { }; -+ struct nvmem_config nvmem_config = { }; -+ u32 byte_len, page_size, flags, addrw; -+ const struct at24_chip_data *cdata; -+ struct device *dev = &client->dev; -+ bool i2c_fn_i2c, i2c_fn_block; -+ unsigned int i, num_addresses; -+ struct at24_data *at24; -+ struct regmap *regmap; -+ bool writable; -+ u8 test_byte; -+ int err; -+ -+ i2c_fn_i2c = i2c_check_functionality(client->adapter, I2C_FUNC_I2C); -+ i2c_fn_block = i2c_check_functionality(client->adapter, -+ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK); -+ -+ cdata = at24_get_chip_data(dev); -+ if (IS_ERR(cdata)) -+ return PTR_ERR(cdata); -+ -+ err = device_property_read_u32(dev, "pagesize", &page_size); -+ if (err) -+ /* -+ * This is slow, but we can't know all eeproms, so we better -+ * play safe. Specifying custom eeprom-types via device tree -+ * or properties is recommended anyhow. -+ */ -+ page_size = 1; -+ -+ flags = cdata->flags; -+ if (device_property_present(dev, "read-only")) -+ flags |= AT24_FLAG_READONLY; -+ if (device_property_present(dev, "no-read-rollover")) -+ flags |= AT24_FLAG_NO_RDROL; -+ -+ err = device_property_read_u32(dev, "address-width", &addrw); -+ if (!err) { -+ switch (addrw) { -+ case 8: -+ if (flags & AT24_FLAG_ADDR16) -+ dev_warn(dev, -+ "Override address width to be 8, while default is 16\n"); -+ flags &= ~AT24_FLAG_ADDR16; -+ break; -+ case 16: -+ flags |= AT24_FLAG_ADDR16; -+ break; -+ default: -+ dev_warn(dev, "Bad \"address-width\" property: %u\n", -+ addrw); -+ } -+ } -+ -+ err = device_property_read_u32(dev, "size", &byte_len); -+ if (err) -+ byte_len = cdata->byte_len; -+ -+ if (!i2c_fn_i2c && !i2c_fn_block) -+ page_size = 1; -+ -+ if (!page_size) { -+ dev_err(dev, "page_size must not be 0!\n"); -+ return -EINVAL; -+ } -+ -+ if (!is_power_of_2(page_size)) -+ dev_warn(dev, "page_size looks suspicious (no power of 2)!\n"); -+ -+ err = device_property_read_u32(dev, "num-addresses", &num_addresses); -+ if (err) { -+ if (flags & AT24_FLAG_TAKE8ADDR) -+ num_addresses = 8; -+ else -+ num_addresses = DIV_ROUND_UP(byte_len, -+ (flags & AT24_FLAG_ADDR16) ? 65536 : 256); -+ } -+ -+ if ((flags & AT24_FLAG_SERIAL) && (flags & AT24_FLAG_MAC)) { -+ dev_err(dev, -+ "invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC."); -+ return -EINVAL; -+ } -+ -+ regmap_config.val_bits = 8; -+ regmap_config.reg_bits = (flags & AT24_FLAG_ADDR16) ? 16 : 8; -+ regmap_config.disable_locking = true; -+ -+ regmap = devm_regmap_init_i2c(client, ®map_config); -+ if (IS_ERR(regmap)) -+ return PTR_ERR(regmap); -+ -+ at24 = devm_kzalloc(dev, struct_size(at24, client, num_addresses), -+ GFP_KERNEL); -+ if (!at24) -+ return -ENOMEM; -+ -+ mutex_init(&at24->lock); -+ at24->byte_len = byte_len; -+ at24->page_size = page_size; -+ at24->flags = flags; -+ at24->read_post = cdata->read_post; -+ at24->num_addresses = num_addresses; -+ at24->offset_adj = at24_get_offset_adj(flags, byte_len); -+ at24->client[0].client = client; -+ at24->client[0].regmap = regmap; -+ -+ at24->vcc_reg = devm_regulator_get(dev, "vcc"); -+ if (IS_ERR(at24->vcc_reg)) -+ return PTR_ERR(at24->vcc_reg); -+ -+ writable = !(flags & AT24_FLAG_READONLY); -+ if (writable) { -+ at24->write_max = min_t(unsigned int, -+ page_size, at24_io_limit); -+ if (!i2c_fn_i2c && at24->write_max > I2C_SMBUS_BLOCK_MAX) -+ at24->write_max = I2C_SMBUS_BLOCK_MAX; -+ } -+ -+ /* use dummy devices for multiple-address chips */ -+ for (i = 1; i < num_addresses; i++) { -+ err = at24_make_dummy_client(at24, i, ®map_config); -+ if (err) -+ return err; -+ } -+ -+ /* -+ * If the 'label' property is not present for the AT24 EEPROM, -+ * then nvmem_config.id is initialised to NVMEM_DEVID_AUTO, -+ * and this will append the 'devid' to the name of the NVMEM -+ * device. This is purely legacy and the AT24 driver has always -+ * defaulted to this. However, if the 'label' property is -+ * present then this means that the name is specified by the -+ * firmware and this name should be used verbatim and so it is -+ * not necessary to append the 'devid'. -+ */ -+ if (device_property_present(dev, "label")) { -+ nvmem_config.id = NVMEM_DEVID_NONE; -+ err = device_property_read_string(dev, "label", -+ &nvmem_config.name); -+ if (err) -+ return err; -+ } else { -+ nvmem_config.id = NVMEM_DEVID_AUTO; -+ nvmem_config.name = dev_name(dev); -+ } -+ -+ nvmem_config.type = NVMEM_TYPE_EEPROM; -+ nvmem_config.dev = dev; -+ nvmem_config.read_only = !writable; -+ nvmem_config.root_only = !(flags & AT24_FLAG_IRUGO); -+ nvmem_config.owner = THIS_MODULE; -+ nvmem_config.compat = true; -+ nvmem_config.base_dev = dev; -+ nvmem_config.reg_read = at24_read; -+ nvmem_config.reg_write = at24_write; -+ nvmem_config.priv = at24; -+ nvmem_config.stride = 1; -+ nvmem_config.word_size = 1; -+ nvmem_config.size = byte_len; -+ -+ i2c_set_clientdata(client, at24); -+ -+ err = regulator_enable(at24->vcc_reg); -+ if (err) { -+ dev_err(dev, "Failed to enable vcc regulator\n"); -+ return err; -+ } -+ -+ /* enable runtime pm */ -+ pm_runtime_set_active(dev); -+ pm_runtime_enable(dev); -+ -+ at24->nvmem = devm_nvmem_register(dev, &nvmem_config); -+ if (IS_ERR(at24->nvmem)) { -+ pm_runtime_disable(dev); -+ if (!pm_runtime_status_suspended(dev)) -+ regulator_disable(at24->vcc_reg); -+ return PTR_ERR(at24->nvmem); -+ } -+ -+ /* -+ * Perform a one-byte test read to verify that the -+ * chip is functional. -+ */ -+ err = at24_read(at24, 0, &test_byte, 1); -+ if (err) { -+ pm_runtime_disable(dev); -+ if (!pm_runtime_status_suspended(dev)) -+ regulator_disable(at24->vcc_reg); -+ return -ENODEV; -+ } -+ -+ pm_runtime_idle(dev); -+ -+ if (writable) -+ dev_info(dev, "%u byte %s EEPROM, writable, %u bytes/write\n", -+ byte_len, client->name, at24->write_max); -+ else -+ dev_info(dev, "%u byte %s EEPROM, read-only\n", -+ byte_len, client->name); -+ -+ return 0; -+} -+ -+static int at24_remove(struct i2c_client *client) -+{ -+ struct at24_data *at24 = i2c_get_clientdata(client); -+ -+ pm_runtime_disable(&client->dev); -+ if (!pm_runtime_status_suspended(&client->dev)) -+ regulator_disable(at24->vcc_reg); -+ pm_runtime_set_suspended(&client->dev); -+ -+ return 0; -+} -+ -+static int __maybe_unused at24_suspend(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct at24_data *at24 = i2c_get_clientdata(client); -+ -+ return regulator_disable(at24->vcc_reg); -+} -+ -+static int __maybe_unused at24_resume(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct at24_data *at24 = i2c_get_clientdata(client); -+ -+ return regulator_enable(at24->vcc_reg); -+} -+ -+static const struct dev_pm_ops at24_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, -+ pm_runtime_force_resume) -+ SET_RUNTIME_PM_OPS(at24_suspend, at24_resume, NULL) -+}; -+ -+static struct i2c_driver at24_driver = { -+ .driver = { -+ .name = "wb_at24", -+ .pm = &at24_pm_ops, -+ .of_match_table = at24_of_match, -+ .acpi_match_table = ACPI_PTR(at24_acpi_ids), -+ }, -+ .probe_new = at24_probe, -+ .remove = at24_remove, -+ .id_table = at24_ids, -+}; -+ -+static int __init at24_init(void) -+{ -+ if (!at24_io_limit) { -+ pr_err("at24: at24_io_limit must not be 0!\n"); -+ return -EINVAL; -+ } -+ -+ at24_io_limit = rounddown_pow_of_two(at24_io_limit); -+ return i2c_add_driver(&at24_driver); -+} -+module_init(at24_init); -+ -+static void __exit at24_exit(void) -+{ -+ i2c_del_driver(&at24_driver); -+} -+module_exit(at24_exit); -+ -+MODULE_DESCRIPTION("Driver for most I2C EEPROMs"); -+MODULE_AUTHOR("support"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_csu550.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_csu550.c -new file mode 100644 -index 000000000..36d07f071 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_csu550.c -@@ -0,0 +1,236 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Hardware monitoring driver for PMBus devices -+ * -+ * Copyright (c) 2010, 2011 Ericsson AB. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "wb_pmbus.h" -+ -+struct pmbus_device_info { -+ int pages; -+ u32 flags; -+}; -+ -+static const struct i2c_device_id pmbus_id[]; -+ -+/* -+ * Find sensor groups and status registers on each page. -+ */ -+static void pmbus_find_sensor_groups(struct i2c_client *client, -+ struct pmbus_driver_info *info) -+{ -+ int page; -+ -+ /* Sensors detected on page 0 only */ -+ if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_VIN)) -+ info->func[0] |= PMBUS_HAVE_VIN; -+ if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_IIN)) -+ info->func[0] |= PMBUS_HAVE_IIN; -+ if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_PIN)) -+ info->func[0] |= PMBUS_HAVE_PIN; -+ if (info->func[0] -+ && wb_pmbus_check_byte_register(client, 0, PMBUS_STATUS_INPUT)) -+ info->func[0] |= PMBUS_HAVE_STATUS_INPUT; -+ if (wb_pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_12) && -+ wb_pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_1)) { -+ info->func[0] |= PMBUS_HAVE_FAN12; -+ if (wb_pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_12)) -+ info->func[0] |= PMBUS_HAVE_STATUS_FAN12; -+ } -+ if (wb_pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_34) && -+ wb_pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_3)) { -+ info->func[0] |= PMBUS_HAVE_FAN34; -+ if (wb_pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_34)) -+ info->func[0] |= PMBUS_HAVE_STATUS_FAN34; -+ } -+ if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_1)) -+ info->func[0] |= PMBUS_HAVE_TEMP; -+ if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_2)) -+ info->func[0] |= PMBUS_HAVE_TEMP2; -+ if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_3)) -+ info->func[0] |= PMBUS_HAVE_TEMP3; -+ if (info->func[0] & (PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 -+ | PMBUS_HAVE_TEMP3) -+ && wb_pmbus_check_byte_register(client, 0, -+ PMBUS_STATUS_TEMPERATURE)) -+ info->func[0] |= PMBUS_HAVE_STATUS_TEMP; -+ -+ /* Sensors detected on all pages */ -+ for (page = 0; page < info->pages; page++) { -+ if (wb_pmbus_check_word_register(client, page, PMBUS_READ_VOUT)) { -+ info->func[page] |= PMBUS_HAVE_VOUT; -+ if (wb_pmbus_check_byte_register(client, page, -+ PMBUS_STATUS_VOUT)) -+ info->func[page] |= PMBUS_HAVE_STATUS_VOUT; -+ } -+ if (wb_pmbus_check_word_register(client, page, PMBUS_READ_IOUT)) { -+ info->func[page] |= PMBUS_HAVE_IOUT; -+ if (wb_pmbus_check_byte_register(client, 0, -+ PMBUS_STATUS_IOUT)) -+ info->func[page] |= PMBUS_HAVE_STATUS_IOUT; -+ } -+ if (wb_pmbus_check_word_register(client, page, PMBUS_READ_POUT)) -+ info->func[page] |= PMBUS_HAVE_POUT; -+ } -+} -+ -+/* -+ * Identify chip parameters. -+ */ -+static int pmbus_identify(struct i2c_client *client, -+ struct pmbus_driver_info *info) -+{ -+ int ret = 0; -+ -+ if (!info->pages) { -+ /* -+ * Check if the PAGE command is supported. If it is, -+ * keep setting the page number until it fails or until the -+ * maximum number of pages has been reached. Assume that -+ * this is the number of pages supported by the chip. -+ */ -+ if (wb_pmbus_check_byte_register(client, 0, PMBUS_PAGE)) { -+ int page; -+ -+ for (page = 1; page < PMBUS_PAGES; page++) { -+ if (wb_pmbus_set_page(client, page, 0xff) < 0) -+ break; -+ } -+ wb_pmbus_set_page(client, 0, 0xff); -+ info->pages = page; -+ } else { -+ info->pages = 1; -+ } -+ -+ wb_pmbus_clear_faults(client); -+ } -+ -+ if (wb_pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) { -+ int vout_mode, i; -+ -+ vout_mode = wb_pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); -+ if (vout_mode >= 0 && vout_mode != 0xff) { -+ switch (vout_mode >> 5) { -+ case 0: -+ break; -+ case 1: -+ info->format[PSC_VOLTAGE_OUT] = vid; -+ for (i = 0; i < info->pages; i++) -+ info->vrm_version[i] = vr11; -+ break; -+ case 2: -+ info->format[PSC_VOLTAGE_OUT] = direct; -+ break; -+ default: -+ ret = -ENODEV; -+ goto abort; -+ } -+ } -+ } -+ -+ /* -+ * We should check if the COEFFICIENTS register is supported. -+ * If it is, and the chip is configured for direct mode, we can read -+ * the coefficients from the chip, one set per group of sensor -+ * registers. -+ * -+ * To do this, we will need access to a chip which actually supports the -+ * COEFFICIENTS command, since the command is too complex to implement -+ * without testing it. Until then, abort if a chip configured for direct -+ * mode was detected. -+ */ -+ if (info->format[PSC_VOLTAGE_OUT] == direct) { -+ ret = -ENODEV; -+ goto abort; -+ } -+ -+ /* Try to find sensor groups */ -+ pmbus_find_sensor_groups(client, info); -+abort: -+ return ret; -+} -+ -+static int pmbus_probe(struct i2c_client *client) -+{ -+ struct pmbus_driver_info *info; -+ struct pmbus_platform_data *pdata = NULL; -+ struct device *dev = &client->dev; -+ struct pmbus_device_info *device_info; -+ -+ info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info), GFP_KERNEL); -+ if (!info) -+ return -ENOMEM; -+ -+ device_info = (struct pmbus_device_info *)i2c_match_id(pmbus_id, client)->driver_data; -+ if (device_info->flags & PMBUS_SKIP_STATUS_CHECK) { -+ pdata = devm_kzalloc(dev, sizeof(struct pmbus_platform_data), -+ GFP_KERNEL); -+ if (!pdata) -+ return -ENOMEM; -+ -+ pdata->flags = PMBUS_SKIP_STATUS_CHECK; -+ } -+ -+ info->pages = device_info->pages; -+ info->identify = pmbus_identify; -+ dev->platform_data = pdata; -+ -+ return wb_pmbus_do_probe(client, info); -+} -+ -+static const struct pmbus_device_info pmbus_info_one = { -+ .pages = 1, -+ .flags = 0 -+}; -+ -+static const struct pmbus_device_info pmbus_info_zero = { -+ .pages = 0, -+ .flags = 0 -+}; -+ -+static const struct pmbus_device_info pmbus_info_one_skip = { -+ .pages = 1, -+ .flags = PMBUS_SKIP_STATUS_CHECK -+}; -+ -+static const struct pmbus_device_info pmbus_info_zero_skip = { -+ .pages = 0, -+ .flags = PMBUS_SKIP_STATUS_CHECK -+}; -+/* -+ * Use driver_data to set the number of pages supported by the chip. -+ */ -+static const struct i2c_device_id pmbus_id[] = { -+ {"wb_csu550", (kernel_ulong_t)&pmbus_info_zero_skip}, -+ {"wb_csu800", (kernel_ulong_t)&pmbus_info_one_skip}, -+ {"wb_fsp1200", (kernel_ulong_t)&pmbus_info_one_skip}, -+ {"wb_dps550", (kernel_ulong_t)&pmbus_info_one_skip}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(i2c, pmbus_id); -+ -+/* This is the driver that will be inserted */ -+static struct i2c_driver pmbus_driver = { -+ .driver = { -+ .name = "wb_pmbus", -+ }, -+ .probe_new = pmbus_probe, -+ .remove = wb_pmbus_do_remove, -+ .id_table = pmbus_id, -+}; -+ -+module_i2c_driver(pmbus_driver); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("Generic PMBus driver"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_algo_bit.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_algo_bit.c -new file mode 100644 -index 000000000..c98ac7a1c ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_algo_bit.c -@@ -0,0 +1,725 @@ -+/* ------------------------------------------------------------------------- -+ * i2c-algo-bit.c i2c driver algorithms for bit-shift adapters -+ * ------------------------------------------------------------------------- -+ * Copyright (C) 1995-2000 Simon G. Vogl -+ -+ 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. -+ * ------------------------------------------------------------------------- */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static int g_i2c_algo_bit_debug = 0; -+static int g_i2c_algo_bit_error = 0; -+ -+module_param(g_i2c_algo_bit_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_i2c_algo_bit_error, int, S_IRUGO | S_IWUSR); -+ -+#define I2C_ALGO_BIT_DEBUG(fmt, args...) do { \ -+ if (g_i2c_algo_bit_debug) { \ -+ printk(KERN_INFO "[I2C_ALGO_BIT][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define I2C_ALGO_BIT_ERROR(fmt, args...) do { \ -+ if (g_i2c_algo_bit_error) { \ -+ printk(KERN_ERR "[I2C_ALGO_BIT][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+/* ----- global defines ----------------------------------------------- */ -+ -+#ifdef DEBUG -+#define bit_dbg(level, dev, format, args...) \ -+ do { \ -+ if (i2c_debug >= level) \ -+ dev_dbg(dev, format, ##args); \ -+ } while (0) -+#else -+#define bit_dbg(level, dev, format, args...) \ -+ do {} while (0) -+#endif /* DEBUG */ -+ -+/* ----- global variables --------------------------------------------- */ -+ -+static int bit_test; /* see if the line-setting functions work */ -+module_param(bit_test, int, S_IRUGO); -+MODULE_PARM_DESC(bit_test, "lines testing - 0 off; 1 report; 2 fail if stuck"); -+ -+#ifdef DEBUG -+static int i2c_debug = 1; -+module_param(i2c_debug, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(i2c_debug, -+ "debug level - 0 off; 1 normal; 2 verbose; 3 very verbose"); -+#endif -+ -+/* --- setting states on the bus with the right timing: --------------- */ -+ -+#define setsda(adap, val) adap->setsda(adap->data, val) -+#define setscl(adap, val) adap->setscl(adap->data, val) -+#define getsda(adap) adap->getsda(adap->data) -+#define getscl(adap) adap->getscl(adap->data) -+ -+static inline void sdalo(struct i2c_algo_bit_data *adap) -+{ -+ setsda(adap, 0); -+ udelay((adap->udelay + 1) / 2); -+} -+ -+static inline void sdahi(struct i2c_algo_bit_data *adap) -+{ -+ setsda(adap, 1); -+ udelay((adap->udelay + 1) / 2); -+} -+ -+static inline void scllo(struct i2c_algo_bit_data *adap) -+{ -+ setscl(adap, 0); -+ udelay(adap->udelay / 2); -+} -+ -+/* -+ * Raise scl line, and do checking for delays. This is necessary for slower -+ * devices. -+ */ -+static int sclhi(struct i2c_algo_bit_data *adap) -+{ -+ unsigned long start; -+ -+ setscl(adap, 1); -+ -+ /* Not all adapters have scl sense line... */ -+ if (!adap->getscl) -+ goto done; -+ -+ start = jiffies; -+ while (!getscl(adap)) { -+ /* This hw knows how to read the clock line, so we wait -+ * until it actually gets high. This is safer as some -+ * chips may hold it low ("clock stretching") while they -+ * are processing data internally. -+ */ -+ if (time_after(jiffies, start + adap->timeout)) { -+ /* Test one last time, as we may have been preempted -+ * between last check and timeout test. -+ */ -+ if (getscl(adap)) -+ break; -+ return -ETIMEDOUT; -+ } -+ cpu_relax(); -+ } -+#ifdef DEBUG -+ if (jiffies != start && i2c_debug >= 3) -+ pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go " -+ "high\n", jiffies - start); -+#endif -+ -+done: -+ udelay(adap->udelay); -+ return 0; -+} -+ -+/* --- other auxiliary functions -------------------------------------- */ -+static void i2c_start(struct i2c_algo_bit_data *adap) -+{ -+ /* assert: scl, sda are high */ -+ setsda(adap, 0); -+ udelay(adap->udelay); -+ scllo(adap); -+} -+ -+static void i2c_repstart(struct i2c_algo_bit_data *adap) -+{ -+ /* assert: scl is low */ -+ sdahi(adap); -+ sclhi(adap); -+ setsda(adap, 0); -+ udelay(adap->udelay); -+ scllo(adap); -+} -+ -+static void i2c_stop(struct i2c_algo_bit_data *adap) -+{ -+ /* assert: scl is low */ -+ sdalo(adap); -+ sclhi(adap); -+ setsda(adap, 1); -+ udelay(adap->udelay); -+} -+ -+/* send a byte without start cond., look for arbitration, -+ check ackn. from slave */ -+/* returns: -+ * 1 if the device acknowledged -+ * 0 if the device did not ack -+ * -ETIMEDOUT if an error occurred (while raising the scl line) -+ */ -+static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c) -+{ -+ int i; -+ int sb; -+ int ack; -+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; -+ -+ /* assert: scl is low */ -+ for (i = 7; i >= 0; i--) { -+ sb = (c >> i) & 1; -+ setsda(adap, sb); -+ udelay((adap->udelay + 1) / 2); -+ if (sclhi(adap) < 0) { /* timed out */ -+ bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " -+ "timeout at bit #%d\n", (int)c, i); -+ return -ETIMEDOUT; -+ } -+ /* FIXME do arbitration here: -+ * if (sb && !getsda(adap)) -> ouch! Get out of here. -+ * -+ * Report a unique code, so higher level code can retry -+ * the whole (combined) message and *NOT* issue STOP. -+ */ -+ scllo(adap); -+ } -+ sdahi(adap); -+ if (sclhi(adap) < 0) { /* timeout */ -+ bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " -+ "timeout at ack\n", (int)c); -+ return -ETIMEDOUT; -+ } -+ -+ /* read ack: SDA should be pulled down by slave, or it may -+ * NAK (usually to report problems with the data we wrote). -+ */ -+ ack = !getsda(adap); /* ack: sda is pulled low -> success */ -+ bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c, -+ ack ? "A" : "NA"); -+ -+ scllo(adap); -+ return ack; -+ /* assert: scl is low (sda undef) */ -+} -+ -+static int i2c_inb(struct i2c_adapter *i2c_adap) -+{ -+ /* read byte via i2c port, without start/stop sequence */ -+ /* acknowledge is sent in i2c_read. */ -+ int i; -+ unsigned char indata = 0; -+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; -+ -+ /* assert: scl is low */ -+ sdahi(adap); -+ for (i = 0; i < 8; i++) { -+ if (sclhi(adap) < 0) { /* timeout */ -+ bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit " -+ "#%d\n", 7 - i); -+ return -ETIMEDOUT; -+ } -+ indata *= 2; -+ if (getsda(adap)) -+ indata |= 0x01; -+ setscl(adap, 0); -+ udelay(i == 7 ? adap->udelay / 2 : adap->udelay); -+ } -+ /* assert: scl is low */ -+ return indata; -+} -+ -+/* -+ * Sanity check for the adapter hardware - check the reaction of -+ * the bus lines only if it seems to be idle. -+ */ -+static int test_bus(struct i2c_adapter *i2c_adap) -+{ -+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; -+ const char *name = i2c_adap->name; -+ int scl, sda, ret; -+ -+ if (adap->pre_xfer) { -+ ret = adap->pre_xfer(i2c_adap); -+ if (ret < 0) -+ return -ENODEV; -+ } -+ -+ if (adap->getscl == NULL) -+ pr_info("%s: Testing SDA only, SCL is not readable\n", name); -+ -+ sda = getsda(adap); -+ scl = (adap->getscl == NULL) ? 1 : getscl(adap); -+ if (!scl || !sda) { -+ printk(KERN_WARNING -+ "%s: bus seems to be busy (scl=%d, sda=%d)\n", -+ name, scl, sda); -+ goto bailout; -+ } -+ -+ sdalo(adap); -+ sda = getsda(adap); -+ scl = (adap->getscl == NULL) ? 1 : getscl(adap); -+ if (sda) { -+ printk(KERN_WARNING "%s: SDA stuck high!\n", name); -+ goto bailout; -+ } -+ if (!scl) { -+ printk(KERN_WARNING "%s: SCL unexpected low " -+ "while pulling SDA low!\n", name); -+ goto bailout; -+ } -+ -+ sdahi(adap); -+ sda = getsda(adap); -+ scl = (adap->getscl == NULL) ? 1 : getscl(adap); -+ if (!sda) { -+ printk(KERN_WARNING "%s: SDA stuck low!\n", name); -+ goto bailout; -+ } -+ if (!scl) { -+ printk(KERN_WARNING "%s: SCL unexpected low " -+ "while pulling SDA high!\n", name); -+ goto bailout; -+ } -+ -+ scllo(adap); -+ sda = getsda(adap); -+ scl = (adap->getscl == NULL) ? 0 : getscl(adap); -+ if (scl) { -+ printk(KERN_WARNING "%s: SCL stuck high!\n", name); -+ goto bailout; -+ } -+ if (!sda) { -+ printk(KERN_WARNING "%s: SDA unexpected low " -+ "while pulling SCL low!\n", name); -+ goto bailout; -+ } -+ -+ sclhi(adap); -+ sda = getsda(adap); -+ scl = (adap->getscl == NULL) ? 1 : getscl(adap); -+ if (!scl) { -+ printk(KERN_WARNING "%s: SCL stuck low!\n", name); -+ goto bailout; -+ } -+ if (!sda) { -+ printk(KERN_WARNING "%s: SDA unexpected low " -+ "while pulling SCL high!\n", name); -+ goto bailout; -+ } -+ -+ if (adap->post_xfer) -+ adap->post_xfer(i2c_adap); -+ -+ pr_info("%s: Test OK\n", name); -+ return 0; -+bailout: -+ sdahi(adap); -+ sclhi(adap); -+ -+ if (adap->post_xfer) -+ adap->post_xfer(i2c_adap); -+ -+ return -ENODEV; -+} -+ -+/* ----- Utility functions -+ */ -+ -+/* try_address tries to contact a chip for a number of -+ * times before it gives up. -+ * return values: -+ * 1 chip answered -+ * 0 chip did not answer -+ * -x transmission error -+ */ -+static int try_address(struct i2c_adapter *i2c_adap, -+ unsigned char addr, int retries) -+{ -+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; -+ int i, ret = 0; -+ -+ for (i = 0; i <= retries; i++) { -+ ret = i2c_outb(i2c_adap, addr); -+ if (ret == 1 || i == retries) -+ break; -+ bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); -+ i2c_stop(adap); -+ udelay(adap->udelay); -+ yield(); -+ bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); -+ i2c_start(adap); -+ } -+ if (i && ret) -+ bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at " -+ "0x%02x: %s\n", i + 1, -+ addr & 1 ? "read from" : "write to", addr >> 1, -+ ret == 1 ? "success" : "failed, timeout?"); -+ return ret; -+} -+ -+static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) -+{ -+ const unsigned char *temp = msg->buf; -+ int count = msg->len; -+ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; -+ int retval; -+ int wrcount = 0; -+ -+ while (count > 0) { -+ retval = i2c_outb(i2c_adap, *temp); -+ -+ /* OK/ACK; or ignored NAK */ -+ if ((retval > 0) || (nak_ok && (retval == 0))) { -+ count--; -+ temp++; -+ wrcount++; -+ -+ /* A slave NAKing the master means the slave didn't like -+ * something about the data it saw. For example, maybe -+ * the SMBus PEC was wrong. -+ */ -+ } else if (retval == 0) { -+ dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n"); -+ return -EIO; -+ -+ /* Timeout; or (someday) lost arbitration -+ * -+ * FIXME Lost ARB implies retrying the transaction from -+ * the first message, after the "winning" master issues -+ * its STOP. As a rule, upper layer code has no reason -+ * to know or care about this ... it is *NOT* an error. -+ */ -+ } else { -+ dev_err(&i2c_adap->dev, "sendbytes: error %d\n", -+ retval); -+ return retval; -+ } -+ } -+ return wrcount; -+} -+ -+static int acknak(struct i2c_adapter *i2c_adap, int is_ack) -+{ -+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; -+ -+ /* assert: sda is high */ -+ if (is_ack) /* send ack */ -+ setsda(adap, 0); -+ udelay((adap->udelay + 1) / 2); -+ if (sclhi(adap) < 0) { /* timeout */ -+ dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n"); -+ return -ETIMEDOUT; -+ } -+ scllo(adap); -+ return 0; -+} -+ -+static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) -+{ -+ int inval; -+ int rdcount = 0; /* counts bytes read */ -+ unsigned char *temp = msg->buf; -+ int count = msg->len; -+ const unsigned flags = msg->flags; -+ -+ while (count > 0) { -+ inval = i2c_inb(i2c_adap); -+ if (inval >= 0) { -+ *temp = inval; -+ rdcount++; -+ } else { /* read timed out */ -+ break; -+ } -+ -+ temp++; -+ count--; -+ -+ /* Some SMBus transactions require that we receive the -+ transaction length as the first read byte. */ -+ if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) { -+ if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) { -+ if (!(flags & I2C_M_NO_RD_ACK)) -+ acknak(i2c_adap, 0); -+ dev_err(&i2c_adap->dev, "readbytes: invalid " -+ "block length (%d)\n", inval); -+ return -EPROTO; -+ } -+ /* The original count value accounts for the extra -+ bytes, that is, either 1 for a regular transaction, -+ or 2 for a PEC transaction. */ -+ count += inval; -+ msg->len += inval; -+ } -+ -+ bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n", -+ inval, -+ (flags & I2C_M_NO_RD_ACK) -+ ? "(no ack/nak)" -+ : (count ? "A" : "NA")); -+ -+ if (!(flags & I2C_M_NO_RD_ACK)) { -+ inval = acknak(i2c_adap, count); -+ if (inval < 0) -+ return inval; -+ } -+ } -+ return rdcount; -+} -+ -+/* doAddress initiates the transfer by generating the start condition (in -+ * try_address) and transmits the address in the necessary format to handle -+ * reads, writes as well as 10bit-addresses. -+ * returns: -+ * 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set -+ * -x an error occurred (like: -ENXIO if the device did not answer, or -+ * -ETIMEDOUT, for example if the lines are stuck...) -+ */ -+static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) -+{ -+ unsigned short flags = msg->flags; -+ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; -+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; -+ -+ unsigned char addr; -+ int ret, retries; -+ -+ retries = nak_ok ? 0 : i2c_adap->retries; -+ -+ if (flags & I2C_M_TEN) { -+ /* a ten bit address */ -+ addr = 0xf0 | ((msg->addr >> 7) & 0x06); -+ bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr); -+ /* try extended address code...*/ -+ ret = try_address(i2c_adap, addr, retries); -+ if ((ret != 1) && !nak_ok) { -+ dev_err(&i2c_adap->dev, -+ "died at extended address code\n"); -+ return -ENXIO; -+ } -+ /* the remaining 8 bit address */ -+ ret = i2c_outb(i2c_adap, msg->addr & 0xff); -+ if ((ret != 1) && !nak_ok) { -+ /* the chip did not ack / xmission error occurred */ -+ dev_err(&i2c_adap->dev, "died at 2nd address code\n"); -+ return -ENXIO; -+ } -+ if (flags & I2C_M_RD) { -+ bit_dbg(3, &i2c_adap->dev, "emitting repeated " -+ "start condition\n"); -+ i2c_repstart(adap); -+ /* okay, now switch into reading mode */ -+ addr |= 0x01; -+ ret = try_address(i2c_adap, addr, retries); -+ if ((ret != 1) && !nak_ok) { -+ dev_err(&i2c_adap->dev, -+ "died at repeated address code\n"); -+ return -EIO; -+ } -+ } -+ } else { /* normal 7bit address */ -+ addr = msg->addr << 1; -+ if (flags & I2C_M_RD) -+ addr |= 1; -+ if (flags & I2C_M_REV_DIR_ADDR) -+ addr ^= 1; -+ ret = try_address(i2c_adap, addr, retries); -+ if ((ret != 1) && !nak_ok) -+ return -ENXIO; -+ } -+ -+ return 0; -+} -+ -+static void bit_i2c_unblock(struct i2c_adapter *i2c_adap) -+{ -+ int i; -+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; -+ -+ for (i = 0; i < 9; i++) { -+ setscl(adap, 0); -+ udelay(5); -+ setscl(adap, 1); -+ udelay(5); -+ } -+ setscl(adap, 0); -+ setsda(adap, 0); -+ udelay(5); -+ setscl(adap, 1); -+ udelay(5); -+ setsda(adap, 1); -+} -+ -+static int check_bit_i2c_unblock(struct i2c_adapter *i2c_adap) -+{ -+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; -+ int sda, scl; -+ -+ sda = getsda(adap); -+ scl = getscl(adap); -+ if ((sda == 0) && scl) { -+ I2C_ALGO_BIT_ERROR("SCL is high and SDA is low, send 9 clock to device.\n"); -+ bit_i2c_unblock(i2c_adap); -+ } -+ -+ sda = getsda(adap); -+ scl = getscl(adap); -+ if (sda && scl) { -+ I2C_ALGO_BIT_DEBUG("SCL and SDA are both high, i2c level check ok.\n"); -+ return 0; -+ } -+ dev_warn(&i2c_adap->dev, "Check i2c level failed, SCL %s, SDA %s.\n", scl ? "high" : "low", sda ? "high" : "low"); -+ return -EIO; -+} -+ -+static int bit_xfer(struct i2c_adapter *i2c_adap, -+ struct i2c_msg msgs[], int num) -+{ -+ struct i2c_msg *pmsg; -+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; -+ int i, ret; -+ unsigned short nak_ok; -+ -+ if (adap->pre_xfer) { -+ ret = adap->pre_xfer(i2c_adap); -+ if (ret < 0) -+ return ret; -+ } -+ -+ if (check_bit_i2c_unblock(i2c_adap) < 0) { -+ I2C_ALGO_BIT_ERROR("check i2c is block.\n"); -+ return -EIO; -+ } -+ -+ bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); -+ i2c_start(adap); -+ for (i = 0; i < num; i++) { -+ pmsg = &msgs[i]; -+ nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; -+ if (!(pmsg->flags & I2C_M_NOSTART)) { -+ if (i) { -+ bit_dbg(3, &i2c_adap->dev, "emitting " -+ "repeated start condition\n"); -+ i2c_repstart(adap); -+ } -+ ret = bit_doAddress(i2c_adap, pmsg); -+ if ((ret != 0) && !nak_ok) { -+ bit_dbg(1, &i2c_adap->dev, "NAK from " -+ "device addr 0x%02x msg #%d\n", -+ msgs[i].addr, i); -+ goto bailout; -+ } -+ } -+ if (pmsg->flags & I2C_M_RD) { -+ /* read bytes into buffer*/ -+ ret = readbytes(i2c_adap, pmsg); -+ if (ret >= 1) -+ bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n", -+ ret, ret == 1 ? "" : "s"); -+ if (ret < pmsg->len) { -+ if (ret >= 0) -+ ret = -EIO; -+ goto bailout; -+ } -+ } else { -+ /* write bytes from buffer */ -+ ret = sendbytes(i2c_adap, pmsg); -+ if (ret >= 1) -+ bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n", -+ ret, ret == 1 ? "" : "s"); -+ if (ret < pmsg->len) { -+ if (ret >= 0) -+ ret = -EIO; -+ goto bailout; -+ } -+ } -+ } -+ ret = i; -+ -+bailout: -+ bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); -+ i2c_stop(adap); -+ -+ if (adap->post_xfer) -+ adap->post_xfer(i2c_adap); -+ return ret; -+} -+ -+static u32 bit_func(struct i2c_adapter *adap) -+{ -+ return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL | -+ I2C_FUNC_SMBUS_READ_BLOCK_DATA | -+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL | -+ I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; -+} -+ -+/* -----exported algorithm data: ------------------------------------- */ -+ -+const struct i2c_algorithm wb_i2c_bit_algo = { -+ .master_xfer = bit_xfer, -+ .functionality = bit_func, -+}; -+EXPORT_SYMBOL(wb_i2c_bit_algo); -+ -+static const struct i2c_adapter_quirks i2c_bit_quirk_no_clk_stretch = { -+ .flags = I2C_AQ_NO_CLK_STRETCH, -+}; -+ -+/* -+ * registering functions to load algorithms at runtime -+ */ -+static int __i2c_bit_add_bus(struct i2c_adapter *adap, -+ int (*add_adapter)(struct i2c_adapter *)) -+{ -+ struct i2c_algo_bit_data *bit_adap = adap->algo_data; -+ int ret; -+ -+ if (bit_test) { -+ ret = test_bus(adap); -+ if (bit_test >= 2 && ret < 0) -+ return -ENODEV; -+ } -+ -+ /* register new adapter to i2c module... */ -+ adap->algo = &wb_i2c_bit_algo; -+ adap->retries = 3; -+ if (bit_adap->getscl == NULL) -+ adap->quirks = &i2c_bit_quirk_no_clk_stretch; -+ -+ ret = add_adapter(adap); -+ if (ret < 0) -+ return ret; -+ -+ /* Complain if SCL can't be read */ -+ if (bit_adap->getscl == NULL) { -+ dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n"); -+ dev_warn(&adap->dev, "Bus may be unreliable\n"); -+ } -+ return 0; -+} -+ -+int wb_i2c_bit_add_bus(struct i2c_adapter *adap) -+{ -+ return __i2c_bit_add_bus(adap, i2c_add_adapter); -+} -+EXPORT_SYMBOL(wb_i2c_bit_add_bus); -+ -+int wb_i2c_bit_add_numbered_bus(struct i2c_adapter *adap) -+{ -+ return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter); -+} -+EXPORT_SYMBOL(wb_i2c_bit_add_numbered_bus); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio.c -new file mode 100644 -index 000000000..0362e905f ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio.c -@@ -0,0 +1,431 @@ -+/* -+ * Bitbanging I2C bus driver using the GPIO API -+ * -+ * Copyright (C) 2007 Atmel Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+extern int wb_i2c_bit_add_numbered_bus(struct i2c_adapter *adap); -+ -+struct i2c_gpio_private_data { -+ struct gpio_desc *sda; -+ struct gpio_desc *scl; -+ struct i2c_adapter adap; -+ struct i2c_algo_bit_data bit_data; -+ struct i2c_gpio_platform_data pdata; -+#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR -+ struct dentry *debug_dir; -+#endif -+}; -+ -+/* -+ * Toggle SDA by changing the output value of the pin. This is only -+ * valid for pins configured as open drain (i.e. setting the value -+ * high effectively turns off the output driver.) -+ */ -+static void i2c_gpio_setsda_val(void *data, int state) -+{ -+ struct i2c_gpio_private_data *priv = data; -+ -+ gpiod_set_value_cansleep(priv->sda, state); -+} -+ -+/* -+ * Toggle SCL by changing the output value of the pin. This is used -+ * for pins that are configured as open drain and for output-only -+ * pins. The latter case will break the i2c protocol, but it will -+ * often work in practice. -+ */ -+static void i2c_gpio_setscl_val(void *data, int state) -+{ -+ struct i2c_gpio_private_data *priv = data; -+ -+ gpiod_set_value_cansleep(priv->scl, state); -+} -+ -+static int i2c_gpio_getsda(void *data) -+{ -+ struct i2c_gpio_private_data *priv = data; -+ -+ return gpiod_get_value_cansleep(priv->sda); -+} -+ -+static int i2c_gpio_getscl(void *data) -+{ -+ struct i2c_gpio_private_data *priv = data; -+ -+ return gpiod_get_value_cansleep(priv->scl); -+} -+ -+#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR -+static struct dentry *i2c_gpio_debug_dir; -+ -+#define setsda(bd, val) ((bd)->setsda((bd)->data, val)) -+#define setscl(bd, val) ((bd)->setscl((bd)->data, val)) -+#define getsda(bd) ((bd)->getsda((bd)->data)) -+#define getscl(bd) ((bd)->getscl((bd)->data)) -+ -+#define WIRE_ATTRIBUTE(wire) \ -+static int fops_##wire##_get(void *data, u64 *val) \ -+{ \ -+ struct i2c_gpio_private_data *priv = data; \ -+ \ -+ i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ -+ *val = get##wire(&priv->bit_data); \ -+ i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ -+ return 0; \ -+} \ -+static int fops_##wire##_set(void *data, u64 val) \ -+{ \ -+ struct i2c_gpio_private_data *priv = data; \ -+ \ -+ i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ -+ set##wire(&priv->bit_data, val); \ -+ i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ -+ return 0; \ -+} \ -+DEFINE_DEBUGFS_ATTRIBUTE(fops_##wire, fops_##wire##_get, fops_##wire##_set, "%llu\n") -+ -+WIRE_ATTRIBUTE(scl); -+WIRE_ATTRIBUTE(sda); -+ -+static void i2c_gpio_incomplete_transfer(struct i2c_gpio_private_data *priv, -+ u32 pattern, u8 pattern_size) -+{ -+ struct i2c_algo_bit_data *bit_data = &priv->bit_data; -+ int i; -+ -+ i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); -+ -+ /* START condition */ -+ setsda(bit_data, 0); -+ udelay(bit_data->udelay); -+ -+ /* Send pattern, request ACK, don't send STOP */ -+ for (i = pattern_size - 1; i >= 0; i--) { -+ setscl(bit_data, 0); -+ udelay(bit_data->udelay / 2); -+ setsda(bit_data, (pattern >> i) & 1); -+ udelay((bit_data->udelay + 1) / 2); -+ setscl(bit_data, 1); -+ udelay(bit_data->udelay); -+ } -+ -+ i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); -+} -+ -+static int fops_incomplete_addr_phase_set(void *data, u64 addr) -+{ -+ struct i2c_gpio_private_data *priv = data; -+ u32 pattern; -+ -+ if (addr > 0x7f) -+ return -EINVAL; -+ -+ /* ADDR (7 bit) + RD (1 bit) + Client ACK, keep SDA hi (1 bit) */ -+ pattern = (addr << 2) | 3; -+ -+ i2c_gpio_incomplete_transfer(priv, pattern, 9); -+ -+ return 0; -+} -+DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_addr_phase, NULL, fops_incomplete_addr_phase_set, "%llu\n"); -+ -+static int fops_incomplete_write_byte_set(void *data, u64 addr) -+{ -+ struct i2c_gpio_private_data *priv = data; -+ u32 pattern; -+ -+ if (addr > 0x7f) -+ return -EINVAL; -+ -+ /* ADDR (7 bit) + WR (1 bit) + Client ACK (1 bit) */ -+ pattern = (addr << 2) | 1; -+ /* 0x00 (8 bit) + Client ACK, keep SDA hi (1 bit) */ -+ pattern = (pattern << 9) | 1; -+ -+ i2c_gpio_incomplete_transfer(priv, pattern, 18); -+ -+ return 0; -+} -+DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write_byte_set, "%llu\n"); -+ -+static void i2c_gpio_fault_injector_init(struct platform_device *pdev) -+{ -+ struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); -+ -+ /* -+ * If there will be a debugfs-dir per i2c adapter somewhen, put the -+ * 'fault-injector' dir there. Until then, we have a global dir with -+ * all adapters as subdirs. -+ */ -+ if (!i2c_gpio_debug_dir) { -+ i2c_gpio_debug_dir = debugfs_create_dir("i2c-fault-injector", NULL); -+ if (!i2c_gpio_debug_dir) -+ return; -+ } -+ -+ priv->debug_dir = debugfs_create_dir(pdev->name, i2c_gpio_debug_dir); -+ if (!priv->debug_dir) -+ return; -+ -+ debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl); -+ debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda); -+ debugfs_create_file_unsafe("incomplete_address_phase", 0200, priv->debug_dir, -+ priv, &fops_incomplete_addr_phase); -+ debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->debug_dir, -+ priv, &fops_incomplete_write_byte); -+} -+ -+static void i2c_gpio_fault_injector_exit(struct platform_device *pdev) -+{ -+ struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); -+ -+ debugfs_remove_recursive(priv->debug_dir); -+} -+#else -+static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {} -+static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {} -+#endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/ -+ -+static void of_i2c_gpio_get_props(struct device_node *np, -+ struct i2c_gpio_platform_data *pdata) -+{ -+ u32 reg; -+ -+ of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay); -+ -+ if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", ®)) -+ pdata->timeout = msecs_to_jiffies(reg); -+ -+ pdata->sda_is_open_drain = -+ of_property_read_bool(np, "i2c-gpio,sda-open-drain"); -+ pdata->scl_is_open_drain = -+ of_property_read_bool(np, "i2c-gpio,scl-open-drain"); -+ pdata->scl_is_output_only = -+ of_property_read_bool(np, "i2c-gpio,scl-output-only"); -+} -+ -+static struct gpio_desc *i2c_gpio_get_desc(struct device *dev, -+ const char *con_id, -+ unsigned int index, -+ enum gpiod_flags gflags) -+{ -+ struct gpio_desc *retdesc; -+ int ret; -+ -+ retdesc = devm_gpiod_get(dev, con_id, gflags); -+ if (!IS_ERR(retdesc)) { -+ dev_dbg(dev, "got GPIO from name %s\n", con_id); -+ return retdesc; -+ } -+ -+ retdesc = devm_gpiod_get_index(dev, NULL, index, gflags); -+ if (!IS_ERR(retdesc)) { -+ dev_dbg(dev, "got GPIO from index %u\n", index); -+ return retdesc; -+ } -+ -+ ret = PTR_ERR(retdesc); -+ -+ /* FIXME: hack in the old code, is this really necessary? */ -+ if (ret == -EINVAL) -+ retdesc = ERR_PTR(-EPROBE_DEFER); -+ -+ /* This happens if the GPIO driver is not yet probed, let's defer */ -+ if (ret == -ENOENT) -+ retdesc = ERR_PTR(-EPROBE_DEFER); -+ -+ if (PTR_ERR(retdesc) != -EPROBE_DEFER) -+ dev_err(dev, "error trying to get descriptor: %d\n", ret); -+ -+ return retdesc; -+} -+ -+static int i2c_gpio_probe(struct platform_device *pdev) -+{ -+ struct i2c_gpio_private_data *priv; -+ struct i2c_gpio_platform_data *pdata; -+ struct i2c_algo_bit_data *bit_data; -+ struct i2c_adapter *adap; -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ enum gpiod_flags gflags; -+ int ret; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ adap = &priv->adap; -+ bit_data = &priv->bit_data; -+ pdata = &priv->pdata; -+ -+ if (np) { -+ of_i2c_gpio_get_props(np, pdata); -+ } else { -+ /* -+ * If all platform data settings are zero it is OK -+ * to not provide any platform data from the board. -+ */ -+ if (dev_get_platdata(dev)) -+ memcpy(pdata, dev_get_platdata(dev), sizeof(*pdata)); -+ } -+ -+ /* -+ * First get the GPIO pins; if it fails, we'll defer the probe. -+ * If the SDA line is marked from platform data or device tree as -+ * "open drain" it means something outside of our control is making -+ * this line being handled as open drain, and we should just handle -+ * it as any other output. Else we enforce open drain as this is -+ * required for an I2C bus. -+ */ -+ if (pdata->sda_is_open_drain) -+ gflags = GPIOD_OUT_HIGH; -+ else -+ gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; -+ priv->sda = i2c_gpio_get_desc(dev, "sda", 0, gflags); -+ if (IS_ERR(priv->sda)) -+ return PTR_ERR(priv->sda); -+ -+ /* -+ * If the SCL line is marked from platform data or device tree as -+ * "open drain" it means something outside of our control is making -+ * this line being handled as open drain, and we should just handle -+ * it as any other output. Else we enforce open drain as this is -+ * required for an I2C bus. -+ */ -+ if (pdata->scl_is_open_drain) -+ gflags = GPIOD_OUT_HIGH; -+ else -+ gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; -+ priv->scl = i2c_gpio_get_desc(dev, "scl", 1, gflags); -+ if (IS_ERR(priv->scl)) -+ return PTR_ERR(priv->scl); -+ -+ if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl)) -+ dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing"); -+ -+ bit_data->setsda = i2c_gpio_setsda_val; -+ bit_data->setscl = i2c_gpio_setscl_val; -+ -+ if (!pdata->scl_is_output_only) -+ bit_data->getscl = i2c_gpio_getscl; -+ bit_data->getsda = i2c_gpio_getsda; -+ -+ if (pdata->udelay) -+ bit_data->udelay = pdata->udelay; -+ else if (pdata->scl_is_output_only) -+ bit_data->udelay = 50; /* 10 kHz */ -+ else -+ bit_data->udelay = 5; /* 100 kHz */ -+ -+ if (pdata->timeout) -+ bit_data->timeout = pdata->timeout; -+ else -+ bit_data->timeout = HZ / 10; /* 100 ms */ -+ -+ bit_data->data = priv; -+ -+ adap->owner = THIS_MODULE; -+ if (np) -+ strlcpy(adap->name, dev_name(dev), sizeof(adap->name)); -+ else -+ snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); -+ -+ adap->algo_data = bit_data; -+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; -+ adap->dev.parent = dev; -+ adap->dev.of_node = np; -+ -+ adap->nr = pdev->id; -+ ret = wb_i2c_bit_add_numbered_bus(adap); -+ if (ret) -+ return ret; -+ -+ platform_set_drvdata(pdev, priv); -+ -+ /* -+ * FIXME: using global GPIO numbers is not helpful. If/when we -+ * get accessors to get the actual name of the GPIO line, -+ * from the descriptor, then provide that instead. -+ */ -+ dev_info(dev, "using lines %u (SDA) and %u (SCL%s)\n", -+ desc_to_gpio(priv->sda), desc_to_gpio(priv->scl), -+ pdata->scl_is_output_only -+ ? ", no clock stretching" : ""); -+ -+ i2c_gpio_fault_injector_init(pdev); -+ -+ return 0; -+} -+ -+static int i2c_gpio_remove(struct platform_device *pdev) -+{ -+ struct i2c_gpio_private_data *priv; -+ struct i2c_adapter *adap; -+ -+ i2c_gpio_fault_injector_exit(pdev); -+ -+ priv = platform_get_drvdata(pdev); -+ adap = &priv->adap; -+ -+ i2c_del_adapter(adap); -+ -+ return 0; -+} -+ -+#if defined(CONFIG_OF) -+static const struct of_device_id i2c_gpio_dt_ids[] = { -+ { .compatible = "wb-i2c-gpio", }, -+ { /* sentinel */ } -+}; -+ -+MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids); -+#endif -+ -+static struct platform_driver i2c_gpio_driver = { -+ .driver = { -+ .name = "wb-i2c-gpio", -+ .of_match_table = of_match_ptr(i2c_gpio_dt_ids), -+ }, -+ .probe = i2c_gpio_probe, -+ .remove = i2c_gpio_remove, -+}; -+ -+static int __init i2c_gpio_init(void) -+{ -+ int ret; -+ -+ ret = platform_driver_register(&i2c_gpio_driver); -+ if (ret) -+ printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret); -+ -+ return ret; -+} -+subsys_initcall(i2c_gpio_init); -+ -+static void __exit i2c_gpio_exit(void) -+{ -+ platform_driver_unregister(&i2c_gpio_driver); -+} -+module_exit(i2c_gpio_exit); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:i2c-gpio"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio_device.c -new file mode 100644 -index 000000000..1e1d815ee ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_gpio_device.c -@@ -0,0 +1,133 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define I2C_GPIO_DEV_NAME_LEN (16) -+static char i2c_gpio_dev_name[I2C_GPIO_DEV_NAME_LEN] = {0}; -+ -+static int gpio_sda = 17; -+module_param(gpio_sda, int, S_IRUGO | S_IWUSR); -+ -+static int gpio_scl = 1; -+module_param(gpio_scl, int, S_IRUGO | S_IWUSR); -+ -+static int gpio_udelay = 2; -+module_param(gpio_udelay, int, S_IRUGO | S_IWUSR); -+ -+static int bus_num = -1; -+module_param(bus_num, int, S_IRUGO | S_IWUSR); -+ -+static char *gpio_chip_name = NULL; -+module_param(gpio_chip_name, charp, 0644); -+MODULE_PARM_DESC(str_var, "A string variable for GPIO controller"); -+ -+static int g_wb_i2c_gpio_device_debug = 0; -+static int g_wb_i2c_gpio_device_error = 0; -+ -+module_param(g_wb_i2c_gpio_device_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_i2c_gpio_device_error, int, S_IRUGO | S_IWUSR); -+ -+#define WB_I2C_GPIO_DEVICE_VERBOSE(fmt, args...) do { \ -+ if (g_wb_i2c_gpio_device_debug) { \ -+ printk(KERN_INFO "[WB_I2C_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_I2C_GPIO_DEVICE_ERROR(fmt, args...) do { \ -+ if (g_wb_i2c_gpio_device_error) { \ -+ printk(KERN_ERR "[WB_I2C_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+/****************** i2c adapter with gpio ***********************/ -+static struct i2c_gpio_platform_data i2c_pdata = { -+ .udelay = 2, -+ .scl_is_output_only = 0, -+ .sda_is_open_drain = 0, -+ .scl_is_open_drain = 0, -+}; -+ -+static void i2c_gpio_release(struct device *dev) -+{ -+ return; -+} -+ -+static struct platform_device wb_i2c_gpio_device = { -+ .name = "wb-i2c-gpio", -+ .id = -1, -+ .num_resources = 0, -+ .resource = NULL, -+ .dev = { -+ .platform_data = &i2c_pdata, -+ .release = i2c_gpio_release, -+ }, -+}; -+ -+/* -+ * i2c -+ */ -+static struct gpiod_lookup_table wb_i2c_gpio_table = { -+ .dev_id = "wb-i2c-gpio", -+ .table = { -+ GPIO_LOOKUP("wb_gpio_d1500", 17, "sda", -+ GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), -+ GPIO_LOOKUP("wb_gpio_d1500", 1, "scl", -+ GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), -+ { }, -+ }, -+}; -+ -+static int __init wb_i2c_gpio_device_init(void) -+{ -+ int err; -+ -+ WB_I2C_GPIO_DEVICE_VERBOSE("wb_i2c_gpio_device_init enter!\n"); -+ wb_i2c_gpio_table.table[0].chip_hwnum = gpio_sda; -+ wb_i2c_gpio_table.table[1].chip_hwnum = gpio_scl; -+ i2c_pdata.udelay = gpio_udelay; -+ -+ if (gpio_chip_name) { -+ wb_i2c_gpio_table.table[0].key = gpio_chip_name; -+ wb_i2c_gpio_table.table[1].key = gpio_chip_name; -+ } -+ -+ if (bus_num >= 0) { -+ wb_i2c_gpio_device.id = bus_num; -+ snprintf(i2c_gpio_dev_name, I2C_GPIO_DEV_NAME_LEN, "wb-i2c-gpio.%d", bus_num); -+ wb_i2c_gpio_table.dev_id = i2c_gpio_dev_name; -+ } -+ -+ gpiod_add_lookup_table(&wb_i2c_gpio_table); -+ -+ err = platform_device_register(&wb_i2c_gpio_device); -+ if (err < 0) { -+ printk(KERN_ERR "register i2c gpio device fail(%d). \n", err); -+ gpiod_remove_lookup_table(&wb_i2c_gpio_table); -+ return -1; -+ } -+ return 0; -+} -+ -+static void __exit wb_i2c_gpio_device_exit(void) -+{ -+ WB_I2C_GPIO_DEVICE_VERBOSE("wb_i2c_gpio_device_exit enter!\n"); -+ platform_device_unregister(&wb_i2c_gpio_device); -+ gpiod_remove_lookup_table(&wb_i2c_gpio_table); -+} -+ -+module_init(wb_i2c_gpio_device_init); -+module_exit(wb_i2c_gpio_device_exit); -+MODULE_DESCRIPTION("I2C GPIO Devices"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_i801.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_i801.c -new file mode 100644 -index 000000000..a733c1154 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_i801.c -@@ -0,0 +1,2114 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ Copyright (c) 1998 - 2002 Frodo Looijaard , -+ Philip Edelbrock , and Mark D. Studebaker -+ -+ Copyright (C) 2007 - 2014 Jean Delvare -+ Copyright (C) 2010 Intel Corporation, -+ David Woodhouse -+ -+*/ -+ -+/* -+ * Supports the following Intel I/O Controller Hubs (ICH): -+ * -+ * I/O Block I2C -+ * region SMBus Block proc. block -+ * Chip name PCI ID size PEC buffer call read -+ * --------------------------------------------------------------------------- -+ * 82801AA (ICH) 0x2413 16 no no no no -+ * 82801AB (ICH0) 0x2423 16 no no no no -+ * 82801BA (ICH2) 0x2443 16 no no no no -+ * 82801CA (ICH3) 0x2483 32 soft no no no -+ * 82801DB (ICH4) 0x24c3 32 hard yes no no -+ * 82801E (ICH5) 0x24d3 32 hard yes yes yes -+ * 6300ESB 0x25a4 32 hard yes yes yes -+ * 82801F (ICH6) 0x266a 32 hard yes yes yes -+ * 6310ESB/6320ESB 0x269b 32 hard yes yes yes -+ * 82801G (ICH7) 0x27da 32 hard yes yes yes -+ * 82801H (ICH8) 0x283e 32 hard yes yes yes -+ * 82801I (ICH9) 0x2930 32 hard yes yes yes -+ * EP80579 (Tolapai) 0x5032 32 hard yes yes yes -+ * ICH10 0x3a30 32 hard yes yes yes -+ * ICH10 0x3a60 32 hard yes yes yes -+ * 5/3400 Series (PCH) 0x3b30 32 hard yes yes yes -+ * 6 Series (PCH) 0x1c22 32 hard yes yes yes -+ * Patsburg (PCH) 0x1d22 32 hard yes yes yes -+ * Patsburg (PCH) IDF 0x1d70 32 hard yes yes yes -+ * Patsburg (PCH) IDF 0x1d71 32 hard yes yes yes -+ * Patsburg (PCH) IDF 0x1d72 32 hard yes yes yes -+ * DH89xxCC (PCH) 0x2330 32 hard yes yes yes -+ * Panther Point (PCH) 0x1e22 32 hard yes yes yes -+ * Lynx Point (PCH) 0x8c22 32 hard yes yes yes -+ * Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes -+ * Avoton (SOC) 0x1f3c 32 hard yes yes yes -+ * Wellsburg (PCH) 0x8d22 32 hard yes yes yes -+ * Wellsburg (PCH) MS 0x8d7d 32 hard yes yes yes -+ * Wellsburg (PCH) MS 0x8d7e 32 hard yes yes yes -+ * Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes -+ * Coleto Creek (PCH) 0x23b0 32 hard yes yes yes -+ * Wildcat Point (PCH) 0x8ca2 32 hard yes yes yes -+ * Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes -+ * BayTrail (SOC) 0x0f12 32 hard yes yes yes -+ * Braswell (SOC) 0x2292 32 hard yes yes yes -+ * Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes -+ * Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes -+ * DNV (SOC) 0x19df 32 hard yes yes yes -+ * Emmitsburg (PCH) 0x1bc9 32 hard yes yes yes -+ * Broxton (SOC) 0x5ad4 32 hard yes yes yes -+ * Lewisburg (PCH) 0xa1a3 32 hard yes yes yes -+ * Lewisburg Supersku (PCH) 0xa223 32 hard yes yes yes -+ * Kaby Lake PCH-H (PCH) 0xa2a3 32 hard yes yes yes -+ * Gemini Lake (SOC) 0x31d4 32 hard yes yes yes -+ * Cannon Lake-H (PCH) 0xa323 32 hard yes yes yes -+ * Cannon Lake-LP (PCH) 0x9da3 32 hard yes yes yes -+ * Cedar Fork (PCH) 0x18df 32 hard yes yes yes -+ * Ice Lake-LP (PCH) 0x34a3 32 hard yes yes yes -+ * Comet Lake (PCH) 0x02a3 32 hard yes yes yes -+ * Comet Lake-H (PCH) 0x06a3 32 hard yes yes yes -+ * Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes -+ * Tiger Lake-LP (PCH) 0xa0a3 32 hard yes yes yes -+ * Tiger Lake-H (PCH) 0x43a3 32 hard yes yes yes -+ * Jasper Lake (SOC) 0x4da3 32 hard yes yes yes -+ * Comet Lake-V (PCH) 0xa3a3 32 hard yes yes yes -+ * Alder Lake-S (PCH) 0x7aa3 32 hard yes yes yes -+ * -+ * Features supported by this driver: -+ * Software PEC no -+ * Hardware PEC yes -+ * Block buffer yes -+ * Block process call transaction yes -+ * I2C block read transaction yes (doesn't use the block buffer) -+ * Slave mode no -+ * SMBus Host Notify yes -+ * Interrupt processing yes -+ * -+ * See the file Documentation/i2c/busses/i2c-i801.rst for details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI -+#include -+#include -+#endif -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+ -+/* I801 SMBus address offsets */ -+#define SMBHSTSTS(p) (0 + (p)->smba) -+#define SMBHSTCNT(p) (2 + (p)->smba) -+#define SMBHSTCMD(p) (3 + (p)->smba) -+#define SMBHSTADD(p) (4 + (p)->smba) -+#define SMBHSTDAT0(p) (5 + (p)->smba) -+#define SMBHSTDAT1(p) (6 + (p)->smba) -+#define SMBBLKDAT(p) (7 + (p)->smba) -+#define SMBPEC(p) (8 + (p)->smba) /* ICH3 and later */ -+#define SMBAUXSTS(p) (12 + (p)->smba) /* ICH4 and later */ -+#define SMBAUXCTL(p) (13 + (p)->smba) /* ICH4 and later */ -+#define SMBSLVSTS(p) (16 + (p)->smba) /* ICH3 and later */ -+#define SMBSLVCMD(p) (17 + (p)->smba) /* ICH3 and later */ -+#define SMBNTFDADD(p) (20 + (p)->smba) /* ICH3 and later */ -+#define SMBPINCTL(p) (15 + (p)->smba) /* SMBus Pin Control Register */ -+ -+/* PCI Address Constants */ -+#define SMBBAR 4 -+#define SMBPCICTL 0x004 -+#define SMBPCISTS 0x006 -+#define SMBHSTCFG 0x040 -+#define TCOBASE 0x050 -+#define TCOCTL 0x054 -+ -+#define SBREG_BAR 0x10 -+#define SBREG_SMBCTRL 0xc6000c -+#define SBREG_SMBCTRL_DNV 0xcf000c -+ -+/* Host status bits for SMBPCISTS */ -+#define SMBPCISTS_INTS BIT(3) -+ -+/* Control bits for SMBPCICTL */ -+#define SMBPCICTL_INTDIS BIT(10) -+ -+/* Host configuration bits for SMBHSTCFG */ -+#define SMBHSTCFG_HST_EN BIT(0) -+#define SMBHSTCFG_SMB_SMI_EN BIT(1) -+#define SMBHSTCFG_I2C_EN BIT(2) -+#define SMBHSTCFG_SSRESET BIT(3) -+#define SSRESET_SLEEP_TIME 1 /* 1us */ -+#define SSRESET_RETRY_TIME (1000 / SSRESET_SLEEP_TIME) -+ -+/* Pin status for SMBPINCTL */ -+#define SMBPINCTL_CLK_STS 1 /* bit0 SMBCLK_CUR_STS*/ -+#define SMBPINCTL_SDA_STS 2 /* bit1 SMBDATA_CUR_STS*/ -+#define SMBPINCTL_CLK_CTL 4 /* bit2 SMBCLK_CTL */ -+ -+#define SMBHSTCFG_SPD_WD BIT(4) -+ -+/* TCO configuration bits for TCOCTL */ -+#define TCOCTL_EN BIT(8) -+ -+/* Auxiliary status register bits, ICH4+ only */ -+#define SMBAUXSTS_CRCE BIT(0) -+#define SMBAUXSTS_STCO BIT(1) -+ -+/* Auxiliary control register bits, ICH4+ only */ -+#define SMBAUXCTL_CRC BIT(0) -+#define SMBAUXCTL_E32B BIT(1) -+ -+/* Other settings */ -+#define MAX_RETRIES 400 -+ -+/* I801 command constants */ -+#define I801_QUICK 0x00 -+#define I801_BYTE 0x04 -+#define I801_BYTE_DATA 0x08 -+#define I801_WORD_DATA 0x0C -+#define I801_PROC_CALL 0x10 /* unimplemented */ -+#define I801_BLOCK_DATA 0x14 -+#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ -+#define I801_BLOCK_PROC_CALL 0x1C -+ -+/* I801 Host Control register bits */ -+#define SMBHSTCNT_INTREN BIT(0) -+#define SMBHSTCNT_KILL BIT(1) -+#define SMBHSTCNT_LAST_BYTE BIT(5) -+#define SMBHSTCNT_START BIT(6) -+#define SMBHSTCNT_PEC_EN BIT(7) /* ICH3 and later */ -+ -+/* I801 Hosts Status register bits */ -+#define SMBHSTSTS_BYTE_DONE BIT(7) -+#define SMBHSTSTS_INUSE_STS BIT(6) -+#define SMBHSTSTS_SMBALERT_STS BIT(5) -+#define SMBHSTSTS_FAILED BIT(4) -+#define SMBHSTSTS_BUS_ERR BIT(3) -+#define SMBHSTSTS_DEV_ERR BIT(2) -+#define SMBHSTSTS_INTR BIT(1) -+#define SMBHSTSTS_HOST_BUSY BIT(0) -+ -+/* Host Notify Status register bits */ -+#define SMBSLVSTS_HST_NTFY_STS BIT(0) -+ -+/* Host Notify Command register bits */ -+#define SMBSLVCMD_HST_NTFY_INTREN BIT(0) -+ -+#define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \ -+ SMBHSTSTS_DEV_ERR) -+ -+#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR | \ -+ STATUS_ERROR_FLAGS) -+ -+/* Older devices have their ID defined in */ -+#define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS 0x02a3 -+#define PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS 0x06a3 -+#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12 -+#define PCI_DEVICE_ID_INTEL_CDF_SMBUS 0x18df -+#define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df -+#define PCI_DEVICE_ID_INTEL_EBG_SMBUS 0x1bc9 -+#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 -+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 -+/* Patsburg also has three 'Integrated Device Function' SMBus controllers */ -+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70 -+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71 -+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72 -+#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22 -+#define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS 0x1f3c -+#define PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS 0x2292 -+#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 -+#define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0 -+#define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4 -+#define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS 0x34a3 -+#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 -+#define PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS 0x43a3 -+#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23 -+#define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS 0x4da3 -+#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4 -+#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS 0x7aa3 -+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 -+#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS 0x8ca2 -+#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22 -+#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0 0x8d7d -+#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1 0x8d7e -+#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2 0x8d7f -+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22 -+#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2 -+#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23 -+#define PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS 0x9da3 -+#define PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS 0xa0a3 -+#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123 -+#define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS 0xa1a3 -+#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223 -+#define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS 0xa2a3 -+#define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323 -+#define PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS 0xa3a3 -+ -+struct i801_mux_config { -+ char *gpio_chip; -+ unsigned values[3]; -+ int n_values; -+ unsigned classes[3]; -+ unsigned gpios[2]; /* Relative to gpio_chip->base */ -+ int n_gpios; -+}; -+ -+struct i801_priv { -+ struct i2c_adapter adapter; -+ unsigned long smba; -+ unsigned char original_hstcfg; -+ unsigned char original_slvcmd; -+ struct pci_dev *pci_dev; -+ unsigned int features; -+ -+ /* isr processing */ -+ wait_queue_head_t waitq; -+ u8 status; -+ -+ /* Command state used by isr for byte-by-byte block transactions */ -+ u8 cmd; -+ bool is_read; -+ int count; -+ int len; -+ u8 *data; -+ -+#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI -+ const struct i801_mux_config *mux_drvdata; -+ struct platform_device *mux_pdev; -+ struct gpiod_lookup_table *lookup; -+#endif -+ struct platform_device *tco_pdev; -+ -+ /* -+ * If set to true the host controller registers are reserved for -+ * ACPI AML use. Protected by acpi_lock. -+ */ -+ bool acpi_reserved; -+ struct mutex acpi_lock; -+}; -+ -+#define FEATURE_SMBUS_PEC BIT(0) -+#define FEATURE_BLOCK_BUFFER BIT(1) -+#define FEATURE_BLOCK_PROC BIT(2) -+#define FEATURE_I2C_BLOCK_READ BIT(3) -+#define FEATURE_IRQ BIT(4) -+#define FEATURE_HOST_NOTIFY BIT(5) -+/* Not really a feature, but it's convenient to handle it as such */ -+#define FEATURE_IDF BIT(15) -+#define FEATURE_TCO_SPT BIT(16) -+#define FEATURE_TCO_CNL BIT(17) -+ -+static const char *i801_feature_names[] = { -+ "SMBus PEC", -+ "Block buffer", -+ "Block process call", -+ "I2C block read", -+ "Interrupt", -+ "SMBus Host Notify", -+}; -+ -+static unsigned int disable_features; -+module_param(disable_features, uint, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n" -+ "\t\t 0x01 disable SMBus PEC\n" -+ "\t\t 0x02 disable the block buffer\n" -+ "\t\t 0x08 disable the I2C block read functionality\n" -+ "\t\t 0x10 don't use interrupts\n" -+ "\t\t 0x20 disable SMBus Host Notify "); -+ -+static void i801_setscl(struct i801_priv *priv, unsigned int level) -+{ -+ int pin_status; -+ pin_status = inb_p(SMBPINCTL(priv)); -+ if (level == 0) { -+ pin_status &= (~SMBPINCTL_CLK_CTL); -+ } -+ else { -+ pin_status |= SMBPINCTL_CLK_CTL; -+ } -+ outb_p(pin_status, SMBPINCTL(priv)); -+ return; -+} -+ -+static void i801_i2c_unblock(struct i801_priv *priv) -+{ -+ int i; -+ for (i = 0; i < 10; i++) { -+ i801_setscl(priv, 0); -+ udelay(5); -+ i801_setscl(priv, 1); -+ udelay(5); -+ } -+ return; -+} -+ -+static int i801_check_i2c_unblock(struct i801_priv *priv) -+{ -+ int pin_status; -+ -+ pin_status = inb_p(SMBPINCTL(priv)); -+ if ( (!(pin_status & SMBPINCTL_SDA_STS) ) && (pin_status & SMBPINCTL_CLK_STS) ) { -+ dev_dbg(&priv->pci_dev->dev, "SDA is low, send 9 clock to device!\n"); -+ i801_i2c_unblock(priv); -+ } -+ return 0; -+} -+ -+static void i801_do_reset(struct i801_priv *priv) -+{ -+ unsigned char tmp; -+ unsigned int retry_count = 0; -+ -+ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &tmp); -+ tmp |= SMBHSTCFG_SSRESET; -+ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, tmp); -+ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &tmp); -+ -+ while( ((tmp & SMBHSTCFG_SSRESET) != 0) && (retry_count < SSRESET_RETRY_TIME)) { -+ usleep_range(SSRESET_SLEEP_TIME, SSRESET_SLEEP_TIME + 1); -+ retry_count++; -+ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &tmp); -+ } -+ -+ return ; -+} -+ -+static int i801_check_i2c_scl(struct i801_priv *priv) -+{ -+ int pin_status; -+ -+ pin_status = inb_p(SMBPINCTL(priv)); -+ if ( (pin_status & SMBPINCTL_SDA_STS) && (pin_status & SMBPINCTL_CLK_STS) ) { -+ return 0; -+ } -+ -+ dev_dbg(&priv->pci_dev->dev, "SDA or SCL is low, begin to reset SMBus adapter, pin_status: 0x%x\n",pin_status); -+ i801_do_reset(priv); -+ pin_status = inb_p(SMBPINCTL(priv)); -+ if ( (pin_status & SMBPINCTL_SDA_STS) && (pin_status & SMBPINCTL_CLK_STS) ) { -+ return 0; -+ } -+ dev_warn(&priv->pci_dev->dev, "SDA or SCL is low.pin_status:0x%x\n",pin_status); -+ return -1; -+} -+ -+/* Make sure the SMBus host is ready to start transmitting. -+ Return 0 if it is, -EBUSY if it is not. */ -+static int i801_check_pre(struct i801_priv *priv) -+{ -+ int status; -+ -+ i801_check_i2c_unblock(priv); -+ -+ if (i801_check_i2c_scl(priv)) { -+ return -EIO; -+ } -+ -+ status = inb_p(SMBHSTSTS(priv)); -+ if (status & SMBHSTSTS_HOST_BUSY) { -+ dev_dbg(&priv->pci_dev->dev, "SMBus is busy, begin to reset SMBus adapter!\n"); -+ -+ i801_do_reset(priv); -+ -+ status = inb_p(SMBHSTSTS(priv)); -+ if (status & SMBHSTSTS_HOST_BUSY) { -+ dev_err(&priv->pci_dev->dev, "SMBus is busy, can't use it!\n"); -+ return -EBUSY; -+ } -+ } -+ -+ status &= STATUS_FLAGS; -+ if (status) { -+ dev_dbg(&priv->pci_dev->dev, "Clearing status flags (%02x)\n", -+ status); -+ outb_p(status, SMBHSTSTS(priv)); -+ status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS; -+ if (status) { -+ dev_err(&priv->pci_dev->dev, -+ "Failed clearing status flags (%02x)\n", -+ status); -+ return -EBUSY; -+ } -+ } -+ -+ /* -+ * Clear CRC status if needed. -+ * During normal operation, i801_check_post() takes care -+ * of it after every operation. We do it here only in case -+ * the hardware was already in this state when the driver -+ * started. -+ */ -+ if (priv->features & FEATURE_SMBUS_PEC) { -+ status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; -+ if (status) { -+ dev_dbg(&priv->pci_dev->dev, -+ "Clearing aux status flags (%02x)\n", status); -+ outb_p(status, SMBAUXSTS(priv)); -+ status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; -+ if (status) { -+ dev_err(&priv->pci_dev->dev, -+ "Failed clearing aux status flags (%02x)\n", -+ status); -+ return -EBUSY; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+/* -+ * Convert the status register to an error code, and clear it. -+ * Note that status only contains the bits we want to clear, not the -+ * actual register value. -+ */ -+static int i801_check_post(struct i801_priv *priv, int status) -+{ -+ int result = 0; -+ -+ /* -+ * If the SMBus is still busy, we give up -+ * Note: This timeout condition only happens when using polling -+ * transactions. For interrupt operation, NAK/timeout is indicated by -+ * DEV_ERR. -+ */ -+ if (unlikely(status < 0)) { -+ dev_err(&priv->pci_dev->dev, "Transaction timeout\n"); -+ /* try to stop the current command */ -+ dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n"); -+ outb_p(SMBHSTCNT_KILL, SMBHSTCNT(priv)); -+ usleep_range(1000, 2000); -+ outb_p(0, SMBHSTCNT(priv)); -+ -+ /* Check if it worked */ -+ status = inb_p(SMBHSTSTS(priv)); -+ if ((status & SMBHSTSTS_HOST_BUSY) || -+ !(status & SMBHSTSTS_FAILED)) -+ dev_err(&priv->pci_dev->dev, -+ "Failed terminating the transaction\n"); -+ outb_p(STATUS_FLAGS, SMBHSTSTS(priv)); -+ return -ETIMEDOUT; -+ } -+ -+ if (status & SMBHSTSTS_FAILED) { -+ result = -EIO; -+ dev_err(&priv->pci_dev->dev, "Transaction failed\n"); -+ } -+ if (status & SMBHSTSTS_DEV_ERR) { -+ /* -+ * This may be a PEC error, check and clear it. -+ * -+ * AUXSTS is handled differently from HSTSTS. -+ * For HSTSTS, i801_isr() or i801_wait_intr() -+ * has already cleared the error bits in hardware, -+ * and we are passed a copy of the original value -+ * in "status". -+ * For AUXSTS, the hardware register is left -+ * for us to handle here. -+ * This is asymmetric, slightly iffy, but safe, -+ * since all this code is serialized and the CRCE -+ * bit is harmless as long as it's cleared before -+ * the next operation. -+ */ -+ if ((priv->features & FEATURE_SMBUS_PEC) && -+ (inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE)) { -+ outb_p(SMBAUXSTS_CRCE, SMBAUXSTS(priv)); -+ result = -EBADMSG; -+ dev_dbg(&priv->pci_dev->dev, "PEC error\n"); -+ } else { -+ result = -ENXIO; -+ dev_dbg(&priv->pci_dev->dev, "No response\n"); -+ } -+ } -+ if (status & SMBHSTSTS_BUS_ERR) { -+ result = -EAGAIN; -+ dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n"); -+ } -+ -+ /* Clear status flags except BYTE_DONE, to be cleared by caller */ -+ outb_p(status, SMBHSTSTS(priv)); -+ -+ return result; -+} -+ -+/* Wait for BUSY being cleared and either INTR or an error flag being set */ -+static int i801_wait_intr(struct i801_priv *priv) -+{ -+ int timeout = 0; -+ int status; -+ -+ /* We will always wait for a fraction of a second! */ -+ do { -+ usleep_range(250, 500); -+ status = inb_p(SMBHSTSTS(priv)); -+ } while (((status & SMBHSTSTS_HOST_BUSY) || -+ !(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR))) && -+ (timeout++ < MAX_RETRIES)); -+ -+ if (timeout > MAX_RETRIES) { -+ dev_dbg(&priv->pci_dev->dev, "INTR Timeout!\n"); -+ return -ETIMEDOUT; -+ } -+ return status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR); -+} -+ -+/* Wait for either BYTE_DONE or an error flag being set */ -+static int i801_wait_byte_done(struct i801_priv *priv) -+{ -+ int timeout = 0; -+ int status; -+ -+ /* We will always wait for a fraction of a second! */ -+ do { -+ usleep_range(250, 500); -+ status = inb_p(SMBHSTSTS(priv)); -+ } while (!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE)) && -+ (timeout++ < MAX_RETRIES)); -+ -+ if (timeout > MAX_RETRIES) { -+ dev_dbg(&priv->pci_dev->dev, "BYTE_DONE Timeout!\n"); -+ return -ETIMEDOUT; -+ } -+ return status & STATUS_ERROR_FLAGS; -+} -+ -+static int i801_transaction(struct i801_priv *priv, int xact) -+{ -+ int status; -+ int result; -+ const struct i2c_adapter *adap = &priv->adapter; -+ -+ result = i801_check_pre(priv); -+ if (result < 0) -+ return result; -+ -+ if (priv->features & FEATURE_IRQ) { -+ outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START, -+ SMBHSTCNT(priv)); -+ result = wait_event_timeout(priv->waitq, -+ (status = priv->status), -+ adap->timeout); -+ if (!result) { -+ status = -ETIMEDOUT; -+ dev_warn(&priv->pci_dev->dev, -+ "Timeout waiting for interrupt!\n"); -+ } -+ priv->status = 0; -+ return i801_check_post(priv, status); -+ } -+ -+ /* the current contents of SMBHSTCNT can be overwritten, since PEC, -+ * SMBSCMD are passed in xact */ -+ outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv)); -+ -+ status = i801_wait_intr(priv); -+ return i801_check_post(priv, status); -+} -+ -+static int i801_block_transaction_by_block(struct i801_priv *priv, -+ union i2c_smbus_data *data, -+ char read_write, int command, -+ int hwpec) -+{ -+ int i, len; -+ int status; -+ int xact = hwpec ? SMBHSTCNT_PEC_EN : 0; -+ -+ switch (command) { -+ case I2C_SMBUS_BLOCK_PROC_CALL: -+ xact |= I801_BLOCK_PROC_CALL; -+ break; -+ case I2C_SMBUS_BLOCK_DATA: -+ xact |= I801_BLOCK_DATA; -+ break; -+ default: -+ return -EOPNOTSUPP; -+ } -+ -+ inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */ -+ -+ /* Use 32-byte buffer to process this transaction */ -+ if (read_write == I2C_SMBUS_WRITE) { -+ len = data->block[0]; -+ outb_p(len, SMBHSTDAT0(priv)); -+ for (i = 0; i < len; i++) -+ outb_p(data->block[i+1], SMBBLKDAT(priv)); -+ } -+ -+ status = i801_transaction(priv, xact); -+ if (status) -+ return status; -+ -+ if (read_write == I2C_SMBUS_READ || -+ command == I2C_SMBUS_BLOCK_PROC_CALL) { -+ len = inb_p(SMBHSTDAT0(priv)); -+ if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) -+ return -EPROTO; -+ -+ data->block[0] = len; -+ for (i = 0; i < len; i++) -+ data->block[i + 1] = inb_p(SMBBLKDAT(priv)); -+ } -+ return 0; -+} -+ -+static void i801_isr_byte_done(struct i801_priv *priv) -+{ -+ if (priv->is_read) { -+ /* For SMBus block reads, length is received with first byte */ -+ if (((priv->cmd & 0x1c) == I801_BLOCK_DATA) && -+ (priv->count == 0)) { -+ priv->len = inb_p(SMBHSTDAT0(priv)); -+ if (priv->len < 1 || priv->len > I2C_SMBUS_BLOCK_MAX) { -+ dev_err(&priv->pci_dev->dev, -+ "Illegal SMBus block read size %d\n", -+ priv->len); -+ /* FIXME: Recover */ -+ priv->len = I2C_SMBUS_BLOCK_MAX; -+ } else { -+ dev_dbg(&priv->pci_dev->dev, -+ "SMBus block read size is %d\n", -+ priv->len); -+ } -+ priv->data[-1] = priv->len; -+ } -+ -+ /* Read next byte */ -+ if (priv->count < priv->len) -+ priv->data[priv->count++] = inb(SMBBLKDAT(priv)); -+ else -+ dev_dbg(&priv->pci_dev->dev, -+ "Discarding extra byte on block read\n"); -+ -+ /* Set LAST_BYTE for last byte of read transaction */ -+ if (priv->count == priv->len - 1) -+ outb_p(priv->cmd | SMBHSTCNT_LAST_BYTE, -+ SMBHSTCNT(priv)); -+ } else if (priv->count < priv->len - 1) { -+ /* Write next byte, except for IRQ after last byte */ -+ outb_p(priv->data[++priv->count], SMBBLKDAT(priv)); -+ } -+ -+ /* Clear BYTE_DONE to continue with next byte */ -+ outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); -+} -+ -+static irqreturn_t i801_host_notify_isr(struct i801_priv *priv) -+{ -+ unsigned short addr; -+ -+ addr = inb_p(SMBNTFDADD(priv)) >> 1; -+ -+ /* -+ * With the tested platforms, reading SMBNTFDDAT (22 + (p)->smba) -+ * always returns 0. Our current implementation doesn't provide -+ * data, so we just ignore it. -+ */ -+ i2c_handle_smbus_host_notify(&priv->adapter, addr); -+ -+ /* clear Host Notify bit and return */ -+ outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); -+ return IRQ_HANDLED; -+} -+ -+/* -+ * There are three kinds of interrupts: -+ * -+ * 1) i801 signals transaction completion with one of these interrupts: -+ * INTR - Success -+ * DEV_ERR - Invalid command, NAK or communication timeout -+ * BUS_ERR - SMI# transaction collision -+ * FAILED - transaction was canceled due to a KILL request -+ * When any of these occur, update ->status and wake up the waitq. -+ * ->status must be cleared before kicking off the next transaction. -+ * -+ * 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt -+ * occurs for each byte of a byte-by-byte to prepare the next byte. -+ * -+ * 3) Host Notify interrupts -+ */ -+static irqreturn_t i801_isr(int irq, void *dev_id) -+{ -+ struct i801_priv *priv = dev_id; -+ u16 pcists; -+ u8 status; -+ -+ /* Confirm this is our interrupt */ -+ pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists); -+ if (!(pcists & SMBPCISTS_INTS)) -+ return IRQ_NONE; -+ -+ if (priv->features & FEATURE_HOST_NOTIFY) { -+ status = inb_p(SMBSLVSTS(priv)); -+ if (status & SMBSLVSTS_HST_NTFY_STS) -+ return i801_host_notify_isr(priv); -+ } -+ -+ status = inb_p(SMBHSTSTS(priv)); -+ if (status & SMBHSTSTS_BYTE_DONE) -+ i801_isr_byte_done(priv); -+ -+ /* -+ * Clear irq sources and report transaction result. -+ * ->status must be cleared before the next transaction is started. -+ */ -+ status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS; -+ if (status) { -+ outb_p(status, SMBHSTSTS(priv)); -+ priv->status = status; -+ wake_up(&priv->waitq); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * For "byte-by-byte" block transactions: -+ * I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1 -+ * I2C read uses cmd=I801_I2C_BLOCK_DATA -+ */ -+static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, -+ union i2c_smbus_data *data, -+ char read_write, int command, -+ int hwpec) -+{ -+ int i, len; -+ int smbcmd; -+ int status; -+ int result; -+ const struct i2c_adapter *adap = &priv->adapter; -+ -+ if (command == I2C_SMBUS_BLOCK_PROC_CALL) -+ return -EOPNOTSUPP; -+ -+ result = i801_check_pre(priv); -+ if (result < 0) -+ return result; -+ -+ len = data->block[0]; -+ -+ if (read_write == I2C_SMBUS_WRITE) { -+ outb_p(len, SMBHSTDAT0(priv)); -+ outb_p(data->block[1], SMBBLKDAT(priv)); -+ } -+ -+ if (command == I2C_SMBUS_I2C_BLOCK_DATA && -+ read_write == I2C_SMBUS_READ) -+ smbcmd = I801_I2C_BLOCK_DATA; -+ else -+ smbcmd = I801_BLOCK_DATA; -+ -+ if (priv->features & FEATURE_IRQ) { -+ priv->is_read = (read_write == I2C_SMBUS_READ); -+ if (len == 1 && priv->is_read) -+ smbcmd |= SMBHSTCNT_LAST_BYTE; -+ priv->cmd = smbcmd | SMBHSTCNT_INTREN; -+ priv->len = len; -+ priv->count = 0; -+ priv->data = &data->block[1]; -+ -+ outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv)); -+ result = wait_event_timeout(priv->waitq, -+ (status = priv->status), -+ adap->timeout); -+ if (!result) { -+ status = -ETIMEDOUT; -+ dev_warn(&priv->pci_dev->dev, -+ "Timeout waiting for interrupt!\n"); -+ } -+ priv->status = 0; -+ return i801_check_post(priv, status); -+ } -+ -+ for (i = 1; i <= len; i++) { -+ if (i == len && read_write == I2C_SMBUS_READ) -+ smbcmd |= SMBHSTCNT_LAST_BYTE; -+ outb_p(smbcmd, SMBHSTCNT(priv)); -+ -+ if (i == 1) -+ outb_p(inb(SMBHSTCNT(priv)) | SMBHSTCNT_START, -+ SMBHSTCNT(priv)); -+ -+ status = i801_wait_byte_done(priv); -+ if (status) -+ goto exit; -+ -+ if (i == 1 && read_write == I2C_SMBUS_READ -+ && command != I2C_SMBUS_I2C_BLOCK_DATA) { -+ len = inb_p(SMBHSTDAT0(priv)); -+ if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) { -+ dev_err(&priv->pci_dev->dev, -+ "Illegal SMBus block read size %d\n", -+ len); -+ /* Recover */ -+ while (inb_p(SMBHSTSTS(priv)) & -+ SMBHSTSTS_HOST_BUSY) -+ outb_p(SMBHSTSTS_BYTE_DONE, -+ SMBHSTSTS(priv)); -+ outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv)); -+ return -EPROTO; -+ } -+ data->block[0] = len; -+ } -+ -+ /* Retrieve/store value in SMBBLKDAT */ -+ if (read_write == I2C_SMBUS_READ) -+ data->block[i] = inb_p(SMBBLKDAT(priv)); -+ if (read_write == I2C_SMBUS_WRITE && i+1 <= len) -+ outb_p(data->block[i+1], SMBBLKDAT(priv)); -+ -+ /* signals SMBBLKDAT ready */ -+ outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); -+ } -+ -+ status = i801_wait_intr(priv); -+exit: -+ return i801_check_post(priv, status); -+} -+ -+static int i801_set_block_buffer_mode(struct i801_priv *priv) -+{ -+ outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv)); -+ if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0) -+ return -EIO; -+ return 0; -+} -+ -+/* Block transaction function */ -+static int i801_block_transaction(struct i801_priv *priv, -+ union i2c_smbus_data *data, char read_write, -+ int command, int hwpec) -+{ -+ int result = 0; -+ unsigned char hostc; -+ -+ if (command == I2C_SMBUS_I2C_BLOCK_DATA) { -+ if (read_write == I2C_SMBUS_WRITE) { -+ /* set I2C_EN bit in configuration register */ -+ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc); -+ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, -+ hostc | SMBHSTCFG_I2C_EN); -+ } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) { -+ dev_err(&priv->pci_dev->dev, -+ "I2C block read is unsupported!\n"); -+ return -EOPNOTSUPP; -+ } -+ } -+ -+ if (read_write == I2C_SMBUS_WRITE -+ || command == I2C_SMBUS_I2C_BLOCK_DATA) { -+ if (data->block[0] < 1) -+ data->block[0] = 1; -+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX) -+ data->block[0] = I2C_SMBUS_BLOCK_MAX; -+ } else { -+ data->block[0] = 32; /* max for SMBus block reads */ -+ } -+ -+ /* Experience has shown that the block buffer can only be used for -+ SMBus (not I2C) block transactions, even though the datasheet -+ doesn't mention this limitation. */ -+ if ((priv->features & FEATURE_BLOCK_BUFFER) -+ && command != I2C_SMBUS_I2C_BLOCK_DATA -+ && i801_set_block_buffer_mode(priv) == 0) -+ result = i801_block_transaction_by_block(priv, data, -+ read_write, -+ command, hwpec); -+ else -+ result = i801_block_transaction_byte_by_byte(priv, data, -+ read_write, -+ command, hwpec); -+ -+ if (command == I2C_SMBUS_I2C_BLOCK_DATA -+ && read_write == I2C_SMBUS_WRITE) { -+ /* restore saved configuration register value */ -+ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc); -+ } -+ return result; -+} -+ -+/* Return negative errno on error. */ -+static s32 i801_access(struct i2c_adapter *adap, u16 addr, -+ unsigned short flags, char read_write, u8 command, -+ int size, union i2c_smbus_data *data) -+{ -+ int hwpec; -+ int block = 0; -+ int ret = 0, xact = 0; -+ struct i801_priv *priv = i2c_get_adapdata(adap); -+ -+ mutex_lock(&priv->acpi_lock); -+ if (priv->acpi_reserved) { -+ mutex_unlock(&priv->acpi_lock); -+ return -EBUSY; -+ } -+ -+ pm_runtime_get_sync(&priv->pci_dev->dev); -+ -+ hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) -+ && size != I2C_SMBUS_QUICK -+ && size != I2C_SMBUS_I2C_BLOCK_DATA; -+ -+ switch (size) { -+ case I2C_SMBUS_QUICK: -+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), -+ SMBHSTADD(priv)); -+ xact = I801_QUICK; -+ break; -+ case I2C_SMBUS_BYTE: -+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), -+ SMBHSTADD(priv)); -+ if (read_write == I2C_SMBUS_WRITE) -+ outb_p(command, SMBHSTCMD(priv)); -+ xact = I801_BYTE; -+ break; -+ case I2C_SMBUS_BYTE_DATA: -+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), -+ SMBHSTADD(priv)); -+ outb_p(command, SMBHSTCMD(priv)); -+ if (read_write == I2C_SMBUS_WRITE) -+ outb_p(data->byte, SMBHSTDAT0(priv)); -+ xact = I801_BYTE_DATA; -+ break; -+ case I2C_SMBUS_WORD_DATA: -+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), -+ SMBHSTADD(priv)); -+ outb_p(command, SMBHSTCMD(priv)); -+ if (read_write == I2C_SMBUS_WRITE) { -+ outb_p(data->word & 0xff, SMBHSTDAT0(priv)); -+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv)); -+ } -+ xact = I801_WORD_DATA; -+ break; -+ case I2C_SMBUS_BLOCK_DATA: -+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), -+ SMBHSTADD(priv)); -+ outb_p(command, SMBHSTCMD(priv)); -+ block = 1; -+ break; -+ case I2C_SMBUS_I2C_BLOCK_DATA: -+ /* -+ * NB: page 240 of ICH5 datasheet shows that the R/#W -+ * bit should be cleared here, even when reading. -+ * However if SPD Write Disable is set (Lynx Point and later), -+ * the read will fail if we don't set the R/#W bit. -+ */ -+ outb_p(((addr & 0x7f) << 1) | -+ ((priv->original_hstcfg & SMBHSTCFG_SPD_WD) ? -+ (read_write & 0x01) : 0), -+ SMBHSTADD(priv)); -+ if (read_write == I2C_SMBUS_READ) { -+ /* NB: page 240 of ICH5 datasheet also shows -+ * that DATA1 is the cmd field when reading */ -+ outb_p(command, SMBHSTDAT1(priv)); -+ } else -+ outb_p(command, SMBHSTCMD(priv)); -+ block = 1; -+ break; -+ case I2C_SMBUS_BLOCK_PROC_CALL: -+ /* -+ * Bit 0 of the slave address register always indicate a write -+ * command. -+ */ -+ outb_p((addr & 0x7f) << 1, SMBHSTADD(priv)); -+ outb_p(command, SMBHSTCMD(priv)); -+ block = 1; -+ break; -+ default: -+ dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n", -+ size); -+ ret = -EOPNOTSUPP; -+ goto out; -+ } -+ -+ if (hwpec) /* enable/disable hardware PEC */ -+ outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv)); -+ else -+ outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC), -+ SMBAUXCTL(priv)); -+ -+ if (block) -+ ret = i801_block_transaction(priv, data, read_write, size, -+ hwpec); -+ else -+ ret = i801_transaction(priv, xact); -+ -+ /* Some BIOSes don't like it when PEC is enabled at reboot or resume -+ time, so we forcibly disable it after every transaction. Turn off -+ E32B for the same reason. */ -+ if (hwpec || block) -+ outb_p(inb_p(SMBAUXCTL(priv)) & -+ ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); -+ -+ if (block) -+ goto out; -+ if (ret) -+ goto out; -+ if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) -+ goto out; -+ -+ switch (xact & 0x7f) { -+ case I801_BYTE: /* Result put in SMBHSTDAT0 */ -+ case I801_BYTE_DATA: -+ data->byte = inb_p(SMBHSTDAT0(priv)); -+ break; -+ case I801_WORD_DATA: -+ data->word = inb_p(SMBHSTDAT0(priv)) + -+ (inb_p(SMBHSTDAT1(priv)) << 8); -+ break; -+ } -+ -+out: -+ pm_runtime_mark_last_busy(&priv->pci_dev->dev); -+ pm_runtime_put_autosuspend(&priv->pci_dev->dev); -+ mutex_unlock(&priv->acpi_lock); -+ return ret; -+} -+ -+static u32 i801_func(struct i2c_adapter *adapter) -+{ -+ struct i801_priv *priv = i2c_get_adapdata(adapter); -+ -+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | -+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | -+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | -+ ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | -+ ((priv->features & FEATURE_BLOCK_PROC) ? -+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL : 0) | -+ ((priv->features & FEATURE_I2C_BLOCK_READ) ? -+ I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) | -+ ((priv->features & FEATURE_HOST_NOTIFY) ? -+ I2C_FUNC_SMBUS_HOST_NOTIFY : 0); -+} -+ -+static void i801_enable_host_notify(struct i2c_adapter *adapter) -+{ -+ struct i801_priv *priv = i2c_get_adapdata(adapter); -+ -+ if (!(priv->features & FEATURE_HOST_NOTIFY)) -+ return; -+ -+ if (!(SMBSLVCMD_HST_NTFY_INTREN & priv->original_slvcmd)) -+ outb_p(SMBSLVCMD_HST_NTFY_INTREN | priv->original_slvcmd, -+ SMBSLVCMD(priv)); -+ -+ /* clear Host Notify bit to allow a new notification */ -+ outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); -+} -+ -+static void i801_disable_host_notify(struct i801_priv *priv) -+{ -+ if (!(priv->features & FEATURE_HOST_NOTIFY)) -+ return; -+ -+ outb_p(priv->original_slvcmd, SMBSLVCMD(priv)); -+} -+ -+static const struct i2c_algorithm smbus_algorithm = { -+ .smbus_xfer = i801_access, -+ .functionality = i801_func, -+}; -+ -+static const struct pci_device_id i801_ids[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_3) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_3) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_3) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_4) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_16) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EP80579_1) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EBG_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS) }, -+ { 0, } -+}; -+ -+MODULE_DEVICE_TABLE(pci, i801_ids); -+ -+#if defined CONFIG_X86 && defined CONFIG_DMI -+static unsigned char apanel_addr; -+ -+/* Scan the system ROM for the signature "FJKEYINF" */ -+static __init const void __iomem *bios_signature(const void __iomem *bios) -+{ -+ ssize_t offset; -+ const unsigned char signature[] = "FJKEYINF"; -+ -+ for (offset = 0; offset < 0x10000; offset += 0x10) { -+ if (check_signature(bios + offset, signature, -+ sizeof(signature)-1)) -+ return bios + offset; -+ } -+ return NULL; -+} -+ -+static void __init input_apanel_init(void) -+{ -+ void __iomem *bios; -+ const void __iomem *p; -+ -+ bios = ioremap(0xF0000, 0x10000); /* Can't fail */ -+ p = bios_signature(bios); -+ if (p) { -+ /* just use the first address */ -+ apanel_addr = readb(p + 8 + 3) >> 1; -+ } -+ iounmap(bios); -+} -+ -+struct dmi_onboard_device_info { -+ const char *name; -+ u8 type; -+ unsigned short i2c_addr; -+ const char *i2c_type; -+}; -+ -+static const struct dmi_onboard_device_info dmi_devices[] = { -+ { "Syleus", DMI_DEV_TYPE_OTHER, 0x73, "fscsyl" }, -+ { "Hermes", DMI_DEV_TYPE_OTHER, 0x73, "fscher" }, -+ { "Hades", DMI_DEV_TYPE_OTHER, 0x73, "fschds" }, -+}; -+ -+static void dmi_check_onboard_device(u8 type, const char *name, -+ struct i2c_adapter *adap) -+{ -+ int i; -+ struct i2c_board_info info; -+ -+ for (i = 0; i < ARRAY_SIZE(dmi_devices); i++) { -+ /* & ~0x80, ignore enabled/disabled bit */ -+ if ((type & ~0x80) != dmi_devices[i].type) -+ continue; -+ if (strcasecmp(name, dmi_devices[i].name)) -+ continue; -+ -+ mem_clear(&info, sizeof(struct i2c_board_info)); -+ info.addr = dmi_devices[i].i2c_addr; -+ strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE); -+ i2c_new_client_device(adap, &info); -+ break; -+ } -+} -+ -+/* We use our own function to check for onboard devices instead of -+ dmi_find_device() as some buggy BIOS's have the devices we are interested -+ in marked as disabled */ -+static void dmi_check_onboard_devices(const struct dmi_header *dm, void *adap) -+{ -+ int i, count; -+ -+ if (dm->type != 10) -+ return; -+ -+ count = (dm->length - sizeof(struct dmi_header)) / 2; -+ for (i = 0; i < count; i++) { -+ const u8 *d = (char *)(dm + 1) + (i * 2); -+ const char *name = ((char *) dm) + dm->length; -+ u8 type = d[0]; -+ u8 s = d[1]; -+ -+ if (!s) -+ continue; -+ s--; -+ while (s > 0 && name[0]) { -+ name += strlen(name) + 1; -+ s--; -+ } -+ if (name[0] == 0) /* Bogus string reference */ -+ continue; -+ -+ dmi_check_onboard_device(type, name, adap); -+ } -+} -+ -+/* NOTE: Keep this list in sync with drivers/platform/x86/dell-smo8800.c */ -+static const char *const acpi_smo8800_ids[] = { -+ "SMO8800", -+ "SMO8801", -+ "SMO8810", -+ "SMO8811", -+ "SMO8820", -+ "SMO8821", -+ "SMO8830", -+ "SMO8831", -+}; -+ -+static acpi_status check_acpi_smo88xx_device(acpi_handle obj_handle, -+ u32 nesting_level, -+ void *context, -+ void **return_value) -+{ -+ struct acpi_device_info *info; -+ acpi_status status; -+ char *hid; -+ int i; -+ -+ status = acpi_get_object_info(obj_handle, &info); -+ if (ACPI_FAILURE(status)) -+ return AE_OK; -+ -+ if (!(info->valid & ACPI_VALID_HID)) -+ goto smo88xx_not_found; -+ -+ hid = info->hardware_id.string; -+ if (!hid) -+ goto smo88xx_not_found; -+ -+ i = match_string(acpi_smo8800_ids, ARRAY_SIZE(acpi_smo8800_ids), hid); -+ if (i < 0) -+ goto smo88xx_not_found; -+ -+ kfree(info); -+ -+ *((bool *)return_value) = true; -+ return AE_CTRL_TERMINATE; -+ -+smo88xx_not_found: -+ kfree(info); -+ return AE_OK; -+} -+ -+static bool is_dell_system_with_lis3lv02d(void) -+{ -+ bool found; -+ const char *vendor; -+ -+ vendor = dmi_get_system_info(DMI_SYS_VENDOR); -+ if (!vendor || strcmp(vendor, "Dell Inc.")) -+ return false; -+ -+ /* -+ * Check that ACPI device SMO88xx is present and is functioning. -+ * Function acpi_get_devices() already filters all ACPI devices -+ * which are not present or are not functioning. -+ * ACPI device SMO88xx represents our ST microelectronics lis3lv02d -+ * accelerometer but unfortunately ACPI does not provide any other -+ * information (like I2C address). -+ */ -+ found = false; -+ acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL, -+ (void **)&found); -+ -+ return found; -+} -+ -+/* -+ * Accelerometer's I2C address is not specified in DMI nor ACPI, -+ * so it is needed to define mapping table based on DMI product names. -+ */ -+static const struct { -+ const char *dmi_product_name; -+ unsigned short i2c_addr; -+} dell_lis3lv02d_devices[] = { -+ /* -+ * Dell platform team told us that these Latitude devices have -+ * ST microelectronics accelerometer at I2C address 0x29. -+ */ -+ { "Latitude E5250", 0x29 }, -+ { "Latitude E5450", 0x29 }, -+ { "Latitude E5550", 0x29 }, -+ { "Latitude E6440", 0x29 }, -+ { "Latitude E6440 ATG", 0x29 }, -+ { "Latitude E6540", 0x29 }, -+ /* -+ * Additional individual entries were added after verification. -+ */ -+ { "Latitude 5480", 0x29 }, -+ { "Vostro V131", 0x1d }, -+}; -+ -+static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv) -+{ -+ struct i2c_board_info info; -+ const char *dmi_product_name; -+ int i; -+ -+ dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME); -+ for (i = 0; i < ARRAY_SIZE(dell_lis3lv02d_devices); ++i) { -+ if (strcmp(dmi_product_name, -+ dell_lis3lv02d_devices[i].dmi_product_name) == 0) -+ break; -+ } -+ -+ if (i == ARRAY_SIZE(dell_lis3lv02d_devices)) { -+ dev_warn(&priv->pci_dev->dev, -+ "Accelerometer lis3lv02d is present on SMBus but its" -+ " address is unknown, skipping registration\n"); -+ return; -+ } -+ -+ mem_clear(&info, sizeof(struct i2c_board_info)); -+ info.addr = dell_lis3lv02d_devices[i].i2c_addr; -+ strlcpy(info.type, "lis3lv02d", I2C_NAME_SIZE); -+ i2c_new_client_device(&priv->adapter, &info); -+} -+ -+/* Register optional slaves */ -+static void i801_probe_optional_slaves(struct i801_priv *priv) -+{ -+ /* Only register slaves on main SMBus channel */ -+ if (priv->features & FEATURE_IDF) -+ return; -+ -+ if (apanel_addr) { -+ struct i2c_board_info info; -+ -+ mem_clear(&info, sizeof(struct i2c_board_info)); -+ info.addr = apanel_addr; -+ strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE); -+ i2c_new_client_device(&priv->adapter, &info); -+ } -+ -+ if (dmi_name_in_vendors("FUJITSU")) -+ dmi_walk(dmi_check_onboard_devices, &priv->adapter); -+ -+ if (is_dell_system_with_lis3lv02d()) -+ register_dell_lis3lv02d_i2c_device(priv); -+ -+ /* Instantiate SPD EEPROMs unless the SMBus is multiplexed */ -+#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) -+ if (!priv->mux_drvdata) -+#endif -+ i2c_register_spd(&priv->adapter); -+} -+#else -+static void __init input_apanel_init(void) {} -+static void i801_probe_optional_slaves(struct i801_priv *priv) {} -+#endif /* CONFIG_X86 && CONFIG_DMI */ -+ -+#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI -+static struct i801_mux_config i801_mux_config_asus_z8_d12 = { -+ .gpio_chip = "gpio_ich", -+ .values = { 0x02, 0x03 }, -+ .n_values = 2, -+ .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD }, -+ .gpios = { 52, 53 }, -+ .n_gpios = 2, -+}; -+ -+static struct i801_mux_config i801_mux_config_asus_z8_d18 = { -+ .gpio_chip = "gpio_ich", -+ .values = { 0x02, 0x03, 0x01 }, -+ .n_values = 3, -+ .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD, I2C_CLASS_SPD }, -+ .gpios = { 52, 53 }, -+ .n_gpios = 2, -+}; -+ -+static const struct dmi_system_id mux_dmi_table[] = { -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), -+ DMI_MATCH(DMI_BOARD_NAME, "Z8NA-D6(C)"), -+ }, -+ .driver_data = &i801_mux_config_asus_z8_d12, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), -+ DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)E-D12(X)"), -+ }, -+ .driver_data = &i801_mux_config_asus_z8_d12, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), -+ DMI_MATCH(DMI_BOARD_NAME, "Z8NH-D12"), -+ }, -+ .driver_data = &i801_mux_config_asus_z8_d12, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), -+ DMI_MATCH(DMI_BOARD_NAME, "Z8PH-D12/IFB"), -+ }, -+ .driver_data = &i801_mux_config_asus_z8_d12, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), -+ DMI_MATCH(DMI_BOARD_NAME, "Z8NR-D12"), -+ }, -+ .driver_data = &i801_mux_config_asus_z8_d12, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), -+ DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)H-D12"), -+ }, -+ .driver_data = &i801_mux_config_asus_z8_d12, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), -+ DMI_MATCH(DMI_BOARD_NAME, "Z8PG-D18"), -+ }, -+ .driver_data = &i801_mux_config_asus_z8_d18, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), -+ DMI_MATCH(DMI_BOARD_NAME, "Z8PE-D18"), -+ }, -+ .driver_data = &i801_mux_config_asus_z8_d18, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), -+ DMI_MATCH(DMI_BOARD_NAME, "Z8PS-D12"), -+ }, -+ .driver_data = &i801_mux_config_asus_z8_d12, -+ }, -+ { } -+}; -+ -+/* Setup multiplexing if needed */ -+static int i801_add_mux(struct i801_priv *priv) -+{ -+ struct device *dev = &priv->adapter.dev; -+ const struct i801_mux_config *mux_config; -+ struct i2c_mux_gpio_platform_data gpio_data; -+ struct gpiod_lookup_table *lookup; -+ int err, i; -+ -+ if (!priv->mux_drvdata) -+ return 0; -+ mux_config = priv->mux_drvdata; -+ -+ /* Prepare the platform data */ -+ mem_clear(&gpio_data, sizeof(struct i2c_mux_gpio_platform_data)); -+ gpio_data.parent = priv->adapter.nr; -+ gpio_data.values = mux_config->values; -+ gpio_data.n_values = mux_config->n_values; -+ gpio_data.classes = mux_config->classes; -+ gpio_data.idle = I2C_MUX_GPIO_NO_IDLE; -+ -+ /* Register GPIO descriptor lookup table */ -+ lookup = devm_kzalloc(dev, -+ struct_size(lookup, table, mux_config->n_gpios + 1), -+ GFP_KERNEL); -+ if (!lookup) -+ return -ENOMEM; -+ lookup->dev_id = "i2c-mux-gpio"; -+ for (i = 0; i < mux_config->n_gpios; i++) { -+ lookup->table[i] = (struct gpiod_lookup) -+ GPIO_LOOKUP(mux_config->gpio_chip, -+ mux_config->gpios[i], "mux", 0); -+ } -+ gpiod_add_lookup_table(lookup); -+ priv->lookup = lookup; -+ -+ /* -+ * Register the mux device, we use PLATFORM_DEVID_NONE here -+ * because since we are referring to the GPIO chip by name we are -+ * anyways in deep trouble if there is more than one of these -+ * devices, and there should likely only be one platform controller -+ * hub. -+ */ -+ priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio", -+ PLATFORM_DEVID_NONE, &gpio_data, -+ sizeof(struct i2c_mux_gpio_platform_data)); -+ if (IS_ERR(priv->mux_pdev)) { -+ err = PTR_ERR(priv->mux_pdev); -+ gpiod_remove_lookup_table(lookup); -+ priv->mux_pdev = NULL; -+ dev_err(dev, "Failed to register i2c-mux-gpio device\n"); -+ return err; -+ } -+ -+ return 0; -+} -+ -+static void i801_del_mux(struct i801_priv *priv) -+{ -+ if (priv->mux_pdev) -+ platform_device_unregister(priv->mux_pdev); -+ if (priv->lookup) -+ gpiod_remove_lookup_table(priv->lookup); -+} -+ -+static unsigned int i801_get_adapter_class(struct i801_priv *priv) -+{ -+ const struct dmi_system_id *id; -+ const struct i801_mux_config *mux_config; -+ unsigned int class = I2C_CLASS_HWMON | I2C_CLASS_SPD; -+ int i; -+ -+ id = dmi_first_match(mux_dmi_table); -+ if (id) { -+ /* Remove branch classes from trunk */ -+ mux_config = id->driver_data; -+ for (i = 0; i < mux_config->n_values; i++) -+ class &= ~mux_config->classes[i]; -+ -+ /* Remember for later */ -+ priv->mux_drvdata = mux_config; -+ } -+ -+ return class; -+} -+#else -+static inline int i801_add_mux(struct i801_priv *priv) { return 0; } -+static inline void i801_del_mux(struct i801_priv *priv) { } -+ -+static inline unsigned int i801_get_adapter_class(struct i801_priv *priv) -+{ -+ return I2C_CLASS_HWMON | I2C_CLASS_SPD; -+} -+#endif -+ -+static const struct itco_wdt_platform_data spt_tco_platform_data = { -+ .name = "Intel PCH", -+ .version = 4, -+}; -+ -+static DEFINE_SPINLOCK(p2sb_spinlock); -+ -+static struct platform_device * -+i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev, -+ struct resource *tco_res) -+{ -+ struct resource *res; -+ unsigned int devfn; -+ u64 base64_addr; -+ u32 base_addr; -+ u8 hidden; -+ -+ /* -+ * We must access the NO_REBOOT bit over the Primary to Sideband -+ * bridge (P2SB). The BIOS prevents the P2SB device from being -+ * enumerated by the PCI subsystem, so we need to unhide/hide it -+ * to lookup the P2SB BAR. -+ */ -+ spin_lock(&p2sb_spinlock); -+ -+ devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 1); -+ -+ /* Unhide the P2SB device, if it is hidden */ -+ pci_bus_read_config_byte(pci_dev->bus, devfn, 0xe1, &hidden); -+ if (hidden) -+ pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, 0x0); -+ -+ pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR, &base_addr); -+ base64_addr = base_addr & 0xfffffff0; -+ -+ pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR + 0x4, &base_addr); -+ base64_addr |= (u64)base_addr << 32; -+ -+ /* Hide the P2SB device, if it was hidden before */ -+ if (hidden) -+ pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden); -+ spin_unlock(&p2sb_spinlock); -+ -+ res = &tco_res[1]; -+ if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS) -+ res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL_DNV; -+ else -+ res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL; -+ -+ res->end = res->start + 3; -+ res->flags = IORESOURCE_MEM; -+ -+ return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1, -+ tco_res, 2, &spt_tco_platform_data, -+ sizeof(spt_tco_platform_data)); -+} -+ -+static const struct itco_wdt_platform_data cnl_tco_platform_data = { -+ .name = "Intel PCH", -+ .version = 6, -+}; -+ -+static struct platform_device * -+i801_add_tco_cnl(struct i801_priv *priv, struct pci_dev *pci_dev, -+ struct resource *tco_res) -+{ -+ return platform_device_register_resndata(&pci_dev->dev, -+ "iTCO_wdt", -1, tco_res, 1, &cnl_tco_platform_data, -+ sizeof(cnl_tco_platform_data)); -+} -+ -+static void i801_add_tco(struct i801_priv *priv) -+{ -+ struct pci_dev *pci_dev = priv->pci_dev; -+ struct resource tco_res[2], *res; -+ u32 tco_base, tco_ctl; -+ -+ /* If we have ACPI based watchdog use that instead */ -+ if (acpi_has_watchdog()) -+ return; -+ -+ if (!(priv->features & (FEATURE_TCO_SPT | FEATURE_TCO_CNL))) -+ return; -+ -+ pci_read_config_dword(pci_dev, TCOBASE, &tco_base); -+ pci_read_config_dword(pci_dev, TCOCTL, &tco_ctl); -+ if (!(tco_ctl & TCOCTL_EN)) -+ return; -+ -+ mem_clear(tco_res, sizeof(tco_res)); -+ /* -+ * Always populate the main iTCO IO resource here. The second entry -+ * for NO_REBOOT MMIO is filled by the SPT specific function. -+ */ -+ res = &tco_res[0]; -+ res->start = tco_base & ~1; -+ res->end = res->start + 32 - 1; -+ res->flags = IORESOURCE_IO; -+ -+ if (priv->features & FEATURE_TCO_CNL) -+ priv->tco_pdev = i801_add_tco_cnl(priv, pci_dev, tco_res); -+ else -+ priv->tco_pdev = i801_add_tco_spt(priv, pci_dev, tco_res); -+ -+ if (IS_ERR(priv->tco_pdev)) -+ dev_warn(&pci_dev->dev, "failed to create iTCO device\n"); -+} -+ -+#ifdef CONFIG_ACPI -+static bool i801_acpi_is_smbus_ioport(const struct i801_priv *priv, -+ acpi_physical_address address) -+{ -+ return address >= priv->smba && -+ address <= pci_resource_end(priv->pci_dev, SMBBAR); -+} -+ -+static acpi_status -+i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, -+ u64 *value, void *handler_context, void *region_context) -+{ -+ struct i801_priv *priv = handler_context; -+ struct pci_dev *pdev = priv->pci_dev; -+ acpi_status status; -+ -+ /* -+ * Once BIOS AML code touches the OpRegion we warn and inhibit any -+ * further access from the driver itself. This device is now owned -+ * by the system firmware. -+ */ -+ mutex_lock(&priv->acpi_lock); -+ -+ if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) { -+ priv->acpi_reserved = true; -+ -+ dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n"); -+ dev_warn(&pdev->dev, "Driver SMBus register access inhibited\n"); -+ -+ /* -+ * BIOS is accessing the host controller so prevent it from -+ * suspending automatically from now on. -+ */ -+ pm_runtime_get_sync(&pdev->dev); -+ } -+ -+ if ((function & ACPI_IO_MASK) == ACPI_READ) -+ status = acpi_os_read_port(address, (u32 *)value, bits); -+ else -+ status = acpi_os_write_port(address, (u32)*value, bits); -+ -+ mutex_unlock(&priv->acpi_lock); -+ -+ return status; -+} -+ -+static int i801_acpi_probe(struct i801_priv *priv) -+{ -+ struct acpi_device *adev; -+ acpi_status status; -+ -+ adev = ACPI_COMPANION(&priv->pci_dev->dev); -+ if (adev) { -+ status = acpi_install_address_space_handler(adev->handle, -+ ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler, -+ NULL, priv); -+ if (ACPI_SUCCESS(status)) -+ return 0; -+ } -+ -+ return acpi_check_resource_conflict(&priv->pci_dev->resource[SMBBAR]); -+} -+ -+static void i801_acpi_remove(struct i801_priv *priv) -+{ -+ struct acpi_device *adev; -+ -+ adev = ACPI_COMPANION(&priv->pci_dev->dev); -+ if (!adev) -+ return; -+ -+ acpi_remove_address_space_handler(adev->handle, -+ ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler); -+ -+ mutex_lock(&priv->acpi_lock); -+ if (priv->acpi_reserved) -+ pm_runtime_put(&priv->pci_dev->dev); -+ mutex_unlock(&priv->acpi_lock); -+} -+#else -+static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; } -+static inline void i801_acpi_remove(struct i801_priv *priv) { } -+#endif -+ -+static unsigned char i801_setup_hstcfg(struct i801_priv *priv) -+{ -+ unsigned char hstcfg = priv->original_hstcfg; -+ -+ hstcfg &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */ -+ hstcfg |= SMBHSTCFG_HST_EN; -+ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hstcfg); -+ return hstcfg; -+} -+ -+static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ unsigned char temp; -+ int err, i; -+ struct i801_priv *priv; -+ -+ priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ i2c_set_adapdata(&priv->adapter, priv); -+ priv->adapter.owner = THIS_MODULE; -+ priv->adapter.class = i801_get_adapter_class(priv); -+ priv->adapter.algo = &smbus_algorithm; -+ priv->adapter.dev.parent = &dev->dev; -+ ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev)); -+ priv->adapter.retries = 3; -+ mutex_init(&priv->acpi_lock); -+ -+ priv->pci_dev = dev; -+ switch (dev->device) { -+ case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS: -+ case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS: -+ case PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS: -+ case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS: -+ case PCI_DEVICE_ID_INTEL_DNV_SMBUS: -+ case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS: -+ case PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS: -+ priv->features |= FEATURE_BLOCK_PROC; -+ priv->features |= FEATURE_I2C_BLOCK_READ; -+ priv->features |= FEATURE_IRQ; -+ priv->features |= FEATURE_SMBUS_PEC; -+ priv->features |= FEATURE_BLOCK_BUFFER; -+ priv->features |= FEATURE_TCO_SPT; -+ priv->features |= FEATURE_HOST_NOTIFY; -+ break; -+ -+ case PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS: -+ case PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS: -+ case PCI_DEVICE_ID_INTEL_CDF_SMBUS: -+ case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS: -+ case PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS: -+ case PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS: -+ case PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS: -+ case PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS: -+ case PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS: -+ case PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS: -+ case PCI_DEVICE_ID_INTEL_EBG_SMBUS: -+ case PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS: -+ priv->features |= FEATURE_BLOCK_PROC; -+ priv->features |= FEATURE_I2C_BLOCK_READ; -+ priv->features |= FEATURE_IRQ; -+ priv->features |= FEATURE_SMBUS_PEC; -+ priv->features |= FEATURE_BLOCK_BUFFER; -+ priv->features |= FEATURE_TCO_CNL; -+ priv->features |= FEATURE_HOST_NOTIFY; -+ break; -+ -+ case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0: -+ case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1: -+ case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2: -+ case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0: -+ case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1: -+ case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2: -+ priv->features |= FEATURE_IDF; -+ fallthrough; -+ default: -+ priv->features |= FEATURE_BLOCK_PROC; -+ priv->features |= FEATURE_I2C_BLOCK_READ; -+ priv->features |= FEATURE_IRQ; -+ fallthrough; -+ case PCI_DEVICE_ID_INTEL_82801DB_3: -+ priv->features |= FEATURE_SMBUS_PEC; -+ priv->features |= FEATURE_BLOCK_BUFFER; -+ fallthrough; -+ case PCI_DEVICE_ID_INTEL_82801CA_3: -+ priv->features |= FEATURE_HOST_NOTIFY; -+ fallthrough; -+ case PCI_DEVICE_ID_INTEL_82801BA_2: -+ case PCI_DEVICE_ID_INTEL_82801AB_3: -+ case PCI_DEVICE_ID_INTEL_82801AA_3: -+ break; -+ } -+ -+ /* Disable features on user request */ -+ for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) { -+ if (priv->features & disable_features & (1 << i)) -+ dev_notice(&dev->dev, "%s disabled by user\n", -+ i801_feature_names[i]); -+ } -+ priv->features &= ~disable_features; -+ -+ err = pcim_enable_device(dev); -+ if (err) { -+ dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n", -+ err); -+ return err; -+ } -+ pcim_pin_device(dev); -+ -+ /* Determine the address of the SMBus area */ -+ priv->smba = pci_resource_start(dev, SMBBAR); -+ if (!priv->smba) { -+ dev_err(&dev->dev, -+ "SMBus base address uninitialized, upgrade BIOS\n"); -+ return -ENODEV; -+ } -+ -+ if (i801_acpi_probe(priv)) -+ return -ENODEV; -+ -+ err = pcim_iomap_regions(dev, 1 << SMBBAR, -+ dev_driver_string(&dev->dev)); -+ if (err) { -+ dev_err(&dev->dev, -+ "Failed to request SMBus region 0x%lx-0x%Lx\n", -+ priv->smba, -+ (unsigned long long)pci_resource_end(dev, SMBBAR)); -+ i801_acpi_remove(priv); -+ return err; -+ } -+ -+ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &priv->original_hstcfg); -+ temp = i801_setup_hstcfg(priv); -+ if (!(priv->original_hstcfg & SMBHSTCFG_HST_EN)) -+ dev_info(&dev->dev, "Enabling SMBus device\n"); -+ -+ if (temp & SMBHSTCFG_SMB_SMI_EN) { -+ dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n"); -+ /* Disable SMBus interrupt feature if SMBus using SMI# */ -+ priv->features &= ~FEATURE_IRQ; -+ } -+ if (temp & SMBHSTCFG_SPD_WD) -+ dev_info(&dev->dev, "SPD Write Disable is set\n"); -+ -+ /* Clear special mode bits */ -+ if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER)) -+ outb_p(inb_p(SMBAUXCTL(priv)) & -+ ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); -+ -+ /* Remember original Host Notify setting */ -+ if (priv->features & FEATURE_HOST_NOTIFY) -+ priv->original_slvcmd = inb_p(SMBSLVCMD(priv)); -+ -+ /* Default timeout in interrupt mode: 200 ms */ -+ priv->adapter.timeout = HZ / 5; -+ -+ if (dev->irq == IRQ_NOTCONNECTED) -+ priv->features &= ~FEATURE_IRQ; -+ -+ if (priv->features & FEATURE_IRQ) { -+ u16 pcictl, pcists; -+ -+ /* Complain if an interrupt is already pending */ -+ pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists); -+ if (pcists & SMBPCISTS_INTS) -+ dev_warn(&dev->dev, "An interrupt is pending!\n"); -+ -+ /* Check if interrupts have been disabled */ -+ pci_read_config_word(priv->pci_dev, SMBPCICTL, &pcictl); -+ if (pcictl & SMBPCICTL_INTDIS) { -+ dev_info(&dev->dev, "Interrupts are disabled\n"); -+ priv->features &= ~FEATURE_IRQ; -+ } -+ } -+ -+ if (priv->features & FEATURE_IRQ) { -+ init_waitqueue_head(&priv->waitq); -+ -+ err = devm_request_irq(&dev->dev, dev->irq, i801_isr, -+ IRQF_SHARED, -+ dev_driver_string(&dev->dev), priv); -+ if (err) { -+ dev_err(&dev->dev, "Failed to allocate irq %d: %d\n", -+ dev->irq, err); -+ priv->features &= ~FEATURE_IRQ; -+ } -+ } -+ dev_info(&dev->dev, "SMBus using %s\n", -+ priv->features & FEATURE_IRQ ? "PCI interrupt" : "polling"); -+ -+ i801_add_tco(priv); -+ -+ snprintf(priv->adapter.name, sizeof(priv->adapter.name), -+ "SMBus I801 adapter at %04lx", priv->smba); -+ err = i2c_add_adapter(&priv->adapter); -+ if (err) { -+ i801_acpi_remove(priv); -+ return err; -+ } -+ -+ i801_enable_host_notify(&priv->adapter); -+ -+ i801_probe_optional_slaves(priv); -+ /* We ignore errors - multiplexing is optional */ -+ i801_add_mux(priv); -+ -+ pci_set_drvdata(dev, priv); -+ -+ dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_NO_DIRECT_COMPLETE); -+ pm_runtime_set_autosuspend_delay(&dev->dev, 1000); -+ pm_runtime_use_autosuspend(&dev->dev); -+ pm_runtime_put_autosuspend(&dev->dev); -+ pm_runtime_allow(&dev->dev); -+ dev_info(&dev->dev, "wb-i2c-i801 probe ok.\n"); -+ -+ return 0; -+} -+ -+static void i801_remove(struct pci_dev *dev) -+{ -+ struct i801_priv *priv = pci_get_drvdata(dev); -+ -+ pm_runtime_forbid(&dev->dev); -+ pm_runtime_get_noresume(&dev->dev); -+ -+ i801_disable_host_notify(priv); -+ i801_del_mux(priv); -+ i2c_del_adapter(&priv->adapter); -+ i801_acpi_remove(priv); -+ pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); -+ -+ platform_device_unregister(priv->tco_pdev); -+ -+ /* -+ * do not call pci_disable_device(dev) since it can cause hard hangs on -+ * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010) -+ */ -+} -+ -+static void i801_shutdown(struct pci_dev *dev) -+{ -+ struct i801_priv *priv = pci_get_drvdata(dev); -+ -+ /* Restore config registers to avoid hard hang on some systems */ -+ i801_disable_host_notify(priv); -+ pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int i801_suspend(struct device *dev) -+{ -+ struct i801_priv *priv = dev_get_drvdata(dev); -+ -+ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, priv->original_hstcfg); -+ return 0; -+} -+ -+static int i801_resume(struct device *dev) -+{ -+ struct i801_priv *priv = dev_get_drvdata(dev); -+ -+ i801_setup_hstcfg(priv); -+ i801_enable_host_notify(&priv->adapter); -+ -+ return 0; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume); -+ -+static struct pci_driver i801_driver = { -+ .name = "wb_i801_smbus", -+ .id_table = i801_ids, -+ .probe = i801_probe, -+ .remove = i801_remove, -+ .shutdown = i801_shutdown, -+ .driver = { -+ .pm = &i801_pm_ops, -+ }, -+}; -+ -+static int __init i2c_i801_init(void) -+{ -+ if (dmi_name_in_vendors("FUJITSU")) -+ input_apanel_init(); -+ return pci_register_driver(&i801_driver); -+} -+ -+static void __exit i2c_i801_exit(void) -+{ -+ pci_unregister_driver(&i801_driver); -+} -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("I801 SMBus driver"); -+MODULE_LICENSE("GPL"); -+ -+module_init(i2c_i801_init); -+module_exit(i2c_i801_exit); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_ismt.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_ismt.c -new file mode 100644 -index 000000000..2015c8ca2 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_ismt.c -@@ -0,0 +1,1105 @@ -+/* -+ * This file is provided under a dual BSD/GPLv2 license. When using or -+ * redistributing this file, you may do so under either license. -+ * -+ * Copyright(c) 2012 Intel Corporation. All rights reserved. -+ * -+ * GPL LICENSE SUMMARY -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * 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. -+ * The full GNU General Public License is included in this distribution -+ * in the file called LICENSE.GPL. -+ * -+ * BSD LICENSE -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * * Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * * Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in -+ * the documentation and/or other materials provided with the -+ * distribution. -+ * * Neither the name of Intel Corporation nor the names of its -+ * contributors may be used to endorse or promote products derived -+ * from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+/* -+ * Supports the SMBus Message Transport (SMT) in the Intel Atom Processor -+ * S12xx Product Family. -+ * -+ * Features supported by this driver: -+ * Hardware PEC yes -+ * Block buffer yes -+ * Block process call transaction no -+ * Slave mode no -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+ -+/* PCI Address Constants */ -+#define SMBBAR 0 -+ -+#define ISMT_DBCTRL 0x388 /* ISMT PIN Control Register */ -+#define ISMT_DBSTS 0X38C /* ISMT PIN Status Register */ -+ -+#define ISMT_DBSTS_CLK_STS (1<<9) /* bit9 SMBCLK_CUR_STS */ -+#define ISMT_DBSTS_SDA_STS (1<<8) /* bit8 SMBDATA_CUR_STS */ -+#define ISMT_DBCTRL_CLK_CTL (1<<1) /* bit1 SMBCLK_CTL */ -+#define ISMT_DBCTRL_ENABLE (1<<31) /* bit31 EN */ -+ -+/* PCI DIDs for the Intel SMBus Message Transport (SMT) Devices */ -+#define PCI_DEVICE_ID_INTEL_S1200_SMT0 0x0c59 -+#define PCI_DEVICE_ID_INTEL_S1200_SMT1 0x0c5a -+#define PCI_DEVICE_ID_INTEL_CDF_SMT 0x18ac -+#define PCI_DEVICE_ID_INTEL_DNV_SMT 0x19ac -+#define PCI_DEVICE_ID_INTEL_EBG_SMT 0x1bff -+#define PCI_DEVICE_ID_INTEL_AVOTON_SMT 0x1f15 -+ -+#define ISMT_DESC_ENTRIES 2 /* number of descriptor entries */ -+#define ISMT_MAX_RETRIES 3 /* number of SMBus retries to attempt */ -+ -+/* Hardware Descriptor Constants - Control Field */ -+#define ISMT_DESC_CWRL 0x01 /* Command/Write Length */ -+#define ISMT_DESC_BLK 0X04 /* Perform Block Transaction */ -+#define ISMT_DESC_FAIR 0x08 /* Set fairness flag upon successful arbit. */ -+#define ISMT_DESC_PEC 0x10 /* Packet Error Code */ -+#define ISMT_DESC_I2C 0x20 /* I2C Enable */ -+#define ISMT_DESC_INT 0x40 /* Interrupt */ -+#define ISMT_DESC_SOE 0x80 /* Stop On Error */ -+ -+/* Hardware Descriptor Constants - Status Field */ -+#define ISMT_DESC_SCS 0x01 /* Success */ -+#define ISMT_DESC_DLTO 0x04 /* Data Low Time Out */ -+#define ISMT_DESC_NAK 0x08 /* NAK Received */ -+#define ISMT_DESC_CRC 0x10 /* CRC Error */ -+#define ISMT_DESC_CLTO 0x20 /* Clock Low Time Out */ -+#define ISMT_DESC_COL 0x40 /* Collisions */ -+#define ISMT_DESC_LPR 0x80 /* Large Packet Received */ -+ -+/* Macros */ -+#define ISMT_DESC_ADDR_RW(addr, rw) (((addr) << 1) | (rw)) -+ -+/* iSMT General Register address offsets (SMBBAR + ) */ -+#define ISMT_GR_GCTRL 0x000 /* General Control */ -+#define ISMT_GR_SMTICL 0x008 /* SMT Interrupt Cause Location */ -+#define ISMT_GR_ERRINTMSK 0x010 /* Error Interrupt Mask */ -+#define ISMT_GR_ERRAERMSK 0x014 /* Error AER Mask */ -+#define ISMT_GR_ERRSTS 0x018 /* Error Status */ -+#define ISMT_GR_ERRINFO 0x01c /* Error Information */ -+ -+/* iSMT Master Registers */ -+#define ISMT_MSTR_MDBA 0x100 /* Master Descriptor Base Address */ -+#define ISMT_MSTR_MCTRL 0x108 /* Master Control */ -+#define ISMT_MSTR_MSTS 0x10c /* Master Status */ -+#define ISMT_MSTR_MDS 0x110 /* Master Descriptor Size */ -+#define ISMT_MSTR_RPOLICY 0x114 /* Retry Policy */ -+ -+/* iSMT Miscellaneous Registers */ -+#define ISMT_SPGT 0x300 /* SMBus PHY Global Timing */ -+ -+/* General Control Register (GCTRL) bit definitions */ -+#define ISMT_GCTRL_TRST 0x04 /* Target Reset */ -+#define ISMT_GCTRL_KILL 0x08 /* Kill */ -+#define ISMT_GCTRL_SRST 0x40 /* Soft Reset */ -+ -+/* Master Control Register (MCTRL) bit definitions */ -+#define ISMT_MCTRL_SS 0x01 /* Start/Stop */ -+#define ISMT_MCTRL_MEIE 0x10 /* Master Error Interrupt Enable */ -+#define ISMT_MCTRL_FMHP 0x00ff0000 /* Firmware Master Head Ptr (FMHP) */ -+ -+/* Master Status Register (MSTS) bit definitions */ -+#define ISMT_MSTS_HMTP 0xff0000 /* HW Master Tail Pointer (HMTP) */ -+#define ISMT_MSTS_MIS 0x20 /* Master Interrupt Status (MIS) */ -+#define ISMT_MSTS_MEIS 0x10 /* Master Error Int Status (MEIS) */ -+#define ISMT_MSTS_IP 0x01 /* In Progress */ -+ -+/* Master Descriptor Size (MDS) bit definitions */ -+#define ISMT_MDS_MASK 0xff /* Master Descriptor Size mask (MDS) */ -+ -+/* SMBus PHY Global Timing Register (SPGT) bit definitions */ -+#define ISMT_SPGT_SPD_MASK 0xc0000000 /* SMBus Speed mask */ -+#define ISMT_SPGT_SPD_80K 0x00 /* 80 kHz */ -+#define ISMT_SPGT_SPD_100K (0x1 << 30) /* 100 kHz */ -+#define ISMT_SPGT_SPD_400K (0x2 << 30) /* 400 kHz */ -+#define ISMT_SPGT_SPD_1M (0x3 << 30) /* 1 MHz */ -+ -+/* MSI Control Register (MSICTL) bit definitions */ -+#define ISMT_MSICTL_MSIE 0x01 /* MSI Enable */ -+ -+/* iSMT Hardware Descriptor */ -+struct ismt_desc { -+ u8 tgtaddr_rw; /* target address & r/w bit */ -+ u8 wr_len_cmd; /* write length in bytes or a command */ -+ u8 rd_len; /* read length */ -+ u8 control; /* control bits */ -+ u8 status; /* status bits */ -+ u8 retry; /* collision retry and retry count */ -+ u8 rxbytes; /* received bytes */ -+ u8 txbytes; /* transmitted bytes */ -+ u32 dptr_low; /* lower 32 bit of the data pointer */ -+ u32 dptr_high; /* upper 32 bit of the data pointer */ -+} __packed; -+ -+struct ismt_priv { -+ struct i2c_adapter adapter; -+ void __iomem *smba; /* PCI BAR */ -+ struct pci_dev *pci_dev; -+ struct ismt_desc *hw; /* descriptor virt base addr */ -+ dma_addr_t io_rng_dma; /* descriptor HW base addr */ -+ u8 head; /* ring buffer head pointer */ -+ struct completion cmp; /* interrupt completion */ -+ u8 buffer[I2C_SMBUS_BLOCK_MAX + 16]; /* temp R/W data buffer */ -+}; -+ -+static const struct pci_device_id ismt_ids[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMT) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMT) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EBG_SMT) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) }, -+ { 0, } -+}; -+ -+MODULE_DEVICE_TABLE(pci, ismt_ids); -+ -+/* Bus speed control bits for slow debuggers - refer to the docs for usage */ -+static unsigned int bus_speed = 100; -+static unsigned int delay = 1000; -+module_param(bus_speed, uint, S_IRUGO); -+MODULE_PARM_DESC(bus_speed, "Bus Speed in kHz (100 by default)"); -+module_param(delay, uint, S_IRUGO); -+MODULE_PARM_DESC(delay, "Delay in microsecs before access (1000 by default)"); -+ -+static unsigned int dma_reset_timeout = 1000; -+module_param(dma_reset_timeout, uint, S_IRUGO); -+ -+static void ismt_hw_init(struct ismt_priv *priv); -+ -+/** -+ * __ismt_desc_dump() - dump the contents of a specific descriptor -+ * @dev: the iSMT device -+ * @desc: the iSMT hardware descriptor -+ */ -+static void __ismt_desc_dump(struct device *dev, const struct ismt_desc *desc) -+{ -+ -+ dev_dbg(dev, "Descriptor struct: %p\n", desc); -+ dev_dbg(dev, "\ttgtaddr_rw=0x%02X\n", desc->tgtaddr_rw); -+ dev_dbg(dev, "\twr_len_cmd=0x%02X\n", desc->wr_len_cmd); -+ dev_dbg(dev, "\trd_len= 0x%02X\n", desc->rd_len); -+ dev_dbg(dev, "\tcontrol= 0x%02X\n", desc->control); -+ dev_dbg(dev, "\tstatus= 0x%02X\n", desc->status); -+ dev_dbg(dev, "\tretry= 0x%02X\n", desc->retry); -+ dev_dbg(dev, "\trxbytes= 0x%02X\n", desc->rxbytes); -+ dev_dbg(dev, "\ttxbytes= 0x%02X\n", desc->txbytes); -+ dev_dbg(dev, "\tdptr_low= 0x%08X\n", desc->dptr_low); -+ dev_dbg(dev, "\tdptr_high= 0x%08X\n", desc->dptr_high); -+} -+/** -+ * ismt_desc_dump() - dump the contents of a descriptor for debug purposes -+ * @priv: iSMT private data -+ */ -+static void ismt_desc_dump(struct ismt_priv *priv) -+{ -+ struct device *dev = &priv->pci_dev->dev; -+ struct ismt_desc *desc = &priv->hw[priv->head]; -+ -+ dev_dbg(dev, "Dump of the descriptor struct: 0x%X\n", priv->head); -+ __ismt_desc_dump(dev, desc); -+} -+ -+static void ismt_reset_dma(struct ismt_priv *priv) -+{ -+ uint val; -+ u16 ctrl; -+ struct pci_dev *pdev; -+ u32 addr_lo, addr_hi; -+ -+ /* save msiaddr */ -+ pdev = priv->pci_dev; -+ pci_read_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_LO, &addr_lo); -+ pci_read_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_HI, &addr_hi); -+ -+ /* Clear the start bit */ -+ val = readl(priv->smba + ISMT_MSTR_MCTRL); -+ val &= ~ISMT_MCTRL_SS; -+ writel(val, priv->smba + ISMT_MSTR_MCTRL); -+ -+ val = readl(priv->smba + ISMT_GR_GCTRL); -+ writel(val | ISMT_GCTRL_KILL | ISMT_GCTRL_TRST | ISMT_GCTRL_SRST, priv->smba + ISMT_GR_GCTRL); -+ -+ if (dma_reset_timeout > 0) { -+ usleep_range(dma_reset_timeout, dma_reset_timeout + 1); -+ } -+ -+ ismt_hw_init(priv); -+ pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_LO, addr_lo); -+ pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_HI, addr_hi); -+ /* enable msi */ -+ pci_read_config_word(pdev, pdev->msi_cap + PCI_MSI_FLAGS, &ctrl); -+ ctrl |= PCI_MSI_FLAGS_ENABLE; -+ pci_write_config_word(pdev, pdev->msi_cap + PCI_MSI_FLAGS, ctrl); -+} -+ -+/** -+ * ismt_gen_reg_dump() - dump the iSMT General Registers -+ * @priv: iSMT private data -+ */ -+static void ismt_gen_reg_dump(struct ismt_priv *priv) -+{ -+ struct device *dev = &priv->pci_dev->dev; -+ -+ dev_dbg(dev, "Dump of the iSMT General Registers\n"); -+ dev_dbg(dev, " GCTRL.... : (0x%p)=0x%X\n", -+ priv->smba + ISMT_GR_GCTRL, -+ readl(priv->smba + ISMT_GR_GCTRL)); -+ dev_dbg(dev, " SMTICL... : (0x%p)=0x%016llX\n", -+ priv->smba + ISMT_GR_SMTICL, -+ (long long unsigned int)readq(priv->smba + ISMT_GR_SMTICL)); -+ dev_dbg(dev, " ERRINTMSK : (0x%p)=0x%X\n", -+ priv->smba + ISMT_GR_ERRINTMSK, -+ readl(priv->smba + ISMT_GR_ERRINTMSK)); -+ dev_dbg(dev, " ERRAERMSK : (0x%p)=0x%X\n", -+ priv->smba + ISMT_GR_ERRAERMSK, -+ readl(priv->smba + ISMT_GR_ERRAERMSK)); -+ dev_dbg(dev, " ERRSTS... : (0x%p)=0x%X\n", -+ priv->smba + ISMT_GR_ERRSTS, -+ readl(priv->smba + ISMT_GR_ERRSTS)); -+ dev_dbg(dev, " ERRINFO.. : (0x%p)=0x%X\n", -+ priv->smba + ISMT_GR_ERRINFO, -+ readl(priv->smba + ISMT_GR_ERRINFO)); -+} -+ -+/** -+ * ismt_mstr_reg_dump() - dump the iSMT Master Registers -+ * @priv: iSMT private data -+ */ -+static void ismt_mstr_reg_dump(struct ismt_priv *priv) -+{ -+ struct device *dev = &priv->pci_dev->dev; -+ -+ dev_dbg(dev, "Dump of the iSMT Master Registers\n"); -+ dev_dbg(dev, " MDBA..... : (0x%p)=0x%016llX\n", -+ priv->smba + ISMT_MSTR_MDBA, -+ (long long unsigned int)readq(priv->smba + ISMT_MSTR_MDBA)); -+ dev_dbg(dev, " MCTRL.... : (0x%p)=0x%X\n", -+ priv->smba + ISMT_MSTR_MCTRL, -+ readl(priv->smba + ISMT_MSTR_MCTRL)); -+ dev_dbg(dev, " MSTS..... : (0x%p)=0x%X\n", -+ priv->smba + ISMT_MSTR_MSTS, -+ readl(priv->smba + ISMT_MSTR_MSTS)); -+ dev_dbg(dev, " MDS...... : (0x%p)=0x%X\n", -+ priv->smba + ISMT_MSTR_MDS, -+ readl(priv->smba + ISMT_MSTR_MDS)); -+ dev_dbg(dev, " RPOLICY.. : (0x%p)=0x%X\n", -+ priv->smba + ISMT_MSTR_RPOLICY, -+ readl(priv->smba + ISMT_MSTR_RPOLICY)); -+ dev_dbg(dev, " SPGT..... : (0x%p)=0x%X\n", -+ priv->smba + ISMT_SPGT, -+ readl(priv->smba + ISMT_SPGT)); -+} -+ -+/** -+ * ismt_submit_desc() - add a descriptor to the ring -+ * @priv: iSMT private data -+ */ -+static void ismt_submit_desc(struct ismt_priv *priv) -+{ -+ uint fmhp; -+ uint val; -+ -+ ismt_desc_dump(priv); -+ ismt_gen_reg_dump(priv); -+ ismt_mstr_reg_dump(priv); -+ -+ /* Set the FMHP (Firmware Master Head Pointer)*/ -+ fmhp = ((priv->head + 1) % ISMT_DESC_ENTRIES) << 16; -+ val = readl(priv->smba + ISMT_MSTR_MCTRL); -+ writel((val & ~ISMT_MCTRL_FMHP) | fmhp, -+ priv->smba + ISMT_MSTR_MCTRL); -+ -+ /* Set the start bit */ -+ val = readl(priv->smba + ISMT_MSTR_MCTRL); -+ writel(val | ISMT_MCTRL_SS, -+ priv->smba + ISMT_MSTR_MCTRL); -+} -+ -+/** -+ * ismt_process_desc() - handle the completion of the descriptor -+ * @desc: the iSMT hardware descriptor -+ * @data: data buffer from the upper layer -+ * @priv: ismt_priv struct holding our dma buffer -+ * @size: SMBus transaction type -+ * @read_write: flag to indicate if this is a read or write -+ */ -+static int ismt_process_desc(const struct ismt_desc *desc, -+ union i2c_smbus_data *data, -+ struct ismt_priv *priv, int size, -+ char read_write) -+{ -+ u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16); -+ -+ dev_dbg(&priv->pci_dev->dev, "Processing completed descriptor\n"); -+ __ismt_desc_dump(&priv->pci_dev->dev, desc); -+ ismt_gen_reg_dump(priv); -+ ismt_mstr_reg_dump(priv); -+ -+ if (desc->status & ISMT_DESC_SCS) { -+ if (read_write == I2C_SMBUS_WRITE && -+ size != I2C_SMBUS_PROC_CALL) -+ return 0; -+ -+ switch (size) { -+ case I2C_SMBUS_BYTE: -+ case I2C_SMBUS_BYTE_DATA: -+ data->byte = dma_buffer[0]; -+ break; -+ case I2C_SMBUS_WORD_DATA: -+ case I2C_SMBUS_PROC_CALL: -+ data->word = dma_buffer[0] | (dma_buffer[1] << 8); -+ break; -+ case I2C_SMBUS_BLOCK_DATA: -+ if (desc->rxbytes != dma_buffer[0] + 1) -+ return -EMSGSIZE; -+ -+ memcpy(data->block, dma_buffer, desc->rxbytes); -+ break; -+ case I2C_SMBUS_I2C_BLOCK_DATA: -+ memcpy(&data->block[1], dma_buffer, desc->rxbytes); -+ data->block[0] = desc->rxbytes; -+ break; -+ } -+ return 0; -+ } -+ -+ if (likely(desc->status & ISMT_DESC_NAK)) -+ return -ENXIO; -+ -+ if (desc->status & ISMT_DESC_CRC) -+ return -EBADMSG; -+ -+ if (desc->status & ISMT_DESC_COL) -+ return -EAGAIN; -+ -+ if (desc->status & ISMT_DESC_LPR) -+ return -EPROTO; -+ -+ if (desc->status & (ISMT_DESC_DLTO | ISMT_DESC_CLTO)) -+ return -ETIMEDOUT; -+ -+ return -EIO; -+} -+ -+static void ismt_setscl(struct ismt_priv *priv, unsigned int level) -+{ -+ int pin_status; -+ -+ pin_status = readl(priv->smba + ISMT_DBCTRL); -+ if (level == 0) { -+ pin_status &= (~ISMT_DBCTRL_CLK_CTL); -+ } else { -+ pin_status |= ISMT_DBCTRL_CLK_CTL; -+ } -+ writel(pin_status, priv->smba + ISMT_DBCTRL); -+ pin_status = readl(priv->smba + ISMT_DBCTRL); -+ dev_dbg(&priv->pci_dev->dev, "dbctrl status = 0x%04x\r\n", pin_status); -+ return; -+} -+ -+static void ismt_i2c_unblock(struct ismt_priv *priv) -+{ -+ int i; -+ int pin_status, ori_status; -+ -+ pin_status = readl(priv->smba + ISMT_DBCTRL); -+ ori_status = pin_status; -+ if ((pin_status & ISMT_DBCTRL_ENABLE) == 0) { -+ pin_status |= ISMT_DBCTRL_ENABLE; -+ writel(pin_status, priv->smba + ISMT_DBCTRL); -+ pin_status = readl(priv->smba + ISMT_DBCTRL); -+ dev_dbg(&priv->pci_dev->dev, "enable dbctrl pin status = 0x%04x\r\n", pin_status); -+ } -+ -+ for (i = 0; i < 10; i++) { -+ ismt_setscl(priv, 0); -+ udelay(5); -+ ismt_setscl(priv, 1); -+ udelay(5); -+ } -+ -+ pin_status = readl(priv->smba + ISMT_DBCTRL); -+ if (pin_status != ori_status) { -+ writel(ori_status, priv->smba + ISMT_DBCTRL); -+ pin_status = readl(priv->smba + ISMT_DBCTRL); -+ dev_dbg(&priv->pci_dev->dev, "reback dbctrl pin status = 0x%04x\r\n", pin_status); -+ } -+ -+ return; -+} -+ -+static int ismt_check_i2c_unblock(struct ismt_priv *priv) -+{ -+ int pin_status; -+ -+ pin_status = readl(priv->smba + ISMT_DBSTS); -+ -+ if ( (!(pin_status & ISMT_DBSTS_SDA_STS) ) && (pin_status & ISMT_DBSTS_CLK_STS) ) { -+ dev_dbg(&priv->pci_dev->dev, "SDA is low, send 9 clock to device!\n"); -+ ismt_i2c_unblock(priv); -+ } -+ return 0; -+} -+ -+static int ismt_check_i2c_scl(struct ismt_priv *priv) -+{ -+ int pin_status; -+ -+ pin_status = readl(priv->smba + ISMT_DBSTS); -+ -+ if ( (pin_status & ISMT_DBSTS_SDA_STS) && (pin_status & ISMT_DBSTS_CLK_STS) ) { -+ return 0; -+ } -+ -+ dev_warn(&priv->pci_dev->dev, "SDA or SCL is low.pin_status:0x%x\n", pin_status); -+ return -1; -+} -+ -+/* Make sure the SMBus host is ready to start transmitting. -+ Return 0 if it is, -EIO if it is not. */ -+static int ismt_check_pre(struct ismt_priv *priv) -+{ -+ ismt_check_i2c_unblock(priv); -+ -+ /* SDA or SCL is low, return -EIO */ -+ if (ismt_check_i2c_scl(priv)) { -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+/** -+ * ismt_access() - process an SMBus command -+ * @adap: the i2c host adapter -+ * @addr: address of the i2c/SMBus target -+ * @flags: command options -+ * @read_write: read from or write to device -+ * @command: the i2c/SMBus command to issue -+ * @size: SMBus transaction type -+ * @data: read/write data buffer -+ */ -+static int ismt_access(struct i2c_adapter *adap, u16 addr, -+ unsigned short flags, char read_write, u8 command, -+ int size, union i2c_smbus_data *data) -+{ -+ int ret; -+ unsigned long time_left; -+ dma_addr_t dma_addr = 0; /* address of the data buffer */ -+ u8 dma_size = 0; -+ enum dma_data_direction dma_direction = 0; -+ struct ismt_desc *desc; -+ struct ismt_priv *priv = i2c_get_adapdata(adap); -+ struct device *dev = &priv->pci_dev->dev; -+ u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16); -+ -+ if (delay > 0) { -+ usleep_range(delay, delay + 1); -+ } -+ -+ ret = ismt_check_pre(priv); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ desc = &priv->hw[priv->head]; -+ -+ /* Initialize the DMA buffer */ -+ mem_clear(priv->buffer, sizeof(priv->buffer)); -+ -+ /* Initialize the descriptor */ -+ mem_clear(desc, sizeof(struct ismt_desc)); -+ desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write); -+ -+ /* Initialize common control bits */ -+ if (likely(pci_dev_msi_enabled(priv->pci_dev))) -+ desc->control = ISMT_DESC_INT | ISMT_DESC_FAIR; -+ else -+ desc->control = ISMT_DESC_FAIR; -+ -+ if ((flags & I2C_CLIENT_PEC) && (size != I2C_SMBUS_QUICK) -+ && (size != I2C_SMBUS_I2C_BLOCK_DATA)) -+ desc->control |= ISMT_DESC_PEC; -+ -+ switch (size) { -+ case I2C_SMBUS_QUICK: -+ dev_dbg(dev, "I2C_SMBUS_QUICK\n"); -+ break; -+ -+ case I2C_SMBUS_BYTE: -+ if (read_write == I2C_SMBUS_WRITE) { -+ /* -+ * Send Byte -+ * The command field contains the write data -+ */ -+ dev_dbg(dev, "I2C_SMBUS_BYTE: WRITE\n"); -+ desc->control |= ISMT_DESC_CWRL; -+ desc->wr_len_cmd = command; -+ } else { -+ /* Receive Byte */ -+ dev_dbg(dev, "I2C_SMBUS_BYTE: READ\n"); -+ dma_size = 1; -+ dma_direction = DMA_FROM_DEVICE; -+ desc->rd_len = 1; -+ } -+ break; -+ -+ case I2C_SMBUS_BYTE_DATA: -+ if (read_write == I2C_SMBUS_WRITE) { -+ /* -+ * Write Byte -+ * Command plus 1 data byte -+ */ -+ dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: WRITE\n"); -+ desc->wr_len_cmd = 2; -+ dma_size = 2; -+ dma_direction = DMA_TO_DEVICE; -+ dma_buffer[0] = command; -+ dma_buffer[1] = data->byte; -+ } else { -+ /* Read Byte */ -+ dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: READ\n"); -+ desc->control |= ISMT_DESC_CWRL; -+ desc->wr_len_cmd = command; -+ desc->rd_len = 1; -+ dma_size = 1; -+ dma_direction = DMA_FROM_DEVICE; -+ } -+ break; -+ -+ case I2C_SMBUS_WORD_DATA: -+ if (read_write == I2C_SMBUS_WRITE) { -+ /* Write Word */ -+ dev_dbg(dev, "I2C_SMBUS_WORD_DATA: WRITE\n"); -+ desc->wr_len_cmd = 3; -+ dma_size = 3; -+ dma_direction = DMA_TO_DEVICE; -+ dma_buffer[0] = command; -+ dma_buffer[1] = data->word & 0xff; -+ dma_buffer[2] = data->word >> 8; -+ } else { -+ /* Read Word */ -+ dev_dbg(dev, "I2C_SMBUS_WORD_DATA: READ\n"); -+ desc->wr_len_cmd = command; -+ desc->control |= ISMT_DESC_CWRL; -+ desc->rd_len = 2; -+ dma_size = 2; -+ dma_direction = DMA_FROM_DEVICE; -+ } -+ break; -+ -+ case I2C_SMBUS_PROC_CALL: -+ dev_dbg(dev, "I2C_SMBUS_PROC_CALL\n"); -+ desc->wr_len_cmd = 3; -+ desc->rd_len = 2; -+ dma_size = 3; -+ dma_direction = DMA_BIDIRECTIONAL; -+ dma_buffer[0] = command; -+ dma_buffer[1] = data->word & 0xff; -+ dma_buffer[2] = data->word >> 8; -+ break; -+ -+ case I2C_SMBUS_BLOCK_DATA: -+ if (read_write == I2C_SMBUS_WRITE) { -+ /* Block Write */ -+ dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: WRITE\n"); -+ dma_size = data->block[0] + 1; -+ dma_direction = DMA_TO_DEVICE; -+ desc->wr_len_cmd = dma_size; -+ desc->control |= ISMT_DESC_BLK; -+ dma_buffer[0] = command; -+ memcpy(&dma_buffer[1], &data->block[1], dma_size - 1); -+ } else { -+ /* Block Read */ -+ dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: READ\n"); -+ dma_size = I2C_SMBUS_BLOCK_MAX; -+ dma_direction = DMA_FROM_DEVICE; -+ desc->rd_len = dma_size; -+ desc->wr_len_cmd = command; -+ desc->control |= (ISMT_DESC_BLK | ISMT_DESC_CWRL); -+ } -+ break; -+ -+ case I2C_SMBUS_I2C_BLOCK_DATA: -+ /* Make sure the length is valid */ -+ if (data->block[0] < 1) -+ data->block[0] = 1; -+ -+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX) -+ data->block[0] = I2C_SMBUS_BLOCK_MAX; -+ -+ if (read_write == I2C_SMBUS_WRITE) { -+ /* i2c Block Write */ -+ dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: WRITE\n"); -+ dma_size = data->block[0] + 1; -+ dma_direction = DMA_TO_DEVICE; -+ desc->wr_len_cmd = dma_size; -+ desc->control |= ISMT_DESC_I2C; -+ dma_buffer[0] = command; -+ memcpy(&dma_buffer[1], &data->block[1], dma_size - 1); -+ } else { -+ /* i2c Block Read */ -+ dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: READ\n"); -+ dma_size = data->block[0]; -+ dma_direction = DMA_FROM_DEVICE; -+ desc->rd_len = dma_size; -+ desc->wr_len_cmd = command; -+ desc->control |= (ISMT_DESC_I2C | ISMT_DESC_CWRL); -+ /* -+ * Per the "Table 15-15. I2C Commands", -+ * in the External Design Specification (EDS), -+ * (Document Number: 508084, Revision: 2.0), -+ * the _rw bit must be 0 -+ */ -+ desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, 0); -+ } -+ break; -+ -+ default: -+ dev_err(dev, "Unsupported transaction %d\n", -+ size); -+ return -EOPNOTSUPP; -+ } -+ -+ /* map the data buffer */ -+ if (dma_size != 0) { -+ dev_dbg(dev, " dev=%p\n", dev); -+ dev_dbg(dev, " data=%p\n", data); -+ dev_dbg(dev, " dma_buffer=%p\n", dma_buffer); -+ dev_dbg(dev, " dma_size=%d\n", dma_size); -+ dev_dbg(dev, " dma_direction=%d\n", dma_direction); -+ -+ dma_addr = dma_map_single(dev, -+ dma_buffer, -+ dma_size, -+ dma_direction); -+ -+ if (dma_mapping_error(dev, dma_addr)) { -+ dev_err(dev, "Error in mapping dma buffer %p\n", -+ dma_buffer); -+ return -EIO; -+ } -+ -+ dev_dbg(dev, " dma_addr = %pad\n", &dma_addr); -+ -+ desc->dptr_low = lower_32_bits(dma_addr); -+ desc->dptr_high = upper_32_bits(dma_addr); -+ } -+ -+ reinit_completion(&priv->cmp); -+ -+ /* Add the descriptor */ -+ ismt_submit_desc(priv); -+ -+ /* Now we wait for interrupt completion, 1s */ -+ time_left = wait_for_completion_timeout(&priv->cmp, HZ*1); -+ -+ /* unmap the data buffer */ -+ if (dma_size != 0) -+ dma_unmap_single(dev, dma_addr, dma_size, dma_direction); -+ -+ if (unlikely(!time_left)) { -+ dev_warn(dev, "completion wait timed out:addr[%d-0x%x], read_write[%d], command[0x%x], size[%d]\n", -+ adap->nr, addr, read_write, command, size); -+ ismt_reset_dma(priv); -+ ret = -ETIMEDOUT; -+ priv->head = 0; -+ return ret; -+ } -+ -+ /* do any post processing of the descriptor here */ -+ ret = ismt_process_desc(desc, data, priv, size, read_write); -+ /* Update the ring pointer */ -+ priv->head++; -+ priv->head %= ISMT_DESC_ENTRIES; -+ -+ return ret; -+} -+ -+/** -+ * ismt_func() - report which i2c commands are supported by this adapter -+ * @adap: the i2c host adapter -+ */ -+static u32 ismt_func(struct i2c_adapter *adap) -+{ -+ return I2C_FUNC_SMBUS_QUICK | -+ I2C_FUNC_SMBUS_BYTE | -+ I2C_FUNC_SMBUS_BYTE_DATA | -+ I2C_FUNC_SMBUS_WORD_DATA | -+ I2C_FUNC_SMBUS_PROC_CALL | -+ I2C_FUNC_SMBUS_BLOCK_DATA | -+ I2C_FUNC_SMBUS_I2C_BLOCK | -+ I2C_FUNC_SMBUS_PEC; -+} -+ -+static const struct i2c_algorithm smbus_algorithm = { -+ .smbus_xfer = ismt_access, -+ .functionality = ismt_func, -+}; -+ -+/** -+ * ismt_handle_isr() - interrupt handler bottom half -+ * @priv: iSMT private data -+ */ -+static irqreturn_t ismt_handle_isr(struct ismt_priv *priv) -+{ -+ complete(&priv->cmp); -+ -+ return IRQ_HANDLED; -+} -+ -+/** -+ * ismt_do_interrupt() - IRQ interrupt handler -+ * @vec: interrupt vector -+ * @data: iSMT private data -+ */ -+static irqreturn_t ismt_do_interrupt(int vec, void *data) -+{ -+ u32 val; -+ struct ismt_priv *priv = data; -+ -+ /* -+ * check to see it's our interrupt, return IRQ_NONE if not ours -+ * since we are sharing interrupt -+ */ -+ val = readl(priv->smba + ISMT_MSTR_MSTS); -+ -+ if (!(val & (ISMT_MSTS_MIS | ISMT_MSTS_MEIS))) -+ return IRQ_NONE; -+ else -+ writel(val | ISMT_MSTS_MIS | ISMT_MSTS_MEIS, -+ priv->smba + ISMT_MSTR_MSTS); -+ -+ return ismt_handle_isr(priv); -+} -+ -+/** -+ * ismt_do_msi_interrupt() - MSI interrupt handler -+ * @vec: interrupt vector -+ * @data: iSMT private data -+ */ -+static irqreturn_t ismt_do_msi_interrupt(int vec, void *data) -+{ -+ return ismt_handle_isr(data); -+} -+ -+/** -+ * ismt_hw_init() - initialize the iSMT hardware -+ * @priv: iSMT private data -+ */ -+static void ismt_hw_init(struct ismt_priv *priv) -+{ -+ u32 val; -+ struct device *dev = &priv->pci_dev->dev; -+ -+ /* initialize the Master Descriptor Base Address (MDBA) */ -+ writeq(priv->io_rng_dma, priv->smba + ISMT_MSTR_MDBA); -+ -+ /* initialize the Master Control Register (MCTRL) */ -+ writel(ISMT_MCTRL_MEIE, priv->smba + ISMT_MSTR_MCTRL); -+ -+ /* initialize the Master Status Register (MSTS) */ -+ writel(0, priv->smba + ISMT_MSTR_MSTS); -+ -+ /* initialize the Master Descriptor Size (MDS) */ -+ val = readl(priv->smba + ISMT_MSTR_MDS); -+ writel((val & ~ISMT_MDS_MASK) | (ISMT_DESC_ENTRIES - 1), -+ priv->smba + ISMT_MSTR_MDS); -+ -+ /* -+ * Set the SMBus speed (could use this for slow HW debuggers) -+ */ -+ -+ val = readl(priv->smba + ISMT_SPGT); -+ -+ switch (bus_speed) { -+ case 0: -+ break; -+ -+ case 80: -+ dev_dbg(dev, "Setting SMBus clock to 80 kHz\n"); -+ writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_80K), -+ priv->smba + ISMT_SPGT); -+ break; -+ -+ case 100: -+ dev_dbg(dev, "Setting SMBus clock to 100 kHz\n"); -+ writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_100K), -+ priv->smba + ISMT_SPGT); -+ break; -+ -+ case 400: -+ dev_dbg(dev, "Setting SMBus clock to 400 kHz\n"); -+ writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_400K), -+ priv->smba + ISMT_SPGT); -+ break; -+ -+ case 1000: -+ dev_dbg(dev, "Setting SMBus clock to 1000 kHz\n"); -+ writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_1M), -+ priv->smba + ISMT_SPGT); -+ break; -+ -+ default: -+ dev_warn(dev, "Invalid SMBus clock speed, only 0, 80, 100, 400, and 1000 are valid\n"); -+ break; -+ } -+ -+ val = readl(priv->smba + ISMT_SPGT); -+ -+ switch (val & ISMT_SPGT_SPD_MASK) { -+ case ISMT_SPGT_SPD_80K: -+ bus_speed = 80; -+ break; -+ case ISMT_SPGT_SPD_100K: -+ bus_speed = 100; -+ break; -+ case ISMT_SPGT_SPD_400K: -+ bus_speed = 400; -+ break; -+ case ISMT_SPGT_SPD_1M: -+ bus_speed = 1000; -+ break; -+ } -+ dev_info(dev, "SMBus clock is running at %d kHz with delay %d us\n", bus_speed, delay); -+} -+ -+/** -+ * ismt_dev_init() - initialize the iSMT data structures -+ * @priv: iSMT private data -+ */ -+static int ismt_dev_init(struct ismt_priv *priv) -+{ -+ /* allocate memory for the descriptor */ -+ priv->hw = dmam_alloc_coherent(&priv->pci_dev->dev, -+ (ISMT_DESC_ENTRIES -+ * sizeof(struct ismt_desc)), -+ &priv->io_rng_dma, -+ GFP_KERNEL); -+ if (!priv->hw) -+ return -ENOMEM; -+ -+ priv->head = 0; -+ init_completion(&priv->cmp); -+ -+ return 0; -+} -+ -+/** -+ * ismt_int_init() - initialize interrupts -+ * @priv: iSMT private data -+ */ -+static int ismt_int_init(struct ismt_priv *priv) -+{ -+ int err; -+ -+ /* Try using MSI interrupts */ -+ err = pci_enable_msi(priv->pci_dev); -+ if (err) -+ goto intx; -+ -+ err = devm_request_irq(&priv->pci_dev->dev, -+ priv->pci_dev->irq, -+ ismt_do_msi_interrupt, -+ 0, -+ "ismt-msi", -+ priv); -+ if (err) { -+ pci_disable_msi(priv->pci_dev); -+ goto intx; -+ } -+ -+ return 0; -+ -+ /* Try using legacy interrupts */ -+intx: -+ dev_warn(&priv->pci_dev->dev, -+ "Unable to use MSI interrupts, falling back to legacy\n"); -+ -+ err = devm_request_irq(&priv->pci_dev->dev, -+ priv->pci_dev->irq, -+ ismt_do_interrupt, -+ IRQF_SHARED, -+ "ismt-intx", -+ priv); -+ if (err) { -+ dev_err(&priv->pci_dev->dev, "no usable interrupts\n"); -+ return err; -+ } -+ -+ return 0; -+} -+ -+static struct pci_driver ismt_driver; -+ -+/** -+ * ismt_probe() - probe for iSMT devices -+ * @pdev: PCI-Express device -+ * @id: PCI-Express device ID -+ */ -+static int -+ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ int err; -+ struct ismt_priv *priv; -+ unsigned long start, len; -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ pci_set_drvdata(pdev, priv); -+ -+ i2c_set_adapdata(&priv->adapter, priv); -+ priv->adapter.owner = THIS_MODULE; -+ priv->adapter.class = I2C_CLASS_HWMON; -+ priv->adapter.algo = &smbus_algorithm; -+ priv->adapter.dev.parent = &pdev->dev; -+ ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev)); -+ priv->adapter.retries = ISMT_MAX_RETRIES; -+ -+ priv->pci_dev = pdev; -+ -+ err = pcim_enable_device(pdev); -+ if (err) { -+ dev_err(&pdev->dev, "Failed to enable SMBus PCI device (%d)\n", -+ err); -+ return err; -+ } -+ -+ /* enable bus mastering */ -+ pci_set_master(pdev); -+ -+ /* Determine the address of the SMBus area */ -+ start = pci_resource_start(pdev, SMBBAR); -+ len = pci_resource_len(pdev, SMBBAR); -+ if (!start || !len) { -+ dev_err(&pdev->dev, -+ "SMBus base address uninitialized, upgrade BIOS\n"); -+ return -ENODEV; -+ } -+ -+ snprintf(priv->adapter.name, sizeof(priv->adapter.name), -+ "SMBus iSMT adapter at %lx", start); -+ -+ dev_dbg(&priv->pci_dev->dev, " start=0x%lX\n", start); -+ dev_dbg(&priv->pci_dev->dev, " len=0x%lX\n", len); -+ -+ err = acpi_check_resource_conflict(&pdev->resource[SMBBAR]); -+ if (err) { -+ dev_err(&pdev->dev, "ACPI resource conflict!\n"); -+ return err; -+ } -+ -+ err = pci_request_region(pdev, SMBBAR, ismt_driver.name); -+ if (err) { -+ dev_err(&pdev->dev, -+ "Failed to request SMBus region 0x%lx-0x%lx\n", -+ start, start + len); -+ return err; -+ } -+ -+ priv->smba = pcim_iomap(pdev, SMBBAR, len); -+ if (!priv->smba) { -+ dev_err(&pdev->dev, "Unable to ioremap SMBus BAR\n"); -+ return -ENODEV; -+ } -+ -+ if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) || -+ (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)) { -+ if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) || -+ (pci_set_consistent_dma_mask(pdev, -+ DMA_BIT_MASK(32)) != 0)) { -+ dev_err(&pdev->dev, "pci_set_dma_mask fail %p\n", -+ pdev); -+ return -ENODEV; -+ } -+ } -+ -+ err = ismt_dev_init(priv); -+ if (err) -+ return err; -+ -+ ismt_hw_init(priv); -+ -+ err = ismt_int_init(priv); -+ if (err) -+ return err; -+ -+ err = i2c_add_adapter(&priv->adapter); -+ if (err) -+ return -ENODEV; -+ dev_info(&pdev->dev, "wb-i2c-ismt probe ok.\n"); -+ return 0; -+} -+ -+/** -+ * ismt_remove() - release driver resources -+ * @pdev: PCI-Express device -+ */ -+static void ismt_remove(struct pci_dev *pdev) -+{ -+ struct ismt_priv *priv = pci_get_drvdata(pdev); -+ -+ i2c_del_adapter(&priv->adapter); -+} -+ -+static struct pci_driver ismt_driver = { -+ .name = "wb_ismt_smbus", -+ .id_table = ismt_ids, -+ .probe = ismt_probe, -+ .remove = ismt_remove, -+}; -+ -+module_pci_driver(ismt_driver); -+ -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Bill E. Brown "); -+MODULE_DESCRIPTION("Intel SMBus Message Transport (iSMT) driver"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.c -new file mode 100644 -index 000000000..f318234ae ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.c -@@ -0,0 +1,1332 @@ -+/* -+ * I2C multiplexer -+ * -+ * Copyright (c) 2008-2009 Rodolfo Giometti -+ * Copyright (c) 2008-2009 Eurotech S.p.A. -+ * -+ * This module supports the PCA954x series of I2C multiplexer/switch chips -+ * made by Philips Semiconductors. -+ * This includes the: -+ * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547 -+ * and PCA9548. -+ * -+ * These chips are all controlled via the I2C bus itself, and all have a -+ * single 8-bit register. The upstream "parent" bus fans out to two, -+ * four, or eight downstream busses or channels; which of these -+ * are selected is determined by the chip type and register contents. A -+ * mux can select only one sub-bus at a time; a switch can select any -+ * combination simultaneously. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "wb_i2c_mux_pca954x.h" -+ -+#define PCA954X_MAX_NCHANS 8 -+#define PCA954X_IRQ_OFFSET 4 -+ -+#define I2C_RETRY_TIMES 5 -+#define I2C_RETRY_WAIT_TIMES 10 /*delay 10ms*/ -+ -+typedef struct pca9548_cfg_info_s { -+ uint32_t pca9548_base_nr; -+ uint32_t pca9548_reset_type; -+ uint32_t rst_delay_b; /* delay time before reset(us) */ -+ uint32_t rst_delay; /* reset time(us) */ -+ uint32_t rst_delay_a; /* delay time after reset(us) */ -+ union { -+ i2c_attr_t i2c_attr; -+ gpio_attr_t gpio_attr; -+ io_attr_t io_attr; -+ file_attr_t file_attr; -+ } attr; -+ bool select_chan_check; -+ bool close_chan_force_reset; -+} pca9548_cfg_info_t; -+ -+int g_pca954x_debug = 0; -+int g_pca954x_error = 0; -+ -+module_param(g_pca954x_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_pca954x_error, int, S_IRUGO | S_IWUSR); -+ -+#define PCA954X_DEBUG(fmt, args...) do { \ -+ if (g_pca954x_debug) { \ -+ printk(KERN_INFO "[PCA95x][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define PCA954X_ERROR(fmt, args...) do { \ -+ if (g_pca954x_error) { \ -+ printk(KERN_ERR "[PCA95x][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+extern int pca9641_setmuxflag(int nr, int flag); -+enum pca_type { -+ pca_9540, -+ pca_9542, -+ pca_9543, -+ pca_9544, -+ pca_9545, -+ pca_9546, -+ pca_9547, -+ pca_9548, -+}; -+ -+struct chip_desc { -+ u8 nchans; -+ u8 enable; /* used for muxes only */ -+ u8 has_irq; -+ enum muxtype { -+ pca954x_ismux = 0, -+ pca954x_isswi -+ } muxtype; -+}; -+ -+struct pca954x { -+ const struct chip_desc *chip; -+ u8 last_chan; /* last register value */ -+ u8 deselect; -+ struct i2c_client *client; -+ struct irq_domain *irq; -+ unsigned int irq_mask; -+ raw_spinlock_t lock; -+ pca9548_cfg_info_t pca9548_cfg_info; /* pca9548 reset cfg */ -+}; -+ -+/* Provide specs for the PCA954x types we know about */ -+static const struct chip_desc chips[] = { -+ [pca_9540] = { -+ .nchans = 2, -+ .enable = 0x4, -+ .muxtype = pca954x_ismux, -+ }, -+ [pca_9542] = { -+ .nchans = 2, -+ .enable = 0x4, -+ .has_irq = 1, -+ .muxtype = pca954x_ismux, -+ }, -+ [pca_9543] = { -+ .nchans = 2, -+ .has_irq = 1, -+ .muxtype = pca954x_isswi, -+ }, -+ [pca_9544] = { -+ .nchans = 4, -+ .enable = 0x4, -+ .has_irq = 1, -+ .muxtype = pca954x_ismux, -+ }, -+ [pca_9545] = { -+ .nchans = 4, -+ .has_irq = 1, -+ .muxtype = pca954x_isswi, -+ }, -+ [pca_9546] = { -+ .nchans = 4, -+ .muxtype = pca954x_isswi, -+ }, -+ [pca_9547] = { -+ .nchans = 8, -+ .enable = 0x8, -+ .muxtype = pca954x_ismux, -+ }, -+ [pca_9548] = { -+ .nchans = 8, -+ .muxtype = pca954x_isswi, -+ }, -+}; -+ -+static const struct i2c_device_id pca954x_id[] = { -+ { "wb_pca9540", pca_9540 }, -+ { "wb_pca9542", pca_9542 }, -+ { "wb_pca9543", pca_9543 }, -+ { "wb_pca9544", pca_9544 }, -+ { "wb_pca9545", pca_9545 }, -+ { "wb_pca9546", pca_9546 }, -+ { "wb_pca9547", pca_9547 }, -+ { "wb_pca9548", pca_9548 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, pca954x_id); -+ -+#ifdef CONFIG_OF -+static const struct of_device_id pca954x_of_match[] = { -+ { .compatible = "nxp,wb_pca9540", .data = &chips[pca_9540] }, -+ { .compatible = "nxp,wb_pca9542", .data = &chips[pca_9542] }, -+ { .compatible = "nxp,wb_pca9543", .data = &chips[pca_9543] }, -+ { .compatible = "nxp,wb_pca9544", .data = &chips[pca_9544] }, -+ { .compatible = "nxp,wb_pca9545", .data = &chips[pca_9545] }, -+ { .compatible = "nxp,wb_pca9546", .data = &chips[pca_9546] }, -+ { .compatible = "nxp,wb_pca9547", .data = &chips[pca_9547] }, -+ { .compatible = "nxp,wb_pca9548", .data = &chips[pca_9548] }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, pca954x_of_match); -+#endif -+ -+/* 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 pca954x_reg_write(struct i2c_adapter *adap, -+ struct i2c_client *client, u8 val) -+{ -+ int ret = -ENODEV; -+ -+ if (adap->algo->master_xfer) { -+ struct i2c_msg msg; -+ char buf[1]; -+ -+ msg.addr = client->addr; -+ msg.flags = 0; -+ msg.len = 1; -+ buf[0] = val; -+ msg.buf = buf; -+ ret = __i2c_transfer(adap, &msg, 1); -+ -+ if (ret >= 0 && ret != 1) -+ ret = -EREMOTEIO; -+ } else { -+ union i2c_smbus_data data; -+ ret = adap->algo->smbus_xfer(adap, client->addr, -+ client->flags, -+ I2C_SMBUS_WRITE, -+ val, I2C_SMBUS_BYTE, &data); -+ } -+ return ret; -+} -+ -+static int pca954x_reg_read(struct i2c_adapter *adap, -+ struct i2c_client *client, u8 *val) -+{ -+ int ret = -ENODEV; -+ u8 tmp_val; -+ -+ if (adap->algo->master_xfer) { -+ struct i2c_msg msg; -+ -+ msg.addr = client->addr; -+ msg.flags = I2C_M_RD; -+ msg.len = 1; -+ msg.buf = &tmp_val; -+ ret = __i2c_transfer(adap, &msg, 1); -+ -+ if (ret >= 0 && ret != 1) { -+ ret = -EREMOTEIO; -+ } else { -+ *val = tmp_val; -+ } -+ } else { -+ union i2c_smbus_data data; -+ ret = adap->algo->smbus_xfer(adap, client->addr, -+ client->flags, -+ I2C_SMBUS_READ, -+ 0, I2C_SMBUS_BYTE, &data); -+ -+ if (!ret) { -+ tmp_val = data.byte; -+ *val = tmp_val; -+ } -+ } -+ -+ return ret; -+} -+ -+static int pca954x_setmuxflag(struct i2c_client *client, int flag) -+{ -+ int ret; -+ struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); -+ -+ ret = pca9641_setmuxflag(adap->nr, flag); -+ return ret; -+} -+ -+static int pca9548_gpio_init(gpio_attr_t *gpio_attr) -+{ -+ int err; -+ -+ if (gpio_attr->gpio_init) { -+ PCA954X_DEBUG("gpio%d already init, do nothing.\n", gpio_attr->gpio); -+ return 0; -+ } -+ -+ PCA954X_DEBUG("gpio%d init.\n", gpio_attr->gpio); -+ err = gpio_request(gpio_attr->gpio, "pca9548_reset"); -+ if (err) { -+ goto error; -+ } -+ err = gpio_direction_output(gpio_attr->gpio, gpio_attr->reset_off); -+ if (err) { -+ gpio_free(gpio_attr->gpio); -+ goto error; -+ } -+ gpio_attr->gpio_init = 1; -+ return 0; -+error: -+ PCA954X_ERROR("pca9548_gpio_init failed, ret:%d.\n", err); -+ return err; -+} -+ -+static void pca9548_gpio_free(gpio_attr_t *gpio_attr) -+{ -+ if (gpio_attr->gpio_init == 1) { -+ PCA954X_DEBUG("gpio%d release.\n", gpio_attr->gpio); -+ gpio_free(gpio_attr->gpio); -+ gpio_attr->gpio_init = 0; -+ } -+} -+ -+static int pca954x_reset_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) -+{ -+ int ret; -+ struct file *filp; -+ loff_t tmp_pos; -+ -+ filp = filp_open(path, O_RDONLY, 0); -+ if (IS_ERR(filp)) { -+ PCA954X_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); -+ filp = NULL; -+ goto exit; -+ } -+ -+ tmp_pos = (loff_t)pos; -+ ret = kernel_read(filp, val, size, &tmp_pos); -+ if (ret < 0) { -+ PCA954X_ERROR("kernel_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); -+ goto exit; -+ } -+ -+ filp_close(filp, NULL); -+ -+ return ret; -+ -+exit: -+ if (filp != NULL) { -+ filp_close(filp, NULL); -+ } -+ -+ return -1; -+} -+ -+static int pca954x_reset_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) -+{ -+ int ret; -+ struct file *filp; -+ loff_t tmp_pos; -+ -+ filp = filp_open(path, O_RDWR, 777); -+ if (IS_ERR(filp)) { -+ PCA954X_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); -+ filp = NULL; -+ goto exit; -+ } -+ -+ tmp_pos = (loff_t)pos; -+ ret = kernel_write(filp, val, size, &tmp_pos); -+ if (ret < 0) { -+ PCA954X_ERROR("kernel_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); -+ goto exit; -+ } -+ -+ vfs_fsync(filp, 1); -+ filp_close(filp, NULL); -+ -+ return ret; -+ -+exit: -+ if (filp != NULL) { -+ filp_close(filp, NULL); -+ } -+ -+ return -1; -+} -+ -+static int pca954x_reset_i2c_read(uint32_t bus, uint32_t addr, uint32_t offset_addr, -+ unsigned char *buf, uint32_t size) -+{ -+ struct file *fp; -+ struct i2c_client client; -+ char i2c_path[32]; -+ int i ,j ; -+ int rv; -+ -+ rv = 0; -+ mem_clear(i2c_path, sizeof(i2c_path)); -+ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); -+ fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); -+ if (IS_ERR(fp)) { -+ PCA954X_ERROR("i2c open fail.\n"); -+ return -1; -+ } -+ memcpy(&client, fp->private_data, sizeof(struct i2c_client)); -+ client.addr = addr; -+ for (j = 0 ;j < size ;j++) { -+ for (i = 0; i < I2C_RETRY_TIMES; i++) { -+ rv = i2c_smbus_read_byte_data(&client, (offset_addr + j)); -+ if (rv < 0) { -+ PCA954X_ERROR("i2c read failed, try again.\n"); -+ msleep(I2C_RETRY_WAIT_TIMES); -+ if (i >= (I2C_RETRY_TIMES - 1)) { -+ goto out; -+ } -+ continue; -+ } -+ *(buf + j) = (unsigned char)rv; -+ break; -+ } -+ } -+out: -+ filp_close(fp, NULL); -+ return rv; -+} -+ -+static int pca954x_reset_i2c_write(uint32_t bus, uint32_t dev_addr, uint32_t offset_addr, -+ uint8_t write_buf) -+{ -+ struct file *fp; -+ struct i2c_client client; -+ char i2c_path[32]; -+ int i; -+ int rv; -+ -+ rv = 0; -+ mem_clear(i2c_path, sizeof(i2c_path)); -+ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); -+ fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); -+ if (IS_ERR(fp)) { -+ PCA954X_ERROR("i2c open fail.\n"); -+ return -1; -+ } -+ memcpy(&client, fp->private_data, sizeof(struct i2c_client)); -+ client.addr = dev_addr; -+ for (i = 0; i < I2C_RETRY_TIMES; i++) { -+ rv = i2c_smbus_write_byte_data(&client, offset_addr, write_buf); -+ if (rv < 0) { -+ PCA954X_ERROR("i2c write failed, try again.\n"); -+ msleep(I2C_RETRY_WAIT_TIMES); -+ if (i >= (I2C_RETRY_TIMES - 1)) { -+ goto out; -+ } -+ continue; -+ } -+ break; -+ } -+out: -+ filp_close(fp, NULL); -+ return rv; -+} -+ -+static int pca954x_do_file_reset(struct i2c_mux_core *muxc) -+{ -+ int ret, timeout, err; -+ struct pca954x *data; -+ pca9548_cfg_info_t *reset_cfg; -+ file_attr_t *file_attr; -+ u8 val; -+ int udelay_cnt; -+ -+ data = i2c_mux_priv(muxc); -+ reset_cfg = &data->pca9548_cfg_info; -+ file_attr = &reset_cfg->attr.file_attr; -+ ret = -1; -+ -+ PCA954X_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", -+ reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); -+ PCA954X_DEBUG("dev_name:%s, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", -+ file_attr->dev_name, file_attr->offset, file_attr->mask, -+ file_attr->reset_on, file_attr->reset_off); -+ -+ if (reset_cfg->rst_delay_b) { -+ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); -+ } -+ -+ err = pca954x_reset_file_read(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); -+ if (err < 0) { -+ goto out; -+ } -+ val &= ~(file_attr->mask); -+ val |= file_attr->reset_on; -+ err = pca954x_reset_file_write(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); -+ if (err < 0) { -+ goto out; -+ } -+ -+ if (reset_cfg->rst_delay) { -+ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); -+ } -+ -+ val &= ~(file_attr->mask); -+ val |= file_attr->reset_off; -+ err = pca954x_reset_file_write(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); -+ if (err < 0) { -+ goto out; -+ } -+ -+ udelay_cnt = 0; -+ timeout = reset_cfg->rst_delay_a; -+ while (timeout > 0) { -+ usleep_range(1, 2); -+ err = pca954x_reset_file_read(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); -+ if (err < 0) { -+ goto out; -+ } -+ val &= (file_attr->mask); -+ if (val == file_attr->reset_off) { -+ ret = 0; -+ PCA954X_DEBUG("pca954x_do_file_reset success.\n"); -+ break; -+ } -+ udelay_cnt++; -+ if ((udelay_cnt % 1000) == 0) { -+ /* 1MS schedule*/ -+ schedule(); -+ } -+ timeout--; -+ } -+ if (ret < 0) { -+ PCA954X_ERROR("pca954x_do_file_reset timeout.\n"); -+ } -+out: -+ if (err < 0) { -+ PCA954X_ERROR("pca954x_do_file_reset file rd/wr failed, ret:%d.\n", err); -+ } -+ -+ return ret; -+} -+ -+static int pca954x_do_io_reset(struct i2c_mux_core *muxc) -+{ -+ int ret, timeout; -+ struct pca954x *data; -+ pca9548_cfg_info_t *reset_cfg; -+ io_attr_t *io_attr; -+ u8 val; -+ int udelay_cnt; -+ -+ data = i2c_mux_priv(muxc); -+ reset_cfg = &data->pca9548_cfg_info; -+ io_attr = &reset_cfg->attr.io_attr; -+ -+ PCA954X_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", -+ reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); -+ PCA954X_DEBUG("io_addr:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", -+ io_attr->io_addr, io_attr->mask, io_attr->reset_on, io_attr->reset_off); -+ -+ if (reset_cfg->rst_delay_b) { -+ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); -+ } -+ -+ val = inb(io_attr->io_addr); -+ val &= ~(io_attr->mask); -+ val |= io_attr->reset_on; -+ outb(val, io_attr->io_addr); -+ -+ if (reset_cfg->rst_delay) { -+ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); -+ } -+ -+ val &= ~(io_attr->mask); -+ val |= io_attr->reset_off; -+ outb(val, io_attr->io_addr); -+ -+ ret = -1; -+ udelay_cnt = 0; -+ timeout = reset_cfg->rst_delay_a; -+ while (timeout > 0) { -+ usleep_range(1, 2); -+ val = inb(io_attr->io_addr); -+ val &= (io_attr->mask); -+ if (val == io_attr->reset_off) { -+ ret = 0; -+ PCA954X_DEBUG("pca954x_do_io_reset success.\n"); -+ break; -+ } -+ udelay_cnt++; -+ if ((udelay_cnt % 1000) == 0) { -+ /* 1MS schedule*/ -+ schedule(); -+ } -+ timeout--; -+ } -+ -+ if (ret < 0) { -+ PCA954X_ERROR("pca954x_do_io_reset timeout.\n"); -+ } -+ -+ return ret; -+} -+ -+static int pca954x_do_gpio_reset(struct i2c_mux_core *muxc) -+{ -+ int ret, timeout; -+ struct pca954x *data; -+ pca9548_cfg_info_t *reset_cfg; -+ gpio_attr_t *gpio_attr; -+ u8 val; -+ int udelay_cnt; -+ -+ data = i2c_mux_priv(muxc); -+ reset_cfg = &data->pca9548_cfg_info; -+ gpio_attr = &reset_cfg->attr.gpio_attr; -+ -+ ret = pca9548_gpio_init(gpio_attr); -+ if (ret) { -+ return -1; -+ } -+ -+ if (reset_cfg->rst_delay_b) { -+ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); -+ } -+ -+ /* reset on */ -+ __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_on); -+ -+ if (reset_cfg->rst_delay) { -+ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); -+ } -+ -+ /* reset off */ -+ __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_off); -+ ret = -1; -+ udelay_cnt = 0; -+ timeout = reset_cfg->rst_delay_a; -+ while (timeout > 0) { -+ usleep_range(1, 2); -+ val = __gpio_get_value(gpio_attr->gpio); -+ if (val == gpio_attr->reset_off) { -+ ret = 0; -+ PCA954X_DEBUG("pca954x_do_gpio_reset success.\n"); -+ break; -+ } -+ udelay_cnt++; -+ if ((udelay_cnt % 1000) == 0) { -+ /* 1MS schedule*/ -+ schedule(); -+ } -+ timeout--; -+ } -+ -+ if (ret < 0) { -+ PCA954X_ERROR("pca954x_do_gpio_reset timeout.\n"); -+ } -+ -+ pca9548_gpio_free(gpio_attr); -+ return ret; -+} -+ -+static int pca954x_do_i2c_reset(struct i2c_mux_core *muxc) -+{ -+ int ret, timeout, err; -+ struct pca954x *data; -+ pca9548_cfg_info_t *reset_cfg; -+ i2c_attr_t *i2c_attr; -+ u8 val; -+ int udelay_cnt; -+ -+ data = i2c_mux_priv(muxc); -+ reset_cfg = &data->pca9548_cfg_info; -+ i2c_attr = &reset_cfg->attr.i2c_attr; -+ ret = -1; -+ -+ PCA954X_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", -+ reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); -+ PCA954X_DEBUG("bus:0x%x, addr:0x%x, reg:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", -+ i2c_attr->i2c_bus, i2c_attr->i2c_addr, i2c_attr->reg_offset, -+ i2c_attr->mask, i2c_attr->reset_on, i2c_attr->reset_off); -+ -+ if (reset_cfg->rst_delay_b) { -+ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); -+ } -+ -+ err = pca954x_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, -+ i2c_attr->reg_offset, &val, sizeof(val)); -+ if (err < 0) { -+ goto out; -+ } -+ val &= ~(i2c_attr->mask); -+ val |= i2c_attr->reset_on; -+ err = pca954x_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, -+ i2c_attr->reg_offset, val); -+ if (err < 0) { -+ goto out; -+ } -+ -+ if (reset_cfg->rst_delay) { -+ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); -+ } -+ -+ val &= ~(i2c_attr->mask); -+ val |= i2c_attr->reset_off; -+ err = pca954x_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, -+ i2c_attr->reg_offset, val); -+ if (err < 0) { -+ goto out; -+ } -+ -+ udelay_cnt = 0; -+ timeout = reset_cfg->rst_delay_a; -+ while (timeout > 0) { -+ usleep_range(1, 2); -+ err = pca954x_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, -+ i2c_attr->reg_offset, &val, sizeof(val)); -+ if (err < 0) { -+ goto out; -+ } -+ val &= (i2c_attr->mask); -+ if (val == i2c_attr->reset_off) { -+ ret = 0; -+ PCA954X_DEBUG("pca954x_do_i2c_reset success.\n"); -+ break; -+ } -+ udelay_cnt++; -+ if ((udelay_cnt % 1000) == 0) { -+ /* 1MS schedule*/ -+ schedule(); -+ } -+ timeout--; -+ } -+ if (ret < 0) { -+ PCA954X_ERROR("pca954x_do_i2c_reset timeout.\n"); -+ } -+out: -+ if (err < 0) { -+ PCA954X_ERROR("pca954x_do_i2c_reset i2c op failed, ret:%d.\n", err); -+ } -+ return ret; -+} -+ -+static int pca954x_do_reset(struct i2c_mux_core *muxc) -+{ -+ int ret; -+ struct pca954x *data; -+ -+ data = i2c_mux_priv(muxc); -+ if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_NONE) { -+ ret = -1; -+ PCA954X_DEBUG("Don't need to reset.\n"); -+ } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_I2C) { -+ ret = pca954x_do_i2c_reset(muxc); -+ } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_GPIO) { -+ ret = pca954x_do_gpio_reset(muxc); -+ } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_IO) { -+ ret = pca954x_do_io_reset(muxc); -+ } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_FILE) { -+ ret = pca954x_do_file_reset(muxc); -+ } else { -+ ret = -1; -+ PCA954X_ERROR("Unsupport reset type:0x%x.\n", -+ data->pca9548_cfg_info.pca9548_reset_type); -+ } -+ -+ if (ret < 0) { -+ PCA954X_ERROR("pca9548_reset_ctrl failed, reset type:%u, ret:%d.\n", -+ data->pca9548_cfg_info.pca9548_reset_type, ret); -+ } -+ return ret; -+} -+ -+static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) -+{ -+ struct pca954x *data = i2c_mux_priv(muxc); -+ struct i2c_client *client = data->client; -+ const struct chip_desc *chip = data->chip; -+ u8 regval; -+ int ret = 0; -+ u8 read_val = 0; -+ int rv; -+ -+ /* we make switches look like muxes, not sure how to be smarter */ -+ if (chip->muxtype == pca954x_ismux) -+ regval = chan | chip->enable; -+ else -+ regval = 1 << chan; -+ -+ /* Only select the channel if its different from the last channel */ -+ if (data->last_chan != regval) { -+ pca954x_setmuxflag(client, 0); -+ ret = pca954x_reg_write(muxc->parent, client, regval); -+ data->last_chan = ret < 0 ? 0 : regval; -+ } -+ -+ if (data->pca9548_cfg_info.select_chan_check) { /* check chan */ -+ ret = pca954x_reg_read(muxc->parent, client, &read_val); -+ /* read failed or chan not open, reset pca9548 */ -+ if ((ret < 0) || (read_val != data->last_chan)) { -+ dev_warn(&client->dev, "pca954x open channle %u failed, do reset.\n", chan); -+ PCA954X_DEBUG("ret = %d, read_val = %d, last_chan = %d.\n", ret, read_val, data->last_chan); -+ rv = pca954x_do_reset(muxc); -+ if (rv >= 0) { -+ PCA954X_DEBUG("pca954x_do_reset success, rv = %d.\n", rv); -+ } else { -+ PCA954X_DEBUG("pca954x_do_reset failed, rv = %d.\n", rv); -+ } -+ if (ret >= 0) { -+ ret = -EIO; /* chan not match, return IO error */ -+ } -+ } -+ } -+ -+ return ret; -+} -+ -+static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan) -+{ -+ struct pca954x *data = i2c_mux_priv(muxc); -+ struct i2c_client *client = data->client; -+ int ret, rv; -+ -+ /* Deselect active channel */ -+ data->last_chan = 0; -+ if (data->pca9548_cfg_info.close_chan_force_reset) { -+ ret = pca954x_do_reset(muxc); -+ } else { -+ ret = pca954x_reg_write(muxc->parent, client, data->last_chan); -+ if (ret < 0 ) { -+ dev_warn(&client->dev, "pca954x close channel %u failed, do reset.\n", chan); -+ rv = pca954x_do_reset(muxc); -+ if (rv == 0) { -+ ret = 0; -+ } -+ } -+ } -+ -+ rv = pca954x_setmuxflag(client, 1); -+ if (rv == 0) { -+ PCA954X_DEBUG("match 9641, close 9548 channel to deselect 9641.\n"); -+ (void)pca954x_reg_write(muxc->parent, client, data->last_chan); -+ } else { -+ PCA954X_DEBUG("dismatch 9641, do nothing.\n"); -+ } -+ -+ return ret; -+ -+} -+ -+static irqreturn_t pca954x_irq_handler(int irq, void *dev_id) -+{ -+ struct pca954x *data = dev_id; -+ unsigned int child_irq; -+ int ret, i, handled = 0; -+ -+ ret = i2c_smbus_read_byte(data->client); -+ if (ret < 0) -+ return IRQ_NONE; -+ -+ for (i = 0; i < data->chip->nchans; i++) { -+ if (ret & BIT(PCA954X_IRQ_OFFSET + i)) { -+ child_irq = irq_linear_revmap(data->irq, i); -+ handle_nested_irq(child_irq); -+ handled++; -+ } -+ } -+ return handled ? IRQ_HANDLED : IRQ_NONE; -+} -+ -+static void pca954x_irq_mask(struct irq_data *idata) -+{ -+ struct pca954x *data = irq_data_get_irq_chip_data(idata); -+ unsigned int pos = idata->hwirq; -+ unsigned long flags; -+ -+ raw_spin_lock_irqsave(&data->lock, flags); -+ -+ data->irq_mask &= ~BIT(pos); -+ if (!data->irq_mask) -+ disable_irq(data->client->irq); -+ -+ raw_spin_unlock_irqrestore(&data->lock, flags); -+} -+ -+static void pca954x_irq_unmask(struct irq_data *idata) -+{ -+ struct pca954x *data = irq_data_get_irq_chip_data(idata); -+ unsigned int pos = idata->hwirq; -+ unsigned long flags; -+ -+ raw_spin_lock_irqsave(&data->lock, flags); -+ -+ if (!data->irq_mask) -+ enable_irq(data->client->irq); -+ data->irq_mask |= BIT(pos); -+ -+ raw_spin_unlock_irqrestore(&data->lock, flags); -+} -+ -+static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) -+{ -+ if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_LOW) -+ return -EINVAL; -+ return 0; -+} -+ -+static struct irq_chip pca954x_irq_chip = { -+ .name = "i2c-mux-pca954x", -+ .irq_mask = pca954x_irq_mask, -+ .irq_unmask = pca954x_irq_unmask, -+ .irq_set_type = pca954x_irq_set_type, -+}; -+ -+static int of_pca954x_irq_setup(struct i2c_mux_core *muxc) -+{ -+ struct pca954x *data = i2c_mux_priv(muxc); -+ struct i2c_client *client = data->client; -+ int c, err, irq; -+ -+ if (!data->chip->has_irq || client->irq <= 0) -+ return 0; -+ -+ raw_spin_lock_init(&data->lock); -+ -+ data->irq = irq_domain_add_linear(client->dev.of_node, -+ data->chip->nchans, -+ &irq_domain_simple_ops, data); -+ if (!data->irq) -+ return -ENODEV; -+ -+ for (c = 0; c < data->chip->nchans; c++) { -+ irq = irq_create_mapping(data->irq, c); -+ irq_set_chip_data(irq, data); -+ irq_set_chip_and_handler(irq, &pca954x_irq_chip, -+ handle_simple_irq); -+ } -+ -+ err = devm_request_threaded_irq(&client->dev, data->client->irq, NULL, -+ pca954x_irq_handler, -+ IRQF_ONESHOT | IRQF_SHARED, -+ "pca954x", data); -+ if (err) -+ goto err_req_irq; -+ -+ disable_irq(data->client->irq); -+ -+ return 0; -+err_req_irq: -+ for (c = 0; c < data->chip->nchans; c++) { -+ irq = irq_find_mapping(data->irq, c); -+ irq_dispose_mapping(irq); -+ } -+ irq_domain_remove(data->irq); -+ -+ return err; -+} -+ -+static int pca954x_irq_setup(struct i2c_mux_core *muxc) -+{ -+ return 0; -+} -+ -+static int of_pca954x_reset_data_init(struct pca954x *data) -+{ -+ int err; -+ struct device *dev = &data->client->dev; -+ pca9548_cfg_info_t *reset_cfg; -+ -+ reset_cfg = &data->pca9548_cfg_info; -+ if (dev == NULL || dev->of_node == NULL) { -+ PCA954X_DEBUG("dev or dev->of_node is NUll, no reset.\n"); -+ reset_cfg->pca9548_reset_type = PCA9548_RESET_NONE; -+ return 0; -+ } -+ -+ reset_cfg->select_chan_check = of_property_read_bool(dev->of_node, "select_chan_check"); -+ reset_cfg->close_chan_force_reset = of_property_read_bool(dev->of_node, "close_chan_force_reset"); -+ PCA954X_DEBUG("select_chan_check:%d, close_chan_force_reset:%d.\n", reset_cfg->select_chan_check, -+ reset_cfg->close_chan_force_reset); -+ -+ if (of_property_read_u32(dev->of_node, "pca9548_reset_type", &reset_cfg->pca9548_reset_type)) { -+ -+ PCA954X_DEBUG("pca9548_reset_type not found, no reset.\n"); -+ reset_cfg->pca9548_reset_type = PCA9548_RESET_NONE; -+ return 0; -+ } -+ err = of_property_read_u32(dev->of_node, "rst_delay_b", &reset_cfg->rst_delay_b); -+ err |= of_property_read_u32(dev->of_node, "rst_delay", &reset_cfg->rst_delay); -+ err |= of_property_read_u32(dev->of_node, "rst_delay_a", &reset_cfg->rst_delay_a); -+ -+ if (err) { -+ goto dts_config_err; -+ } -+ PCA954X_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", -+ reset_cfg->pca9548_reset_type, reset_cfg->rst_delay_b, -+ reset_cfg->rst_delay, reset_cfg->rst_delay_a); -+ -+ if (reset_cfg->pca9548_reset_type == PCA9548_RESET_I2C) { -+ -+ PCA954X_DEBUG("reset by i2c.\n"); -+ err = of_property_read_u32(dev->of_node, "i2c_bus", &reset_cfg->attr.i2c_attr.i2c_bus); -+ err |=of_property_read_u32(dev->of_node, "i2c_addr", &reset_cfg->attr.i2c_attr.i2c_addr); -+ err |=of_property_read_u32(dev->of_node, "reg_offset", &reset_cfg->attr.i2c_attr.reg_offset); -+ err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.i2c_attr.mask); -+ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.i2c_attr.reset_on); -+ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.i2c_attr.reset_off); -+ if (err) { -+ goto dts_config_err; -+ } -+ PCA954X_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", -+ reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, -+ reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, -+ reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); -+ } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_GPIO) { -+ -+ PCA954X_DEBUG("reset by gpio.\n"); -+ err = of_property_read_u32(dev->of_node, "gpio", &reset_cfg->attr.gpio_attr.gpio); -+ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.gpio_attr.reset_on); -+ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.gpio_attr.reset_off); -+ if (err) { -+ goto dts_config_err; -+ } -+ PCA954X_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", -+ reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, -+ reset_cfg->attr.gpio_attr.reset_off); -+ reset_cfg->attr.gpio_attr.gpio_init = 0; -+ } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_IO) { -+ -+ PCA954X_DEBUG("reset by io.\n"); -+ err = of_property_read_u32(dev->of_node, "io_addr", &reset_cfg->attr.io_attr.io_addr); -+ err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.io_attr.mask); -+ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.io_attr.reset_on); -+ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.io_attr.reset_off); -+ if (err) { -+ goto dts_config_err; -+ } -+ PCA954X_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", -+ reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, -+ reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); -+ } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_FILE) { -+ -+ PCA954X_DEBUG("reset by file.\n"); -+ err = of_property_read_string(dev->of_node, "dev_name", &reset_cfg->attr.file_attr.dev_name); -+ err |=of_property_read_u32(dev->of_node, "offset", &reset_cfg->attr.file_attr.offset); -+ err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.file_attr.mask); -+ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.file_attr.reset_on); -+ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.file_attr.reset_off); -+ if (err) { -+ goto dts_config_err; -+ } -+ PCA954X_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", -+ reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, -+ reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off); -+ } else { -+ PCA954X_ERROR("Unsupport reset type:%d.\n", reset_cfg->pca9548_reset_type); -+ goto dts_config_err; -+ } -+ return 0; -+dts_config_err: -+ PCA954X_ERROR("dts config error, ret:%d.\n", err); -+ return -EINVAL; -+} -+ -+static int pca954x_reset_data_init(struct pca954x *data) -+{ -+ pca9548_cfg_info_t *reset_cfg; -+ i2c_mux_pca954x_device_t *i2c_mux_pca954x_device; -+ -+ if (data->client->dev.platform_data == NULL) { -+ PCA954X_DEBUG("pca954x has no reset platform data config.\n"); -+ return 0; -+ } -+ reset_cfg = &data->pca9548_cfg_info; -+ i2c_mux_pca954x_device = data->client->dev.platform_data; -+ reset_cfg->select_chan_check = i2c_mux_pca954x_device->select_chan_check; -+ reset_cfg->close_chan_force_reset = i2c_mux_pca954x_device->close_chan_force_reset; -+ PCA954X_DEBUG("select_chan_check:%d, close_chan_force_reset:%d.\n", reset_cfg->select_chan_check, -+ reset_cfg->close_chan_force_reset); -+ -+ reset_cfg->pca9548_reset_type = i2c_mux_pca954x_device->pca9548_reset_type; -+ if (reset_cfg->pca9548_reset_type == PCA9548_RESET_NONE) { -+ PCA954X_DEBUG("pca9548_reset_type not found, no reset.\n"); -+ return 0; -+ } -+ -+ reset_cfg->rst_delay_b = i2c_mux_pca954x_device->rst_delay_b; -+ reset_cfg->rst_delay = i2c_mux_pca954x_device->rst_delay; -+ reset_cfg->rst_delay_a = i2c_mux_pca954x_device->rst_delay_a; -+ PCA954X_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", -+ reset_cfg->pca9548_reset_type, reset_cfg->rst_delay_b, -+ reset_cfg->rst_delay, reset_cfg->rst_delay_a); -+ -+ if (reset_cfg->pca9548_reset_type == PCA9548_RESET_I2C) { -+ -+ PCA954X_DEBUG("reset by i2c.\n"); -+ reset_cfg->attr.i2c_attr.i2c_bus = i2c_mux_pca954x_device->attr.i2c_attr.i2c_bus; -+ reset_cfg->attr.i2c_attr.i2c_addr = i2c_mux_pca954x_device->attr.i2c_attr.i2c_addr; -+ reset_cfg->attr.i2c_attr.reg_offset = i2c_mux_pca954x_device->attr.i2c_attr.reg_offset; -+ reset_cfg->attr.i2c_attr.mask = i2c_mux_pca954x_device->attr.i2c_attr.mask; -+ reset_cfg->attr.i2c_attr.reset_on = i2c_mux_pca954x_device->attr.i2c_attr.reset_on; -+ reset_cfg->attr.i2c_attr.reset_off = i2c_mux_pca954x_device->attr.i2c_attr.reset_off; -+ PCA954X_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", -+ reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, -+ reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, -+ reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); -+ } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_GPIO) { -+ -+ PCA954X_DEBUG("reset by gpio.\n"); -+ reset_cfg->attr.gpio_attr.gpio = i2c_mux_pca954x_device->attr.gpio_attr.gpio; -+ reset_cfg->attr.gpio_attr.reset_on = i2c_mux_pca954x_device->attr.gpio_attr.reset_on; -+ reset_cfg->attr.gpio_attr.reset_off = i2c_mux_pca954x_device->attr.gpio_attr.reset_off; -+ PCA954X_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", -+ reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, -+ reset_cfg->attr.gpio_attr.reset_off); -+ reset_cfg->attr.gpio_attr.gpio_init = 0; -+ } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_IO) { -+ -+ PCA954X_DEBUG("reset by io.\n"); -+ reset_cfg->attr.io_attr.io_addr = i2c_mux_pca954x_device->attr.io_attr.io_addr; -+ reset_cfg->attr.io_attr.mask = i2c_mux_pca954x_device->attr.io_attr.mask; -+ reset_cfg->attr.io_attr.reset_on = i2c_mux_pca954x_device->attr.io_attr.reset_on; -+ reset_cfg->attr.io_attr.reset_off = i2c_mux_pca954x_device->attr.io_attr.reset_off; -+ PCA954X_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", -+ reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, -+ reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); -+ } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_FILE) { -+ -+ reset_cfg->attr.file_attr.dev_name = i2c_mux_pca954x_device->attr.file_attr.dev_name; -+ reset_cfg->attr.file_attr.offset = i2c_mux_pca954x_device->attr.file_attr.offset; -+ reset_cfg->attr.file_attr.mask = i2c_mux_pca954x_device->attr.file_attr.mask; -+ reset_cfg->attr.file_attr.reset_on = i2c_mux_pca954x_device->attr.file_attr.reset_on; -+ reset_cfg->attr.file_attr.reset_off = i2c_mux_pca954x_device->attr.file_attr.reset_off; -+ PCA954X_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", -+ reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, -+ reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off); -+ } else { -+ PCA954X_ERROR("Unsupport reset type:%d.\n", reset_cfg->pca9548_reset_type); -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+/* -+ * I2C init/probing/exit functions -+ */ -+static int pca954x_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); -+ struct device_node *of_node = client->dev.of_node; -+ bool idle_disconnect_dt; -+ struct gpio_desc *gpio; -+ int num, force, class; -+ struct i2c_mux_core *muxc; -+ struct pca954x *data; -+ const struct of_device_id *match; -+ unsigned int probe_disable; -+ int ret, dynamic_nr; -+ i2c_mux_pca954x_device_t *i2c_mux_pca954x_device; -+ -+ PCA954X_DEBUG("pca954x_probe, parent bus: %d, 9548 addr:0x%x.\n", adap->nr, client->addr); -+ -+ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) -+ return -ENODEV; -+ -+ muxc = i2c_mux_alloc(adap, &client->dev, -+ PCA954X_MAX_NCHANS, sizeof(*data), 0, -+ pca954x_select_chan, pca954x_deselect_mux); -+ if (!muxc) -+ return -ENOMEM; -+ data = i2c_mux_priv(muxc); -+ -+ i2c_set_clientdata(client, muxc); -+ data->client = client; -+ -+ /* Get the mux out of reset if a reset GPIO is specified. */ -+ gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); -+ if (IS_ERR(gpio)) -+ return PTR_ERR(gpio); -+ -+ /* check device connection status */ -+ -+ if (client->dev.of_node == NULL) { -+ if (client->dev.platform_data == NULL) { -+ probe_disable = 1; -+ PCA954X_DEBUG("has no platform data config, set probe_disable = 1.\n"); -+ } else { -+ i2c_mux_pca954x_device = client->dev.platform_data; -+ probe_disable = i2c_mux_pca954x_device->probe_disable; -+ } -+ } else { -+ probe_disable = of_property_read_bool(of_node, "probe_disable"); -+ } -+ -+ /* Write the mux register at addr to verify -+ * that the mux is in fact present. This also -+ * initializes the mux to disconnected state. -+ */ -+ if (!probe_disable && (i2c_smbus_write_byte(client, 0) < 0)) { -+ dev_warn(&client->dev, "probe failed\n"); -+ return -ENODEV; -+ } -+ -+ match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); -+ if (match) -+ data->chip = of_device_get_match_data(&client->dev); -+ else -+ data->chip = &chips[id->driver_data]; -+ -+ data->last_chan = 0; /* force the first selection */ -+ -+ if (client->dev.of_node == NULL) { -+ idle_disconnect_dt = false; -+ } else { -+ idle_disconnect_dt = of_node && -+ of_property_read_bool(of_node, "i2c-mux-idle-disconnect"); -+ } -+ -+ if (client->dev.of_node) { -+ ret= of_pca954x_reset_data_init(data); -+ } else { -+ ret= pca954x_reset_data_init(data); -+ } -+ if (ret < 0) { -+ dev_err(&client->dev, "pca954x reset config err, ret:%d.\n", ret); -+ return ret; -+ } -+ -+ if (client->dev.of_node) { -+ ret = of_pca954x_irq_setup(muxc); -+ } else { -+ ret = pca954x_irq_setup(muxc); -+ } -+ if (ret) { -+ goto fail_del_adapters; -+ } -+ -+ if (client->dev.of_node == NULL) { -+ if (client->dev.platform_data == NULL) { -+ dynamic_nr = 1; -+ PCA954X_DEBUG("platform data is NULL, use dynamic adap number.\n"); -+ } else { -+ i2c_mux_pca954x_device = client->dev.platform_data; -+ data->pca9548_cfg_info.pca9548_base_nr = i2c_mux_pca954x_device->pca9548_base_nr; -+ if (data->pca9548_cfg_info.pca9548_base_nr == 0) { -+ dynamic_nr = 1; -+ PCA954X_DEBUG("pca9548_base_nr = 0, use dynamic adap number.\n"); -+ } else { -+ dynamic_nr = 0; -+ PCA954X_DEBUG("pca9548_base_nr:%u.\n", data->pca9548_cfg_info.pca9548_base_nr); -+ } -+ } -+ } else { -+ if (of_property_read_u32(of_node, "pca9548_base_nr", &data->pca9548_cfg_info.pca9548_base_nr)) { -+ -+ dynamic_nr = 1; -+ PCA954X_DEBUG("pca9548_base_nr not found, use dynamic adap number"); -+ } else { -+ dynamic_nr = 0; -+ PCA954X_DEBUG("pca9548_base_nr:%u.\n", data->pca9548_cfg_info.pca9548_base_nr); -+ } -+ } -+ -+ /* Now create an adapter for each channel */ -+ for (num = 0; num < data->chip->nchans; num++) { -+ bool idle_disconnect_pd = false; -+ if (dynamic_nr == 1) { -+ force = 0; /* dynamic adap number */ -+ } else { -+ force = data->pca9548_cfg_info.pca9548_base_nr + num; -+ } -+ -+ class = 0; /* no class by default */ -+ data->deselect |= (idle_disconnect_pd || -+ idle_disconnect_dt) << num; -+ -+ ret = i2c_mux_add_adapter(muxc, force, num, class); -+ if (ret) -+ goto fail_del_adapters; -+ } -+ -+ dev_info(&client->dev, -+ "registered %d multiplexed busses for I2C %s %s\n", -+ num, data->chip->muxtype == pca954x_ismux -+ ? "mux" : "switch", client->name); -+ -+ return 0; -+ -+fail_del_adapters: -+ i2c_mux_del_adapters(muxc); -+ return ret; -+} -+ -+static int pca954x_remove(struct i2c_client *client) -+{ -+ struct i2c_mux_core *muxc = i2c_get_clientdata(client); -+ struct pca954x *data = i2c_mux_priv(muxc); -+ int c, irq; -+ -+ if (data->irq) { -+ for (c = 0; c < data->chip->nchans; c++) { -+ irq = irq_find_mapping(data->irq, c); -+ irq_dispose_mapping(irq); -+ } -+ irq_domain_remove(data->irq); -+ } -+ -+ i2c_mux_del_adapters(muxc); -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int pca954x_resume(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct i2c_mux_core *muxc = i2c_get_clientdata(client); -+ struct pca954x *data = i2c_mux_priv(muxc); -+ -+ data->last_chan = 0; -+ return i2c_smbus_write_byte(client, 0); -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(pca954x_pm, NULL, pca954x_resume); -+ -+static struct i2c_driver pca954x_driver = { -+ .driver = { -+ .name = "wb_pca954x", -+ .pm = &pca954x_pm, -+ .of_match_table = of_match_ptr(pca954x_of_match), -+ }, -+ .probe = pca954x_probe, -+ .remove = pca954x_remove, -+ .id_table = pca954x_id, -+}; -+ -+module_i2c_driver(pca954x_driver); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("PCA954x I2C mux/switch driver"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.h -new file mode 100644 -index 000000000..9cbe16278 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca954x.h -@@ -0,0 +1,67 @@ -+#ifndef __WB_I2C_MUX_PCA954X_H__ -+#define __WB_I2C_MUX_PCA954X_H__ -+ -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+ -+typedef enum pca9548_reset_type_s { -+ PCA9548_RESET_NONE = 0, -+ PCA9548_RESET_I2C = 1, -+ PCA9548_RESET_GPIO = 2, -+ PCA9548_RESET_IO = 3, -+ PCA9548_RESET_FILE = 4, -+} pca9548_reset_type_t; -+ -+typedef struct i2c_attr_s { -+ uint32_t i2c_bus; -+ uint32_t i2c_addr; -+ uint32_t reg_offset; -+ uint32_t mask; -+ uint32_t reset_on; -+ uint32_t reset_off; -+} i2c_attr_t; -+ -+typedef struct io_attr_s { -+ uint32_t io_addr; -+ uint32_t mask; -+ uint32_t reset_on; -+ uint32_t reset_off; -+} io_attr_t; -+ -+typedef struct file_attr_s { -+ const char *dev_name; -+ uint32_t offset; -+ uint32_t mask; -+ uint32_t reset_on; -+ uint32_t reset_off; -+} file_attr_t; -+ -+typedef struct gpio_attr_s { -+ int gpio_init; -+ uint32_t gpio; -+ uint32_t reset_on; -+ uint32_t reset_off; -+} gpio_attr_t; -+ -+typedef struct i2c_mux_pca954x_device_s { -+ struct i2c_client *client; -+ uint32_t i2c_bus; -+ uint32_t i2c_addr; -+ uint32_t pca9548_base_nr; -+ uint32_t pca9548_reset_type; -+ uint32_t rst_delay_b; /* delay time before reset(us) */ -+ uint32_t rst_delay; /* reset time(us) */ -+ uint32_t rst_delay_a; /* delay time after reset(us) */ -+ bool probe_disable; -+ bool select_chan_check; -+ bool close_chan_force_reset; -+ union { -+ i2c_attr_t i2c_attr; -+ gpio_attr_t gpio_attr; -+ io_attr_t io_attr; -+ file_attr_t file_attr; -+ } attr; -+} i2c_mux_pca954x_device_t; -+ -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.c -new file mode 100644 -index 000000000..c5b6a835a ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.c -@@ -0,0 +1,1396 @@ -+/* -+ * I2C multiplexer driver for PCA9541 bus master selector -+ * -+ * Copyright (c) 2010 Ericsson AB. -+ * -+ * Author: Guenter Roeck -+ * -+ * Derived from: -+ * pca954x.c -+ * -+ * Copyright (c) 2008-2009 Rodolfo Giometti -+ * Copyright (c) 2008-2009 Eurotech S.p.A. -+ * -+ * 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 -+#include -+#include -+ -+#include "wb_i2c_mux_pca9641.h" -+ -+/* -+ * The PCA9541 is a bus master selector. It supports two I2C masters connected -+ * to a single slave bus. -+ * -+ * Before each bus transaction, a master has to acquire bus ownership. After the -+ * transaction is complete, bus ownership has to be released. This fits well -+ * into the I2C multiplexer framework, which provides select and release -+ * functions for this purpose. For this reason, this driver is modeled as -+ * single-channel I2C bus multiplexer. -+ * -+ * This driver assumes that the two bus masters are controlled by two different -+ * hosts. If a single host controls both masters, platform code has to ensure -+ * that only one of the masters is instantiated at any given time. -+ */ -+ -+#define PCA9541_CONTROL 0x01 -+#define PCA9541_ISTAT 0x02 -+ -+#define PCA9541_CTL_MYBUS (1 << 0) -+#define PCA9541_CTL_NMYBUS (1 << 1) -+#define PCA9541_CTL_BUSON (1 << 2) -+#define PCA9541_CTL_NBUSON (1 << 3) -+#define PCA9541_CTL_BUSINIT (1 << 4) -+#define PCA9541_CTL_TESTON (1 << 6) -+#define PCA9541_CTL_NTESTON (1 << 7) -+#define PCA9541_ISTAT_INTIN (1 << 0) -+#define PCA9541_ISTAT_BUSINIT (1 << 1) -+#define PCA9541_ISTAT_BUSOK (1 << 2) -+#define PCA9541_ISTAT_BUSLOST (1 << 3) -+#define PCA9541_ISTAT_MYTEST (1 << 6) -+#define PCA9541_ISTAT_NMYTEST (1 << 7) -+#define PCA9641_ID 0x00 -+#define PCA9641_ID_MAGIC 0x38 -+#define PCA9641_CONTROL 0x01 -+#define PCA9641_STATUS 0x02 -+#define PCA9641_TIME 0x03 -+#define PCA9641_CTL_LOCK_REQ BIT(0) -+#define PCA9641_CTL_LOCK_GRANT BIT(1) -+#define PCA9641_CTL_BUS_CONNECT BIT(2) -+#define PCA9641_CTL_BUS_INIT BIT(3) -+#define PCA9641_CTL_SMBUS_SWRST BIT(4) -+#define PCA9641_CTL_IDLE_TIMER_DIS BIT(5) -+#define PCA9641_CTL_SMBUS_DIS BIT(6) -+#define PCA9641_CTL_PRIORITY BIT(7) -+#define PCA9641_STS_OTHER_LOCK BIT(0) -+#define PCA9641_STS_BUS_INIT_FAIL BIT(1) -+#define PCA9641_STS_BUS_HUNG BIT(2) -+#define PCA9641_STS_MBOX_EMPTY BIT(3) -+#define PCA9641_STS_MBOX_FULL BIT(4) -+#define PCA9641_STS_TEST_INT BIT(5) -+#define PCA9641_STS_SCL_IO BIT(6) -+#define PCA9641_STS_SDA_IO BIT(7) -+#define PCA9641_RES_TIME 0x03 -+#define BUSON (PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON) -+#define MYBUS (PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS) -+#define mybus(x) (!((x) & MYBUS) || ((x) & MYBUS) == MYBUS) -+#define busoff(x) (!((x) & BUSON) || ((x) & BUSON) == BUSON) -+#define BUSOFF(x, y) (!((x) & PCA9641_CTL_LOCK_GRANT) && \ -+ !((y) & PCA9641_STS_OTHER_LOCK)) -+#define other_lock(x) ((x) & PCA9641_STS_OTHER_LOCK) -+#define lock_grant(x) ((x) & PCA9641_CTL_LOCK_GRANT) -+ -+#define PCA9641_RETRY_TIME (8) -+#define PCA9641_RESET_DELAY (150) -+ -+typedef struct i2c_muxs_struct_flag -+{ -+ int nr; -+ char name[48]; -+ struct mutex update_lock; -+ int flag; -+}i2c_mux_flag; -+ -+i2c_mux_flag pca_flag = { -+ .nr = -1, -+ .flag = -1, -+}; -+ -+int pca9641_setmuxflag(int nr, int flag) -+{ -+ if (pca_flag.nr == nr) { -+ pca_flag.flag = flag; -+ return 0; -+ } -+ return -1; -+} -+EXPORT_SYMBOL(pca9641_setmuxflag); -+ -+static int g_debug_info = 0; -+static int g_debug_err = 0; -+ -+module_param(g_debug_info, int, S_IRUGO | S_IWUSR); -+module_param(g_debug_err, int, S_IRUGO | S_IWUSR); -+ -+#define PCA_DEBUG(fmt, args...) do { \ -+ if (g_debug_info) { \ -+ printk(KERN_INFO "[pca9641][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define PCA_DEBUG_ERR(fmt, args...) do { \ -+ if (g_debug_err) { \ -+ printk(KERN_ERR "[pca9641][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+/* arbitration timeouts, in jiffies */ -+#define ARB_TIMEOUT (HZ / 8) /* 125 ms until forcing bus ownership */ -+#define ARB2_TIMEOUT (HZ / 4) /* 250 ms until acquisition failure */ -+ -+/* arbitration retry delays, in us */ -+#define SELECT_DELAY_SHORT 50 -+#define SELECT_DELAY_LONG 1000 -+#define I2C_RETRY_TIMES (5) -+#define I2C_RETRY_WAIT_TIMES (10) /*delay 10ms*/ -+ -+typedef struct pca9641_cfg_info_s { -+ uint32_t pca9641_reset_type; -+ uint32_t rst_delay_b; /* delay time before reset(us) */ -+ uint32_t rst_delay; /* reset time(us) */ -+ uint32_t rst_delay_a; /* delay time after reset(us) */ -+ union { -+ i2c_attr_t i2c_attr; -+ gpio_attr_t gpio_attr; -+ io_attr_t io_attr; -+ file_attr_t file_attr; -+ } attr; -+} pca9641_cfg_info_t; -+ -+struct pca9541 { -+ struct i2c_client *client; -+ unsigned long select_timeout; -+ unsigned long arb_timeout; -+ uint32_t pca9641_nr; -+ pca9641_cfg_info_t pca9641_cfg_info; /* pca9641 reset cfg */ -+}; -+ -+static const struct i2c_device_id pca9541_id[] = { -+ {"wb_pca9541", 0}, -+ {"wb_pca9641", 1}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(i2c, pca9541_id); -+ -+#ifdef CONFIG_OF -+static const struct of_device_id pca9541_of_match[] = { -+ { .compatible = "nxp,wb_pca9541" }, -+ { .compatible = "nxp,wb_pca9641" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, pca9541_of_match); -+#endif -+ -+static int pca9641_gpio_init(gpio_attr_t *gpio_attr) -+{ -+ int err; -+ -+ if (gpio_attr->gpio_init) { -+ PCA_DEBUG("gpio%d already init, do nothing.\n", gpio_attr->gpio); -+ return 0; -+ } -+ -+ PCA_DEBUG("gpio%d init.\n", gpio_attr->gpio); -+ err = gpio_request(gpio_attr->gpio, "pca9641_reset"); -+ if (err) { -+ goto error; -+ } -+ err = gpio_direction_output(gpio_attr->gpio, gpio_attr->reset_off); -+ if (err) { -+ gpio_free(gpio_attr->gpio); -+ goto error; -+ } -+ gpio_attr->gpio_init = 1; -+ return 0; -+error: -+ PCA_DEBUG_ERR("pca9641_gpio_init failed, ret:%d.\n", err); -+ return err; -+} -+ -+static void pca9641_gpio_free(gpio_attr_t *gpio_attr) -+{ -+ if (gpio_attr->gpio_init == 1) { -+ PCA_DEBUG("gpio%d release.\n", gpio_attr->gpio); -+ gpio_free(gpio_attr->gpio); -+ gpio_attr->gpio_init = 0; -+ } -+ return; -+} -+ -+static int pca9641_reset_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) -+{ -+ int ret; -+ struct file *filp; -+ loff_t tmp_pos; -+ -+ filp = filp_open(path, O_RDONLY, 0); -+ if (IS_ERR(filp)) { -+ PCA_DEBUG_ERR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); -+ filp = NULL; -+ goto exit; -+ } -+ -+ tmp_pos = (loff_t)pos; -+ ret = kernel_read(filp, val, size, &tmp_pos); -+ if (ret < 0) { -+ PCA_DEBUG_ERR("kernel_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); -+ goto exit; -+ } -+ -+ filp_close(filp, NULL); -+ -+ return ret; -+ -+exit: -+ if (filp != NULL) { -+ filp_close(filp, NULL); -+ } -+ -+ return -1; -+} -+ -+static int pca9641_reset_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) -+{ -+ -+ int ret; -+ struct file *filp; -+ loff_t tmp_pos; -+ -+ filp = filp_open(path, O_RDWR, 777); -+ if (IS_ERR(filp)) { -+ PCA_DEBUG_ERR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); -+ filp = NULL; -+ goto exit; -+ } -+ -+ tmp_pos = (loff_t)pos; -+ ret = kernel_write(filp, val, size, &tmp_pos); -+ if (ret < 0) { -+ PCA_DEBUG_ERR("kernel_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); -+ goto exit; -+ } -+ -+ vfs_fsync(filp, 1); -+ filp_close(filp, NULL); -+ -+ return ret; -+ -+exit: -+ if (filp != NULL) { -+ filp_close(filp, NULL); -+ } -+ -+ return -1; -+} -+ -+static int pca9641_reset_i2c_read(uint32_t bus, uint32_t addr, uint32_t offset_addr, -+ unsigned char *buf, uint32_t size) -+{ -+ struct file *fp; -+ struct i2c_client client; -+ char i2c_path[32]; -+ int i, j; -+ int rv; -+ -+ rv = 0; -+ mem_clear(i2c_path, sizeof(i2c_path)); -+ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); -+ fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); -+ if (IS_ERR(fp)) { -+ PCA_DEBUG_ERR("i2c open fail.\n"); -+ return -1; -+ } -+ memcpy(&client, fp->private_data, sizeof(struct i2c_client)); -+ client.addr = addr; -+ for (j = 0; j < size; j++) { -+ for (i = 0; i < I2C_RETRY_TIMES; i++) { -+ rv = i2c_smbus_read_byte_data(&client, (offset_addr + j)); -+ if (rv < 0) { -+ PCA_DEBUG_ERR("i2c read failed, try again.\n"); -+ msleep(I2C_RETRY_WAIT_TIMES); -+ if (i >= (I2C_RETRY_TIMES - 1)) { -+ goto out; -+ } -+ continue; -+ } -+ *(buf + j) = (unsigned char)rv; -+ break; -+ } -+ } -+out: -+ filp_close(fp, NULL); -+ return rv; -+} -+ -+static int pca9641_reset_i2c_write(uint32_t bus, uint32_t dev_addr, uint32_t offset_addr, -+ uint8_t write_buf) -+{ -+ struct file *fp; -+ struct i2c_client client; -+ char i2c_path[32]; -+ int i; -+ int rv; -+ -+ rv = 0; -+ mem_clear(i2c_path, sizeof(i2c_path)); -+ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); -+ fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); -+ if (IS_ERR(fp)) { -+ PCA_DEBUG_ERR("i2c open fail.\n"); -+ return -1; -+ } -+ memcpy(&client, fp->private_data, sizeof(struct i2c_client)); -+ client.addr = dev_addr; -+ for (i = 0; i < I2C_RETRY_TIMES; i++) { -+ rv = i2c_smbus_write_byte_data(&client, offset_addr, write_buf); -+ if (rv < 0) { -+ PCA_DEBUG_ERR("i2c write failed, try again.\n"); -+ msleep(I2C_RETRY_WAIT_TIMES); -+ if (i >= (I2C_RETRY_TIMES - 1)) { -+ goto out; -+ } -+ continue; -+ } -+ break; -+ } -+out: -+ filp_close(fp, NULL); -+ return rv; -+} -+ -+static int pca9641_do_file_reset(struct i2c_mux_core *muxc) -+{ -+ int ret, timeout, err; -+ struct pca9541 *data; -+ pca9641_cfg_info_t *reset_cfg; -+ file_attr_t *file_attr; -+ u8 val; -+ int udelay_cnt; -+ -+ data = i2c_mux_priv(muxc); -+ reset_cfg = &data->pca9641_cfg_info; -+ file_attr = &reset_cfg->attr.file_attr; -+ ret = -1; -+ -+ PCA_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", -+ reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); -+ PCA_DEBUG("dev_name:%s, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", -+ file_attr->dev_name, file_attr->offset, file_attr->mask, -+ file_attr->reset_on, file_attr->reset_off); -+ -+ if (reset_cfg->rst_delay_b) { -+ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); -+ } -+ -+ err = pca9641_reset_file_read(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); -+ if (err < 0) { -+ goto out; -+ } -+ -+ val &= ~(file_attr->mask); -+ val |= file_attr->reset_on; -+ err = pca9641_reset_file_write(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); -+ if (err < 0) { -+ goto out; -+ } -+ -+ if (reset_cfg->rst_delay) { -+ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); -+ } -+ -+ val &= ~(file_attr->mask); -+ val |= file_attr->reset_off; -+ err = pca9641_reset_file_write(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); -+ if (err < 0) { -+ goto out; -+ } -+ -+ udelay_cnt = 0; -+ timeout = reset_cfg->rst_delay_a; -+ while (timeout > 0) { -+ usleep_range(1, 2); -+ err = pca9641_reset_file_read(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); -+ if (err < 0) { -+ goto out; -+ } -+ val &= (file_attr->mask); -+ if (val == file_attr->reset_off) { -+ ret = 0; -+ PCA_DEBUG("pca9641_do_file_reset success.\n"); -+ break; -+ } -+ udelay_cnt++; -+ if ((udelay_cnt % 1000) == 0) { -+ /* 1MS schedule*/ -+ schedule(); -+ } -+ timeout--; -+ } -+ if (ret < 0) { -+ PCA_DEBUG_ERR("pca9641_do_file_reset timeout.\n"); -+ } -+out: -+ if (err < 0) { -+ PCA_DEBUG_ERR("pca9641_do_file_reset file rd/wr failed, ret:%d.\n", err); -+ } -+ -+ return ret; -+} -+ -+static int pca9641_do_io_reset(struct i2c_mux_core *muxc) -+{ -+ int ret, timeout; -+ struct pca9541 *data; -+ pca9641_cfg_info_t *reset_cfg; -+ io_attr_t *io_attr; -+ u8 val; -+ int udelay_cnt; -+ -+ data = i2c_mux_priv(muxc); -+ reset_cfg = &data->pca9641_cfg_info; -+ io_attr = &reset_cfg->attr.io_attr; -+ -+ PCA_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", -+ reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); -+ PCA_DEBUG("io_addr:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", -+ io_attr->io_addr, io_attr->mask, io_attr->reset_on, io_attr->reset_off); -+ -+ if (reset_cfg->rst_delay_b) { -+ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); -+ } -+ -+ val = inb(io_attr->io_addr); -+ val &= ~(io_attr->mask); -+ val |= io_attr->reset_on; -+ outb(val, io_attr->io_addr); -+ -+ if (reset_cfg->rst_delay) { -+ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); -+ } -+ -+ val &= ~(io_attr->mask); -+ val |= io_attr->reset_off; -+ outb(val, io_attr->io_addr); -+ -+ ret = -1; -+ udelay_cnt = 0; -+ timeout = reset_cfg->rst_delay_a; -+ while (timeout > 0) { -+ usleep_range(1, 2); -+ val = inb(io_attr->io_addr); -+ val &= (io_attr->mask); -+ if (val == io_attr->reset_off) { -+ ret = 0; -+ PCA_DEBUG("pca9641_do_io_reset success.\n"); -+ break; -+ } -+ udelay_cnt++; -+ if ((udelay_cnt % 1000) == 0) { -+ /* 1MS schedule*/ -+ schedule(); -+ } -+ timeout--; -+ } -+ -+ if (ret < 0) { -+ PCA_DEBUG_ERR("pca9641_do_io_reset timeout.\n"); -+ } -+ -+ return ret; -+} -+ -+static int pca9641_do_gpio_reset(struct i2c_mux_core *muxc) -+{ -+ int ret, timeout; -+ struct pca9541 *data; -+ pca9641_cfg_info_t *reset_cfg; -+ gpio_attr_t *gpio_attr; -+ u8 val; -+ int udelay_cnt; -+ -+ data = i2c_mux_priv(muxc); -+ reset_cfg = &data->pca9641_cfg_info; -+ gpio_attr = &reset_cfg->attr.gpio_attr; -+ -+ ret = pca9641_gpio_init(gpio_attr); -+ if (ret) { -+ return -1; -+ } -+ -+ if (reset_cfg->rst_delay_b) { -+ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); -+ } -+ -+ __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_on); -+ -+ if (reset_cfg->rst_delay) { -+ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); -+ } -+ -+ __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_off); -+ ret = -1; -+ udelay_cnt = 0; -+ timeout = reset_cfg->rst_delay_a; -+ while (timeout > 0) { -+ usleep_range(1, 2); -+ val = __gpio_get_value(gpio_attr->gpio); -+ if (val == gpio_attr->reset_off) { -+ ret = 0; -+ PCA_DEBUG("pca9641_do_gpio_reset success.\n"); -+ break; -+ } -+ udelay_cnt++; -+ if ((udelay_cnt % 1000) == 0) { -+ /* 1MS schedule*/ -+ schedule(); -+ } -+ timeout--; -+ } -+ -+ if (ret < 0) { -+ PCA_DEBUG_ERR("pca9641_do_gpio_reset timeout.\n"); -+ } -+ -+ pca9641_gpio_free(gpio_attr); -+ return ret; -+} -+ -+static int pca9641_do_i2c_reset(struct i2c_mux_core *muxc) -+{ -+ int ret, timeout, err; -+ struct pca9541 *data; -+ pca9641_cfg_info_t *reset_cfg; -+ i2c_attr_t *i2c_attr; -+ u8 val; -+ int udelay_cnt; -+ -+ data = i2c_mux_priv(muxc); -+ reset_cfg = &data->pca9641_cfg_info; -+ i2c_attr = &reset_cfg->attr.i2c_attr; -+ ret = -1; -+ -+ PCA_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", -+ reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); -+ PCA_DEBUG("bus:0x%x, addr:0x%x, reg:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", -+ i2c_attr->i2c_bus, i2c_attr->i2c_addr, i2c_attr->reg_offset, -+ i2c_attr->mask, i2c_attr->reset_on, i2c_attr->reset_off); -+ -+ if (reset_cfg->rst_delay_b) { -+ usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); -+ } -+ -+ err = pca9641_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, -+ i2c_attr->reg_offset, &val, sizeof(val)); -+ if (err < 0) { -+ goto out; -+ } -+ -+ val &= ~(i2c_attr->mask); -+ val |= i2c_attr->reset_on; -+ err = pca9641_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, -+ i2c_attr->reg_offset, val); -+ if (err < 0) { -+ goto out; -+ } -+ -+ if (reset_cfg->rst_delay) { -+ usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); -+ } -+ -+ val &= ~(i2c_attr->mask); -+ val |= i2c_attr->reset_off; -+ err = pca9641_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, -+ i2c_attr->reg_offset, val); -+ if (err < 0) { -+ goto out; -+ } -+ -+ udelay_cnt = 0; -+ timeout = reset_cfg->rst_delay_a; -+ while (timeout > 0) { -+ usleep_range(1, 2); -+ err = pca9641_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, -+ i2c_attr->reg_offset, &val, sizeof(val)); -+ if (err < 0) { -+ goto out; -+ } -+ val &= (i2c_attr->mask); -+ if (val == i2c_attr->reset_off) { -+ ret = 0; -+ PCA_DEBUG("pca9641_do_i2c_reset success.\n"); -+ break; -+ } -+ udelay_cnt++; -+ if ((udelay_cnt % 1000) == 0) { -+ /* 1MS schedule*/ -+ schedule(); -+ } -+ timeout--; -+ } -+ if (ret < 0) { -+ PCA_DEBUG_ERR("pca9641_do_i2c_reset timeout.\n"); -+ } -+out: -+ if (err < 0) { -+ PCA_DEBUG_ERR("pca9641_do_i2c_reset i2c op failed, ret:%d.\n", err); -+ } -+ return ret; -+} -+ -+static int pca9641_do_reset(struct i2c_mux_core *muxc) -+{ -+ int ret; -+ struct pca9541 *data; -+ -+ data = i2c_mux_priv(muxc); -+ if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_NONE) { -+ ret = -1; -+ PCA_DEBUG("Don't need to reset.\n"); -+ } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_I2C) { -+ ret = pca9641_do_i2c_reset(muxc); -+ } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_GPIO) { -+ ret = pca9641_do_gpio_reset(muxc); -+ } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_IO) { -+ ret = pca9641_do_io_reset(muxc); -+ } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_FILE) { -+ ret = pca9641_do_file_reset(muxc); -+ } else { -+ ret = -1; -+ PCA_DEBUG_ERR("Unsupport reset type:0x%x.\n", -+ data->pca9641_cfg_info.pca9641_reset_type); -+ } -+ -+ if (ret < 0) { -+ PCA_DEBUG_ERR("pca9641_reset_ctrl failed, reset type:%u, ret:%d.\n", -+ data->pca9641_cfg_info.pca9641_reset_type, ret); -+ } else { -+ usleep_range(PCA9641_RESET_DELAY, PCA9641_RESET_DELAY + 1); -+ } -+ return ret; -+} -+ -+/* -+ * Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer() -+ * as they will try to lock the adapter a second time. -+ */ -+static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val) -+{ -+ struct i2c_adapter *adap = client->adapter; -+ int ret; -+ -+ if (adap->algo->master_xfer) { -+ struct i2c_msg msg; -+ char buf[2]; -+ -+ msg.addr = client->addr; -+ msg.flags = 0; -+ msg.len = 2; -+ buf[0] = command; -+ buf[1] = val; -+ msg.buf = buf; -+ ret = __i2c_transfer(adap, &msg, 1); -+ } else { -+ union i2c_smbus_data data; -+ -+ data.byte = val; -+ ret = adap->algo->smbus_xfer(adap, client->addr, -+ client->flags, -+ I2C_SMBUS_WRITE, -+ command, -+ I2C_SMBUS_BYTE_DATA, &data); -+ } -+ -+ return ret; -+} -+ -+/* -+ * Read from chip register. Don't use i2c_transfer()/i2c_smbus_xfer() -+ * as they will try to lock adapter a second time. -+ */ -+static int pca9541_reg_read(struct i2c_client *client, u8 command) -+{ -+ struct i2c_adapter *adap = client->adapter; -+ int ret; -+ u8 val; -+ -+ if (adap->algo->master_xfer) { -+ struct i2c_msg msg[2] = { -+ { -+ .addr = client->addr, -+ .flags = 0, -+ .len = 1, -+ .buf = &command -+ }, -+ { -+ .addr = client->addr, -+ .flags = I2C_M_RD, -+ .len = 1, -+ .buf = &val -+ } -+ }; -+ ret = __i2c_transfer(adap, msg, 2); -+ if (ret == 2) -+ ret = val; -+ else if (ret >= 0) -+ ret = -EIO; -+ } else { -+ union i2c_smbus_data data; -+ -+ ret = adap->algo->smbus_xfer(adap, client->addr, -+ client->flags, -+ I2C_SMBUS_READ, -+ command, -+ I2C_SMBUS_BYTE_DATA, &data); -+ if (!ret) -+ ret = data.byte; -+ } -+ return ret; -+} -+ -+/* -+ * Arbitration management functions -+ */ -+ -+/* Release bus. Also reset NTESTON and BUSINIT if it was set. */ -+static void pca9541_release_bus(struct i2c_client *client) -+{ -+ int reg; -+ -+ reg = pca9541_reg_read(client, PCA9541_CONTROL); -+ if (reg >= 0 && !busoff(reg) && mybus(reg)) -+ pca9541_reg_write(client, PCA9541_CONTROL, -+ (reg & PCA9541_CTL_NBUSON) >> 1); -+} -+ -+/* -+ * Arbitration is defined as a two-step process. A bus master can only activate -+ * the slave bus if it owns it; otherwise it has to request ownership first. -+ * This multi-step process ensures that access contention is resolved -+ * gracefully. -+ * -+ * Bus Ownership Other master Action -+ * state requested access -+ * ---------------------------------------------------- -+ * off - yes wait for arbitration timeout or -+ * for other master to drop request -+ * off no no take ownership -+ * off yes no turn on bus -+ * on yes - done -+ * on no - wait for arbitration timeout or -+ * for other master to release bus -+ * -+ * The main contention point occurs if the slave bus is off and both masters -+ * request ownership at the same time. In this case, one master will turn on -+ * the slave bus, believing that it owns it. The other master will request -+ * bus ownership. Result is that the bus is turned on, and master which did -+ * _not_ own the slave bus before ends up owning it. -+ */ -+ -+/* Control commands per PCA9541 datasheet */ -+static const u8 pca9541_control[16] = { -+ 4, 0, 1, 5, 4, 4, 5, 5, 0, 0, 1, 1, 0, 4, 5, 1 -+}; -+ -+/* -+ * Channel arbitration -+ * -+ * Return values: -+ * <0: error -+ * 0 : bus not acquired -+ * 1 : bus acquired -+ */ -+static int pca9541_arbitrate(struct i2c_client *client) -+{ -+ struct i2c_mux_core *muxc = i2c_get_clientdata(client); -+ struct pca9541 *data = i2c_mux_priv(muxc); -+ int reg; -+ -+ reg = pca9541_reg_read(client, PCA9541_CONTROL); -+ if (reg < 0) -+ return reg; -+ -+ if (busoff(reg)) { -+ int istat; -+ /* -+ * Bus is off. Request ownership or turn it on unless -+ * other master requested ownership. -+ */ -+ istat = pca9541_reg_read(client, PCA9541_ISTAT); -+ if (!(istat & PCA9541_ISTAT_NMYTEST) -+ || time_is_before_eq_jiffies(data->arb_timeout)) { -+ /* -+ * Other master did not request ownership, -+ * or arbitration timeout expired. Take the bus. -+ */ -+ pca9541_reg_write(client, -+ PCA9541_CONTROL, -+ pca9541_control[reg & 0x0f] -+ | PCA9541_CTL_NTESTON); -+ data->select_timeout = SELECT_DELAY_SHORT; -+ } else { -+ /* -+ * Other master requested ownership. -+ * Set extra long timeout to give it time to acquire it. -+ */ -+ data->select_timeout = SELECT_DELAY_LONG * 2; -+ } -+ } else if (mybus(reg)) { -+ /* -+ * Bus is on, and we own it. We are done with acquisition. -+ * Reset NTESTON and BUSINIT, then return success. -+ */ -+ if (reg & (PCA9541_CTL_NTESTON | PCA9541_CTL_BUSINIT)) -+ pca9541_reg_write(client, -+ PCA9541_CONTROL, -+ reg & ~(PCA9541_CTL_NTESTON -+ | PCA9541_CTL_BUSINIT)); -+ return 1; -+ } else { -+ /* -+ * Other master owns the bus. -+ * If arbitration timeout has expired, force ownership. -+ * Otherwise request it. -+ */ -+ data->select_timeout = SELECT_DELAY_LONG; -+ if (time_is_before_eq_jiffies(data->arb_timeout)) { -+ /* Time is up, take the bus and reset it. */ -+ pca9541_reg_write(client, -+ PCA9541_CONTROL, -+ pca9541_control[reg & 0x0f] -+ | PCA9541_CTL_BUSINIT -+ | PCA9541_CTL_NTESTON); -+ } else { -+ /* Request bus ownership if needed */ -+ if (!(reg & PCA9541_CTL_NTESTON)) -+ pca9541_reg_write(client, -+ PCA9541_CONTROL, -+ reg | PCA9541_CTL_NTESTON); -+ } -+ } -+ return 0; -+} -+ -+static int pca9541_select_chan(struct i2c_mux_core *muxc, u32 chan) -+{ -+ struct pca9541 *data = i2c_mux_priv(muxc); -+ struct i2c_client *client = data->client; -+ int ret; -+ unsigned long timeout = jiffies + ARB2_TIMEOUT; -+ /* give up after this time */ -+ -+ data->arb_timeout = jiffies + ARB_TIMEOUT; -+ /* force bus ownership after this time */ -+ -+ do { -+ ret = pca9541_arbitrate(client); -+ if (ret) -+ return ret < 0 ? ret : 0; -+ -+ if (data->select_timeout == SELECT_DELAY_SHORT) -+ udelay(data->select_timeout); -+ else -+ msleep(data->select_timeout / 1000); -+ } while (time_is_after_eq_jiffies(timeout)); -+ -+ dev_warn(&client->dev, "pca9541 select channel timeout.\n"); -+ return -ETIMEDOUT; -+} -+ -+static int pca9541_release_chan(struct i2c_mux_core *muxc, u32 chan) -+{ -+ struct pca9541 *data = i2c_mux_priv(muxc); -+ struct i2c_client *client = data->client; -+ pca9541_release_bus(client); -+ return 0; -+} -+ -+/* -+* Arbitration management functions -+*/ -+static void pca9641_release_bus(struct i2c_client *client) -+{ -+ pca9541_reg_write(client, PCA9641_CONTROL, 0x80); //master 0x80 -+} -+ -+/* -+* Channel arbitration -+* -+* Return values: -+* <0: error -+* 0 : bus not acquired -+* 1 : bus acquired -+*/ -+static int pca9641_arbitrate(struct i2c_client *client) -+{ -+ struct i2c_mux_core *muxc = i2c_get_clientdata(client); -+ struct pca9541 *data = i2c_mux_priv(muxc); -+ int reg_ctl, reg_sts; -+ -+ reg_ctl = pca9541_reg_read(client, PCA9641_CONTROL); -+ if (reg_ctl < 0) { -+ PCA_DEBUG_ERR("pca9641 read control register failed, ret:%d.\n", reg_ctl); -+ return reg_ctl; -+ } -+ -+ reg_sts = pca9541_reg_read(client, PCA9641_STATUS); -+ if (reg_sts < 0) { -+ PCA_DEBUG_ERR("pca9641 read status register failed, ret:%d.\n", reg_sts); -+ return reg_sts; -+ } -+ -+ if (BUSOFF(reg_ctl, reg_sts)) { -+ /* -+ * Bus is off. Request ownership or turn it on unless -+ * other master requested ownership. -+ */ -+ reg_ctl |= PCA9641_CTL_LOCK_REQ; -+ pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); -+ reg_ctl = pca9541_reg_read(client, PCA9641_CONTROL); -+ if (reg_ctl < 0) { -+ PCA_DEBUG_ERR("Bus is off, but read control register failed, ret:%d.\n", reg_ctl); -+ return reg_ctl; -+ } -+ -+ if (lock_grant(reg_ctl)) { -+ /* -+ * Other master did not request ownership, -+ * or arbitration timeout expired. Take the bus. -+ */ -+ PCA_DEBUG("Bus is off, get pca9641 arbitration success.\n"); -+ reg_ctl |= PCA9641_CTL_BUS_CONNECT | PCA9641_CTL_LOCK_REQ; -+ pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); -+ return 1; -+ } else { -+ /* -+ * Other master requested ownership. -+ * Set extra long timeout to give it time to acquire it. -+ */ -+ PCA_DEBUG("Bus is off, but get pca9641 arbitration failed.\n"); -+ data->select_timeout = SELECT_DELAY_LONG * 2; -+ } -+ } else if (lock_grant(reg_ctl)) { -+ /* -+ * Bus is on, and we own it. We are done with acquisition. -+ */ -+ PCA_DEBUG("Bus is on, get pca9641 arbitration success.\n"); -+ reg_ctl |= PCA9641_CTL_BUS_CONNECT | PCA9641_CTL_LOCK_REQ; -+ pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); -+ return 1; -+ } else if (other_lock(reg_sts)) { -+ /* -+ * Other master owns the bus. -+ * If arbitration timeout has expired, force ownership. -+ * Otherwise request it. -+ */ -+ PCA_DEBUG("Other master owns the bus, try to request it.\n"); -+ data->select_timeout = SELECT_DELAY_LONG; -+ reg_ctl |= PCA9641_CTL_LOCK_REQ; -+ pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); -+ } -+ return 0; -+} -+ -+int pca9641_select_chan_single(struct i2c_mux_core *muxc, u32 chan) -+{ -+ struct pca9541 *data = i2c_mux_priv(muxc); -+ struct i2c_client *client = data->client; -+ int ret; -+ int result; -+ unsigned long msleep_time; -+ unsigned long timeout = jiffies + ARB2_TIMEOUT; -+ /* give up after this time */ -+ data->arb_timeout = jiffies + ARB_TIMEOUT; -+ /* force bus ownership after this time */ -+ for (result = 0 ; result < PCA9641_RETRY_TIME ; result ++) { -+ do { -+ ret = pca9641_arbitrate(client); -+ if (ret) { -+ return ret < 0 ? -EIO : 0; -+ } -+ msleep_time = data->select_timeout / 1000; -+ if (msleep_time < 1) { -+ msleep(1); -+ } else { -+ msleep(msleep_time); -+ } -+ } while (time_is_after_eq_jiffies(timeout)); -+ timeout = jiffies + ARB2_TIMEOUT; -+ } -+ dev_warn(&client->dev, "pca9641 select channel timeout.\n"); -+ return -ETIMEDOUT; -+} -+ -+static int pca9641_select_chan(struct i2c_mux_core *muxc, u32 chan) -+{ -+ int ret, rv; -+ -+ ret = pca9641_select_chan_single(muxc, chan); -+ if (ret < 0) { -+ PCA_DEBUG_ERR("pca9641 select channel failed, ret:%d, try to reset pca9641.\n", ret); -+ rv = pca9641_do_reset(muxc); -+ -+ if (rv < 0) { -+ PCA_DEBUG_ERR("pca9641 reset failed, rv:%d.\n", rv); -+ return ret; -+ } -+ -+ ret = pca9641_select_chan_single(muxc, chan); -+ if (ret < 0) { -+ PCA_DEBUG_ERR("after pca9641 reset, select channel still failed, ret:%d.\n", ret); -+ } -+ } -+ return ret; -+} -+ -+static int pca9641_release_chan(struct i2c_mux_core *muxc, u32 chan) -+{ -+ struct pca9541 *data = i2c_mux_priv(muxc); -+ struct i2c_client *client = data->client; -+ if (pca_flag.flag) { -+ pca9641_release_bus(client); -+ } -+ return 0; -+} -+ -+static int pca9641_detect_id(struct i2c_client *client) -+{ -+#if 0 -+ int reg; -+ -+ reg = pca9541_reg_read(client, PCA9641_ID); -+ if (reg == PCA9641_ID_MAGIC) -+ return 1; -+ else -+ return 0; -+#endif -+ /* only support pca9641 */ -+ return 1; -+} -+ -+static int pca9641_recordflag(struct i2c_adapter *adap) { -+ if (pca_flag.flag != -1) { -+ pr_err(" %s %d has init already!!!", __func__, __LINE__); -+ return -1 ; -+ } -+ pca_flag.nr = adap->nr; -+ PCA_DEBUG(" adap->nr:%d\n", adap->nr); -+ snprintf(pca_flag.name, sizeof(pca_flag.name),adap->name); -+ return 0; -+} -+ -+static int of_pca9641_reset_data_init(struct pca9541 *data) -+{ -+ int err; -+ struct device *dev = &data->client->dev; -+ pca9641_cfg_info_t *reset_cfg; -+ -+ reset_cfg = &data->pca9641_cfg_info; -+ if (dev == NULL || dev->of_node == NULL) { -+ PCA_DEBUG("dev or dev->of_node is NUll, no reset.\n"); -+ reset_cfg->pca9641_reset_type = PCA9641_RESET_NONE; -+ return 0; -+ } -+ -+ if (of_property_read_u32(dev->of_node, "pca9641_reset_type", &reset_cfg->pca9641_reset_type)) { -+ -+ PCA_DEBUG("pca9641_reset_type not found, no reset.\n"); -+ reset_cfg->pca9641_reset_type = PCA9641_RESET_NONE; -+ return 0; -+ } -+ err = of_property_read_u32(dev->of_node, "rst_delay_b", &reset_cfg->rst_delay_b); -+ err |= of_property_read_u32(dev->of_node, "rst_delay", &reset_cfg->rst_delay); -+ err |= of_property_read_u32(dev->of_node, "rst_delay_a", &reset_cfg->rst_delay_a); -+ -+ if (err) { -+ goto dts_config_err; -+ } -+ PCA_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", -+ reset_cfg->pca9641_reset_type, reset_cfg->rst_delay_b, -+ reset_cfg->rst_delay, reset_cfg->rst_delay_a); -+ -+ if (reset_cfg->pca9641_reset_type == PCA9641_RESET_I2C) { -+ -+ PCA_DEBUG("reset by i2c.\n"); -+ err = of_property_read_u32(dev->of_node, "i2c_bus", &reset_cfg->attr.i2c_attr.i2c_bus); -+ err |=of_property_read_u32(dev->of_node, "i2c_addr", &reset_cfg->attr.i2c_attr.i2c_addr); -+ err |=of_property_read_u32(dev->of_node, "reg_offset", &reset_cfg->attr.i2c_attr.reg_offset); -+ err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.i2c_attr.mask); -+ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.i2c_attr.reset_on); -+ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.i2c_attr.reset_off); -+ if (err) { -+ goto dts_config_err; -+ } -+ PCA_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", -+ reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, -+ reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, -+ reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); -+ } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_GPIO) { -+ -+ PCA_DEBUG("reset by gpio.\n"); -+ err = of_property_read_u32(dev->of_node, "gpio", &reset_cfg->attr.gpio_attr.gpio); -+ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.gpio_attr.reset_on); -+ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.gpio_attr.reset_off); -+ if (err) { -+ goto dts_config_err; -+ } -+ PCA_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", -+ reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, -+ reset_cfg->attr.gpio_attr.reset_off); -+ reset_cfg->attr.gpio_attr.gpio_init = 0; -+ } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_IO) { -+ -+ PCA_DEBUG("reset by io.\n"); -+ err = of_property_read_u32(dev->of_node, "io_addr", &reset_cfg->attr.io_attr.io_addr); -+ err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.io_attr.mask); -+ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.io_attr.reset_on); -+ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.io_attr.reset_off); -+ if (err) { -+ goto dts_config_err; -+ } -+ PCA_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", -+ reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, -+ reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); -+ } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_FILE) { -+ -+ PCA_DEBUG("reset by file.\n"); -+ err = of_property_read_string(dev->of_node, "dev_name", &reset_cfg->attr.file_attr.dev_name); -+ err |=of_property_read_u32(dev->of_node, "offset", &reset_cfg->attr.file_attr.offset); -+ err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.file_attr.mask); -+ err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.file_attr.reset_on); -+ err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.file_attr.reset_off); -+ if (err) { -+ goto dts_config_err; -+ } -+ PCA_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", -+ reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, -+ reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off); -+ } else { -+ PCA_DEBUG_ERR("Unsupport reset type:%d.\n", reset_cfg->pca9641_reset_type); -+ goto dts_config_err; -+ } -+ return 0; -+dts_config_err: -+ PCA_DEBUG_ERR("dts config error, ret:%d.\n", err); -+ return -EINVAL; -+} -+ -+static int pca9641_reset_data_init(struct pca9541 *data) -+{ -+ pca9641_cfg_info_t *reset_cfg; -+ i2c_mux_pca9641_device_t *i2c_mux_pca9641_device; -+ -+ if (data->client->dev.platform_data == NULL) { -+ PCA_DEBUG("pca9641 has no reset platform data config.\n"); -+ return 0; -+ } -+ reset_cfg = &data->pca9641_cfg_info; -+ i2c_mux_pca9641_device = data->client->dev.platform_data; -+ reset_cfg->pca9641_reset_type = i2c_mux_pca9641_device->pca9641_reset_type; -+ if (reset_cfg->pca9641_reset_type == PCA9641_RESET_NONE) { -+ PCA_DEBUG("pca9641 has no reset function.\n"); -+ return 0; -+ } -+ -+ reset_cfg->rst_delay_b = i2c_mux_pca9641_device->rst_delay_b; -+ reset_cfg->rst_delay = i2c_mux_pca9641_device->rst_delay; -+ reset_cfg->rst_delay_a = i2c_mux_pca9641_device->rst_delay_a; -+ PCA_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", -+ reset_cfg->pca9641_reset_type, reset_cfg->rst_delay_b, -+ reset_cfg->rst_delay, reset_cfg->rst_delay_a); -+ -+ if (reset_cfg->pca9641_reset_type == PCA9641_RESET_I2C) { -+ -+ PCA_DEBUG("reset by i2c.\n"); -+ reset_cfg->attr.i2c_attr.i2c_bus = i2c_mux_pca9641_device->attr.i2c_attr.i2c_bus; -+ reset_cfg->attr.i2c_attr.i2c_addr = i2c_mux_pca9641_device->attr.i2c_attr.i2c_addr; -+ reset_cfg->attr.i2c_attr.reg_offset = i2c_mux_pca9641_device->attr.i2c_attr.reg_offset; -+ reset_cfg->attr.i2c_attr.mask = i2c_mux_pca9641_device->attr.i2c_attr.mask; -+ reset_cfg->attr.i2c_attr.reset_on = i2c_mux_pca9641_device->attr.i2c_attr.reset_on; -+ reset_cfg->attr.i2c_attr.reset_off = i2c_mux_pca9641_device->attr.i2c_attr.reset_off; -+ PCA_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", -+ reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, -+ reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, -+ reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); -+ } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_GPIO) { -+ -+ PCA_DEBUG("reset by gpio.\n"); -+ reset_cfg->attr.gpio_attr.gpio = i2c_mux_pca9641_device->attr.gpio_attr.gpio; -+ reset_cfg->attr.gpio_attr.reset_on = i2c_mux_pca9641_device->attr.gpio_attr.reset_on; -+ reset_cfg->attr.gpio_attr.reset_off = i2c_mux_pca9641_device->attr.gpio_attr.reset_off; -+ PCA_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", -+ reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, -+ reset_cfg->attr.gpio_attr.reset_off); -+ reset_cfg->attr.gpio_attr.gpio_init = 0; -+ } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_IO) { -+ -+ PCA_DEBUG("reset by io.\n"); -+ reset_cfg->attr.io_attr.io_addr = i2c_mux_pca9641_device->attr.io_attr.io_addr; -+ reset_cfg->attr.io_attr.mask = i2c_mux_pca9641_device->attr.io_attr.mask; -+ reset_cfg->attr.io_attr.reset_on = i2c_mux_pca9641_device->attr.io_attr.reset_on; -+ reset_cfg->attr.io_attr.reset_off = i2c_mux_pca9641_device->attr.io_attr.reset_off; -+ PCA_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", -+ reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, -+ reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); -+ } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_FILE) { -+ -+ PCA_DEBUG("reset by file.\n"); -+ reset_cfg->attr.file_attr.dev_name = i2c_mux_pca9641_device->attr.file_attr.dev_name; -+ reset_cfg->attr.file_attr.offset = i2c_mux_pca9641_device->attr.file_attr.offset; -+ reset_cfg->attr.file_attr.mask = i2c_mux_pca9641_device->attr.file_attr.mask; -+ reset_cfg->attr.file_attr.reset_on = i2c_mux_pca9641_device->attr.file_attr.reset_on; -+ reset_cfg->attr.file_attr.reset_off = i2c_mux_pca9641_device->attr.file_attr.reset_off; -+ PCA_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", -+ reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, -+ reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off); -+ } else { -+ PCA_DEBUG_ERR("Unsupport reset type:%d.\n", reset_cfg->pca9641_reset_type); -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+/* -+ * I2C init/probing/exit functions -+ */ -+static int pca9541_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct i2c_adapter *adap = client->adapter; -+ struct i2c_mux_core *muxc; -+ struct pca9541 *data; -+ int force; -+ int ret = -ENODEV; -+ int detect_id; -+ i2c_mux_pca9641_device_t *i2c_mux_pca9641_device; -+ -+ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA)) -+ return -ENODEV; -+ -+ detect_id = pca9641_detect_id(client); -+ -+ /* -+ * I2C accesses are unprotected here. -+ * We have to lock the adapter before releasing the bus. -+ */ -+ if (detect_id == 0) { -+ i2c_lock_bus(adap, I2C_LOCK_ROOT_ADAPTER); -+ pca9541_release_bus(client); -+ i2c_unlock_bus(adap, I2C_LOCK_ROOT_ADAPTER); -+ } else { -+ i2c_lock_bus(adap, I2C_LOCK_ROOT_ADAPTER); -+ pca9641_release_bus(client); -+ i2c_unlock_bus(adap, I2C_LOCK_ROOT_ADAPTER); -+ } -+ -+ if (detect_id == 0) { /* pca9541 */ -+ muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), -+ I2C_MUX_ARBITRATOR, -+ pca9541_select_chan, pca9541_release_chan); -+ if (!muxc) -+ return -ENOMEM; -+ -+ data = i2c_mux_priv(muxc); -+ data->client = client; -+ -+ i2c_set_clientdata(client, muxc); -+ /* Create mux adapter */ -+ if (of_property_read_u32(client->dev.of_node, "pca9641_nr", &data->pca9641_nr)) { -+ -+ force = 0; -+ PCA_DEBUG("pca9641_nr not found, use dynamic adap number.\n"); -+ } else { -+ force = data->pca9641_nr; -+ PCA_DEBUG("pca9641_nr: %d.\n", force); -+ } -+ -+ ret = i2c_mux_add_adapter(muxc, force, 0, 0); -+ if (ret) -+ return ret; -+ } else { -+ muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), I2C_MUX_ARBITRATOR, -+ pca9641_select_chan, pca9641_release_chan); -+ if (!muxc) { -+ dev_err(&client->dev, "i2c_mux_alloc failed, out of memory.\n"); -+ return -ENOMEM; -+ } -+ -+ data = i2c_mux_priv(muxc); -+ data->client = client; -+ -+ i2c_set_clientdata(client, muxc); -+ -+ if (client->dev.of_node) { -+ ret= of_pca9641_reset_data_init(data); -+ } else { -+ ret= pca9641_reset_data_init(data); -+ } -+ if (ret < 0) { -+ dev_err(&client->dev, "pca9641 reset config err, ret:%d.\n", ret); -+ return ret; -+ } -+ -+ if (client->dev.of_node == NULL) { -+ if (client->dev.platform_data == NULL) { -+ force = 0; -+ PCA_DEBUG("platform data is NULL, use dynamic adap number.\n"); -+ } else { -+ i2c_mux_pca9641_device = client->dev.platform_data; -+ data->pca9641_nr = i2c_mux_pca9641_device->pca9641_nr; -+ if (data->pca9641_nr == 0) { -+ force = 0; -+ PCA_DEBUG("pca9641_nr = 0, use dynamic adap number.\n"); -+ } else { -+ force = data->pca9641_nr; -+ PCA_DEBUG("pca9641_nr: %d.\n", force); -+ } -+ } -+ } else { -+ /* Create mux adapter */ -+ if (of_property_read_u32(client->dev.of_node, "pca9641_nr", &data->pca9641_nr)) { -+ -+ force = 0; -+ PCA_DEBUG("pca9641_nr not found, use dynamic adap number.\n"); -+ } else { -+ force = data->pca9641_nr; -+ PCA_DEBUG("pca9641_nr: %d.\n", force); -+ } -+ } -+ -+ ret = i2c_mux_add_adapter(muxc, force, 0, 0); -+ if (ret) { -+ dev_err(&client->dev, "Failed to register master selector.\n"); -+ return ret; -+ } -+ } -+ pca9641_recordflag(muxc->adapter[0]); -+ -+ dev_info(&client->dev, "registered master selector for I2C %s\n", client->name); -+ -+ return 0; -+} -+ -+static int pca9541_remove(struct i2c_client *client) -+{ -+ struct i2c_mux_core *muxc = i2c_get_clientdata(client); -+ -+ i2c_mux_del_adapters(muxc); -+ return 0; -+} -+ -+static struct i2c_driver pca9641_driver = { -+ .driver = { -+ .name = "wb_pca9641", -+ .of_match_table = of_match_ptr(pca9541_of_match), -+ }, -+ .probe = pca9541_probe, -+ .remove = pca9541_remove, -+ .id_table = pca9541_id, -+}; -+ -+module_i2c_driver(pca9641_driver); -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("PCA9541 I2C master selector driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.h -new file mode 100644 -index 000000000..b87f75855 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_i2c_mux_pca9641.h -@@ -0,0 +1,64 @@ -+#ifndef __WB_I2C_MUX_PCA9641_H__ -+#define __WB_I2C_MUX_PCA9641_H__ -+ -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+ -+typedef enum pca9641_reset_type_s { -+ PCA9641_RESET_NONE = 0, -+ PCA9641_RESET_I2C = 1, -+ PCA9641_RESET_GPIO = 2, -+ PCA9641_RESET_IO = 3, -+ PCA9641_RESET_FILE = 4, -+} pca9641_reset_type_t; -+ -+typedef struct i2c_attr_s { -+ uint32_t i2c_bus; -+ uint32_t i2c_addr; -+ uint32_t reg_offset; -+ uint32_t mask; -+ uint32_t reset_on; -+ uint32_t reset_off; -+} i2c_attr_t; -+ -+typedef struct io_attr_s { -+ uint32_t io_addr; -+ uint32_t mask; -+ uint32_t reset_on; -+ uint32_t reset_off; -+} io_attr_t; -+ -+typedef struct file_attr_s { -+ const char *dev_name; -+ uint32_t offset; -+ uint32_t mask; -+ uint32_t reset_on; -+ uint32_t reset_off; -+} file_attr_t; -+ -+typedef struct gpio_attr_s { -+ int gpio_init; -+ uint32_t gpio; -+ uint32_t reset_on; -+ uint32_t reset_off; -+} gpio_attr_t; -+ -+typedef struct i2c_mux_pca9641_device_s { -+ struct i2c_client *client; -+ uint32_t i2c_bus; -+ uint32_t i2c_addr; -+ uint32_t pca9641_nr; -+ uint32_t pca9641_reset_type; -+ uint32_t rst_delay_b; /* delay time before reset(us) */ -+ uint32_t rst_delay; /* reset time(us) */ -+ uint32_t rst_delay_a; /* delay time after reset(us) */ -+ union { -+ i2c_attr_t i2c_attr; -+ gpio_attr_t gpio_attr; -+ io_attr_t io_attr; -+ file_attr_t file_attr; -+ } attr; -+} i2c_mux_pca9641_device_t; -+ -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ina3221.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ina3221.c -new file mode 100644 -index 000000000..fba2c4e3a ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ina3221.c -@@ -0,0 +1,1031 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * INA3221 Triple Current/Voltage Monitor -+ * -+ * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ -+ * Andrew F. Davis -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define INA3221_DRIVER_NAME "wb_ina3221" -+ -+#define INA3221_CONFIG 0x00 -+#define INA3221_SHUNT1 0x01 -+#define INA3221_BUS1 0x02 -+#define INA3221_SHUNT2 0x03 -+#define INA3221_BUS2 0x04 -+#define INA3221_SHUNT3 0x05 -+#define INA3221_BUS3 0x06 -+#define INA3221_CRIT1 0x07 -+#define INA3221_WARN1 0x08 -+#define INA3221_CRIT2 0x09 -+#define INA3221_WARN2 0x0a -+#define INA3221_CRIT3 0x0b -+#define INA3221_WARN3 0x0c -+#define INA3221_SHUNT_SUM 0x0d -+#define INA3221_CRIT_SUM 0x0e -+#define INA3221_MASK_ENABLE 0x0f -+ -+#define INA3221_CONFIG_MODE_MASK GENMASK(2, 0) -+#define INA3221_CONFIG_MODE_POWERDOWN 0 -+#define INA3221_CONFIG_MODE_SHUNT BIT(0) -+#define INA3221_CONFIG_MODE_BUS BIT(1) -+#define INA3221_CONFIG_MODE_CONTINUOUS BIT(2) -+#define INA3221_CONFIG_VSH_CT_SHIFT 3 -+#define INA3221_CONFIG_VSH_CT_MASK GENMASK(5, 3) -+#define INA3221_CONFIG_VSH_CT(x) (((x) & GENMASK(5, 3)) >> 3) -+#define INA3221_CONFIG_VBUS_CT_SHIFT 6 -+#define INA3221_CONFIG_VBUS_CT_MASK GENMASK(8, 6) -+#define INA3221_CONFIG_VBUS_CT(x) (((x) & GENMASK(8, 6)) >> 6) -+#define INA3221_CONFIG_AVG_SHIFT 9 -+#define INA3221_CONFIG_AVG_MASK GENMASK(11, 9) -+#define INA3221_CONFIG_AVG(x) (((x) & GENMASK(11, 9)) >> 9) -+#define INA3221_CONFIG_CHs_EN_MASK GENMASK(14, 12) -+#define INA3221_CONFIG_CHx_EN(x) BIT(14 - (x)) -+ -+#define INA3221_MASK_ENABLE_SCC_MASK GENMASK(14, 12) -+ -+#define INA3221_CONFIG_DEFAULT 0x7127 -+#define INA3221_RSHUNT_DEFAULT 10000 -+ -+enum ina3221_fields { -+ /* Configuration */ -+ F_RST, -+ -+ /* Status Flags */ -+ F_CVRF, -+ -+ /* Warning Flags */ -+ F_WF3, F_WF2, F_WF1, -+ -+ /* Alert Flags: SF is the summation-alert flag */ -+ F_SF, F_CF3, F_CF2, F_CF1, -+ -+ /* sentinel */ -+ F_MAX_FIELDS -+}; -+ -+static const struct reg_field ina3221_reg_fields[] = { -+ [F_RST] = REG_FIELD(INA3221_CONFIG, 15, 15), -+ -+ [F_CVRF] = REG_FIELD(INA3221_MASK_ENABLE, 0, 0), -+ [F_WF3] = REG_FIELD(INA3221_MASK_ENABLE, 3, 3), -+ [F_WF2] = REG_FIELD(INA3221_MASK_ENABLE, 4, 4), -+ [F_WF1] = REG_FIELD(INA3221_MASK_ENABLE, 5, 5), -+ [F_SF] = REG_FIELD(INA3221_MASK_ENABLE, 6, 6), -+ [F_CF3] = REG_FIELD(INA3221_MASK_ENABLE, 7, 7), -+ [F_CF2] = REG_FIELD(INA3221_MASK_ENABLE, 8, 8), -+ [F_CF1] = REG_FIELD(INA3221_MASK_ENABLE, 9, 9), -+}; -+ -+enum ina3221_channels { -+ INA3221_CHANNEL1, -+ INA3221_CHANNEL2, -+ INA3221_CHANNEL3, -+ INA3221_NUM_CHANNELS -+}; -+ -+/** -+ * struct ina3221_input - channel input source specific information -+ * @label: label of channel input source -+ * @shunt_resistor: shunt resistor value of channel input source -+ * @disconnected: connection status of channel input source -+ */ -+struct ina3221_input { -+ const char *label; -+ int shunt_resistor; -+ bool disconnected; -+}; -+ -+/** -+ * struct ina3221_data - device specific information -+ * @pm_dev: Device pointer for pm runtime -+ * @regmap: Register map of the device -+ * @fields: Register fields of the device -+ * @inputs: Array of channel input source specific structures -+ * @lock: mutex lock to serialize sysfs attribute accesses -+ * @reg_config: Register value of INA3221_CONFIG -+ * @summation_shunt_resistor: equivalent shunt resistor value for summation -+ * @single_shot: running in single-shot operating mode -+ */ -+struct ina3221_data { -+ struct device *pm_dev; -+ struct regmap *regmap; -+ struct regmap_field *fields[F_MAX_FIELDS]; -+ struct ina3221_input inputs[INA3221_NUM_CHANNELS]; -+ struct mutex lock; -+ u32 reg_config; -+ int summation_shunt_resistor; -+ -+ bool single_shot; -+}; -+ -+static inline bool ina3221_is_enabled(struct ina3221_data *ina, int channel) -+{ -+ /* Summation channel checks shunt resistor values */ -+ if (channel > INA3221_CHANNEL3) -+ return ina->summation_shunt_resistor != 0; -+ -+ return pm_runtime_active(ina->pm_dev) && -+ (ina->reg_config & INA3221_CONFIG_CHx_EN(channel)); -+} -+ -+/** -+ * Helper function to return the resistor value for current summation. -+ * -+ * There is a condition to calculate current summation -- all the shunt -+ * resistor values should be the same, so as to simply fit the formula: -+ * current summation = shunt voltage summation / shunt resistor -+ * -+ * Returns the equivalent shunt resistor value on success or 0 on failure -+ */ -+static inline int ina3221_summation_shunt_resistor(struct ina3221_data *ina) -+{ -+ struct ina3221_input *input = ina->inputs; -+ int i, shunt_resistor = 0; -+ -+ for (i = 0; i < INA3221_NUM_CHANNELS; i++) { -+ if (input[i].disconnected || !input[i].shunt_resistor) -+ continue; -+ if (!shunt_resistor) { -+ /* Found the reference shunt resistor value */ -+ shunt_resistor = input[i].shunt_resistor; -+ } else { -+ /* No summation if resistor values are different */ -+ if (shunt_resistor != input[i].shunt_resistor) -+ return 0; -+ } -+ } -+ -+ return shunt_resistor; -+} -+ -+/* Lookup table for Bus and Shunt conversion times in usec */ -+static const u16 ina3221_conv_time[] = { -+ 140, 204, 332, 588, 1100, 2116, 4156, 8244, -+}; -+ -+/* Lookup table for number of samples using in averaging mode */ -+static const int ina3221_avg_samples[] = { -+ 1, 4, 16, 64, 128, 256, 512, 1024, -+}; -+ -+/* Converting update_interval in msec to conversion time in usec */ -+static inline u32 ina3221_interval_ms_to_conv_time(u16 config, int interval) -+{ -+ u32 channels = hweight16(config & INA3221_CONFIG_CHs_EN_MASK); -+ u32 samples_idx = INA3221_CONFIG_AVG(config); -+ u32 samples = ina3221_avg_samples[samples_idx]; -+ -+ /* Bisect the result to Bus and Shunt conversion times */ -+ return DIV_ROUND_CLOSEST(interval * 1000 / 2, channels * samples); -+} -+ -+/* Converting CONFIG register value to update_interval in usec */ -+static inline u32 ina3221_reg_to_interval_us(u16 config) -+{ -+ u32 channels = hweight16(config & INA3221_CONFIG_CHs_EN_MASK); -+ u32 vbus_ct_idx = INA3221_CONFIG_VBUS_CT(config); -+ u32 vsh_ct_idx = INA3221_CONFIG_VSH_CT(config); -+ u32 samples_idx = INA3221_CONFIG_AVG(config); -+ u32 samples = ina3221_avg_samples[samples_idx]; -+ u32 vbus_ct = ina3221_conv_time[vbus_ct_idx]; -+ u32 vsh_ct = ina3221_conv_time[vsh_ct_idx]; -+ -+ /* Calculate total conversion time */ -+ return channels * (vbus_ct + vsh_ct) * samples; -+} -+ -+static inline int ina3221_wait_for_data(struct ina3221_data *ina) -+{ -+ u32 wait, cvrf; -+ -+ wait = ina3221_reg_to_interval_us(ina->reg_config); -+ -+ /* Polling the CVRF bit to make sure read data is ready */ -+ return regmap_field_read_poll_timeout(ina->fields[F_CVRF], -+ cvrf, cvrf, wait, wait * 2); -+} -+ -+static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, -+ int *val) -+{ -+ unsigned int regval; -+ int ret; -+ -+ ret = regmap_read(ina->regmap, reg, ®val); -+ if (ret) -+ return ret; -+ -+ /* -+ * Shunt Voltage Sum register has 14-bit value with 1-bit shift -+ * Other Shunt Voltage registers have 12 bits with 3-bit shift -+ */ -+ if (reg == INA3221_SHUNT_SUM) -+ *val = sign_extend32(regval >> 1, 14); -+ else -+ *val = sign_extend32(regval >> 3, 12); -+ -+ return 0; -+} -+ -+static const u8 ina3221_in_reg[] = { -+ INA3221_BUS1, -+ INA3221_BUS2, -+ INA3221_BUS3, -+ INA3221_SHUNT1, -+ INA3221_SHUNT2, -+ INA3221_SHUNT3, -+ INA3221_SHUNT_SUM, -+}; -+ -+static int ina3221_read_chip(struct device *dev, u32 attr, long *val) -+{ -+ struct ina3221_data *ina = dev_get_drvdata(dev); -+ int regval; -+ -+ switch (attr) { -+ case hwmon_chip_samples: -+ regval = INA3221_CONFIG_AVG(ina->reg_config); -+ *val = ina3221_avg_samples[regval]; -+ return 0; -+ case hwmon_chip_update_interval: -+ /* Return in msec */ -+ *val = ina3221_reg_to_interval_us(ina->reg_config); -+ *val = DIV_ROUND_CLOSEST(*val, 1000); -+ return 0; -+ default: -+ return -EOPNOTSUPP; -+ } -+} -+ -+static int ina3221_read_in(struct device *dev, u32 attr, int channel, long *val) -+{ -+ const bool is_shunt = channel > INA3221_CHANNEL3; -+ struct ina3221_data *ina = dev_get_drvdata(dev); -+ u8 reg = ina3221_in_reg[channel]; -+ int regval, ret; -+ -+ /* -+ * Translate shunt channel index to sensor channel index except -+ * the 7th channel (6 since being 0-aligned) is for summation. -+ */ -+ if (channel != 6) -+ channel %= INA3221_NUM_CHANNELS; -+ -+ switch (attr) { -+ case hwmon_in_input: -+ if (!ina3221_is_enabled(ina, channel)) -+ return -ENODATA; -+ -+ /* Write CONFIG register to trigger a single-shot measurement */ -+ if (ina->single_shot) -+ regmap_write(ina->regmap, INA3221_CONFIG, -+ ina->reg_config); -+ -+ ret = ina3221_wait_for_data(ina); -+ if (ret) -+ return ret; -+ -+ ret = ina3221_read_value(ina, reg, ®val); -+ if (ret) -+ return ret; -+ -+ /* -+ * Scale of shunt voltage (uV): LSB is 40uV -+ * Scale of bus voltage (mV): LSB is 8mV -+ */ -+ *val = regval * (is_shunt ? 40 : 8); -+ return 0; -+ case hwmon_in_enable: -+ *val = ina3221_is_enabled(ina, channel); -+ return 0; -+ default: -+ return -EOPNOTSUPP; -+ } -+} -+ -+static const u8 ina3221_curr_reg[][INA3221_NUM_CHANNELS + 1] = { -+ [hwmon_curr_input] = { INA3221_SHUNT1, INA3221_SHUNT2, -+ INA3221_SHUNT3, INA3221_SHUNT_SUM }, -+ [hwmon_curr_max] = { INA3221_WARN1, INA3221_WARN2, INA3221_WARN3, 0 }, -+ [hwmon_curr_crit] = { INA3221_CRIT1, INA3221_CRIT2, -+ INA3221_CRIT3, INA3221_CRIT_SUM }, -+ [hwmon_curr_max_alarm] = { F_WF1, F_WF2, F_WF3, 0 }, -+ [hwmon_curr_crit_alarm] = { F_CF1, F_CF2, F_CF3, F_SF }, -+}; -+ -+static int ina3221_read_curr(struct device *dev, u32 attr, -+ int channel, long *val) -+{ -+ struct ina3221_data *ina = dev_get_drvdata(dev); -+ struct ina3221_input *input = ina->inputs; -+ u8 reg = ina3221_curr_reg[attr][channel]; -+ int resistance_uo, voltage_nv; -+ int regval, ret; -+ -+ if (channel > INA3221_CHANNEL3) -+ resistance_uo = ina->summation_shunt_resistor; -+ else -+ resistance_uo = input[channel].shunt_resistor; -+ -+ switch (attr) { -+ case hwmon_curr_input: -+ if (!ina3221_is_enabled(ina, channel)) -+ return -ENODATA; -+ -+ /* Write CONFIG register to trigger a single-shot measurement */ -+ if (ina->single_shot) -+ regmap_write(ina->regmap, INA3221_CONFIG, -+ ina->reg_config); -+ -+ ret = ina3221_wait_for_data(ina); -+ if (ret) -+ return ret; -+ -+ fallthrough; -+ case hwmon_curr_crit: -+ case hwmon_curr_max: -+ if (!resistance_uo) -+ return -ENODATA; -+ -+ ret = ina3221_read_value(ina, reg, ®val); -+ if (ret) -+ return ret; -+ -+ /* Scale of shunt voltage: LSB is 40uV (40000nV) */ -+ voltage_nv = regval * 40000; -+ /* Return current in mA */ -+ *val = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo); -+ return 0; -+ case hwmon_curr_crit_alarm: -+ case hwmon_curr_max_alarm: -+ /* No actual register read if channel is disabled */ -+ if (!ina3221_is_enabled(ina, channel)) { -+ /* Return 0 for alert flags */ -+ *val = 0; -+ return 0; -+ } -+ ret = regmap_field_read(ina->fields[reg], ®val); -+ if (ret) -+ return ret; -+ *val = regval; -+ return 0; -+ default: -+ return -EOPNOTSUPP; -+ } -+} -+ -+static int ina3221_write_chip(struct device *dev, u32 attr, long val) -+{ -+ struct ina3221_data *ina = dev_get_drvdata(dev); -+ int ret, idx; -+ u32 tmp; -+ -+ switch (attr) { -+ case hwmon_chip_samples: -+ idx = find_closest(val, ina3221_avg_samples, -+ ARRAY_SIZE(ina3221_avg_samples)); -+ -+ tmp = (ina->reg_config & ~INA3221_CONFIG_AVG_MASK) | -+ (idx << INA3221_CONFIG_AVG_SHIFT); -+ ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp); -+ if (ret) -+ return ret; -+ -+ /* Update reg_config accordingly */ -+ ina->reg_config = tmp; -+ return 0; -+ case hwmon_chip_update_interval: -+ tmp = ina3221_interval_ms_to_conv_time(ina->reg_config, val); -+ idx = find_closest(tmp, ina3221_conv_time, -+ ARRAY_SIZE(ina3221_conv_time)); -+ -+ /* Update Bus and Shunt voltage conversion times */ -+ tmp = INA3221_CONFIG_VBUS_CT_MASK | INA3221_CONFIG_VSH_CT_MASK; -+ tmp = (ina->reg_config & ~tmp) | -+ (idx << INA3221_CONFIG_VBUS_CT_SHIFT) | -+ (idx << INA3221_CONFIG_VSH_CT_SHIFT); -+ ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp); -+ if (ret) -+ return ret; -+ -+ /* Update reg_config accordingly */ -+ ina->reg_config = tmp; -+ return 0; -+ default: -+ return -EOPNOTSUPP; -+ } -+} -+ -+static int ina3221_write_curr(struct device *dev, u32 attr, -+ int channel, long val) -+{ -+ struct ina3221_data *ina = dev_get_drvdata(dev); -+ struct ina3221_input *input = ina->inputs; -+ u8 reg = ina3221_curr_reg[attr][channel]; -+ int resistance_uo, current_ma, voltage_uv; -+ int regval; -+ -+ if (channel > INA3221_CHANNEL3) -+ resistance_uo = ina->summation_shunt_resistor; -+ else -+ resistance_uo = input[channel].shunt_resistor; -+ -+ if (!resistance_uo) -+ return -EOPNOTSUPP; -+ -+ /* clamp current */ -+ current_ma = clamp_val(val, -+ INT_MIN / resistance_uo, -+ INT_MAX / resistance_uo); -+ -+ voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000); -+ -+ /* clamp voltage */ -+ voltage_uv = clamp_val(voltage_uv, -163800, 163800); -+ -+ /* -+ * Formula to convert voltage_uv to register value: -+ * regval = (voltage_uv / scale) << shift -+ * Note: -+ * The scale is 40uV for all shunt voltage registers -+ * Shunt Voltage Sum register left-shifts 1 bit -+ * All other Shunt Voltage registers shift 3 bits -+ * Results: -+ * SHUNT_SUM: (1 / 40uV) << 1 = 1 / 20uV -+ * SHUNT[1-3]: (1 / 40uV) << 3 = 1 / 5uV -+ */ -+ if (reg == INA3221_SHUNT_SUM) -+ regval = DIV_ROUND_CLOSEST(voltage_uv, 20) & 0xfffe; -+ else -+ regval = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8; -+ -+ return regmap_write(ina->regmap, reg, regval); -+} -+ -+static int ina3221_write_enable(struct device *dev, int channel, bool enable) -+{ -+ struct ina3221_data *ina = dev_get_drvdata(dev); -+ u16 config, mask = INA3221_CONFIG_CHx_EN(channel); -+ u16 config_old = ina->reg_config & mask; -+ u32 tmp; -+ int ret; -+ -+ config = enable ? mask : 0; -+ -+ /* Bypass if enable status is not being changed */ -+ if (config_old == config) -+ return 0; -+ -+ /* For enabling routine, increase refcount and resume() at first */ -+ if (enable) { -+ ret = pm_runtime_resume_and_get(ina->pm_dev); -+ if (ret < 0) { -+ dev_err(dev, "Failed to get PM runtime\n"); -+ return ret; -+ } -+ } -+ -+ /* Enable or disable the channel */ -+ tmp = (ina->reg_config & ~mask) | (config & mask); -+ ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp); -+ if (ret) -+ goto fail; -+ -+ /* Cache the latest config register value */ -+ ina->reg_config = tmp; -+ -+ /* For disabling routine, decrease refcount or suspend() at last */ -+ if (!enable) -+ pm_runtime_put_sync(ina->pm_dev); -+ -+ return 0; -+ -+fail: -+ if (enable) { -+ dev_err(dev, "Failed to enable channel %d: error %d\n", -+ channel, ret); -+ pm_runtime_put_sync(ina->pm_dev); -+ } -+ -+ return ret; -+} -+ -+static int ina3221_read(struct device *dev, enum hwmon_sensor_types type, -+ u32 attr, int channel, long *val) -+{ -+ struct ina3221_data *ina = dev_get_drvdata(dev); -+ int ret; -+ -+ mutex_lock(&ina->lock); -+ -+ switch (type) { -+ case hwmon_chip: -+ ret = ina3221_read_chip(dev, attr, val); -+ break; -+ case hwmon_in: -+ /* 0-align channel ID */ -+ ret = ina3221_read_in(dev, attr, channel - 1, val); -+ break; -+ case hwmon_curr: -+ ret = ina3221_read_curr(dev, attr, channel, val); -+ break; -+ default: -+ ret = -EOPNOTSUPP; -+ break; -+ } -+ -+ mutex_unlock(&ina->lock); -+ -+ return ret; -+} -+ -+static int ina3221_write(struct device *dev, enum hwmon_sensor_types type, -+ u32 attr, int channel, long val) -+{ -+ struct ina3221_data *ina = dev_get_drvdata(dev); -+ int ret; -+ -+ mutex_lock(&ina->lock); -+ -+ switch (type) { -+ case hwmon_chip: -+ ret = ina3221_write_chip(dev, attr, val); -+ break; -+ case hwmon_in: -+ /* 0-align channel ID */ -+ ret = ina3221_write_enable(dev, channel - 1, val); -+ break; -+ case hwmon_curr: -+ ret = ina3221_write_curr(dev, attr, channel, val); -+ break; -+ default: -+ ret = -EOPNOTSUPP; -+ break; -+ } -+ -+ mutex_unlock(&ina->lock); -+ -+ return ret; -+} -+ -+static int ina3221_read_string(struct device *dev, enum hwmon_sensor_types type, -+ u32 attr, int channel, const char **str) -+{ -+ struct ina3221_data *ina = dev_get_drvdata(dev); -+ int index = channel - 1; -+ -+ if (channel == 7) -+ *str = "sum of shunt voltages"; -+ else -+ *str = ina->inputs[index].label; -+ -+ return 0; -+} -+ -+static umode_t ina3221_is_visible(const void *drvdata, -+ enum hwmon_sensor_types type, -+ u32 attr, int channel) -+{ -+ const struct ina3221_data *ina = drvdata; -+ const struct ina3221_input *input = NULL; -+ -+ switch (type) { -+ case hwmon_chip: -+ switch (attr) { -+ case hwmon_chip_samples: -+ case hwmon_chip_update_interval: -+ return 0644; -+ default: -+ return 0; -+ } -+ case hwmon_in: -+ /* Ignore in0_ */ -+ if (channel == 0) -+ return 0; -+ -+ switch (attr) { -+ case hwmon_in_label: -+ if (channel - 1 <= INA3221_CHANNEL3) -+ input = &ina->inputs[channel - 1]; -+ else if (channel == 7) -+ return 0444; -+ /* Hide label node if label is not provided */ -+ return (input && input->label) ? 0444 : 0; -+ case hwmon_in_input: -+ return 0444; -+ case hwmon_in_enable: -+ return 0644; -+ default: -+ return 0; -+ } -+ case hwmon_curr: -+ switch (attr) { -+ case hwmon_curr_input: -+ case hwmon_curr_crit_alarm: -+ case hwmon_curr_max_alarm: -+ return 0444; -+ case hwmon_curr_crit: -+ case hwmon_curr_max: -+ return 0644; -+ default: -+ return 0; -+ } -+ default: -+ return 0; -+ } -+} -+ -+#define INA3221_HWMON_CURR_CONFIG (HWMON_C_INPUT | \ -+ HWMON_C_CRIT | HWMON_C_CRIT_ALARM | \ -+ HWMON_C_MAX | HWMON_C_MAX_ALARM) -+ -+static const struct hwmon_channel_info *ina3221_info[] = { -+ HWMON_CHANNEL_INFO(chip, -+ HWMON_C_SAMPLES, -+ HWMON_C_UPDATE_INTERVAL), -+ HWMON_CHANNEL_INFO(in, -+ /* 0: dummy, skipped in is_visible */ -+ HWMON_I_INPUT, -+ /* 1-3: input voltage Channels */ -+ HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, -+ HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, -+ HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, -+ /* 4-6: shunt voltage Channels */ -+ HWMON_I_INPUT, -+ HWMON_I_INPUT, -+ HWMON_I_INPUT, -+ /* 7: summation of shunt voltage channels */ -+ HWMON_I_INPUT | HWMON_I_LABEL), -+ HWMON_CHANNEL_INFO(curr, -+ /* 1-3: current channels*/ -+ INA3221_HWMON_CURR_CONFIG, -+ INA3221_HWMON_CURR_CONFIG, -+ INA3221_HWMON_CURR_CONFIG, -+ /* 4: summation of current channels */ -+ HWMON_C_INPUT | HWMON_C_CRIT | HWMON_C_CRIT_ALARM), -+ NULL -+}; -+ -+static const struct hwmon_ops ina3221_hwmon_ops = { -+ .is_visible = ina3221_is_visible, -+ .read_string = ina3221_read_string, -+ .read = ina3221_read, -+ .write = ina3221_write, -+}; -+ -+static const struct hwmon_chip_info ina3221_chip_info = { -+ .ops = &ina3221_hwmon_ops, -+ .info = ina3221_info, -+}; -+ -+/* Extra attribute groups */ -+static ssize_t ina3221_shunt_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); -+ struct ina3221_data *ina = dev_get_drvdata(dev); -+ unsigned int channel = sd_attr->index; -+ struct ina3221_input *input = &ina->inputs[channel]; -+ -+ return snprintf(buf, PAGE_SIZE, "%d\n", input->shunt_resistor); -+} -+ -+static ssize_t ina3221_shunt_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); -+ struct ina3221_data *ina = dev_get_drvdata(dev); -+ unsigned int channel = sd_attr->index; -+ struct ina3221_input *input = &ina->inputs[channel]; -+ int val; -+ int ret; -+ -+ ret = kstrtoint(buf, 0, &val); -+ if (ret) -+ return ret; -+ -+ val = clamp_val(val, 1, INT_MAX); -+ -+ input->shunt_resistor = val; -+ -+ /* Update summation_shunt_resistor for summation channel */ -+ ina->summation_shunt_resistor = ina3221_summation_shunt_resistor(ina); -+ -+ return count; -+} -+ -+/* shunt resistance */ -+static SENSOR_DEVICE_ATTR_RW(shunt1_resistor, ina3221_shunt, INA3221_CHANNEL1); -+static SENSOR_DEVICE_ATTR_RW(shunt2_resistor, ina3221_shunt, INA3221_CHANNEL2); -+static SENSOR_DEVICE_ATTR_RW(shunt3_resistor, ina3221_shunt, INA3221_CHANNEL3); -+ -+static struct attribute *ina3221_attrs[] = { -+ &sensor_dev_attr_shunt1_resistor.dev_attr.attr, -+ &sensor_dev_attr_shunt2_resistor.dev_attr.attr, -+ &sensor_dev_attr_shunt3_resistor.dev_attr.attr, -+ NULL, -+}; -+ATTRIBUTE_GROUPS(ina3221); -+ -+static const struct regmap_range ina3221_yes_ranges[] = { -+ regmap_reg_range(INA3221_CONFIG, INA3221_BUS3), -+ regmap_reg_range(INA3221_SHUNT_SUM, INA3221_SHUNT_SUM), -+ regmap_reg_range(INA3221_MASK_ENABLE, INA3221_MASK_ENABLE), -+}; -+ -+static const struct regmap_access_table ina3221_volatile_table = { -+ .yes_ranges = ina3221_yes_ranges, -+ .n_yes_ranges = ARRAY_SIZE(ina3221_yes_ranges), -+}; -+ -+static const struct regmap_config ina3221_regmap_config = { -+ .reg_bits = 8, -+ .val_bits = 16, -+ -+ .cache_type = REGCACHE_RBTREE, -+ .volatile_table = &ina3221_volatile_table, -+}; -+ -+static int ina3221_probe_child_from_dt(struct device *dev, -+ struct device_node *child, -+ struct ina3221_data *ina) -+{ -+ struct ina3221_input *input; -+ u32 val; -+ int ret; -+ -+ ret = of_property_read_u32(child, "reg", &val); -+ if (ret) { -+ dev_err(dev, "missing reg property of %pOFn\n", child); -+ return ret; -+ } else if (val > INA3221_CHANNEL3) { -+ dev_err(dev, "invalid reg %d of %pOFn\n", val, child); -+ return ret; -+ } -+ -+ input = &ina->inputs[val]; -+ -+ /* Log the disconnected channel input */ -+ if (!of_device_is_available(child)) { -+ input->disconnected = true; -+ return 0; -+ } -+ -+ /* Save the connected input label if available */ -+ of_property_read_string(child, "label", &input->label); -+ -+ /* Overwrite default shunt resistor value optionally */ -+ if (!of_property_read_u32(child, "shunt-resistor-micro-ohms", &val)) { -+ if (val < 1 || val > INT_MAX) { -+ dev_err(dev, "invalid shunt resistor value %u of %pOFn\n", -+ val, child); -+ return -EINVAL; -+ } -+ input->shunt_resistor = val; -+ } -+ -+ return 0; -+} -+ -+static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina) -+{ -+ const struct device_node *np = dev->of_node; -+ struct device_node *child; -+ int ret; -+ -+ /* Compatible with non-DT platforms */ -+ if (!np) -+ return 0; -+ -+ ina->single_shot = of_property_read_bool(np, "ti,single-shot"); -+ -+ for_each_child_of_node(np, child) { -+ ret = ina3221_probe_child_from_dt(dev, child, ina); -+ if (ret) { -+ of_node_put(child); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static int ina3221_probe(struct i2c_client *client) -+{ -+ struct device *dev = &client->dev; -+ struct ina3221_data *ina; -+ struct device *hwmon_dev; -+ int i, ret; -+ -+ ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL); -+ if (!ina) -+ return -ENOMEM; -+ -+ ina->regmap = devm_regmap_init_i2c(client, &ina3221_regmap_config); -+ if (IS_ERR(ina->regmap)) { -+ dev_err(dev, "Unable to allocate register map\n"); -+ return PTR_ERR(ina->regmap); -+ } -+ -+ for (i = 0; i < F_MAX_FIELDS; i++) { -+ ina->fields[i] = devm_regmap_field_alloc(dev, -+ ina->regmap, -+ ina3221_reg_fields[i]); -+ if (IS_ERR(ina->fields[i])) { -+ dev_err(dev, "Unable to allocate regmap fields\n"); -+ return PTR_ERR(ina->fields[i]); -+ } -+ } -+ -+ for (i = 0; i < INA3221_NUM_CHANNELS; i++) -+ ina->inputs[i].shunt_resistor = INA3221_RSHUNT_DEFAULT; -+ -+ ret = ina3221_probe_from_dt(dev, ina); -+ if (ret) { -+ dev_err(dev, "Unable to probe from device tree\n"); -+ return ret; -+ } -+ -+ /* The driver will be reset, so use reset value */ -+ ina->reg_config = INA3221_CONFIG_DEFAULT; -+ -+ /* Clear continuous bit to use single-shot mode */ -+ if (ina->single_shot) -+ ina->reg_config &= ~INA3221_CONFIG_MODE_CONTINUOUS; -+ -+ /* Disable channels if their inputs are disconnected */ -+ for (i = 0; i < INA3221_NUM_CHANNELS; i++) { -+ if (ina->inputs[i].disconnected) -+ ina->reg_config &= ~INA3221_CONFIG_CHx_EN(i); -+ } -+ -+ /* Initialize summation_shunt_resistor for summation channel control */ -+ ina->summation_shunt_resistor = ina3221_summation_shunt_resistor(ina); -+ -+ ina->pm_dev = dev; -+ mutex_init(&ina->lock); -+ dev_set_drvdata(dev, ina); -+ -+ /* Enable PM runtime -- status is suspended by default */ -+ pm_runtime_enable(ina->pm_dev); -+ -+ /* Initialize (resume) the device */ -+ for (i = 0; i < INA3221_NUM_CHANNELS; i++) { -+ if (ina->inputs[i].disconnected) -+ continue; -+ /* Match the refcount with number of enabled channels */ -+ ret = pm_runtime_get_sync(ina->pm_dev); -+ if (ret < 0) -+ goto fail; -+ } -+ -+ hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ina, -+ &ina3221_chip_info, -+ ina3221_groups); -+ if (IS_ERR(hwmon_dev)) { -+ dev_err(dev, "Unable to register hwmon device\n"); -+ ret = PTR_ERR(hwmon_dev); -+ goto fail; -+ } -+ -+ return 0; -+ -+fail: -+ pm_runtime_disable(ina->pm_dev); -+ pm_runtime_set_suspended(ina->pm_dev); -+ /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */ -+ for (i = 0; i < INA3221_NUM_CHANNELS; i++) -+ pm_runtime_put_noidle(ina->pm_dev); -+ mutex_destroy(&ina->lock); -+ -+ return ret; -+} -+ -+static int ina3221_remove(struct i2c_client *client) -+{ -+ struct ina3221_data *ina = dev_get_drvdata(&client->dev); -+ int i; -+ -+ pm_runtime_disable(ina->pm_dev); -+ pm_runtime_set_suspended(ina->pm_dev); -+ -+ /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */ -+ for (i = 0; i < INA3221_NUM_CHANNELS; i++) -+ pm_runtime_put_noidle(ina->pm_dev); -+ -+ mutex_destroy(&ina->lock); -+ -+ return 0; -+} -+ -+static int __maybe_unused ina3221_suspend(struct device *dev) -+{ -+ struct ina3221_data *ina = dev_get_drvdata(dev); -+ int ret; -+ -+ /* Save config register value and enable cache-only */ -+ ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); -+ if (ret) -+ return ret; -+ -+ /* Set to power-down mode for power saving */ -+ ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, -+ INA3221_CONFIG_MODE_MASK, -+ INA3221_CONFIG_MODE_POWERDOWN); -+ if (ret) -+ return ret; -+ -+ regcache_cache_only(ina->regmap, true); -+ regcache_mark_dirty(ina->regmap); -+ -+ return 0; -+} -+ -+static int __maybe_unused ina3221_resume(struct device *dev) -+{ -+ struct ina3221_data *ina = dev_get_drvdata(dev); -+ int ret; -+ -+ regcache_cache_only(ina->regmap, false); -+ -+ /* Software reset the chip */ -+ ret = regmap_field_write(ina->fields[F_RST], true); -+ if (ret) { -+ dev_err(dev, "Unable to reset device\n"); -+ return ret; -+ } -+ -+ /* Restore cached register values to hardware */ -+ ret = regcache_sync(ina->regmap); -+ if (ret) -+ return ret; -+ -+ /* Restore config register value to hardware */ -+ ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config); -+ if (ret) -+ return ret; -+ -+ /* Initialize summation channel control */ -+ if (ina->summation_shunt_resistor) { -+ /* -+ * Take all three channels into summation by default -+ * Shunt measurements of disconnected channels should -+ * be 0, so it does not matter for summation. -+ */ -+ ret = regmap_update_bits(ina->regmap, INA3221_MASK_ENABLE, -+ INA3221_MASK_ENABLE_SCC_MASK, -+ INA3221_MASK_ENABLE_SCC_MASK); -+ if (ret) { -+ dev_err(dev, "Unable to control summation channel\n"); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops ina3221_pm = { -+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, -+ pm_runtime_force_resume) -+ SET_RUNTIME_PM_OPS(ina3221_suspend, ina3221_resume, NULL) -+}; -+ -+static const struct of_device_id ina3221_of_match_table[] = { -+ { .compatible = "ti,wb_ina3221", }, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, ina3221_of_match_table); -+ -+static const struct i2c_device_id ina3221_ids[] = { -+ { "wb_ina3221", 0 }, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(i2c, ina3221_ids); -+ -+static struct i2c_driver ina3221_i2c_driver = { -+ .probe_new = ina3221_probe, -+ .remove = ina3221_remove, -+ .driver = { -+ .name = INA3221_DRIVER_NAME, -+ .of_match_table = ina3221_of_match_table, -+ .pm = &ina3221_pm, -+ }, -+ .id_table = ina3221_ids, -+}; -+module_i2c_driver(ina3221_i2c_driver); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("Texas Instruments INA3221 HWMon Driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_isl68137.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_isl68137.c -new file mode 100644 -index 000000000..5b3b54d92 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_isl68137.c -@@ -0,0 +1,572 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Hardware monitoring driver for Renesas Digital Multiphase Voltage Regulators -+ * -+ * Copyright (c) 2017 Google Inc -+ * Copyright (c) 2020 Renesas Electronics America -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "wb_pmbus.h" -+ -+#define ISL68137_VOUT_AVS (0x30) -+#define RAA_DMPVR2_READ_VMON (0xc8) -+#define WRITE_PROTECT_CLOSE (0x00) -+#define WRITE_PROTECT_OPEN (0x40) -+ -+static int g_wb_isl68137_debug = 0; -+static int g_wb_isl68137_error = 0; -+ -+module_param(g_wb_isl68137_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_isl68137_error, int, S_IRUGO | S_IWUSR); -+ -+#define WB_ISL68137_VERBOSE(fmt, args...) do { \ -+ if (g_wb_isl68137_debug) { \ -+ printk(KERN_INFO "[WB_ISL68137][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_ISL68137_ERROR(fmt, args...) do { \ -+ if (g_wb_isl68137_error) { \ -+ printk(KERN_ERR "[WB_ISL68137][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+enum chips { -+ isl68137, -+ isl68220, -+ isl68221, -+ isl68222, -+ isl68223, -+ isl68224, -+ isl68225, -+ isl68226, -+ isl68227, -+ isl68229, -+ isl68233, -+ isl68239, -+ isl69222, -+ isl69223, -+ isl69224, -+ isl69225, -+ isl69227, -+ isl69228, -+ isl69234, -+ isl69236, -+ isl69239, -+ isl69242, -+ isl69243, -+ isl69247, -+ isl69248, -+ isl69254, -+ isl69255, -+ isl69256, -+ isl69259, -+ isl69260, -+ isl69268, -+ isl69269, -+ isl69298, -+ raa228000, -+ raa228004, -+ raa228006, -+ raa228228, -+ raa229001, -+ raa229004, -+}; -+ -+enum variants { -+ raa_dmpvr1_2rail, -+ raa_dmpvr2_1rail, -+ raa_dmpvr2_2rail, -+ raa_dmpvr2_2rail_nontc, -+ raa_dmpvr2_3rail, -+ raa_dmpvr2_hv, -+}; -+ -+static const struct i2c_device_id raa_dmpvr_id[]; -+ -+static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client, -+ int page, -+ char *buf) -+{ -+ int val = wb_pmbus_read_byte_data(client, page, PMBUS_OPERATION); -+ -+ return sprintf(buf, "%d\n", -+ (val & ISL68137_VOUT_AVS) == ISL68137_VOUT_AVS ? 1 : 0); -+} -+ -+static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client, -+ int page, -+ const char *buf, size_t count) -+{ -+ int rc, op_val; -+ bool result; -+ -+ rc = kstrtobool(buf, &result); -+ if (rc) -+ return rc; -+ -+ op_val = result ? ISL68137_VOUT_AVS : 0; -+ -+ /* -+ * Writes to VOUT setpoint over AVSBus will persist after the VRM is -+ * switched to PMBus control. Switching back to AVSBus control -+ * restores this persisted setpoint rather than re-initializing to -+ * PMBus VOUT_COMMAND. Writing VOUT_COMMAND first over PMBus before -+ * enabling AVS control is the workaround. -+ */ -+ if (op_val == ISL68137_VOUT_AVS) { -+ rc = wb_pmbus_read_word_data(client, page, 0xff, -+ PMBUS_VOUT_COMMAND); -+ if (rc < 0) -+ return rc; -+ -+ rc = wb_pmbus_write_word_data(client, page, PMBUS_VOUT_COMMAND, -+ rc); -+ if (rc < 0) -+ return rc; -+ } -+ -+ rc = wb_pmbus_update_byte_data(client, page, PMBUS_OPERATION, -+ ISL68137_VOUT_AVS, op_val); -+ -+ return (rc < 0) ? rc : count; -+} -+ -+static ssize_t isl68137_avs_enable_show(struct device *dev, -+ struct device_attribute *devattr, -+ char *buf) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ -+ return isl68137_avs_enable_show_page(client, attr->index, buf); -+} -+ -+static ssize_t isl68137_avs_enable_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ -+ return isl68137_avs_enable_store_page(client, attr->index, buf, count); -+} -+ -+static ssize_t isl68137_avs_vout_show(struct device *dev, struct device_attribute *devattr, -+ char *buf) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ int vout_cmd, vout; -+ -+ mutex_lock(&data->update_lock); -+ vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); -+ if (vout_cmd < 0) { -+ WB_ISL68137_ERROR("%d-%04x: read page%d vout command reg: 0x%x failed, ret: %d\n", -+ client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd); -+ mutex_unlock(&data->update_lock); -+ return vout_cmd; -+ } -+ vout = vout_cmd * 1000; -+ WB_ISL68137_VERBOSE("%d-%04x: page%d, vout: %d, vout_cmd: 0x%x\n", client->adapter->nr, -+ client->addr, attr->index, vout, vout_cmd); -+ mutex_unlock(&data->update_lock); -+ return snprintf(buf, PAGE_SIZE, "%d\n", vout); -+} -+ -+static ssize_t isl68137_avs_vout_store(struct device *dev, struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ int vout, vout_max, vout_min; -+ int ret, vout_cmd, vout_cmd_set; -+ -+ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { -+ WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, -+ attr->index); -+ return -EINVAL; -+ } -+ -+ ret = kstrtoint(buf, 0, &vout); -+ if (ret) { -+ WB_ISL68137_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); -+ return -EINVAL; -+ } -+ -+ vout_max = data->vout_max[attr->index]; -+ vout_min = data->vout_min[attr->index]; -+ if ((vout > vout_max) || (vout < vout_min)) { -+ WB_ISL68137_ERROR("%d-%04x: vout value: %d, out of range [%d, %d] \n", client->adapter->nr, -+ client->addr, vout, vout_min, vout_max); -+ return -EINVAL; -+ } -+ -+ /* calc VOUT_COMMAND set value */ -+ vout_cmd_set = vout / 1000; -+ if (vout_cmd_set > 0xffff) { -+ WB_ISL68137_ERROR("%d-%04x: invalid value, vout %d, vout_cmd_set: 0x%x\n", -+ client->adapter->nr, client->addr, vout, vout_cmd_set); -+ return -EINVAL; -+ } -+ -+ mutex_lock(&data->update_lock); -+ -+ /* close write protect */ -+ ret = wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, WRITE_PROTECT_CLOSE); -+ if (ret < 0) { -+ WB_ISL68137_ERROR("%d-%04x: close page%d write protect failed, ret: %d\n", client->adapter->nr, -+ client->addr, attr->index, ret); -+ mutex_unlock(&data->update_lock); -+ return ret; -+ } -+ -+ /* set VOUT_COMMAND */ -+ ret = wb_pmbus_write_word_data(client, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set); -+ if (ret < 0) { -+ WB_ISL68137_ERROR("%d-%04x: set page%d vout cmd reg: 0x%x, value: 0x%x failed, ret: %d\n", -+ client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set, ret); -+ goto error; -+ } -+ -+ /* read back VOUT_COMMAND */ -+ vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); -+ if (vout_cmd < 0) { -+ ret = vout_cmd; -+ WB_ISL68137_ERROR("%d-%04x: read page%d vout command reg: 0x%x failed, ret: %d\n", -+ client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, ret); -+ goto error; -+ } -+ -+ /* compare vout_cmd and vout_cmd_set */ -+ if (vout_cmd != vout_cmd_set) { -+ ret = -EIO; -+ WB_ISL68137_ERROR("%d-%04x: vout cmd value check error, vout cmd read: 0x%x, vout cmd set: 0x%x\n", -+ client->adapter->nr, client->addr, vout_cmd, vout_cmd_set); -+ goto error; -+ } -+ -+ /* open write protect */ -+ wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, WRITE_PROTECT_OPEN); -+ mutex_unlock(&data->update_lock); -+ WB_ISL68137_VERBOSE("%d-%04x: set page%d vout cmd success, vout %d, vout_cmd_set: 0x%x\n", -+ client->adapter->nr, client->addr, attr->index, vout, vout_cmd_set); -+ return count; -+error: -+ wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, WRITE_PROTECT_OPEN); -+ mutex_unlock(&data->update_lock); -+ return ret; -+} -+ -+static ssize_t isl68137_avs_vout_max_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, size_t count) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ int ret, vout_threshold; -+ -+ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { -+ WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, -+ attr->index); -+ return -EINVAL; -+ } -+ -+ ret = kstrtoint(buf, 0, &vout_threshold); -+ if (ret) { -+ WB_ISL68137_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); -+ return -EINVAL; -+ } -+ -+ WB_ISL68137_VERBOSE("%d-%04x: vout%d max threshold: %d", client->adapter->nr, client->addr, -+ attr->index, vout_threshold); -+ -+ data->vout_max[attr->index] = vout_threshold; -+ return count; -+} -+ -+static ssize_t isl68137_avs_vout_max_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ -+ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { -+ WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, -+ attr->index); -+ return -EINVAL; -+ } -+ -+ return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_max[attr->index]); -+} -+ -+static ssize_t isl68137_avs_vout_min_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, size_t count) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ int ret, vout_threshold; -+ -+ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { -+ WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, -+ attr->index); -+ return -EINVAL; -+ } -+ -+ ret = kstrtoint(buf, 0, &vout_threshold); -+ if (ret) { -+ WB_ISL68137_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); -+ return -EINVAL; -+ } -+ -+ WB_ISL68137_VERBOSE("%d-%04x: vout%d min threshold: %d", client->adapter->nr, client->addr, -+ attr->index, vout_threshold); -+ -+ data->vout_min[attr->index] = vout_threshold; -+ return count; -+} -+ -+static ssize_t isl68137_avs_vout_min_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ -+ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { -+ WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, -+ attr->index); -+ return -EINVAL; -+ } -+ -+ return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_min[attr->index]); -+} -+ -+static SENSOR_DEVICE_ATTR_RW(avs0_enable, isl68137_avs_enable, 0); -+static SENSOR_DEVICE_ATTR_RW(avs1_enable, isl68137_avs_enable, 1); -+ -+static SENSOR_DEVICE_ATTR_RW(avs0_vout, isl68137_avs_vout, 0); -+static SENSOR_DEVICE_ATTR_RW(avs1_vout, isl68137_avs_vout, 1); -+static SENSOR_DEVICE_ATTR_RW(avs0_vout_max, isl68137_avs_vout_max, 0); -+static SENSOR_DEVICE_ATTR_RW(avs0_vout_min, isl68137_avs_vout_min, 0); -+static SENSOR_DEVICE_ATTR_RW(avs1_vout_max, isl68137_avs_vout_max, 1); -+static SENSOR_DEVICE_ATTR_RW(avs1_vout_min, isl68137_avs_vout_min, 1); -+ -+static struct attribute *enable_attrs[] = { -+ &sensor_dev_attr_avs0_enable.dev_attr.attr, -+ &sensor_dev_attr_avs1_enable.dev_attr.attr, -+ NULL, -+}; -+ -+static struct attribute *avs_ctrl_attrs[] = { -+ &sensor_dev_attr_avs0_vout.dev_attr.attr, -+ &sensor_dev_attr_avs1_vout.dev_attr.attr, -+ &sensor_dev_attr_avs0_vout_max.dev_attr.attr, -+ &sensor_dev_attr_avs0_vout_min.dev_attr.attr, -+ &sensor_dev_attr_avs1_vout_max.dev_attr.attr, -+ &sensor_dev_attr_avs1_vout_min.dev_attr.attr, -+ NULL, -+}; -+ -+static const struct attribute_group enable_group = { -+ .attrs = enable_attrs, -+}; -+ -+static const struct attribute_group avs_ctrl_group = { -+ .attrs = avs_ctrl_attrs, -+}; -+ -+static const struct attribute_group *isl68137_attribute_groups[] = { -+ &enable_group, -+ &avs_ctrl_group, -+ NULL, -+}; -+ -+static int raa_dmpvr2_read_word_data(struct i2c_client *client, int page, -+ int phase, int reg) -+{ -+ int ret; -+ -+ switch (reg) { -+ case PMBUS_VIRT_READ_VMON: -+ ret = wb_pmbus_read_word_data(client, page, phase, -+ RAA_DMPVR2_READ_VMON); -+ break; -+ default: -+ ret = -ENODATA; -+ break; -+ } -+ -+ return ret; -+} -+ -+static struct pmbus_driver_info raa_dmpvr_info = { -+ .pages = 3, -+ .format[PSC_VOLTAGE_IN] = direct, -+ .format[PSC_VOLTAGE_OUT] = direct, -+ .format[PSC_CURRENT_IN] = direct, -+ .format[PSC_CURRENT_OUT] = direct, -+ .format[PSC_POWER] = direct, -+ .format[PSC_TEMPERATURE] = direct, -+ .m[PSC_VOLTAGE_IN] = 1, -+ .b[PSC_VOLTAGE_IN] = 0, -+ .R[PSC_VOLTAGE_IN] = 2, -+ .m[PSC_VOLTAGE_OUT] = 1, -+ .b[PSC_VOLTAGE_OUT] = 0, -+ .R[PSC_VOLTAGE_OUT] = 3, -+ .m[PSC_CURRENT_IN] = 1, -+ .b[PSC_CURRENT_IN] = 0, -+ .R[PSC_CURRENT_IN] = 2, -+ .m[PSC_CURRENT_OUT] = 1, -+ .b[PSC_CURRENT_OUT] = 0, -+ .R[PSC_CURRENT_OUT] = 1, -+ .m[PSC_POWER] = 1, -+ .b[PSC_POWER] = 0, -+ .R[PSC_POWER] = 0, -+ .m[PSC_TEMPERATURE] = 1, -+ .b[PSC_TEMPERATURE] = 0, -+ .R[PSC_TEMPERATURE] = 0, -+ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN -+ | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 -+ | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP -+ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT -+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT -+ | PMBUS_HAVE_VMON, -+ .func[1] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT -+ | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP -+ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT -+ | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, -+ .func[2] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT -+ | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP -+ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT -+ | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, -+}; -+ -+static int isl68137_probe(struct i2c_client *client) -+{ -+ struct pmbus_driver_info *info; -+ -+ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); -+ if (!info) -+ return -ENOMEM; -+ memcpy(info, &raa_dmpvr_info, sizeof(*info)); -+ -+ switch (i2c_match_id(raa_dmpvr_id, client)->driver_data) { -+ case raa_dmpvr1_2rail: -+ info->pages = 2; -+ info->R[PSC_VOLTAGE_IN] = 3; -+ info->func[0] &= ~PMBUS_HAVE_VMON; -+ info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT -+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT -+ | PMBUS_HAVE_POUT; -+ info->groups = isl68137_attribute_groups; -+ break; -+ case raa_dmpvr2_1rail: -+ info->pages = 1; -+ info->read_word_data = raa_dmpvr2_read_word_data; -+ break; -+ case raa_dmpvr2_2rail_nontc: -+ info->func[0] &= ~PMBUS_HAVE_TEMP3; -+ info->func[1] &= ~PMBUS_HAVE_TEMP3; -+ fallthrough; -+ case raa_dmpvr2_2rail: -+ info->pages = 2; -+ info->read_word_data = raa_dmpvr2_read_word_data; -+ break; -+ case raa_dmpvr2_3rail: -+ info->read_word_data = raa_dmpvr2_read_word_data; -+ break; -+ case raa_dmpvr2_hv: -+ info->pages = 1; -+ info->R[PSC_VOLTAGE_IN] = 1; -+ info->m[PSC_VOLTAGE_OUT] = 2; -+ info->R[PSC_VOLTAGE_OUT] = 2; -+ info->m[PSC_CURRENT_IN] = 2; -+ info->m[PSC_POWER] = 2; -+ info->R[PSC_POWER] = -1; -+ info->read_word_data = raa_dmpvr2_read_word_data; -+ break; -+ default: -+ return -ENODEV; -+ } -+ -+ return wb_pmbus_do_probe(client, info); -+} -+ -+static const struct i2c_device_id raa_dmpvr_id[] = { -+ {"wb_isl68127", raa_dmpvr1_2rail}, -+ {"wb_isl68137", raa_dmpvr1_2rail}, -+ {"wb_isl68220", raa_dmpvr2_2rail}, -+ {"wb_isl68221", raa_dmpvr2_3rail}, -+ {"wb_isl68222", raa_dmpvr2_2rail}, -+ {"wb_isl68223", raa_dmpvr2_2rail}, -+ {"wb_isl68224", raa_dmpvr2_3rail}, -+ {"wb_isl68225", raa_dmpvr2_2rail}, -+ {"wb_isl68226", raa_dmpvr2_3rail}, -+ {"wb_isl68227", raa_dmpvr2_1rail}, -+ {"wb_isl68229", raa_dmpvr2_3rail}, -+ {"wb_isl68233", raa_dmpvr2_2rail}, -+ {"wb_isl68239", raa_dmpvr2_3rail}, -+ -+ {"wb_isl69222", raa_dmpvr2_2rail}, -+ {"wb_isl69223", raa_dmpvr2_3rail}, -+ {"wb_isl69224", raa_dmpvr2_2rail}, -+ {"wb_isl69225", raa_dmpvr2_2rail}, -+ {"wb_isl69227", raa_dmpvr2_3rail}, -+ {"wb_isl69228", raa_dmpvr2_3rail}, -+ {"wb_isl69234", raa_dmpvr2_2rail}, -+ {"wb_isl69236", raa_dmpvr2_2rail}, -+ {"wb_isl69239", raa_dmpvr2_3rail}, -+ {"wb_isl69242", raa_dmpvr2_2rail}, -+ {"wb_isl69243", raa_dmpvr2_1rail}, -+ {"wb_isl69247", raa_dmpvr2_2rail}, -+ {"wb_isl69248", raa_dmpvr2_2rail}, -+ {"wb_isl69254", raa_dmpvr2_2rail}, -+ {"wb_isl69255", raa_dmpvr2_2rail}, -+ {"wb_isl69256", raa_dmpvr2_2rail}, -+ {"wb_isl69259", raa_dmpvr2_2rail}, -+ {"wb_isl69260", raa_dmpvr2_2rail}, -+ {"wb_isl69268", raa_dmpvr2_2rail}, -+ {"wb_isl69269", raa_dmpvr2_3rail}, -+ {"wb_isl69298", raa_dmpvr2_2rail}, -+ -+ {"wb_raa228000", raa_dmpvr2_hv}, -+ {"wb_raa228004", raa_dmpvr2_hv}, -+ {"wb_raa228006", raa_dmpvr2_hv}, -+ {"wb_raa228228", raa_dmpvr2_2rail_nontc}, -+ {"wb_raa229001", raa_dmpvr2_2rail}, -+ {"wb_raa229004", raa_dmpvr2_2rail}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(i2c, raa_dmpvr_id); -+ -+/* This is the driver that will be inserted */ -+static struct i2c_driver isl68137_driver = { -+ .driver = { -+ .name = "wb_isl68137", -+ }, -+ .probe_new = isl68137_probe, -+ .remove = wb_pmbus_do_remove, -+ .id_table = raa_dmpvr_id, -+}; -+ -+module_i2c_driver(isl68137_driver); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("PMBus driver for Renesas digital multiphase voltage regulators"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.c -new file mode 100644 -index 000000000..0386cfb0b ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.c -@@ -0,0 +1,992 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * lm75.c - Part of lm_sensors, Linux kernel modules for hardware -+ * monitoring -+ * Copyright (c) 1998, 1999 Frodo Looijaard -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "wb_lm75.h" -+ -+/* -+ * This driver handles the LM75 and compatible digital temperature sensors. -+ */ -+ -+enum lm75_type { /* keep sorted in alphabetical order */ -+ adt75, -+ ds1775, -+ ds75, -+ ds7505, -+ g751, -+ lm75, -+ lm75a, -+ lm75b, -+ max6625, -+ max6626, -+ max31725, -+ mcp980x, -+ pct2075, -+ stds75, -+ stlm75, -+ tcn75, -+ tmp100, -+ tmp101, -+ tmp105, -+ tmp112, -+ tmp175, -+ tmp275, -+ tmp75, -+ tmp75b, -+ tmp75c, -+}; -+ -+/** -+ * struct lm75_params - lm75 configuration parameters. -+ * @set_mask: Bits to set in configuration register when configuring -+ * the chip. -+ * @clr_mask: Bits to clear in configuration register when configuring -+ * the chip. -+ * @default_resolution: Default number of bits to represent the temperature -+ * value. -+ * @resolution_limits: Limit register resolution. Optional. Should be set if -+ * the resolution of limit registers does not match the -+ * resolution of the temperature register. -+ * @resolutions: List of resolutions associated with sample times. -+ * Optional. Should be set if num_sample_times is larger -+ * than 1, and if the resolution changes with sample times. -+ * If set, number of entries must match num_sample_times. -+ * @default_sample_time:Sample time to be set by default. -+ * @num_sample_times: Number of possible sample times to be set. Optional. -+ * Should be set if the number of sample times is larger -+ * than one. -+ * @sample_times: All the possible sample times to be set. Mandatory if -+ * num_sample_times is larger than 1. If set, number of -+ * entries must match num_sample_times. -+ */ -+ -+struct lm75_params { -+ u8 set_mask; -+ u8 clr_mask; -+ u8 default_resolution; -+ u8 resolution_limits; -+ const u8 *resolutions; -+ unsigned int default_sample_time; -+ u8 num_sample_times; -+ const unsigned int *sample_times; -+}; -+#if 0 -+/* Addresses scanned */ -+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, -+ 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; -+#endif -+/* The LM75 registers */ -+#define LM75_REG_TEMP 0x00 -+#define LM75_REG_CONF 0x01 -+#define LM75_REG_HYST 0x02 -+#define LM75_REG_MAX 0x03 -+#define PCT2075_REG_IDLE 0x04 -+#define LM75_TEMP_INVALID_RETRY_TIMES (3) -+ -+/* Each client has this additional data */ -+struct lm75_data { -+ struct i2c_client *client; -+ struct regmap *regmap; -+ struct regulator *vs; -+ u8 orig_conf; -+ u8 current_conf; -+ u8 resolution; /* In bits, 9 to 16 */ -+ unsigned int sample_time; /* In ms */ -+ enum lm75_type kind; -+ const struct lm75_params *params; -+}; -+ -+/*-----------------------------------------------------------------------*/ -+ -+static const u8 lm75_sample_set_masks[] = { 0 << 5, 1 << 5, 2 << 5, 3 << 5 }; -+ -+#define LM75_SAMPLE_CLEAR_MASK (3 << 5) -+ -+/* The structure below stores the configuration values of the supported devices. -+ * In case of being supported multiple configurations, the default one must -+ * always be the first element of the array -+ */ -+static const struct lm75_params device_params[] = { -+ [adt75] = { -+ .clr_mask = 1 << 5, /* not one-shot mode */ -+ .default_resolution = 12, -+ .default_sample_time = MSEC_PER_SEC / 10, -+ }, -+ [ds1775] = { -+ .clr_mask = 3 << 5, -+ .set_mask = 2 << 5, /* 11-bit mode */ -+ .default_resolution = 11, -+ .default_sample_time = 500, -+ .num_sample_times = 4, -+ .sample_times = (unsigned int []){ 125, 250, 500, 1000 }, -+ .resolutions = (u8 []) {9, 10, 11, 12 }, -+ }, -+ [ds75] = { -+ .clr_mask = 3 << 5, -+ .set_mask = 2 << 5, /* 11-bit mode */ -+ .default_resolution = 11, -+ .default_sample_time = 600, -+ .num_sample_times = 4, -+ .sample_times = (unsigned int []){ 150, 300, 600, 1200 }, -+ .resolutions = (u8 []) {9, 10, 11, 12 }, -+ }, -+ [stds75] = { -+ .clr_mask = 3 << 5, -+ .set_mask = 2 << 5, /* 11-bit mode */ -+ .default_resolution = 11, -+ .default_sample_time = 600, -+ .num_sample_times = 4, -+ .sample_times = (unsigned int []){ 150, 300, 600, 1200 }, -+ .resolutions = (u8 []) {9, 10, 11, 12 }, -+ }, -+ [stlm75] = { -+ .default_resolution = 9, -+ .default_sample_time = MSEC_PER_SEC / 6, -+ }, -+ [ds7505] = { -+ .set_mask = 3 << 5, /* 12-bit mode*/ -+ .default_resolution = 12, -+ .default_sample_time = 200, -+ .num_sample_times = 4, -+ .sample_times = (unsigned int []){ 25, 50, 100, 200 }, -+ .resolutions = (u8 []) {9, 10, 11, 12 }, -+ }, -+ [g751] = { -+ .default_resolution = 9, -+ .default_sample_time = MSEC_PER_SEC / 10, -+ }, -+ [lm75] = { -+ .default_resolution = 9, -+ .default_sample_time = MSEC_PER_SEC / 10, -+ }, -+ [lm75a] = { -+ .default_resolution = 9, -+ .default_sample_time = MSEC_PER_SEC / 10, -+ }, -+ [lm75b] = { -+ .default_resolution = 11, -+ .default_sample_time = MSEC_PER_SEC / 10, -+ }, -+ [max6625] = { -+ .default_resolution = 9, -+ .default_sample_time = MSEC_PER_SEC / 7, -+ }, -+ [max6626] = { -+ .default_resolution = 12, -+ .default_sample_time = MSEC_PER_SEC / 7, -+ .resolution_limits = 9, -+ }, -+ [max31725] = { -+ .default_resolution = 16, -+ .default_sample_time = MSEC_PER_SEC / 20, -+ }, -+ [tcn75] = { -+ .default_resolution = 9, -+ .default_sample_time = MSEC_PER_SEC / 18, -+ }, -+ [pct2075] = { -+ .default_resolution = 11, -+ .default_sample_time = MSEC_PER_SEC / 10, -+ .num_sample_times = 31, -+ .sample_times = (unsigned int []){ 100, 200, 300, 400, 500, 600, -+ 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, -+ 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, -+ 2800, 2900, 3000, 3100 }, -+ }, -+ [mcp980x] = { -+ .set_mask = 3 << 5, /* 12-bit mode */ -+ .clr_mask = 1 << 7, /* not one-shot mode */ -+ .default_resolution = 12, -+ .resolution_limits = 9, -+ .default_sample_time = 240, -+ .num_sample_times = 4, -+ .sample_times = (unsigned int []){ 30, 60, 120, 240 }, -+ .resolutions = (u8 []) {9, 10, 11, 12 }, -+ }, -+ [tmp100] = { -+ .set_mask = 3 << 5, /* 12-bit mode */ -+ .clr_mask = 1 << 7, /* not one-shot mode */ -+ .default_resolution = 12, -+ .default_sample_time = 320, -+ .num_sample_times = 4, -+ .sample_times = (unsigned int []){ 40, 80, 160, 320 }, -+ .resolutions = (u8 []) {9, 10, 11, 12 }, -+ }, -+ [tmp101] = { -+ .set_mask = 3 << 5, /* 12-bit mode */ -+ .clr_mask = 1 << 7, /* not one-shot mode */ -+ .default_resolution = 12, -+ .default_sample_time = 320, -+ .num_sample_times = 4, -+ .sample_times = (unsigned int []){ 40, 80, 160, 320 }, -+ .resolutions = (u8 []) {9, 10, 11, 12 }, -+ }, -+ [tmp105] = { -+ .set_mask = 3 << 5, /* 12-bit mode */ -+ .clr_mask = 1 << 7, /* not one-shot mode*/ -+ .default_resolution = 12, -+ .default_sample_time = 220, -+ .num_sample_times = 4, -+ .sample_times = (unsigned int []){ 28, 55, 110, 220 }, -+ .resolutions = (u8 []) {9, 10, 11, 12 }, -+ }, -+ [tmp112] = { -+ .set_mask = 3 << 5, /* 8 samples / second */ -+ .clr_mask = 1 << 7, /* no one-shot mode*/ -+ .default_resolution = 12, -+ .default_sample_time = 125, -+ .num_sample_times = 4, -+ .sample_times = (unsigned int []){ 125, 250, 1000, 4000 }, -+ }, -+ [tmp175] = { -+ .set_mask = 3 << 5, /* 12-bit mode */ -+ .clr_mask = 1 << 7, /* not one-shot mode*/ -+ .default_resolution = 12, -+ .default_sample_time = 220, -+ .num_sample_times = 4, -+ .sample_times = (unsigned int []){ 28, 55, 110, 220 }, -+ .resolutions = (u8 []) {9, 10, 11, 12 }, -+ }, -+ [tmp275] = { -+ .set_mask = 3 << 5, /* 12-bit mode */ -+ .clr_mask = 1 << 7, /* not one-shot mode*/ -+ .default_resolution = 12, -+ .default_sample_time = 220, -+ .num_sample_times = 4, -+ .sample_times = (unsigned int []){ 28, 55, 110, 220 }, -+ .resolutions = (u8 []) {9, 10, 11, 12 }, -+ }, -+ [tmp75] = { -+ .set_mask = 3 << 5, /* 12-bit mode */ -+ .clr_mask = 1 << 7, /* not one-shot mode*/ -+ .default_resolution = 12, -+ .default_sample_time = 220, -+ .num_sample_times = 4, -+ .sample_times = (unsigned int []){ 28, 55, 110, 220 }, -+ .resolutions = (u8 []) {9, 10, 11, 12 }, -+ }, -+ [tmp75b] = { /* not one-shot mode, Conversion rate 37Hz */ -+ .clr_mask = 1 << 7 | 3 << 5, -+ .default_resolution = 12, -+ .default_sample_time = MSEC_PER_SEC / 37, -+ .sample_times = (unsigned int []){ MSEC_PER_SEC / 37, -+ MSEC_PER_SEC / 18, -+ MSEC_PER_SEC / 9, MSEC_PER_SEC / 4 }, -+ .num_sample_times = 4, -+ }, -+ [tmp75c] = { -+ .clr_mask = 1 << 5, /*not one-shot mode*/ -+ .default_resolution = 12, -+ .default_sample_time = MSEC_PER_SEC / 12, -+ } -+}; -+ -+/* input temp threshold check */ -+typedef struct lm75_temp_threshold_s { -+ int chip_type; -+ int temp_max; -+ int temp_min; -+} lm75_temp_threshold_t; -+ -+static lm75_temp_threshold_t g_lm75_temp_threshold_info[] = { -+ { -+ .chip_type = lm75, -+ .temp_max = 125000, -+ .temp_min = -55000, -+ }, -+ { -+ .chip_type = tmp275, -+ .temp_max = 125000, -+ .temp_min = -40000, -+ }, -+}; -+ -+/*-----------------------------------------------------------------------*/ -+static int lm75_input_temp_check(struct lm75_data *data, int input_val) -+{ -+ int i, size; -+ -+ size = ARRAY_SIZE(g_lm75_temp_threshold_info); -+ -+ for (i = 0; i < size; i++) { -+ if (g_lm75_temp_threshold_info[i].chip_type == data->kind) { -+ if ((input_val > g_lm75_temp_threshold_info[i].temp_max) -+ || (input_val < g_lm75_temp_threshold_info[i].temp_min)) { -+ dev_dbg(&data->client->dev, "input temp: %d not in range[%d, %d]\n", -+ input_val, g_lm75_temp_threshold_info[i].temp_min, -+ g_lm75_temp_threshold_info[i].temp_max); -+ return -EINVAL; -+ } -+ dev_dbg(&data->client->dev, "input temp: %d in range[%d, %d]", input_val, -+ g_lm75_temp_threshold_info[i].temp_min, g_lm75_temp_threshold_info[i].temp_max); -+ return 0; -+ } -+ } -+ return 0; -+} -+ -+static inline long lm75_reg_to_mc(s16 temp, u8 resolution) -+{ -+ return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8); -+} -+ -+static int lm75_write_config(struct lm75_data *data, u8 set_mask, -+ u8 clr_mask) -+{ -+ u8 value; -+ -+ clr_mask |= LM75_SHUTDOWN; -+ value = data->current_conf & ~clr_mask; -+ value |= set_mask; -+ -+ if (data->current_conf != value) { -+ s32 err; -+ -+ err = i2c_smbus_write_byte_data(data->client, LM75_REG_CONF, -+ value); -+ if (err) -+ return err; -+ data->current_conf = value; -+ } -+ return 0; -+} -+ -+static int lm75_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, -+ long *val) -+{ -+ struct lm75_data *data = dev_get_drvdata(dev); -+ unsigned int regval; -+ int err, reg, i, ret; -+ -+ switch (type) { -+ case hwmon_chip: -+ switch (attr) { -+ case hwmon_chip_update_interval: -+ *val = data->sample_time; -+ break; -+ default: -+ return -EINVAL; -+ } -+ break; -+ case hwmon_temp: -+ switch (attr) { -+ case hwmon_temp_input: -+ reg = LM75_REG_TEMP; -+ break; -+ case hwmon_temp_max: -+ reg = LM75_REG_MAX; -+ break; -+ case hwmon_temp_max_hyst: -+ reg = LM75_REG_HYST; -+ break; -+ default: -+ return -EINVAL; -+ } -+ for (i = 0; i < LM75_TEMP_INVALID_RETRY_TIMES; i++) { -+ err = regmap_read(data->regmap, reg, ®val); -+ if (err < 0) { -+ return err; -+ } -+ *val = lm75_reg_to_mc(regval, data->resolution); -+ if (reg != LM75_REG_TEMP) { -+ return 0; -+ } -+ /* do input_temp_check */ -+ ret = lm75_input_temp_check(data, *val); -+ if (ret == 0) { /* input temp check ok */ -+ return 0; -+ } -+ if ((i + 1) < LM75_TEMP_INVALID_RETRY_TIMES) { -+ msleep(data->sample_time); -+ } -+ } -+ dev_info(&data->client->dev, "temp_input value: %ld invalid\n", *val); -+ return -EINVAL; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static int lm75_write_temp(struct device *dev, u32 attr, long temp) -+{ -+ struct lm75_data *data = dev_get_drvdata(dev); -+ u8 resolution; -+ int reg; -+ -+ switch (attr) { -+ case hwmon_temp_max: -+ reg = LM75_REG_MAX; -+ break; -+ case hwmon_temp_max_hyst: -+ reg = LM75_REG_HYST; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ /* -+ * Resolution of limit registers is assumed to be the same as the -+ * temperature input register resolution unless given explicitly. -+ */ -+ if (data->params->resolution_limits) -+ resolution = data->params->resolution_limits; -+ else -+ resolution = data->resolution; -+ -+ temp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); -+ temp = DIV_ROUND_CLOSEST(temp << (resolution - 8), -+ 1000) << (16 - resolution); -+ -+ return regmap_write(data->regmap, reg, (u16)temp); -+} -+ -+static int lm75_update_interval(struct device *dev, long val) -+{ -+ struct lm75_data *data = dev_get_drvdata(dev); -+ unsigned int reg; -+ u8 index; -+ s32 err; -+ -+ index = find_closest(val, data->params->sample_times, -+ (int)data->params->num_sample_times); -+ -+ switch (data->kind) { -+ default: -+ err = lm75_write_config(data, lm75_sample_set_masks[index], -+ LM75_SAMPLE_CLEAR_MASK); -+ if (err) -+ return err; -+ -+ data->sample_time = data->params->sample_times[index]; -+ if (data->params->resolutions) -+ data->resolution = data->params->resolutions[index]; -+ break; -+ case tmp112: -+ err = regmap_read(data->regmap, LM75_REG_CONF, ®); -+ if (err < 0) -+ return err; -+ reg &= ~0x00c0; -+ reg |= (3 - index) << 6; -+ err = regmap_write(data->regmap, LM75_REG_CONF, reg); -+ if (err < 0) -+ return err; -+ data->sample_time = data->params->sample_times[index]; -+ break; -+ case pct2075: -+ err = i2c_smbus_write_byte_data(data->client, PCT2075_REG_IDLE, -+ index + 1); -+ if (err) -+ return err; -+ data->sample_time = data->params->sample_times[index]; -+ break; -+ } -+ return 0; -+} -+ -+static int lm75_write_chip(struct device *dev, u32 attr, long val) -+{ -+ switch (attr) { -+ case hwmon_chip_update_interval: -+ return lm75_update_interval(dev, val); -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static int lm75_write(struct device *dev, enum hwmon_sensor_types type, -+ u32 attr, int channel, long val) -+{ -+ switch (type) { -+ case hwmon_chip: -+ return lm75_write_chip(dev, attr, val); -+ case hwmon_temp: -+ return lm75_write_temp(dev, attr, val); -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type, -+ u32 attr, int channel) -+{ -+ const struct lm75_data *config_data = data; -+ -+ switch (type) { -+ case hwmon_chip: -+ switch (attr) { -+ case hwmon_chip_update_interval: -+ if (config_data->params->num_sample_times > 1) -+ return 0644; -+ return 0444; -+ } -+ break; -+ case hwmon_temp: -+ switch (attr) { -+ case hwmon_temp_input: -+ return 0444; -+ case hwmon_temp_max: -+ case hwmon_temp_max_hyst: -+ return 0644; -+ } -+ break; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+static const struct hwmon_channel_info *lm75_info[] = { -+ HWMON_CHANNEL_INFO(chip, -+ HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL), -+ HWMON_CHANNEL_INFO(temp, -+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST), -+ NULL -+}; -+ -+static const struct hwmon_ops lm75_hwmon_ops = { -+ .is_visible = lm75_is_visible, -+ .read = lm75_read, -+ .write = lm75_write, -+}; -+ -+static const struct hwmon_chip_info lm75_chip_info = { -+ .ops = &lm75_hwmon_ops, -+ .info = lm75_info, -+}; -+ -+static bool lm75_is_writeable_reg(struct device *dev, unsigned int reg) -+{ -+ return reg != LM75_REG_TEMP; -+} -+ -+static bool lm75_is_volatile_reg(struct device *dev, unsigned int reg) -+{ -+ return reg == LM75_REG_TEMP || reg == LM75_REG_CONF; -+} -+ -+static const struct regmap_config lm75_regmap_config = { -+ .reg_bits = 8, -+ .val_bits = 16, -+ .max_register = PCT2075_REG_IDLE, -+ .writeable_reg = lm75_is_writeable_reg, -+ .volatile_reg = lm75_is_volatile_reg, -+ .val_format_endian = REGMAP_ENDIAN_BIG, -+ .cache_type = REGCACHE_RBTREE, -+ .use_single_read = true, -+ .use_single_write = true, -+}; -+ -+static void lm75_disable_regulator(void *data) -+{ -+ struct lm75_data *lm75 = data; -+ -+ regulator_disable(lm75->vs); -+} -+ -+static void lm75_remove(void *data) -+{ -+ struct lm75_data *lm75 = data; -+ struct i2c_client *client = lm75->client; -+ -+ i2c_smbus_write_byte_data(client, LM75_REG_CONF, lm75->orig_conf); -+} -+ -+static const struct i2c_device_id lm75_ids[]; -+ -+static int lm75_probe(struct i2c_client *client) -+{ -+ struct device *dev = &client->dev; -+ struct device *hwmon_dev; -+ struct lm75_data *data; -+ int status, err; -+ enum lm75_type kind; -+ -+ if (client->dev.of_node) -+ kind = (enum lm75_type)of_device_get_match_data(&client->dev); -+ else -+ kind = i2c_match_id(lm75_ids, client)->driver_data; -+ -+ if (!i2c_check_functionality(client->adapter, -+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) -+ return -EIO; -+ -+ data = devm_kzalloc(dev, sizeof(struct lm75_data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ data->client = client; -+ data->kind = kind; -+ -+ data->vs = devm_regulator_get(dev, "vs"); -+ if (IS_ERR(data->vs)) -+ return PTR_ERR(data->vs); -+ -+ data->regmap = devm_regmap_init_i2c(client, &lm75_regmap_config); -+ if (IS_ERR(data->regmap)) -+ return PTR_ERR(data->regmap); -+ -+ /* Set to LM75 resolution (9 bits, 1/2 degree C) and range. -+ * Then tweak to be more precise when appropriate. -+ */ -+ -+ data->params = &device_params[data->kind]; -+ -+ /* Save default sample time and resolution*/ -+ data->sample_time = data->params->default_sample_time; -+ data->resolution = data->params->default_resolution; -+ -+ /* Enable the power */ -+ err = regulator_enable(data->vs); -+ if (err) { -+ dev_err(dev, "failed to enable regulator: %d\n", err); -+ return err; -+ } -+ -+ err = devm_add_action_or_reset(dev, lm75_disable_regulator, data); -+ if (err) -+ return err; -+ -+ /* Cache original configuration */ -+ status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); -+ if (status < 0) { -+ dev_dbg(dev, "Can't read config? %d\n", status); -+ return status; -+ } -+ data->orig_conf = status; -+ data->current_conf = status; -+ -+ err = lm75_write_config(data, data->params->set_mask, -+ data->params->clr_mask); -+ if (err) -+ return err; -+ -+ err = devm_add_action_or_reset(dev, lm75_remove, data); -+ if (err) -+ return err; -+ -+ hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, -+ data, &lm75_chip_info, -+ NULL); -+ if (IS_ERR(hwmon_dev)) -+ return PTR_ERR(hwmon_dev); -+ -+ dev_info(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), client->name); -+ -+ return 0; -+} -+ -+static const struct i2c_device_id lm75_ids[] = { -+ { "wb_adt75", adt75, }, -+ { "wb_ds1775", ds1775, }, -+ { "wb_ds75", ds75, }, -+ { "wb_ds7505", ds7505, }, -+ { "wb_g751", g751, }, -+ { "wb_lm75", lm75, }, -+ { "wb_lm75a", lm75a, }, -+ { "wb_lm75b", lm75b, }, -+ { "wb_max6625", max6625, }, -+ { "wb_max6626", max6626, }, -+ { "wb_max31725", max31725, }, -+ { "wb_max31726", max31725, }, -+ { "wb_mcp980x", mcp980x, }, -+ { "wb_pct2075", pct2075, }, -+ { "wb_stds75", stds75, }, -+ { "wb_stlm75", stlm75, }, -+ { "wb_tcn75", tcn75, }, -+ { "wb_tmp100", tmp100, }, -+ { "wb_tmp101", tmp101, }, -+ { "wb_tmp105", tmp105, }, -+ { "wb_tmp112", tmp112, }, -+ { "wb_tmp175", tmp175, }, -+ { "wb_tmp275", tmp275, }, -+ { "wb_tmp75", tmp75, }, -+ { "wb_tmp75b", tmp75b, }, -+ { "wb_tmp75c", tmp75c, }, -+ { /* LIST END */ } -+}; -+MODULE_DEVICE_TABLE(i2c, lm75_ids); -+ -+static const struct of_device_id __maybe_unused lm75_of_match[] = { -+ { -+ .compatible = "adi,adt75", -+ .data = (void *)adt75 -+ }, -+ { -+ .compatible = "dallas,ds1775", -+ .data = (void *)ds1775 -+ }, -+ { -+ .compatible = "dallas,ds75", -+ .data = (void *)ds75 -+ }, -+ { -+ .compatible = "dallas,ds7505", -+ .data = (void *)ds7505 -+ }, -+ { -+ .compatible = "gmt,g751", -+ .data = (void *)g751 -+ }, -+ { -+ .compatible = "national,lm75", -+ .data = (void *)lm75 -+ }, -+ { -+ .compatible = "national,lm75a", -+ .data = (void *)lm75a -+ }, -+ { -+ .compatible = "national,lm75b", -+ .data = (void *)lm75b -+ }, -+ { -+ .compatible = "maxim,max6625", -+ .data = (void *)max6625 -+ }, -+ { -+ .compatible = "maxim,max6626", -+ .data = (void *)max6626 -+ }, -+ { -+ .compatible = "maxim,max31725", -+ .data = (void *)max31725 -+ }, -+ { -+ .compatible = "maxim,max31726", -+ .data = (void *)max31725 -+ }, -+ { -+ .compatible = "maxim,mcp980x", -+ .data = (void *)mcp980x -+ }, -+ { -+ .compatible = "nxp,pct2075", -+ .data = (void *)pct2075 -+ }, -+ { -+ .compatible = "st,stds75", -+ .data = (void *)stds75 -+ }, -+ { -+ .compatible = "st,stlm75", -+ .data = (void *)stlm75 -+ }, -+ { -+ .compatible = "microchip,tcn75", -+ .data = (void *)tcn75 -+ }, -+ { -+ .compatible = "ti,tmp100", -+ .data = (void *)tmp100 -+ }, -+ { -+ .compatible = "ti,tmp101", -+ .data = (void *)tmp101 -+ }, -+ { -+ .compatible = "ti,tmp105", -+ .data = (void *)tmp105 -+ }, -+ { -+ .compatible = "ti,tmp112", -+ .data = (void *)tmp112 -+ }, -+ { -+ .compatible = "ti,tmp175", -+ .data = (void *)tmp175 -+ }, -+ { -+ .compatible = "ti,tmp275", -+ .data = (void *)tmp275 -+ }, -+ { -+ .compatible = "ti,tmp75", -+ .data = (void *)tmp75 -+ }, -+ { -+ .compatible = "ti,tmp75b", -+ .data = (void *)tmp75b -+ }, -+ { -+ .compatible = "ti,tmp75c", -+ .data = (void *)tmp75c -+ }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, lm75_of_match); -+ -+#define LM75A_ID 0xA1 -+#if 0 -+/* Return 0 if detection is successful, -ENODEV otherwise */ -+static int lm75_detect(struct i2c_client *new_client, -+ struct i2c_board_info *info) -+{ -+ struct i2c_adapter *adapter = new_client->adapter; -+ int i; -+ int conf, hyst, os; -+ bool is_lm75a = 0; -+ -+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | -+ I2C_FUNC_SMBUS_WORD_DATA)) -+ return -ENODEV; -+ -+ /* -+ * Now, we do the remaining detection. There is no identification- -+ * dedicated register so we have to rely on several tricks: -+ * unused bits, registers cycling over 8-address boundaries, -+ * addresses 0x04-0x07 returning the last read value. -+ * The cycling+unused addresses combination is not tested, -+ * since it would significantly slow the detection down and would -+ * hardly add any value. -+ * -+ * The National Semiconductor LM75A is different than earlier -+ * LM75s. It has an ID byte of 0xaX (where X is the chip -+ * revision, with 1 being the only revision in existence) in -+ * register 7, and unused registers return 0xff rather than the -+ * last read value. -+ * -+ * Note that this function only detects the original National -+ * Semiconductor LM75 and the LM75A. Clones from other vendors -+ * aren't detected, on purpose, because they are typically never -+ * found on PC hardware. They are found on embedded designs where -+ * they can be instantiated explicitly so detection is not needed. -+ * The absence of identification registers on all these clones -+ * would make their exhaustive detection very difficult and weak, -+ * and odds are that the driver would bind to unsupported devices. -+ */ -+ -+ /* Unused bits */ -+ conf = i2c_smbus_read_byte_data(new_client, 1); -+ if (conf & 0xe0) -+ return -ENODEV; -+ -+ /* First check for LM75A */ -+ if (i2c_smbus_read_byte_data(new_client, 7) == LM75A_ID) { -+ /* -+ * LM75A returns 0xff on unused registers so -+ * just to be sure we check for that too. -+ */ -+ if (i2c_smbus_read_byte_data(new_client, 4) != 0xff -+ || i2c_smbus_read_byte_data(new_client, 5) != 0xff -+ || i2c_smbus_read_byte_data(new_client, 6) != 0xff) -+ return -ENODEV; -+ is_lm75a = 1; -+ hyst = i2c_smbus_read_byte_data(new_client, 2); -+ os = i2c_smbus_read_byte_data(new_client, 3); -+ } else { /* Traditional style LM75 detection */ -+ /* Unused addresses */ -+ hyst = i2c_smbus_read_byte_data(new_client, 2); -+ if (i2c_smbus_read_byte_data(new_client, 4) != hyst -+ || i2c_smbus_read_byte_data(new_client, 5) != hyst -+ || i2c_smbus_read_byte_data(new_client, 6) != hyst -+ || i2c_smbus_read_byte_data(new_client, 7) != hyst) -+ return -ENODEV; -+ os = i2c_smbus_read_byte_data(new_client, 3); -+ if (i2c_smbus_read_byte_data(new_client, 4) != os -+ || i2c_smbus_read_byte_data(new_client, 5) != os -+ || i2c_smbus_read_byte_data(new_client, 6) != os -+ || i2c_smbus_read_byte_data(new_client, 7) != os) -+ return -ENODEV; -+ } -+ /* -+ * It is very unlikely that this is a LM75 if both -+ * hysteresis and temperature limit registers are 0. -+ */ -+ if (hyst == 0 && os == 0) -+ return -ENODEV; -+ -+ /* Addresses cycling */ -+ for (i = 8; i <= 248; i += 40) { -+ if (i2c_smbus_read_byte_data(new_client, i + 1) != conf -+ || i2c_smbus_read_byte_data(new_client, i + 2) != hyst -+ || i2c_smbus_read_byte_data(new_client, i + 3) != os) -+ return -ENODEV; -+ if (is_lm75a && i2c_smbus_read_byte_data(new_client, i + 7) -+ != LM75A_ID) -+ return -ENODEV; -+ } -+ -+ strlcpy(info->type, is_lm75a ? "lm75a" : "lm75", I2C_NAME_SIZE); -+ -+ return 0; -+} -+#endif -+ -+#ifdef CONFIG_PM -+static int lm75_suspend(struct device *dev) -+{ -+ int status; -+ struct i2c_client *client = to_i2c_client(dev); -+ -+ status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); -+ if (status < 0) { -+ dev_dbg(&client->dev, "Can't read config? %d\n", status); -+ return status; -+ } -+ status = status | LM75_SHUTDOWN; -+ i2c_smbus_write_byte_data(client, LM75_REG_CONF, status); -+ return 0; -+} -+ -+static int lm75_resume(struct device *dev) -+{ -+ int status; -+ struct i2c_client *client = to_i2c_client(dev); -+ -+ status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); -+ if (status < 0) { -+ dev_dbg(&client->dev, "Can't read config? %d\n", status); -+ return status; -+ } -+ status = status & ~LM75_SHUTDOWN; -+ i2c_smbus_write_byte_data(client, LM75_REG_CONF, status); -+ return 0; -+} -+ -+static const struct dev_pm_ops lm75_dev_pm_ops = { -+ .suspend = lm75_suspend, -+ .resume = lm75_resume, -+}; -+#define LM75_DEV_PM_OPS (&lm75_dev_pm_ops) -+#else -+#define LM75_DEV_PM_OPS NULL -+#endif /* CONFIG_PM */ -+ -+static struct i2c_driver lm75_driver = { -+ .class = I2C_CLASS_HWMON, -+ .driver = { -+ .name = "wb_lm75", -+ .of_match_table = of_match_ptr(lm75_of_match), -+ .pm = LM75_DEV_PM_OPS, -+ }, -+ .probe_new = lm75_probe, -+ .id_table = lm75_ids, -+ /* .detect = lm75_detect, */ -+ /* .address_list = normal_i2c, */ -+}; -+ -+module_i2c_driver(lm75_driver); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("LM75 driver"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.h -new file mode 100644 -index 000000000..a39817116 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_lm75.h -@@ -0,0 +1,40 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * lm75.h - Part of lm_sensors, Linux kernel modules for hardware monitoring -+ * Copyright (c) 2003 Mark M. Hoffman -+ */ -+ -+/* -+ * This file contains common code for encoding/decoding LM75 type -+ * temperature readings, which are emulated by many of the chips -+ * we support. As the user is unlikely to load more than one driver -+ * which contains this code, we don't worry about the wasted space. -+ */ -+ -+#include -+ -+/* straight from the datasheet */ -+#define LM75_TEMP_MIN (-55000) -+#define LM75_TEMP_MAX 125000 -+#define LM75_SHUTDOWN 0x01 -+ -+/* -+ * TEMP: 0.001C/bit (-55C to +125C) -+ * REG: (0.5C/bit, two's complement) << 7 -+ */ -+static inline u16 LM75_TEMP_TO_REG(long temp) -+{ -+ int ntemp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); -+ -+ ntemp += (ntemp < 0 ? -250 : 250); -+ return (u16)((ntemp / 500) << 7); -+} -+ -+static inline int LM75_TEMP_FROM_REG(u16 reg) -+{ -+ /* -+ * use integer division instead of equivalent right shift to -+ * guarantee arithmetic shift and preserve the sign -+ */ -+ return ((s16)reg / 128) * 500; -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus.h -new file mode 100644 -index 000000000..9fb2c9017 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus.h -@@ -0,0 +1,535 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * wb_pmbus.h - Common defines and structures for PMBus devices -+ * -+ * Copyright (c) 2010, 2011 Ericsson AB. -+ * Copyright (c) 2012 Guenter Roeck -+ */ -+ -+#ifndef WB_PMBUS_H -+#define WB_PMBUS_H -+ -+#include -+#include -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+ -+/* -+ * Registers -+ */ -+enum pmbus_regs { -+ PMBUS_PAGE = 0x00, -+ PMBUS_OPERATION = 0x01, -+ PMBUS_ON_OFF_CONFIG = 0x02, -+ PMBUS_CLEAR_FAULTS = 0x03, -+ PMBUS_PHASE = 0x04, -+ -+ PMBUS_WRITE_PROTECT = 0x10, -+ -+ PMBUS_CAPABILITY = 0x19, -+ PMBUS_QUERY = 0x1A, -+ -+ PMBUS_VOUT_MODE = 0x20, -+ PMBUS_VOUT_COMMAND = 0x21, -+ PMBUS_VOUT_TRIM = 0x22, -+ PMBUS_VOUT_CAL_OFFSET = 0x23, -+ PMBUS_VOUT_MAX = 0x24, -+ PMBUS_VOUT_MARGIN_HIGH = 0x25, -+ PMBUS_VOUT_MARGIN_LOW = 0x26, -+ PMBUS_VOUT_TRANSITION_RATE = 0x27, -+ PMBUS_VOUT_DROOP = 0x28, -+ PMBUS_VOUT_SCALE_LOOP = 0x29, -+ PMBUS_VOUT_SCALE_MONITOR = 0x2A, -+ -+ PMBUS_COEFFICIENTS = 0x30, -+ PMBUS_POUT_MAX = 0x31, -+ -+ PMBUS_FAN_CONFIG_12 = 0x3A, -+ PMBUS_FAN_COMMAND_1 = 0x3B, -+ PMBUS_FAN_COMMAND_2 = 0x3C, -+ PMBUS_FAN_CONFIG_34 = 0x3D, -+ PMBUS_FAN_COMMAND_3 = 0x3E, -+ PMBUS_FAN_COMMAND_4 = 0x3F, -+ -+ PMBUS_VOUT_OV_FAULT_LIMIT = 0x40, -+ PMBUS_VOUT_OV_FAULT_RESPONSE = 0x41, -+ PMBUS_VOUT_OV_WARN_LIMIT = 0x42, -+ PMBUS_VOUT_UV_WARN_LIMIT = 0x43, -+ PMBUS_VOUT_UV_FAULT_LIMIT = 0x44, -+ PMBUS_VOUT_UV_FAULT_RESPONSE = 0x45, -+ PMBUS_IOUT_OC_FAULT_LIMIT = 0x46, -+ PMBUS_IOUT_OC_FAULT_RESPONSE = 0x47, -+ PMBUS_IOUT_OC_LV_FAULT_LIMIT = 0x48, -+ PMBUS_IOUT_OC_LV_FAULT_RESPONSE = 0x49, -+ PMBUS_IOUT_OC_WARN_LIMIT = 0x4A, -+ PMBUS_IOUT_UC_FAULT_LIMIT = 0x4B, -+ PMBUS_IOUT_UC_FAULT_RESPONSE = 0x4C, -+ -+ PMBUS_OT_FAULT_LIMIT = 0x4F, -+ PMBUS_OT_FAULT_RESPONSE = 0x50, -+ PMBUS_OT_WARN_LIMIT = 0x51, -+ PMBUS_UT_WARN_LIMIT = 0x52, -+ PMBUS_UT_FAULT_LIMIT = 0x53, -+ PMBUS_UT_FAULT_RESPONSE = 0x54, -+ PMBUS_VIN_OV_FAULT_LIMIT = 0x55, -+ PMBUS_VIN_OV_FAULT_RESPONSE = 0x56, -+ PMBUS_VIN_OV_WARN_LIMIT = 0x57, -+ PMBUS_VIN_UV_WARN_LIMIT = 0x58, -+ PMBUS_VIN_UV_FAULT_LIMIT = 0x59, -+ -+ PMBUS_IIN_OC_FAULT_LIMIT = 0x5B, -+ PMBUS_IIN_OC_WARN_LIMIT = 0x5D, -+ -+ PMBUS_POUT_OP_FAULT_LIMIT = 0x68, -+ PMBUS_POUT_OP_WARN_LIMIT = 0x6A, -+ PMBUS_PIN_OP_WARN_LIMIT = 0x6B, -+ -+ PMBUS_STATUS_BYTE = 0x78, -+ PMBUS_STATUS_WORD = 0x79, -+ PMBUS_STATUS_VOUT = 0x7A, -+ PMBUS_STATUS_IOUT = 0x7B, -+ PMBUS_STATUS_INPUT = 0x7C, -+ PMBUS_STATUS_TEMPERATURE = 0x7D, -+ PMBUS_STATUS_CML = 0x7E, -+ PMBUS_STATUS_OTHER = 0x7F, -+ PMBUS_STATUS_MFR_SPECIFIC = 0x80, -+ PMBUS_STATUS_FAN_12 = 0x81, -+ PMBUS_STATUS_FAN_34 = 0x82, -+ -+ PMBUS_READ_VIN = 0x88, -+ PMBUS_READ_IIN = 0x89, -+ PMBUS_READ_VCAP = 0x8A, -+ PMBUS_READ_VOUT = 0x8B, -+ PMBUS_READ_IOUT = 0x8C, -+ PMBUS_READ_TEMPERATURE_1 = 0x8D, -+ PMBUS_READ_TEMPERATURE_2 = 0x8E, -+ PMBUS_READ_TEMPERATURE_3 = 0x8F, -+ PMBUS_READ_FAN_SPEED_1 = 0x90, -+ PMBUS_READ_FAN_SPEED_2 = 0x91, -+ PMBUS_READ_FAN_SPEED_3 = 0x92, -+ PMBUS_READ_FAN_SPEED_4 = 0x93, -+ PMBUS_READ_DUTY_CYCLE = 0x94, -+ PMBUS_READ_FREQUENCY = 0x95, -+ PMBUS_READ_POUT = 0x96, -+ PMBUS_READ_PIN = 0x97, -+ -+ PMBUS_REVISION = 0x98, -+ PMBUS_MFR_ID = 0x99, -+ PMBUS_MFR_MODEL = 0x9A, -+ PMBUS_MFR_REVISION = 0x9B, -+ PMBUS_MFR_LOCATION = 0x9C, -+ PMBUS_MFR_DATE = 0x9D, -+ PMBUS_MFR_SERIAL = 0x9E, -+ -+ PMBUS_MFR_VIN_MIN = 0xA0, -+ PMBUS_MFR_VIN_MAX = 0xA1, -+ PMBUS_MFR_IIN_MAX = 0xA2, -+ PMBUS_MFR_PIN_MAX = 0xA3, -+ PMBUS_MFR_VOUT_MIN = 0xA4, -+ PMBUS_MFR_VOUT_MAX = 0xA5, -+ PMBUS_MFR_IOUT_MAX = 0xA6, -+ PMBUS_MFR_POUT_MAX = 0xA7, -+ -+ PMBUS_IC_DEVICE_ID = 0xAD, -+ PMBUS_IC_DEVICE_REV = 0xAE, -+ -+ PMBUS_MFR_MAX_TEMP_1 = 0xC0, -+ PMBUS_MFR_MAX_TEMP_2 = 0xC1, -+ PMBUS_MFR_MAX_TEMP_3 = 0xC2, -+ -+/* -+ * Virtual registers. -+ * Useful to support attributes which are not supported by standard PMBus -+ * registers but exist as manufacturer specific registers on individual chips. -+ * Must be mapped to real registers in device specific code. -+ * -+ * Semantics: -+ * Virtual registers are all word size. -+ * READ registers are read-only; writes are either ignored or return an error. -+ * RESET registers are read/write. Reading reset registers returns zero -+ * (used for detection), writing any value causes the associated history to be -+ * reset. -+ * Virtual registers have to be handled in device specific driver code. Chip -+ * driver code returns non-negative register values if a virtual register is -+ * supported, or a negative error code if not. The chip driver may return -+ * -ENODATA or any other error code in this case, though an error code other -+ * than -ENODATA is handled more efficiently and thus preferred. Either case, -+ * the calling PMBus core code will abort if the chip driver returns an error -+ * code when reading or writing virtual registers. -+ */ -+ PMBUS_VIRT_BASE = 0x100, -+ PMBUS_VIRT_READ_TEMP_AVG, -+ PMBUS_VIRT_READ_TEMP_MIN, -+ PMBUS_VIRT_READ_TEMP_MAX, -+ PMBUS_VIRT_RESET_TEMP_HISTORY, -+ PMBUS_VIRT_READ_VIN_AVG, -+ PMBUS_VIRT_READ_VIN_MIN, -+ PMBUS_VIRT_READ_VIN_MAX, -+ PMBUS_VIRT_RESET_VIN_HISTORY, -+ PMBUS_VIRT_READ_IIN_AVG, -+ PMBUS_VIRT_READ_IIN_MIN, -+ PMBUS_VIRT_READ_IIN_MAX, -+ PMBUS_VIRT_RESET_IIN_HISTORY, -+ PMBUS_VIRT_READ_PIN_AVG, -+ PMBUS_VIRT_READ_PIN_MIN, -+ PMBUS_VIRT_READ_PIN_MAX, -+ PMBUS_VIRT_RESET_PIN_HISTORY, -+ PMBUS_VIRT_READ_POUT_AVG, -+ PMBUS_VIRT_READ_POUT_MIN, -+ PMBUS_VIRT_READ_POUT_MAX, -+ PMBUS_VIRT_RESET_POUT_HISTORY, -+ PMBUS_VIRT_READ_VOUT_AVG, -+ PMBUS_VIRT_READ_VOUT_MIN, -+ PMBUS_VIRT_READ_VOUT_MAX, -+ PMBUS_VIRT_RESET_VOUT_HISTORY, -+ PMBUS_VIRT_READ_IOUT_AVG, -+ PMBUS_VIRT_READ_IOUT_MIN, -+ PMBUS_VIRT_READ_IOUT_MAX, -+ PMBUS_VIRT_RESET_IOUT_HISTORY, -+ PMBUS_VIRT_READ_TEMP2_AVG, -+ PMBUS_VIRT_READ_TEMP2_MIN, -+ PMBUS_VIRT_READ_TEMP2_MAX, -+ PMBUS_VIRT_RESET_TEMP2_HISTORY, -+ -+ PMBUS_VIRT_READ_VMON, -+ PMBUS_VIRT_VMON_UV_WARN_LIMIT, -+ PMBUS_VIRT_VMON_OV_WARN_LIMIT, -+ PMBUS_VIRT_VMON_UV_FAULT_LIMIT, -+ PMBUS_VIRT_VMON_OV_FAULT_LIMIT, -+ PMBUS_VIRT_STATUS_VMON, -+ -+ /* -+ * RPM and PWM Fan control -+ * -+ * Drivers wanting to expose PWM control must define the behaviour of -+ * PMBUS_VIRT_PWM_[1-4] and PMBUS_VIRT_PWM_ENABLE_[1-4] in the -+ * {read,write}_word_data callback. -+ * -+ * pmbus core provides a default implementation for -+ * PMBUS_VIRT_FAN_TARGET_[1-4]. -+ * -+ * TARGET, PWM and PWM_ENABLE members must be defined sequentially; -+ * pmbus core uses the difference between the provided register and -+ * it's _1 counterpart to calculate the FAN/PWM ID. -+ */ -+ PMBUS_VIRT_FAN_TARGET_1, -+ PMBUS_VIRT_FAN_TARGET_2, -+ PMBUS_VIRT_FAN_TARGET_3, -+ PMBUS_VIRT_FAN_TARGET_4, -+ PMBUS_VIRT_PWM_1, -+ PMBUS_VIRT_PWM_2, -+ PMBUS_VIRT_PWM_3, -+ PMBUS_VIRT_PWM_4, -+ PMBUS_VIRT_PWM_ENABLE_1, -+ PMBUS_VIRT_PWM_ENABLE_2, -+ PMBUS_VIRT_PWM_ENABLE_3, -+ PMBUS_VIRT_PWM_ENABLE_4, -+ -+ /* Samples for average -+ * -+ * Drivers wanting to expose functionality for changing the number of -+ * samples used for average values should implement support in -+ * {read,write}_word_data callback for either PMBUS_VIRT_SAMPLES if it -+ * applies to all types of measurements, or any number of specific -+ * PMBUS_VIRT_*_SAMPLES registers to allow for individual control. -+ */ -+ PMBUS_VIRT_SAMPLES, -+ PMBUS_VIRT_IN_SAMPLES, -+ PMBUS_VIRT_CURR_SAMPLES, -+ PMBUS_VIRT_POWER_SAMPLES, -+ PMBUS_VIRT_TEMP_SAMPLES, -+}; -+ -+/* -+ * OPERATION -+ */ -+#define PB_OPERATION_CONTROL_ON BIT(7) -+ -+/* -+ * WRITE_PROTECT -+ */ -+#define PB_WP_ALL BIT(7) /* all but WRITE_PROTECT */ -+#define PB_WP_OP BIT(6) /* all but WP, OPERATION, PAGE */ -+#define PB_WP_VOUT BIT(5) /* all but WP, OPERATION, PAGE, VOUT, ON_OFF */ -+ -+#define PB_WP_ANY (PB_WP_ALL | PB_WP_OP | PB_WP_VOUT) -+ -+/* -+ * CAPABILITY -+ */ -+#define PB_CAPABILITY_SMBALERT BIT(4) -+#define PB_CAPABILITY_ERROR_CHECK BIT(7) -+ -+/* -+ * VOUT_MODE -+ */ -+#define PB_VOUT_MODE_MODE_MASK 0xe0 -+#define PB_VOUT_MODE_PARAM_MASK 0x1f -+ -+#define PB_VOUT_MODE_LINEAR 0x00 -+#define PB_VOUT_MODE_VID 0x20 -+#define PB_VOUT_MODE_DIRECT 0x40 -+ -+/* -+ * Fan configuration -+ */ -+#define PB_FAN_2_PULSE_MASK (BIT(0) | BIT(1)) -+#define PB_FAN_2_RPM BIT(2) -+#define PB_FAN_2_INSTALLED BIT(3) -+#define PB_FAN_1_PULSE_MASK (BIT(4) | BIT(5)) -+#define PB_FAN_1_RPM BIT(6) -+#define PB_FAN_1_INSTALLED BIT(7) -+ -+enum pmbus_fan_mode { percent = 0, rpm }; -+ -+/* -+ * STATUS_BYTE, STATUS_WORD (lower) -+ */ -+#define PB_STATUS_NONE_ABOVE BIT(0) -+#define PB_STATUS_CML BIT(1) -+#define PB_STATUS_TEMPERATURE BIT(2) -+#define PB_STATUS_VIN_UV BIT(3) -+#define PB_STATUS_IOUT_OC BIT(4) -+#define PB_STATUS_VOUT_OV BIT(5) -+#define PB_STATUS_OFF BIT(6) -+#define PB_STATUS_BUSY BIT(7) -+ -+/* -+ * STATUS_WORD (upper) -+ */ -+#define PB_STATUS_UNKNOWN BIT(8) -+#define PB_STATUS_OTHER BIT(9) -+#define PB_STATUS_FANS BIT(10) -+#define PB_STATUS_POWER_GOOD_N BIT(11) -+#define PB_STATUS_WORD_MFR BIT(12) -+#define PB_STATUS_INPUT BIT(13) -+#define PB_STATUS_IOUT_POUT BIT(14) -+#define PB_STATUS_VOUT BIT(15) -+ -+/* -+ * STATUS_IOUT -+ */ -+#define PB_POUT_OP_WARNING BIT(0) -+#define PB_POUT_OP_FAULT BIT(1) -+#define PB_POWER_LIMITING BIT(2) -+#define PB_CURRENT_SHARE_FAULT BIT(3) -+#define PB_IOUT_UC_FAULT BIT(4) -+#define PB_IOUT_OC_WARNING BIT(5) -+#define PB_IOUT_OC_LV_FAULT BIT(6) -+#define PB_IOUT_OC_FAULT BIT(7) -+ -+/* -+ * STATUS_VOUT, STATUS_INPUT -+ */ -+#define PB_VOLTAGE_UV_FAULT BIT(4) -+#define PB_VOLTAGE_UV_WARNING BIT(5) -+#define PB_VOLTAGE_OV_WARNING BIT(6) -+#define PB_VOLTAGE_OV_FAULT BIT(7) -+ -+/* -+ * STATUS_INPUT -+ */ -+#define PB_PIN_OP_WARNING BIT(0) -+#define PB_IIN_OC_WARNING BIT(1) -+#define PB_IIN_OC_FAULT BIT(2) -+ -+/* -+ * STATUS_TEMPERATURE -+ */ -+#define PB_TEMP_UT_FAULT BIT(4) -+#define PB_TEMP_UT_WARNING BIT(5) -+#define PB_TEMP_OT_WARNING BIT(6) -+#define PB_TEMP_OT_FAULT BIT(7) -+ -+/* -+ * STATUS_FAN -+ */ -+#define PB_FAN_AIRFLOW_WARNING BIT(0) -+#define PB_FAN_AIRFLOW_FAULT BIT(1) -+#define PB_FAN_FAN2_SPEED_OVERRIDE BIT(2) -+#define PB_FAN_FAN1_SPEED_OVERRIDE BIT(3) -+#define PB_FAN_FAN2_WARNING BIT(4) -+#define PB_FAN_FAN1_WARNING BIT(5) -+#define PB_FAN_FAN2_FAULT BIT(6) -+#define PB_FAN_FAN1_FAULT BIT(7) -+ -+/* -+ * CML_FAULT_STATUS -+ */ -+#define PB_CML_FAULT_OTHER_MEM_LOGIC BIT(0) -+#define PB_CML_FAULT_OTHER_COMM BIT(1) -+#define PB_CML_FAULT_PROCESSOR BIT(3) -+#define PB_CML_FAULT_MEMORY BIT(4) -+#define PB_CML_FAULT_PACKET_ERROR BIT(5) -+#define PB_CML_FAULT_INVALID_DATA BIT(6) -+#define PB_CML_FAULT_INVALID_COMMAND BIT(7) -+ -+enum pmbus_sensor_classes { -+ PSC_VOLTAGE_IN = 0, -+ PSC_VOLTAGE_OUT, -+ PSC_CURRENT_IN, -+ PSC_CURRENT_OUT, -+ PSC_POWER, -+ PSC_TEMPERATURE, -+ PSC_FAN, -+ PSC_PWM, -+ PSC_NUM_CLASSES /* Number of power sensor classes */ -+}; -+ -+#define PMBUS_PAGES 32 /* Per PMBus specification */ -+#define PMBUS_PHASES 8 /* Maximum number of phases per page */ -+ -+/* Functionality bit mask */ -+#define PMBUS_HAVE_VIN BIT(0) -+#define PMBUS_HAVE_VCAP BIT(1) -+#define PMBUS_HAVE_VOUT BIT(2) -+#define PMBUS_HAVE_IIN BIT(3) -+#define PMBUS_HAVE_IOUT BIT(4) -+#define PMBUS_HAVE_PIN BIT(5) -+#define PMBUS_HAVE_POUT BIT(6) -+#define PMBUS_HAVE_FAN12 BIT(7) -+#define PMBUS_HAVE_FAN34 BIT(8) -+#define PMBUS_HAVE_TEMP BIT(9) -+#define PMBUS_HAVE_TEMP2 BIT(10) -+#define PMBUS_HAVE_TEMP3 BIT(11) -+#define PMBUS_HAVE_STATUS_VOUT BIT(12) -+#define PMBUS_HAVE_STATUS_IOUT BIT(13) -+#define PMBUS_HAVE_STATUS_INPUT BIT(14) -+#define PMBUS_HAVE_STATUS_TEMP BIT(15) -+#define PMBUS_HAVE_STATUS_FAN12 BIT(16) -+#define PMBUS_HAVE_STATUS_FAN34 BIT(17) -+#define PMBUS_HAVE_VMON BIT(18) -+#define PMBUS_HAVE_STATUS_VMON BIT(19) -+#define PMBUS_HAVE_PWM12 BIT(20) -+#define PMBUS_HAVE_PWM34 BIT(21) -+#define PMBUS_HAVE_SAMPLES BIT(22) -+ -+#define PMBUS_PHASE_VIRTUAL BIT(30) /* Phases on this page are virtual */ -+#define PMBUS_PAGE_VIRTUAL BIT(31) /* Page is virtual */ -+ -+enum pmbus_data_format { linear = 0, direct, vid }; -+enum vrm_version { vr11 = 0, vr12, vr13, imvp9, amd625mv }; -+ -+struct pmbus_driver_info { -+ int pages; /* Total number of pages */ -+ u8 phases[PMBUS_PAGES]; /* Number of phases per page */ -+ enum pmbus_data_format format[PSC_NUM_CLASSES]; -+ enum vrm_version vrm_version[PMBUS_PAGES]; /* vrm version per page */ -+ /* -+ * Support one set of coefficients for each sensor type -+ * Used for chips providing data in direct mode. -+ */ -+ int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */ -+ int b[PSC_NUM_CLASSES]; /* offset */ -+ int R[PSC_NUM_CLASSES]; /* exponent */ -+ -+ u32 func[PMBUS_PAGES]; /* Functionality, per page */ -+ u32 pfunc[PMBUS_PHASES];/* Functionality, per phase */ -+ /* -+ * The following functions map manufacturing specific register values -+ * to PMBus standard register values. Specify only if mapping is -+ * necessary. -+ * Functions return the register value (read) or zero (write) if -+ * successful. A return value of -ENODATA indicates that there is no -+ * manufacturer specific register, but that a standard PMBus register -+ * may exist. Any other negative return value indicates that the -+ * register does not exist, and that no attempt should be made to read -+ * the standard register. -+ */ -+ int (*read_byte_data)(struct i2c_client *client, int page, int reg); -+ int (*read_word_data)(struct i2c_client *client, int page, int phase, -+ int reg); -+ int (*write_word_data)(struct i2c_client *client, int page, int reg, -+ u16 word); -+ int (*write_byte)(struct i2c_client *client, int page, u8 value); -+ /* -+ * The identify function determines supported PMBus functionality. -+ * This function is only necessary if a chip driver supports multiple -+ * chips, and the chip functionality is not pre-determined. -+ */ -+ int (*identify)(struct i2c_client *client, -+ struct pmbus_driver_info *info); -+ -+ /* Regulator functionality, if supported by this chip driver. */ -+ int num_regulators; -+ const struct regulator_desc *reg_desc; -+ -+ /* custom attributes */ -+ const struct attribute_group **groups; -+}; -+ -+/* Regulator ops */ -+ -+extern const struct regulator_ops wb_pmbus_regulator_ops; -+ -+/* Macro for filling in array of struct regulator_desc */ -+#define PMBUS_REGULATOR(_name, _id) \ -+ [_id] = { \ -+ .name = (_name # _id), \ -+ .id = (_id), \ -+ .of_match = of_match_ptr(_name # _id), \ -+ .regulators_node = of_match_ptr("regulators"), \ -+ .ops = &wb_pmbus_regulator_ops, \ -+ .type = REGULATOR_VOLTAGE, \ -+ .owner = THIS_MODULE, \ -+ } -+ -+struct pmbus_data { -+ struct device *dev; -+ struct device *hwmon_dev; -+ -+ u32 flags; /* from platform data */ -+ -+ int exponent[PMBUS_PAGES]; /* linear mode: exponent for output voltages */ -+ -+ const struct pmbus_driver_info *info; -+ -+ int max_attributes; -+ int num_attributes; -+ struct attribute_group group; -+ const struct attribute_group **groups; -+ struct dentry *debugfs; /* debugfs device directory */ -+ -+ struct pmbus_sensor *sensors; -+ -+ struct mutex update_lock; -+ -+ bool has_status_word; /* device uses STATUS_WORD register */ -+ int (*read_status)(struct i2c_client *client, int page); -+ -+ s16 currpage; /* current page, -1 for unknown/unset */ -+ s16 currphase; /* current phase, 0xff for all, -1 for unknown/unset */ -+ int vout_max[PMBUS_PAGES]; /* pmbus maximum output voltage */ -+ int vout_min[PMBUS_PAGES]; /* pmbus minimum output voltage */ -+}; -+ -+/* Function declarations */ -+void wb_pmbus_clear_cache(struct i2c_client *client); -+int wb_pmbus_set_page(struct i2c_client *client, int page, int phase); -+int wb_pmbus_read_word_data(struct i2c_client *client, int page, int phase, -+ u8 reg); -+int wb_pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, -+ u16 word); -+int wb_pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg); -+int wb_pmbus_write_byte(struct i2c_client *client, int page, u8 value); -+int wb_pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, -+ u8 value); -+int wb_pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, -+ u8 mask, u8 value); -+void wb_pmbus_clear_faults(struct i2c_client *client); -+bool wb_pmbus_check_byte_register(struct i2c_client *client, int page, int reg); -+bool wb_pmbus_check_word_register(struct i2c_client *client, int page, int reg); -+int wb_pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info); -+int wb_pmbus_do_remove(struct i2c_client *client); -+const struct pmbus_driver_info *wb_pmbus_get_driver_info(struct i2c_client -+ *client); -+int wb_pmbus_get_fan_rate_device(struct i2c_client *client, int page, int id, -+ enum pmbus_fan_mode mode); -+int wb_pmbus_get_fan_rate_cached(struct i2c_client *client, int page, int id, -+ enum pmbus_fan_mode mode); -+int wb_pmbus_update_fan(struct i2c_client *client, int page, int id, -+ u8 config, u8 mask, u16 command); -+struct dentry *wb_pmbus_get_debugfs_dir(struct i2c_client *client); -+ -+#endif /* WB_PMBUS_H */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus_core.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus_core.c -new file mode 100644 -index 000000000..343aea446 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_pmbus_core.c -@@ -0,0 +1,2780 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Hardware monitoring driver for PMBus devices -+ * -+ * Copyright (c) 2010, 2011 Ericsson AB. -+ * Copyright (c) 2012 Guenter Roeck -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "wb_pmbus.h" -+ -+/* -+ * Number of additional attribute pointers to allocate -+ * with each call to krealloc -+ */ -+#define PMBUS_ATTR_ALLOC_SIZE (32) -+#define PMBUS_NAME_SIZE (24) -+#define PMBUS_RETRY_SLEEP_TIME (10000) /* 10ms */ -+#define PMBUS_RETRY_TIME (3) -+ -+struct pmbus_sensor { -+ struct pmbus_sensor *next; -+ char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */ -+ struct device_attribute attribute; -+ u8 page; /* page number */ -+ u8 phase; /* phase number, 0xff for all phases */ -+ u16 reg; /* register */ -+ enum pmbus_sensor_classes class; /* sensor class */ -+ bool update; /* runtime sensor update needed */ -+ bool convert; /* Whether or not to apply linear/vid/direct */ -+ int data; /* Sensor data. -+ Negative if there was a read error */ -+}; -+#define to_pmbus_sensor(_attr) \ -+ container_of(_attr, struct pmbus_sensor, attribute) -+ -+struct pmbus_boolean { -+ char name[PMBUS_NAME_SIZE]; /* sysfs boolean name */ -+ struct sensor_device_attribute attribute; -+ struct pmbus_sensor *s1; -+ struct pmbus_sensor *s2; -+}; -+#define to_pmbus_boolean(_attr) \ -+ container_of(_attr, struct pmbus_boolean, attribute) -+ -+struct pmbus_label { -+ char name[PMBUS_NAME_SIZE]; /* sysfs label name */ -+ struct device_attribute attribute; -+ char label[PMBUS_NAME_SIZE]; /* label */ -+}; -+#define to_pmbus_label(_attr) \ -+ container_of(_attr, struct pmbus_label, attribute) -+ -+/* Macros for converting between sensor index and register/page/status mask */ -+ -+#define PB_STATUS_MASK 0xffff -+#define PB_REG_SHIFT 16 -+#define PB_REG_MASK 0x3ff -+#define PB_PAGE_SHIFT 26 -+#define PB_PAGE_MASK 0x3f -+ -+#define pb_reg_to_index(page, reg, mask) (((page) << PB_PAGE_SHIFT) | \ -+ ((reg) << PB_REG_SHIFT) | (mask)) -+ -+#define pb_index_to_page(index) (((index) >> PB_PAGE_SHIFT) & PB_PAGE_MASK) -+#define pb_index_to_reg(index) (((index) >> PB_REG_SHIFT) & PB_REG_MASK) -+#define pb_index_to_mask(index) ((index) & PB_STATUS_MASK) -+ -+struct pmbus_debugfs_entry { -+ struct i2c_client *client; -+ u8 page; -+ u8 reg; -+}; -+ -+static const int pmbus_fan_rpm_mask[] = { -+ PB_FAN_1_RPM, -+ PB_FAN_2_RPM, -+ PB_FAN_1_RPM, -+ PB_FAN_2_RPM, -+}; -+ -+static const int pmbus_fan_config_registers[] = { -+ PMBUS_FAN_CONFIG_12, -+ PMBUS_FAN_CONFIG_12, -+ PMBUS_FAN_CONFIG_34, -+ PMBUS_FAN_CONFIG_34 -+}; -+ -+static const int pmbus_fan_command_registers[] = { -+ PMBUS_FAN_COMMAND_1, -+ PMBUS_FAN_COMMAND_2, -+ PMBUS_FAN_COMMAND_3, -+ PMBUS_FAN_COMMAND_4, -+}; -+ -+void wb_pmbus_clear_cache(struct i2c_client *client) -+{ -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ struct pmbus_sensor *sensor; -+ -+ for (sensor = data->sensors; sensor; sensor = sensor->next) -+ sensor->data = -ENODATA; -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_clear_cache); -+ -+static int wb_pmbus_set_page_tmp(struct i2c_client *client, int page, int phase) -+{ -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ int rv; -+ -+ if (page < 0) -+ return 0; -+ -+ if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL) && -+ data->info->pages > 1 && page != data->currpage) { -+ rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); -+ if (rv < 0) -+ return rv; -+ -+ rv = i2c_smbus_read_byte_data(client, PMBUS_PAGE); -+ if (rv < 0) -+ return rv; -+ -+ if (rv != page) -+ return -EIO; -+ } -+ data->currpage = page; -+ -+ if (data->info->phases[page] && data->currphase != phase && -+ !(data->info->func[page] & PMBUS_PHASE_VIRTUAL)) { -+ rv = i2c_smbus_write_byte_data(client, PMBUS_PHASE, -+ phase); -+ if (rv) -+ return rv; -+ } -+ data->currphase = phase; -+ -+ return 0; -+} -+ -+int wb_pmbus_set_page(struct i2c_client *client, int page, int phase) -+{ -+ int rv, i; -+ struct device *dev = &client->dev; -+ -+ for (i = 0; i < PMBUS_RETRY_TIME; i++) { -+ rv = wb_pmbus_set_page_tmp(client, page, phase); -+ if(rv >= 0){ -+ return rv; -+ } -+ if ((i + 1) < PMBUS_RETRY_TIME) { -+ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); -+ } -+ } -+ dev_dbg(dev, "wb_pmbus_set_page failed, page=%d, phase=%d, rv=%d\n", -+ page, phase, rv); -+ return rv; -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_set_page); -+ -+static int wb_pmbus_write_byte_tmp(struct i2c_client *client, int page, u8 value) -+{ -+ int rv; -+ -+ rv = wb_pmbus_set_page(client, page, 0xff); -+ if (rv < 0) -+ return rv; -+ -+ return i2c_smbus_write_byte(client, value); -+} -+ -+int wb_pmbus_write_byte(struct i2c_client *client, int page, u8 value) -+{ -+ int rv, i; -+ struct device *dev = &client->dev; -+ -+ for (i = 0; i < PMBUS_RETRY_TIME; i++) { -+ rv = wb_pmbus_write_byte_tmp(client, page, value); -+ if(rv >= 0){ -+ return rv; -+ } -+ if ((i + 1) < PMBUS_RETRY_TIME) { -+ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); -+ } -+ } -+ dev_dbg(dev, "wb_pmbus_write_byte failed, page=%d, value=0x%x, rv: %d\n", -+ page, value, rv); -+ return rv; -+} -+ -+EXPORT_SYMBOL_GPL(wb_pmbus_write_byte); -+ -+/* -+ * _pmbus_write_byte() is similar to pmbus_write_byte(), but checks if -+ * a device specific mapping function exists and calls it if necessary. -+ */ -+static int _pmbus_write_byte(struct i2c_client *client, int page, u8 value) -+{ -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ const struct pmbus_driver_info *info = data->info; -+ int status; -+ -+ if (info->write_byte) { -+ status = info->write_byte(client, page, value); -+ if (status != -ENODATA) -+ return status; -+ } -+ return wb_pmbus_write_byte(client, page, value); -+} -+ -+static int wb_pmbus_write_word_data_tmp(struct i2c_client *client, int page, u8 reg, -+ u16 word) -+{ -+ int rv; -+ -+ rv = wb_pmbus_set_page(client, page, 0xff); -+ if (rv < 0) -+ return rv; -+ -+ return i2c_smbus_write_word_data(client, reg, word); -+} -+ -+int wb_pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, -+ u16 word) -+{ -+ int rv, i; -+ struct device *dev = &client->dev; -+ -+ for (i = 0; i < PMBUS_RETRY_TIME; i++) { -+ rv = wb_pmbus_write_word_data_tmp(client, page, reg, word); -+ if(rv >= 0){ -+ return rv; -+ } -+ if ((i + 1) < PMBUS_RETRY_TIME) { -+ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); -+ } -+ } -+ dev_dbg(dev, "wb_pmbus_write_word_data failed, page: %d, reg: 0x%x, value: 0x%x, rv: %d\n", -+ page, reg, word, rv); -+ return rv; -+ -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_write_word_data); -+ -+static int pmbus_write_virt_reg(struct i2c_client *client, int page, int reg, -+ u16 word) -+{ -+ int bit; -+ int id; -+ int rv; -+ -+ switch (reg) { -+ case PMBUS_VIRT_FAN_TARGET_1 ... PMBUS_VIRT_FAN_TARGET_4: -+ id = reg - PMBUS_VIRT_FAN_TARGET_1; -+ bit = pmbus_fan_rpm_mask[id]; -+ rv = wb_pmbus_update_fan(client, page, id, bit, bit, word); -+ break; -+ default: -+ rv = -ENXIO; -+ break; -+ } -+ -+ return rv; -+} -+ -+/* -+ * _pmbus_write_word_data() is similar to pmbus_write_word_data(), but checks if -+ * a device specific mapping function exists and calls it if necessary. -+ */ -+static int _pmbus_write_word_data(struct i2c_client *client, int page, int reg, -+ u16 word) -+{ -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ const struct pmbus_driver_info *info = data->info; -+ int status; -+ -+ if (info->write_word_data) { -+ status = info->write_word_data(client, page, reg, word); -+ if (status != -ENODATA) -+ return status; -+ } -+ -+ if (reg >= PMBUS_VIRT_BASE) -+ return pmbus_write_virt_reg(client, page, reg, word); -+ -+ return wb_pmbus_write_word_data(client, page, reg, word); -+} -+ -+int wb_pmbus_update_fan(struct i2c_client *client, int page, int id, -+ u8 config, u8 mask, u16 command) -+{ -+ int from; -+ int rv; -+ u8 to; -+ -+ from = wb_pmbus_read_byte_data(client, page, -+ pmbus_fan_config_registers[id]); -+ if (from < 0) -+ return from; -+ -+ to = (from & ~mask) | (config & mask); -+ if (to != from) { -+ rv = wb_pmbus_write_byte_data(client, page, -+ pmbus_fan_config_registers[id], to); -+ if (rv < 0) -+ return rv; -+ } -+ -+ return _pmbus_write_word_data(client, page, -+ pmbus_fan_command_registers[id], command); -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_update_fan); -+ -+static int wb_pmbus_read_word_data_tmp(struct i2c_client *client, int page, int phase, u8 reg) -+{ -+ int rv; -+ -+ rv = wb_pmbus_set_page(client, page, phase); -+ if (rv < 0) -+ return rv; -+ -+ return i2c_smbus_read_word_data(client, reg); -+} -+ -+int wb_pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg) -+{ -+ int rv, i; -+ struct device *dev = &client->dev; -+ -+ for (i = 0; i < PMBUS_RETRY_TIME; i++) { -+ rv = wb_pmbus_read_word_data_tmp(client, page, phase, reg); -+ if(rv >= 0){ -+ return rv; -+ } -+ if ((i + 1) < PMBUS_RETRY_TIME) { -+ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); -+ } -+ } -+ dev_dbg(dev, "wb_pmbus_read_word_data failed, page: %d, phase: %d, reg: 0x%x, rv: %d\n", -+ page, phase, reg, rv); -+ return rv; -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_read_word_data); -+ -+static int pmbus_read_virt_reg(struct i2c_client *client, int page, int reg) -+{ -+ int rv; -+ int id; -+ -+ switch (reg) { -+ case PMBUS_VIRT_FAN_TARGET_1 ... PMBUS_VIRT_FAN_TARGET_4: -+ id = reg - PMBUS_VIRT_FAN_TARGET_1; -+ rv = wb_pmbus_get_fan_rate_device(client, page, id, rpm); -+ break; -+ default: -+ rv = -ENXIO; -+ break; -+ } -+ -+ return rv; -+} -+ -+/* -+ * _pmbus_read_word_data() is similar to wb_pmbus_read_word_data(), but checks if -+ * a device specific mapping function exists and calls it if necessary. -+ */ -+static int _pmbus_read_word_data(struct i2c_client *client, int page, -+ int phase, int reg) -+{ -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ const struct pmbus_driver_info *info = data->info; -+ int status; -+ -+ if (info->read_word_data) { -+ status = info->read_word_data(client, page, phase, reg); -+ if (status != -ENODATA) -+ return status; -+ } -+ -+ if (reg >= PMBUS_VIRT_BASE) -+ return pmbus_read_virt_reg(client, page, reg); -+ -+ return wb_pmbus_read_word_data(client, page, phase, reg); -+} -+ -+/* Same as above, but without phase parameter, for use in check functions */ -+static int __pmbus_read_word_data(struct i2c_client *client, int page, int reg) -+{ -+ return _pmbus_read_word_data(client, page, 0xff, reg); -+} -+ -+static int wb_pmbus_read_byte_data_tmp(struct i2c_client *client, int page, u8 reg) -+{ -+ int rv; -+ -+ rv = wb_pmbus_set_page(client, page, 0xff); -+ if (rv < 0) -+ return rv; -+ -+ return i2c_smbus_read_byte_data(client, reg); -+} -+ -+int wb_pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg) -+{ -+ int rv, i; -+ struct device *dev = &client->dev; -+ -+ for (i = 0; i < PMBUS_RETRY_TIME; i++) { -+ rv = wb_pmbus_read_byte_data_tmp(client, page, reg); -+ if(rv >= 0){ -+ return rv; -+ } -+ if ((i + 1) < PMBUS_RETRY_TIME) { -+ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); -+ } -+ } -+ dev_dbg(dev, "wb_pmbus_read_byte_data failed, page: %d, reg: 0x%x, rv: %d\n", -+ page, reg, rv); -+ return rv; -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_read_byte_data); -+ -+static int wb_pmbus_write_byte_data_tmp(struct i2c_client *client, int page, u8 reg, u8 value) -+{ -+ int rv; -+ -+ rv = wb_pmbus_set_page(client, page, 0xff); -+ if (rv < 0) -+ return rv; -+ -+ return i2c_smbus_write_byte_data(client, reg, value); -+} -+ -+int wb_pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value) -+{ -+ int rv, i; -+ struct device *dev = &client->dev; -+ -+ for (i = 0; i < PMBUS_RETRY_TIME; i++) { -+ rv = wb_pmbus_write_byte_data_tmp(client, page, reg, value); -+ if(rv >= 0){ -+ return rv; -+ } -+ if ((i + 1) < PMBUS_RETRY_TIME) { -+ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); -+ } -+ } -+ dev_dbg(dev, "wb_pmbus_write_byte_data failed, page: %d, reg: 0x%x, value: 0x%x, rv: %d\n", -+ page, reg, value, rv); -+ return rv; -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_write_byte_data); -+ -+int wb_pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, -+ u8 mask, u8 value) -+{ -+ unsigned int tmp; -+ int rv; -+ -+ rv = wb_pmbus_read_byte_data(client, page, reg); -+ if (rv < 0) -+ return rv; -+ -+ tmp = (rv & ~mask) | (value & mask); -+ -+ if (tmp != rv) -+ rv = wb_pmbus_write_byte_data(client, page, reg, tmp); -+ -+ return rv; -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_update_byte_data); -+ -+/* -+ * _pmbus_read_byte_data() is similar to wb_pmbus_read_byte_data(), but checks if -+ * a device specific mapping function exists and calls it if necessary. -+ */ -+static int _pmbus_read_byte_data(struct i2c_client *client, int page, int reg) -+{ -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ const struct pmbus_driver_info *info = data->info; -+ int status; -+ -+ if (info->read_byte_data) { -+ status = info->read_byte_data(client, page, reg); -+ if (status != -ENODATA) -+ return status; -+ } -+ return wb_pmbus_read_byte_data(client, page, reg); -+} -+ -+static struct pmbus_sensor *pmbus_find_sensor(struct pmbus_data *data, int page, -+ int reg) -+{ -+ struct pmbus_sensor *sensor; -+ -+ for (sensor = data->sensors; sensor; sensor = sensor->next) { -+ if (sensor->page == page && sensor->reg == reg) -+ return sensor; -+ } -+ -+ return ERR_PTR(-EINVAL); -+} -+ -+static int pmbus_get_fan_rate(struct i2c_client *client, int page, int id, -+ enum pmbus_fan_mode mode, -+ bool from_cache) -+{ -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ bool want_rpm, have_rpm; -+ struct pmbus_sensor *s; -+ int config; -+ int reg; -+ -+ want_rpm = (mode == rpm); -+ -+ if (from_cache) { -+ reg = want_rpm ? PMBUS_VIRT_FAN_TARGET_1 : PMBUS_VIRT_PWM_1; -+ s = pmbus_find_sensor(data, page, reg + id); -+ if (IS_ERR(s)) -+ return PTR_ERR(s); -+ -+ return s->data; -+ } -+ -+ config = wb_pmbus_read_byte_data(client, page, -+ pmbus_fan_config_registers[id]); -+ if (config < 0) -+ return config; -+ -+ have_rpm = !!(config & pmbus_fan_rpm_mask[id]); -+ if (want_rpm == have_rpm) -+ return wb_pmbus_read_word_data(client, page, 0xff, -+ pmbus_fan_command_registers[id]); -+ -+ /* Can't sensibly map between RPM and PWM, just return zero */ -+ return 0; -+} -+ -+int wb_pmbus_get_fan_rate_device(struct i2c_client *client, int page, int id, -+ enum pmbus_fan_mode mode) -+{ -+ return pmbus_get_fan_rate(client, page, id, mode, false); -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_get_fan_rate_device); -+ -+int wb_pmbus_get_fan_rate_cached(struct i2c_client *client, int page, int id, -+ enum pmbus_fan_mode mode) -+{ -+ return pmbus_get_fan_rate(client, page, id, mode, true); -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_get_fan_rate_cached); -+ -+static void pmbus_clear_fault_page(struct i2c_client *client, int page) -+{ -+ _pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); -+} -+ -+void wb_pmbus_clear_faults(struct i2c_client *client) -+{ -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ int i; -+ -+ for (i = 0; i < data->info->pages; i++) -+ pmbus_clear_fault_page(client, i); -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_clear_faults); -+ -+static int pmbus_check_status_cml(struct i2c_client *client) -+{ -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ int status, status2; -+ -+ status = data->read_status(client, -1); -+ if (status < 0 || (status & PB_STATUS_CML)) { -+ status2 = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML); -+ if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND)) -+ return -EIO; -+ } -+ return 0; -+} -+ -+static bool pmbus_check_register(struct i2c_client *client, -+ int (*func)(struct i2c_client *client, -+ int page, int reg), -+ int page, int reg) -+{ -+ int rv; -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ -+ rv = func(client, page, reg); -+ if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK)) -+ rv = pmbus_check_status_cml(client); -+ pmbus_clear_fault_page(client, -1); -+ return rv >= 0; -+} -+ -+static bool pmbus_check_status_register(struct i2c_client *client, int page) -+{ -+ int status; -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ -+ status = data->read_status(client, page); -+ if (status >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK) && -+ (status & PB_STATUS_CML)) { -+ status = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML); -+ if (status < 0 || (status & PB_CML_FAULT_INVALID_COMMAND)) -+ status = -EIO; -+ } -+ -+ pmbus_clear_fault_page(client, -1); -+ return status >= 0; -+} -+ -+bool wb_pmbus_check_byte_register(struct i2c_client *client, int page, int reg) -+{ -+ return pmbus_check_register(client, _pmbus_read_byte_data, page, reg); -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_check_byte_register); -+ -+bool wb_pmbus_check_word_register(struct i2c_client *client, int page, int reg) -+{ -+ return pmbus_check_register(client, __pmbus_read_word_data, page, reg); -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_check_word_register); -+ -+const struct pmbus_driver_info *wb_pmbus_get_driver_info(struct i2c_client *client) -+{ -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ -+ return data->info; -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_get_driver_info); -+ -+static int pmbus_read_status_byte(struct i2c_client *client, int page) -+{ -+ return _pmbus_read_byte_data(client, page, PMBUS_STATUS_BYTE); -+} -+ -+static int pmbus_read_status_word(struct i2c_client *client, int page) -+{ -+ return _pmbus_read_word_data(client, page, 0xff, PMBUS_STATUS_WORD); -+} -+ -+static int pmbus_get_status(struct i2c_client *client, int page, int reg) -+{ -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ int status; -+ -+ switch (reg) { -+ case PMBUS_STATUS_WORD: -+ status = data->read_status(client, page); -+ if ((status < 0) || (data->has_status_word && (status == 0xffff)) -+ || (!data->has_status_word && (status == 0xff))) { -+ if (data->has_status_word) { -+ data->read_status = pmbus_read_status_byte; -+ } else { -+ data->read_status = pmbus_read_status_word; -+ } -+ data->has_status_word = !data->has_status_word; -+ status = data->read_status(client, page); -+ } -+ break; -+ default: -+ status = _pmbus_read_byte_data(client, page, reg); -+ break; -+ } -+ if (status < 0) -+ wb_pmbus_clear_faults(client); -+ return status; -+} -+ -+static void pmbus_update_sensor_data(struct i2c_client *client, struct pmbus_sensor *sensor) -+{ -+ if (sensor->data < 0 || sensor->update) -+ sensor->data = _pmbus_read_word_data(client, sensor->page, -+ sensor->phase, sensor->reg); -+} -+ -+/* -+ * Convert linear sensor values to milli- or micro-units -+ * depending on sensor type. -+ */ -+static s64 pmbus_reg2data_linear(struct pmbus_data *data, -+ struct pmbus_sensor *sensor) -+{ -+ s16 exponent; -+ s32 mantissa; -+ s64 val; -+ -+ if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */ -+ exponent = data->exponent[sensor->page]; -+ mantissa = (u16) sensor->data; -+ } else { /* LINEAR11 */ -+ exponent = ((s16)sensor->data) >> 11; -+ mantissa = ((s16)((sensor->data & 0x7ff) << 5)) >> 5; -+ } -+ -+ val = mantissa; -+ -+ /* scale result to milli-units for all sensors except fans */ -+ if (sensor->class != PSC_FAN) -+ val = val * 1000LL; -+ -+ /* scale result to micro-units for power sensors */ -+ if (sensor->class == PSC_POWER) -+ val = val * 1000LL; -+ -+ if (exponent >= 0) -+ val <<= exponent; -+ else -+ val >>= -exponent; -+ -+ return val; -+} -+ -+/* -+ * Convert direct sensor values to milli- or micro-units -+ * depending on sensor type. -+ */ -+static s64 pmbus_reg2data_direct(struct pmbus_data *data, -+ struct pmbus_sensor *sensor) -+{ -+ s64 b, val = (s16)sensor->data; -+ s32 m, R; -+ -+ m = data->info->m[sensor->class]; -+ b = data->info->b[sensor->class]; -+ R = data->info->R[sensor->class]; -+ -+ if (m == 0) -+ return 0; -+ -+ /* X = 1/m * (Y * 10^-R - b) */ -+ R = -R; -+ /* scale result to milli-units for everything but fans */ -+ if (!(sensor->class == PSC_FAN || sensor->class == PSC_PWM)) { -+ R += 3; -+ b *= 1000; -+ } -+ -+ /* scale result to micro-units for power sensors */ -+ if (sensor->class == PSC_POWER) { -+ R += 3; -+ b *= 1000; -+ } -+ -+ while (R > 0) { -+ val *= 10; -+ R--; -+ } -+ while (R < 0) { -+ val = div_s64(val + 5LL, 10L); /* round closest */ -+ R++; -+ } -+ -+ val = div_s64(val - b, m); -+ return val; -+} -+ -+/* -+ * Convert VID sensor values to milli- or micro-units -+ * depending on sensor type. -+ */ -+static s64 pmbus_reg2data_vid(struct pmbus_data *data, -+ struct pmbus_sensor *sensor) -+{ -+ long val = sensor->data; -+ long rv = 0; -+ -+ switch (data->info->vrm_version[sensor->page]) { -+ case vr11: -+ if (val >= 0x02 && val <= 0xb2) -+ rv = DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); -+ break; -+ case vr12: -+ if (val >= 0x01) -+ rv = 250 + (val - 1) * 5; -+ break; -+ case vr13: -+ if (val >= 0x01) -+ rv = 500 + (val - 1) * 10; -+ break; -+ case imvp9: -+ if (val >= 0x01) -+ rv = 200 + (val - 1) * 10; -+ break; -+ case amd625mv: -+ if (val >= 0x0 && val <= 0xd8) -+ rv = DIV_ROUND_CLOSEST(155000 - val * 625, 100); -+ break; -+ } -+ return rv; -+} -+ -+static s64 pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) -+{ -+ s64 val; -+ -+ if (!sensor->convert) -+ return sensor->data; -+ -+ switch (data->info->format[sensor->class]) { -+ case direct: -+ val = pmbus_reg2data_direct(data, sensor); -+ break; -+ case vid: -+ val = pmbus_reg2data_vid(data, sensor); -+ break; -+ case linear: -+ default: -+ val = pmbus_reg2data_linear(data, sensor); -+ break; -+ } -+ return val; -+} -+ -+#define MAX_MANTISSA (1023 * 1000) -+#define MIN_MANTISSA (511 * 1000) -+ -+static u16 pmbus_data2reg_linear(struct pmbus_data *data, -+ struct pmbus_sensor *sensor, s64 val) -+{ -+ s16 exponent = 0, mantissa; -+ bool negative = false; -+ -+ /* simple case */ -+ if (val == 0) -+ return 0; -+ -+ if (sensor->class == PSC_VOLTAGE_OUT) { -+ /* LINEAR16 does not support negative voltages */ -+ if (val < 0) -+ return 0; -+ -+ /* -+ * For a static exponents, we don't have a choice -+ * but to adjust the value to it. -+ */ -+ if (data->exponent[sensor->page] < 0) -+ val <<= -data->exponent[sensor->page]; -+ else -+ val >>= data->exponent[sensor->page]; -+ val = DIV_ROUND_CLOSEST_ULL(val, 1000); -+ return clamp_val(val, 0, 0xffff); -+ } -+ -+ if (val < 0) { -+ negative = true; -+ val = -val; -+ } -+ -+ /* Power is in uW. Convert to mW before converting. */ -+ if (sensor->class == PSC_POWER) -+ val = DIV_ROUND_CLOSEST_ULL(val, 1000); -+ -+ /* -+ * For simplicity, convert fan data to milli-units -+ * before calculating the exponent. -+ */ -+ if (sensor->class == PSC_FAN) -+ val = val * 1000LL; -+ -+ /* Reduce large mantissa until it fits into 10 bit */ -+ while (val >= MAX_MANTISSA && exponent < 15) { -+ exponent++; -+ val >>= 1; -+ } -+ /* Increase small mantissa to improve precision */ -+ while (val < MIN_MANTISSA && exponent > -15) { -+ exponent--; -+ val <<= 1; -+ } -+ -+ /* Convert mantissa from milli-units to units */ -+ mantissa = clamp_val(DIV_ROUND_CLOSEST_ULL(val, 1000), 0, 0x3ff); -+ -+ /* restore sign */ -+ if (negative) -+ mantissa = -mantissa; -+ -+ /* Convert to 5 bit exponent, 11 bit mantissa */ -+ return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800); -+} -+ -+static u16 pmbus_data2reg_direct(struct pmbus_data *data, -+ struct pmbus_sensor *sensor, s64 val) -+{ -+ s64 b; -+ s32 m, R; -+ -+ m = data->info->m[sensor->class]; -+ b = data->info->b[sensor->class]; -+ R = data->info->R[sensor->class]; -+ -+ /* Power is in uW. Adjust R and b. */ -+ if (sensor->class == PSC_POWER) { -+ R -= 3; -+ b *= 1000; -+ } -+ -+ /* Calculate Y = (m * X + b) * 10^R */ -+ if (!(sensor->class == PSC_FAN || sensor->class == PSC_PWM)) { -+ R -= 3; /* Adjust R and b for data in milli-units */ -+ b *= 1000; -+ } -+ val = val * m + b; -+ -+ while (R > 0) { -+ val *= 10; -+ R--; -+ } -+ while (R < 0) { -+ val = div_s64(val + 5LL, 10L); /* round closest */ -+ R++; -+ } -+ -+ return (u16)clamp_val(val, S16_MIN, S16_MAX); -+} -+ -+static u16 pmbus_data2reg_vid(struct pmbus_data *data, -+ struct pmbus_sensor *sensor, s64 val) -+{ -+ val = clamp_val(val, 500, 1600); -+ -+ return 2 + DIV_ROUND_CLOSEST_ULL((1600LL - val) * 100LL, 625); -+} -+ -+static u16 pmbus_data2reg(struct pmbus_data *data, -+ struct pmbus_sensor *sensor, s64 val) -+{ -+ u16 regval; -+ -+ if (!sensor->convert) -+ return val; -+ -+ switch (data->info->format[sensor->class]) { -+ case direct: -+ regval = pmbus_data2reg_direct(data, sensor, val); -+ break; -+ case vid: -+ regval = pmbus_data2reg_vid(data, sensor, val); -+ break; -+ case linear: -+ default: -+ regval = pmbus_data2reg_linear(data, sensor, val); -+ break; -+ } -+ return regval; -+} -+ -+/* -+ * Return boolean calculated from converted data. -+ * defines a status register index and mask. -+ * The mask is in the lower 8 bits, the register index is in bits 8..23. -+ * -+ * The associated pmbus_boolean structure contains optional pointers to two -+ * sensor attributes. If specified, those attributes are compared against each -+ * other to determine if a limit has been exceeded. -+ * -+ * If the sensor attribute pointers are NULL, the function returns true if -+ * (status[reg] & mask) is true. -+ * -+ * If sensor attribute pointers are provided, a comparison against a specified -+ * limit has to be performed to determine the boolean result. -+ * In this case, the function returns true if v1 >= v2 (where v1 and v2 are -+ * sensor values referenced by sensor attribute pointers s1 and s2). -+ * -+ * To determine if an object exceeds upper limits, specify = . -+ * To determine if an object exceeds lower limits, specify = . -+ * -+ * If a negative value is stored in any of the referenced registers, this value -+ * reflects an error code which will be returned. -+ */ -+static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b, -+ int index) -+{ -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ struct pmbus_sensor *s1 = b->s1; -+ struct pmbus_sensor *s2 = b->s2; -+ u16 mask = pb_index_to_mask(index); -+ u8 page = pb_index_to_page(index); -+ u16 reg = pb_index_to_reg(index); -+ int ret, status; -+ u16 regval; -+ -+ mutex_lock(&data->update_lock); -+ status = pmbus_get_status(client, page, reg); -+ if (status < 0) { -+ ret = status; -+ goto unlock; -+ } -+ -+ if (s1) -+ pmbus_update_sensor_data(client, s1); -+ if (s2) -+ pmbus_update_sensor_data(client, s2); -+ -+ regval = status & mask; -+ if (s1 && s2) { -+ s64 v1, v2; -+ -+ if (s1->data < 0) { -+ ret = s1->data; -+ goto unlock; -+ } -+ if (s2->data < 0) { -+ ret = s2->data; -+ goto unlock; -+ } -+ -+ v1 = pmbus_reg2data(data, s1); -+ v2 = pmbus_reg2data(data, s2); -+ ret = !!(regval && v1 >= v2); -+ } else { -+ ret = !!regval; -+ } -+unlock: -+ mutex_unlock(&data->update_lock); -+ return ret; -+} -+ -+static ssize_t pmbus_show_boolean(struct device *dev, -+ struct device_attribute *da, char *buf) -+{ -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); -+ struct pmbus_boolean *boolean = to_pmbus_boolean(attr); -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ int val; -+ -+ val = pmbus_get_boolean(client, boolean, attr->index); -+ if (val < 0) -+ return val; -+ return snprintf(buf, PAGE_SIZE, "%d\n", val); -+} -+ -+static ssize_t pmbus_show_sensor(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ ssize_t ret; -+ -+ mutex_lock(&data->update_lock); -+ pmbus_update_sensor_data(client, sensor); -+ if (sensor->data < 0) -+ ret = sensor->data; -+ else -+ ret = snprintf(buf, PAGE_SIZE, "%lld\n", pmbus_reg2data(data, sensor)); -+ mutex_unlock(&data->update_lock); -+ return ret; -+} -+ -+static ssize_t pmbus_set_sensor(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); -+ ssize_t rv = count; -+ s64 val; -+ int ret; -+ u16 regval; -+ -+ if (kstrtos64(buf, 10, &val) < 0) -+ return -EINVAL; -+ -+ mutex_lock(&data->update_lock); -+ regval = pmbus_data2reg(data, sensor, val); -+ ret = _pmbus_write_word_data(client, sensor->page, sensor->reg, regval); -+ if (ret < 0) -+ rv = ret; -+ else -+ sensor->data = regval; -+ mutex_unlock(&data->update_lock); -+ return rv; -+} -+ -+static ssize_t pmbus_show_label(struct device *dev, -+ struct device_attribute *da, char *buf) -+{ -+ struct pmbus_label *label = to_pmbus_label(da); -+ -+ return snprintf(buf, PAGE_SIZE, "%s\n", label->label); -+} -+ -+static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr) -+{ -+ if (data->num_attributes >= data->max_attributes - 1) { -+ int new_max_attrs = data->max_attributes + PMBUS_ATTR_ALLOC_SIZE; -+ void *new_attrs = devm_krealloc(data->dev, data->group.attrs, -+ new_max_attrs * sizeof(void *), -+ GFP_KERNEL); -+ if (!new_attrs) -+ return -ENOMEM; -+ data->group.attrs = new_attrs; -+ data->max_attributes = new_max_attrs; -+ } -+ -+ data->group.attrs[data->num_attributes++] = attr; -+ data->group.attrs[data->num_attributes] = NULL; -+ return 0; -+} -+ -+static void pmbus_dev_attr_init(struct device_attribute *dev_attr, -+ const char *name, -+ umode_t mode, -+ ssize_t (*show)(struct device *dev, -+ struct device_attribute *attr, -+ char *buf), -+ ssize_t (*store)(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count)) -+{ -+ sysfs_attr_init(&dev_attr->attr); -+ dev_attr->attr.name = name; -+ dev_attr->attr.mode = mode; -+ dev_attr->show = show; -+ dev_attr->store = store; -+} -+ -+static void pmbus_attr_init(struct sensor_device_attribute *a, -+ const char *name, -+ umode_t mode, -+ ssize_t (*show)(struct device *dev, -+ struct device_attribute *attr, -+ char *buf), -+ ssize_t (*store)(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count), -+ int idx) -+{ -+ pmbus_dev_attr_init(&a->dev_attr, name, mode, show, store); -+ a->index = idx; -+} -+ -+static int pmbus_add_boolean(struct pmbus_data *data, -+ const char *name, const char *type, int seq, -+ struct pmbus_sensor *s1, -+ struct pmbus_sensor *s2, -+ u8 page, u16 reg, u16 mask) -+{ -+ struct pmbus_boolean *boolean; -+ struct sensor_device_attribute *a; -+ -+ if (WARN((s1 && !s2) || (!s1 && s2), "Bad s1/s2 parameters\n")) -+ return -EINVAL; -+ -+ boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL); -+ if (!boolean) -+ return -ENOMEM; -+ -+ a = &boolean->attribute; -+ -+ snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s", -+ name, seq, type); -+ boolean->s1 = s1; -+ boolean->s2 = s2; -+ pmbus_attr_init(a, boolean->name, 0444, pmbus_show_boolean, NULL, -+ pb_reg_to_index(page, reg, mask)); -+ -+ return pmbus_add_attribute(data, &a->dev_attr.attr); -+} -+ -+static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, -+ const char *name, const char *type, -+ int seq, int page, int phase, -+ int reg, -+ enum pmbus_sensor_classes class, -+ bool update, bool readonly, -+ bool convert) -+{ -+ struct pmbus_sensor *sensor; -+ struct device_attribute *a; -+ -+ sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL); -+ if (!sensor) -+ return NULL; -+ a = &sensor->attribute; -+ -+ if (type) -+ snprintf(sensor->name, sizeof(sensor->name), "%s%d_%s", -+ name, seq, type); -+ else -+ snprintf(sensor->name, sizeof(sensor->name), "%s%d", -+ name, seq); -+ -+ if (data->flags & PMBUS_WRITE_PROTECTED) -+ readonly = true; -+ -+ sensor->page = page; -+ sensor->phase = phase; -+ sensor->reg = reg; -+ sensor->class = class; -+ sensor->update = update; -+ sensor->convert = convert; -+ sensor->data = -ENODATA; -+ pmbus_dev_attr_init(a, sensor->name, -+ readonly ? 0444 : 0644, -+ pmbus_show_sensor, pmbus_set_sensor); -+ -+ if (pmbus_add_attribute(data, &a->attr)) -+ return NULL; -+ -+ sensor->next = data->sensors; -+ data->sensors = sensor; -+ -+ return sensor; -+} -+ -+static int pmbus_add_label(struct pmbus_data *data, -+ const char *name, int seq, -+ const char *lstring, int index, int phase) -+{ -+ struct pmbus_label *label; -+ struct device_attribute *a; -+ -+ label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL); -+ if (!label) -+ return -ENOMEM; -+ -+ a = &label->attribute; -+ -+ snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq); -+ if (!index) { -+ if (phase == 0xff) -+ strncpy(label->label, lstring, -+ sizeof(label->label) - 1); -+ else -+ snprintf(label->label, sizeof(label->label), "%s.%d", -+ lstring, phase); -+ } else { -+ if (phase == 0xff) -+ snprintf(label->label, sizeof(label->label), "%s%d", -+ lstring, index); -+ else -+ snprintf(label->label, sizeof(label->label), "%s%d.%d", -+ lstring, index, phase); -+ } -+ -+ pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL); -+ return pmbus_add_attribute(data, &a->attr); -+} -+ -+/* -+ * Search for attributes. Allocate sensors, booleans, and labels as needed. -+ */ -+ -+/* -+ * The pmbus_limit_attr structure describes a single limit attribute -+ * and its associated alarm attribute. -+ */ -+struct pmbus_limit_attr { -+ u16 reg; /* Limit register */ -+ u16 sbit; /* Alarm attribute status bit */ -+ bool update; /* True if register needs updates */ -+ bool low; /* True if low limit; for limits with compare -+ functions only */ -+ const char *attr; /* Attribute name */ -+ const char *alarm; /* Alarm attribute name */ -+}; -+ -+/* -+ * The pmbus_sensor_attr structure describes one sensor attribute. This -+ * description includes a reference to the associated limit attributes. -+ */ -+struct pmbus_sensor_attr { -+ u16 reg; /* sensor register */ -+ u16 gbit; /* generic status bit */ -+ u8 nlimit; /* # of limit registers */ -+ enum pmbus_sensor_classes class;/* sensor class */ -+ const char *label; /* sensor label */ -+ bool paged; /* true if paged sensor */ -+ bool update; /* true if update needed */ -+ bool compare; /* true if compare function needed */ -+ u32 func; /* sensor mask */ -+ u32 sfunc; /* sensor status mask */ -+ int sreg; /* status register */ -+ const struct pmbus_limit_attr *limit;/* limit registers */ -+}; -+ -+/* -+ * Add a set of limit attributes and, if supported, the associated -+ * alarm attributes. -+ * returns 0 if no alarm register found, 1 if an alarm register was found, -+ * < 0 on errors. -+ */ -+static int pmbus_add_limit_attrs(struct i2c_client *client, -+ struct pmbus_data *data, -+ const struct pmbus_driver_info *info, -+ const char *name, int index, int page, -+ struct pmbus_sensor *base, -+ const struct pmbus_sensor_attr *attr) -+{ -+ const struct pmbus_limit_attr *l = attr->limit; -+ int nlimit = attr->nlimit; -+ int have_alarm = 0; -+ int i, ret; -+ struct pmbus_sensor *curr; -+ -+ for (i = 0; i < nlimit; i++) { -+ if (wb_pmbus_check_word_register(client, page, l->reg)) { -+ curr = pmbus_add_sensor(data, name, l->attr, index, -+ page, 0xff, l->reg, attr->class, -+ attr->update || l->update, -+ false, true); -+ if (!curr) -+ return -ENOMEM; -+ if (l->sbit && (info->func[page] & attr->sfunc)) { -+ ret = pmbus_add_boolean(data, name, -+ l->alarm, index, -+ attr->compare ? l->low ? curr : base -+ : NULL, -+ attr->compare ? l->low ? base : curr -+ : NULL, -+ page, attr->sreg, l->sbit); -+ if (ret) -+ return ret; -+ have_alarm = 1; -+ } -+ } -+ l++; -+ } -+ return have_alarm; -+} -+ -+static int pmbus_add_sensor_attrs_one(struct i2c_client *client, -+ struct pmbus_data *data, -+ const struct pmbus_driver_info *info, -+ const char *name, -+ int index, int page, int phase, -+ const struct pmbus_sensor_attr *attr, -+ bool paged) -+{ -+ struct pmbus_sensor *base; -+ bool upper = !!(attr->gbit & 0xff00); /* need to check STATUS_WORD */ -+ int ret; -+ -+ if (attr->label) { -+ ret = pmbus_add_label(data, name, index, attr->label, -+ paged ? page + 1 : 0, phase); -+ if (ret) -+ return ret; -+ } -+ base = pmbus_add_sensor(data, name, "input", index, page, phase, -+ attr->reg, attr->class, true, true, true); -+ if (!base) -+ return -ENOMEM; -+ /* No limit and alarm attributes for phase specific sensors */ -+ if (attr->sfunc && phase == 0xff) { -+ ret = pmbus_add_limit_attrs(client, data, info, name, -+ index, page, base, attr); -+ if (ret < 0) -+ return ret; -+ /* -+ * Add generic alarm attribute only if there are no individual -+ * alarm attributes, if there is a global alarm bit, and if -+ * the generic status register (word or byte, depending on -+ * which global bit is set) for this page is accessible. -+ */ -+ if (!ret && attr->gbit && -+ (!upper || (upper && data->has_status_word)) && -+ pmbus_check_status_register(client, page)) { -+ ret = pmbus_add_boolean(data, name, "alarm", index, -+ NULL, NULL, -+ page, PMBUS_STATUS_WORD, -+ attr->gbit); -+ if (ret) -+ return ret; -+ } -+ } -+ return 0; -+} -+ -+static bool pmbus_sensor_is_paged(const struct pmbus_driver_info *info, -+ const struct pmbus_sensor_attr *attr) -+{ -+ int p; -+ -+ if (attr->paged) -+ return true; -+ -+ /* -+ * Some attributes may be present on more than one page despite -+ * not being marked with the paged attribute. If that is the case, -+ * then treat the sensor as being paged and add the page suffix to the -+ * attribute name. -+ * We don't just add the paged attribute to all such attributes, in -+ * order to maintain the un-suffixed labels in the case where the -+ * attribute is only on page 0. -+ */ -+ for (p = 1; p < info->pages; p++) { -+ if (info->func[p] & attr->func) -+ return true; -+ } -+ return false; -+} -+ -+static int pmbus_add_sensor_attrs(struct i2c_client *client, -+ struct pmbus_data *data, -+ const char *name, -+ const struct pmbus_sensor_attr *attrs, -+ int nattrs) -+{ -+ const struct pmbus_driver_info *info = data->info; -+ int index, i; -+ int ret; -+ -+ index = 1; -+ for (i = 0; i < nattrs; i++) { -+ int page, pages; -+ bool paged = pmbus_sensor_is_paged(info, attrs); -+ -+ pages = paged ? info->pages : 1; -+ for (page = 0; page < pages; page++) { -+ if (!(info->func[page] & attrs->func)) -+ continue; -+ ret = pmbus_add_sensor_attrs_one(client, data, info, -+ name, index, page, -+ 0xff, attrs, paged); -+ if (ret) -+ return ret; -+ index++; -+ if (info->phases[page]) { -+ int phase; -+ -+ for (phase = 0; phase < info->phases[page]; -+ phase++) { -+ if (!(info->pfunc[phase] & attrs->func)) -+ continue; -+ ret = pmbus_add_sensor_attrs_one(client, -+ data, info, name, index, page, -+ phase, attrs, paged); -+ if (ret) -+ return ret; -+ index++; -+ } -+ } -+ } -+ attrs++; -+ } -+ return 0; -+} -+ -+static const struct pmbus_limit_attr vin_limit_attrs[] = { -+ { -+ .reg = PMBUS_VIN_UV_WARN_LIMIT, -+ .attr = "min", -+ .alarm = "min_alarm", -+ .sbit = PB_VOLTAGE_UV_WARNING, -+ }, { -+ .reg = PMBUS_VIN_UV_FAULT_LIMIT, -+ .attr = "lcrit", -+ .alarm = "lcrit_alarm", -+ .sbit = PB_VOLTAGE_UV_FAULT, -+ }, { -+ .reg = PMBUS_VIN_OV_WARN_LIMIT, -+ .attr = "max", -+ .alarm = "max_alarm", -+ .sbit = PB_VOLTAGE_OV_WARNING, -+ }, { -+ .reg = PMBUS_VIN_OV_FAULT_LIMIT, -+ .attr = "crit", -+ .alarm = "crit_alarm", -+ .sbit = PB_VOLTAGE_OV_FAULT, -+ }, { -+ .reg = PMBUS_VIRT_READ_VIN_AVG, -+ .update = true, -+ .attr = "average", -+ }, { -+ .reg = PMBUS_VIRT_READ_VIN_MIN, -+ .update = true, -+ .attr = "lowest", -+ }, { -+ .reg = PMBUS_VIRT_READ_VIN_MAX, -+ .update = true, -+ .attr = "highest", -+ }, { -+ .reg = PMBUS_VIRT_RESET_VIN_HISTORY, -+ .attr = "reset_history", -+ }, { -+ .reg = PMBUS_MFR_VIN_MIN, -+ .attr = "rated_min", -+ }, { -+ .reg = PMBUS_MFR_VIN_MAX, -+ .attr = "rated_max", -+ }, -+}; -+ -+static const struct pmbus_limit_attr vmon_limit_attrs[] = { -+ { -+ .reg = PMBUS_VIRT_VMON_UV_WARN_LIMIT, -+ .attr = "min", -+ .alarm = "min_alarm", -+ .sbit = PB_VOLTAGE_UV_WARNING, -+ }, { -+ .reg = PMBUS_VIRT_VMON_UV_FAULT_LIMIT, -+ .attr = "lcrit", -+ .alarm = "lcrit_alarm", -+ .sbit = PB_VOLTAGE_UV_FAULT, -+ }, { -+ .reg = PMBUS_VIRT_VMON_OV_WARN_LIMIT, -+ .attr = "max", -+ .alarm = "max_alarm", -+ .sbit = PB_VOLTAGE_OV_WARNING, -+ }, { -+ .reg = PMBUS_VIRT_VMON_OV_FAULT_LIMIT, -+ .attr = "crit", -+ .alarm = "crit_alarm", -+ .sbit = PB_VOLTAGE_OV_FAULT, -+ } -+}; -+ -+static const struct pmbus_limit_attr vout_limit_attrs[] = { -+ { -+ .reg = PMBUS_VOUT_UV_WARN_LIMIT, -+ .attr = "min", -+ .alarm = "min_alarm", -+ .sbit = PB_VOLTAGE_UV_WARNING, -+ }, { -+ .reg = PMBUS_VOUT_UV_FAULT_LIMIT, -+ .attr = "lcrit", -+ .alarm = "lcrit_alarm", -+ .sbit = PB_VOLTAGE_UV_FAULT, -+ }, { -+ .reg = PMBUS_VOUT_OV_WARN_LIMIT, -+ .attr = "max", -+ .alarm = "max_alarm", -+ .sbit = PB_VOLTAGE_OV_WARNING, -+ }, { -+ .reg = PMBUS_VOUT_OV_FAULT_LIMIT, -+ .attr = "crit", -+ .alarm = "crit_alarm", -+ .sbit = PB_VOLTAGE_OV_FAULT, -+ }, { -+ .reg = PMBUS_VIRT_READ_VOUT_AVG, -+ .update = true, -+ .attr = "average", -+ }, { -+ .reg = PMBUS_VIRT_READ_VOUT_MIN, -+ .update = true, -+ .attr = "lowest", -+ }, { -+ .reg = PMBUS_VIRT_READ_VOUT_MAX, -+ .update = true, -+ .attr = "highest", -+ }, { -+ .reg = PMBUS_VIRT_RESET_VOUT_HISTORY, -+ .attr = "reset_history", -+ }, { -+ .reg = PMBUS_MFR_VOUT_MIN, -+ .attr = "rated_min", -+ }, { -+ .reg = PMBUS_MFR_VOUT_MAX, -+ .attr = "rated_max", -+ }, -+}; -+ -+static const struct pmbus_sensor_attr voltage_attributes[] = { -+ { -+ .reg = PMBUS_READ_VIN, -+ .class = PSC_VOLTAGE_IN, -+ .label = "vin", -+ .func = PMBUS_HAVE_VIN, -+ .sfunc = PMBUS_HAVE_STATUS_INPUT, -+ .sreg = PMBUS_STATUS_INPUT, -+ .gbit = PB_STATUS_VIN_UV, -+ .limit = vin_limit_attrs, -+ .nlimit = 0, -+ }, { -+ .reg = PMBUS_VIRT_READ_VMON, -+ .class = PSC_VOLTAGE_IN, -+ .label = "vmon", -+ .func = PMBUS_HAVE_VMON, -+ .sfunc = PMBUS_HAVE_STATUS_VMON, -+ .sreg = PMBUS_VIRT_STATUS_VMON, -+ .limit = vmon_limit_attrs, -+ .nlimit = 0, -+ }, { -+ .reg = PMBUS_READ_VCAP, -+ .class = PSC_VOLTAGE_IN, -+ .label = "vcap", -+ .func = PMBUS_HAVE_VCAP, -+ }, { -+ .reg = PMBUS_READ_VOUT, -+ .class = PSC_VOLTAGE_OUT, -+ .label = "vout", -+ .paged = true, -+ .func = PMBUS_HAVE_VOUT, -+ .sfunc = PMBUS_HAVE_STATUS_VOUT, -+ .sreg = PMBUS_STATUS_VOUT, -+ .gbit = PB_STATUS_VOUT_OV, -+ .limit = vout_limit_attrs, -+ .nlimit = 0, -+ } -+}; -+ -+/* Current attributes */ -+ -+static const struct pmbus_limit_attr iin_limit_attrs[] = { -+ { -+ .reg = PMBUS_IIN_OC_WARN_LIMIT, -+ .attr = "max", -+ .alarm = "max_alarm", -+ .sbit = PB_IIN_OC_WARNING, -+ }, { -+ .reg = PMBUS_IIN_OC_FAULT_LIMIT, -+ .attr = "crit", -+ .alarm = "crit_alarm", -+ .sbit = PB_IIN_OC_FAULT, -+ }, { -+ .reg = PMBUS_VIRT_READ_IIN_AVG, -+ .update = true, -+ .attr = "average", -+ }, { -+ .reg = PMBUS_VIRT_READ_IIN_MIN, -+ .update = true, -+ .attr = "lowest", -+ }, { -+ .reg = PMBUS_VIRT_READ_IIN_MAX, -+ .update = true, -+ .attr = "highest", -+ }, { -+ .reg = PMBUS_VIRT_RESET_IIN_HISTORY, -+ .attr = "reset_history", -+ }, { -+ .reg = PMBUS_MFR_IIN_MAX, -+ .attr = "rated_max", -+ }, -+}; -+ -+static const struct pmbus_limit_attr iout_limit_attrs[] = { -+ { -+ .reg = PMBUS_IOUT_OC_WARN_LIMIT, -+ .attr = "max", -+ .alarm = "max_alarm", -+ .sbit = PB_IOUT_OC_WARNING, -+ }, { -+ .reg = PMBUS_IOUT_UC_FAULT_LIMIT, -+ .attr = "lcrit", -+ .alarm = "lcrit_alarm", -+ .sbit = PB_IOUT_UC_FAULT, -+ }, { -+ .reg = PMBUS_IOUT_OC_FAULT_LIMIT, -+ .attr = "crit", -+ .alarm = "crit_alarm", -+ .sbit = PB_IOUT_OC_FAULT, -+ }, { -+ .reg = PMBUS_VIRT_READ_IOUT_AVG, -+ .update = true, -+ .attr = "average", -+ }, { -+ .reg = PMBUS_VIRT_READ_IOUT_MIN, -+ .update = true, -+ .attr = "lowest", -+ }, { -+ .reg = PMBUS_VIRT_READ_IOUT_MAX, -+ .update = true, -+ .attr = "highest", -+ }, { -+ .reg = PMBUS_VIRT_RESET_IOUT_HISTORY, -+ .attr = "reset_history", -+ }, { -+ .reg = PMBUS_MFR_IOUT_MAX, -+ .attr = "rated_max", -+ }, -+}; -+ -+static const struct pmbus_sensor_attr current_attributes[] = { -+ { -+ .reg = PMBUS_READ_IIN, -+ .class = PSC_CURRENT_IN, -+ .label = "iin", -+ .func = PMBUS_HAVE_IIN, -+ .sfunc = PMBUS_HAVE_STATUS_INPUT, -+ .sreg = PMBUS_STATUS_INPUT, -+ .gbit = PB_STATUS_INPUT, -+ .limit = iin_limit_attrs, -+ .nlimit = 0, -+ }, { -+ .reg = PMBUS_READ_IOUT, -+ .class = PSC_CURRENT_OUT, -+ .label = "iout", -+ .paged = true, -+ .func = PMBUS_HAVE_IOUT, -+ .sfunc = PMBUS_HAVE_STATUS_IOUT, -+ .sreg = PMBUS_STATUS_IOUT, -+ .gbit = PB_STATUS_IOUT_OC, -+ .limit = iout_limit_attrs, -+ .nlimit = 0, -+ } -+}; -+ -+/* Power attributes */ -+ -+static const struct pmbus_limit_attr pin_limit_attrs[] = { -+ { -+ .reg = PMBUS_PIN_OP_WARN_LIMIT, -+ .attr = "max", -+ .alarm = "alarm", -+ .sbit = PB_PIN_OP_WARNING, -+ }, { -+ .reg = PMBUS_VIRT_READ_PIN_AVG, -+ .update = true, -+ .attr = "average", -+ }, { -+ .reg = PMBUS_VIRT_READ_PIN_MIN, -+ .update = true, -+ .attr = "input_lowest", -+ }, { -+ .reg = PMBUS_VIRT_READ_PIN_MAX, -+ .update = true, -+ .attr = "input_highest", -+ }, { -+ .reg = PMBUS_VIRT_RESET_PIN_HISTORY, -+ .attr = "reset_history", -+ }, { -+ .reg = PMBUS_MFR_PIN_MAX, -+ .attr = "rated_max", -+ }, -+}; -+ -+static const struct pmbus_limit_attr pout_limit_attrs[] = { -+ { -+ .reg = PMBUS_POUT_MAX, -+ .attr = "cap", -+ .alarm = "cap_alarm", -+ .sbit = PB_POWER_LIMITING, -+ }, { -+ .reg = PMBUS_POUT_OP_WARN_LIMIT, -+ .attr = "max", -+ .alarm = "max_alarm", -+ .sbit = PB_POUT_OP_WARNING, -+ }, { -+ .reg = PMBUS_POUT_OP_FAULT_LIMIT, -+ .attr = "crit", -+ .alarm = "crit_alarm", -+ .sbit = PB_POUT_OP_FAULT, -+ }, { -+ .reg = PMBUS_VIRT_READ_POUT_AVG, -+ .update = true, -+ .attr = "average", -+ }, { -+ .reg = PMBUS_VIRT_READ_POUT_MIN, -+ .update = true, -+ .attr = "input_lowest", -+ }, { -+ .reg = PMBUS_VIRT_READ_POUT_MAX, -+ .update = true, -+ .attr = "input_highest", -+ }, { -+ .reg = PMBUS_VIRT_RESET_POUT_HISTORY, -+ .attr = "reset_history", -+ }, { -+ .reg = PMBUS_MFR_POUT_MAX, -+ .attr = "rated_max", -+ }, -+}; -+ -+static const struct pmbus_sensor_attr power_attributes[] = { -+ { -+ .reg = PMBUS_READ_PIN, -+ .class = PSC_POWER, -+ .label = "pin", -+ .func = PMBUS_HAVE_PIN, -+ .sfunc = PMBUS_HAVE_STATUS_INPUT, -+ .sreg = PMBUS_STATUS_INPUT, -+ .gbit = PB_STATUS_INPUT, -+ .limit = pin_limit_attrs, -+ .nlimit = 0, -+ }, { -+ .reg = PMBUS_READ_POUT, -+ .class = PSC_POWER, -+ .label = "pout", -+ .paged = true, -+ .func = PMBUS_HAVE_POUT, -+ .sfunc = PMBUS_HAVE_STATUS_IOUT, -+ .sreg = PMBUS_STATUS_IOUT, -+ .limit = pout_limit_attrs, -+ .nlimit = 0, -+ } -+}; -+ -+/* Temperature atributes */ -+ -+static const struct pmbus_limit_attr temp_limit_attrs[] = { -+ { -+ .reg = PMBUS_UT_WARN_LIMIT, -+ .low = true, -+ .attr = "min", -+ .alarm = "min_alarm", -+ .sbit = PB_TEMP_UT_WARNING, -+ }, { -+ .reg = PMBUS_UT_FAULT_LIMIT, -+ .low = true, -+ .attr = "lcrit", -+ .alarm = "lcrit_alarm", -+ .sbit = PB_TEMP_UT_FAULT, -+ }, { -+ .reg = PMBUS_OT_WARN_LIMIT, -+ .attr = "max", -+ .alarm = "max_alarm", -+ .sbit = PB_TEMP_OT_WARNING, -+ }, { -+ .reg = PMBUS_OT_FAULT_LIMIT, -+ .attr = "crit", -+ .alarm = "crit_alarm", -+ .sbit = PB_TEMP_OT_FAULT, -+ }, { -+ .reg = PMBUS_VIRT_READ_TEMP_MIN, -+ .attr = "lowest", -+ }, { -+ .reg = PMBUS_VIRT_READ_TEMP_AVG, -+ .attr = "average", -+ }, { -+ .reg = PMBUS_VIRT_READ_TEMP_MAX, -+ .attr = "highest", -+ }, { -+ .reg = PMBUS_VIRT_RESET_TEMP_HISTORY, -+ .attr = "reset_history", -+ }, { -+ .reg = PMBUS_MFR_MAX_TEMP_1, -+ .attr = "rated_max", -+ }, -+}; -+ -+static const struct pmbus_limit_attr temp_limit_attrs2[] = { -+ { -+ .reg = PMBUS_UT_WARN_LIMIT, -+ .low = true, -+ .attr = "min", -+ .alarm = "min_alarm", -+ .sbit = PB_TEMP_UT_WARNING, -+ }, { -+ .reg = PMBUS_UT_FAULT_LIMIT, -+ .low = true, -+ .attr = "lcrit", -+ .alarm = "lcrit_alarm", -+ .sbit = PB_TEMP_UT_FAULT, -+ }, { -+ .reg = PMBUS_OT_WARN_LIMIT, -+ .attr = "max", -+ .alarm = "max_alarm", -+ .sbit = PB_TEMP_OT_WARNING, -+ }, { -+ .reg = PMBUS_OT_FAULT_LIMIT, -+ .attr = "crit", -+ .alarm = "crit_alarm", -+ .sbit = PB_TEMP_OT_FAULT, -+ }, { -+ .reg = PMBUS_VIRT_READ_TEMP2_MIN, -+ .attr = "lowest", -+ }, { -+ .reg = PMBUS_VIRT_READ_TEMP2_AVG, -+ .attr = "average", -+ }, { -+ .reg = PMBUS_VIRT_READ_TEMP2_MAX, -+ .attr = "highest", -+ }, { -+ .reg = PMBUS_VIRT_RESET_TEMP2_HISTORY, -+ .attr = "reset_history", -+ }, { -+ .reg = PMBUS_MFR_MAX_TEMP_2, -+ .attr = "rated_max", -+ }, -+}; -+ -+static const struct pmbus_limit_attr temp_limit_attrs3[] = { -+ { -+ .reg = PMBUS_UT_WARN_LIMIT, -+ .low = true, -+ .attr = "min", -+ .alarm = "min_alarm", -+ .sbit = PB_TEMP_UT_WARNING, -+ }, { -+ .reg = PMBUS_UT_FAULT_LIMIT, -+ .low = true, -+ .attr = "lcrit", -+ .alarm = "lcrit_alarm", -+ .sbit = PB_TEMP_UT_FAULT, -+ }, { -+ .reg = PMBUS_OT_WARN_LIMIT, -+ .attr = "max", -+ .alarm = "max_alarm", -+ .sbit = PB_TEMP_OT_WARNING, -+ }, { -+ .reg = PMBUS_OT_FAULT_LIMIT, -+ .attr = "crit", -+ .alarm = "crit_alarm", -+ .sbit = PB_TEMP_OT_FAULT, -+ }, { -+ .reg = PMBUS_MFR_MAX_TEMP_3, -+ .attr = "rated_max", -+ }, -+}; -+ -+static const struct pmbus_sensor_attr temp_attributes[] = { -+ { -+ .reg = PMBUS_READ_TEMPERATURE_1, -+ .class = PSC_TEMPERATURE, -+ .paged = true, -+ .update = true, -+ .compare = true, -+ .func = PMBUS_HAVE_TEMP, -+ .sfunc = PMBUS_HAVE_STATUS_TEMP, -+ .sreg = PMBUS_STATUS_TEMPERATURE, -+ .gbit = PB_STATUS_TEMPERATURE, -+ .limit = temp_limit_attrs, -+ .nlimit = 0, -+ }, { -+ .reg = PMBUS_READ_TEMPERATURE_2, -+ .class = PSC_TEMPERATURE, -+ .paged = true, -+ .update = true, -+ .compare = true, -+ .func = PMBUS_HAVE_TEMP2, -+ .sfunc = PMBUS_HAVE_STATUS_TEMP, -+ .sreg = PMBUS_STATUS_TEMPERATURE, -+ .gbit = PB_STATUS_TEMPERATURE, -+ .limit = temp_limit_attrs2, -+ .nlimit = 0, -+ }, { -+ .reg = PMBUS_READ_TEMPERATURE_3, -+ .class = PSC_TEMPERATURE, -+ .paged = true, -+ .update = true, -+ .compare = true, -+ .func = PMBUS_HAVE_TEMP3, -+ .sfunc = PMBUS_HAVE_STATUS_TEMP, -+ .sreg = PMBUS_STATUS_TEMPERATURE, -+ .gbit = PB_STATUS_TEMPERATURE, -+ .limit = temp_limit_attrs3, -+ .nlimit = 0, -+ } -+}; -+ -+static const int pmbus_fan_registers[] = { -+ PMBUS_READ_FAN_SPEED_1, -+ PMBUS_READ_FAN_SPEED_2, -+ PMBUS_READ_FAN_SPEED_3, -+ PMBUS_READ_FAN_SPEED_4 -+}; -+ -+static const int pmbus_fan_status_registers[] = { -+ PMBUS_STATUS_FAN_12, -+ PMBUS_STATUS_FAN_12, -+ PMBUS_STATUS_FAN_34, -+ PMBUS_STATUS_FAN_34 -+}; -+ -+static const u32 pmbus_fan_flags[] = { -+ PMBUS_HAVE_FAN12, -+ PMBUS_HAVE_FAN12, -+ PMBUS_HAVE_FAN34, -+ PMBUS_HAVE_FAN34 -+}; -+ -+static const u32 pmbus_fan_status_flags[] = { -+ PMBUS_HAVE_STATUS_FAN12, -+ PMBUS_HAVE_STATUS_FAN12, -+ PMBUS_HAVE_STATUS_FAN34, -+ PMBUS_HAVE_STATUS_FAN34 -+}; -+ -+/* Fans */ -+ -+/* Precondition: FAN_CONFIG_x_y and FAN_COMMAND_x must exist for the fan ID */ -+static int pmbus_add_fan_ctrl(struct i2c_client *client, -+ struct pmbus_data *data, int index, int page, int id, -+ u8 config) -+{ -+ struct pmbus_sensor *sensor; -+ -+ sensor = pmbus_add_sensor(data, "fan", "target", index, page, -+ 0xff, PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN, -+ false, false, true); -+ -+ if (!sensor) -+ return -ENOMEM; -+ -+ if (!((data->info->func[page] & PMBUS_HAVE_PWM12) || -+ (data->info->func[page] & PMBUS_HAVE_PWM34))) -+ return 0; -+ -+ sensor = pmbus_add_sensor(data, "pwm", NULL, index, page, -+ 0xff, PMBUS_VIRT_PWM_1 + id, PSC_PWM, -+ false, false, true); -+ -+ if (!sensor) -+ return -ENOMEM; -+ -+ sensor = pmbus_add_sensor(data, "pwm", "enable", index, page, -+ 0xff, PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM, -+ true, false, false); -+ -+ if (!sensor) -+ return -ENOMEM; -+ -+ return 0; -+} -+ -+static int pmbus_add_fan_attributes(struct i2c_client *client, -+ struct pmbus_data *data) -+{ -+ const struct pmbus_driver_info *info = data->info; -+ int index = 1; -+ int page; -+ int ret; -+ -+ for (page = 0; page < info->pages; page++) { -+ int f; -+ -+ for (f = 0; f < ARRAY_SIZE(pmbus_fan_registers); f++) { -+ int regval; -+ -+ if (!(info->func[page] & pmbus_fan_flags[f])) -+ break; -+ -+ if (!wb_pmbus_check_word_register(client, page, -+ pmbus_fan_registers[f])) -+ break; -+ -+ /* -+ * Skip fan if not installed. -+ * Each fan configuration register covers multiple fans, -+ * so we have to do some magic. -+ */ -+ regval = _pmbus_read_byte_data(client, page, -+ pmbus_fan_config_registers[f]); -+ if (regval < 0 || -+ (!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4))))) -+ continue; -+ -+ if (pmbus_add_sensor(data, "fan", "input", index, -+ page, 0xff, pmbus_fan_registers[f], -+ PSC_FAN, true, true, true) == NULL) -+ return -ENOMEM; -+ -+ /* Fan control */ -+ if (wb_pmbus_check_word_register(client, page, -+ pmbus_fan_command_registers[f])) { -+ ret = pmbus_add_fan_ctrl(client, data, index, -+ page, f, regval); -+ if (ret < 0) -+ return ret; -+ } -+ -+ /* -+ * Each fan status register covers multiple fans, -+ * so we have to do some magic. -+ */ -+ if ((info->func[page] & pmbus_fan_status_flags[f]) && -+ wb_pmbus_check_byte_register(client, -+ page, pmbus_fan_status_registers[f])) { -+ int reg; -+ -+ if (f > 1) /* fan 3, 4 */ -+ reg = PMBUS_STATUS_FAN_34; -+ else -+ reg = PMBUS_STATUS_FAN_12; -+ ret = pmbus_add_boolean(data, "fan", -+ "alarm", index, NULL, NULL, page, reg, -+ PB_FAN_FAN1_WARNING >> (f & 1)); -+ if (ret) -+ return ret; -+ ret = pmbus_add_boolean(data, "fan", -+ "fault", index, NULL, NULL, page, reg, -+ PB_FAN_FAN1_FAULT >> (f & 1)); -+ if (ret) -+ return ret; -+ } -+ index++; -+ } -+ } -+ return 0; -+} -+ -+struct pmbus_samples_attr { -+ int reg; -+ char *name; -+}; -+ -+struct pmbus_samples_reg { -+ int page; -+ struct pmbus_samples_attr *attr; -+ struct device_attribute dev_attr; -+}; -+ -+static struct pmbus_samples_attr pmbus_samples_registers[] = { -+ { -+ .reg = PMBUS_VIRT_SAMPLES, -+ .name = "samples", -+ }, { -+ .reg = PMBUS_VIRT_IN_SAMPLES, -+ .name = "in_samples", -+ }, { -+ .reg = PMBUS_VIRT_CURR_SAMPLES, -+ .name = "curr_samples", -+ }, { -+ .reg = PMBUS_VIRT_POWER_SAMPLES, -+ .name = "power_samples", -+ }, { -+ .reg = PMBUS_VIRT_TEMP_SAMPLES, -+ .name = "temp_samples", -+ } -+}; -+ -+#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, dev_attr) -+ -+static ssize_t pmbus_show_samples(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ int val; -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct pmbus_samples_reg *reg = to_samples_reg(devattr); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ -+ mutex_lock(&data->update_lock); -+ val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg); -+ mutex_unlock(&data->update_lock); -+ if (val < 0) -+ return val; -+ -+ return snprintf(buf, PAGE_SIZE, "%d\n", val); -+} -+ -+static ssize_t pmbus_set_samples(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ int ret; -+ long val; -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct pmbus_samples_reg *reg = to_samples_reg(devattr); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ -+ if (kstrtol(buf, 0, &val) < 0) -+ return -EINVAL; -+ -+ mutex_lock(&data->update_lock); -+ ret = _pmbus_write_word_data(client, reg->page, reg->attr->reg, val); -+ mutex_unlock(&data->update_lock); -+ -+ return ret ? : count; -+} -+ -+static int pmbus_add_samples_attr(struct pmbus_data *data, int page, -+ struct pmbus_samples_attr *attr) -+{ -+ struct pmbus_samples_reg *reg; -+ -+ reg = devm_kzalloc(data->dev, sizeof(*reg), GFP_KERNEL); -+ if (!reg) -+ return -ENOMEM; -+ -+ reg->attr = attr; -+ reg->page = page; -+ -+ pmbus_dev_attr_init(®->dev_attr, attr->name, 0644, -+ pmbus_show_samples, pmbus_set_samples); -+ -+ return pmbus_add_attribute(data, ®->dev_attr.attr); -+} -+ -+static int pmbus_add_samples_attributes(struct i2c_client *client, -+ struct pmbus_data *data) -+{ -+ const struct pmbus_driver_info *info = data->info; -+ int s; -+ -+ if (!(info->func[0] & PMBUS_HAVE_SAMPLES)) -+ return 0; -+ -+ for (s = 0; s < ARRAY_SIZE(pmbus_samples_registers); s++) { -+ struct pmbus_samples_attr *attr; -+ int ret; -+ -+ attr = &pmbus_samples_registers[s]; -+ if (!wb_pmbus_check_word_register(client, 0, attr->reg)) -+ continue; -+ -+ ret = pmbus_add_samples_attr(data, 0, attr); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int pmbus_find_attributes(struct i2c_client *client, -+ struct pmbus_data *data) -+{ -+ int ret; -+ -+ /* Voltage sensors */ -+ ret = pmbus_add_sensor_attrs(client, data, "in", voltage_attributes, -+ ARRAY_SIZE(voltage_attributes)); -+ if (ret) -+ return ret; -+ -+ /* Current sensors */ -+ ret = pmbus_add_sensor_attrs(client, data, "curr", current_attributes, -+ ARRAY_SIZE(current_attributes)); -+ if (ret) -+ return ret; -+ -+ /* Power sensors */ -+ ret = pmbus_add_sensor_attrs(client, data, "power", power_attributes, -+ ARRAY_SIZE(power_attributes)); -+ if (ret) -+ return ret; -+ -+ /* Temperature sensors */ -+ ret = pmbus_add_sensor_attrs(client, data, "temp", temp_attributes, -+ ARRAY_SIZE(temp_attributes)); -+ if (ret) -+ return ret; -+ -+ /* Fans */ -+ ret = pmbus_add_fan_attributes(client, data); -+ if (ret) -+ return ret; -+ -+ ret = pmbus_add_samples_attributes(client, data); -+ return ret; -+} -+ -+/* -+ * Identify chip parameters. -+ * This function is called for all chips. -+ */ -+static int pmbus_identify_common(struct i2c_client *client, -+ struct pmbus_data *data, int page) -+{ -+ int vout_mode = -1; -+ -+ if (wb_pmbus_check_byte_register(client, page, PMBUS_VOUT_MODE)) -+ vout_mode = _pmbus_read_byte_data(client, page, -+ PMBUS_VOUT_MODE); -+ if (vout_mode >= 0 && vout_mode != 0xff) { -+ /* -+ * Not all chips support the VOUT_MODE command, -+ * so a failure to read it is not an error. -+ */ -+ switch (vout_mode >> 5) { -+ case 0: /* linear mode */ -+ if (data->info->format[PSC_VOLTAGE_OUT] != linear) -+ return -ENODEV; -+ -+ data->exponent[page] = ((s8)(vout_mode << 3)) >> 3; -+ break; -+ case 1: /* VID mode */ -+ if (data->info->format[PSC_VOLTAGE_OUT] != vid) -+ return -ENODEV; -+ break; -+ case 2: /* direct mode */ -+ if (data->info->format[PSC_VOLTAGE_OUT] != direct) -+ return -ENODEV; -+ break; -+ default: -+ return -ENODEV; -+ } -+ } -+ -+ pmbus_clear_fault_page(client, page); -+ return 0; -+} -+ -+static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, -+ struct pmbus_driver_info *info) -+{ -+ struct device *dev = &client->dev; -+ int page, ret, i; -+ -+ /* -+ * Some PMBus chips don't support PMBUS_STATUS_WORD, so try -+ * to use PMBUS_STATUS_BYTE instead if that is the case. -+ * Bail out if both registers are not supported. -+ */ -+ for(i = 0; i < PMBUS_RETRY_TIME; i++) { -+ data->read_status = pmbus_read_status_word; -+ ret = i2c_smbus_read_word_data(client, PMBUS_STATUS_WORD); -+ if (ret < 0 || ret == 0xffff) { -+ data->read_status = pmbus_read_status_byte; -+ ret = i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE); -+ if (ret < 0 || ret == 0xff) { -+ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); -+ continue; -+ } -+ } else { -+ data->has_status_word = true; -+ } -+ break; -+ } -+ -+ if(i == PMBUS_RETRY_TIME) { -+ dev_err(dev, "PMBus status register not found\n"); -+ return -ENODEV; -+ } -+ -+ /* Enable PEC if the controller supports it */ -+ for(i = 0; i < PMBUS_RETRY_TIME; i++) { -+ ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); -+ if (ret >= 0) { -+ break; -+ } -+ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); -+ } -+ -+ if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) -+ client->flags |= I2C_CLIENT_PEC; -+ -+ /* -+ * Check if the chip is write protected. If it is, we can not clear -+ * faults, and we should not try it. Also, in that case, writes into -+ * limit registers need to be disabled. -+ */ -+ for(i = 0; i < PMBUS_RETRY_TIME; i++) { -+ ret = i2c_smbus_read_byte_data(client, PMBUS_WRITE_PROTECT); -+ if (ret >= 0) { -+ break; -+ } -+ usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); -+ } -+ -+ if (ret > 0 && (ret & PB_WP_ANY)) -+ data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK; -+ -+ if (data->info->pages) -+ wb_pmbus_clear_faults(client); -+ else -+ pmbus_clear_fault_page(client, -1); -+ -+ if (info->identify) { -+ ret = (*info->identify)(client, info); -+ if (ret < 0) { -+ dev_err(dev, "Chip identification failed\n"); -+ return ret; -+ } -+ } -+ -+ if (info->pages <= 0 || info->pages > PMBUS_PAGES) { -+ dev_err(dev, "Bad number of PMBus pages: %d\n", info->pages); -+ return -ENODEV; -+ } -+ -+ for (page = 0; page < info->pages; page++) { -+ ret = pmbus_identify_common(client, data, page); -+ if (ret < 0) { -+ dev_err(dev, "Failed to identify chip capabilities\n"); -+ return ret; -+ } -+ } -+ return 0; -+} -+ -+#if IS_ENABLED(CONFIG_REGULATOR) -+static int pmbus_regulator_is_enabled(struct regulator_dev *rdev) -+{ -+ struct device *dev = rdev_get_dev(rdev); -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ u8 page = rdev_get_id(rdev); -+ int ret; -+ -+ ret = wb_pmbus_read_byte_data(client, page, PMBUS_OPERATION); -+ if (ret < 0) -+ return ret; -+ -+ return !!(ret & PB_OPERATION_CONTROL_ON); -+} -+ -+static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable) -+{ -+ struct device *dev = rdev_get_dev(rdev); -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ u8 page = rdev_get_id(rdev); -+ -+ return wb_pmbus_update_byte_data(client, page, PMBUS_OPERATION, -+ PB_OPERATION_CONTROL_ON, -+ enable ? PB_OPERATION_CONTROL_ON : 0); -+} -+ -+static int pmbus_regulator_enable(struct regulator_dev *rdev) -+{ -+ return _pmbus_regulator_on_off(rdev, 1); -+} -+ -+static int pmbus_regulator_disable(struct regulator_dev *rdev) -+{ -+ return _pmbus_regulator_on_off(rdev, 0); -+} -+ -+const struct regulator_ops wb_pmbus_regulator_ops = { -+ .enable = pmbus_regulator_enable, -+ .disable = pmbus_regulator_disable, -+ .is_enabled = pmbus_regulator_is_enabled, -+}; -+EXPORT_SYMBOL_GPL(wb_pmbus_regulator_ops); -+ -+static int pmbus_regulator_register(struct pmbus_data *data) -+{ -+ struct device *dev = data->dev; -+ const struct pmbus_driver_info *info = data->info; -+ const struct pmbus_platform_data *pdata = dev_get_platdata(dev); -+ struct regulator_dev *rdev; -+ int i; -+ -+ for (i = 0; i < info->num_regulators; i++) { -+ struct regulator_config config = { }; -+ -+ config.dev = dev; -+ config.driver_data = data; -+ -+ if (pdata && pdata->reg_init_data) -+ config.init_data = &pdata->reg_init_data[i]; -+ -+ rdev = devm_regulator_register(dev, &info->reg_desc[i], -+ &config); -+ if (IS_ERR(rdev)) { -+ dev_err(dev, "Failed to register %s regulator\n", -+ info->reg_desc[i].name); -+ return PTR_ERR(rdev); -+ } -+ } -+ -+ return 0; -+} -+#else -+static int pmbus_regulator_register(struct pmbus_data *data) -+{ -+ return 0; -+} -+#endif -+ -+static struct dentry *pmbus_debugfs_dir; /* pmbus debugfs directory */ -+ -+#if IS_ENABLED(CONFIG_DEBUG_FS) -+static int pmbus_debugfs_get(void *data, u64 *val) -+{ -+ int rc; -+ struct pmbus_debugfs_entry *entry = data; -+ -+ rc = _pmbus_read_byte_data(entry->client, entry->page, entry->reg); -+ if (rc < 0) -+ return rc; -+ -+ *val = rc; -+ -+ return 0; -+} -+DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops, pmbus_debugfs_get, NULL, -+ "0x%02llx\n"); -+ -+static int pmbus_debugfs_get_status(void *data, u64 *val) -+{ -+ int rc; -+ struct pmbus_debugfs_entry *entry = data; -+ struct pmbus_data *pdata = i2c_get_clientdata(entry->client); -+ -+ rc = pdata->read_status(entry->client, entry->page); -+ if (rc < 0) -+ return rc; -+ -+ *val = rc; -+ -+ return 0; -+} -+DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_status, pmbus_debugfs_get_status, -+ NULL, "0x%04llx\n"); -+ -+static int pmbus_debugfs_get_pec(void *data, u64 *val) -+{ -+ struct i2c_client *client = data; -+ -+ *val = !!(client->flags & I2C_CLIENT_PEC); -+ -+ return 0; -+} -+ -+static int pmbus_debugfs_set_pec(void *data, u64 val) -+{ -+ int rc; -+ struct i2c_client *client = data; -+ -+ if (!val) { -+ client->flags &= ~I2C_CLIENT_PEC; -+ return 0; -+ } -+ -+ if (val != 1) -+ return -EINVAL; -+ -+ rc = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); -+ if (rc < 0) -+ return rc; -+ -+ if (!(rc & PB_CAPABILITY_ERROR_CHECK)) -+ return -EOPNOTSUPP; -+ -+ client->flags |= I2C_CLIENT_PEC; -+ -+ return 0; -+} -+DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_pec, pmbus_debugfs_get_pec, -+ pmbus_debugfs_set_pec, "%llu\n"); -+ -+static int pmbus_init_debugfs(struct i2c_client *client, -+ struct pmbus_data *data) -+{ -+ int i, idx = 0; -+ char name[PMBUS_NAME_SIZE]; -+ struct pmbus_debugfs_entry *entries; -+ -+ if (!pmbus_debugfs_dir) -+ return -ENODEV; -+ -+ /* -+ * Create the debugfs directory for this device. Use the hwmon device -+ * name to avoid conflicts (hwmon numbers are globally unique). -+ */ -+ data->debugfs = debugfs_create_dir(dev_name(data->hwmon_dev), -+ pmbus_debugfs_dir); -+ if (IS_ERR_OR_NULL(data->debugfs)) { -+ data->debugfs = NULL; -+ return -ENODEV; -+ } -+ -+ /* Allocate the max possible entries we need. */ -+ entries = devm_kcalloc(data->dev, -+ data->info->pages * 10, sizeof(*entries), -+ GFP_KERNEL); -+ if (!entries) -+ return -ENOMEM; -+ -+ debugfs_create_file("pec", 0664, data->debugfs, client, -+ &pmbus_debugfs_ops_pec); -+ -+ for (i = 0; i < data->info->pages; ++i) { -+ /* Check accessibility of status register if it's not page 0 */ -+ if (!i || pmbus_check_status_register(client, i)) { -+ /* No need to set reg as we have special read op. */ -+ entries[idx].client = client; -+ entries[idx].page = i; -+ scnprintf(name, PMBUS_NAME_SIZE, "status%d", i); -+ debugfs_create_file(name, 0444, data->debugfs, -+ &entries[idx++], -+ &pmbus_debugfs_ops_status); -+ } -+ -+ if (data->info->func[i] & PMBUS_HAVE_STATUS_VOUT) { -+ entries[idx].client = client; -+ entries[idx].page = i; -+ entries[idx].reg = PMBUS_STATUS_VOUT; -+ scnprintf(name, PMBUS_NAME_SIZE, "status%d_vout", i); -+ debugfs_create_file(name, 0444, data->debugfs, -+ &entries[idx++], -+ &pmbus_debugfs_ops); -+ } -+ -+ if (data->info->func[i] & PMBUS_HAVE_STATUS_IOUT) { -+ entries[idx].client = client; -+ entries[idx].page = i; -+ entries[idx].reg = PMBUS_STATUS_IOUT; -+ scnprintf(name, PMBUS_NAME_SIZE, "status%d_iout", i); -+ debugfs_create_file(name, 0444, data->debugfs, -+ &entries[idx++], -+ &pmbus_debugfs_ops); -+ } -+ -+ if (data->info->func[i] & PMBUS_HAVE_STATUS_INPUT) { -+ entries[idx].client = client; -+ entries[idx].page = i; -+ entries[idx].reg = PMBUS_STATUS_INPUT; -+ scnprintf(name, PMBUS_NAME_SIZE, "status%d_input", i); -+ debugfs_create_file(name, 0444, data->debugfs, -+ &entries[idx++], -+ &pmbus_debugfs_ops); -+ } -+ -+ if (data->info->func[i] & PMBUS_HAVE_STATUS_TEMP) { -+ entries[idx].client = client; -+ entries[idx].page = i; -+ entries[idx].reg = PMBUS_STATUS_TEMPERATURE; -+ scnprintf(name, PMBUS_NAME_SIZE, "status%d_temp", i); -+ debugfs_create_file(name, 0444, data->debugfs, -+ &entries[idx++], -+ &pmbus_debugfs_ops); -+ } -+ -+ if (wb_pmbus_check_byte_register(client, i, PMBUS_STATUS_CML)) { -+ entries[idx].client = client; -+ entries[idx].page = i; -+ entries[idx].reg = PMBUS_STATUS_CML; -+ scnprintf(name, PMBUS_NAME_SIZE, "status%d_cml", i); -+ debugfs_create_file(name, 0444, data->debugfs, -+ &entries[idx++], -+ &pmbus_debugfs_ops); -+ } -+ -+ if (wb_pmbus_check_byte_register(client, i, PMBUS_STATUS_OTHER)) { -+ entries[idx].client = client; -+ entries[idx].page = i; -+ entries[idx].reg = PMBUS_STATUS_OTHER; -+ scnprintf(name, PMBUS_NAME_SIZE, "status%d_other", i); -+ debugfs_create_file(name, 0444, data->debugfs, -+ &entries[idx++], -+ &pmbus_debugfs_ops); -+ } -+ -+ if (wb_pmbus_check_byte_register(client, i, -+ PMBUS_STATUS_MFR_SPECIFIC)) { -+ entries[idx].client = client; -+ entries[idx].page = i; -+ entries[idx].reg = PMBUS_STATUS_MFR_SPECIFIC; -+ scnprintf(name, PMBUS_NAME_SIZE, "status%d_mfr", i); -+ debugfs_create_file(name, 0444, data->debugfs, -+ &entries[idx++], -+ &pmbus_debugfs_ops); -+ } -+ -+ if (data->info->func[i] & PMBUS_HAVE_STATUS_FAN12) { -+ entries[idx].client = client; -+ entries[idx].page = i; -+ entries[idx].reg = PMBUS_STATUS_FAN_12; -+ scnprintf(name, PMBUS_NAME_SIZE, "status%d_fan12", i); -+ debugfs_create_file(name, 0444, data->debugfs, -+ &entries[idx++], -+ &pmbus_debugfs_ops); -+ } -+ -+ if (data->info->func[i] & PMBUS_HAVE_STATUS_FAN34) { -+ entries[idx].client = client; -+ entries[idx].page = i; -+ entries[idx].reg = PMBUS_STATUS_FAN_34; -+ scnprintf(name, PMBUS_NAME_SIZE, "status%d_fan34", i); -+ debugfs_create_file(name, 0444, data->debugfs, -+ &entries[idx++], -+ &pmbus_debugfs_ops); -+ } -+ } -+ -+ return 0; -+} -+#else -+static int pmbus_init_debugfs(struct i2c_client *client, -+ struct pmbus_data *data) -+{ -+ return 0; -+} -+#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */ -+ -+int wb_pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info) -+{ -+ struct device *dev = &client->dev; -+ const struct pmbus_platform_data *pdata = dev_get_platdata(dev); -+ struct pmbus_data *data; -+ size_t groups_num = 0; -+ int ret; -+ -+ if (!info) -+ return -ENODEV; -+ -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE -+ | I2C_FUNC_SMBUS_BYTE_DATA -+ | I2C_FUNC_SMBUS_WORD_DATA)) -+ return -ENODEV; -+ -+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ if (info->groups) -+ while (info->groups[groups_num]) -+ groups_num++; -+ -+ data->groups = devm_kcalloc(dev, groups_num + 2, sizeof(void *), -+ GFP_KERNEL); -+ if (!data->groups) -+ return -ENOMEM; -+ -+ i2c_set_clientdata(client, data); -+ mutex_init(&data->update_lock); -+ data->dev = dev; -+ -+ if (pdata) -+ data->flags = pdata->flags; -+ data->info = info; -+ data->currpage = -1; -+ data->currphase = -1; -+ -+ ret = pmbus_init_common(client, data, info); -+ if (ret < 0) -+ return ret; -+ -+ ret = pmbus_find_attributes(client, data); -+ if (ret) -+ return ret; -+ -+ /* -+ * If there are no attributes, something is wrong. -+ * Bail out instead of trying to register nothing. -+ */ -+ if (!data->num_attributes) { -+ dev_err(dev, "No attributes found\n"); -+ return -ENODEV; -+ } -+ -+ data->groups[0] = &data->group; -+ memcpy(data->groups + 1, info->groups, sizeof(void *) * groups_num); -+ data->hwmon_dev = devm_hwmon_device_register_with_groups(dev, -+ client->name, data, data->groups); -+ if (IS_ERR(data->hwmon_dev)) { -+ dev_err(dev, "Failed to register hwmon device\n"); -+ return PTR_ERR(data->hwmon_dev); -+ } -+ -+ ret = pmbus_regulator_register(data); -+ if (ret) -+ return ret; -+ -+ ret = pmbus_init_debugfs(client, data); -+ if (ret) -+ dev_warn(dev, "Failed to register debugfs\n"); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_do_probe); -+ -+int wb_pmbus_do_remove(struct i2c_client *client) -+{ -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ -+ debugfs_remove_recursive(data->debugfs); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_do_remove); -+ -+struct dentry *wb_pmbus_get_debugfs_dir(struct i2c_client *client) -+{ -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ -+ return data->debugfs; -+} -+EXPORT_SYMBOL_GPL(wb_pmbus_get_debugfs_dir); -+ -+static int __init pmbus_core_init(void) -+{ -+ pmbus_debugfs_dir = debugfs_create_dir("pmbus", NULL); -+ if (IS_ERR(pmbus_debugfs_dir)) -+ pmbus_debugfs_dir = NULL; -+ -+ return 0; -+} -+ -+static void __exit pmbus_core_exit(void) -+{ -+ debugfs_remove_recursive(pmbus_debugfs_dir); -+} -+ -+module_init(pmbus_core_init); -+module_exit(pmbus_core_exit); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("PMBus core driver"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tmp401.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tmp401.c -new file mode 100644 -index 000000000..b8d3a024f ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tmp401.c -@@ -0,0 +1,1010 @@ -+/* tmp401.c -+ * -+ * Copyright (C) 2007,2008 Hans de Goede -+ * Preliminary tmp411 support by: -+ * Gabriel Konat, Sander Leget, Wouter Willems -+ * Copyright (C) 2009 Andre Prendel -+ * -+ * Cleanup and support for TMP431 and TMP432 by Guenter Roeck -+ * Copyright (c) 2013 Guenter Roeck -+ * -+ * 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. -+ */ -+ -+/* -+ * Driver for the Texas Instruments TMP401 SMBUS temperature sensor IC. -+ * -+ * Note this IC is in some aspect similar to the LM90, but it has quite a -+ * few differences too, for example the local temp has a higher resolution -+ * and thus has 16 bits registers for its value and limit instead of 8 bits. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* Addresses to scan */ -+/* static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c, 0x4d, -+ 0x4e, 0x4f, I2C_CLIENT_END }; */ -+ -+enum chips { tmp401, tmp411, tmp431, tmp432, tmp435, tmp461 }; -+ -+/* -+ * The TMP401 registers, note some registers have different addresses for -+ * reading and writing -+ */ -+#define TMP401_STATUS (0x02) -+#define TMP401_CONFIG_READ (0x03) -+#define TMP401_CONFIG_WRITE (0x09) -+#define TMP401_CONVERSION_RATE_READ (0x04) -+#define TMP401_CONVERSION_RATE_WRITE (0x0A) -+#define TMP401_TEMP_CRIT_HYST (0x21) -+#define TMP401_MANUFACTURER_ID_REG (0xFE) -+#define TMP401_DEVICE_ID_REG (0xFF) -+#define TMP401_DEVICE_CAR_REG (0x22) /* Consecutive Alert Register */ -+ -+static const u8 TMP401_TEMP_MSB_READ[7][2] = { -+ { 0x00, 0x01 }, /* temp */ -+ { 0x06, 0x08 }, /* low limit */ -+ { 0x05, 0x07 }, /* high limit */ -+ { 0x20, 0x19 }, /* therm (crit) limit */ -+ { 0x30, 0x34 }, /* lowest */ -+ { 0x32, 0x36 }, /* highest */ -+ { 0, 0x11 }, /* offset */ -+}; -+ -+static const u8 TMP401_TEMP_MSB_WRITE[7][2] = { -+ { 0, 0 }, /* temp (unused) */ -+ { 0x0C, 0x0E }, /* low limit */ -+ { 0x0B, 0x0D }, /* high limit */ -+ { 0x20, 0x19 }, /* therm (crit) limit */ -+ { 0x30, 0x34 }, /* lowest */ -+ { 0x32, 0x36 }, /* highest */ -+ { 0, 0x11 }, /* offset */ -+}; -+ -+static const u8 TMP401_TEMP_LSB[7][2] = { -+ { 0x15, 0x10 }, /* temp */ -+ { 0x17, 0x14 }, /* low limit */ -+ { 0x16, 0x13 }, /* high limit */ -+ { 0, 0 }, /* therm (crit) limit (unused) */ -+ { 0x31, 0x35 }, /* lowest */ -+ { 0x33, 0x37 }, /* highest */ -+ { 0, 0x12 }, /* offset */ -+}; -+ -+static const u8 TMP432_TEMP_MSB_READ[4][3] = { -+ { 0x00, 0x01, 0x23 }, /* temp */ -+ { 0x06, 0x08, 0x16 }, /* low limit */ -+ { 0x05, 0x07, 0x15 }, /* high limit */ -+ { 0x20, 0x19, 0x1A }, /* therm (crit) limit */ -+}; -+ -+static const u8 TMP432_TEMP_MSB_WRITE[4][3] = { -+ { 0, 0, 0 }, /* temp - unused */ -+ { 0x0C, 0x0E, 0x16 }, /* low limit */ -+ { 0x0B, 0x0D, 0x15 }, /* high limit */ -+ { 0x20, 0x19, 0x1A }, /* therm (crit) limit */ -+}; -+ -+static const u8 TMP432_TEMP_LSB[3][3] = { -+ { 0x29, 0x10, 0x24 }, /* temp */ -+ { 0x3E, 0x14, 0x18 }, /* low limit */ -+ { 0x3D, 0x13, 0x17 }, /* high limit */ -+}; -+ -+/* [0] = fault, [1] = low, [2] = high, [3] = therm/crit */ -+static const u8 TMP432_STATUS_REG[] = { -+ 0x1b, 0x36, 0x35, 0x37 }; -+ -+/* Flags */ -+#define TMP401_CONFIG_RANGE BIT(2) -+#define TMP401_CONFIG_SHUTDOWN BIT(6) -+#define TMP401_STATUS_LOCAL_CRIT BIT(0) -+#define TMP401_STATUS_REMOTE_CRIT BIT(1) -+#define TMP401_STATUS_REMOTE_OPEN BIT(2) -+#define TMP401_STATUS_REMOTE_LOW BIT(3) -+#define TMP401_STATUS_REMOTE_HIGH BIT(4) -+#define TMP401_STATUS_LOCAL_LOW BIT(5) -+#define TMP401_STATUS_LOCAL_HIGH BIT(6) -+ -+/* On TMP432, each status has its own register */ -+#define TMP432_STATUS_LOCAL BIT(0) -+#define TMP432_STATUS_REMOTE1 BIT(1) -+#define TMP432_STATUS_REMOTE2 BIT(2) -+ -+/* Manufacturer / Device ID's */ -+#define TMP401_MANUFACTURER_ID (0x55) -+#define TMP401_DEVICE_ID (0x11) -+#define TMP411A_DEVICE_ID (0x12) -+#define TMP411B_DEVICE_ID (0x13) -+#define TMP411C_DEVICE_ID (0x10) -+#define TMP431_DEVICE_ID (0x31) -+#define TMP432_DEVICE_ID (0x32) -+#define TMP435_DEVICE_ID (0x35) -+ -+/* Timeout function bit */ -+#define TIMEOUT_STATE_BIT (7) /* 1:enable 0:disable */ -+#define TIMEOUT_STATE_EN (1) /* 1:enable */ -+#define TIMEOUT_STATE_IEN (0) /* 0:disable */ -+#define TIMEOUT_STATE_NA "NA" -+#define TMP401_TEMP_INVALID_RETRY_TIMES (3) -+ -+/* input temp threshold check */ -+typedef struct tmp401_temp_threshold_s { -+ int chip_type; -+ int temp_max; -+ int temp_min; -+} tmp401_temp_threshold_t; -+ -+static tmp401_temp_threshold_t g_tmp401_input_threshold_info[] = { -+ { -+ .chip_type = tmp411, -+ .temp_max = 127000, -+ .temp_min = -55000, -+ }, -+}; -+ -+/* -+ * Driver data (common to all clients) -+ */ -+ -+static const struct i2c_device_id tmp401_id[] = { -+ { "wb_tmp401", tmp401 }, -+ { "wb_tmp411", tmp411 }, -+ { "wb_tmp431", tmp431 }, -+ { "wb_tmp432", tmp432 }, -+ { "wb_tmp435", tmp435 }, -+ { "wb_tmp461", tmp461 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, tmp401_id); -+ -+/* -+ * Client data (each client gets its own) -+ */ -+ -+struct tmp401_data { -+ struct i2c_client *client; -+ const struct attribute_group *groups[3]; -+ struct mutex update_lock; -+ char valid; /* zero until following fields are valid */ -+ unsigned long last_updated; /* in jiffies */ -+ enum chips kind; -+ -+ unsigned int update_interval; /* in milliseconds */ -+ -+ /* register values */ -+ u8 status[4]; -+ u8 config; -+ u16 temp[7][3]; -+ u8 temp_crit_hyst; -+}; -+ -+/* -+ * Sysfs attr show / store functions -+ */ -+ -+static int tmp401_register_to_temp(u16 reg, u8 config) -+{ -+ int temp = reg; -+ -+ if (config & TMP401_CONFIG_RANGE) -+ temp -= 64 * 256; -+ -+ return DIV_ROUND_CLOSEST(temp * 125, 32); -+} -+ -+static u16 tmp401_temp_to_register(long temp, u8 config, int zbits) -+{ -+ if (config & TMP401_CONFIG_RANGE) { -+ temp = clamp_val(temp, -64000, 191000); -+ temp += 64000; -+ } else -+ temp = clamp_val(temp, 0, 127000); -+ -+ return DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits; -+} -+ -+static int tmp401_update_device_reg16(struct i2c_client *client, -+ struct tmp401_data *data) -+{ -+ int i, j, val; -+ int num_regs = data->kind == tmp411 ? 6 : 4; -+ int num_sensors = data->kind == tmp432 ? 3 : 2; -+ -+ for (i = 0; i < num_sensors; i++) { /* local / r1 / r2 */ -+ for (j = 0; j < num_regs; j++) { /* temp / low / ... */ -+ u8 regaddr; -+ /* -+ * High byte must be read first immediately followed -+ * by the low byte -+ */ -+ regaddr = data->kind == tmp432 ? -+ TMP432_TEMP_MSB_READ[j][i] : -+ TMP401_TEMP_MSB_READ[j][i]; -+ val = i2c_smbus_read_byte_data(client, regaddr); -+ if (val < 0) -+ return val; -+ data->temp[j][i] = val << 8; -+ if (j == 3) /* crit is msb only */ -+ continue; -+ regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[j][i] -+ : TMP401_TEMP_LSB[j][i]; -+ val = i2c_smbus_read_byte_data(client, regaddr); -+ if (val < 0) -+ return val; -+ data->temp[j][i] |= val; -+ } -+ } -+ return 0; -+} -+ -+static struct tmp401_data *tmp401_update_device(struct device *dev) -+{ -+ struct tmp401_data *data = dev_get_drvdata(dev); -+ struct i2c_client *client = data->client; -+ struct tmp401_data *ret = data; -+ int i, val; -+ unsigned long next_update; -+ -+ mutex_lock(&data->update_lock); -+ -+ next_update = data->last_updated + -+ msecs_to_jiffies(data->update_interval); -+ if (time_after(jiffies, next_update) || !data->valid) { -+ if (data->kind != tmp432) { -+ /* -+ * The driver uses the TMP432 status format internally. -+ * Convert status to TMP432 format for other chips. -+ */ -+ val = i2c_smbus_read_byte_data(client, TMP401_STATUS); -+ if (val < 0) { -+ ret = ERR_PTR(val); -+ goto abort; -+ } -+ data->status[0] = -+ (val & TMP401_STATUS_REMOTE_OPEN) >> 1; -+ data->status[1] = -+ ((val & TMP401_STATUS_REMOTE_LOW) >> 2) | -+ ((val & TMP401_STATUS_LOCAL_LOW) >> 5); -+ data->status[2] = -+ ((val & TMP401_STATUS_REMOTE_HIGH) >> 3) | -+ ((val & TMP401_STATUS_LOCAL_HIGH) >> 6); -+ data->status[3] = val & (TMP401_STATUS_LOCAL_CRIT -+ | TMP401_STATUS_REMOTE_CRIT); -+ } else { -+ for (i = 0; i < ARRAY_SIZE(data->status); i++) { -+ val = i2c_smbus_read_byte_data(client, -+ TMP432_STATUS_REG[i]); -+ if (val < 0) { -+ ret = ERR_PTR(val); -+ goto abort; -+ } -+ data->status[i] = val; -+ } -+ } -+ -+ val = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); -+ if (val < 0) { -+ ret = ERR_PTR(val); -+ goto abort; -+ } -+ data->config = val; -+ val = tmp401_update_device_reg16(client, data); -+ if (val < 0) { -+ ret = ERR_PTR(val); -+ goto abort; -+ } -+ val = i2c_smbus_read_byte_data(client, TMP401_TEMP_CRIT_HYST); -+ if (val < 0) { -+ ret = ERR_PTR(val); -+ goto abort; -+ } -+ data->temp_crit_hyst = val; -+ -+ data->last_updated = jiffies; -+ data->valid = 1; -+ } -+ -+abort: -+ mutex_unlock(&data->update_lock); -+ return ret; -+} -+ -+static int tmp401_input_temp_check(struct tmp401_data *data, int input_val) -+{ -+ int i, size; -+ -+ size = ARRAY_SIZE(g_tmp401_input_threshold_info); -+ -+ for (i = 0; i < size; i++) { -+ if (g_tmp401_input_threshold_info[i].chip_type == data->kind) { -+ if ((input_val > g_tmp401_input_threshold_info[i].temp_max) -+ || (input_val < g_tmp401_input_threshold_info[i].temp_min)) { -+ dev_dbg(&data->client->dev, "input temp: %d not in range[%d, %d]\n", -+ input_val, g_tmp401_input_threshold_info[i].temp_min, -+ g_tmp401_input_threshold_info[i].temp_max); -+ return -EINVAL; -+ } -+ dev_dbg(&data->client->dev, "input temp: %d in range[%d, %d]", input_val, -+ g_tmp401_input_threshold_info[i].temp_min, g_tmp401_input_threshold_info[i].temp_max); -+ return 0; -+ } -+ } -+ return 0; -+} -+ -+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, char *buf) -+{ -+ int nr, index, i, value, ret; -+ struct tmp401_data *data; -+ struct i2c_client *client; -+ -+ data = dev_get_drvdata(dev); -+ client = data->client; -+ -+ nr = to_sensor_dev_attr_2(devattr)->nr; -+ index = to_sensor_dev_attr_2(devattr)->index; -+ -+ for (i = 0; i < TMP401_TEMP_INVALID_RETRY_TIMES; i++) { -+ data = tmp401_update_device(dev); -+ if (IS_ERR(data)) { -+ return PTR_ERR(data); -+ } -+ value = tmp401_register_to_temp(data->temp[nr][index], data->config); -+ if (nr != 0) { /* not input temp, return value */ -+ return sprintf(buf, "%d\n", value); -+ } -+ /* nr == 0 is temp input, do input_temp_check */ -+ ret = tmp401_input_temp_check(data, value); -+ if (ret == 0) { /* input temp check ok */ -+ return sprintf(buf, "%d\n", value); -+ } -+ if ((i + 1) < TMP401_TEMP_INVALID_RETRY_TIMES) { -+ msleep(data->update_interval); -+ } -+ } -+ dev_info(&client->dev, "temp%d_input value: %d invalid\n", index + 1, value); -+ return -EINVAL; -+} -+ -+static ssize_t show_temp_crit_hyst(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ int temp, index = to_sensor_dev_attr(devattr)->index; -+ struct tmp401_data *data = tmp401_update_device(dev); -+ -+ if (IS_ERR(data)) -+ return PTR_ERR(data); -+ -+ mutex_lock(&data->update_lock); -+ temp = tmp401_register_to_temp(data->temp[3][index], data->config); -+ temp -= data->temp_crit_hyst * 1000; -+ mutex_unlock(&data->update_lock); -+ -+ return sprintf(buf, "%d\n", temp); -+} -+ -+static ssize_t show_status(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ int nr = to_sensor_dev_attr_2(devattr)->nr; -+ int mask = to_sensor_dev_attr_2(devattr)->index; -+ struct tmp401_data *data = tmp401_update_device(dev); -+ -+ if (IS_ERR(data)) -+ return PTR_ERR(data); -+ -+ return sprintf(buf, "%d\n", !!(data->status[nr] & mask)); -+} -+ -+static ssize_t store_temp(struct device *dev, struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ int nr = to_sensor_dev_attr_2(devattr)->nr; -+ int index = to_sensor_dev_attr_2(devattr)->index; -+ struct tmp401_data *data = dev_get_drvdata(dev); -+ struct i2c_client *client = data->client; -+ long val; -+ u16 reg; -+ u8 regaddr; -+ -+ if (kstrtol(buf, 10, &val)) -+ return -EINVAL; -+ -+ reg = tmp401_temp_to_register(val, data->config, nr == 3 ? 8 : 4); -+ -+ mutex_lock(&data->update_lock); -+ -+ regaddr = data->kind == tmp432 ? TMP432_TEMP_MSB_WRITE[nr][index] -+ : TMP401_TEMP_MSB_WRITE[nr][index]; -+ i2c_smbus_write_byte_data(client, regaddr, reg >> 8); -+ if (nr != 3) { -+ regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[nr][index] -+ : TMP401_TEMP_LSB[nr][index]; -+ i2c_smbus_write_byte_data(client, regaddr, reg & 0xFF); -+ } -+ data->temp[nr][index] = reg; -+ -+ mutex_unlock(&data->update_lock); -+ -+ return count; -+} -+ -+static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute -+ *devattr, const char *buf, size_t count) -+{ -+ int temp, index = to_sensor_dev_attr(devattr)->index; -+ struct tmp401_data *data = tmp401_update_device(dev); -+ long val; -+ u8 reg; -+ -+ if (IS_ERR(data)) -+ return PTR_ERR(data); -+ -+ if (kstrtol(buf, 10, &val)) -+ return -EINVAL; -+ -+ if (data->config & TMP401_CONFIG_RANGE) -+ val = clamp_val(val, -64000, 191000); -+ else -+ val = clamp_val(val, 0, 127000); -+ -+ mutex_lock(&data->update_lock); -+ temp = tmp401_register_to_temp(data->temp[3][index], data->config); -+ val = clamp_val(val, temp - 255000, temp); -+ reg = ((temp - val) + 500) / 1000; -+ -+ i2c_smbus_write_byte_data(data->client, TMP401_TEMP_CRIT_HYST, -+ reg); -+ -+ data->temp_crit_hyst = reg; -+ -+ mutex_unlock(&data->update_lock); -+ -+ return count; -+} -+ -+/* -+ * Resets the historical measurements of minimum and maximum temperatures. -+ * This is done by writing any value to any of the minimum/maximum registers -+ * (0x30-0x37). -+ */ -+static ssize_t reset_temp_history(struct device *dev, -+ struct device_attribute *devattr, const char *buf, size_t count) -+{ -+ struct tmp401_data *data = dev_get_drvdata(dev); -+ struct i2c_client *client = data->client; -+ long val; -+ -+ if (kstrtol(buf, 10, &val)) -+ return -EINVAL; -+ -+ if (val != 1) { -+ dev_err(dev, -+ "temp_reset_history value %ld not supported. Use 1 to reset the history!\n", -+ val); -+ return -EINVAL; -+ } -+ mutex_lock(&data->update_lock); -+ i2c_smbus_write_byte_data(client, TMP401_TEMP_MSB_WRITE[5][0], val); -+ data->valid = 0; -+ mutex_unlock(&data->update_lock); -+ -+ return count; -+} -+ -+static ssize_t show_update_interval(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct tmp401_data *data = dev_get_drvdata(dev); -+ -+ return sprintf(buf, "%u\n", data->update_interval); -+} -+ -+static ssize_t set_update_interval(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct tmp401_data *data = dev_get_drvdata(dev); -+ struct i2c_client *client = data->client; -+ unsigned long val; -+ int err, rate; -+ -+ err = kstrtoul(buf, 10, &val); -+ if (err) -+ return err; -+ -+ /* -+ * For valid rates, interval can be calculated as -+ * interval = (1 << (7 - rate)) * 125; -+ * Rounded rate is therefore -+ * rate = 7 - __fls(interval * 4 / (125 * 3)); -+ * Use clamp_val() to avoid overflows, and to ensure valid input -+ * for __fls. -+ */ -+ val = clamp_val(val, 125, 16000); -+ rate = 7 - __fls(val * 4 / (125 * 3)); -+ mutex_lock(&data->update_lock); -+ i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, rate); -+ data->update_interval = (1 << (7 - rate)) * 125; -+ mutex_unlock(&data->update_lock); -+ -+ return count; -+} -+ -+/* -+ * Enable/disable the state of the timeout function -+ * @dev: device info -+ * @state: 1:enable 0:disable -+ */ -+static int timeout_cfg(struct device *dev, int state) -+{ -+ int rv, chip_type; -+ u8 reg_value; -+ struct tmp401_data *data; -+ struct i2c_client *client; -+ -+ data = dev_get_drvdata(dev); -+ client = data->client; -+ -+ /* get chip type */ -+ chip_type = data->kind; -+ dev_dbg(&client->dev, "set timeout. chip:%d, state:%d\n", chip_type, state); -+ -+ /* chip type check */ -+ if(chip_type != tmp401 && chip_type != tmp411) { -+ dev_info(&client->dev, -+ "Chip type: %d, not support timeout config.!\n", chip_type); -+ return -EPERM; -+ } -+ -+ /* parameter check */ -+ if(state != TIMEOUT_STATE_EN && state != TIMEOUT_STATE_IEN) { -+ dev_err(&client->dev, -+ "Parameter check error. state: %d not supported.!\n", state); -+ return -EINVAL; -+ } -+ -+ mutex_lock(&data->update_lock); -+ /* read the Consecutive alert register */ -+ reg_value = i2c_smbus_read_byte_data(client, TMP401_DEVICE_CAR_REG); -+ if (reg_value < 0) { -+ dev_err(&client->dev, "Failed to read. reg:0x%0x, value:%d\n", TMP401_DEVICE_CAR_REG, reg_value); -+ mutex_unlock(&data->update_lock); -+ return -EIO; -+ } -+ dev_dbg(&client->dev, "get register value. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); -+ -+ /* same value case, do not write */ -+ if((u8)state == (reg_value >> TIMEOUT_STATE_BIT)) { -+ mutex_unlock(&data->update_lock); -+ dev_info(&client->dev, "timeout config has been set and the current state is %d.\n", state); -+ return 0; -+ } -+ -+ /* calculate the register value */ -+ reg_value = (reg_value & ~(1 << TIMEOUT_STATE_BIT)) | (state << TIMEOUT_STATE_BIT); -+ -+ /* set the Consecutive alert register */ -+ dev_dbg(&client->dev, "set register value. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); -+ rv = i2c_smbus_write_byte_data(client, TMP401_DEVICE_CAR_REG, reg_value); -+ if (rv < 0) { -+ dev_err(&client->dev, -+ "set the register Error. reg:0x%0x, value:%d\n", TMP401_DEVICE_CAR_REG, reg_value); -+ mutex_unlock(&data->update_lock); -+ return -EIO; -+ } -+ mutex_unlock(&data->update_lock); -+ -+ dev_info(&client->dev, "set bus timeout success. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); -+ -+ return 0; -+} -+ -+static ssize_t set_timeout_en(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int val, err; -+ struct i2c_client *client; -+ struct tmp401_data *data; -+ -+ data = dev_get_drvdata(dev); -+ client = data->client; -+ -+ err = kstrtoint(buf, 0, &val); -+ if (err) { -+ dev_err(&client->dev, -+ "kstrtoint error: %d.\n", err); -+ return err; -+ } -+ -+ err = timeout_cfg(dev, val); -+ if(err < 0) { -+ dev_err(&client->dev, -+ "set bus timeout error: %d. value:%d!\n", err, val); -+ return err; -+ } -+ -+ return count; -+} -+ -+static ssize_t show_timeout_en(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ int chip_type; -+ u8 reg_value; -+ struct tmp401_data *data; -+ struct i2c_client *client; -+ -+ data = dev_get_drvdata(dev); -+ client = data->client; -+ -+ /* get chip type */ -+ chip_type = data->kind; -+ dev_dbg(&client->dev, "get timeout. chip:%d\n", chip_type); -+ -+ /* chip type check */ -+ if(chip_type != tmp401 && chip_type != tmp411) { -+ dev_info(&client->dev, -+ "Chip type: %d, not support timeout config.!\n", chip_type); -+ /* not support, return NA */ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", TIMEOUT_STATE_NA); -+ } -+ -+ /* read the Consecutive alert register */ -+ reg_value = i2c_smbus_read_byte_data(client, TMP401_DEVICE_CAR_REG); -+ if (reg_value < 0) { -+ dev_err(&client->dev, "Failed to read. reg:0x%0x, value:%d\n", TMP401_DEVICE_CAR_REG, reg_value); -+ return -EIO; -+ } -+ dev_dbg(&client->dev, "get register value. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); -+ -+ /* decode the register value */ -+ reg_value = reg_value >> TIMEOUT_STATE_BIT; -+ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", reg_value); -+} -+ -+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0); -+static SENSOR_DEVICE_ATTR_2(temp1_min, S_IWUSR | S_IRUGO, show_temp, -+ store_temp, 1, 0); -+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IWUSR | S_IRUGO, show_temp, -+ store_temp, 2, 0); -+static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IWUSR | S_IRUGO, show_temp, -+ store_temp, 3, 0); -+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, -+ show_temp_crit_hyst, store_temp_crit_hyst, 0); -+static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO, show_status, NULL, -+ 1, TMP432_STATUS_LOCAL); -+static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_status, NULL, -+ 2, TMP432_STATUS_LOCAL); -+static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_status, NULL, -+ 3, TMP432_STATUS_LOCAL); -+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1); -+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp, -+ store_temp, 1, 1); -+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp, -+ store_temp, 2, 1); -+static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IWUSR | S_IRUGO, show_temp, -+ store_temp, 3, 1); -+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, -+ NULL, 1); -+static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_status, NULL, -+ 0, TMP432_STATUS_REMOTE1); -+static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_status, NULL, -+ 1, TMP432_STATUS_REMOTE1); -+static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_status, NULL, -+ 2, TMP432_STATUS_REMOTE1); -+static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_status, NULL, -+ 3, TMP432_STATUS_REMOTE1); -+ -+static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval, -+ set_update_interval); -+static DEVICE_ATTR(timeout_en, S_IRUGO | S_IWUSR, show_timeout_en, set_timeout_en); -+ -+static struct attribute *tmp401_attributes[] = { -+ &sensor_dev_attr_temp1_input.dev_attr.attr, -+ &sensor_dev_attr_temp1_min.dev_attr.attr, -+ &sensor_dev_attr_temp1_max.dev_attr.attr, -+ &sensor_dev_attr_temp1_crit.dev_attr.attr, -+ &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, -+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, -+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, -+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, -+ -+ &sensor_dev_attr_temp2_input.dev_attr.attr, -+ &sensor_dev_attr_temp2_min.dev_attr.attr, -+ &sensor_dev_attr_temp2_max.dev_attr.attr, -+ &sensor_dev_attr_temp2_crit.dev_attr.attr, -+ &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, -+ &sensor_dev_attr_temp2_fault.dev_attr.attr, -+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, -+ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, -+ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, -+ -+ &dev_attr_update_interval.attr, -+ &dev_attr_timeout_en.attr, -+ -+ NULL -+}; -+ -+static const struct attribute_group tmp401_group = { -+ .attrs = tmp401_attributes, -+}; -+ -+/* -+ * Additional features of the TMP411 chip. -+ * The TMP411 stores the minimum and maximum -+ * temperature measured since power-on, chip-reset, or -+ * minimum and maximum register reset for both the local -+ * and remote channels. -+ */ -+static SENSOR_DEVICE_ATTR_2(temp1_lowest, S_IRUGO, show_temp, NULL, 4, 0); -+static SENSOR_DEVICE_ATTR_2(temp1_highest, S_IRUGO, show_temp, NULL, 5, 0); -+static SENSOR_DEVICE_ATTR_2(temp2_lowest, S_IRUGO, show_temp, NULL, 4, 1); -+static SENSOR_DEVICE_ATTR_2(temp2_highest, S_IRUGO, show_temp, NULL, 5, 1); -+static SENSOR_DEVICE_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history, -+ 0); -+ -+static struct attribute *tmp411_attributes[] = { -+ &sensor_dev_attr_temp1_highest.dev_attr.attr, -+ &sensor_dev_attr_temp1_lowest.dev_attr.attr, -+ &sensor_dev_attr_temp2_highest.dev_attr.attr, -+ &sensor_dev_attr_temp2_lowest.dev_attr.attr, -+ &sensor_dev_attr_temp_reset_history.dev_attr.attr, -+ NULL -+}; -+ -+static const struct attribute_group tmp411_group = { -+ .attrs = tmp411_attributes, -+}; -+ -+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2); -+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IWUSR | S_IRUGO, show_temp, -+ store_temp, 1, 2); -+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IWUSR | S_IRUGO, show_temp, -+ store_temp, 2, 2); -+static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IWUSR | S_IRUGO, show_temp, -+ store_temp, 3, 2); -+static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, -+ NULL, 2); -+static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_status, NULL, -+ 0, TMP432_STATUS_REMOTE2); -+static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_status, NULL, -+ 1, TMP432_STATUS_REMOTE2); -+static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_status, NULL, -+ 2, TMP432_STATUS_REMOTE2); -+static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_status, NULL, -+ 3, TMP432_STATUS_REMOTE2); -+ -+static struct attribute *tmp432_attributes[] = { -+ &sensor_dev_attr_temp3_input.dev_attr.attr, -+ &sensor_dev_attr_temp3_min.dev_attr.attr, -+ &sensor_dev_attr_temp3_max.dev_attr.attr, -+ &sensor_dev_attr_temp3_crit.dev_attr.attr, -+ &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, -+ &sensor_dev_attr_temp3_fault.dev_attr.attr, -+ &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, -+ &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, -+ &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, -+ -+ NULL -+}; -+ -+static const struct attribute_group tmp432_group = { -+ .attrs = tmp432_attributes, -+}; -+ -+/* -+ * Additional features of the TMP461 chip. -+ * The TMP461 temperature offset for the remote channel. -+ */ -+static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IWUSR | S_IRUGO, show_temp, -+ store_temp, 6, 1); -+ -+static struct attribute *tmp461_attributes[] = { -+ &sensor_dev_attr_temp2_offset.dev_attr.attr, -+ NULL -+}; -+ -+static const struct attribute_group tmp461_group = { -+ .attrs = tmp461_attributes, -+}; -+ -+/* -+ * Begin non sysfs callback code (aka Real code) -+ */ -+ -+static int tmp401_init_client(struct tmp401_data *data, -+ struct i2c_client *client) -+{ -+ int config, config_orig, status = 0; -+ -+ /* Set the conversion rate to 2 Hz */ -+ i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5); -+ data->update_interval = 500; -+ -+ /* Start conversions (disable shutdown if necessary) */ -+ config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); -+ if (config < 0) -+ return config; -+ -+ config_orig = config; -+ config &= ~TMP401_CONFIG_SHUTDOWN; -+ -+ if (config != config_orig) -+ status = i2c_smbus_write_byte_data(client, -+ TMP401_CONFIG_WRITE, -+ config); -+ -+ return status; -+} -+ -+#if 0 -+static int tmp401_detect(struct i2c_client *client, -+ struct i2c_board_info *info) -+{ -+ enum chips kind; -+ struct i2c_adapter *adapter = client->adapter; -+ u8 reg; -+ -+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) -+ return -ENODEV; -+ -+ /* Detect and identify the chip */ -+ reg = i2c_smbus_read_byte_data(client, TMP401_MANUFACTURER_ID_REG); -+ if (reg != TMP401_MANUFACTURER_ID) -+ return -ENODEV; -+ -+ reg = i2c_smbus_read_byte_data(client, TMP401_DEVICE_ID_REG); -+ -+ switch (reg) { -+ case TMP401_DEVICE_ID: -+ if (client->addr != 0x4c) -+ return -ENODEV; -+ kind = tmp401; -+ break; -+ case TMP411A_DEVICE_ID: -+ if (client->addr != 0x4c) -+ return -ENODEV; -+ kind = tmp411; -+ break; -+ case TMP411B_DEVICE_ID: -+ if (client->addr != 0x4d) -+ return -ENODEV; -+ kind = tmp411; -+ break; -+ case TMP411C_DEVICE_ID: -+ if (client->addr != 0x4e) -+ return -ENODEV; -+ kind = tmp411; -+ break; -+ case TMP431_DEVICE_ID: -+ if (client->addr != 0x4c && client->addr != 0x4d) -+ return -ENODEV; -+ kind = tmp431; -+ break; -+ case TMP432_DEVICE_ID: -+ if (client->addr != 0x4c && client->addr != 0x4d) -+ return -ENODEV; -+ kind = tmp432; -+ break; -+ case TMP435_DEVICE_ID: -+ kind = tmp435; -+ break; -+ default: -+ return -ENODEV; -+ } -+ -+ reg = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); -+ if (reg & 0x1b) -+ return -ENODEV; -+ -+ reg = i2c_smbus_read_byte_data(client, TMP401_CONVERSION_RATE_READ); -+ /* Datasheet says: 0x1-0x6 */ -+ if (reg > 15) -+ return -ENODEV; -+ -+ strlcpy(info->type, tmp401_id[kind].name, I2C_NAME_SIZE); -+ -+ return 0; -+} -+#endif -+ -+static int tmp401_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ static const char * const names[] = { -+ "TMP401", "TMP411", "TMP431", "TMP432", "TMP435", "TMP461" -+ }; -+ struct device *dev = &client->dev; -+ struct device *hwmon_dev; -+ struct tmp401_data *data; -+ int groups = 0, status; -+ -+ data = devm_kzalloc(dev, sizeof(struct tmp401_data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ data->client = client; -+ mutex_init(&data->update_lock); -+ data->kind = id->driver_data; -+ -+ /* Initialize the TMP401 chip */ -+ status = tmp401_init_client(data, client); -+ if (status < 0) -+ return status; -+ -+ /* Register sysfs hooks */ -+ data->groups[groups++] = &tmp401_group; -+ -+ /* Register additional tmp411 sysfs hooks */ -+ if (data->kind == tmp411) -+ data->groups[groups++] = &tmp411_group; -+ -+ /* Register additional tmp432 sysfs hooks */ -+ if (data->kind == tmp432) -+ data->groups[groups++] = &tmp432_group; -+ -+ if (data->kind == tmp461) -+ data->groups[groups++] = &tmp461_group; -+ -+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, -+ data, data->groups); -+ if (IS_ERR(hwmon_dev)) -+ return PTR_ERR(hwmon_dev); -+ -+ /* disable the timeout function */ -+ status = timeout_cfg(hwmon_dev, TIMEOUT_STATE_IEN); -+ if((status < 0) && (status != -EPERM)) { -+ dev_err(dev, -+ "set bus timeout error when probing: %d.!\n", status); -+ /* here, no need call devm_hwmon_device_unregister, device managed. */ -+ return status; -+ } -+ -+ dev_info(dev, "Detected TI %s chip\n", names[data->kind]); -+ -+ return 0; -+} -+ -+static struct i2c_driver tmp401_driver = { -+ .class = I2C_CLASS_HWMON, -+ .driver = { -+ .name = "wb_tmp401", -+ }, -+ .probe = tmp401_probe, -+ .id_table = tmp401_id, -+ /* .detect = tmp401_detect, */ -+ /* .address_list = normal_i2c, */ -+}; -+ -+module_i2c_driver(tmp401_driver); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("Texas Instruments TMP401 temperature sensor driver"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tps53622.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tps53622.c -new file mode 100644 -index 000000000..b68196d9f ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_tps53622.c -@@ -0,0 +1,265 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Hardware monitoring driver for Texas Instruments TPS53679 -+ * -+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved. -+ * Copyright (c) 2017 Vadim Pasternak -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "wb_pmbus.h" -+ -+enum chips { -+ tps53647, tps53667, tps53679, tps53681, tps53688, tps53622 -+}; -+ -+#define TPS53647_PAGE_NUM 1 -+ -+#define TPS53679_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */ -+#define TPS53679_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */ -+#define TPS53679_PROT_VR13_10MV 0x04 /* VR13.0 mode, 10-mV DAC */ -+#define TPS53679_PROT_IMVP8_5MV 0x05 /* IMVP8 mode, 5-mV DAC */ -+#define TPS53679_PROT_VR13_5MV 0x07 /* VR13.0 mode, 5-mV DAC */ -+#define TPS53679_PAGE_NUM 2 -+ -+#define TPS53681_DEVICE_ID 0x81 -+ -+#define TPS53681_PMBUS_REVISION 0x33 -+ -+#define TPS53681_MFR_SPECIFIC_20 0xe4 /* Number of phases, per page */ -+ -+static const struct i2c_device_id tps53679_id[]; -+ -+static int tps53679_identify_mode(struct i2c_client *client, -+ struct pmbus_driver_info *info) -+{ -+ u8 vout_params; -+ int i, ret; -+ -+ for (i = 0; i < info->pages; i++) { -+ /* Read the register with VOUT scaling value.*/ -+ ret = wb_pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); -+ if (ret < 0) -+ return ret; -+ -+ vout_params = ret & GENMASK(4, 0); -+ -+ switch (vout_params) { -+ case TPS53679_PROT_VR13_10MV: -+ case TPS53679_PROT_VR12_5_10MV: -+ info->vrm_version[i] = vr13; -+ break; -+ case TPS53679_PROT_VR13_5MV: -+ case TPS53679_PROT_VR12_5MV: -+ case TPS53679_PROT_IMVP8_5MV: -+ info->vrm_version[i] = vr12; -+ break; -+ default: -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ -+static int tps53679_identify_phases(struct i2c_client *client, -+ struct pmbus_driver_info *info) -+{ -+ int ret; -+ -+ /* On TPS53681, only channel A provides per-phase output current */ -+ ret = wb_pmbus_read_byte_data(client, 0, TPS53681_MFR_SPECIFIC_20); -+ if (ret < 0) -+ return ret; -+ info->phases[0] = (ret & 0x07) + 1; -+ -+ return 0; -+} -+ -+static int tps53679_identify_chip(struct i2c_client *client, -+ u8 revision, u16 id) -+{ -+ u8 buf[I2C_SMBUS_BLOCK_MAX]; -+ int ret; -+ -+ ret = wb_pmbus_read_byte_data(client, 0, PMBUS_REVISION); -+ if (ret < 0) -+ return ret; -+ if (ret != revision) { -+ dev_err(&client->dev, "Unexpected PMBus revision 0x%x\n", ret); -+ return -ENODEV; -+ } -+ -+ ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf); -+ if (ret < 0) -+ return ret; -+ if (ret != 1 || buf[0] != id) { -+ dev_err(&client->dev, "Unexpected device ID 0x%x\n", buf[0]); -+ return -ENODEV; -+ } -+ return 0; -+} -+ -+/* -+ * Common identification function for chips with multi-phase support. -+ * Since those chips have special configuration registers, we want to have -+ * some level of reassurance that we are really talking with the chip -+ * being probed. Check PMBus revision and chip ID. -+ */ -+static int tps53679_identify_multiphase(struct i2c_client *client, -+ struct pmbus_driver_info *info, -+ int pmbus_rev, int device_id) -+{ -+ int ret; -+ -+ ret = tps53679_identify_chip(client, pmbus_rev, device_id); -+ if (ret < 0) -+ return ret; -+ -+ ret = tps53679_identify_mode(client, info); -+ if (ret < 0) -+ return ret; -+ -+ return tps53679_identify_phases(client, info); -+} -+ -+static int tps53679_identify(struct i2c_client *client, -+ struct pmbus_driver_info *info) -+{ -+ return tps53679_identify_mode(client, info); -+} -+ -+static int tps53681_identify(struct i2c_client *client, -+ struct pmbus_driver_info *info) -+{ -+ return tps53679_identify_multiphase(client, info, -+ TPS53681_PMBUS_REVISION, -+ TPS53681_DEVICE_ID); -+} -+ -+static int tps53681_read_word_data(struct i2c_client *client, int page, -+ int phase, int reg) -+{ -+ /* -+ * For reading the total output current (READ_IOUT) for all phases, -+ * the chip datasheet is a bit vague. It says "PHASE must be set to -+ * FFh to access all phases simultaneously. PHASE may also be set to -+ * 80h readack (!) the total phase current". -+ * Experiments show that the command does _not_ report the total -+ * current for all phases if the phase is set to 0xff. Instead, it -+ * appears to report the current of one of the phases. Override phase -+ * parameter with 0x80 when reading the total output current on page 0. -+ */ -+ if (reg == PMBUS_READ_IOUT && page == 0 && phase == 0xff) -+ return wb_pmbus_read_word_data(client, page, 0x80, reg); -+ return -ENODATA; -+} -+ -+static struct pmbus_driver_info tps53679_info = { -+ .format[PSC_VOLTAGE_IN] = linear, -+ .format[PSC_VOLTAGE_OUT] = vid, -+ .format[PSC_TEMPERATURE] = linear, -+ .format[PSC_CURRENT_OUT] = linear, -+ .format[PSC_POWER] = linear, -+ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | -+ PMBUS_HAVE_STATUS_INPUT | -+ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | -+ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | -+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | -+ PMBUS_HAVE_POUT, -+ .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | -+ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | -+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | -+ PMBUS_HAVE_POUT, -+ .pfunc[0] = PMBUS_HAVE_IOUT, -+ .pfunc[1] = PMBUS_HAVE_IOUT, -+ .pfunc[2] = PMBUS_HAVE_IOUT, -+ .pfunc[3] = PMBUS_HAVE_IOUT, -+ .pfunc[4] = PMBUS_HAVE_IOUT, -+ .pfunc[5] = PMBUS_HAVE_IOUT, -+}; -+ -+static int tps53679_probe(struct i2c_client *client) -+{ -+ struct device *dev = &client->dev; -+ struct pmbus_driver_info *info; -+ enum chips chip_id; -+ -+ if (dev->of_node) -+ chip_id = (enum chips)of_device_get_match_data(dev); -+ else -+ chip_id = i2c_match_id(tps53679_id, client)->driver_data; -+ -+ info = devm_kmemdup(dev, &tps53679_info, sizeof(*info), GFP_KERNEL); -+ if (!info) -+ return -ENOMEM; -+ -+ switch (chip_id) { -+ case tps53647: -+ case tps53667: -+ info->pages = TPS53647_PAGE_NUM; -+ info->identify = tps53679_identify; -+ break; -+ case tps53679: -+ case tps53688: -+ case tps53622: -+ info->pages = TPS53679_PAGE_NUM; -+ info->identify = tps53679_identify; -+ break; -+ case tps53681: -+ info->pages = TPS53679_PAGE_NUM; -+ info->phases[0] = 6; -+ info->identify = tps53681_identify; -+ info->read_word_data = tps53681_read_word_data; -+ break; -+ default: -+ return -ENODEV; -+ } -+ -+ return wb_pmbus_do_probe(client, info); -+} -+ -+static const struct i2c_device_id tps53679_id[] = { -+ {"wb_tps53647", tps53647}, -+ {"wb_tps53667", tps53667}, -+ {"wb_tps53679", tps53679}, -+ {"wb_tps53681", tps53681}, -+ {"wb_tps53688", tps53688}, -+ {"wb_tps53622", tps53622}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(i2c, tps53679_id); -+ -+static const struct of_device_id __maybe_unused tps53679_of_match[] = { -+ {.compatible = "ti,wb_tps53647", .data = (void *)tps53647}, -+ {.compatible = "ti,wb_tps53667", .data = (void *)tps53667}, -+ {.compatible = "ti,wb_tps53679", .data = (void *)tps53679}, -+ {.compatible = "ti,wb_tps53681", .data = (void *)tps53681}, -+ {.compatible = "ti,wb_tps53688", .data = (void *)tps53688}, -+ {.compatible = "ti,wb_tps53622", .data = (void *)tps53622}, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, tps53679_of_match); -+ -+static struct i2c_driver tps53679_driver = { -+ .driver = { -+ .name = "wb_tps53622", -+ .of_match_table = of_match_ptr(tps53679_of_match), -+ }, -+ .probe_new = tps53679_probe, -+ .remove = wb_pmbus_do_remove, -+ .id_table = tps53679_id, -+}; -+ -+module_i2c_driver(tps53679_driver); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("PMBus driver for Texas Instruments TPS53679"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ucd9000.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ucd9000.c -new file mode 100644 -index 000000000..5c3d125af ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_ucd9000.c -@@ -0,0 +1,676 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Hardware monitoring driver for UCD90xxx Sequencer and System Health -+ * Controller series -+ * -+ * Copyright (C) 2011 Ericsson AB. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "wb_pmbus.h" -+ -+enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd90320, ucd9090, -+ ucd90910 }; -+ -+#define UCD9000_MONITOR_CONFIG 0xd5 -+#define UCD9000_NUM_PAGES 0xd6 -+#define UCD9000_FAN_CONFIG_INDEX 0xe7 -+#define UCD9000_FAN_CONFIG 0xe8 -+#define UCD9000_MFR_STATUS 0xf3 -+#define UCD9000_GPIO_SELECT 0xfa -+#define UCD9000_GPIO_CONFIG 0xfb -+#define UCD9000_DEVICE_ID 0xfd -+ -+/* GPIO CONFIG bits */ -+#define UCD9000_GPIO_CONFIG_ENABLE BIT(0) -+#define UCD9000_GPIO_CONFIG_OUT_ENABLE BIT(1) -+#define UCD9000_GPIO_CONFIG_OUT_VALUE BIT(2) -+#define UCD9000_GPIO_CONFIG_STATUS BIT(3) -+#define UCD9000_GPIO_INPUT 0 -+#define UCD9000_GPIO_OUTPUT 1 -+ -+#define UCD9000_MON_TYPE(x) (((x) >> 5) & 0x07) -+#define UCD9000_MON_PAGE(x) ((x) & 0x1f) -+ -+#define UCD9000_MON_VOLTAGE 1 -+#define UCD9000_MON_TEMPERATURE 2 -+#define UCD9000_MON_CURRENT 3 -+#define UCD9000_MON_VOLTAGE_HW 4 -+ -+#define UCD9000_NUM_FAN 4 -+ -+#define UCD9000_GPIO_NAME_LEN 16 -+#define UCD9090_NUM_GPIOS 23 -+#define UCD901XX_NUM_GPIOS 26 -+#define UCD90320_NUM_GPIOS 84 -+#define UCD90910_NUM_GPIOS 26 -+ -+#define UCD9000_DEBUGFS_NAME_LEN 24 -+#define UCD9000_GPI_COUNT 8 -+#define UCD90320_GPI_COUNT 32 -+ -+#define UCD9000_RETRY_SLEEP_TIME (10000) /* 10ms */ -+#define UCD9000_RETRY_TIME (3) -+#define WB_DEV_NAME_MAX_LEN (64) -+ -+static int g_wb_ucd9000_debug = 0; -+static int g_wb_ucd9000_error = 0; -+ -+module_param(g_wb_ucd9000_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_ucd9000_error, int, S_IRUGO | S_IWUSR); -+ -+#define WB_UDC9000_VERBOSE(fmt, args...) do { \ -+ if (g_wb_ucd9000_debug) { \ -+ printk(KERN_INFO "[WB_UCD9000][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_UDC9000_ERROR(fmt, args...) do { \ -+ if (g_wb_ucd9000_error) { \ -+ printk(KERN_ERR "[WB_UCD9000][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+struct ucd9000_data { -+ u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX]; -+ struct pmbus_driver_info info; -+#ifdef CONFIG_GPIOLIB -+ struct gpio_chip gpio; -+#endif -+ struct dentry *debugfs; -+}; -+#define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info) -+ -+struct ucd9000_debugfs_entry { -+ struct i2c_client *client; -+ u8 index; -+}; -+ -+static int wb_i2c_smbus_read_block_data(const struct i2c_client *client, u8 command, u8 *values) -+{ -+ int rv, i; -+ -+ for(i = 0; i < UCD9000_RETRY_TIME; i++) { -+ rv = i2c_smbus_read_block_data(client, command, values); -+ if(rv >= 0){ -+ return rv; -+ } -+ usleep_range(UCD9000_RETRY_SLEEP_TIME, UCD9000_RETRY_SLEEP_TIME + 1); -+ } -+ WB_UDC9000_ERROR("read_block_data failed. nr:%d, addr:0x%x, reg:0x%x, rv:%d.", -+ client->adapter->nr, client->addr, command, rv); -+ return rv; -+} -+ -+static int ucd9000_get_fan_config(struct i2c_client *client, int fan) -+{ -+ int fan_config = 0; -+ struct ucd9000_data *data -+ = to_ucd9000_data(wb_pmbus_get_driver_info(client)); -+ -+ if (data->fan_data[fan][3] & 1) -+ fan_config |= PB_FAN_2_INSTALLED; /* Use lower bit position */ -+ -+ /* Pulses/revolution */ -+ fan_config |= (data->fan_data[fan][3] & 0x06) >> 1; -+ -+ return fan_config; -+} -+ -+static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg) -+{ -+ int ret = 0; -+ int fan_config; -+ -+ switch (reg) { -+ case PMBUS_FAN_CONFIG_12: -+ if (page > 0) -+ return -ENXIO; -+ -+ ret = ucd9000_get_fan_config(client, 0); -+ if (ret < 0) -+ return ret; -+ fan_config = ret << 4; -+ ret = ucd9000_get_fan_config(client, 1); -+ if (ret < 0) -+ return ret; -+ fan_config |= ret; -+ ret = fan_config; -+ break; -+ case PMBUS_FAN_CONFIG_34: -+ if (page > 0) -+ return -ENXIO; -+ -+ ret = ucd9000_get_fan_config(client, 2); -+ if (ret < 0) -+ return ret; -+ fan_config = ret << 4; -+ ret = ucd9000_get_fan_config(client, 3); -+ if (ret < 0) -+ return ret; -+ fan_config |= ret; -+ ret = fan_config; -+ break; -+ default: -+ ret = -ENODATA; -+ break; -+ } -+ return ret; -+} -+ -+static const struct i2c_device_id ucd9000_id[] = { -+ {"wb_ucd9000", ucd9000}, -+ {"wb_ucd90120", ucd90120}, -+ {"wb_ucd90124", ucd90124}, -+ {"wb_ucd90160", ucd90160}, -+ {"wb_ucd90320", ucd90320}, -+ {"wb_ucd9090", ucd9090}, -+ {"wb_ucd90910", ucd90910}, -+ {} -+}; -+MODULE_DEVICE_TABLE(i2c, ucd9000_id); -+ -+static const struct of_device_id __maybe_unused ucd9000_of_match[] = { -+ { -+ .compatible = "ti,wb_ucd9000", -+ .data = (void *)ucd9000 -+ }, -+ { -+ .compatible = "ti,wb_ucd90120", -+ .data = (void *)ucd90120 -+ }, -+ { -+ .compatible = "ti,wb_ucd90124", -+ .data = (void *)ucd90124 -+ }, -+ { -+ .compatible = "ti,wb_ucd90160", -+ .data = (void *)ucd90160 -+ }, -+ { -+ .compatible = "ti,wb_ucd90320", -+ .data = (void *)ucd90320 -+ }, -+ { -+ .compatible = "ti,wb_ucd9090", -+ .data = (void *)ucd9090 -+ }, -+ { -+ .compatible = "ti,wb_ucd90910", -+ .data = (void *)ucd90910 -+ }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, ucd9000_of_match); -+ -+#ifdef CONFIG_GPIOLIB -+static int ucd9000_gpio_read_config(struct i2c_client *client, -+ unsigned int offset) -+{ -+ int ret; -+ -+ /* No page set required */ -+ ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_SELECT, offset); -+ if (ret < 0) -+ return ret; -+ -+ return i2c_smbus_read_byte_data(client, UCD9000_GPIO_CONFIG); -+} -+ -+static int ucd9000_gpio_get(struct gpio_chip *gc, unsigned int offset) -+{ -+ struct i2c_client *client = gpiochip_get_data(gc); -+ int ret; -+ -+ ret = ucd9000_gpio_read_config(client, offset); -+ if (ret < 0) -+ return ret; -+ -+ return !!(ret & UCD9000_GPIO_CONFIG_STATUS); -+} -+ -+static void ucd9000_gpio_set(struct gpio_chip *gc, unsigned int offset, -+ int value) -+{ -+ struct i2c_client *client = gpiochip_get_data(gc); -+ int ret; -+ -+ ret = ucd9000_gpio_read_config(client, offset); -+ if (ret < 0) { -+ dev_dbg(&client->dev, "failed to read GPIO %d config: %d\n", -+ offset, ret); -+ return; -+ } -+ -+ if (value) { -+ if (ret & UCD9000_GPIO_CONFIG_STATUS) -+ return; -+ -+ ret |= UCD9000_GPIO_CONFIG_STATUS; -+ } else { -+ if (!(ret & UCD9000_GPIO_CONFIG_STATUS)) -+ return; -+ -+ ret &= ~UCD9000_GPIO_CONFIG_STATUS; -+ } -+ -+ ret |= UCD9000_GPIO_CONFIG_ENABLE; -+ -+ /* Page set not required */ -+ ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, ret); -+ if (ret < 0) { -+ dev_dbg(&client->dev, "Failed to write GPIO %d config: %d\n", -+ offset, ret); -+ return; -+ } -+ -+ ret &= ~UCD9000_GPIO_CONFIG_ENABLE; -+ -+ ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, ret); -+ if (ret < 0) -+ dev_dbg(&client->dev, "Failed to write GPIO %d config: %d\n", -+ offset, ret); -+} -+ -+static int ucd9000_gpio_get_direction(struct gpio_chip *gc, -+ unsigned int offset) -+{ -+ struct i2c_client *client = gpiochip_get_data(gc); -+ int ret; -+ -+ ret = ucd9000_gpio_read_config(client, offset); -+ if (ret < 0) -+ return ret; -+ -+ return !(ret & UCD9000_GPIO_CONFIG_OUT_ENABLE); -+} -+ -+static int ucd9000_gpio_set_direction(struct gpio_chip *gc, -+ unsigned int offset, bool direction_out, -+ int requested_out) -+{ -+ struct i2c_client *client = gpiochip_get_data(gc); -+ int ret, config, out_val; -+ -+ ret = ucd9000_gpio_read_config(client, offset); -+ if (ret < 0) -+ return ret; -+ -+ if (direction_out) { -+ out_val = requested_out ? UCD9000_GPIO_CONFIG_OUT_VALUE : 0; -+ -+ if (ret & UCD9000_GPIO_CONFIG_OUT_ENABLE) { -+ if ((ret & UCD9000_GPIO_CONFIG_OUT_VALUE) == out_val) -+ return 0; -+ } else { -+ ret |= UCD9000_GPIO_CONFIG_OUT_ENABLE; -+ } -+ -+ if (out_val) -+ ret |= UCD9000_GPIO_CONFIG_OUT_VALUE; -+ else -+ ret &= ~UCD9000_GPIO_CONFIG_OUT_VALUE; -+ -+ } else { -+ if (!(ret & UCD9000_GPIO_CONFIG_OUT_ENABLE)) -+ return 0; -+ -+ ret &= ~UCD9000_GPIO_CONFIG_OUT_ENABLE; -+ } -+ -+ ret |= UCD9000_GPIO_CONFIG_ENABLE; -+ config = ret; -+ -+ /* Page set not required */ -+ ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, config); -+ if (ret < 0) -+ return ret; -+ -+ config &= ~UCD9000_GPIO_CONFIG_ENABLE; -+ -+ return i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, config); -+} -+ -+static int ucd9000_gpio_direction_input(struct gpio_chip *gc, -+ unsigned int offset) -+{ -+ return ucd9000_gpio_set_direction(gc, offset, UCD9000_GPIO_INPUT, 0); -+} -+ -+static int ucd9000_gpio_direction_output(struct gpio_chip *gc, -+ unsigned int offset, int val) -+{ -+ return ucd9000_gpio_set_direction(gc, offset, UCD9000_GPIO_OUTPUT, -+ val); -+} -+ -+static void ucd9000_probe_gpio(struct i2c_client *client, -+ const struct i2c_device_id *mid, -+ struct ucd9000_data *data) -+{ -+ int rc; -+ -+ switch (mid->driver_data) { -+ case ucd9090: -+ data->gpio.ngpio = UCD9090_NUM_GPIOS; -+ break; -+ case ucd90120: -+ case ucd90124: -+ case ucd90160: -+ data->gpio.ngpio = UCD901XX_NUM_GPIOS; -+ break; -+ case ucd90320: -+ data->gpio.ngpio = UCD90320_NUM_GPIOS; -+ break; -+ case ucd90910: -+ data->gpio.ngpio = UCD90910_NUM_GPIOS; -+ break; -+ default: -+ return; /* GPIO support is optional. */ -+ } -+ -+ /* -+ * Pinmux support has not been added to the new gpio_chip. -+ * This support should be added when possible given the mux -+ * behavior of these IO devices. -+ */ -+ data->gpio.label = client->name; -+ data->gpio.get_direction = ucd9000_gpio_get_direction; -+ data->gpio.direction_input = ucd9000_gpio_direction_input; -+ data->gpio.direction_output = ucd9000_gpio_direction_output; -+ data->gpio.get = ucd9000_gpio_get; -+ data->gpio.set = ucd9000_gpio_set; -+ data->gpio.can_sleep = true; -+ data->gpio.base = -1; -+ data->gpio.parent = &client->dev; -+ -+ rc = devm_gpiochip_add_data(&client->dev, &data->gpio, client); -+ if (rc) -+ dev_warn(&client->dev, "Could not add gpiochip: %d\n", rc); -+} -+#else -+static void ucd9000_probe_gpio(struct i2c_client *client, -+ const struct i2c_device_id *mid, -+ struct ucd9000_data *data) -+{ -+} -+#endif /* CONFIG_GPIOLIB */ -+ -+#ifdef CONFIG_DEBUG_FS -+static int ucd9000_get_mfr_status(struct i2c_client *client, u8 *buffer) -+{ -+ int ret = wb_pmbus_set_page(client, 0, 0xff); -+ -+ if (ret < 0) -+ return ret; -+ -+ return wb_i2c_smbus_read_block_data(client, UCD9000_MFR_STATUS, buffer); -+} -+ -+static int ucd9000_debugfs_show_mfr_status_bit(void *data, u64 *val) -+{ -+ struct ucd9000_debugfs_entry *entry = data; -+ struct i2c_client *client = entry->client; -+ u8 buffer[I2C_SMBUS_BLOCK_MAX]; -+ int ret, i; -+ -+ ret = ucd9000_get_mfr_status(client, buffer); -+ if (ret < 0) -+ return ret; -+ -+ /* -+ * GPI fault bits are in sets of 8, two bytes from end of response. -+ */ -+ i = ret - 3 - entry->index / 8; -+ if (i >= 0) -+ *val = !!(buffer[i] & BIT(entry->index % 8)); -+ -+ return 0; -+} -+DEFINE_DEBUGFS_ATTRIBUTE(ucd9000_debugfs_mfr_status_bit, -+ ucd9000_debugfs_show_mfr_status_bit, NULL, "%1lld\n"); -+ -+static ssize_t ucd9000_debugfs_read_mfr_status(struct file *file, -+ char __user *buf, size_t count, -+ loff_t *ppos) -+{ -+ struct i2c_client *client = file->private_data; -+ u8 buffer[I2C_SMBUS_BLOCK_MAX]; -+ char str[(I2C_SMBUS_BLOCK_MAX * 2) + 2]; -+ char *res; -+ int rc; -+ -+ rc = ucd9000_get_mfr_status(client, buffer); -+ if (rc < 0) -+ return rc; -+ -+ res = bin2hex(str, buffer, min(rc, I2C_SMBUS_BLOCK_MAX)); -+ *res++ = '\n'; -+ *res = 0; -+ -+ return simple_read_from_buffer(buf, count, ppos, str, res - str); -+} -+ -+static const struct file_operations ucd9000_debugfs_show_mfr_status_fops = { -+ .llseek = noop_llseek, -+ .read = ucd9000_debugfs_read_mfr_status, -+ .open = simple_open, -+}; -+ -+static int ucd9000_init_debugfs(struct i2c_client *client, -+ const struct i2c_device_id *mid, -+ struct ucd9000_data *data) -+{ -+ struct dentry *debugfs; -+ struct ucd9000_debugfs_entry *entries; -+ int i, gpi_count; -+ char name[UCD9000_DEBUGFS_NAME_LEN]; -+ -+ debugfs = wb_pmbus_get_debugfs_dir(client); -+ if (!debugfs) -+ return -ENOENT; -+ -+ data->debugfs = debugfs_create_dir(client->name, debugfs); -+ if (!data->debugfs) -+ return -ENOENT; -+ -+ /* -+ * Of the chips this driver supports, only the UCD9090, UCD90160, -+ * UCD90320, and UCD90910 report GPI faults in their MFR_STATUS -+ * register, so only create the GPI fault debugfs attributes for those -+ * chips. -+ */ -+ if (mid->driver_data == ucd9090 || mid->driver_data == ucd90160 || -+ mid->driver_data == ucd90320 || mid->driver_data == ucd90910) { -+ gpi_count = mid->driver_data == ucd90320 ? UCD90320_GPI_COUNT -+ : UCD9000_GPI_COUNT; -+ entries = devm_kcalloc(&client->dev, -+ gpi_count, sizeof(*entries), -+ GFP_KERNEL); -+ if (!entries) -+ return -ENOMEM; -+ -+ for (i = 0; i < gpi_count; i++) { -+ entries[i].client = client; -+ entries[i].index = i; -+ scnprintf(name, UCD9000_DEBUGFS_NAME_LEN, -+ "gpi%d_alarm", i + 1); -+ debugfs_create_file(name, 0444, data->debugfs, -+ &entries[i], -+ &ucd9000_debugfs_mfr_status_bit); -+ } -+ } -+ -+ scnprintf(name, UCD9000_DEBUGFS_NAME_LEN, "mfr_status"); -+ debugfs_create_file(name, 0444, data->debugfs, client, -+ &ucd9000_debugfs_show_mfr_status_fops); -+ -+ return 0; -+} -+#else -+static int ucd9000_init_debugfs(struct i2c_client *client, -+ const struct i2c_device_id *mid, -+ struct ucd9000_data *data) -+{ -+ return 0; -+} -+#endif /* CONFIG_DEBUG_FS */ -+ -+static int ucd9000_probe(struct i2c_client *client) -+{ -+ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; -+ char wb_device_name[WB_DEV_NAME_MAX_LEN]; -+ struct ucd9000_data *data; -+ struct pmbus_driver_info *info; -+ const struct i2c_device_id *mid; -+ enum chips chip; -+ int i, ret; -+ -+ if (!i2c_check_functionality(client->adapter, -+ I2C_FUNC_SMBUS_BYTE_DATA | -+ I2C_FUNC_SMBUS_BLOCK_DATA)) -+ return -ENODEV; -+ -+ ret = wb_i2c_smbus_read_block_data(client, UCD9000_DEVICE_ID, -+ block_buffer); -+ if (ret < 0) { -+ dev_err(&client->dev, "Failed to read device ID\n"); -+ return ret; -+ } -+ block_buffer[ret] = '\0'; -+ dev_info(&client->dev, "Device ID %s\n", block_buffer); -+ -+ mem_clear(wb_device_name, sizeof(wb_device_name)); -+ snprintf(wb_device_name, sizeof(wb_device_name), "wb_%s", block_buffer); -+ -+ for (mid = ucd9000_id; mid->name[0]; mid++) { -+ if (!strncasecmp(mid->name, wb_device_name, strlen(mid->name))) -+ break; -+ } -+ if (!mid->name[0]) { -+ dev_err(&client->dev, "Unsupported device\n"); -+ return -ENODEV; -+ } -+ -+ if (client->dev.of_node) -+ chip = (enum chips)of_device_get_match_data(&client->dev); -+ else -+ chip = mid->driver_data; -+ -+ if (chip != ucd9000 && strcmp(client->name, mid->name) != 0) -+ dev_notice(&client->dev, -+ "Device mismatch: Configured %s, detected %s\n", -+ client->name, mid->name); -+ -+ data = devm_kzalloc(&client->dev, sizeof(struct ucd9000_data), -+ GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ info = &data->info; -+ -+ ret = i2c_smbus_read_byte_data(client, UCD9000_NUM_PAGES); -+ if (ret < 0) { -+ dev_err(&client->dev, -+ "Failed to read number of active pages\n"); -+ return ret; -+ } -+ info->pages = ret; -+ if (!info->pages) { -+ dev_err(&client->dev, "No pages configured\n"); -+ return -ENODEV; -+ } -+ -+ /* The internal temperature sensor is always active */ -+ /* ucd90160 have no temperature */ -+ /* info->func[0] = PMBUS_HAVE_TEMP; */ -+ -+ /* Everything else is configurable */ -+ ret = wb_i2c_smbus_read_block_data(client, UCD9000_MONITOR_CONFIG, -+ block_buffer); -+ if (ret <= 0) { -+ dev_err(&client->dev, "Failed to read configuration data\n"); -+ return -ENODEV; -+ } -+ for (i = 0; i < ret; i++) { -+ int page = UCD9000_MON_PAGE(block_buffer[i]); -+ -+ if (page >= info->pages) -+ continue; -+ -+ switch (UCD9000_MON_TYPE(block_buffer[i])) { -+ case UCD9000_MON_VOLTAGE: -+ case UCD9000_MON_VOLTAGE_HW: -+ info->func[page] |= PMBUS_HAVE_VOUT -+ | PMBUS_HAVE_STATUS_VOUT; -+ break; -+ case UCD9000_MON_TEMPERATURE: -+ info->func[page] |= PMBUS_HAVE_TEMP2 -+ | PMBUS_HAVE_STATUS_TEMP; -+ break; -+ case UCD9000_MON_CURRENT: -+ info->func[page] |= PMBUS_HAVE_IOUT -+ | PMBUS_HAVE_STATUS_IOUT; -+ break; -+ default: -+ break; -+ } -+ } -+ -+ /* Fan configuration */ -+ if (mid->driver_data == ucd90124) { -+ for (i = 0; i < UCD9000_NUM_FAN; i++) { -+ i2c_smbus_write_byte_data(client, -+ UCD9000_FAN_CONFIG_INDEX, i); -+ ret = wb_i2c_smbus_read_block_data(client, -+ UCD9000_FAN_CONFIG, -+ data->fan_data[i]); -+ if (ret < 0) -+ return ret; -+ } -+ i2c_smbus_write_byte_data(client, UCD9000_FAN_CONFIG_INDEX, 0); -+ -+ info->read_byte_data = ucd9000_read_byte_data; -+ info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 -+ | PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34; -+ } -+ -+ ucd9000_probe_gpio(client, mid, data); -+ -+ ret = wb_pmbus_do_probe(client, info); -+ if (ret) -+ return ret; -+ -+ ret = ucd9000_init_debugfs(client, mid, data); -+ if (ret) -+ dev_warn(&client->dev, "Failed to register debugfs: %d\n", -+ ret); -+ -+ return 0; -+} -+ -+/* This is the driver that will be inserted */ -+static struct i2c_driver ucd9000_driver = { -+ .driver = { -+ .name = "wb_ucd9000", -+ .of_match_table = of_match_ptr(ucd9000_of_match), -+ }, -+ .probe_new = ucd9000_probe, -+ .remove = wb_pmbus_do_remove, -+ .id_table = ucd9000_id, -+}; -+ -+module_i2c_driver(ucd9000_driver); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe12284.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe12284.c -new file mode 100644 -index 000000000..404c349f5 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe12284.c -@@ -0,0 +1,495 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Hardware monitoring driver for Infineon Multi-phase Digital VR Controllers -+ * -+ * Copyright (c) 2020 Mellanox Technologies. All rights reserved. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "wb_pmbus.h" -+ -+#define XDPE122_PROT_VR12_5MV (0x01) /* VR12.0 mode, 5-mV DAC */ -+#define XDPE122_PROT_VR12_5_10MV (0x02) /* VR12.5 mode, 10-mV DAC */ -+#define XDPE122_PROT_IMVP9_10MV (0x03) /* IMVP9 mode, 10-mV DAC */ -+#define XDPE122_AMD_625MV (0x10) /* AMD mode 6.25mV */ -+#define XDPE122_PAGE_NUM (2) -+#define XDPE122_WRITE_PROTECT_CLOSE (0x00) -+#define XDPE122_WRITE_PROTECT_OPEN (0x40) -+ -+static int g_wb_xdpe122_debug = 0; -+static int g_wb_xdpe122_error = 0; -+ -+module_param(g_wb_xdpe122_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_xdpe122_error, int, S_IRUGO | S_IWUSR); -+ -+#define WB_XDPE122_VERBOSE(fmt, args...) do { \ -+ if (g_wb_xdpe122_debug) { \ -+ printk(KERN_INFO "[WB_XDPE122][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_XDPE122_ERROR(fmt, args...) do { \ -+ if (g_wb_xdpe122_error) { \ -+ printk(KERN_ERR "[WB_XDPE122][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static int xdpe122_data2reg_vid(struct pmbus_data *data, int page, long val) -+{ -+ int vrm_version; -+ -+ vrm_version = data->info->vrm_version[page]; -+ WB_XDPE122_VERBOSE("page%d, vrm_version: %d, data_val: %ld\n", -+ page, vrm_version, val); -+ /* Convert data to VID register. */ -+ switch (vrm_version) { -+ case vr13: -+ if (val >= 500) { -+ return 1 + DIV_ROUND_CLOSEST(val - 500, 10); -+ } -+ return 0; -+ case vr12: -+ if (val >= 250) { -+ return 1 + DIV_ROUND_CLOSEST(val - 250, 5); -+ } -+ return 0; -+ case imvp9: -+ if (val >= 200) { -+ return 1 + DIV_ROUND_CLOSEST(val - 200, 10); -+ } -+ return 0; -+ case amd625mv: -+ if (val >= 200 && val <= 1550) { -+ return DIV_ROUND_CLOSEST((1550 - val) * 100, 625); -+ } -+ return 0; -+ default: -+ WB_XDPE122_ERROR("Unsupport vrm_version, page%d, vrm_version: %d\n", -+ page, vrm_version); -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+ -+/* -+ * Convert VID sensor values to milli- or micro-units -+ * depending on sensor type. -+ */ -+static s64 xdpe122_reg2data_vid(struct pmbus_data *data, int page, long val) -+{ -+ -+ long rv; -+ int vrm_version; -+ -+ rv = 0; -+ vrm_version = data->info->vrm_version[page]; -+ switch (vrm_version) { -+ case vr11: -+ if (val >= 0x02 && val <= 0xb2) -+ rv = DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); -+ break; -+ case vr12: -+ if (val >= 0x01) -+ rv = 250 + (val - 1) * 5; -+ break; -+ case vr13: -+ if (val >= 0x01) -+ rv = 500 + (val - 1) * 10; -+ break; -+ case imvp9: -+ if (val >= 0x01) -+ rv = 200 + (val - 1) * 10; -+ break; -+ case amd625mv: -+ if (val >= 0x0 && val <= 0xd8) -+ rv = DIV_ROUND_CLOSEST(155000 - val * 625, 100); -+ break; -+ } -+ WB_XDPE122_VERBOSE("page%d, vrm_version: %d, reg_val: 0x%lx, data_val: %ld\n", -+ page, vrm_version, val, rv); -+ return rv; -+} -+ -+static ssize_t xdpe122_avs_vout_show(struct device *dev, struct device_attribute *devattr, -+ char *buf) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ int vout_cmd, vout; -+ -+ mutex_lock(&data->update_lock); -+ vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); -+ if (vout_cmd < 0) { -+ WB_XDPE122_ERROR("%d-%04x: read page%d, vout command reg: 0x%x failed, ret: %d\n", -+ client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd); -+ mutex_unlock(&data->update_lock); -+ return vout_cmd; -+ } -+ -+ vout = xdpe122_reg2data_vid(data, attr->index, vout_cmd); -+ vout = vout * 1000; -+ WB_XDPE122_VERBOSE("%d-%04x: page%d, vout command reg_val: 0x%x, vout: %d uV\n", -+ client->adapter->nr, client->addr, attr->index, vout_cmd, vout); -+ -+ mutex_unlock(&data->update_lock); -+ return snprintf(buf, PAGE_SIZE, "%d\n", vout); -+} -+ -+static ssize_t xdpe122_avs_vout_store(struct device *dev, struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ int vout, vout_max, vout_min, vout_mv; -+ int ret, vout_cmd, vout_cmd_set; -+ -+ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { -+ WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, -+ attr->index); -+ return -EINVAL; -+ } -+ -+ ret = kstrtoint(buf, 0, &vout); -+ if (ret) { -+ WB_XDPE122_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); -+ return -EINVAL; -+ } -+ -+ vout_max = data->vout_max[attr->index]; -+ vout_min = data->vout_min[attr->index]; -+ if ((vout > vout_max) || (vout < vout_min)) { -+ WB_XDPE122_ERROR("%d-%04x: vout value: %d, out of range [%d, %d] \n", client->adapter->nr, -+ client->addr, vout, vout_min, vout_max); -+ return -EINVAL; -+ } -+ -+ /* calc VOUT_COMMAND set value Unit must be mV*/ -+ vout_mv = vout / 1000; -+ vout_cmd_set = xdpe122_data2reg_vid(data, attr->index, vout_mv); -+ if ((vout_cmd_set < 0) || (vout_cmd_set > 0xffff)) { -+ WB_XDPE122_ERROR("%d-%04x: invalid value, vout %d uV, vout_cmd_set: %d\n", -+ client->adapter->nr, client->addr, vout, vout_cmd_set); -+ return -EINVAL; -+ } -+ -+ mutex_lock(&data->update_lock); -+ -+ /* close write protect */ -+ ret = wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, XDPE122_WRITE_PROTECT_CLOSE); -+ if (ret < 0) { -+ WB_XDPE122_ERROR("%d-%04x: close page%d write protect failed, ret: %d\n", client->adapter->nr, -+ client->addr, attr->index, ret); -+ mutex_unlock(&data->update_lock); -+ return ret; -+ } -+ -+ /* set VOUT_COMMAND */ -+ ret = wb_pmbus_write_word_data(client, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set); -+ if (ret < 0) { -+ WB_XDPE122_ERROR("%d-%04x: set page%d vout cmd reg: 0x%x, value: 0x%x failed, ret: %d\n", -+ client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set, ret); -+ goto error; -+ } -+ -+ /* read back VOUT_COMMAND */ -+ vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); -+ if (vout_cmd < 0) { -+ ret = vout_cmd; -+ WB_XDPE122_ERROR("%d-%04x: read page%d vout command reg: 0x%x failed, ret: %d\n", -+ client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, ret); -+ goto error; -+ } -+ -+ /* compare vout_cmd and vout_cmd_set */ -+ if (vout_cmd != vout_cmd_set) { -+ ret = -EIO; -+ WB_XDPE122_ERROR("%d-%04x: vout cmd value check error, vout cmd read: 0x%x, vout cmd set: 0x%x\n", -+ client->adapter->nr, client->addr, vout_cmd, vout_cmd_set); -+ goto error; -+ } -+ -+ /* open write protect */ -+ wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, XDPE122_WRITE_PROTECT_OPEN); -+ mutex_unlock(&data->update_lock); -+ WB_XDPE122_VERBOSE("%d-%04x: set page%d vout cmd success, vout %d uV, vout_cmd_set: 0x%x\n", -+ client->adapter->nr, client->addr, attr->index, vout, vout_cmd_set); -+ return count; -+error: -+ wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, XDPE122_WRITE_PROTECT_OPEN); -+ mutex_unlock(&data->update_lock); -+ return ret; -+} -+ -+static ssize_t xdpe122_avs_vout_max_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, size_t count) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ int ret, vout_threshold; -+ -+ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { -+ WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, -+ attr->index); -+ return -EINVAL; -+ } -+ -+ ret = kstrtoint(buf, 0, &vout_threshold); -+ if (ret) { -+ WB_XDPE122_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); -+ return -EINVAL; -+ } -+ -+ WB_XDPE122_VERBOSE("%d-%04x: vout%d max threshold: %d", client->adapter->nr, client->addr, -+ attr->index, vout_threshold); -+ -+ data->vout_max[attr->index] = vout_threshold; -+ return count; -+} -+ -+static ssize_t xdpe122_avs_vout_max_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ -+ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { -+ WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, -+ attr->index); -+ return -EINVAL; -+ } -+ -+ return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_max[attr->index]); -+} -+ -+static ssize_t xdpe122_avs_vout_min_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, size_t count) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ int ret, vout_threshold; -+ -+ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { -+ WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, -+ attr->index); -+ return -EINVAL; -+ } -+ -+ ret = kstrtoint(buf, 0, &vout_threshold); -+ if (ret) { -+ WB_XDPE122_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); -+ return -EINVAL; -+ } -+ -+ WB_XDPE122_VERBOSE("%d-%04x: vout%d min threshold: %d", client->adapter->nr, client->addr, -+ attr->index, vout_threshold); -+ -+ data->vout_min[attr->index] = vout_threshold; -+ return count; -+} -+ -+static ssize_t xdpe122_avs_vout_min_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct i2c_client *client = to_i2c_client(dev->parent); -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct pmbus_data *data = i2c_get_clientdata(client); -+ -+ if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { -+ WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, -+ attr->index); -+ return -EINVAL; -+ } -+ -+ return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_min[attr->index]); -+} -+ -+static SENSOR_DEVICE_ATTR_RW(avs0_vout, xdpe122_avs_vout, 0); -+static SENSOR_DEVICE_ATTR_RW(avs1_vout, xdpe122_avs_vout, 1); -+static SENSOR_DEVICE_ATTR_RW(avs0_vout_max, xdpe122_avs_vout_max, 0); -+static SENSOR_DEVICE_ATTR_RW(avs0_vout_min, xdpe122_avs_vout_min, 0); -+static SENSOR_DEVICE_ATTR_RW(avs1_vout_max, xdpe122_avs_vout_max, 1); -+static SENSOR_DEVICE_ATTR_RW(avs1_vout_min, xdpe122_avs_vout_min, 1); -+ -+static struct attribute *avs_ctrl_attrs[] = { -+ &sensor_dev_attr_avs0_vout.dev_attr.attr, -+ &sensor_dev_attr_avs1_vout.dev_attr.attr, -+ &sensor_dev_attr_avs0_vout_max.dev_attr.attr, -+ &sensor_dev_attr_avs0_vout_min.dev_attr.attr, -+ &sensor_dev_attr_avs1_vout_max.dev_attr.attr, -+ &sensor_dev_attr_avs1_vout_min.dev_attr.attr, -+ NULL, -+}; -+ -+static const struct attribute_group avs_ctrl_group = { -+ .attrs = avs_ctrl_attrs, -+}; -+ -+static const struct attribute_group *xdpe122_attribute_groups[] = { -+ &avs_ctrl_group, -+ NULL, -+}; -+ -+static int xdpe122_read_word_data(struct i2c_client *client, int page, -+ int phase, int reg) -+{ -+ const struct pmbus_driver_info *info = wb_pmbus_get_driver_info(client); -+ long val; -+ s16 exponent; -+ s32 mantissa; -+ int ret; -+ -+ switch (reg) { -+ case PMBUS_VOUT_OV_FAULT_LIMIT: -+ case PMBUS_VOUT_UV_FAULT_LIMIT: -+ ret = wb_pmbus_read_word_data(client, page, phase, reg); -+ if (ret < 0) -+ return ret; -+ -+ /* Convert register value to LINEAR11 data. */ -+ exponent = ((s16)ret) >> 11; -+ mantissa = ((s16)((ret & GENMASK(10, 0)) << 5)) >> 5; -+ val = mantissa * 1000L; -+ if (exponent >= 0) -+ val <<= exponent; -+ else -+ val >>= -exponent; -+ -+ /* Convert data to VID register. */ -+ switch (info->vrm_version[page]) { -+ case vr13: -+ if (val >= 500) -+ return 1 + DIV_ROUND_CLOSEST(val - 500, 10); -+ return 0; -+ case vr12: -+ if (val >= 250) -+ return 1 + DIV_ROUND_CLOSEST(val - 250, 5); -+ return 0; -+ case imvp9: -+ if (val >= 200) -+ return 1 + DIV_ROUND_CLOSEST(val - 200, 10); -+ return 0; -+ case amd625mv: -+ if (val >= 200 && val <= 1550) -+ return DIV_ROUND_CLOSEST((1550 - val) * 100, -+ 625); -+ return 0; -+ default: -+ return -EINVAL; -+ } -+ default: -+ return -ENODATA; -+ } -+ -+ return 0; -+} -+ -+static int xdpe122_identify(struct i2c_client *client, -+ struct pmbus_driver_info *info) -+{ -+ u8 vout_params; -+ int i, ret; -+ -+ for (i = 0; i < XDPE122_PAGE_NUM; i++) { -+ /* Read the register with VOUT scaling value.*/ -+ ret = wb_pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); -+ if (ret < 0) -+ return ret; -+ -+ vout_params = ret & GENMASK(4, 0); -+ -+ switch (vout_params) { -+ case XDPE122_PROT_VR12_5_10MV: -+ info->vrm_version[i] = vr13; -+ break; -+ case XDPE122_PROT_VR12_5MV: -+ info->vrm_version[i] = vr12; -+ break; -+ case XDPE122_PROT_IMVP9_10MV: -+ info->vrm_version[i] = imvp9; -+ break; -+ case XDPE122_AMD_625MV: -+ info->vrm_version[i] = amd625mv; -+ break; -+ default: -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ -+static struct pmbus_driver_info xdpe122_info = { -+ .pages = XDPE122_PAGE_NUM, -+ .format[PSC_VOLTAGE_IN] = linear, -+ .format[PSC_VOLTAGE_OUT] = vid, -+ .format[PSC_TEMPERATURE] = linear, -+ .format[PSC_CURRENT_IN] = linear, -+ .format[PSC_CURRENT_OUT] = linear, -+ .format[PSC_POWER] = linear, -+ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | -+ PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | -+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | -+ PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT, -+ .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | -+ PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | -+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | -+ PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT, -+ .groups = xdpe122_attribute_groups, -+ .identify = xdpe122_identify, -+ .read_word_data = xdpe122_read_word_data, -+}; -+ -+static int xdpe122_probe(struct i2c_client *client) -+{ -+ struct pmbus_driver_info *info; -+ -+ info = devm_kmemdup(&client->dev, &xdpe122_info, sizeof(*info), -+ GFP_KERNEL); -+ if (!info) -+ return -ENOMEM; -+ -+ return wb_pmbus_do_probe(client, info); -+} -+ -+static const struct i2c_device_id xdpe122_id[] = { -+ {"wb_xdpe12254", 0}, -+ {"wb_xdpe12284", 0}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(i2c, xdpe122_id); -+ -+static const struct of_device_id __maybe_unused xdpe122_of_match[] = { -+ {.compatible = "infineon,wb_xdpe12254"}, -+ {.compatible = "infineon,wb_xdpe12284"}, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, xdpe122_of_match); -+ -+static struct i2c_driver xdpe122_driver = { -+ .driver = { -+ .name = "wb_xdpe12284", -+ .of_match_table = of_match_ptr(xdpe122_of_match), -+ }, -+ .probe_new = xdpe122_probe, -+ .remove = wb_pmbus_do_remove, -+ .id_table = xdpe122_id, -+}; -+ -+module_i2c_driver(xdpe122_driver); -+ -+MODULE_AUTHOR("Vadim Pasternak "); -+MODULE_DESCRIPTION("PMBus driver for Infineon XDPE122 family"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe132g5c_pmbus.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe132g5c_pmbus.c -new file mode 100644 -index 000000000..c0c3d2bc7 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux-5.10/wb_xdpe132g5c_pmbus.c -@@ -0,0 +1,277 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "wb_pmbus.h" -+ -+typedef enum { -+ DBG_START, -+ DBG_VERBOSE, -+ DBG_KEY, -+ DBG_WARN, -+ DBG_ERROR, -+ DBG_END, -+} dbg_level_t; -+ -+static int debuglevel = 0; -+module_param(debuglevel, int, S_IRUGO); -+ -+#define DBG_DEBUG(fmt, arg...) do { \ -+ if ( debuglevel > DBG_START && debuglevel < DBG_ERROR) { \ -+ printk(KERN_INFO "[DEBUG]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ -+ } else if ( debuglevel >= DBG_ERROR ) { \ -+ printk(KERN_ERR "[DEBUG]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ -+ } else { } \ -+} while (0) -+ -+#define DBG_ERROR(fmt, arg...) do { \ -+ if ( debuglevel > DBG_START) { \ -+ printk(KERN_ERR "[ERROR]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ -+ } \ -+} while (0) -+ -+#define BUF_SIZE (256) -+#define XDPE132G5C_PAGE_NUM (2) -+#define XDPE132G5C_PROT_VR12_5MV (0x01) /* VR12.0 mode, 5-mV DAC */ -+#define XDPE132G5C_PROT_VR12_5_10MV (0x02) /* VR12.5 mode, 10-mV DAC */ -+#define XDPE132G5C_PROT_IMVP9_10MV (0x03) /* IMVP9 mode, 10-mV DAC */ -+#define XDPE132G5C_PROT_VR13_10MV (0x04) /* VR13.0 mode, 10-mV DAC */ -+#define XDPE132G5C_PROT_IMVP8_5MV (0x05) /* IMVP8 mode, 5-mV DAC */ -+#define XDPE132G5C_PROT_VR13_5MV (0x07) /* VR13.0 mode, 5-mV DAC */ -+#define RETRY_TIME (15) -+ -+static ssize_t set_xdpe132g5c_avs(struct device *dev, struct device_attribute *da, const char *buf, size_t count) -+{ -+ int ret; -+ unsigned long val; -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); -+ struct i2c_client *client = to_i2c_client(dev); -+ struct pmbus_data *data; -+ -+ data = i2c_get_clientdata(client); -+ ret = kstrtoul(buf, 0, &val); -+ if (ret){ -+ return ret; -+ } -+ mutex_lock(&data->update_lock); -+ /* set value */ -+ ret = wb_pmbus_write_word_data(client, attr->index, PMBUS_VOUT_COMMAND, (u16)val); -+ if (ret < 0) { -+ DBG_ERROR("set pmbus_vout_command fail\n"); -+ goto finish_set; -+ } -+finish_set: -+ wb_pmbus_clear_faults(client); -+ mutex_unlock(&data->update_lock); -+ return (ret < 0) ? ret : count; -+ -+} -+ -+static ssize_t show_xdpe132g5c_avs(struct device *dev, struct device_attribute *da, char *buf) -+{ -+ int val; -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); -+ struct i2c_client *client = to_i2c_client(dev); -+ struct pmbus_data *data; -+ -+ data = i2c_get_clientdata(client); -+ mutex_lock(&data->update_lock); -+ val = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); -+ if (val < 0) { -+ DBG_ERROR("fail val = %d\n", val); -+ goto finish_show; -+ } -+finish_show: -+ wb_pmbus_clear_faults(client); -+ mutex_unlock(&data->update_lock); -+ return snprintf(buf, BUF_SIZE, "0x%04x\n", val); -+} -+ -+static SENSOR_DEVICE_ATTR(avs0_vout_command, S_IRUGO | S_IWUSR, show_xdpe132g5c_avs, set_xdpe132g5c_avs, 0); -+static SENSOR_DEVICE_ATTR(avs1_vout_command, S_IRUGO | S_IWUSR, show_xdpe132g5c_avs, set_xdpe132g5c_avs, 1); -+ -+static struct attribute *xdpe132g5c_sysfs_attrs[] = { -+ &sensor_dev_attr_avs0_vout_command.dev_attr.attr, -+ &sensor_dev_attr_avs1_vout_command.dev_attr.attr, -+ NULL, -+}; -+ -+static const struct attribute_group xdpe132g5c_sysfs_attrs_group = { -+ .attrs = xdpe132g5c_sysfs_attrs, -+}; -+ -+static int xdpe132g5c_read_word_data(struct i2c_client *client, int page, int phase, int reg) -+{ -+ int rv; -+ int retry; -+ int value; -+ -+ rv = wb_pmbus_set_page(client, page, 0xff); -+ if (rv < 0) { -+ return rv; -+ } -+ -+ retry = 3; -+ while (retry--) { -+ value = i2c_smbus_read_word_data(client, reg); -+ if ((value == 0xffff) || (value < 0)) { -+ continue; -+ } -+ } -+ return value; -+} -+ -+static int xdpe132g5c_identify(struct i2c_client *client, struct pmbus_driver_info *info) -+{ -+ u8 vout_params; -+ int ret, i, retry; -+ -+ /* Read the register with VOUT scaling value.*/ -+ for (i = 0; i < XDPE132G5C_PAGE_NUM; i++) { -+ for (retry = 0; retry < RETRY_TIME; retry++) { -+ ret = wb_pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); -+ if (ret < 0 || ret == 0xff) { -+ msleep(5); -+ continue; -+ } else { -+ break; -+ } -+ } -+ if (ret < 0) { -+ return ret; -+ } -+ -+ switch (ret >> 5) { -+ case 0: /* linear mode */ -+ if (info->format[PSC_VOLTAGE_OUT] != linear) { -+ return -ENODEV; -+ } -+ break; -+ case 1: /* VID mode */ -+ if (info->format[PSC_VOLTAGE_OUT] != vid) { -+ return -ENODEV; -+ } -+ vout_params = ret & GENMASK(4, 0); -+ switch (vout_params) { -+ case XDPE132G5C_PROT_VR13_10MV: -+ case XDPE132G5C_PROT_VR12_5_10MV: -+ info->vrm_version[i] = vr13; -+ break; -+ case XDPE132G5C_PROT_VR13_5MV: -+ case XDPE132G5C_PROT_VR12_5MV: -+ case XDPE132G5C_PROT_IMVP8_5MV: -+ info->vrm_version[i] = vr12; -+ break; -+ case XDPE132G5C_PROT_IMVP9_10MV: -+ info->vrm_version[i] = imvp9; -+ break; -+ default: -+ return -EINVAL; -+ } -+ break; -+ case 2: /* direct mode */ -+ if (info->format[PSC_VOLTAGE_OUT] != direct) { -+ return -ENODEV; -+ } -+ break; -+ default: -+ return -ENODEV; -+ } -+ } -+ -+ return 0; -+} -+ -+static struct pmbus_driver_info xdpe132g5c_info = { -+ .pages = XDPE132G5C_PAGE_NUM, -+ .format[PSC_VOLTAGE_IN] = linear, -+ .format[PSC_VOLTAGE_OUT] = linear, -+ .format[PSC_TEMPERATURE] = linear, -+ .format[PSC_CURRENT_IN] = linear, -+ .format[PSC_CURRENT_OUT] = linear, -+ .format[PSC_POWER] = linear, -+ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN -+ | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP -+ | PMBUS_HAVE_STATUS_TEMP -+ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT -+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, -+ .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN -+ | PMBUS_HAVE_STATUS_INPUT -+ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT -+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, -+ .identify = xdpe132g5c_identify, -+ .read_word_data = xdpe132g5c_read_word_data, -+}; -+ -+static int xdpe132g5c_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ int status; -+ struct pmbus_driver_info *info; -+ -+ info = devm_kmemdup(&client->dev, &xdpe132g5c_info, sizeof(*info), GFP_KERNEL); -+ if (!info) { -+ return -ENOMEM; -+ } -+ -+ status = wb_pmbus_do_probe(client, &xdpe132g5c_info); -+ if (status != 0) { -+ DBG_ERROR("pmbus probe error %d\n", status); -+ return status; -+ } -+ -+ status = sysfs_create_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); -+ if (status != 0) { -+ DBG_ERROR("sysfs_create_group error %d\n", status); -+ return status; -+ } -+ -+ return status; -+} -+ -+static int xdpe132g5c_remove(struct i2c_client *client) -+{ -+ int ret; -+ -+ sysfs_remove_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); -+ ret = wb_pmbus_do_remove(client); -+ if (ret != 0){ -+ DBG_ERROR("fail remove xdpe132g5c %d\n", ret); -+ } -+ return ret; -+} -+ -+static const struct i2c_device_id xdpe132g5c_id[] = { -+ {"wb_xdpe132g5c_pmbus", 0}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(i2c, xdpe132g5c_id); -+ -+static const struct of_device_id __maybe_unused xdpe132g5c_of_match[] = { -+ {.compatible = "infineon,wb_xdpe132g5c_pmbus"}, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, xdpe132g5c_of_match); -+ -+static struct i2c_driver xdpe132g5c_driver = { -+ .driver = { -+ .name = "wb_xdpe132g5c_pmbus", -+ .of_match_table = of_match_ptr(xdpe132g5c_of_match), -+ }, -+ .probe = xdpe132g5c_probe, -+ .remove = xdpe132g5c_remove, -+ .id_table = xdpe132g5c_id, -+}; -+ -+module_i2c_driver(xdpe132g5c_driver); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("PMBus driver for Infineon XDPE132 family"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/Makefile -new file mode 100644 -index 000000000..4d5f8d535 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/Makefile -@@ -0,0 +1,23 @@ -+PWD = $(shell pwd) -+ -+EXTRA_CFLAGS:= -I$(M)/include -+EXTRA_CFLAGS+= -Wall -+ -+ifndef CONFIG_MDIO_BITBANG -+obj-m += mdio_bitbang.o -+endif -+ -+ifndef CONFIG_MDIO_GPIO -+obj-m += mdio_gpio.o -+endif -+ -+obj-m += wb_mdio_gpio_device.o -+ -+all: -+ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules -+ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi -+ cp -p $(PWD)/*.ko $(module_out_put_dir) -+clean: -+ rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/*.mod -+ rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order -+ rm -rf $(PWD)/.tmp_versions -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_bitbang.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_bitbang.c -new file mode 100644 -index 000000000..5136275c8 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_bitbang.c -@@ -0,0 +1,232 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Bitbanged MDIO support. -+ * -+ * Author: Scott Wood -+ * Copyright (c) 2007 Freescale Semiconductor -+ * -+ * Based on CPM2 MDIO code which is: -+ * -+ * Copyright (c) 2003 Intracom S.A. -+ * by Pantelis Antoniou -+ * -+ * 2005 (c) MontaVista Software, Inc. -+ * Vitaly Bordug -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#define MDIO_READ 2 -+#define MDIO_WRITE 1 -+ -+#define MDIO_C45 (1<<15) -+#define MDIO_C45_ADDR (MDIO_C45 | 0) -+#define MDIO_C45_READ (MDIO_C45 | 3) -+#define MDIO_C45_WRITE (MDIO_C45 | 1) -+ -+#define MDIO_SETUP_TIME 10 -+#define MDIO_HOLD_TIME 10 -+ -+/* Minimum MDC period is 400 ns, plus some margin for error. MDIO_DELAY -+ * is done twice per period. -+ */ -+#define MDIO_DELAY 250 -+ -+/* The PHY may take up to 300 ns to produce data, plus some margin -+ * for error. -+ */ -+#define MDIO_READ_DELAY 350 -+ -+/* MDIO must already be configured as output. */ -+static void mdiobb_send_bit(struct mdiobb_ctrl *ctrl, int val) -+{ -+ const struct mdiobb_ops *ops = ctrl->ops; -+ -+ ops->set_mdio_data(ctrl, val); -+ ndelay(MDIO_DELAY); -+ ops->set_mdc(ctrl, 1); -+ ndelay(MDIO_DELAY); -+ ops->set_mdc(ctrl, 0); -+} -+ -+/* MDIO must already be configured as input. */ -+static int mdiobb_get_bit(struct mdiobb_ctrl *ctrl) -+{ -+ const struct mdiobb_ops *ops = ctrl->ops; -+ -+ ndelay(MDIO_DELAY); -+ ops->set_mdc(ctrl, 1); -+ ndelay(MDIO_READ_DELAY); -+ ops->set_mdc(ctrl, 0); -+ -+ return ops->get_mdio_data(ctrl); -+} -+ -+/* MDIO must already be configured as output. */ -+static void mdiobb_send_num(struct mdiobb_ctrl *ctrl, u16 val, int bits) -+{ -+ int i; -+ -+ for (i = bits - 1; i >= 0; i--) -+ mdiobb_send_bit(ctrl, (val >> i) & 1); -+} -+ -+/* MDIO must already be configured as input. */ -+static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits) -+{ -+ int i; -+ u16 ret = 0; -+ -+ for (i = bits - 1; i >= 0; i--) { -+ ret <<= 1; -+ ret |= mdiobb_get_bit(ctrl); -+ } -+ -+ return ret; -+} -+ -+/* Utility to send the preamble, address, and -+ * register (common to read and write). -+ */ -+static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int op, u8 phy, u8 reg) -+{ -+ const struct mdiobb_ops *ops = ctrl->ops; -+ int i; -+ -+ ops->set_mdio_dir(ctrl, 1); -+ -+ /* -+ * Send a 32 bit preamble ('1's) with an extra '1' bit for good -+ * measure. The IEEE spec says this is a PHY optional -+ * requirement. The AMD 79C874 requires one after power up and -+ * one after a MII communications error. This means that we are -+ * doing more preambles than we need, but it is safer and will be -+ * much more robust. -+ */ -+ -+ for (i = 0; i < 32; i++) -+ mdiobb_send_bit(ctrl, 1); -+ -+ /* send the start bit (01) and the read opcode (10) or write (01). -+ Clause 45 operation uses 00 for the start and 11, 10 for -+ read/write */ -+ mdiobb_send_bit(ctrl, 0); -+ if (op & MDIO_C45) -+ mdiobb_send_bit(ctrl, 0); -+ else -+ mdiobb_send_bit(ctrl, 1); -+ mdiobb_send_bit(ctrl, (op >> 1) & 1); -+ mdiobb_send_bit(ctrl, (op >> 0) & 1); -+ -+ mdiobb_send_num(ctrl, phy, 5); -+ mdiobb_send_num(ctrl, reg, 5); -+} -+ -+/* In clause 45 mode all commands are prefixed by MDIO_ADDR to specify the -+ lower 16 bits of the 21 bit address. This transfer is done identically to a -+ MDIO_WRITE except for a different code. To enable clause 45 mode or -+ MII_ADDR_C45 into the address. Theoretically clause 45 and normal devices -+ can exist on the same bus. Normal devices should ignore the MDIO_ADDR -+ phase. */ -+static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr) -+{ -+ unsigned int dev_addr = (addr >> 16) & 0x1F; -+ unsigned int reg = addr & 0xFFFF; -+ mdiobb_cmd(ctrl, MDIO_C45_ADDR, phy, dev_addr); -+ -+ /* send the turnaround (10) */ -+ mdiobb_send_bit(ctrl, 1); -+ mdiobb_send_bit(ctrl, 0); -+ -+ mdiobb_send_num(ctrl, reg, 16); -+ -+ ctrl->ops->set_mdio_dir(ctrl, 0); -+ mdiobb_get_bit(ctrl); -+ -+ return dev_addr; -+} -+ -+static int mdiobb_read(struct mii_bus *bus, int phy, int reg) -+{ -+ struct mdiobb_ctrl *ctrl = bus->priv; -+ int ret, i; -+ -+ if (reg & MII_ADDR_C45) { -+ reg = mdiobb_cmd_addr(ctrl, phy, reg); -+ mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg); -+ } else -+ mdiobb_cmd(ctrl, MDIO_READ, phy, reg); -+ -+ ctrl->ops->set_mdio_dir(ctrl, 0); -+ -+ /* check the turnaround bit: the PHY should be driving it to zero, if this -+ * PHY is listed in phy_ignore_ta_mask as having broken TA, skip that -+ */ -+ if (mdiobb_get_bit(ctrl) != 0 && -+ !(bus->phy_ignore_ta_mask & (1 << phy))) { -+ /* PHY didn't drive TA low -- flush any bits it -+ * may be trying to send. -+ */ -+ for (i = 0; i < 32; i++) -+ mdiobb_get_bit(ctrl); -+ -+ return 0xffff; -+ } -+ -+ ret = mdiobb_get_num(ctrl, 16); -+ mdiobb_get_bit(ctrl); -+ return ret; -+} -+ -+static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val) -+{ -+ struct mdiobb_ctrl *ctrl = bus->priv; -+ -+ if (reg & MII_ADDR_C45) { -+ reg = mdiobb_cmd_addr(ctrl, phy, reg); -+ mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg); -+ } else -+ mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg); -+ -+ /* send the turnaround (10) */ -+ mdiobb_send_bit(ctrl, 1); -+ mdiobb_send_bit(ctrl, 0); -+ -+ mdiobb_send_num(ctrl, val, 16); -+ -+ ctrl->ops->set_mdio_dir(ctrl, 0); -+ mdiobb_get_bit(ctrl); -+ return 0; -+} -+ -+struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) -+{ -+ struct mii_bus *bus; -+ -+ bus = mdiobus_alloc(); -+ if (!bus) -+ return NULL; -+ -+ __module_get(ctrl->ops->owner); -+ -+ bus->read = mdiobb_read; -+ bus->write = mdiobb_write; -+ bus->priv = ctrl; -+ -+ return bus; -+} -+EXPORT_SYMBOL(alloc_mdio_bitbang); -+ -+void free_mdio_bitbang(struct mii_bus *bus) -+{ -+ struct mdiobb_ctrl *ctrl = bus->priv; -+ -+ module_put(ctrl->ops->owner); -+ mdiobus_free(bus); -+} -+EXPORT_SYMBOL(free_mdio_bitbang); -+ -+MODULE_LICENSE("GPL v2"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_gpio.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_gpio.c -new file mode 100644 -index 000000000..1b00235d7 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/mdio_gpio.c -@@ -0,0 +1,217 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * GPIO based MDIO bitbang driver. -+ * Supports OpenFirmware. -+ * -+ * Copyright (c) 2008 CSE Semaphore Belgium. -+ * by Laurent Pinchart -+ * -+ * Copyright (C) 2008, Paulius Zaleckas -+ * -+ * Based on earlier work by -+ * -+ * Copyright (c) 2003 Intracom S.A. -+ * by Pantelis Antoniou -+ * -+ * 2005 (c) MontaVista Software, Inc. -+ * Vitaly Bordug -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct mdio_gpio_info { -+ struct mdiobb_ctrl ctrl; -+ struct gpio_desc *mdc, *mdio, *mdo; -+}; -+ -+static int mdio_gpio_get_data(struct device *dev, -+ struct mdio_gpio_info *bitbang) -+{ -+ bitbang->mdc = devm_gpiod_get_index(dev, NULL, MDIO_GPIO_MDC, -+ GPIOD_OUT_LOW); -+ if (IS_ERR(bitbang->mdc)) -+ return PTR_ERR(bitbang->mdc); -+ -+ bitbang->mdio = devm_gpiod_get_index(dev, NULL, MDIO_GPIO_MDIO, -+ GPIOD_IN); -+ if (IS_ERR(bitbang->mdio)) -+ return PTR_ERR(bitbang->mdio); -+ -+ bitbang->mdo = devm_gpiod_get_index_optional(dev, NULL, MDIO_GPIO_MDO, -+ GPIOD_OUT_LOW); -+ return PTR_ERR_OR_ZERO(bitbang->mdo); -+} -+ -+static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) -+{ -+ struct mdio_gpio_info *bitbang = -+ container_of(ctrl, struct mdio_gpio_info, ctrl); -+ -+ if (bitbang->mdo) { -+ /* Separate output pin. Always set its value to high -+ * when changing direction. If direction is input, -+ * assume the pin serves as pull-up. If direction is -+ * output, the default value is high. -+ */ -+ gpiod_set_value_cansleep(bitbang->mdo, 1); -+ return; -+ } -+ -+ if (dir) -+ gpiod_direction_output(bitbang->mdio, 1); -+ else -+ gpiod_direction_input(bitbang->mdio); -+} -+ -+static int mdio_get(struct mdiobb_ctrl *ctrl) -+{ -+ struct mdio_gpio_info *bitbang = -+ container_of(ctrl, struct mdio_gpio_info, ctrl); -+ -+ return gpiod_get_value_cansleep(bitbang->mdio); -+} -+ -+static void mdio_set(struct mdiobb_ctrl *ctrl, int what) -+{ -+ struct mdio_gpio_info *bitbang = -+ container_of(ctrl, struct mdio_gpio_info, ctrl); -+ -+ if (bitbang->mdo) -+ gpiod_set_value_cansleep(bitbang->mdo, what); -+ else -+ gpiod_set_value_cansleep(bitbang->mdio, what); -+} -+ -+static void mdc_set(struct mdiobb_ctrl *ctrl, int what) -+{ -+ struct mdio_gpio_info *bitbang = -+ container_of(ctrl, struct mdio_gpio_info, ctrl); -+ -+ gpiod_set_value_cansleep(bitbang->mdc, what); -+} -+ -+static const struct mdiobb_ops mdio_gpio_ops = { -+ .owner = THIS_MODULE, -+ .set_mdc = mdc_set, -+ .set_mdio_dir = mdio_dir, -+ .set_mdio_data = mdio_set, -+ .get_mdio_data = mdio_get, -+}; -+ -+static struct mii_bus *mdio_gpio_bus_init(struct device *dev, -+ struct mdio_gpio_info *bitbang, -+ int bus_id) -+{ -+ struct mdio_gpio_platform_data *pdata = dev_get_platdata(dev); -+ struct mii_bus *new_bus; -+ -+ bitbang->ctrl.ops = &mdio_gpio_ops; -+ -+ new_bus = alloc_mdio_bitbang(&bitbang->ctrl); -+ if (!new_bus) -+ return NULL; -+ -+ new_bus->name = "GPIO Bitbanged MDIO"; -+ new_bus->parent = dev; -+ -+ if (bus_id != -1) -+ snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id); -+ else -+ strncpy(new_bus->id, "gpio", MII_BUS_ID_SIZE); -+ -+ if (pdata) { -+ new_bus->phy_mask = pdata->phy_mask; -+ new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask; -+ } -+ -+ dev_set_drvdata(dev, new_bus); -+ -+ return new_bus; -+} -+ -+static void mdio_gpio_bus_deinit(struct device *dev) -+{ -+ struct mii_bus *bus = dev_get_drvdata(dev); -+ -+ free_mdio_bitbang(bus); -+} -+ -+static void mdio_gpio_bus_destroy(struct device *dev) -+{ -+ struct mii_bus *bus = dev_get_drvdata(dev); -+ -+ mdiobus_unregister(bus); -+ mdio_gpio_bus_deinit(dev); -+} -+ -+static int mdio_gpio_probe(struct platform_device *pdev) -+{ -+ struct mdio_gpio_info *bitbang; -+ struct mii_bus *new_bus; -+ int ret, bus_id; -+ -+ bitbang = devm_kzalloc(&pdev->dev, sizeof(*bitbang), GFP_KERNEL); -+ if (!bitbang) -+ return -ENOMEM; -+ -+ ret = mdio_gpio_get_data(&pdev->dev, bitbang); -+ if (ret) -+ return ret; -+ -+ if (pdev->dev.of_node) { -+ bus_id = of_alias_get_id(pdev->dev.of_node, "mdio-gpio"); -+ if (bus_id < 0) { -+ dev_warn(&pdev->dev, "failed to get alias id\n"); -+ bus_id = 0; -+ } -+ } else { -+ bus_id = pdev->id; -+ } -+ -+ new_bus = mdio_gpio_bus_init(&pdev->dev, bitbang, bus_id); -+ if (!new_bus) -+ return -ENODEV; -+ -+ ret = of_mdiobus_register(new_bus, pdev->dev.of_node); -+ if (ret) -+ mdio_gpio_bus_deinit(&pdev->dev); -+ -+ return ret; -+} -+ -+static int mdio_gpio_remove(struct platform_device *pdev) -+{ -+ mdio_gpio_bus_destroy(&pdev->dev); -+ -+ return 0; -+} -+ -+static const struct of_device_id mdio_gpio_of_match[] = { -+ { .compatible = "virtual,mdio-gpio", }, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, mdio_gpio_of_match); -+ -+static struct platform_driver mdio_gpio_driver = { -+ .probe = mdio_gpio_probe, -+ .remove = mdio_gpio_remove, -+ .driver = { -+ .name = "mdio-gpio", -+ .of_match_table = mdio_gpio_of_match, -+ }, -+}; -+ -+module_platform_driver(mdio_gpio_driver); -+ -+MODULE_ALIAS("platform:mdio-gpio"); -+MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas"); -+MODULE_LICENSE("GPL v2"); -+MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/wb_mdio_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/wb_mdio_gpio_device.c -new file mode 100644 -index 000000000..e3198b378 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/phy/wb_mdio_gpio_device.c -@@ -0,0 +1,110 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static int gpio_mdc = 44; -+module_param(gpio_mdc, int, S_IRUGO | S_IWUSR); -+ -+static int gpio_mdio = 45; -+module_param(gpio_mdio, int, S_IRUGO | S_IWUSR); -+ -+static char *gpio_chip_name = NULL; -+module_param(gpio_chip_name, charp, 0644); -+MODULE_PARM_DESC(str_var, "A string variable for GPIO controller"); -+ -+static int g_wb_mdio_gpio_device_debug = 0; -+static int g_wb_mdio_gpio_device_error = 0; -+ -+module_param(g_wb_mdio_gpio_device_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_mdio_gpio_device_error, int, S_IRUGO | S_IWUSR); -+ -+#define WB_MIDO_GPIO_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ -+ if (g_wb_mdio_gpio_device_debug) { \ -+ printk(KERN_INFO "[WB_MDIO_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_MIDO_GPIO_DEVICE_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_wb_mdio_gpio_device_error) { \ -+ printk(KERN_ERR "[WB_MDIO_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+struct mdio_gpio_platform_data mdio_gpio_device_data = { -+ .phy_mask = 0, -+ .phy_ignore_ta_mask = 0, -+}; -+ -+static void wb_mdio_gpio_device_release(struct device *dev) -+{ -+ return; -+} -+ -+static struct platform_device mdio_gpio_device = { -+ .name = "mdio-gpio", -+ .num_resources = 0, -+ .id = -1, -+ .dev = { -+ .platform_data = &mdio_gpio_device_data, -+ .release = wb_mdio_gpio_device_release, -+ }, -+}; -+ -+static struct gpiod_lookup_table wb_mdio_gpio_table = { -+ .dev_id = "mdio-gpio", -+ .table = { -+ GPIO_LOOKUP_IDX("wb_gpio_d1500", 44, NULL, MDIO_GPIO_MDC, -+ GPIO_ACTIVE_HIGH), -+ GPIO_LOOKUP_IDX("wb_gpio_d1500", 45, NULL, MDIO_GPIO_MDIO, -+ GPIO_ACTIVE_HIGH), -+ { }, -+ }, -+}; -+ -+static int __init wb_mdio_gpio_device_init(void) -+{ -+ int err; -+ -+ WB_MIDO_GPIO_DEVICE_DEBUG_VERBOSE("wb_mdio_gpio_device_init enter!\n"); -+ wb_mdio_gpio_table.table[0].chip_hwnum = gpio_mdc; -+ wb_mdio_gpio_table.table[1].chip_hwnum = gpio_mdio; -+ -+ if (gpio_chip_name) { -+ wb_mdio_gpio_table.table[0].key = gpio_chip_name; -+ wb_mdio_gpio_table.table[1].key = gpio_chip_name; -+ } -+ -+ gpiod_add_lookup_table(&wb_mdio_gpio_table); -+ -+ err = platform_device_register(&mdio_gpio_device); -+ if (err < 0) { -+ printk(KERN_ERR "register mdio gpio device fail(%d). \n", err); -+ gpiod_remove_lookup_table(&wb_mdio_gpio_table); -+ return -1; -+ } -+ return 0; -+ -+} -+ -+static void __exit wb_mdio_gpio_device_exit(void) -+{ -+ WB_MIDO_GPIO_DEVICE_DEBUG_VERBOSE("wb_mdio_gpio_device_exit enter!\n"); -+ platform_device_unregister(&mdio_gpio_device); -+ gpiod_remove_lookup_table(&wb_mdio_gpio_table); -+} -+ -+module_init(wb_mdio_gpio_device_init); -+module_exit(wb_mdio_gpio_device_exit); -+MODULE_DESCRIPTION("WB MDIO GPIO Devices"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/Makefile -new file mode 100644 -index 000000000..295934ca4 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/Makefile -@@ -0,0 +1,17 @@ -+PWD = $(shell pwd) -+ -+EXTRA_CFLAGS:= -I$(M)/include -+EXTRA_CFLAGS+= -Wall -+ -+obj-m := wb_pinctrl_intel.o -+obj-m += wb_gpio_c3000.o -+obj-m += wb_gpio_c3000_device.o -+ -+all: -+ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules -+ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi -+ cp -p $(PWD)/*.ko $(module_out_put_dir) -+clean: -+ rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/*.mod -+ rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order -+ rm -rf $(PWD)/.tmp_versions -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/core.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/core.h -new file mode 100644 -index 000000000..840103c40 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/core.h -@@ -0,0 +1,249 @@ -+/* SPDX-License-Identifier: GPL-2.0-only */ -+/* -+ * Core private header for the pin control subsystem -+ * -+ * Copyright (C) 2011 ST-Ericsson SA -+ * Written on behalf of Linaro for ST-Ericsson -+ * -+ * Author: Linus Walleij -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+struct pinctrl_gpio_range; -+ -+/** -+ * struct pinctrl_dev - pin control class device -+ * @node: node to include this pin controller in the global pin controller list -+ * @desc: the pin controller descriptor supplied when initializing this pin -+ * controller -+ * @pin_desc_tree: each pin descriptor for this pin controller is stored in -+ * this radix tree -+ * @pin_group_tree: optionally each pin group can be stored in this radix tree -+ * @num_groups: optionally number of groups can be kept here -+ * @pin_function_tree: optionally each function can be stored in this radix tree -+ * @num_functions: optionally number of functions can be kept here -+ * @gpio_ranges: a list of GPIO ranges that is handled by this pin controller, -+ * ranges are added to this list at runtime -+ * @dev: the device entry for this pin controller -+ * @owner: module providing the pin controller, used for refcounting -+ * @driver_data: driver data for drivers registering to the pin controller -+ * subsystem -+ * @p: result of pinctrl_get() for this device -+ * @hog_default: default state for pins hogged by this device -+ * @hog_sleep: sleep state for pins hogged by this device -+ * @mutex: mutex taken on each pin controller specific action -+ * @device_root: debugfs root for this device -+ */ -+struct pinctrl_dev { -+ struct list_head node; -+ struct pinctrl_desc *desc; -+ struct radix_tree_root pin_desc_tree; -+#ifdef CONFIG_GENERIC_PINCTRL_GROUPS -+ struct radix_tree_root pin_group_tree; -+ unsigned int num_groups; -+#endif -+#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS -+ struct radix_tree_root pin_function_tree; -+ unsigned int num_functions; -+#endif -+ struct list_head gpio_ranges; -+ struct device *dev; -+ struct module *owner; -+ void *driver_data; -+ struct pinctrl *p; -+ struct pinctrl_state *hog_default; -+ struct pinctrl_state *hog_sleep; -+ struct mutex mutex; -+#ifdef CONFIG_DEBUG_FS -+ struct dentry *device_root; -+#endif -+}; -+ -+/** -+ * struct pinctrl - per-device pin control state holder -+ * @node: global list node -+ * @dev: the device using this pin control handle -+ * @states: a list of states for this device -+ * @state: the current state -+ * @dt_maps: the mapping table chunks dynamically parsed from device tree for -+ * this device, if any -+ * @users: reference count -+ */ -+struct pinctrl { -+ struct list_head node; -+ struct device *dev; -+ struct list_head states; -+ struct pinctrl_state *state; -+ struct list_head dt_maps; -+ struct kref users; -+}; -+ -+/** -+ * struct pinctrl_state - a pinctrl state for a device -+ * @node: list node for struct pinctrl's @states field -+ * @name: the name of this state -+ * @settings: a list of settings for this state -+ */ -+struct pinctrl_state { -+ struct list_head node; -+ const char *name; -+ struct list_head settings; -+}; -+ -+/** -+ * struct pinctrl_setting_mux - setting data for MAP_TYPE_MUX_GROUP -+ * @group: the group selector to program -+ * @func: the function selector to program -+ */ -+struct pinctrl_setting_mux { -+ unsigned group; -+ unsigned func; -+}; -+ -+/** -+ * struct pinctrl_setting_configs - setting data for MAP_TYPE_CONFIGS_* -+ * @group_or_pin: the group selector or pin ID to program -+ * @configs: a pointer to an array of config parameters/values to program into -+ * hardware. Each individual pin controller defines the format and meaning -+ * of config parameters. -+ * @num_configs: the number of entries in array @configs -+ */ -+struct pinctrl_setting_configs { -+ unsigned group_or_pin; -+ unsigned long *configs; -+ unsigned num_configs; -+}; -+ -+/** -+ * struct pinctrl_setting - an individual mux or config setting -+ * @node: list node for struct pinctrl_settings's @settings field -+ * @type: the type of setting -+ * @pctldev: pin control device handling to be programmed. Not used for -+ * PIN_MAP_TYPE_DUMMY_STATE. -+ * @dev_name: the name of the device using this state -+ * @data: Data specific to the setting type -+ */ -+struct pinctrl_setting { -+ struct list_head node; -+ enum pinctrl_map_type type; -+ struct pinctrl_dev *pctldev; -+ const char *dev_name; -+ union { -+ struct pinctrl_setting_mux mux; -+ struct pinctrl_setting_configs configs; -+ } data; -+}; -+ -+/** -+ * struct pin_desc - pin descriptor for each physical pin in the arch -+ * @pctldev: corresponding pin control device -+ * @name: a name for the pin, e.g. the name of the pin/pad/finger on a -+ * datasheet or such -+ * @dynamic_name: if the name of this pin was dynamically allocated -+ * @drv_data: driver-defined per-pin data. pinctrl core does not touch this -+ * @mux_usecount: If zero, the pin is not claimed, and @owner should be NULL. -+ * If non-zero, this pin is claimed by @owner. This field is an integer -+ * rather than a boolean, since pinctrl_get() might process multiple -+ * mapping table entries that refer to, and hence claim, the same group -+ * or pin, and each of these will increment the @usecount. -+ * @mux_owner: The name of device that called pinctrl_get(). -+ * @mux_setting: The most recent selected mux setting for this pin, if any. -+ * @gpio_owner: If pinctrl_gpio_request() was called for this pin, this is -+ * the name of the GPIO that "owns" this pin. -+ */ -+struct pin_desc { -+ struct pinctrl_dev *pctldev; -+ const char *name; -+ bool dynamic_name; -+ void *drv_data; -+ /* These fields only added when supporting pinmux drivers */ -+#ifdef CONFIG_PINMUX -+ unsigned mux_usecount; -+ const char *mux_owner; -+ const struct pinctrl_setting_mux *mux_setting; -+ const char *gpio_owner; -+#endif -+}; -+ -+/** -+ * struct pinctrl_maps - a list item containing part of the mapping table -+ * @node: mapping table list node -+ * @maps: array of mapping table entries -+ * @num_maps: the number of entries in @maps -+ */ -+struct pinctrl_maps { -+ struct list_head node; -+ const struct pinctrl_map *maps; -+ unsigned num_maps; -+}; -+ -+#ifdef CONFIG_GENERIC_PINCTRL_GROUPS -+ -+/** -+ * struct group_desc - generic pin group descriptor -+ * @name: name of the pin group -+ * @pins: array of pins that belong to the group -+ * @num_pins: number of pins in the group -+ * @data: pin controller driver specific data -+ */ -+struct group_desc { -+ const char *name; -+ int *pins; -+ int num_pins; -+ void *data; -+}; -+ -+int pinctrl_generic_get_group_count(struct pinctrl_dev *pctldev); -+ -+const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev, -+ unsigned int group_selector); -+ -+int pinctrl_generic_get_group_pins(struct pinctrl_dev *pctldev, -+ unsigned int group_selector, -+ const unsigned int **pins, -+ unsigned int *npins); -+ -+struct group_desc *pinctrl_generic_get_group(struct pinctrl_dev *pctldev, -+ unsigned int group_selector); -+ -+int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name, -+ int *gpins, int ngpins, void *data); -+ -+int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev, -+ unsigned int group_selector); -+ -+#endif /* CONFIG_GENERIC_PINCTRL_GROUPS */ -+ -+struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name); -+struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np); -+int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name); -+const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin); -+int pinctrl_get_group_selector(struct pinctrl_dev *pctldev, -+ const char *pin_group); -+ -+static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev, -+ unsigned int pin) -+{ -+ return radix_tree_lookup(&pctldev->pin_desc_tree, pin); -+} -+ -+extern struct pinctrl_gpio_range * -+pinctrl_find_gpio_range_from_pin_nolock(struct pinctrl_dev *pctldev, -+ unsigned int pin); -+ -+extern int pinctrl_force_sleep(struct pinctrl_dev *pctldev); -+extern int pinctrl_force_default(struct pinctrl_dev *pctldev); -+ -+extern struct mutex pinctrl_maps_mutex; -+extern struct list_head pinctrl_maps; -+ -+#define for_each_maps(_maps_node_, _i_, _map_) \ -+ list_for_each_entry(_maps_node_, &pinctrl_maps, node) \ -+ for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \ -+ _i_ < _maps_node_->num_maps; \ -+ _i_++, _map_ = &_maps_node_->maps[_i_]) -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000.c -new file mode 100644 -index 000000000..753c8a061 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000.c -@@ -0,0 +1,452 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Intel Denverton SoC pinctrl/GPIO driver -+ * -+ * Copyright (C) 2017, Intel Corporation -+ * Author: Mika Westerberg -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "wb_pinctrl_intel.h" -+ -+static int g_c3000_gpio_debug = 0; -+static int g_c3000_gpio_error = 0; -+module_param(g_c3000_gpio_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_c3000_gpio_error, int, S_IRUGO | S_IWUSR); -+ -+#define C3000_GPIO_VERBOSE(fmt, args...) do { \ -+ if (g_c3000_gpio_debug) { \ -+ printk(KERN_INFO "[GPIO_PCIE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define C3000_GPIO_ERROR(fmt, args...) do { \ -+ if (g_c3000_gpio_error) { \ -+ printk(KERN_ERR "[GPIO_PCIE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define DNV_PAD_OWN 0x020 -+#define DNV_PADCFGLOCK 0x090 -+#define DNV_HOSTSW_OWN 0x0C0 -+#define DNV_GPI_IS 0x100 -+#define DNV_GPI_IE 0x120 -+ -+#define DNV_GPP(n, s, e) \ -+ { \ -+ .reg_num = (n), \ -+ .base = (s), \ -+ .size = ((e) - (s) + 1), \ -+ } -+ -+#define DNV_COMMUNITY(b, s, e, g, d) \ -+ { \ -+ .barno = (b), \ -+ .padown_offset = DNV_PAD_OWN, \ -+ .padcfglock_offset = DNV_PADCFGLOCK, \ -+ .hostown_offset = DNV_HOSTSW_OWN, \ -+ .is_offset = DNV_GPI_IS, \ -+ .ie_offset = DNV_GPI_IE, \ -+ .pin_base = (s), \ -+ .npins = ((e) - (s) + 1), \ -+ .gpps = (g), \ -+ .ngpps = ARRAY_SIZE(g), \ -+ .dw_base = (d), \ -+ } -+ -+/* Denverton */ -+static const struct pinctrl_pin_desc dnv_pins[] = { -+ /* North ALL */ -+ PINCTRL_PIN(0, "GBE0_SDP0"), -+ PINCTRL_PIN(1, "GBE1_SDP0"), -+ PINCTRL_PIN(2, "GBE0_SDP1"), -+ PINCTRL_PIN(3, "GBE1_SDP1"), -+ PINCTRL_PIN(4, "GBE0_SDP2"), -+ PINCTRL_PIN(5, "GBE1_SDP2"), -+ PINCTRL_PIN(6, "GBE0_SDP3"), -+ PINCTRL_PIN(7, "GBE1_SDP3"), -+ PINCTRL_PIN(8, "GBE2_LED0"), -+ PINCTRL_PIN(9, "GBE2_LED1"), -+ PINCTRL_PIN(10, "GBE0_I2C_CLK"), -+ PINCTRL_PIN(11, "GBE0_I2C_DATA"), -+ PINCTRL_PIN(12, "GBE1_I2C_CLK"), -+ PINCTRL_PIN(13, "GBE1_I2C_DATA"), -+ PINCTRL_PIN(14, "NCSI_RXD0"), -+ PINCTRL_PIN(15, "NCSI_CLK_IN"), -+ PINCTRL_PIN(16, "NCSI_RXD1"), -+ PINCTRL_PIN(17, "NCSI_CRS_DV"), -+ PINCTRL_PIN(18, "NCSI_ARB_IN"), -+ PINCTRL_PIN(19, "NCSI_TX_EN"), -+ PINCTRL_PIN(20, "NCSI_TXD0"), -+ PINCTRL_PIN(21, "NCSI_TXD1"), -+ PINCTRL_PIN(22, "NCSI_ARB_OUT"), -+ PINCTRL_PIN(23, "GBE0_LED0"), -+ PINCTRL_PIN(24, "GBE0_LED1"), -+ PINCTRL_PIN(25, "GBE1_LED0"), -+ PINCTRL_PIN(26, "GBE1_LED1"), -+ PINCTRL_PIN(27, "GPIO0"), -+ PINCTRL_PIN(28, "PCIE_CLKREQ0_N"), -+ PINCTRL_PIN(29, "PCIE_CLKREQ1_N"), -+ PINCTRL_PIN(30, "PCIE_CLKREQ2_N"), -+ PINCTRL_PIN(31, "PCIE_CLKREQ3_N"), -+ PINCTRL_PIN(32, "PCIE_CLKREQ4_N"), -+ PINCTRL_PIN(33, "GPIO1"), -+ PINCTRL_PIN(34, "GPIO2"), -+ PINCTRL_PIN(35, "SVID_ALERT_N"), -+ PINCTRL_PIN(36, "SVID_DATA"), -+ PINCTRL_PIN(37, "SVID_CLK"), -+ PINCTRL_PIN(38, "THERMTRIP_N"), -+ PINCTRL_PIN(39, "PROCHOT_N"), -+ PINCTRL_PIN(40, "MEMHOT_N"), -+ /* South DFX */ -+ PINCTRL_PIN(41, "DFX_PORT_CLK0"), -+ PINCTRL_PIN(42, "DFX_PORT_CLK1"), -+ PINCTRL_PIN(43, "DFX_PORT0"), -+ PINCTRL_PIN(44, "DFX_PORT1"), -+ PINCTRL_PIN(45, "DFX_PORT2"), -+ PINCTRL_PIN(46, "DFX_PORT3"), -+ PINCTRL_PIN(47, "DFX_PORT4"), -+ PINCTRL_PIN(48, "DFX_PORT5"), -+ PINCTRL_PIN(49, "DFX_PORT6"), -+ PINCTRL_PIN(50, "DFX_PORT7"), -+ PINCTRL_PIN(51, "DFX_PORT8"), -+ PINCTRL_PIN(52, "DFX_PORT9"), -+ PINCTRL_PIN(53, "DFX_PORT10"), -+ PINCTRL_PIN(54, "DFX_PORT11"), -+ PINCTRL_PIN(55, "DFX_PORT12"), -+ PINCTRL_PIN(56, "DFX_PORT13"), -+ PINCTRL_PIN(57, "DFX_PORT14"), -+ PINCTRL_PIN(58, "DFX_PORT15"), -+ /* South GPP0 */ -+ PINCTRL_PIN(59, "GPIO12"), -+ PINCTRL_PIN(60, "SMB5_GBE_ALRT_N"), -+ PINCTRL_PIN(61, "PCIE_CLKREQ5_N"), -+ PINCTRL_PIN(62, "PCIE_CLKREQ6_N"), -+ PINCTRL_PIN(63, "PCIE_CLKREQ7_N"), -+ PINCTRL_PIN(64, "UART0_RXD"), -+ PINCTRL_PIN(65, "UART0_TXD"), -+ PINCTRL_PIN(66, "SMB5_GBE_CLK"), -+ PINCTRL_PIN(67, "SMB5_GBE_DATA"), -+ PINCTRL_PIN(68, "ERROR2_N"), -+ PINCTRL_PIN(69, "ERROR1_N"), -+ PINCTRL_PIN(70, "ERROR0_N"), -+ PINCTRL_PIN(71, "IERR_N"), -+ PINCTRL_PIN(72, "MCERR_N"), -+ PINCTRL_PIN(73, "SMB0_LEG_CLK"), -+ PINCTRL_PIN(74, "SMB0_LEG_DATA"), -+ PINCTRL_PIN(75, "SMB0_LEG_ALRT_N"), -+ PINCTRL_PIN(76, "SMB1_HOST_DATA"), -+ PINCTRL_PIN(77, "SMB1_HOST_CLK"), -+ PINCTRL_PIN(78, "SMB2_PECI_DATA"), -+ PINCTRL_PIN(79, "SMB2_PECI_CLK"), -+ PINCTRL_PIN(80, "SMB4_CSME0_DATA"), -+ PINCTRL_PIN(81, "SMB4_CSME0_CLK"), -+ PINCTRL_PIN(82, "SMB4_CSME0_ALRT_N"), -+ PINCTRL_PIN(83, "USB_OC0_N"), -+ PINCTRL_PIN(84, "FLEX_CLK_SE0"), -+ PINCTRL_PIN(85, "FLEX_CLK_SE1"), -+ PINCTRL_PIN(86, "GPIO4"), -+ PINCTRL_PIN(87, "GPIO5"), -+ PINCTRL_PIN(88, "GPIO6"), -+ PINCTRL_PIN(89, "GPIO7"), -+ PINCTRL_PIN(90, "SATA0_LED_N"), -+ PINCTRL_PIN(91, "SATA1_LED_N"), -+ PINCTRL_PIN(92, "SATA_PDETECT0"), -+ PINCTRL_PIN(93, "SATA_PDETECT1"), -+ PINCTRL_PIN(94, "SATA0_SDOUT"), -+ PINCTRL_PIN(95, "SATA1_SDOUT"), -+ PINCTRL_PIN(96, "UART1_RXD"), -+ PINCTRL_PIN(97, "UART1_TXD"), -+ PINCTRL_PIN(98, "GPIO8"), -+ PINCTRL_PIN(99, "GPIO9"), -+ PINCTRL_PIN(100, "TCK"), -+ PINCTRL_PIN(101, "TRST_N"), -+ PINCTRL_PIN(102, "TMS"), -+ PINCTRL_PIN(103, "TDI"), -+ PINCTRL_PIN(104, "TDO"), -+ PINCTRL_PIN(105, "CX_PRDY_N"), -+ PINCTRL_PIN(106, "CX_PREQ_N"), -+ PINCTRL_PIN(107, "CTBTRIGINOUT"), -+ PINCTRL_PIN(108, "CTBTRIGOUT"), -+ PINCTRL_PIN(109, "DFX_SPARE2"), -+ PINCTRL_PIN(110, "DFX_SPARE3"), -+ PINCTRL_PIN(111, "DFX_SPARE4"), -+ /* South GPP1 */ -+ PINCTRL_PIN(112, "SUSPWRDNACK"), -+ PINCTRL_PIN(113, "PMU_SUSCLK"), -+ PINCTRL_PIN(114, "ADR_TRIGGER"), -+ PINCTRL_PIN(115, "PMU_SLP_S45_N"), -+ PINCTRL_PIN(116, "PMU_SLP_S3_N"), -+ PINCTRL_PIN(117, "PMU_WAKE_N"), -+ PINCTRL_PIN(118, "PMU_PWRBTN_N"), -+ PINCTRL_PIN(119, "PMU_RESETBUTTON_N"), -+ PINCTRL_PIN(120, "PMU_PLTRST_N"), -+ PINCTRL_PIN(121, "SUS_STAT_N"), -+ PINCTRL_PIN(122, "SLP_S0IX_N"), -+ PINCTRL_PIN(123, "SPI_CS0_N"), -+ PINCTRL_PIN(124, "SPI_CS1_N"), -+ PINCTRL_PIN(125, "SPI_MOSI_IO0"), -+ PINCTRL_PIN(126, "SPI_MISO_IO1"), -+ PINCTRL_PIN(127, "SPI_IO2"), -+ PINCTRL_PIN(128, "SPI_IO3"), -+ PINCTRL_PIN(129, "SPI_CLK"), -+ PINCTRL_PIN(130, "SPI_CLK_LOOPBK"), -+ PINCTRL_PIN(131, "ESPI_IO0"), -+ PINCTRL_PIN(132, "ESPI_IO1"), -+ PINCTRL_PIN(133, "ESPI_IO2"), -+ PINCTRL_PIN(134, "ESPI_IO3"), -+ PINCTRL_PIN(135, "ESPI_CS0_N"), -+ PINCTRL_PIN(136, "ESPI_CLK"), -+ PINCTRL_PIN(137, "ESPI_RST_N"), -+ PINCTRL_PIN(138, "ESPI_ALRT0_N"), -+ PINCTRL_PIN(139, "GPIO10"), -+ PINCTRL_PIN(140, "GPIO11"), -+ PINCTRL_PIN(141, "ESPI_CLK_LOOPBK"), -+ PINCTRL_PIN(142, "EMMC_CMD"), -+ PINCTRL_PIN(143, "EMMC_STROBE"), -+ PINCTRL_PIN(144, "EMMC_CLK"), -+ PINCTRL_PIN(145, "EMMC_D0"), -+ PINCTRL_PIN(146, "EMMC_D1"), -+ PINCTRL_PIN(147, "EMMC_D2"), -+ PINCTRL_PIN(148, "EMMC_D3"), -+ PINCTRL_PIN(149, "EMMC_D4"), -+ PINCTRL_PIN(150, "EMMC_D5"), -+ PINCTRL_PIN(151, "EMMC_D6"), -+ PINCTRL_PIN(152, "EMMC_D7"), -+ PINCTRL_PIN(153, "GPIO3"), -+}; -+ -+static const unsigned int dnv_uart0_pins[] = { 60, 61, 64, 65 }; -+static const unsigned int dnv_uart0_modes[] = { 2, 3, 1, 1 }; -+static const unsigned int dnv_uart1_pins[] = { 94, 95, 96, 97 }; -+static const unsigned int dnv_uart2_pins[] = { 60, 61, 62, 63 }; -+static const unsigned int dnv_uart2_modes[] = { 1, 2, 2, 2 }; -+static const unsigned int dnv_emmc_pins[] = { -+ 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, -+}; -+ -+static const struct intel_pingroup dnv_groups[] = { -+ PIN_GROUP("uart0_grp", dnv_uart0_pins, dnv_uart0_modes), -+ PIN_GROUP("uart1_grp", dnv_uart1_pins, 1), -+ PIN_GROUP("uart2_grp", dnv_uart2_pins, dnv_uart2_modes), -+ PIN_GROUP("emmc_grp", dnv_emmc_pins, 1), -+}; -+ -+static const char * const dnv_uart0_groups[] = { "uart0_grp" }; -+static const char * const dnv_uart1_groups[] = { "uart1_grp" }; -+static const char * const dnv_uart2_groups[] = { "uart2_grp" }; -+static const char * const dnv_emmc_groups[] = { "emmc_grp" }; -+ -+static const struct intel_function dnv_functions[] = { -+ FUNCTION("uart0", dnv_uart0_groups), -+ FUNCTION("uart1", dnv_uart1_groups), -+ FUNCTION("uart2", dnv_uart2_groups), -+ FUNCTION("emmc", dnv_emmc_groups), -+}; -+ -+static const struct intel_padgroup dnv_north_gpps[] = { -+ DNV_GPP(0, 0, 31), /* North ALL_0 */ -+ DNV_GPP(1, 32, 40), /* North ALL_1 */ -+}; -+ -+static const struct intel_padgroup dnv_south_gpps[] = { -+ DNV_GPP(0, 41, 58), /* South DFX */ -+ DNV_GPP(1, 59, 90), /* South GPP0_0 */ -+ DNV_GPP(2, 91, 111), /* South GPP0_1 */ -+ DNV_GPP(3, 112, 143), /* South GPP1_0 */ -+ DNV_GPP(4, 144, 153), /* South GPP1_1 */ -+}; -+ -+static const struct intel_community dnv_communities[] = { -+ DNV_COMMUNITY(0, 0, 40, dnv_north_gpps, 0xc20000), -+ DNV_COMMUNITY(1, 41, 153, dnv_south_gpps, 0xc50000), -+}; -+ -+static const struct intel_pinctrl_soc_data dnv_soc_data = { -+ .pins = dnv_pins, -+ .npins = ARRAY_SIZE(dnv_pins), -+ .groups = dnv_groups, -+ .ngroups = ARRAY_SIZE(dnv_groups), -+ .functions = dnv_functions, -+ .nfunctions = ARRAY_SIZE(dnv_functions), -+ .communities = dnv_communities, -+ .ncommunities = ARRAY_SIZE(dnv_communities), -+}; -+ -+static INTEL_PINCTRL_PM_OPS(dnv_pinctrl_pm_ops); -+ -+static int pci_dev_init(wb_gpio_data_t *wb_gpio_data, struct pci_dev *pci_dev) -+{ -+ int err, i; -+ void __iomem *base; -+ -+ C3000_GPIO_VERBOSE("Enter vendor 0x%x, device 0x%x.\n", -+ pci_dev->vendor, pci_dev->device); -+ -+ C3000_GPIO_VERBOSE("start pci_enable_device!\n"); -+ err = pci_enable_device(pci_dev); -+ if (err) { -+ dev_err(&pci_dev->dev, "Failed to enable pci device, ret:%d.\n", err); -+ return err; -+ } -+ -+ err = pci_request_region(pci_dev, 0, "P2SB"); -+ if (err) { -+ dev_err(&pci_dev->dev, "Requesting C3000 P2SB BAR0 region failed, ret: %d\n", err); -+ goto err_disable; -+ } -+ -+ C3000_GPIO_VERBOSE("start pci_set_master!\n"); -+ pci_set_master(pci_dev); -+ -+ base = pci_iomap(pci_dev, wb_gpio_data->pci_bar, 0); -+ if (!base) { -+ dev_err(&pci_dev->dev, "pci_iomap bar: %d failed\n", wb_gpio_data->pci_bar); -+ err = -ENOMEM; -+ goto err_release; -+ } -+ wb_gpio_data->pci_mem_base = base; -+ -+ for (i = 0; i < dnv_soc_data.ncommunities; i++) { -+ wb_gpio_data->res[i] = base + dnv_soc_data.communities[i].dw_base; -+ } -+ return 0; -+err_release: -+ pci_release_region(pci_dev, wb_gpio_data->pci_bar); -+err_disable: -+ pci_disable_device(pci_dev); -+ return err; -+} -+ -+static void pci_dev_release(wb_gpio_data_t *wb_gpio_data) -+{ -+ struct pci_dev *pci_dev; -+ -+ pci_dev = wb_gpio_data->pci_dev; -+ if (wb_gpio_data->pci_mem_base) { -+ pci_iounmap(pci_dev, wb_gpio_data->pci_mem_base); -+ } -+ pci_release_region(pci_dev, wb_gpio_data->pci_bar); -+ pci_disable_device(pci_dev); -+ return; -+} -+ -+static int wb_gpio_driver_probe(struct platform_device *plat_dev) -+{ -+ int ret, devfn; -+ wb_gpio_data_t *wb_gpio_data; -+ wb_gpio_data_t *c3000_gpio_device; -+ struct pci_dev *pci_dev; -+ -+ if (dnv_soc_data.ncommunities > GPIO_RES_MAX) { -+ dev_err(&plat_dev->dev, "GPIO ncommunities %lu is more than GPIO resource number: %d\n", -+ dnv_soc_data.ncommunities, GPIO_RES_MAX); -+ return -EINVAL; -+ } -+ -+ wb_gpio_data = devm_kzalloc(&plat_dev->dev, sizeof(wb_gpio_data_t), GFP_KERNEL); -+ if (!wb_gpio_data) { -+ dev_err(&plat_dev->dev, "devm_kzalloc failed.\n"); -+ ret = -ENOMEM; -+ return ret; -+ } -+ -+ if (plat_dev->dev.of_node) { -+ ret = 0; -+ ret += of_property_read_u32(plat_dev->dev.of_node, "pci_domain", &wb_gpio_data->pci_domain); -+ ret += of_property_read_u32(plat_dev->dev.of_node, "pci_bus", &wb_gpio_data->pci_bus); -+ ret += of_property_read_u32(plat_dev->dev.of_node, "pci_slot", &wb_gpio_data->pci_slot); -+ ret += of_property_read_u32(plat_dev->dev.of_node, "pci_fn", &wb_gpio_data->pci_fn); -+ ret += of_property_read_u32(plat_dev->dev.of_node, "pci_bar", &wb_gpio_data->pci_bar); -+ ret += of_property_read_u32(plat_dev->dev.of_node, "irq", &wb_gpio_data->irq); -+ if (ret != 0) { -+ dev_err(&plat_dev->dev, "Failed to get dts config, ret:%d.\n", ret); -+ return -ENXIO; -+ } -+ } else { -+ if (plat_dev->dev.platform_data == NULL) { -+ dev_err(&plat_dev->dev, "Failed to get platform data config.\n"); -+ return -ENXIO; -+ } -+ c3000_gpio_device = plat_dev->dev.platform_data; -+ wb_gpio_data->pci_domain = c3000_gpio_device->pci_domain; -+ wb_gpio_data->pci_bus = c3000_gpio_device->pci_bus; -+ wb_gpio_data->pci_slot = c3000_gpio_device->pci_slot; -+ wb_gpio_data->pci_fn = c3000_gpio_device->pci_fn; -+ wb_gpio_data->pci_bar = c3000_gpio_device->pci_bar; -+ wb_gpio_data->irq = c3000_gpio_device->irq; -+ } -+ -+ C3000_GPIO_VERBOSE("domain:0x%04x, bus:0x%02x, slot:0x%02x, fn:%u, bar:%u, irq: %d\n", -+ wb_gpio_data->pci_domain, wb_gpio_data->pci_bus, wb_gpio_data->pci_slot, wb_gpio_data->pci_fn, -+ wb_gpio_data->pci_bar, wb_gpio_data->irq); -+ -+ devfn = PCI_DEVFN(wb_gpio_data->pci_slot, wb_gpio_data->pci_fn); -+ pci_dev = pci_get_domain_bus_and_slot(wb_gpio_data->pci_domain, wb_gpio_data->pci_bus, devfn); -+ if (pci_dev == NULL) { -+ dev_err(&plat_dev->dev, "Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", -+ wb_gpio_data->pci_domain, wb_gpio_data->pci_bus, devfn); -+ return -ENXIO; -+ } -+ wb_gpio_data->pci_dev = pci_dev; -+ ret = pci_dev_init(wb_gpio_data, pci_dev); -+ if (ret != 0) { -+ dev_err(&plat_dev->dev, "Failed to get pci bar address.\n"); -+ return ret; -+ } -+ C3000_GPIO_VERBOSE("pci_dev_init success, pci_mem_bae: 0x%pK, res0: 0x%pK, res1: 0x%pK\n", -+ wb_gpio_data->pci_mem_base, wb_gpio_data->res[0], wb_gpio_data->res[1]); -+ -+ platform_set_drvdata(plat_dev, wb_gpio_data); -+ -+ ret = wb_pinctrl_probe(plat_dev, &dnv_soc_data); -+ if (ret) { -+ dev_err(&plat_dev->dev, "C3000 gpio pinctrl probe failed, ret:%d\n", ret); -+ pci_dev_release(wb_gpio_data); -+ return ret; -+ } -+ dev_info(&plat_dev->dev, "C3000 gpio pinctrl probe success.\n"); -+ return 0; -+} -+ -+static int wb_gpio_driver_remove(struct platform_device *plat_dev) -+{ -+ wb_gpio_data_t *wb_gpio_data; -+ -+ C3000_GPIO_VERBOSE("c3000_gpio_pcie_remove.\n"); -+ -+ wb_gpio_data = platform_get_drvdata(plat_dev); -+ pci_dev_release(wb_gpio_data); -+ return 0; -+} -+ -+static const struct of_device_id gpio_c3000_match[] = { -+ { -+ .compatible = "wb_gpio_c3000", -+ }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, gpio_c3000_match); -+ -+static struct platform_driver wb_gpio_c3000_driver = { -+ .driver = { -+ .name = "wb_gpio_c3000", -+ .of_match_table = gpio_c3000_match, -+ }, -+ .probe = wb_gpio_driver_probe, -+ .remove = wb_gpio_driver_remove, -+}; -+ -+module_platform_driver(wb_gpio_c3000_driver); -+ -+MODULE_DESCRIPTION("C3000 GPIO Controller driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000_device.c -new file mode 100644 -index 000000000..33ab19a5a ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000_device.c -@@ -0,0 +1,69 @@ -+#include -+#include -+#include -+#include -+#include -+ -+#include "wb_pinctrl_intel.h" -+ -+static int g_wb_c300_gpio_device_debug = 0; -+static int g_wb_c300_gpio_device_error = 0; -+ -+module_param(g_wb_c300_gpio_device_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_c300_gpio_device_error, int, S_IRUGO | S_IWUSR); -+ -+#define WB_C3000_GPIO_DEVICE_DEBUG(fmt, args...) do { \ -+ if (g_wb_c300_gpio_device_debug) { \ -+ printk(KERN_INFO "[WB_C3000_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_C3000_GPIO_DEVICE_ERROR(fmt, args...) do { \ -+ if (g_wb_c300_gpio_device_error) { \ -+ printk(KERN_ERR "[WB_C3000_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static wb_gpio_data_t c3000_gpio_device_data = { -+ .irq = 15, -+ .pci_domain = 0x0000, -+ .pci_bus = 0x00, -+ .pci_slot = 0x1f, -+ .pci_fn = 1, -+ .pci_bar = 0, -+}; -+ -+static void wb_c3000_gpio_device_release(struct device *dev) -+{ -+ return; -+} -+ -+static struct platform_device c3000_gpio_device = { -+ .name = "wb_gpio_c3000", -+ .id = -1, -+ .dev = { -+ .platform_data = &c3000_gpio_device_data, -+ .release = wb_c3000_gpio_device_release, -+ }, -+}; -+ -+static int __init wb_c3000_gpio_device_init(void) -+{ -+ WB_C3000_GPIO_DEVICE_DEBUG("wb_c3000_gpio_device_init enter!\n"); -+ return platform_device_register(&c3000_gpio_device); -+ -+} -+ -+static void __exit wb_c3000_gpio_device_exit(void) -+{ -+ -+ WB_C3000_GPIO_DEVICE_DEBUG("wb_c3000_gpio_device_exit enter!\n"); -+ platform_device_unregister(&c3000_gpio_device); -+ return; -+} -+ -+module_init(wb_c3000_gpio_device_init); -+module_exit(wb_c3000_gpio_device_exit); -+MODULE_DESCRIPTION("C3000 GPIO Controller device"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.c -new file mode 100644 -index 000000000..7a52f17ac ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.c -@@ -0,0 +1,1829 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Intel pinctrl/GPIO core driver. -+ * -+ * Copyright (C) 2015, Intel Corporation -+ * Authors: Mathias Nyman -+ * Mika Westerberg -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "core.h" -+#include "wb_pinctrl_intel.h" -+ -+/* Offset from regs */ -+#define REVID 0x000 -+#define REVID_SHIFT 16 -+#define REVID_MASK GENMASK(31, 16) -+ -+#define PADBAR 0x00c -+ -+#define PADOWN_BITS 4 -+#define PADOWN_SHIFT(p) ((p) % 8 * PADOWN_BITS) -+#define PADOWN_MASK(p) (GENMASK(3, 0) << PADOWN_SHIFT(p)) -+#define PADOWN_GPP(p) ((p) / 8) -+ -+/* Offset from pad_regs */ -+#define PADCFG0 0x000 -+#define PADCFG0_RXEVCFG_SHIFT 25 -+#define PADCFG0_RXEVCFG_MASK GENMASK(26, 25) -+#define PADCFG0_RXEVCFG_LEVEL 0 -+#define PADCFG0_RXEVCFG_EDGE 1 -+#define PADCFG0_RXEVCFG_DISABLED 2 -+#define PADCFG0_RXEVCFG_EDGE_BOTH 3 -+#define PADCFG0_PREGFRXSEL BIT(24) -+#define PADCFG0_RXINV BIT(23) -+#define PADCFG0_GPIROUTIOXAPIC BIT(20) -+#define PADCFG0_GPIROUTSCI BIT(19) -+#define PADCFG0_GPIROUTSMI BIT(18) -+#define PADCFG0_GPIROUTNMI BIT(17) -+#define PADCFG0_PMODE_SHIFT 10 -+#define PADCFG0_PMODE_MASK GENMASK(13, 10) -+#define PADCFG0_PMODE_GPIO 0 -+#define PADCFG0_GPIORXDIS BIT(9) -+#define PADCFG0_GPIOTXDIS BIT(8) -+#define PADCFG0_GPIORXSTATE BIT(1) -+#define PADCFG0_GPIOTXSTATE BIT(0) -+ -+#define PADCFG1 0x004 -+#define PADCFG1_TERM_UP BIT(13) -+#define PADCFG1_TERM_SHIFT 10 -+#define PADCFG1_TERM_MASK GENMASK(12, 10) -+#define PADCFG1_TERM_20K BIT(2) -+#define PADCFG1_TERM_5K BIT(1) -+#define PADCFG1_TERM_1K BIT(0) -+#define PADCFG1_TERM_833 (BIT(1) | BIT(0)) -+ -+#define PADCFG2 0x008 -+#define PADCFG2_DEBEN BIT(0) -+#define PADCFG2_DEBOUNCE_SHIFT 1 -+#define PADCFG2_DEBOUNCE_MASK GENMASK(4, 1) -+ -+#define DEBOUNCE_PERIOD_NSEC 31250 -+ -+struct intel_pad_context { -+ u32 padcfg0; -+ u32 padcfg1; -+ u32 padcfg2; -+}; -+ -+struct intel_community_context { -+ u32 *intmask; -+ u32 *hostown; -+}; -+ -+#define pin_to_padno(c, p) ((p) - (c)->pin_base) -+#define padgroup_offset(g, p) ((p) - (g)->base) -+ -+static struct intel_community *intel_get_community(struct intel_pinctrl *pctrl, -+ unsigned int pin) -+{ -+ struct intel_community *community; -+ int i; -+ -+ for (i = 0; i < pctrl->ncommunities; i++) { -+ community = &pctrl->communities[i]; -+ if (pin >= community->pin_base && -+ pin < community->pin_base + community->npins) -+ return community; -+ } -+ -+ dev_warn(pctrl->dev, "failed to find community for pin %u\n", pin); -+ return NULL; -+} -+ -+static const struct intel_padgroup * -+intel_community_get_padgroup(const struct intel_community *community, -+ unsigned int pin) -+{ -+ int i; -+ -+ for (i = 0; i < community->ngpps; i++) { -+ const struct intel_padgroup *padgrp = &community->gpps[i]; -+ -+ if (pin >= padgrp->base && pin < padgrp->base + padgrp->size) -+ return padgrp; -+ } -+ -+ return NULL; -+} -+ -+static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl, -+ unsigned int pin, unsigned int reg) -+{ -+ const struct intel_community *community; -+ unsigned int padno; -+ size_t nregs; -+ -+ community = intel_get_community(pctrl, pin); -+ if (!community) -+ return NULL; -+ -+ padno = pin_to_padno(community, pin); -+ nregs = (community->features & PINCTRL_FEATURE_DEBOUNCE) ? 4 : 2; -+ -+ if (reg >= nregs * 4) -+ return NULL; -+ -+ return community->pad_regs + reg + padno * nregs * 4; -+} -+ -+static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned int pin) -+{ -+ const struct intel_community *community; -+ const struct intel_padgroup *padgrp; -+ unsigned int gpp, offset, gpp_offset; -+ void __iomem *padown; -+ -+ community = intel_get_community(pctrl, pin); -+ if (!community) -+ return false; -+ if (!community->padown_offset) -+ return true; -+ -+ padgrp = intel_community_get_padgroup(community, pin); -+ if (!padgrp) -+ return false; -+ -+ gpp_offset = padgroup_offset(padgrp, pin); -+ gpp = PADOWN_GPP(gpp_offset); -+ offset = community->padown_offset + padgrp->padown_num * 4 + gpp * 4; -+ padown = community->regs + offset; -+ -+ return !(readl(padown) & PADOWN_MASK(gpp_offset)); -+} -+ -+static bool intel_pad_set_acpi_mode(struct intel_pinctrl *pctrl, -+ unsigned pin, bool acpi_mode) -+{ -+ const struct intel_community *community; -+ const struct intel_padgroup *padgrp; -+ unsigned int offset, gpp_offset; -+ void __iomem *hostown; -+ uint32_t value; -+ -+ community = intel_get_community(pctrl, pin); -+ if (!community) -+ return true; -+ if (!community->hostown_offset) -+ return false; -+ -+ padgrp = intel_community_get_padgroup(community, pin); -+ if (!padgrp) -+ return true; -+ -+ gpp_offset = padgroup_offset(padgrp, pin); -+ offset = community->hostown_offset + padgrp->reg_num * 4; -+ hostown = community->regs + offset; -+ -+ value = readl(hostown); -+ if (acpi_mode) { -+ /* ACPI mode */ -+ value &= ~BIT(gpp_offset); -+ } else { -+ /* GPIO mode */ -+ value |= BIT(gpp_offset); -+ } -+ -+ writel(value, hostown); -+ -+ return !(readl(hostown) & BIT(gpp_offset)); -+} -+ -+static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned int pin) -+{ -+ const struct intel_community *community; -+ const struct intel_padgroup *padgrp; -+ unsigned int offset, gpp_offset; -+ void __iomem *hostown; -+ -+ community = intel_get_community(pctrl, pin); -+ if (!community) -+ return true; -+ if (!community->hostown_offset) -+ return false; -+ -+ padgrp = intel_community_get_padgroup(community, pin); -+ if (!padgrp) -+ return true; -+ -+ gpp_offset = padgroup_offset(padgrp, pin); -+ offset = community->hostown_offset + padgrp->reg_num * 4; -+ hostown = community->regs + offset; -+ -+ return !(readl(hostown) & BIT(gpp_offset)); -+} -+ -+/** -+ * enum - Locking variants of the pad configuration -+ * -+ * @PAD_UNLOCKED: pad is fully controlled by the configuration registers -+ * @PAD_LOCKED: pad configuration registers, except TX state, are locked -+ * @PAD_LOCKED_TX: pad configuration TX state is locked -+ * @PAD_LOCKED_FULL: pad configuration registers are locked completely -+ * -+ * Locking is considered as read-only mode for corresponding registers and -+ * their respective fields. That said, TX state bit is locked separately from -+ * the main locking scheme. -+ */ -+enum { -+ PAD_UNLOCKED = 0, -+ PAD_LOCKED = 1, -+ PAD_LOCKED_TX = 2, -+ PAD_LOCKED_FULL = PAD_LOCKED | PAD_LOCKED_TX, -+}; -+ -+static int intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin) -+{ -+ struct intel_community *community; -+ const struct intel_padgroup *padgrp; -+ unsigned int offset, gpp_offset; -+ u32 value; -+ int ret = PAD_UNLOCKED; -+ -+ community = intel_get_community(pctrl, pin); -+ if (!community) -+ return PAD_LOCKED_FULL; -+ if (!community->padcfglock_offset) -+ return PAD_UNLOCKED; -+ -+ padgrp = intel_community_get_padgroup(community, pin); -+ if (!padgrp) -+ return PAD_LOCKED_FULL; -+ -+ gpp_offset = padgroup_offset(padgrp, pin); -+ -+ /* -+ * If PADCFGLOCK and PADCFGLOCKTX bits are both clear for this pad, -+ * the pad is considered unlocked. Any other case means that it is -+ * either fully or partially locked. -+ */ -+ offset = community->padcfglock_offset + 0 + padgrp->reg_num * 8; -+ value = readl(community->regs + offset); -+ if (value & BIT(gpp_offset)) -+ ret |= PAD_LOCKED; -+ -+ offset = community->padcfglock_offset + 4 + padgrp->reg_num * 8; -+ value = readl(community->regs + offset); -+ if (value & BIT(gpp_offset)) -+ ret |= PAD_LOCKED_TX; -+ -+ return ret; -+} -+ -+static bool intel_pad_is_unlocked(struct intel_pinctrl *pctrl, unsigned int pin) -+{ -+ return (intel_pad_locked(pctrl, pin) & PAD_LOCKED) == PAD_UNLOCKED; -+} -+ -+static bool intel_pad_usable(struct intel_pinctrl *pctrl, unsigned int pin) -+{ -+ return intel_pad_owned_by_host(pctrl, pin) && intel_pad_is_unlocked(pctrl, pin); -+} -+ -+static int intel_get_groups_count(struct pinctrl_dev *pctldev) -+{ -+ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); -+ -+ return pctrl->soc->ngroups; -+} -+ -+static const char *intel_get_group_name(struct pinctrl_dev *pctldev, -+ unsigned int group) -+{ -+ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); -+ -+ return pctrl->soc->groups[group].name; -+} -+ -+static int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group, -+ const unsigned int **pins, unsigned int *npins) -+{ -+ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); -+ -+ *pins = pctrl->soc->groups[group].pins; -+ *npins = pctrl->soc->groups[group].npins; -+ return 0; -+} -+ -+static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, -+ unsigned int pin) -+{ -+ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); -+ void __iomem *padcfg; -+ u32 cfg0, cfg1, mode; -+ int locked; -+ bool acpi; -+ -+ if (!intel_pad_owned_by_host(pctrl, pin)) { -+ seq_puts(s, "not available"); -+ return; -+ } -+ -+ cfg0 = readl(intel_get_padcfg(pctrl, pin, PADCFG0)); -+ cfg1 = readl(intel_get_padcfg(pctrl, pin, PADCFG1)); -+ -+ mode = (cfg0 & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT; -+ if (mode == PADCFG0_PMODE_GPIO) -+ seq_puts(s, "GPIO "); -+ else -+ seq_printf(s, "mode %d ", mode); -+ -+ seq_printf(s, "0x%08x 0x%08x", cfg0, cfg1); -+ -+ /* Dump the additional PADCFG registers if available */ -+ padcfg = intel_get_padcfg(pctrl, pin, PADCFG2); -+ if (padcfg) -+ seq_printf(s, " 0x%08x", readl(padcfg)); -+ -+ locked = intel_pad_locked(pctrl, pin); -+ acpi = intel_pad_acpi_mode(pctrl, pin); -+ -+ if (locked || acpi) { -+ seq_puts(s, " ["); -+ if (locked) -+ seq_puts(s, "LOCKED"); -+ if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_TX) -+ seq_puts(s, " tx"); -+ else if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_FULL) -+ seq_puts(s, " full"); -+ -+ if (locked && acpi) -+ seq_puts(s, ", "); -+ -+ if (acpi) -+ seq_puts(s, "ACPI"); -+ seq_puts(s, "]"); -+ } -+} -+ -+static const struct pinctrl_ops intel_pinctrl_ops = { -+ .get_groups_count = intel_get_groups_count, -+ .get_group_name = intel_get_group_name, -+ .get_group_pins = intel_get_group_pins, -+ .pin_dbg_show = intel_pin_dbg_show, -+}; -+ -+static int intel_get_functions_count(struct pinctrl_dev *pctldev) -+{ -+ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); -+ -+ return pctrl->soc->nfunctions; -+} -+ -+static const char *intel_get_function_name(struct pinctrl_dev *pctldev, -+ unsigned int function) -+{ -+ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); -+ -+ return pctrl->soc->functions[function].name; -+} -+ -+static int intel_get_function_groups(struct pinctrl_dev *pctldev, -+ unsigned int function, -+ const char * const **groups, -+ unsigned int * const ngroups) -+{ -+ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); -+ -+ *groups = pctrl->soc->functions[function].groups; -+ *ngroups = pctrl->soc->functions[function].ngroups; -+ return 0; -+} -+ -+static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, -+ unsigned int function, unsigned int group) -+{ -+ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); -+ const struct intel_pingroup *grp = &pctrl->soc->groups[group]; -+ unsigned long flags; -+ int i; -+ -+ raw_spin_lock_irqsave(&pctrl->lock, flags); -+ -+ /* -+ * All pins in the groups needs to be accessible and writable -+ * before we can enable the mux for this group. -+ */ -+ for (i = 0; i < grp->npins; i++) { -+ if (!intel_pad_usable(pctrl, grp->pins[i])) { -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ return -EBUSY; -+ } -+ } -+ -+ /* Now enable the mux setting for each pin in the group */ -+ for (i = 0; i < grp->npins; i++) { -+ void __iomem *padcfg0; -+ u32 value; -+ -+ padcfg0 = intel_get_padcfg(pctrl, grp->pins[i], PADCFG0); -+ value = readl(padcfg0); -+ -+ value &= ~PADCFG0_PMODE_MASK; -+ -+ if (grp->modes) -+ value |= grp->modes[i] << PADCFG0_PMODE_SHIFT; -+ else -+ value |= grp->mode << PADCFG0_PMODE_SHIFT; -+ -+ writel(value, padcfg0); -+ } -+ -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ -+ return 0; -+} -+ -+static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input) -+{ -+ u32 value; -+ -+ value = readl(padcfg0); -+ if (input) { -+ value &= ~PADCFG0_GPIORXDIS; -+ value |= PADCFG0_GPIOTXDIS; -+ } else { -+ value &= ~PADCFG0_GPIOTXDIS; -+ value |= PADCFG0_GPIORXDIS; -+ } -+ writel(value, padcfg0); -+} -+ -+static int intel_gpio_get_gpio_mode(void __iomem *padcfg0) -+{ -+ return (readl(padcfg0) & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT; -+} -+ -+static void intel_gpio_set_gpio_mode(void __iomem *padcfg0) -+{ -+ u32 value; -+ -+ value = readl(padcfg0); -+ -+ /* Put the pad into GPIO mode */ -+ value &= ~PADCFG0_PMODE_MASK; -+ value |= PADCFG0_PMODE_GPIO; -+ -+ /* Disable input and output buffers */ -+ value |= PADCFG0_GPIORXDIS; -+ value |= PADCFG0_GPIOTXDIS; -+ -+ /* Disable SCI/SMI/NMI generation */ -+ value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI); -+ value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI); -+ -+ writel(value, padcfg0); -+} -+ -+static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, -+ struct pinctrl_gpio_range *range, -+ unsigned int pin) -+{ -+ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); -+ void __iomem *padcfg0; -+ unsigned long flags; -+ -+ padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); -+ -+ raw_spin_lock_irqsave(&pctrl->lock, flags); -+ -+ if (!intel_pad_owned_by_host(pctrl, pin)) { -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ return -EBUSY; -+ } -+ -+ if (!intel_pad_is_unlocked(pctrl, pin)) { -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ return 0; -+ } -+ -+ /* -+ * If pin is already configured in GPIO mode, we assume that -+ * firmware provides correct settings. In such case we avoid -+ * potential glitches on the pin. Otherwise, for the pin in -+ * alternative mode, consumer has to supply respective flags. -+ */ -+ if (intel_gpio_get_gpio_mode(padcfg0) == PADCFG0_PMODE_GPIO) { -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ return 0; -+ } -+ -+ intel_gpio_set_gpio_mode(padcfg0); -+ -+ /* Disable TX buffer and enable RX (this will be input) */ -+ __intel_gpio_set_direction(padcfg0, true); -+ -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ -+ return 0; -+} -+ -+static int intel_gpio_set_direction(struct pinctrl_dev *pctldev, -+ struct pinctrl_gpio_range *range, -+ unsigned int pin, bool input) -+{ -+ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); -+ void __iomem *padcfg0; -+ unsigned long flags; -+ -+ padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); -+ -+ raw_spin_lock_irqsave(&pctrl->lock, flags); -+ __intel_gpio_set_direction(padcfg0, input); -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ -+ return 0; -+} -+ -+static const struct pinmux_ops intel_pinmux_ops = { -+ .get_functions_count = intel_get_functions_count, -+ .get_function_name = intel_get_function_name, -+ .get_function_groups = intel_get_function_groups, -+ .set_mux = intel_pinmux_set_mux, -+ .gpio_request_enable = intel_gpio_request_enable, -+ .gpio_set_direction = intel_gpio_set_direction, -+}; -+ -+static int intel_config_get_pull(struct intel_pinctrl *pctrl, unsigned int pin, -+ enum pin_config_param param, u32 *arg) -+{ -+ const struct intel_community *community; -+ void __iomem *padcfg1; -+ unsigned long flags; -+ u32 value, term; -+ -+ community = intel_get_community(pctrl, pin); -+ padcfg1 = intel_get_padcfg(pctrl, pin, PADCFG1); -+ -+ raw_spin_lock_irqsave(&pctrl->lock, flags); -+ value = readl(padcfg1); -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ -+ term = (value & PADCFG1_TERM_MASK) >> PADCFG1_TERM_SHIFT; -+ -+ switch (param) { -+ case PIN_CONFIG_BIAS_DISABLE: -+ if (term) -+ return -EINVAL; -+ break; -+ -+ case PIN_CONFIG_BIAS_PULL_UP: -+ if (!term || !(value & PADCFG1_TERM_UP)) -+ return -EINVAL; -+ -+ switch (term) { -+ case PADCFG1_TERM_833: -+ *arg = 833; -+ break; -+ case PADCFG1_TERM_1K: -+ *arg = 1000; -+ break; -+ case PADCFG1_TERM_5K: -+ *arg = 5000; -+ break; -+ case PADCFG1_TERM_20K: -+ *arg = 20000; -+ break; -+ } -+ -+ break; -+ -+ case PIN_CONFIG_BIAS_PULL_DOWN: -+ if (!term || value & PADCFG1_TERM_UP) -+ return -EINVAL; -+ -+ switch (term) { -+ case PADCFG1_TERM_833: -+ if (!(community->features & PINCTRL_FEATURE_1K_PD)) -+ return -EINVAL; -+ *arg = 833; -+ break; -+ case PADCFG1_TERM_1K: -+ if (!(community->features & PINCTRL_FEATURE_1K_PD)) -+ return -EINVAL; -+ *arg = 1000; -+ break; -+ case PADCFG1_TERM_5K: -+ *arg = 5000; -+ break; -+ case PADCFG1_TERM_20K: -+ *arg = 20000; -+ break; -+ } -+ -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int intel_config_get_debounce(struct intel_pinctrl *pctrl, unsigned int pin, -+ enum pin_config_param param, u32 *arg) -+{ -+ void __iomem *padcfg2; -+ unsigned long flags; -+ unsigned long v; -+ u32 value2; -+ -+ padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2); -+ if (!padcfg2) -+ return -ENOTSUPP; -+ -+ raw_spin_lock_irqsave(&pctrl->lock, flags); -+ value2 = readl(padcfg2); -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ if (!(value2 & PADCFG2_DEBEN)) -+ return -EINVAL; -+ -+ v = (value2 & PADCFG2_DEBOUNCE_MASK) >> PADCFG2_DEBOUNCE_SHIFT; -+ *arg = BIT(v) * DEBOUNCE_PERIOD_NSEC / NSEC_PER_USEC; -+ -+ return 0; -+} -+ -+static int intel_config_get(struct pinctrl_dev *pctldev, unsigned int pin, -+ unsigned long *config) -+{ -+ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); -+ enum pin_config_param param = pinconf_to_config_param(*config); -+ u32 arg = 0; -+ int ret; -+ -+ if (!intel_pad_owned_by_host(pctrl, pin)) -+ return -ENOTSUPP; -+ -+ switch (param) { -+ case PIN_CONFIG_BIAS_DISABLE: -+ case PIN_CONFIG_BIAS_PULL_UP: -+ case PIN_CONFIG_BIAS_PULL_DOWN: -+ ret = intel_config_get_pull(pctrl, pin, param, &arg); -+ if (ret) -+ return ret; -+ break; -+ -+ case PIN_CONFIG_INPUT_DEBOUNCE: -+ ret = intel_config_get_debounce(pctrl, pin, param, &arg); -+ if (ret) -+ return ret; -+ break; -+ -+ default: -+ return -ENOTSUPP; -+ } -+ -+ *config = pinconf_to_config_packed(param, arg); -+ return 0; -+} -+ -+static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin, -+ unsigned long config) -+{ -+ unsigned int param = pinconf_to_config_param(config); -+ unsigned int arg = pinconf_to_config_argument(config); -+ const struct intel_community *community; -+ void __iomem *padcfg1; -+ unsigned long flags; -+ int ret = 0; -+ u32 value; -+ -+ community = intel_get_community(pctrl, pin); -+ padcfg1 = intel_get_padcfg(pctrl, pin, PADCFG1); -+ -+ raw_spin_lock_irqsave(&pctrl->lock, flags); -+ -+ value = readl(padcfg1); -+ -+ switch (param) { -+ case PIN_CONFIG_BIAS_DISABLE: -+ value &= ~(PADCFG1_TERM_MASK | PADCFG1_TERM_UP); -+ break; -+ -+ case PIN_CONFIG_BIAS_PULL_UP: -+ value &= ~PADCFG1_TERM_MASK; -+ -+ value |= PADCFG1_TERM_UP; -+ -+ /* Set default strength value in case none is given */ -+ if (arg == 1) -+ arg = 5000; -+ -+ switch (arg) { -+ case 20000: -+ value |= PADCFG1_TERM_20K << PADCFG1_TERM_SHIFT; -+ break; -+ case 5000: -+ value |= PADCFG1_TERM_5K << PADCFG1_TERM_SHIFT; -+ break; -+ case 1000: -+ value |= PADCFG1_TERM_1K << PADCFG1_TERM_SHIFT; -+ break; -+ case 833: -+ value |= PADCFG1_TERM_833 << PADCFG1_TERM_SHIFT; -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ -+ break; -+ -+ case PIN_CONFIG_BIAS_PULL_DOWN: -+ value &= ~(PADCFG1_TERM_UP | PADCFG1_TERM_MASK); -+ -+ /* Set default strength value in case none is given */ -+ if (arg == 1) -+ arg = 5000; -+ -+ switch (arg) { -+ case 20000: -+ value |= PADCFG1_TERM_20K << PADCFG1_TERM_SHIFT; -+ break; -+ case 5000: -+ value |= PADCFG1_TERM_5K << PADCFG1_TERM_SHIFT; -+ break; -+ case 1000: -+ if (!(community->features & PINCTRL_FEATURE_1K_PD)) { -+ ret = -EINVAL; -+ break; -+ } -+ value |= PADCFG1_TERM_1K << PADCFG1_TERM_SHIFT; -+ break; -+ case 833: -+ if (!(community->features & PINCTRL_FEATURE_1K_PD)) { -+ ret = -EINVAL; -+ break; -+ } -+ value |= PADCFG1_TERM_833 << PADCFG1_TERM_SHIFT; -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ -+ break; -+ } -+ -+ if (!ret) -+ writel(value, padcfg1); -+ -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ -+ return ret; -+} -+ -+static int intel_config_set_debounce(struct intel_pinctrl *pctrl, -+ unsigned int pin, unsigned int debounce) -+{ -+ void __iomem *padcfg0, *padcfg2; -+ unsigned long flags; -+ u32 value0, value2; -+ -+ padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2); -+ if (!padcfg2) -+ return -ENOTSUPP; -+ -+ padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); -+ -+ raw_spin_lock_irqsave(&pctrl->lock, flags); -+ -+ value0 = readl(padcfg0); -+ value2 = readl(padcfg2); -+ -+ /* Disable glitch filter and debouncer */ -+ value0 &= ~PADCFG0_PREGFRXSEL; -+ value2 &= ~(PADCFG2_DEBEN | PADCFG2_DEBOUNCE_MASK); -+ -+ if (debounce) { -+ unsigned long v; -+ -+ v = order_base_2(debounce * NSEC_PER_USEC / DEBOUNCE_PERIOD_NSEC); -+ if (v < 3 || v > 15) { -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ return -EINVAL; -+ } -+ -+ /* Enable glitch filter and debouncer */ -+ value0 |= PADCFG0_PREGFRXSEL; -+ value2 |= v << PADCFG2_DEBOUNCE_SHIFT; -+ value2 |= PADCFG2_DEBEN; -+ } -+ -+ writel(value0, padcfg0); -+ writel(value2, padcfg2); -+ -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ -+ return 0; -+} -+ -+static int intel_config_set(struct pinctrl_dev *pctldev, unsigned int pin, -+ unsigned long *configs, unsigned int nconfigs) -+{ -+ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); -+ int i, ret; -+ -+ if (!intel_pad_usable(pctrl, pin)) -+ return -ENOTSUPP; -+ -+ for (i = 0; i < nconfigs; i++) { -+ switch (pinconf_to_config_param(configs[i])) { -+ case PIN_CONFIG_BIAS_DISABLE: -+ case PIN_CONFIG_BIAS_PULL_UP: -+ case PIN_CONFIG_BIAS_PULL_DOWN: -+ ret = intel_config_set_pull(pctrl, pin, configs[i]); -+ if (ret) -+ return ret; -+ break; -+ -+ case PIN_CONFIG_INPUT_DEBOUNCE: -+ ret = intel_config_set_debounce(pctrl, pin, -+ pinconf_to_config_argument(configs[i])); -+ if (ret) -+ return ret; -+ break; -+ -+ default: -+ return -ENOTSUPP; -+ } -+ } -+ -+ return 0; -+} -+ -+static const struct pinconf_ops intel_pinconf_ops = { -+ .is_generic = true, -+ .pin_config_get = intel_config_get, -+ .pin_config_set = intel_config_set, -+}; -+ -+static const struct pinctrl_desc intel_pinctrl_desc = { -+ .pctlops = &intel_pinctrl_ops, -+ .pmxops = &intel_pinmux_ops, -+ .confops = &intel_pinconf_ops, -+ .owner = THIS_MODULE, -+}; -+ -+/** -+ * intel_gpio_to_pin() - Translate from GPIO offset to pin number -+ * @pctrl: Pinctrl structure -+ * @offset: GPIO offset from gpiolib -+ * @community: Community is filled here if not %NULL -+ * @padgrp: Pad group is filled here if not %NULL -+ * -+ * When coming through gpiolib irqchip, the GPIO offset is not -+ * automatically translated to pinctrl pin number. This function can be -+ * used to find out the corresponding pinctrl pin. -+ */ -+static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned int offset, -+ const struct intel_community **community, -+ const struct intel_padgroup **padgrp) -+{ -+ int i; -+ -+ for (i = 0; i < pctrl->ncommunities; i++) { -+ const struct intel_community *comm = &pctrl->communities[i]; -+ int j; -+ -+ for (j = 0; j < comm->ngpps; j++) { -+ const struct intel_padgroup *pgrp = &comm->gpps[j]; -+ -+ if (pgrp->gpio_base == INTEL_GPIO_BASE_NOMAP) -+ continue; -+ -+ if (offset >= pgrp->gpio_base && -+ offset < pgrp->gpio_base + pgrp->size) { -+ int pin; -+ -+ pin = pgrp->base + offset - pgrp->gpio_base; -+ if (community) -+ *community = comm; -+ if (padgrp) -+ *padgrp = pgrp; -+ -+ return pin; -+ } -+ } -+ } -+ -+ return -EINVAL; -+} -+ -+/** -+ * intel_pin_to_gpio() - Translate from pin number to GPIO offset -+ * @pctrl: Pinctrl structure -+ * @pin: pin number -+ * -+ * Translate the pin number of pinctrl to GPIO offset -+ */ -+static __maybe_unused int intel_pin_to_gpio(struct intel_pinctrl *pctrl, int pin) -+{ -+ const struct intel_community *community; -+ const struct intel_padgroup *padgrp; -+ -+ community = intel_get_community(pctrl, pin); -+ if (!community) -+ return -EINVAL; -+ -+ padgrp = intel_community_get_padgroup(community, pin); -+ if (!padgrp) -+ return -EINVAL; -+ -+ return pin - padgrp->base + padgrp->gpio_base; -+} -+ -+static int intel_gpio_get(struct gpio_chip *chip, unsigned int offset) -+{ -+ struct intel_pinctrl *pctrl = gpiochip_get_data(chip); -+ void __iomem *reg; -+ u32 padcfg0; -+ int pin; -+ -+ pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL); -+ if (pin < 0) -+ return -EINVAL; -+ -+ reg = intel_get_padcfg(pctrl, pin, PADCFG0); -+ if (!reg) -+ return -EINVAL; -+ -+ padcfg0 = readl(reg); -+ if (!(padcfg0 & PADCFG0_GPIOTXDIS)) -+ return !!(padcfg0 & PADCFG0_GPIOTXSTATE); -+ -+ return !!(padcfg0 & PADCFG0_GPIORXSTATE); -+} -+ -+static void intel_gpio_set(struct gpio_chip *chip, unsigned int offset, -+ int value) -+{ -+ struct intel_pinctrl *pctrl = gpiochip_get_data(chip); -+ unsigned long flags; -+ void __iomem *reg; -+ u32 padcfg0; -+ int pin; -+ -+ pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL); -+ if (pin < 0) -+ return; -+ -+ reg = intel_get_padcfg(pctrl, pin, PADCFG0); -+ if (!reg) -+ return; -+ -+ raw_spin_lock_irqsave(&pctrl->lock, flags); -+ padcfg0 = readl(reg); -+ if (value) -+ padcfg0 |= PADCFG0_GPIOTXSTATE; -+ else -+ padcfg0 &= ~PADCFG0_GPIOTXSTATE; -+ writel(padcfg0, reg); -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+} -+ -+static int intel_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) -+{ -+ struct intel_pinctrl *pctrl = gpiochip_get_data(chip); -+ unsigned long flags; -+ void __iomem *reg; -+ u32 padcfg0; -+ int pin; -+ -+ pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL); -+ if (pin < 0) -+ return -EINVAL; -+ -+ reg = intel_get_padcfg(pctrl, pin, PADCFG0); -+ if (!reg) -+ return -EINVAL; -+ -+ raw_spin_lock_irqsave(&pctrl->lock, flags); -+ padcfg0 = readl(reg); -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ if (padcfg0 & PADCFG0_PMODE_MASK) -+ return -EINVAL; -+ -+ if (padcfg0 & PADCFG0_GPIOTXDIS) -+ return GPIO_LINE_DIRECTION_IN; -+ -+ return GPIO_LINE_DIRECTION_OUT; -+} -+ -+static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) -+{ -+ return pinctrl_gpio_direction_input(chip->base + offset); -+} -+ -+static int intel_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, -+ int value) -+{ -+ intel_gpio_set(chip, offset, value); -+ return pinctrl_gpio_direction_output(chip->base + offset); -+} -+ -+static const struct gpio_chip intel_gpio_chip = { -+ .owner = THIS_MODULE, -+ .request = gpiochip_generic_request, -+ .free = gpiochip_generic_free, -+ .get_direction = intel_gpio_get_direction, -+ .direction_input = intel_gpio_direction_input, -+ .direction_output = intel_gpio_direction_output, -+ .get = intel_gpio_get, -+ .set = intel_gpio_set, -+ .set_config = gpiochip_generic_config, -+}; -+ -+static void intel_gpio_irq_ack(struct irq_data *d) -+{ -+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); -+ struct intel_pinctrl *pctrl = gpiochip_get_data(gc); -+ const struct intel_community *community; -+ const struct intel_padgroup *padgrp; -+ int pin; -+ -+ pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); -+ if (pin >= 0) { -+ unsigned int gpp, gpp_offset, is_offset; -+ -+ gpp = padgrp->reg_num; -+ gpp_offset = padgroup_offset(padgrp, pin); -+ is_offset = community->is_offset + gpp * 4; -+ -+ raw_spin_lock(&pctrl->lock); -+ writel(BIT(gpp_offset), community->regs + is_offset); -+ raw_spin_unlock(&pctrl->lock); -+ } -+} -+ -+static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask) -+{ -+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); -+ struct intel_pinctrl *pctrl = gpiochip_get_data(gc); -+ const struct intel_community *community; -+ const struct intel_padgroup *padgrp; -+ int pin; -+ -+ pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); -+ if (pin >= 0) { -+ unsigned int gpp, gpp_offset; -+ unsigned long flags; -+ void __iomem *reg, *is; -+ u32 value; -+ -+ gpp = padgrp->reg_num; -+ gpp_offset = padgroup_offset(padgrp, pin); -+ -+ reg = community->regs + community->ie_offset + gpp * 4; -+ is = community->regs + community->is_offset + gpp * 4; -+ -+ raw_spin_lock_irqsave(&pctrl->lock, flags); -+ -+ /* Clear interrupt status first to avoid unexpected interrupt */ -+ writel(BIT(gpp_offset), is); -+ -+ value = readl(reg); -+ if (mask) -+ value &= ~BIT(gpp_offset); -+ else -+ value |= BIT(gpp_offset); -+ writel(value, reg); -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ } -+} -+ -+static void intel_gpio_irq_mask(struct irq_data *d) -+{ -+ intel_gpio_irq_mask_unmask(d, true); -+} -+ -+static void intel_gpio_irq_unmask(struct irq_data *d) -+{ -+ intel_gpio_irq_mask_unmask(d, false); -+} -+ -+static int intel_gpio_irq_type(struct irq_data *d, unsigned int type) -+{ -+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); -+ struct intel_pinctrl *pctrl = gpiochip_get_data(gc); -+ unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); -+ unsigned long flags; -+ void __iomem *reg; -+ u32 value; -+ -+ reg = intel_get_padcfg(pctrl, pin, PADCFG0); -+ if (!reg) -+ return -EINVAL; -+ -+ /* set not ACPI mode */ -+ intel_pad_set_acpi_mode(pctrl, pin, false); -+ -+ /* -+ * If the pin is in ACPI mode it is still usable as a GPIO but it -+ * cannot be used as IRQ because GPI_IS status bit will not be -+ * updated by the host controller hardware. -+ */ -+ if (intel_pad_acpi_mode(pctrl, pin)) { -+ dev_warn(pctrl->dev, "pin %u cannot be used as IRQ\n", pin); -+ return -EPERM; -+ } -+ -+ raw_spin_lock_irqsave(&pctrl->lock, flags); -+ -+ intel_gpio_set_gpio_mode(reg); -+ -+ /* Disable TX buffer and enable RX (this will be input) */ -+ __intel_gpio_set_direction(reg, true); -+ -+ value = readl(reg); -+ -+ value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV); -+ -+ if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { -+ value |= PADCFG0_RXEVCFG_EDGE_BOTH << PADCFG0_RXEVCFG_SHIFT; -+ } else if (type & IRQ_TYPE_EDGE_FALLING) { -+ value |= PADCFG0_RXEVCFG_EDGE << PADCFG0_RXEVCFG_SHIFT; -+ value |= PADCFG0_RXINV; -+ } else if (type & IRQ_TYPE_EDGE_RISING) { -+ value |= PADCFG0_RXEVCFG_EDGE << PADCFG0_RXEVCFG_SHIFT; -+ } else if (type & IRQ_TYPE_LEVEL_MASK) { -+ if (type & IRQ_TYPE_LEVEL_LOW) -+ value |= PADCFG0_RXINV; -+ } else { -+ value |= PADCFG0_RXEVCFG_DISABLED << PADCFG0_RXEVCFG_SHIFT; -+ } -+ -+ writel(value, reg); -+ -+ if (type & IRQ_TYPE_EDGE_BOTH) -+ irq_set_handler_locked(d, handle_edge_irq); -+ else if (type & IRQ_TYPE_LEVEL_MASK) -+ irq_set_handler_locked(d, handle_level_irq); -+ -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ -+ return 0; -+} -+ -+static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on) -+{ -+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); -+ struct intel_pinctrl *pctrl = gpiochip_get_data(gc); -+ unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); -+ -+ if (on) -+ enable_irq_wake(pctrl->irq); -+ else -+ disable_irq_wake(pctrl->irq); -+ -+ dev_dbg(pctrl->dev, "%sable wake for pin %u\n", on ? "en" : "dis", pin); -+ return 0; -+} -+ -+static int intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl, -+ const struct intel_community *community) -+{ -+ struct gpio_chip *gc = &pctrl->chip; -+ unsigned int gpp; -+ int ret = 0; -+ -+ for (gpp = 0; gpp < community->ngpps; gpp++) { -+ const struct intel_padgroup *padgrp = &community->gpps[gpp]; -+ unsigned long pending, enabled, gpp_offset; -+ unsigned long flags; -+ -+ raw_spin_lock_irqsave(&pctrl->lock, flags); -+ -+ pending = readl(community->regs + community->is_offset + -+ padgrp->reg_num * 4); -+ enabled = readl(community->regs + community->ie_offset + -+ padgrp->reg_num * 4); -+ -+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); -+ -+ /* Only interrupts that are enabled */ -+ pending &= enabled; -+ -+ for_each_set_bit(gpp_offset, &pending, padgrp->size) { -+ unsigned int irq; -+ -+ irq = irq_find_mapping(gc->irq.domain, -+ padgrp->gpio_base + gpp_offset); -+ generic_handle_irq(irq); -+ } -+ -+ ret += pending ? 1 : 0; -+ } -+ -+ return ret; -+} -+ -+static irqreturn_t intel_gpio_irq(int irq, void *data) -+{ -+ const struct intel_community *community; -+ struct intel_pinctrl *pctrl = data; -+ unsigned int i; -+ int ret = 0; -+ -+ /* Need to check all communities for pending interrupts */ -+ for (i = 0; i < pctrl->ncommunities; i++) { -+ community = &pctrl->communities[i]; -+ ret += intel_gpio_community_irq_handler(pctrl, community); -+ } -+ -+ return IRQ_RETVAL(ret); -+} -+ -+static int intel_gpio_add_community_ranges(struct intel_pinctrl *pctrl, -+ const struct intel_community *community) -+{ -+ int ret = 0, i; -+ -+ for (i = 0; i < community->ngpps; i++) { -+ const struct intel_padgroup *gpp = &community->gpps[i]; -+ -+ if (gpp->gpio_base == INTEL_GPIO_BASE_NOMAP) -+ continue; -+ -+ ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), -+ gpp->gpio_base, gpp->base, -+ gpp->size); -+ if (ret) -+ return ret; -+ } -+ -+ return ret; -+} -+ -+static int intel_gpio_add_pin_ranges(struct gpio_chip *gc) -+{ -+ struct intel_pinctrl *pctrl = gpiochip_get_data(gc); -+ int ret, i; -+ -+ for (i = 0; i < pctrl->ncommunities; i++) { -+ struct intel_community *community = &pctrl->communities[i]; -+ -+ ret = intel_gpio_add_community_ranges(pctrl, community); -+ if (ret) { -+ dev_err(pctrl->dev, "failed to add GPIO pin range\n"); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static unsigned int intel_gpio_ngpio(const struct intel_pinctrl *pctrl) -+{ -+ const struct intel_community *community; -+ unsigned int ngpio = 0; -+ int i, j; -+ -+ for (i = 0; i < pctrl->ncommunities; i++) { -+ community = &pctrl->communities[i]; -+ for (j = 0; j < community->ngpps; j++) { -+ const struct intel_padgroup *gpp = &community->gpps[j]; -+ -+ if (gpp->gpio_base == INTEL_GPIO_BASE_NOMAP) -+ continue; -+ -+ if (gpp->gpio_base + gpp->size > ngpio) -+ ngpio = gpp->gpio_base + gpp->size; -+ } -+ } -+ -+ return ngpio; -+} -+ -+static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq) -+{ -+ int ret; -+ struct gpio_irq_chip *girq; -+ -+ pctrl->chip = intel_gpio_chip; -+ -+ /* Setup GPIO chip */ -+ pctrl->chip.ngpio = intel_gpio_ngpio(pctrl); -+ pctrl->chip.label = dev_name(pctrl->dev); -+ pctrl->chip.parent = pctrl->dev; -+ pctrl->chip.base = 0; -+ pctrl->chip.add_pin_ranges = intel_gpio_add_pin_ranges; -+ pctrl->irq = irq; -+ -+ /* Setup IRQ chip */ -+ pctrl->irqchip.name = dev_name(pctrl->dev); -+ pctrl->irqchip.irq_ack = intel_gpio_irq_ack; -+ pctrl->irqchip.irq_mask = intel_gpio_irq_mask; -+ pctrl->irqchip.irq_unmask = intel_gpio_irq_unmask; -+ pctrl->irqchip.irq_set_type = intel_gpio_irq_type; -+ pctrl->irqchip.irq_set_wake = intel_gpio_irq_wake; -+ pctrl->irqchip.flags = IRQCHIP_MASK_ON_SUSPEND; -+ -+ /* -+ * On some platforms several GPIO controllers share the same interrupt -+ * line. -+ */ -+ ret = devm_request_irq(pctrl->dev, irq, intel_gpio_irq, -+ IRQF_SHARED | IRQF_NO_THREAD, -+ dev_name(pctrl->dev), pctrl); -+ if (ret) { -+ dev_err(pctrl->dev, "failed to request interrupt\n"); -+ return ret; -+ } -+ -+ girq = &pctrl->chip.irq; -+ girq->chip = &pctrl->irqchip; -+ /* This will let us handle the IRQ in the driver */ -+ girq->parent_handler = NULL; -+ girq->num_parents = 0; -+ girq->default_type = IRQ_TYPE_NONE; -+ girq->handler = handle_bad_irq; -+ -+ ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl); -+ if (ret) { -+ dev_err(pctrl->dev, "failed to register gpiochip\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int intel_pinctrl_add_padgroups(struct intel_pinctrl *pctrl, -+ struct intel_community *community) -+{ -+ struct intel_padgroup *gpps; -+ unsigned int npins = community->npins; -+ unsigned int padown_num = 0; -+ size_t ngpps, i; -+ -+ if (community->gpps) -+ ngpps = community->ngpps; -+ else -+ ngpps = DIV_ROUND_UP(community->npins, community->gpp_size); -+ -+ gpps = devm_kcalloc(pctrl->dev, ngpps, sizeof(*gpps), GFP_KERNEL); -+ if (!gpps) -+ return -ENOMEM; -+ -+ for (i = 0; i < ngpps; i++) { -+ if (community->gpps) { -+ gpps[i] = community->gpps[i]; -+ } else { -+ unsigned int gpp_size = community->gpp_size; -+ -+ gpps[i].reg_num = i; -+ gpps[i].base = community->pin_base + i * gpp_size; -+ gpps[i].size = min(gpp_size, npins); -+ npins -= gpps[i].size; -+ } -+ -+ if (gpps[i].size > 32) -+ return -EINVAL; -+ -+ /* Special treatment for GPIO base */ -+ switch (gpps[i].gpio_base) { -+ case INTEL_GPIO_BASE_MATCH: -+ gpps[i].gpio_base = gpps[i].base; -+ break; -+ case INTEL_GPIO_BASE_ZERO: -+ gpps[i].gpio_base = 0; -+ break; -+ case INTEL_GPIO_BASE_NOMAP: -+ default: -+ break; -+ } -+ -+ gpps[i].padown_num = padown_num; -+ -+ /* -+ * In older hardware the number of padown registers per -+ * group is fixed regardless of the group size. -+ */ -+ if (community->gpp_num_padown_regs) -+ padown_num += community->gpp_num_padown_regs; -+ else -+ padown_num += DIV_ROUND_UP(gpps[i].size * 4, 32); -+ } -+ -+ community->ngpps = ngpps; -+ community->gpps = gpps; -+ -+ return 0; -+} -+ -+static int intel_pinctrl_pm_init(struct intel_pinctrl *pctrl) -+{ -+#ifdef CONFIG_PM_SLEEP -+ const struct intel_pinctrl_soc_data *soc = pctrl->soc; -+ struct intel_community_context *communities; -+ struct intel_pad_context *pads; -+ int i; -+ -+ pads = devm_kcalloc(pctrl->dev, soc->npins, sizeof(*pads), GFP_KERNEL); -+ if (!pads) -+ return -ENOMEM; -+ -+ communities = devm_kcalloc(pctrl->dev, pctrl->ncommunities, -+ sizeof(*communities), GFP_KERNEL); -+ if (!communities) -+ return -ENOMEM; -+ -+ for (i = 0; i < pctrl->ncommunities; i++) { -+ struct intel_community *community = &pctrl->communities[i]; -+ u32 *intmask, *hostown; -+ -+ intmask = devm_kcalloc(pctrl->dev, community->ngpps, -+ sizeof(*intmask), GFP_KERNEL); -+ if (!intmask) -+ return -ENOMEM; -+ -+ communities[i].intmask = intmask; -+ -+ hostown = devm_kcalloc(pctrl->dev, community->ngpps, -+ sizeof(*hostown), GFP_KERNEL); -+ if (!hostown) -+ return -ENOMEM; -+ -+ communities[i].hostown = hostown; -+ } -+ -+ pctrl->context.pads = pads; -+ pctrl->context.communities = communities; -+#endif -+ -+ return 0; -+} -+ -+int wb_pinctrl_probe(struct platform_device *pdev, -+ const struct intel_pinctrl_soc_data *soc_data) -+{ -+ struct intel_pinctrl *pctrl; -+ struct intel_community *community; -+ wb_gpio_data_t *wb_gpio_data; -+ void __iomem *regs; -+ int i, ret; -+ u32 padbar, rev; -+ -+ if (!soc_data) { -+ dev_err(&pdev->dev, "soc_data is null\n"); -+ return -EINVAL; -+ } -+ -+ wb_gpio_data = platform_get_drvdata(pdev); -+ pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); -+ if (!pctrl) { -+ dev_err(&pdev->dev, "pctrl kzalloc failed\n"); -+ return -ENOMEM; -+ } -+ -+ /* check resource */ -+ if (soc_data->ncommunities > GPIO_RES_MAX) { -+ dev_err(&pdev->dev, "GPIO ncommunities %lu is more than GPIO resource number: %d\n", -+ soc_data->ncommunities, GPIO_RES_MAX); -+ return -EINVAL; -+ } -+ -+ pctrl->dev = &pdev->dev; -+ pctrl->soc = soc_data; -+ pctrl->irq = wb_gpio_data->irq; -+ raw_spin_lock_init(&pctrl->lock); -+ -+ /* -+ * Make a copy of the communities which we can use to hold pointers -+ * to the registers. -+ */ -+ pctrl->ncommunities = pctrl->soc->ncommunities; -+ pctrl->communities = devm_kcalloc(&pdev->dev, pctrl->ncommunities, -+ sizeof(*pctrl->communities), GFP_KERNEL); -+ if (!pctrl->communities) { -+ dev_err(&pdev->dev, "devm_kcalloc communities failed. ret:%d\n", ret); -+ return -ENOMEM; -+ } -+ -+ for (i = 0; i < pctrl->ncommunities; i++) { -+ community = &pctrl->communities[i]; -+ *community = pctrl->soc->communities[i]; -+ -+ regs = wb_gpio_data->res[i]; -+ -+ /* -+ * Determine community features based on the revision if -+ * not specified already. -+ */ -+ if (!community->features) { -+ rev = (readl(regs + REVID) & REVID_MASK) >> REVID_SHIFT; -+ if (rev >= 0x94) { -+ community->features |= PINCTRL_FEATURE_DEBOUNCE; -+ community->features |= PINCTRL_FEATURE_1K_PD; -+ } -+ } -+ -+ /* Read offset of the pad configuration registers */ -+ padbar = readl(regs + PADBAR); -+ -+ community->regs = regs; -+ community->pad_regs = regs + padbar; -+ -+ ret = intel_pinctrl_add_padgroups(pctrl, community); -+ if (ret) { -+ dev_err(&pdev->dev, "intel_pinctrl_add_padgroups failed. ret:%d\n", ret); -+ return ret; -+ } -+ } -+ -+ ret = intel_pinctrl_pm_init(pctrl); -+ if (ret) { -+ dev_err(&pdev->dev, "intel_pinctrl_pm_init failed. ret:%d\n", ret); -+ return ret; -+ } -+ -+ pctrl->pctldesc = intel_pinctrl_desc; -+ pctrl->pctldesc.name = dev_name(&pdev->dev); -+ pctrl->pctldesc.pins = pctrl->soc->pins; -+ pctrl->pctldesc.npins = pctrl->soc->npins; -+ -+ pctrl->pctldev = devm_pinctrl_register(&pdev->dev, &pctrl->pctldesc, -+ pctrl); -+ if (IS_ERR(pctrl->pctldev)) { -+ dev_err(&pdev->dev, "failed to register pinctrl driver\n"); -+ return PTR_ERR(pctrl->pctldev); -+ } -+ -+ ret = intel_gpio_probe(pctrl, pctrl->irq); -+ if (ret) { -+ dev_err(&pdev->dev, "intel_gpio_probe failed. ret:%d\n", ret); -+ return ret; -+ } -+ return 0; -+} -+EXPORT_SYMBOL_GPL(wb_pinctrl_probe); -+ -+#if 0 -+int intel_pinctrl_probe_by_hid(struct platform_device *pdev) -+{ -+ const struct intel_pinctrl_soc_data *data; -+ -+ data = device_get_match_data(&pdev->dev); -+ if (!data) -+ return -ENODATA; -+ -+ return intel_pinctrl_probe(pdev, data); -+} -+EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_hid); -+ -+int intel_pinctrl_probe_by_uid(struct platform_device *pdev) -+{ -+ const struct intel_pinctrl_soc_data *data; -+ -+ data = intel_pinctrl_get_soc_data(pdev); -+ if (IS_ERR(data)) -+ return PTR_ERR(data); -+ -+ return intel_pinctrl_probe(pdev, data); -+} -+EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_uid); -+ -+const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_device *pdev) -+{ -+ const struct intel_pinctrl_soc_data *data = NULL; -+ const struct intel_pinctrl_soc_data **table; -+ struct acpi_device *adev; -+ unsigned int i; -+ -+ adev = ACPI_COMPANION(&pdev->dev); -+ if (adev) { -+ const void *match = device_get_match_data(&pdev->dev); -+ -+ table = (const struct intel_pinctrl_soc_data **)match; -+ for (i = 0; table[i]; i++) { -+ if (!strcmp(adev->pnp.unique_id, table[i]->uid)) { -+ data = table[i]; -+ break; -+ } -+ } -+ } else { -+ const struct platform_device_id *id; -+ -+ id = platform_get_device_id(pdev); -+ if (!id) -+ return ERR_PTR(-ENODEV); -+ -+ table = (const struct intel_pinctrl_soc_data **)id->driver_data; -+ data = table[pdev->id]; -+ } -+ -+ return data ?: ERR_PTR(-ENODATA); -+} -+EXPORT_SYMBOL_GPL(intel_pinctrl_get_soc_data); -+#endif -+ -+#ifdef CONFIG_PM_SLEEP -+static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int pin) -+{ -+ const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin); -+ -+ if (!pd || !intel_pad_usable(pctrl, pin)) -+ return false; -+ -+ /* -+ * Only restore the pin if it is actually in use by the kernel (or -+ * by userspace). It is possible that some pins are used by the -+ * BIOS during resume and those are not always locked down so leave -+ * them alone. -+ */ -+ if (pd->mux_owner || pd->gpio_owner || -+ gpiochip_line_is_irq(&pctrl->chip, intel_pin_to_gpio(pctrl, pin))) -+ return true; -+ -+ return false; -+} -+ -+int wb_intel_pinctrl_suspend_noirq(struct device *dev) -+{ -+ struct intel_pinctrl *pctrl = dev_get_drvdata(dev); -+ struct intel_community_context *communities; -+ struct intel_pad_context *pads; -+ int i; -+ -+ pads = pctrl->context.pads; -+ for (i = 0; i < pctrl->soc->npins; i++) { -+ const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i]; -+ void __iomem *padcfg; -+ u32 val; -+ -+ if (!intel_pinctrl_should_save(pctrl, desc->number)) -+ continue; -+ -+ val = readl(intel_get_padcfg(pctrl, desc->number, PADCFG0)); -+ pads[i].padcfg0 = val & ~PADCFG0_GPIORXSTATE; -+ val = readl(intel_get_padcfg(pctrl, desc->number, PADCFG1)); -+ pads[i].padcfg1 = val; -+ -+ padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG2); -+ if (padcfg) -+ pads[i].padcfg2 = readl(padcfg); -+ } -+ -+ communities = pctrl->context.communities; -+ for (i = 0; i < pctrl->ncommunities; i++) { -+ struct intel_community *community = &pctrl->communities[i]; -+ void __iomem *base; -+ unsigned int gpp; -+ -+ base = community->regs + community->ie_offset; -+ for (gpp = 0; gpp < community->ngpps; gpp++) -+ communities[i].intmask[gpp] = readl(base + gpp * 4); -+ -+ base = community->regs + community->hostown_offset; -+ for (gpp = 0; gpp < community->ngpps; gpp++) -+ communities[i].hostown[gpp] = readl(base + gpp * 4); -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(wb_intel_pinctrl_suspend_noirq); -+ -+static void intel_gpio_irq_init(struct intel_pinctrl *pctrl) -+{ -+ size_t i; -+ -+ for (i = 0; i < pctrl->ncommunities; i++) { -+ const struct intel_community *community; -+ void __iomem *base; -+ unsigned int gpp; -+ -+ community = &pctrl->communities[i]; -+ base = community->regs; -+ -+ for (gpp = 0; gpp < community->ngpps; gpp++) { -+ /* Mask and clear all interrupts */ -+ writel(0, base + community->ie_offset + gpp * 4); -+ writel(0xffff, base + community->is_offset + gpp * 4); -+ } -+ } -+} -+ -+static bool intel_gpio_update_reg(void __iomem *reg, u32 mask, u32 value) -+{ -+ u32 curr, updated; -+ -+ curr = readl(reg); -+ -+ updated = (curr & ~mask) | (value & mask); -+ if (curr == updated) -+ return false; -+ -+ writel(updated, reg); -+ return true; -+} -+ -+static void intel_restore_hostown(struct intel_pinctrl *pctrl, unsigned int c, -+ void __iomem *base, unsigned int gpp, u32 saved) -+{ -+ const struct intel_community *community = &pctrl->communities[c]; -+ const struct intel_padgroup *padgrp = &community->gpps[gpp]; -+ struct device *dev = pctrl->dev; -+ const char *dummy; -+ u32 requested = 0; -+ unsigned int i; -+ -+ if (padgrp->gpio_base == INTEL_GPIO_BASE_NOMAP) -+ return; -+ -+ for_each_requested_gpio_in_range(&pctrl->chip, i, padgrp->gpio_base, padgrp->size, dummy) -+ requested |= BIT(i); -+ -+ if (!intel_gpio_update_reg(base + gpp * 4, requested, saved)) -+ return; -+ -+ dev_dbg(dev, "restored hostown %u/%u %#08x\n", c, gpp, readl(base + gpp * 4)); -+} -+ -+static void intel_restore_intmask(struct intel_pinctrl *pctrl, unsigned int c, -+ void __iomem *base, unsigned int gpp, u32 saved) -+{ -+ struct device *dev = pctrl->dev; -+ -+ if (!intel_gpio_update_reg(base + gpp * 4, ~0U, saved)) -+ return; -+ -+ dev_dbg(dev, "restored mask %u/%u %#08x\n", c, gpp, readl(base + gpp * 4)); -+} -+ -+static void intel_restore_padcfg(struct intel_pinctrl *pctrl, unsigned int pin, -+ unsigned int reg, u32 saved) -+{ -+ u32 mask = (reg == PADCFG0) ? PADCFG0_GPIORXSTATE : 0; -+ unsigned int n = reg / sizeof(u32); -+ struct device *dev = pctrl->dev; -+ void __iomem *padcfg; -+ -+ padcfg = intel_get_padcfg(pctrl, pin, reg); -+ if (!padcfg) -+ return; -+ -+ if (!intel_gpio_update_reg(padcfg, ~mask, saved)) -+ return; -+ -+ dev_dbg(dev, "restored pin %u padcfg%u %#08x\n", pin, n, readl(padcfg)); -+} -+ -+int wb_intel_pinctrl_resume_noirq(struct device *dev) -+{ -+ struct intel_pinctrl *pctrl = dev_get_drvdata(dev); -+ const struct intel_community_context *communities; -+ const struct intel_pad_context *pads; -+ int i; -+ -+ /* Mask all interrupts */ -+ intel_gpio_irq_init(pctrl); -+ -+ pads = pctrl->context.pads; -+ for (i = 0; i < pctrl->soc->npins; i++) { -+ const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i]; -+ -+ if (!intel_pinctrl_should_save(pctrl, desc->number)) -+ continue; -+ -+ intel_restore_padcfg(pctrl, desc->number, PADCFG0, pads[i].padcfg0); -+ intel_restore_padcfg(pctrl, desc->number, PADCFG1, pads[i].padcfg1); -+ intel_restore_padcfg(pctrl, desc->number, PADCFG2, pads[i].padcfg2); -+ } -+ -+ communities = pctrl->context.communities; -+ for (i = 0; i < pctrl->ncommunities; i++) { -+ struct intel_community *community = &pctrl->communities[i]; -+ void __iomem *base; -+ unsigned int gpp; -+ -+ base = community->regs + community->ie_offset; -+ for (gpp = 0; gpp < community->ngpps; gpp++) -+ intel_restore_intmask(pctrl, i, base, gpp, communities[i].intmask[gpp]); -+ -+ base = community->regs + community->hostown_offset; -+ for (gpp = 0; gpp < community->ngpps; gpp++) -+ intel_restore_hostown(pctrl, i, base, gpp, communities[i].hostown[gpp]); -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(wb_intel_pinctrl_resume_noirq); -+#endif -+ -+MODULE_AUTHOR("Mathias Nyman "); -+MODULE_AUTHOR("Mika Westerberg "); -+MODULE_DESCRIPTION("Intel pinctrl/GPIO core driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.h -new file mode 100644 -index 000000000..5ed0cc065 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.h -@@ -0,0 +1,275 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Core pinctrl/GPIO driver for Intel GPIO controllers -+ * -+ * Copyright (C) 2015, Intel Corporation -+ * Authors: Mathias Nyman -+ * Mika Westerberg -+ */ -+ -+#ifndef PINCTRL_INTEL_H -+#define PINCTRL_INTEL_H -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct platform_device; -+struct device; -+ -+#define GPIO_RES_MAX (2) -+ -+typedef struct wb_gpio_data_s { -+ int irq; -+ void __iomem *res[GPIO_RES_MAX]; -+ unsigned int pci_domain; -+ unsigned int pci_bus; -+ unsigned int pci_slot; -+ unsigned int pci_fn; -+ unsigned int pci_bar; -+ struct pci_dev *pci_dev; -+ void __iomem *pci_mem_base; -+} wb_gpio_data_t; -+ -+/** -+ * struct intel_pingroup - Description about group of pins -+ * @name: Name of the groups -+ * @pins: All pins in this group -+ * @npins: Number of pins in this groups -+ * @mode: Native mode in which the group is muxed out @pins. Used if @modes -+ * is %NULL. -+ * @modes: If not %NULL this will hold mode for each pin in @pins -+ */ -+struct intel_pingroup { -+ const char *name; -+ const unsigned int *pins; -+ size_t npins; -+ unsigned short mode; -+ const unsigned int *modes; -+}; -+ -+/** -+ * struct intel_function - Description about a function -+ * @name: Name of the function -+ * @groups: An array of groups for this function -+ * @ngroups: Number of groups in @groups -+ */ -+struct intel_function { -+ const char *name; -+ const char * const *groups; -+ size_t ngroups; -+}; -+ -+/** -+ * struct intel_padgroup - Hardware pad group information -+ * @reg_num: GPI_IS register number -+ * @base: Starting pin of this group -+ * @size: Size of this group (maximum is 32). -+ * @gpio_base: Starting GPIO base of this group -+ * @padown_num: PAD_OWN register number (assigned by the core driver) -+ * -+ * If pad groups of a community are not the same size, use this structure -+ * to specify them. -+ */ -+struct intel_padgroup { -+ unsigned int reg_num; -+ unsigned int base; -+ unsigned int size; -+ int gpio_base; -+ unsigned int padown_num; -+}; -+ -+/** -+ * enum - Special treatment for GPIO base in pad group -+ * -+ * @INTEL_GPIO_BASE_ZERO: force GPIO base to be 0 -+ * @INTEL_GPIO_BASE_NOMAP: no GPIO mapping should be created -+ * @INTEL_GPIO_BASE_MATCH: matches with starting pin number -+ */ -+enum { -+ INTEL_GPIO_BASE_ZERO = -2, -+ INTEL_GPIO_BASE_NOMAP = -1, -+ INTEL_GPIO_BASE_MATCH = 0, -+}; -+ -+/** -+ * struct intel_community - Intel pin community description -+ * @barno: MMIO BAR number where registers for this community reside -+ * @padown_offset: Register offset of PAD_OWN register from @regs. If %0 -+ * then there is no support for owner. -+ * @padcfglock_offset: Register offset of PADCFGLOCK from @regs. If %0 then -+ * locking is not supported. -+ * @hostown_offset: Register offset of HOSTSW_OWN from @regs. If %0 then it -+ * is assumed that the host owns the pin (rather than -+ * ACPI). -+ * @is_offset: Register offset of GPI_IS from @regs. -+ * @ie_offset: Register offset of GPI_IE from @regs. -+ * @features: Additional features supported by the hardware -+ * @pin_base: Starting pin of pins in this community -+ * @npins: Number of pins in this community -+ * @gpp_size: Maximum number of pads in each group, such as PADCFGLOCK, -+ * HOSTSW_OWN, GPI_IS, GPI_IE. Used when @gpps is %NULL. -+ * @gpp_num_padown_regs: Number of pad registers each pad group consumes at -+ * minimum. Use %0 if the number of registers can be -+ * determined by the size of the group. -+ * @gpps: Pad groups if the controller has variable size pad groups -+ * @ngpps: Number of pad groups in this community -+ * @pad_map: Optional non-linear mapping of the pads -+ * @nirqs: Optional total number of IRQs this community can generate -+ * @acpi_space_id: Optional address space ID for ACPI OpRegion handler -+ * @regs: Community specific common registers (reserved for core driver) -+ * @pad_regs: Community specific pad registers (reserved for core driver) -+ * -+ * In some of Intel GPIO host controllers this driver supports each pad group -+ * is of equal size (except the last one). In that case the driver can just -+ * fill in @gpp_size field and let the core driver to handle the rest. If -+ * the controller has pad groups of variable size the client driver can -+ * pass custom @gpps and @ngpps instead. -+ */ -+struct intel_community { -+ unsigned int barno; -+ unsigned int padown_offset; -+ unsigned int padcfglock_offset; -+ unsigned int hostown_offset; -+ unsigned int is_offset; -+ unsigned int ie_offset; -+ unsigned int features; -+ unsigned int pin_base; -+ size_t npins; -+ unsigned int gpp_size; -+ unsigned int gpp_num_padown_regs; -+ const struct intel_padgroup *gpps; -+ size_t ngpps; -+ const unsigned int *pad_map; -+ unsigned short nirqs; -+ unsigned short acpi_space_id; -+ -+ /* Reserved for the core driver */ -+ void __iomem *regs; -+ void __iomem *pad_regs; -+ u32 dw_base; -+}; -+ -+/* Additional features supported by the hardware */ -+#define PINCTRL_FEATURE_DEBOUNCE BIT(0) -+#define PINCTRL_FEATURE_1K_PD BIT(1) -+ -+/** -+ * PIN_GROUP - Declare a pin group -+ * @n: Name of the group -+ * @p: An array of pins this group consists -+ * @m: Mode which the pins are put when this group is active. Can be either -+ * a single integer or an array of integers in which case mode is per -+ * pin. -+ */ -+#define PIN_GROUP(n, p, m) \ -+ { \ -+ .name = (n), \ -+ .pins = (p), \ -+ .npins = ARRAY_SIZE((p)), \ -+ .mode = __builtin_choose_expr( \ -+ __builtin_constant_p((m)), (m), 0), \ -+ .modes = __builtin_choose_expr( \ -+ __builtin_constant_p((m)), NULL, (m)), \ -+ } -+ -+#define FUNCTION(n, g) \ -+ { \ -+ .name = (n), \ -+ .groups = (g), \ -+ .ngroups = ARRAY_SIZE((g)), \ -+ } -+ -+/** -+ * struct intel_pinctrl_soc_data - Intel pin controller per-SoC configuration -+ * @uid: ACPI _UID for the probe driver use if needed -+ * @pins: Array if pins this pinctrl controls -+ * @npins: Number of pins in the array -+ * @groups: Array of pin groups -+ * @ngroups: Number of groups in the array -+ * @functions: Array of functions -+ * @nfunctions: Number of functions in the array -+ * @communities: Array of communities this pinctrl handles -+ * @ncommunities: Number of communities in the array -+ * -+ * The @communities is used as a template by the core driver. It will make -+ * copy of all communities and fill in rest of the information. -+ */ -+struct intel_pinctrl_soc_data { -+ const char *uid; -+ const struct pinctrl_pin_desc *pins; -+ size_t npins; -+ const struct intel_pingroup *groups; -+ size_t ngroups; -+ const struct intel_function *functions; -+ size_t nfunctions; -+ const struct intel_community *communities; -+ size_t ncommunities; -+}; -+ -+struct intel_pad_context; -+struct intel_community_context; -+ -+/** -+ * struct intel_pinctrl_context - context to be saved during suspend-resume -+ * @pads: Opaque context per pad (driver dependent) -+ * @communities: Opaque context per community (driver dependent) -+ */ -+struct intel_pinctrl_context { -+ struct intel_pad_context *pads; -+ struct intel_community_context *communities; -+}; -+ -+/** -+ * struct intel_pinctrl - Intel pinctrl private structure -+ * @dev: Pointer to the device structure -+ * @lock: Lock to serialize register access -+ * @pctldesc: Pin controller description -+ * @pctldev: Pointer to the pin controller device -+ * @chip: GPIO chip in this pin controller -+ * @irqchip: IRQ chip in this pin controller -+ * @soc: SoC/PCH specific pin configuration data -+ * @communities: All communities in this pin controller -+ * @ncommunities: Number of communities in this pin controller -+ * @context: Configuration saved over system sleep -+ * @irq: pinctrl/GPIO chip irq number -+ */ -+struct intel_pinctrl { -+ struct device *dev; -+ raw_spinlock_t lock; -+ struct pinctrl_desc pctldesc; -+ struct pinctrl_dev *pctldev; -+ struct gpio_chip chip; -+ struct irq_chip irqchip; -+ const struct intel_pinctrl_soc_data *soc; -+ struct intel_community *communities; -+ size_t ncommunities; -+ struct intel_pinctrl_context context; -+ int irq; -+}; -+ -+int wb_pinctrl_probe(struct platform_device *pdev, const struct intel_pinctrl_soc_data *soc_data); -+ -+#if 0 -+const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_device *pdev); -+int intel_pinctrl_probe_by_hid(struct platform_device *pdev); -+int intel_pinctrl_probe_by_uid(struct platform_device *pdev); -+#endif -+ -+#ifdef CONFIG_PM_SLEEP -+int wb_intel_pinctrl_suspend_noirq(struct device *dev); -+int wb_intel_pinctrl_resume_noirq(struct device *dev); -+#endif -+ -+#define INTEL_PINCTRL_PM_OPS(_name) \ -+const struct dev_pm_ops _name = { \ -+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(wb_intel_pinctrl_suspend_noirq, \ -+ wb_intel_pinctrl_resume_noirq) \ -+} -+ -+#endif /* PINCTRL_INTEL_H */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/Makefile -new file mode 100644 -index 000000000..369b64605 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/Makefile -@@ -0,0 +1,20 @@ -+pes_parent_dir:=$(shell pwd)/$(lastword $(MAKEFILE_LIST)) -+pes_parent_dir:=$(shell dirname $(pes_parent_dir)) -+ -+SUBDIRS=$(shell ls -l | grep ^d | awk '{if($$9 != "build") print $$9}') -+INC = -I./inc -+ -+all : CHECK $(SUBDIRS) -+CHECK : -+ @echo $(pes_parent_dir) -+ -+$(SUBDIRS):ECHO -+ #@echo $@ -+ make -C $@ -+ -+ECHO: -+ @echo $(SUBDIRS) -+ -+.PHONY : clean -+clean : -+ -rm -rf $(SYSFS_OUT_PUT) -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/Makefile -new file mode 100644 -index 000000000..e516b70b3 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/Makefile -@@ -0,0 +1,25 @@ -+PWD = $(shell pwd) -+ -+EXTRA_CFLAGS:= -I$(M)/include -+EXTRA_CFLAGS+= -Wall -+SUBDIR_CFG = cfg -+plat_dfd-objs := dfd_module.o dfd_fan_driver.o \ -+dfd_slot_driver.o \ -+dfd_sensors_driver.o \ -+dfd_psu_driver.o \ -+dfd_sff_driver.o \ -+$(SUBDIR_CFG)/dfd_cfg.o \ -+$(SUBDIR_CFG)/dfd_cfg_adapter.o \ -+$(SUBDIR_CFG)/dfd_cfg_file.o \ -+$(SUBDIR_CFG)/dfd_cfg_info.o \ -+$(SUBDIR_CFG)/dfd_cfg_listnode.o \ -+ -+obj-m := plat_dfd.o -+all: -+ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules -+ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi -+ cp -p $(PWD)/*.ko $(module_out_put_dir) -+clean: -+ rm -f $(PWD)/*.o $(PWD)/$(SUBDIR_CFG)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/$(SUBDIR_CFG)/.*.cmd $(PWD)/*.mod -+ rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order -+ rm -rf $(PWD)/.tmp_versions -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c -new file mode 100644 -index 000000000..3d05621ef ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c -@@ -0,0 +1,815 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "../include/dfd_module.h" -+#include "../include/dfd_cfg_file.h" -+#include "../include/dfd_cfg_listnode.h" -+#include "../include/dfd_cfg_info.h" -+#include "../include/dfd_cfg_adapter.h" -+#include "../include/dfd_cfg.h" -+#include "../../dev_sysfs/include/sysfs_common.h" -+ -+#ifdef DFD_CFG_ITEM -+#undef DFD_CFG_ITEM -+#endif -+#define DFD_CFG_ITEM(_id, _name, _index_min, _index_max) _name, -+static char *dfd_cfg_item_name[] = { -+ DFD_CFG_ITEM_ALL -+}; -+ -+#ifdef DFD_CFG_ITEM -+#undef DFD_CFG_ITEM -+#endif -+#define DFD_CFG_ITEM(_id, _name, _index_min, _index_max) {_index_min, _index_max}, -+static index_range_t dfd_cfg_item_index_range[] = { -+ DFD_CFG_ITEM_ALL -+}; -+ -+static lnode_root_t dfd_ko_cfg_list_root; -+ -+static void dfd_ko_cfg_del_space_lf_cr(char *str) -+{ -+ int i, j; -+ int len; -+ -+ len = strlen(str); -+ for (i = 0; i < len; i++) { -+ if (str[i] == '\r' || str[i] == '\n' || str[i] == ' ') { -+ for (j = i; j < len - 1; j++) { -+ str[j] = str[j + 1]; -+ } -+ str[j] = '\0'; -+ len--; -+ i--; -+ } -+ } -+} -+ -+static int dfd_ko_cfg_get_value_from_char(char *value_str, int32_t *value, int line_num) -+{ -+ int value_tmp = 0; -+ -+ if (strlen(value_str) == 0) { -+ DBG_DEBUG(DBG_WARN, "line%d: value str is empty\n", line_num); -+ *value = DFD_CFG_EMPTY_VALUE; -+ return 0; -+ } -+ -+ if ((strlen(value_str) > 2) && (value_str[0] == '0') -+ && (value_str[1] == 'x' || value_str[1] == 'X')) { -+ value_tmp = (int32_t)simple_strtol(value_str, NULL, 16); -+ } else { -+ value_tmp = (int32_t)simple_strtol(value_str, NULL, 10); -+ } -+ -+ *value = value_tmp; -+ return 0; -+} -+ -+static int dfd_ko_cfg_analyse_index(char *index_str, int *index1, int *index2, int line_num) -+{ -+ int rv; -+ char *index1_begin_char, *index2_begin_char; -+ -+ if (index_str[0] != '_') { -+ DBG_DEBUG(DBG_ERROR, "line%d: no '-' between name and index1\n", line_num); -+ return -1; -+ } -+ -+ index1_begin_char = index_str; -+ rv = dfd_ko_cfg_get_value_from_char(++index1_begin_char, index1, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ -+ if (index2 == NULL) { -+ return 0; -+ } -+ -+ index2_begin_char = strchr(index1_begin_char, '_'); -+ if (index2_begin_char == NULL) { -+ DBG_DEBUG(DBG_ERROR, "line%d: no '-' between index1 and index2\n", line_num); -+ return -1; -+ } else { -+ rv = dfd_ko_cfg_get_value_from_char(++index2_begin_char, index2, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+static int dfd_ko_cfg_check_array_index(index_range_t *index_range, int *index1, int *index2, -+ int line_num) -+{ -+ -+ if ((*index1 < 0) || (*index1 > index_range->index1_max)) { -+ DBG_DEBUG(DBG_ERROR, "line%d: index1[%d] invalid, max=%d\n", line_num, *index1, -+ index_range->index1_max); -+ return -1; -+ } -+ -+ if (index2 == NULL) { -+ return 0; -+ } -+ -+ if ((*index2 < 0) || (*index2 > index_range->index2_max)) { -+ DBG_DEBUG(DBG_ERROR, "line%d: index2[%d] invalid, max=%d\n", line_num, *index2, -+ index_range->index2_max); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int dfd_ko_cfg_get_index(char *index_str, index_range_t *index_range, int *index1, -+ int *index2, int line_num) -+{ -+ int rv; -+ -+ if (index_range->index2_max == INDEX_NOT_EXIST) { -+ index2 = NULL; -+ } -+ -+ rv = dfd_ko_cfg_analyse_index(index_str, index1, index2, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ -+ rv = dfd_ko_cfg_check_array_index(index_range, index1, index2, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int dfd_ko_cfg_add_int_item(int key, int value, int line_num) -+{ -+ int rv; -+ int *int_cfg; -+ -+ int_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); -+ if (int_cfg == NULL) { -+ -+ int_cfg = (int *)kmalloc(sizeof(int), GFP_KERNEL); -+ if (int_cfg == NULL) { -+ DBG_DEBUG(DBG_ERROR, "line%d: kmalloc int fail\n", line_num); -+ return -1; -+ } -+ -+ *int_cfg = value; -+ rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, int_cfg); -+ if (rv == 0) { -+ DBG_DEBUG(DBG_VERBOSE, "line%d: add int item[%d] success, key=0x%08x\n", line_num, value, key); -+ } else { -+ kfree(int_cfg); -+ int_cfg = NULL; -+ DBG_DEBUG(DBG_ERROR, "line%d: add int item[%d] fail, key=0x%08x rv=%d \n", line_num, value, key, rv); -+ return -1; -+ } -+ } else { -+ -+ DBG_DEBUG(DBG_WARN, "line%d: replace int item[%d->%d], key=0x%08x\n", line_num, *int_cfg, value, key); -+ *int_cfg = value; -+ } -+ -+ return 0; -+} -+ -+static int dfd_ko_cfg_analyse_int_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, char *arg_value, -+ char *cfg_pre, index_range_t *index_range, int line_num) -+{ -+ int rv; -+ int index1 = 0, index2 = 0; -+ int value, key; -+ char *arg_name_tmp; -+ -+ if (index_range->index1_max != INDEX_NOT_EXIST) { -+ arg_name_tmp = arg_name + strlen(cfg_pre); -+ rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ } -+ -+ rv = dfd_ko_cfg_get_value_from_char(arg_value, &value, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ -+ key = DFD_CFG_KEY(cfg_item_id, index1, index2); -+ rv = dfd_ko_cfg_add_int_item(key, value, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int dfd_ko_cfg_add_str_item(int key, char *str, int line_num) -+{ -+ int rv; -+ char *str_cfg; -+ -+ str_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); -+ if (str_cfg == NULL) { -+ -+ str_cfg = (char *)kmalloc(DFD_CFG_STR_MAX_LEN, GFP_KERNEL); -+ if (str_cfg == NULL) { -+ DBG_DEBUG(DBG_ERROR, "line%d: kmalloc str[%lu] fail\n", line_num, strlen(str)); -+ return -1; -+ } -+ mem_clear(str_cfg, DFD_CFG_STR_MAX_LEN); -+ strncpy(str_cfg, str, DFD_CFG_STR_MAX_LEN - 1); -+ -+ rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, str_cfg); -+ if (rv == 0) { -+ DBG_DEBUG(DBG_VERBOSE, "line%d: add string item[%s] success, key=0x%08x\n", line_num, str_cfg, key); -+ } else { -+ kfree(str_cfg); -+ str_cfg = NULL; -+ DBG_DEBUG(DBG_ERROR, "line%d: add string item[%s] fail, key=0x%08x rv=%d \n", line_num, str_cfg, key, rv); -+ return -1; -+ } -+ } else { -+ DBG_DEBUG(DBG_WARN, "line%d: replace string item[%s->%s], key=0x%08x\n", line_num, str_cfg, str, key); -+ mem_clear(str_cfg, DFD_CFG_STR_MAX_LEN); -+ strncpy(str_cfg, str, DFD_CFG_STR_MAX_LEN - 1); -+ } -+ -+ return 0; -+} -+ -+static int dfd_ko_cfg_analyse_str_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, char *arg_value, -+ char *cfg_pre, index_range_t *index_range, int line_num) -+{ -+ int rv; -+ int index1 = 0, index2 = 0; -+ int btree_key; -+ char *arg_name_tmp; -+ -+ if (index_range->index1_max != INDEX_NOT_EXIST) { -+ arg_name_tmp = arg_name + strlen(cfg_pre); -+ rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ } -+ -+ if (strlen(arg_value) >= DFD_CFG_STR_MAX_LEN) { -+ DBG_DEBUG(DBG_ERROR, "line%d: string item[%s] is too long \n", line_num, arg_value); -+ return -1; -+ } -+ -+ btree_key = DFD_CFG_KEY(cfg_item_id, index1, index2); -+ rv = dfd_ko_cfg_add_str_item(btree_key, arg_value, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int dfd_ko_cfg_get_i2c_dev_member(char *member_str, dfd_i2c_dev_mem_t *member, int line_num) -+{ -+ dfd_i2c_dev_mem_t mem_index; -+ -+ for (mem_index = DFD_I2C_DEV_MEM_BUS; mem_index < DFD_I2C_DEV_MEM_END; mem_index++) { -+ if (memcmp(member_str, g_dfd_i2c_dev_mem_str[mem_index], -+ strlen(g_dfd_i2c_dev_mem_str[mem_index])) == 0) { -+ *member = mem_index; -+ return 0; -+ } -+ } -+ -+ DBG_DEBUG(DBG_ERROR, "line%d: i2c dev member[%s] invalid\n", line_num, member_str); -+ return -1; -+} -+ -+static void dfd_ko_cfg_set_i2c_dev_mem_value(dfd_i2c_dev_t *i2c_dev, dfd_i2c_dev_mem_t member, -+ int value) -+{ -+ switch (member) { -+ case DFD_I2C_DEV_MEM_BUS: -+ i2c_dev->bus = value; -+ break; -+ case DFD_I2C_DEV_MEM_ADDR: -+ i2c_dev->addr = value; -+ break; -+ default: -+ break; -+ } -+} -+ -+static int dfd_ko_cfg_add_i2c_dev_item(int key, dfd_i2c_dev_mem_t member, int value, int line_num) -+{ -+ int rv; -+ dfd_i2c_dev_t *i2c_dev_cfg; -+ -+ i2c_dev_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); -+ if (i2c_dev_cfg == NULL) { -+ -+ i2c_dev_cfg = (dfd_i2c_dev_t *)kmalloc(sizeof(dfd_i2c_dev_t), GFP_KERNEL); -+ if (i2c_dev_cfg == NULL) { -+ DBG_DEBUG(DBG_ERROR, "line%d: kmalloc i2c_dev fail\n", line_num); -+ return -1; -+ } -+ mem_clear(i2c_dev_cfg, sizeof(dfd_i2c_dev_t)); -+ -+ dfd_ko_cfg_set_i2c_dev_mem_value(i2c_dev_cfg, member, value); -+ rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, i2c_dev_cfg); -+ if (rv == 0) { -+ DBG_DEBUG(DBG_VERBOSE, "line%d: add i2c_dev item[%s=%d] success, key=0x%08x\n", line_num, -+ g_dfd_i2c_dev_mem_str[member], value, key); -+ } else { -+ kfree(i2c_dev_cfg); -+ i2c_dev_cfg = NULL; -+ DBG_DEBUG(DBG_ERROR, "line%d: add i2c_dev item[%s=%d] fail, key=0x%08x rv=%d\n", line_num, -+ g_dfd_i2c_dev_mem_str[member], value, key, rv); -+ return -1; -+ } -+ } else { -+ -+ DBG_DEBUG(DBG_VERBOSE, "line%d: replace i2c_dev item[%s=%d], key=0x%08x\n", line_num, -+ g_dfd_i2c_dev_mem_str[member], value, key); -+ dfd_ko_cfg_set_i2c_dev_mem_value(i2c_dev_cfg, member, value); -+ } -+ -+ return 0; -+} -+ -+static int dfd_ko_cfg_analyse_i2c_dev_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, -+ char *arg_value, char *cfg_pre, index_range_t *index_range, int line_num) -+{ -+ int rv; -+ int index1 = 0, index2 = 0; -+ int value, key; -+ char *arg_name_tmp; -+ dfd_i2c_dev_mem_t member; -+ -+ arg_name_tmp = arg_name + strlen(cfg_pre); -+ rv = dfd_ko_cfg_get_i2c_dev_member(arg_name_tmp, &member, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ -+ if (index_range->index1_max != INDEX_NOT_EXIST) { -+ arg_name_tmp += strlen(g_dfd_i2c_dev_mem_str[member]); -+ rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ } -+ -+ rv = dfd_ko_cfg_get_value_from_char(arg_value, &value, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ -+ key = DFD_CFG_KEY(cfg_item_id, index1, index2); -+ rv = dfd_ko_cfg_add_i2c_dev_item(key, member, value, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int dfd_ko_cfg_get_enum_value_by_str(char *enum_val_str[], int enum_val_end, char *buf) -+{ -+ int i; -+ int enum_val; -+ -+ enum_val = DFD_CFG_INVALID_VALUE; -+ for (i = 0; i < enum_val_end; i++) { -+ if (memcmp(buf, enum_val_str[i], strlen(enum_val_str[i])) == 0) { -+ enum_val = i; -+ break; -+ } -+ } -+ -+ return enum_val; -+} -+ -+static int dfd_ko_cfg_get_info_ctrl_member(char *member_str, info_ctrl_mem_t *member, int line_num) -+{ -+ info_ctrl_mem_t mem_index; -+ -+ for (mem_index = INFO_CTRL_MEM_MODE; mem_index < INFO_CTRL_MEM_END; mem_index++) { -+ if (memcmp(member_str, g_info_ctrl_mem_str[mem_index], -+ strlen(g_info_ctrl_mem_str[mem_index])) == 0) { -+ *member = mem_index; -+ return 0; -+ } -+ } -+ -+ DBG_DEBUG(DBG_ERROR, "line%d: info ctrl member[%s] invalid\n", line_num, member_str); -+ return -1; -+} -+ -+static void dfd_ko_cfg_set_info_ctrl_mem_value(info_ctrl_t *info_ctrl, info_ctrl_mem_t member, -+ char *buf_val, int line_num) -+{ -+ switch (member) { -+ case INFO_CTRL_MEM_MODE: -+ info_ctrl->mode = dfd_ko_cfg_get_enum_value_by_str(g_info_ctrl_mode_str, INFO_CTRL_MODE_END, buf_val);; -+ break; -+ case INFO_CTRL_MEM_INT_CONS: -+ dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_cons), line_num); -+ break; -+ case INFO_CTRL_MEM_SRC: -+ info_ctrl->src = dfd_ko_cfg_get_enum_value_by_str(g_info_src_str, INFO_SRC_END, buf_val); -+ break; -+ case INFO_CTRL_MEM_FRMT: -+ info_ctrl->frmt = dfd_ko_cfg_get_enum_value_by_str(g_info_frmt_str, INFO_FRMT_END, buf_val); -+ break; -+ case INFO_CTRL_MEM_POLA: -+ info_ctrl->pola = dfd_ko_cfg_get_enum_value_by_str(g_info_pola_str, INFO_POLA_END, buf_val); -+ break; -+ case INFO_CTRL_MEM_FPATH: -+ mem_clear(info_ctrl->fpath, sizeof(info_ctrl->fpath)); -+ strncpy(info_ctrl->fpath, buf_val, sizeof(info_ctrl->fpath) - 1); -+ break; -+ case INFO_CTRL_MEM_ADDR: -+ dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->addr), line_num); -+ break; -+ case INFO_CTRL_MEM_LEN: -+ dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->len), line_num); -+ break; -+ case INFO_CTRL_MEM_BIT_OFFSET: -+ dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->bit_offset), line_num); -+ break; -+ case INFO_CTRL_MEM_STR_CONS: -+ mem_clear(info_ctrl->str_cons, sizeof(info_ctrl->str_cons)); -+ strncpy(info_ctrl->str_cons, buf_val, sizeof(info_ctrl->str_cons) - 1); -+ break; -+ case INFO_CTRL_MEM_INT_EXTRA1: -+ dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_extra1), line_num); -+ break; -+ case INFO_CTRL_MEM_INT_EXTRA2: -+ dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_extra2), line_num); -+ break; -+ case INFO_CTRL_MEM_INT_EXTRA3: -+ dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_extra3), line_num); -+ break; -+ default: -+ break; -+ } -+} -+ -+static int dfd_ko_cfg_add_info_ctrl_item(int key, info_ctrl_mem_t member, char *buf_val, -+ int line_num) -+{ -+ int rv; -+ info_ctrl_t *info_ctrl_cfg; -+ -+ info_ctrl_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); -+ if (info_ctrl_cfg == NULL) { -+ -+ info_ctrl_cfg = (info_ctrl_t *)kmalloc(sizeof(info_ctrl_t), GFP_KERNEL); -+ if (info_ctrl_cfg == NULL) { -+ DBG_DEBUG(DBG_ERROR, "line%d: kmalloc info_ctrl fail\n", line_num); -+ return -1; -+ } -+ mem_clear(info_ctrl_cfg, sizeof(info_ctrl_t)); -+ -+ dfd_ko_cfg_set_info_ctrl_mem_value(info_ctrl_cfg, member, buf_val, line_num); -+ rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, info_ctrl_cfg); -+ if (rv == 0) { -+ DBG_DEBUG(DBG_VERBOSE, "line%d: add info_ctrl item[%s=%s] success, key=0x%08x\n", line_num, -+ g_info_ctrl_mem_str[member], buf_val, key); -+ } else { -+ kfree(info_ctrl_cfg); -+ info_ctrl_cfg = NULL; -+ DBG_DEBUG(DBG_ERROR, "line%d: add info_ctrl item[%s=%s] fail, key=0x%08x rv=%d\n", line_num, -+ g_info_ctrl_mem_str[member], buf_val, key, rv); -+ return -1; -+ } -+ } else { -+ -+ DBG_DEBUG(DBG_VERBOSE, "line%d: replace info_ctrl item[%s=%s], key=0x%08x\n", line_num, -+ g_info_ctrl_mem_str[member], buf_val, key); -+ dfd_ko_cfg_set_info_ctrl_mem_value(info_ctrl_cfg, member, buf_val, line_num); -+ } -+ -+ return 0; -+} -+ -+static int dfd_ko_cfg_analyse_info_ctrl_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, -+ char *arg_value, char *cfg_pre, index_range_t *index_range, int line_num) -+{ -+ int rv; -+ int index1 = 0, index2 = 0; -+ int key; -+ char *arg_name_tmp; -+ info_ctrl_mem_t member; -+ -+ arg_name_tmp = arg_name + strlen(cfg_pre); -+ rv = dfd_ko_cfg_get_info_ctrl_member(arg_name_tmp, &member, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ -+ if (index_range->index1_max != INDEX_NOT_EXIST) { -+ arg_name_tmp += strlen(g_info_ctrl_mem_str[member]); -+ rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ } -+ -+ key = DFD_CFG_KEY(cfg_item_id, index1, index2); -+ rv = dfd_ko_cfg_add_info_ctrl_item(key, member, arg_value, line_num); -+ if (rv < 0) { -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int dfd_ko_cfg_analyse_config(char *arg_name, char*arg_value, int line_num) -+{ -+ int i, rv = 0; -+ int cfg_item_num; -+ -+ cfg_item_num = sizeof(dfd_cfg_item_name) / sizeof(dfd_cfg_item_name[0]); -+ for (i = 0; i < cfg_item_num; i++) { -+ if (memcmp(arg_name, dfd_cfg_item_name[i], strlen(dfd_cfg_item_name[i])) == 0){ -+ if (DFD_CFG_ITEM_IS_INT(i)) { -+ rv = dfd_ko_cfg_analyse_int_item(i, arg_name, arg_value, dfd_cfg_item_name[i], -+ &(dfd_cfg_item_index_range[i]), line_num); -+ } else if (DFD_CFG_ITEM_IS_STRING(i)) { -+ rv = dfd_ko_cfg_analyse_str_item(i, arg_name, arg_value, dfd_cfg_item_name[i], -+ &(dfd_cfg_item_index_range[i]), line_num); -+ } else if (DFD_CFG_ITEM_IS_I2C_DEV(i)) { -+ rv = dfd_ko_cfg_analyse_i2c_dev_item(i, arg_name, arg_value, dfd_cfg_item_name[i], -+ &(dfd_cfg_item_index_range[i]), line_num); -+ } else if (DFD_CFG_ITEM_IS_INFO_CTRL(i)) { -+ rv = dfd_ko_cfg_analyse_info_ctrl_item(i, arg_name, arg_value, dfd_cfg_item_name[i], -+ &(dfd_cfg_item_index_range[i]), line_num); -+ } else { -+ rv = -1; -+ } -+ break; -+ } -+ } -+ -+ return rv; -+} -+ -+static int dfd_ko_cfg_cut_config_line(char *config_line, char *arg_name, char *arg_value) -+{ -+ int i, j = 0, k = 0; -+ int len, name_value_flag = 0; -+ -+ len = strlen(config_line); -+ for (i = 0; i < len; i++) { -+ if (config_line[i] == '=') { -+ name_value_flag = 1; -+ continue; -+ } -+ -+ if (name_value_flag == 0) { -+ arg_name[j++] = config_line[i]; -+ } else { -+ arg_value[k++] = config_line[i]; -+ } -+ } -+ -+ if (name_value_flag == 0) { -+ return -1; -+ } else { -+ return 0; -+ } -+} -+ -+static int dfd_ko_cfg_analyse_config_line(char *config_line, int line_num) -+{ -+ int rv; -+ char arg_name[DFD_CFG_NAME_MAX_LEN] = {0}; -+ char arg_value[DFD_CFG_VALUE_MAX_LEN] = {0}; -+ -+ dfd_ko_cfg_del_space_lf_cr(config_line); -+ -+ if (strlen(config_line) == 0) { -+ DBG_DEBUG(DBG_VERBOSE, "line%d: space line\n", line_num); -+ return 0; -+ } -+ -+ if (config_line[0] == '#') { -+ DBG_DEBUG(DBG_VERBOSE, "line%d: comment line[%s]\n", line_num, config_line); -+ return 0; -+ } -+ -+ rv = dfd_ko_cfg_cut_config_line(config_line, arg_name, arg_value); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_VERBOSE, "line%d: [%s]no '=' between name and value\n", line_num, config_line); -+ return -1; -+ } -+ -+ DBG_DEBUG(DBG_VERBOSE, "line%d: config_line[%s] name[%s] value[%s]\n", line_num, config_line, arg_name, arg_value); -+ return dfd_ko_cfg_analyse_config(arg_name, arg_value, line_num); -+} -+ -+static int dfd_ko_cfg_analyse_config_file(char *fpath) -+{ -+ int rv; -+ int line_num = 1; -+ kfile_ctrl_t kfile_ctrl; -+ char config_line[DFD_CFG_CMDLINE_MAX_LEN] = {0}; -+ -+ rv = kfile_open(fpath, &kfile_ctrl); -+ if (rv != KFILE_RV_OK) { -+ DBG_DEBUG(DBG_ERROR, "open config file[%s] fail, rv=%d\n", fpath, rv); -+ return -1; -+ } -+ -+ while(kfile_gets(config_line, sizeof(config_line), &kfile_ctrl) > 0){ -+ rv = dfd_ko_cfg_analyse_config_line(config_line, line_num++); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "!!!!file[%s] config line[%d %s] analyse fail\n", fpath, line_num - 1, -+ config_line); -+ break; -+ } -+ -+ (void)mem_clear(config_line, sizeof(config_line)); -+ -+ } -+ kfile_close(&kfile_ctrl); -+ -+ return rv; -+} -+ -+void *dfd_ko_cfg_get_item(int key) -+{ -+ return lnode_find_node(&dfd_ko_cfg_list_root, key); -+} -+ -+static void dfd_ko_cfg_print_item(int key, const void *cfg) -+{ -+ int item_id; -+ dfd_i2c_dev_t *i2c_dev; -+ info_ctrl_t *info_ctrl; -+ -+ if (cfg == NULL) { -+ DBG_DEBUG(DBG_ERROR, "input arguments error\n"); -+ return; -+ } -+ printk(KERN_INFO "**************************\n"); -+ printk(KERN_INFO "key=0x%08x\n", key); -+ -+ item_id = DFD_CFG_ITEM_ID(key); -+ if (DFD_CFG_ITEM_IS_INT(item_id)) { -+ printk(KERN_INFO "int=%d\n", *((int *)cfg)); -+ } else if (DFD_CFG_ITEM_IS_I2C_DEV(item_id)) { -+ i2c_dev = (dfd_i2c_dev_t *)cfg; -+ printk(KERN_INFO ".bus=0x%02x\n", i2c_dev->bus); -+ printk(KERN_INFO ".addr=0x%02x\n", i2c_dev->addr); -+ } else if (DFD_CFG_ITEM_IS_INFO_CTRL(item_id)) { -+ info_ctrl = (info_ctrl_t *)cfg; -+ printk(KERN_INFO ".mode=%s\n", g_info_ctrl_mode_str[info_ctrl->mode]); -+ printk(KERN_INFO ".int_cons=%d\n", info_ctrl->int_cons); -+ printk(KERN_INFO ".src=%s\n", g_info_src_str[info_ctrl->src]); -+ printk(KERN_INFO ".frmt=%s\n", g_info_frmt_str[info_ctrl->frmt]); -+ printk(KERN_INFO ".pola=%s\n", g_info_pola_str[info_ctrl->pola]); -+ printk(KERN_INFO ".fpath=%s\n", info_ctrl->fpath); -+ printk(KERN_INFO ".addr=0x%02x\n", info_ctrl->addr); -+ printk(KERN_INFO ".len=%d\n", info_ctrl->len); -+ printk(KERN_INFO ".bit_offset=%d\n", info_ctrl->bit_offset); -+ } else { -+ printk(KERN_INFO "item[%d] error!\n", item_id); -+ } -+} -+ -+void dfd_ko_cfg_show_item(int key) -+{ -+ void *cfg; -+ -+ cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); -+ if (cfg == 0) { -+ printk(KERN_INFO "item[0x%08x] not exist\n", key); -+ return; -+ } -+ -+ dfd_ko_cfg_print_item(key, cfg); -+} -+ -+static int dfd_get_my_dev_type_by_file(void) -+{ -+ struct file *fp; -+ loff_t pos; -+ int card_type; -+ char buf[DFD_PID_BUF_LEN]; -+ int ret; -+ -+ fp= filp_open(DFD_PUB_CARDTYPE_FILE, O_RDONLY, 0); -+ if (IS_ERR(fp)) { -+ DBG_DEBUG(DBG_VERBOSE, "open file fail!\n"); -+ return -1; -+ } -+ mem_clear(buf, DFD_PID_BUF_LEN); -+ pos = 0; -+ ret = kernel_read(fp, buf, DFD_PRODUCT_ID_LENGTH + 1, &pos); -+ if (ret < 0) { -+ DBG_DEBUG(DBG_VERBOSE, "kernel_read failed, path=%s, addr=0, size=%d, ret=%d\n", -+ DFD_PUB_CARDTYPE_FILE, DFD_PRODUCT_ID_LENGTH + 1, ret); -+ filp_close(fp, NULL); -+ return -1; -+ } -+ -+ card_type = simple_strtoul(buf, NULL, 10); -+ DBG_DEBUG(DBG_VERBOSE, "card_type 0x%x.\n", card_type); -+ -+ filp_close(fp, NULL); -+ return card_type; -+} -+ -+static int drv_get_my_dev_type(void) -+{ -+ static int type = -1; -+ -+ if (type > 0) { -+ return type; -+ } -+ type = dfd_get_my_dev_type_by_file(); -+ DBG_DEBUG(DBG_VERBOSE, "ko board type %d\n", type); -+ return type; -+} -+ -+static int dfd_ko_cfg_init(void) -+{ -+ int rv; -+ int card_type; -+ char file_name[32] = {0}; -+ char fpath[128] = {0}; -+ kfile_ctrl_t kfile_ctrl; -+ -+ rv = lnode_init_root(&dfd_ko_cfg_list_root); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "init list root fail, rv=%d\n", rv); -+ return -1; -+ } -+ -+ card_type = drv_get_my_dev_type(); -+ if (card_type > 0) { -+ snprintf(fpath, sizeof(fpath), "%s0x%x", DFD_KO_CFG_FILE_DIR, card_type); -+ rv = kfile_open(fpath, &kfile_ctrl); -+ if (rv != KFILE_RV_OK) { -+ DBG_DEBUG(DBG_VERBOSE, "open config file[%s] fail, rv=%d, maybe not exist\n", -+ fpath, rv); -+ -+ rv = kfile_open(DFD_KO_CFG_FILE_NAME, &kfile_ctrl); -+ if (rv != KFILE_RV_OK) { -+ DBG_DEBUG(DBG_ERROR, "open config file[%s] fail, rv=%d\n", DFD_KO_CFG_FILE_NAME, -+ rv); -+ return -1; -+ } -+ DBG_DEBUG(DBG_ERROR, "get config file from: %s, success.\n", DFD_KO_CFG_FILE_NAME); -+ } else { -+ DBG_DEBUG(DBG_VERBOSE, "get config file from: %s, success.\n", fpath); -+ } -+ } else { -+ DBG_DEBUG(DBG_VERBOSE, "get board id failed, try to get config file from: %s\n", -+ DFD_KO_CFG_FILE_NAME); -+ -+ rv = kfile_open(DFD_KO_CFG_FILE_NAME, &kfile_ctrl); -+ if (rv != KFILE_RV_OK) { -+ DBG_DEBUG(DBG_ERROR, "open config file[%s] fail, rv=%d\n", DFD_KO_CFG_FILE_NAME, rv); -+ return -1; -+ } -+ DBG_DEBUG(DBG_ERROR, "get config file from: %s, success.\n", DFD_KO_CFG_FILE_NAME); -+ } -+ -+ while (kfile_gets(file_name, sizeof(file_name), &kfile_ctrl) > 0) { -+ -+ dfd_ko_cfg_del_space_lf_cr(file_name); -+ mem_clear(fpath, sizeof(fpath)); -+ snprintf(fpath, sizeof(fpath), "%s%s.cfg", DFD_KO_CFG_FILE_DIR, file_name); -+ DBG_DEBUG(DBG_VERBOSE, ">>>>start parsing config file[%s]\n", fpath); -+ -+ rv = dfd_ko_cfg_analyse_config_file(fpath); -+ if (rv < 0) { -+ break; -+ } -+ } -+ kfile_close(&kfile_ctrl); -+ -+ return 0; -+} -+ -+int32_t dfd_dev_cfg_init(void) -+{ -+ return dfd_ko_cfg_init(); -+} -+ -+void dfd_dev_cfg_exit(void) -+{ -+ lnode_free_list(&dfd_ko_cfg_list_root); -+ return; -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c -new file mode 100644 -index 000000000..1d5ca7072 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c -@@ -0,0 +1,351 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "../include/dfd_module.h" -+#include "../include/dfd_cfg_file.h" -+#include "../include/dfd_cfg.h" -+#include "../include/dfd_cfg_adapter.h" -+#include "../../dev_sysfs/include/sysfs_common.h" -+ -+char *g_dfd_i2c_dev_mem_str[DFD_I2C_DEV_MEM_END] = { -+ ".bus", -+ ".addr", -+}; -+ -+static dfd_i2c_dev_t* dfd_ko_get_cpld_i2c_dev(int sub_slot, int cpld_id) -+{ -+ int key; -+ dfd_i2c_dev_t *i2c_dev; -+ -+ key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_I2C_DEV, sub_slot, cpld_id); -+ i2c_dev = dfd_ko_cfg_get_item(key); -+ if (i2c_dev == NULL) { -+ DBG_DEBUG(DBG_ERROR, "get cpld[%d] i2c dev config fail, key=0x%08x\n", cpld_id, key); -+ return NULL; -+ } -+ -+ return i2c_dev; -+} -+ -+static int32_t dfd_ko_i2c_smbus_transfer(int read_write, int bus, int addr, int offset, uint8_t *buf, uint32_t size) -+{ -+ int rv; -+ struct i2c_adapter *i2c_adap; -+ union i2c_smbus_data data; -+ -+ i2c_adap = i2c_get_adapter(bus); -+ if (i2c_adap == NULL) { -+ DBG_DEBUG(DBG_ERROR, "get i2c bus[%d] adapter fail\n", bus); -+ return -DFD_RV_DEV_FAIL; -+ } -+ -+ if (read_write == I2C_SMBUS_WRITE) { -+ data.byte = *buf; -+ } else { -+ data.byte = 0; -+ } -+ rv = i2c_smbus_xfer(i2c_adap, addr, 0, read_write, offset, I2C_SMBUS_BYTE_DATA, &data); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "i2c dev[bus=%d addr=0x%x offset=0x%x size=%d rw=%d] transfer fail, rv=%d\n", -+ bus, addr, offset, size, read_write, rv); -+ rv = -DFD_RV_DEV_FAIL; -+ } else { -+ DBG_DEBUG(DBG_VERBOSE, "i2c dev[bus=%d addr=0x%x offset=0x%x size=%d rw=%d] transfer success\n", -+ bus, addr, offset, size, read_write); -+ rv = DFD_RV_OK; -+ } -+ -+ if (read_write == I2C_SMBUS_READ) { -+ if (rv == DFD_RV_OK) { -+ *buf = data.byte; -+ } else { -+ *buf = 0; -+ } -+ } -+ -+ i2c_put_adapter(i2c_adap); -+ return rv; -+} -+ -+static int32_t dfd_ko_i2c_read_data(int bus, int addr, int offset, uint8_t *buf, uint32_t size) -+{ -+ int i, rv; -+ for (i = 0; i < DFD_KO_CPLD_I2C_RETRY_TIMES; i++) { -+ rv = dfd_ko_i2c_smbus_transfer(I2C_SMBUS_READ, bus, addr, offset, buf, size); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "[%d]cpld read[offset=0x%x] fail, rv %d\n", i, addr, rv); -+ msleep(DFD_KO_CPLD_I2C_RETRY_SLEEP); -+ } else { -+ DBG_DEBUG(DBG_VERBOSE, "[%d]cpld read[offset=0x%x] success, value=0x%x\n", -+ i, addr, *buf); -+ break; -+ } -+ } -+ return rv; -+} -+ -+static int32_t dfd_ko_i2c_write_data(int bus, int addr, int offset, uint8_t data, uint32_t size) -+{ -+ int i, rv; -+ for (i = 0; i < DFD_KO_CPLD_I2C_RETRY_TIMES; i++) { -+ rv = dfd_ko_i2c_smbus_transfer(I2C_SMBUS_WRITE, bus, addr, offset, &data, size); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "[%d]cpld write[offset=0x%x] fail, rv=%d\n", i, addr, rv); -+ msleep(DFD_KO_CPLD_I2C_RETRY_SLEEP); -+ } else { -+ DBG_DEBUG(DBG_VERBOSE, "[%d]cpld write[offset=0x%x, data=%d] success\n", i, addr, data); -+ break; -+ } -+ } -+ -+ return rv; -+} -+ -+static int32_t dfd_ko_cpld_i2c_read(int32_t addr, uint8_t *buf) -+{ -+ int rv; -+ int sub_slot, cpld_id, cpld_addr; -+ dfd_i2c_dev_t *i2c_dev; -+ -+ if (buf == NULL) { -+ DBG_DEBUG(DBG_ERROR, "input arguments error\n"); -+ return -DFD_RV_INDEX_INVALID; -+ } -+ -+ sub_slot = DFD_KO_CPLD_GET_SLOT(addr); -+ cpld_id = DFD_KO_CPLD_GET_ID(addr); -+ cpld_addr = DFD_KO_CPLD_GET_INDEX(addr); -+ -+ i2c_dev = dfd_ko_get_cpld_i2c_dev(sub_slot, cpld_id); -+ if (i2c_dev == NULL) { -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ rv = dfd_ko_i2c_read_data(i2c_dev->bus, i2c_dev->addr, cpld_addr, buf, sizeof(uint8_t)); -+ -+ return rv; -+} -+ -+static int32_t dfd_ko_cpld_i2c_write(int32_t addr, uint8_t data) -+{ -+ int rv; -+ int sub_slot, cpld_id, cpld_addr; -+ dfd_i2c_dev_t *i2c_dev; -+ -+ sub_slot = DFD_KO_CPLD_GET_SLOT(addr); -+ cpld_id = DFD_KO_CPLD_GET_ID(addr); -+ cpld_addr = DFD_KO_CPLD_GET_INDEX(addr); -+ -+ i2c_dev = dfd_ko_get_cpld_i2c_dev(sub_slot, cpld_id); -+ if (i2c_dev == NULL) { -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ -+ rv = dfd_ko_i2c_write_data(i2c_dev->bus, i2c_dev->addr, cpld_addr, data, sizeof(uint8_t)); -+ -+ return rv; -+} -+ -+static int32_t dfd_ko_cpld_io_read(int32_t addr, uint8_t *buf) -+{ -+ int cpld_id, sub_slot, offset; -+ int key; -+ int *tmp; -+ uint16_t io_port; -+ -+ sub_slot = DFD_KO_CPLD_GET_SLOT(addr); -+ cpld_id = DFD_KO_CPLD_GET_ID(addr); -+ offset = DFD_KO_CPLD_GET_INDEX(addr); -+ -+ key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_LPC_DEV, sub_slot, cpld_id); -+ tmp = dfd_ko_cfg_get_item(key); -+ if (tmp == NULL) { -+ DBG_DEBUG(DBG_ERROR,"get cpld io base config fail, key=0x%08x\n", key); -+ return -1; -+ } -+ -+ io_port = (u16)(*tmp) + offset; -+ *buf = inb(io_port); -+ DBG_DEBUG(DBG_VERBOSE, "read cpld io port addr 0x%x, data 0x%x\n", io_port, *buf); -+ -+ return DFD_RV_OK; -+ -+} -+ -+static int32_t dfd_ko_cpld_io_write(int32_t addr, uint8_t data) -+{ -+ int cpld_id, sub_slot, offset; -+ int key; -+ int *tmp; -+ uint16_t io_port; -+ -+ sub_slot = DFD_KO_CPLD_GET_SLOT(addr); -+ cpld_id = DFD_KO_CPLD_GET_ID(addr); -+ offset = DFD_KO_CPLD_GET_INDEX(addr); -+ -+ key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_LPC_DEV, sub_slot, cpld_id); -+ tmp = dfd_ko_cfg_get_item(key); -+ if (tmp == NULL) { -+ DBG_DEBUG(DBG_ERROR, "get cpld io base config fail, key=0x%08x\n", key); -+ return -1; -+ } -+ -+ io_port = (u16)(*tmp) + offset; -+ DBG_DEBUG(DBG_VERBOSE, "write cpld io port addr 0x%x, data 0x%x\n", io_port, data); -+ outb(data, (u16)io_port); -+ -+ return DFD_RV_OK; -+} -+ -+static int dfd_cfg_get_cpld_mode(int sub_slot, int cpld_id, int *mode) -+{ -+ int key; -+ char *name; -+ -+ if (mode == NULL) { -+ DBG_DEBUG(DBG_ERROR, "input arguments error\n"); -+ return -DFD_RV_TYPE_ERR; -+ } -+ -+ key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_MODE, sub_slot, cpld_id); -+ name = dfd_ko_cfg_get_item(key); -+ if (name == NULL) { -+ DBG_DEBUG(DBG_ERROR, "get cpld[%d] mode info ctrl fail, key=0x%08x\n", cpld_id, key); -+ return -DFD_RV_NODE_FAIL; -+ } -+ -+ DBG_DEBUG(DBG_VERBOSE, "cpld_id %d mode_name %s.\n", cpld_id, name); -+ if (!strncmp(name, DFD_KO_CPLD_MODE_I2C_STRING, strlen(DFD_KO_CPLD_MODE_I2C_STRING))) { -+ *mode = DFD_CPLD_MODE_I2C; -+ } else if (!strncmp(name, DFD_KO_CPLD_MODE_LPC_STRING, strlen(DFD_KO_CPLD_MODE_LPC_STRING))) { -+ *mode = DFD_CPLD_MODE_LPC; -+ } else { -+ -+ *mode = DFD_CPLD_MODE_I2C; -+ } -+ -+ DBG_DEBUG(DBG_VERBOSE, "cpld_id %d mode %d.\n", cpld_id, *mode); -+ return 0; -+} -+ -+int32_t dfd_ko_cpld_read(int32_t addr, uint8_t *buf) -+{ -+ int ret; -+ int sub_slot, cpld_id; -+ int cpld_mode; -+ -+ sub_slot = DFD_KO_CPLD_GET_SLOT(addr); -+ cpld_id = DFD_KO_CPLD_GET_ID(addr); -+ -+ ret = dfd_cfg_get_cpld_mode(sub_slot, cpld_id, &cpld_mode); -+ if (ret) { -+ DBG_DEBUG(DBG_WARN, "drv_get_cpld_mode sub_slot %d cpldid %d faile, set default i2c mode.\n", sub_slot, cpld_id); -+ cpld_mode = DFD_CPLD_MODE_I2C; -+ } -+ -+ if (cpld_mode == DFD_CPLD_MODE_I2C) { -+ ret = dfd_ko_cpld_i2c_read(addr, buf); -+ } else if (cpld_mode == DFD_CPLD_MODE_LPC) { -+ ret = dfd_ko_cpld_io_read(addr, buf); -+ } else { -+ DBG_DEBUG(DBG_ERROR, "cpld_mode %d invalid.\n", cpld_mode); -+ ret = -DFD_RV_DEV_NOTSUPPORT; -+ } -+ -+ DBG_DEBUG(DBG_VERBOSE, "addr 0x%x val 0x%x ret %d\n", addr, *buf, ret); -+ return ret; -+} -+ -+int32_t dfd_ko_cpld_write(int32_t addr, uint8_t val) -+{ -+ int ret; -+ int sub_slot, cpld_id, cpld_mode; -+ -+ sub_slot = DFD_KO_CPLD_GET_SLOT(addr); -+ cpld_id = DFD_KO_CPLD_GET_ID(addr); -+ -+ ret = dfd_cfg_get_cpld_mode(sub_slot, cpld_id, &cpld_mode); -+ if (ret) { -+ DBG_DEBUG(DBG_ERROR, "drv_get_cpld_mode sub_slot %d cpldid %d faile, set default local_bus mode.\n", sub_slot, cpld_id); -+ cpld_mode = DFD_CPLD_MODE_I2C; -+ } -+ -+ if (cpld_mode == DFD_CPLD_MODE_I2C) { -+ ret = dfd_ko_cpld_i2c_write(addr, val); -+ } else if (cpld_mode == DFD_CPLD_MODE_LPC) { -+ ret = dfd_ko_cpld_io_write(addr, val); -+ } else { -+ DBG_DEBUG(DBG_ERROR, "cpld_mode %d invalid.\n", cpld_mode); -+ ret = -DFD_RV_DEV_NOTSUPPORT; -+ } -+ -+ DBG_DEBUG(DBG_VERBOSE, "addr 0x%x val 0x%x ret %d\n", addr, val, ret); -+ return ret; -+} -+ -+int32_t dfd_ko_i2c_read(int bus, int addr, int offset, uint8_t *buf, uint32_t size) -+{ -+ int i, rv; -+ -+ for (i = 0; i < size; i++) { -+ rv = dfd_ko_i2c_read_data(bus, addr, offset, &buf[i], sizeof(uint8_t)); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "dfd_ko_i2c_read[bus=%d addr=0x%x offset=0x%x]fail, rv=%d\n", -+ bus, addr, offset, rv); -+ return rv; -+ } -+ offset++; -+ } -+ -+ return size; -+} -+ -+int32_t dfd_ko_i2c_write(int bus, int addr, int offset, uint8_t *buf, uint32_t size) -+{ -+ int i, rv; -+ -+ for (i = 0; i < size; i++) { -+ rv = dfd_ko_i2c_write_data(bus, addr, offset, buf[i], sizeof(uint8_t)); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "dfd_ko_i2c_write[bus=%d addr=0x%x offset=0x%x]fail, rv=%d\n", -+ bus, addr, offset, rv); -+ return rv; -+ } -+ offset++; -+ } -+ -+ return size; -+ -+} -+ -+int32_t dfd_ko_read_file(char *fpath, int32_t addr, uint8_t *val, int32_t read_bytes) -+{ -+ int32_t ret; -+ struct file *filp; -+ loff_t pos; -+ -+ if ((fpath == NULL) || (val == NULL) || (addr < 0) || (read_bytes < 0)) { -+ DBG_DEBUG(DBG_ERROR, "input arguments error, addr=%d read_bytes=%d\n", addr, read_bytes); -+ return -DFD_RV_INDEX_INVALID; -+ } -+ -+ filp = filp_open(fpath, O_RDONLY, 0); -+ if (IS_ERR(filp)){ -+ DBG_DEBUG(DBG_ERROR, "open file[%s] fail\n", fpath); -+ return -DFD_RV_DEV_FAIL; -+ } -+ -+ pos = addr; -+ ret = kernel_read(filp, val, read_bytes, &pos); -+ if (ret < 0) { -+ DBG_DEBUG(DBG_ERROR, "kernel_read failed, path=%s, addr=%d, size=%d, ret=%d\n", fpath, addr, read_bytes, ret); -+ ret = -DFD_RV_DEV_FAIL; -+ } -+ -+ filp_close(filp, NULL); -+ return ret; -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c -new file mode 100644 -index 000000000..8d77759ba ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c -@@ -0,0 +1,236 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "../include/dfd_cfg_file.h" -+#include "../include/dfd_module.h" -+#include "../../dev_sysfs/include/sysfs_common.h" -+ -+struct getdents_callback { -+ struct dir_context ctx; -+ const char *obj_name; -+ char *match_name; -+ int dir_len; -+ int found; -+}; -+ -+int kfile_open(char *fname, kfile_ctrl_t *kfile_ctrl) -+{ -+ int ret; -+ struct file *filp; -+ loff_t pos; -+ -+ if ((fname == NULL) || (kfile_ctrl == NULL)) { -+ return KFILE_RV_INPUT_ERR; -+ } -+ -+ filp = filp_open(fname, O_RDONLY, 0); -+ if (IS_ERR(filp)){ -+ return KFILE_RV_OPEN_FAIL; -+ } -+ -+ kfile_ctrl->size = filp->f_inode->i_size; -+ -+ kfile_ctrl->buf = kmalloc(kfile_ctrl->size, GFP_KERNEL); -+ if (kfile_ctrl->buf == NULL) { -+ ret = KFILE_RV_MALLOC_FAIL; -+ goto close_fp; -+ } -+ mem_clear(kfile_ctrl->buf, kfile_ctrl->size); -+ -+ pos = 0; -+ ret = kernel_read(filp, kfile_ctrl->buf, kfile_ctrl->size, &pos); -+ if (ret < 0) { -+ ret = KFILE_RV_RD_FAIL; -+ goto free_buf; -+ } -+ -+ kfile_ctrl->pos = 0; -+ -+ ret = KFILE_RV_OK; -+ goto close_fp; -+ -+free_buf: -+ kfree(kfile_ctrl->buf); -+ kfile_ctrl->buf = NULL; -+ -+close_fp: -+ filp_close(filp, NULL); -+ return ret; -+} -+ -+void kfile_close(kfile_ctrl_t *kfile_ctrl) -+{ -+ if (kfile_ctrl == NULL) { -+ return; -+ } -+ -+ kfile_ctrl->size = 0; -+ kfile_ctrl->pos = 0; -+ if (kfile_ctrl->buf) { -+ kfree(kfile_ctrl->buf); -+ kfile_ctrl->buf = NULL; -+ } -+} -+ -+int kfile_gets(char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl) -+{ -+ int i; -+ int has_cr = 0; -+ -+ if ((buf == NULL) || (buf_size <= 0) || (kfile_ctrl == NULL) || (kfile_ctrl->buf == NULL) -+ || (kfile_ctrl->size <= 0)) { -+ return KFILE_RV_INPUT_ERR; -+ } -+ -+ mem_clear(buf, buf_size); -+ for (i = 0; i < buf_size; i++) { -+ -+ if (kfile_ctrl->pos >= kfile_ctrl->size) { -+ break; -+ } -+ -+ if (has_cr) { -+ break; -+ } -+ -+ if (IS_CR(kfile_ctrl->buf[kfile_ctrl->pos])) { -+ has_cr = 1; -+ } -+ -+ buf[i] = kfile_ctrl->buf[kfile_ctrl->pos]; -+ kfile_ctrl->pos++; -+ } -+ -+ return i; -+} -+ -+int kfile_read(int32_t addr, char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl) -+{ -+ int i; -+ -+ if ((buf == NULL) || (buf_size <= 0) || (kfile_ctrl == NULL) || (kfile_ctrl->buf == NULL) -+ || (kfile_ctrl->size <= 0)) { -+ return KFILE_RV_INPUT_ERR; -+ } -+ -+ if ((addr < 0) || (addr >= kfile_ctrl->size)) { -+ return KFILE_RV_ADDR_ERR; -+ } -+ -+ mem_clear(buf, buf_size); -+ -+ kfile_ctrl->pos = addr; -+ for (i = 0; i < buf_size; i++) { -+ -+ if (kfile_ctrl->pos >= kfile_ctrl->size) { -+ break; -+ } -+ -+ buf[i] = kfile_ctrl->buf[kfile_ctrl->pos]; -+ kfile_ctrl->pos++; -+ } -+ -+ return i; -+} -+ -+static int kfile_filldir_one(struct dir_context *ctx, const char * name, int len, -+ loff_t pos, u64 ino, unsigned int d_type) -+{ -+ struct getdents_callback *buf ; -+ int result; -+ buf = container_of(ctx, struct getdents_callback, ctx); -+ result = 0; -+ if (strncmp(buf->obj_name, name, strlen(buf->obj_name)) == 0) { -+ if (buf->dir_len < len) { -+ DBG_DEBUG(DBG_ERROR, "match ok. dir name:%s, but buf_len %d small than dir len %d.\n", -+ name, buf->dir_len, len); -+ buf->found = 0; -+ return -1; -+ } -+ mem_clear(buf->match_name, buf->dir_len); -+ memcpy(buf->match_name, name, len); -+ buf->found = 1; -+ result = -1; -+ } -+ return result; -+} -+ -+int kfile_iterate_dir(const char *dir_path, const char *obj_name, char *match_name, int len) -+{ -+ int ret; -+ struct file *dir; -+ struct getdents_callback buffer = { -+ .ctx.actor = kfile_filldir_one, -+ }; -+ -+ if(!dir_path || !obj_name || !match_name) { -+ DBG_DEBUG(DBG_ERROR, "params error. \n"); -+ return KFILE_RV_INPUT_ERR; -+ } -+ buffer.obj_name = obj_name; -+ buffer.match_name = match_name; -+ buffer.dir_len = len; -+ buffer.found = 0; -+ -+ dir = filp_open(dir_path, O_RDONLY, 0); -+ if (IS_ERR(dir)) { -+ DBG_DEBUG(DBG_ERROR, "filp_open error, dir path:%s\n", dir_path); -+ return KFILE_RV_OPEN_FAIL; -+ } -+ ret = iterate_dir(dir, &buffer.ctx); -+ if (buffer.found) { -+ DBG_DEBUG(DBG_VERBOSE, "match ok, dir name:%s\n", match_name); -+ filp_close(dir, NULL); -+ return DFD_RV_OK; -+ } -+ filp_close(dir, NULL); -+ return -DFD_RV_NODE_FAIL; -+} -+ -+#if 0 -+ -+int kfile_write(char *fpath, int32_t addr, char *buf, int buf_size) -+{ -+ int ret = KFILE_RV_OK; -+ struct file *filp; -+ mm_segment_t old_fs; -+ int wlen; -+ -+ if ((fpath == NULL) || (buf == NULL) || (buf_size <= 0)) { -+ return KFILE_RV_INPUT_ERR; -+ } -+ -+ if (addr < 0) { -+ return KFILE_RV_ADDR_ERR; -+ } -+ -+ filp = filp_open(fpath, O_RDWR, 0); -+ if (IS_ERR(filp)){ -+ return KFILE_RV_OPEN_FAIL; -+ } -+ -+ old_fs = get_fs(); -+ set_fs(KERNEL_DS); -+ -+ filp->f_op->llseek(filp,0,0); -+ filp->f_pos = addr; -+ -+ wlen = filp->f_op->write(filp, buf, buf_size, &(filp->f_pos)); -+ if (wlen < 0) { -+ ret = KFILE_RV_WR_FAIL; -+ } -+ -+ filp->f_op->llseek(filp,0,0); -+ set_fs(old_fs); -+ filp_close(filp, NULL); -+ -+ return ret; -+} -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c -new file mode 100644 -index 000000000..f8d64dcac ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c -@@ -0,0 +1,771 @@ -+#include -+#include -+#include -+ -+#include "../include/dfd_module.h" -+#include "../include/dfd_cfg_adapter.h" -+#include "../include/dfd_cfg.h" -+#include "../include/dfd_cfg_info.h" -+#include "../include/dfd_cfg_file.h" -+#include "../../dev_sysfs/include/sysfs_common.h" -+ -+#define DFD_HWMON_NAME "hwmon" -+/* CPLD_VOLATGE_VALUE_MODE1 */ -+#define DFD_GET_CPLD_VOLATGE_CODE_VALUE(value) ((value >> 4)& 0xfff) -+/* ((code_val * 16 * 33 * k) / ((65536 - 5000) * 10)) = ((code_val * 33 * k) / 37835) */ -+#define DFD_GET_CPLD_VOLATGE_REAL_VALUE(code_val, k) ((code_val * 33 * k) / 37835) -+ -+ -+/* CPLD_VOLATGE_VALUE_MODE2 */ -+/* high 8 bit + low 4 bit(bit0-bit3) */ -+#define DFD_GET_CPLD_VOLATGE_CODE_VALUE2(value) (((value & 0xff00) >> 4) + (value & 0xf)) -+#define DFD_GET_CPLD_VOLATGE_REAL_VALUE2(code_val, k) ((code_val * 33 * k) / 40950) -+ -+typedef enum cpld_volatge_value_s { -+ CPLD_VOLATGE_VALUE_MODE1, -+ CPLD_VOLATGE_VALUE_MODE2, -+} cpld_volatge_value_t; -+ -+char *g_info_ctrl_mem_str[INFO_CTRL_MEM_END] = { -+ ".mode", -+ ".int_cons", -+ ".src", -+ ".frmt", -+ ".pola", -+ ".fpath", -+ ".addr", -+ ".len", -+ ".bit_offset", -+ ".str_cons", -+ ".int_extra1", -+ ".int_extra2", -+ ".int_extra3", -+}; -+ -+char *g_info_ctrl_mode_str[INFO_CTRL_MODE_END] = { -+ "none", -+ "config", -+ "constant", -+ "tlv", -+ "str_constant", -+}; -+ -+char *g_info_src_str[INFO_SRC_END] = { -+ "none", -+ "cpld", -+ "fpga", -+ "other_i2c", -+ "file", -+}; -+ -+char *g_info_frmt_str[INFO_FRMT_END] = { -+ "none", -+ "bit", -+ "byte", -+ "num_bytes", -+ "num_str", -+ "num_buf", -+ "buf", -+}; -+ -+char *g_info_pola_str[INFO_POLA_END] = { -+ "none", -+ "positive", -+ "negative", -+}; -+ -+static int dfd_read_info_from_cpld(int32_t addr, int read_bytes, uint8_t *val) -+{ -+ int i, rv; -+ -+ for (i = 0; i < read_bytes; i++) { -+ rv = dfd_ko_cpld_read(addr, &(val[i])); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "read info[addr=0x%x read_bytes=%d] from cpld fail, reading_byte=%d rv=%d\n", -+ addr, read_bytes, i, rv); -+ return rv; -+ } -+ addr++; -+ } -+ -+ return read_bytes; -+} -+ -+static int dfd_write_info_to_cpld(int32_t addr, int write_bytes, uint8_t *val, uint8_t bit_mask) -+{ -+ int rv; -+ uint8_t val_tmp; -+ -+ if (bit_mask != 0xff) { -+ rv = dfd_ko_cpld_read(addr, &val_tmp); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "read original info[addr=0x%x] from cpld fail, rv=%d\n", addr, rv); -+ return -1; -+ } -+ -+ val_tmp = (val_tmp & (~bit_mask)) | (val[0] & bit_mask); -+ } else { -+ val_tmp = val[0]; -+ } -+ -+ rv = dfd_ko_cpld_write(addr, val_tmp); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "write info[addr=0x%x val=0x%x] to cpld fail, rv=%d\n", addr, val_tmp, rv); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int dfd_read_info(info_src_t src, char *fpath, int32_t addr, int read_bytes, uint8_t *val) -+{ -+ int rv = 0; -+ -+ switch (src) { -+ case INFO_SRC_CPLD: -+ rv = dfd_read_info_from_cpld(addr, read_bytes, val); -+ break; -+ case INFO_SRC_FPGA: -+ rv = -1; -+ DBG_DEBUG(DBG_ERROR, "not support read info from fpga\n"); -+ break; -+ case INFO_SRC_OTHER_I2C: -+ rv = -1; -+ DBG_DEBUG(DBG_ERROR, "not support read info from other i2c\n"); -+ break; -+ case INFO_SRC_FILE: -+ rv = dfd_ko_read_file(fpath, addr, val, read_bytes); -+ break; -+ default: -+ rv = -1; -+ DBG_DEBUG(DBG_ERROR, "info src[%d] error\n", src); -+ break; -+ } -+ -+ return rv; -+} -+ -+static int dfd_write_info(info_src_t src, char *fpath, int32_t addr, int write_bytes, uint8_t *val, uint8_t bit_mask) -+{ -+ int rv = 0; -+ -+ switch (src) { -+ case INFO_SRC_CPLD: -+ rv = dfd_write_info_to_cpld(addr, write_bytes, val, bit_mask); -+ break; -+ case INFO_SRC_FPGA: -+ rv = -1; -+ DBG_DEBUG(DBG_ERROR, "not support write info to fpga\n"); -+ break; -+ case INFO_SRC_OTHER_I2C: -+ rv = -1; -+ DBG_DEBUG(DBG_ERROR, "not support write info to other i2c\n"); -+ break; -+ case INFO_SRC_FILE: -+ rv = -1; -+ DBG_DEBUG(DBG_ERROR, "not support write info to file\n"); -+ break; -+ default: -+ rv = -1; -+ DBG_DEBUG(DBG_ERROR, "info src[%d] error\n", src); -+ break; -+ } -+ -+ return rv; -+} -+ -+static int dfd_get_info_value(info_ctrl_t *info_ctrl, int *ret, info_num_buf_to_value_f pfun) -+{ -+ int i, rv; -+ int read_bytes, readed_bytes, int_tmp; -+ uint8_t byte_tmp, val[INFO_INT_MAX_LEN + 1] = {0}; -+ -+ if (info_ctrl->mode == INFO_CTRL_MODE_CONS) { -+ *ret = info_ctrl->int_cons; -+ return DFD_RV_OK; -+ } -+ if (info_ctrl->mode == INFO_CTRL_MODE_TLV) { -+ return INFO_CTRL_MODE_TLV; -+ } -+ -+ if (IS_INFO_FRMT_BIT(info_ctrl->frmt)) { -+ if (!INFO_BIT_OFFSET_VALID(info_ctrl->bit_offset)) { -+ DBG_DEBUG(DBG_ERROR, "info ctrl bit_offsest[%d] invalid\n", -+ info_ctrl->bit_offset); -+ return -DFD_RV_TYPE_ERR; -+ } -+ read_bytes = 1; -+ } else if (IS_INFO_FRMT_BYTE(info_ctrl->frmt) || IS_INFO_FRMT_NUM_STR(info_ctrl->frmt) -+ || IS_INFO_FRMT_NUM_BUF(info_ctrl->frmt)) { -+ if (!INFO_INT_LEN_VALAID(info_ctrl->len)) { -+ DBG_DEBUG(DBG_ERROR, "info ctrl len[%d] invalid\n", info_ctrl->len); -+ return -DFD_RV_TYPE_ERR; -+ } -+ read_bytes = info_ctrl->len; -+ } else { -+ DBG_DEBUG(DBG_ERROR, "info ctrl info format[%d] error\n", info_ctrl->frmt); -+ return -DFD_RV_TYPE_ERR; -+ } -+ -+ readed_bytes = dfd_read_info(info_ctrl->src, info_ctrl->fpath, info_ctrl->addr, read_bytes, &(val[0])); -+ if (readed_bytes <= 0) { -+ DBG_DEBUG(DBG_ERROR, "read int info[src=%s frmt=%s fpath=%s addr=0x%x read_bytes=%d] fail, rv=%d\n", -+ g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], info_ctrl->fpath, -+ info_ctrl->addr, read_bytes, readed_bytes); -+ return -DFD_RV_DEV_FAIL; -+ } -+ -+ if (IS_INFO_FRMT_BIT(info_ctrl->frmt)) { -+ if (info_ctrl->pola == INFO_POLA_NEGA) { -+ val[0] = ~val[0]; -+ } -+ byte_tmp = (val[0] >> info_ctrl->bit_offset) & (~(0xff << info_ctrl->len)); -+ if (pfun) { -+ rv = pfun(&byte_tmp, sizeof(byte_tmp), &int_tmp); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "info ctrl bit process fail, rv=%d\n", rv); -+ return rv; -+ } -+ } else { -+ int_tmp = (int)byte_tmp; -+ } -+ } else if (IS_INFO_FRMT_BYTE(info_ctrl->frmt)) { -+ int_tmp = 0; -+ for (i = 0; i < info_ctrl->len; i++) { -+ if (info_ctrl->pola == INFO_POLA_NEGA) { -+ int_tmp |= val[info_ctrl->len - i - 1]; -+ } else { -+ int_tmp |= val[i]; -+ } -+ if (i != (info_ctrl->len - 1)) { -+ int_tmp <<= 8; -+ } -+ } -+ } else if (IS_INFO_FRMT_NUM_STR(info_ctrl->frmt)) { -+ val[readed_bytes] = '\0'; -+ int_tmp = simple_strtol((char *)(&(val[0])), NULL, 10); -+ } else { -+ if (pfun == NULL) { -+ DBG_DEBUG(DBG_ERROR, "info ctrl number buf process function is null\n"); -+ return -DFD_RV_INDEX_INVALID; -+ } -+ rv = pfun(val, readed_bytes, &int_tmp); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "info ctrl number buf process fail, rv=%d\n", rv); -+ return rv; -+ } -+ } -+ -+ *ret = int_tmp; -+ DBG_DEBUG(DBG_VERBOSE, "read int info[src=%s frmt=%s pola=%s fpath=%s addr=0x%x len=%d bit_offset=%d] success, ret=%d\n", -+ g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], g_info_pola_str[info_ctrl->pola], -+ info_ctrl->fpath, info_ctrl->addr, info_ctrl->len, info_ctrl->bit_offset, *ret); -+ return DFD_RV_OK; -+} -+ -+int dfd_info_get_int(int key, int *ret, info_num_buf_to_value_f pfun) -+{ -+ int rv; -+ info_ctrl_t *info_ctrl; -+ -+ if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key)) || (ret == NULL)) { -+ DBG_DEBUG(DBG_ERROR, "input arguments error, key=0x%08x\n", key); -+ return -DFD_RV_INDEX_INVALID; -+ } -+ -+ info_ctrl = dfd_ko_cfg_get_item(key); -+ if (info_ctrl == NULL) { -+ DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ -+ DBG_DEBUG(DBG_VERBOSE, "get info ctrl value, key=0x%08x\n", key); -+ rv = dfd_get_info_value(info_ctrl, ret, pfun); -+ return rv; -+} -+ -+int dfd_info_get_buf(int key, uint8_t *buf, int buf_len, info_buf_to_buf_f pfun) -+{ -+ int rv; -+ int read_bytes, buf_real_len; -+ uint8_t buf_tmp[INFO_BUF_MAX_LEN]; -+ info_ctrl_t *info_ctrl; -+ -+ if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key)) || (buf == NULL)) { -+ DBG_DEBUG(DBG_ERROR, "input arguments error, key=0x%08x\n", key); -+ return -DFD_RV_INDEX_INVALID; -+ } -+ -+ info_ctrl = dfd_ko_cfg_get_item(key); -+ if (info_ctrl == NULL) { -+ DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ -+ if (info_ctrl->mode != INFO_CTRL_MODE_CFG) { -+ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] mode[%d] invalid\n", key, info_ctrl->mode); -+ return -DFD_RV_TYPE_ERR; -+ } -+ -+ if (!IS_INFO_FRMT_BUF(info_ctrl->frmt) || !INFO_BUF_LEN_VALAID(info_ctrl->len) -+ || (buf_len <= info_ctrl->len)) { -+ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] format=%d or len=%d invlaid, buf_len=%d\n", -+ key, info_ctrl->frmt, info_ctrl->len, buf_len); -+ return -DFD_RV_TYPE_ERR; -+ } -+ -+ read_bytes = dfd_read_info(info_ctrl->src, info_ctrl->fpath, info_ctrl->addr, info_ctrl->len, buf_tmp); -+ if (read_bytes <= 0) { -+ DBG_DEBUG(DBG_ERROR, "read buf info[key=0x%08x src=%s frmt=%s fpath=%s addr=0x%x len=%d] fail, rv=%d\n", -+ key, g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], info_ctrl->fpath, -+ info_ctrl->addr, info_ctrl->len, read_bytes); -+ return -DFD_RV_DEV_FAIL; -+ } -+ -+ if (pfun) { -+ buf_real_len = buf_len; -+ rv = pfun(buf_tmp, read_bytes, buf, &buf_real_len); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] buf process fail, rv=%d\n", key, rv); -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ } else { -+ buf_real_len = read_bytes; -+ memcpy(buf, buf_tmp, read_bytes); -+ } -+ -+ return buf_real_len; -+} -+ -+static int dfd_2key_info_get_buf(info_ctrl_t *info_ctrl, uint8_t *buf, int buf_len, info_hwmon_buf_f pfun) -+{ -+ int rv; -+ int read_bytes, buf_real_len; -+ uint8_t buf_tmp[INFO_BUF_MAX_LEN]; -+ char temp_fpath[INFO_FPATH_MAX_LEN]; -+ -+ if (!IS_INFO_FRMT_BUF(info_ctrl->frmt) || !INFO_BUF_LEN_VALAID(info_ctrl->len) -+ || (buf_len <= info_ctrl->len)) { -+ DBG_DEBUG(DBG_ERROR, "key_path info ctrl format=%d or len=%d invlaid, buf_len=%d\n", -+ info_ctrl->frmt, info_ctrl->len, buf_len); -+ return -DFD_RV_TYPE_ERR; -+ } -+ -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ rv = kfile_iterate_dir(info_ctrl->fpath, DFD_HWMON_NAME, buf_tmp, INFO_BUF_MAX_LEN); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "dir patch:%s ,can find name %s dir \n", -+ info_ctrl->fpath, DFD_HWMON_NAME); -+ return -DFD_RV_NO_NODE; -+ } -+ mem_clear(temp_fpath, sizeof(temp_fpath)); -+ snprintf(temp_fpath, sizeof(temp_fpath), "%s%s/%s", -+ info_ctrl->fpath, buf_tmp, info_ctrl->str_cons); -+ DBG_DEBUG(DBG_VERBOSE, "match ok path = %s \n", temp_fpath); -+ -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ -+ read_bytes = dfd_read_info(info_ctrl->src, temp_fpath, info_ctrl->addr, info_ctrl->len, buf_tmp); -+ if (read_bytes <= 0) { -+ DBG_DEBUG(DBG_ERROR, "read buf info[src=%s frmt=%s fpath=%s addr=0x%x len=%d] fail, rv=%d\n", -+ g_info_src_str[info_ctrl->src], g_info_src_str[info_ctrl->frmt], temp_fpath, -+ info_ctrl->addr, info_ctrl->len, read_bytes); -+ return -DFD_RV_DEV_FAIL; -+ } -+ -+ if (pfun) { -+ buf_real_len = buf_len; -+ rv = pfun(buf_tmp, read_bytes, buf, &buf_real_len, info_ctrl); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "info ctrl buf process fail, rv=%d\n", rv); -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ } else { -+ buf_real_len = read_bytes; -+ memcpy(buf, buf_tmp, buf_real_len); -+ } -+ return buf_real_len; -+} -+ -+int dfd_info_set_int(int key, int val) -+{ -+ int rv; -+ int write_bytes; -+ uint8_t byte_tmp, bit_mask; -+ info_ctrl_t *info_ctrl; -+ -+ if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key))) { -+ DBG_DEBUG(DBG_ERROR, "input arguments error, key=0x%08x\n", key); -+ return -DFD_RV_INDEX_INVALID; -+ } -+ -+ info_ctrl = dfd_ko_cfg_get_item(key); -+ if (info_ctrl == NULL) { -+ DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ -+ if (info_ctrl->mode != INFO_CTRL_MODE_CFG) { -+ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] mode[%d] warnning\n", key, info_ctrl->mode); -+ return -DFD_RV_TYPE_ERR; -+ } -+ -+ if (IS_INFO_FRMT_BIT(info_ctrl->frmt)) { -+ -+ if (!INFO_BIT_OFFSET_VALID(info_ctrl->bit_offset)) { -+ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] bit_offsest[%d] invalid\n", -+ key, info_ctrl->bit_offset); -+ return -DFD_RV_TYPE_ERR; -+ } -+ -+ write_bytes = 1; -+ -+ byte_tmp = (uint8_t)(val & 0xff); -+ byte_tmp <<= info_ctrl->bit_offset; -+ if (info_ctrl->pola == INFO_POLA_NEGA) { -+ byte_tmp = ~byte_tmp; -+ } -+ -+ bit_mask = (~(0xff << info_ctrl->len)) << info_ctrl->bit_offset; -+ } else if (IS_INFO_FRMT_BYTE(info_ctrl->frmt)) { -+ -+ if (!INFO_INT_LEN_VALAID(info_ctrl->len)) { -+ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] len[%d] invalid\n", key, info_ctrl->len); -+ return -DFD_RV_TYPE_ERR; -+ } -+ -+ write_bytes = 1; -+ -+ byte_tmp = (uint8_t)(val & 0xff); -+ -+ bit_mask = 0xff; -+ } else if (IS_INFO_FRMT_NUM_STR(info_ctrl->frmt)) { -+ -+ DBG_DEBUG(DBG_ERROR, "not support str int set\n"); -+ return -1; -+ } else if (IS_INFO_FRMT_NUM_BUF(info_ctrl->frmt)) { -+ -+ if (!INFO_INT_LEN_VALAID(info_ctrl->len)) { -+ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] len[%d] invalid\n", key, info_ctrl->len); -+ return -DFD_RV_TYPE_ERR; -+ } -+ -+ write_bytes = 1; -+ -+ byte_tmp = (uint8_t)(val & 0xff); -+ -+ bit_mask = 0xff; -+ } else { -+ DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] format[%d] error\n", key, info_ctrl->frmt); -+ return -DFD_RV_TYPE_ERR; -+ } -+ -+ rv = dfd_write_info(info_ctrl->src, info_ctrl->fpath, info_ctrl->addr, write_bytes, -+ &byte_tmp, bit_mask); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "write int info[src=%s frmt=%s fpath=%s addr=0x%x len=%d val=%d] fail, rv=%d\n", -+ g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], info_ctrl->fpath, -+ info_ctrl->addr, info_ctrl->len, val, rv); -+ return -DFD_RV_DEV_FAIL; -+ } -+ -+ DBG_DEBUG(DBG_VERBOSE, "write int info[src=%s frmt=%s pola=%s fpath=%s addr=0x%x len=%d bit_offset=%d val=%d] success\n", -+ g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], g_info_pola_str[info_ctrl->pola], -+ info_ctrl->fpath, info_ctrl->addr, info_ctrl->len, info_ctrl->bit_offset, val); -+ return DFD_RV_OK; -+} -+ -+static int dfd_info_reg2data_linear(int key, int data, int *temp_value) -+{ -+ s16 exponent; -+ s32 mantissa; -+ int val; -+ info_ctrl_t *info_ctrl; -+ -+ info_ctrl = dfd_ko_cfg_get_item(key); -+ if (info_ctrl == NULL) { -+ DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=%d\n", key); -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ -+ switch (info_ctrl->int_extra1) { -+ case LINEAR11: -+ exponent = ((s16)data) >> 11; -+ mantissa = ((s16)((data & 0x7ff) << 5)) >> 5; -+ val = mantissa; -+ val = val * 1000L; -+ break; -+ case LINEAR16: -+ break; -+ default: -+ break; -+ } -+ -+ if (DFD_CFG_ITEM_ID(key) == DFD_CFG_ITEM_HWMON_POWER) { -+ val = val * 1000L; -+ } -+ -+ if (exponent >= 0) { -+ val <<= exponent; -+ } else { -+ val >>= -exponent; -+ } -+ *temp_value = val; -+ -+ return DFD_RV_OK; -+} -+ -+static int dfd_info_reg2data_tmp464(int data, int *temp_value) -+{ -+ s16 tmp_val; -+ int val; -+ -+ DBG_DEBUG(DBG_VERBOSE, "reg2data_tmp464, data=%d\n", data); -+ -+ if (data >= 0) { -+ val = data*625/80; -+ } else { -+ tmp_val = ~(data & 0x7ff) + 1; -+ val = tmp_val*625/80; -+ } -+ *temp_value = val; -+ -+ return DFD_RV_OK; -+} -+ -+static int dfd_info_reg2data_mac_th5(int data, int *temp_value) -+{ -+ int tmp_val; -+ int val; -+ -+ DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_th5, data=%d\n", data); -+ -+ tmp_val = data >> 4; -+ val = 476359 - (((tmp_val - 2) * 317704) / 2000); -+ -+ DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_th5, val=%d\n", val); -+ *temp_value = val; -+ -+ return DFD_RV_OK; -+} -+ -+static int dfd_info_reg2data_mac_td3(int data, int *temp_value) -+{ -+ int val; -+ -+ if (data == 0) { -+ DBG_DEBUG(DBG_ERROR,"invalid cpld data=%d\n", data); -+ *temp_value = -READ_TEMP_FAIL; -+ return DFD_RV_OK; -+ } -+ -+ DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_td3, data=%d\n", data); -+ val = 434100 - (12500000 / (data * 100 - 1) *535); -+ if ((val / 1000 < -70) || (val / 1000 > 200)) { -+ DBG_DEBUG(DBG_ERROR,"out of range cpld val=%d\n", val); -+ *temp_value = -READ_TEMP_FAIL; -+ return DFD_RV_OK; -+ } -+ DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_td3, val=%d\n", val); -+ *temp_value = val; -+ -+ return DFD_RV_OK; -+} -+ -+static int dfd_info_get_cpld_voltage(int key, uint32_t *value) -+{ -+ int rv; -+ uint32_t vol_ref_tmp, vol_ref; -+ uint32_t vol_curr_tmp, vol_curr; -+ info_ctrl_t *info_ctrl; -+ info_ctrl_t info_ctrl_tmp; -+ uint32_t vol_coefficient; -+ -+ info_ctrl = dfd_ko_cfg_get_item(key); -+ if (info_ctrl == NULL) { -+ DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ -+ vol_coefficient = (uint32_t)info_ctrl->int_extra2; -+ -+ rv = dfd_get_info_value(info_ctrl, &vol_curr_tmp, NULL); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "get cpld current voltage error, addr:0x%x, rv = %d\n", info_ctrl->addr, rv); -+ return rv; -+ } -+ if (info_ctrl->int_extra3 == CPLD_VOLATGE_VALUE_MODE2) { -+ vol_curr_tmp = DFD_GET_CPLD_VOLATGE_CODE_VALUE2(vol_curr_tmp); -+ vol_curr = DFD_GET_CPLD_VOLATGE_REAL_VALUE2(vol_curr_tmp, vol_coefficient); -+ DBG_DEBUG(DBG_VERBOSE, "vol_curr_tmp = 0x%x, vol_curr = 0x%x, is same.\n", vol_curr_tmp, vol_curr); -+ } else { -+ vol_curr_tmp = DFD_GET_CPLD_VOLATGE_CODE_VALUE(vol_curr_tmp); -+ if (info_ctrl->addr == info_ctrl->int_extra1) { -+ vol_curr = DFD_GET_CPLD_VOLATGE_REAL_VALUE(vol_curr_tmp, vol_coefficient); -+ DBG_DEBUG(DBG_VERBOSE, "current voltage is reference voltage, vol_curr_tmp: 0x%x, coefficient: %u, vol_curr: %u\n", -+ vol_curr_tmp, vol_coefficient, vol_curr); -+ } else { -+ memcpy(&info_ctrl_tmp, info_ctrl, sizeof(info_ctrl_t)); -+ info_ctrl_tmp.addr = info_ctrl->int_extra1; -+ rv = dfd_get_info_value(&info_ctrl_tmp, &vol_ref_tmp, NULL); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "get cpld reference voltage error, addr: 0x%x, rv: %d\n", info_ctrl_tmp.addr, rv); -+ return rv; -+ } -+ vol_ref = DFD_GET_CPLD_VOLATGE_CODE_VALUE(vol_ref_tmp); -+ DBG_DEBUG(DBG_VERBOSE, "vol_ref_tmp: 0x%x, vol_ref: 0x%x\n", vol_ref_tmp, vol_ref); -+ vol_curr = (vol_curr_tmp * vol_coefficient) / vol_ref; -+ DBG_DEBUG(DBG_VERBOSE, "vol_curr_tmp: 0x%x, vol_ref: 0x%x, coefficient: %u, vol_curr: %u\n", -+ vol_curr_tmp, vol_ref, vol_coefficient, vol_curr); -+ } -+ } -+ *value = vol_curr; -+ return DFD_RV_OK; -+} -+ -+static int dfd_info_get_cpld_temperature(int key, int *value) -+{ -+ int rv; -+ int temp_reg; -+ int temp_value; -+ info_ctrl_t *info_ctrl; -+ -+ info_ctrl = dfd_ko_cfg_get_item(key); -+ if (info_ctrl == NULL) { -+ DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ -+ rv = dfd_info_get_int(key, &temp_reg, NULL); -+ if(rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "get cpld current temperature error, addr:0x%x, rv =%d\n", info_ctrl->addr, rv); -+ return rv; -+ } -+ DBG_DEBUG(DBG_VERBOSE, "get cpld temp:0x%08x, extra1 0x%x\n", temp_reg, info_ctrl->int_extra1); -+ -+ switch (info_ctrl->int_extra1) { -+ case LINEAR11: -+ rv = dfd_info_reg2data_linear(key, temp_reg, &temp_value); -+ break; -+ case TMP464: -+ rv = dfd_info_reg2data_tmp464(temp_reg, &temp_value); -+ break; -+ case MAC_TH5: -+ rv = dfd_info_reg2data_mac_th5(temp_reg, &temp_value); -+ break; -+ case MAC_TD3: -+ rv = dfd_info_reg2data_mac_td3(temp_reg, &temp_value); -+ break; -+ default: -+ temp_value = temp_reg; -+ rv = DFD_RV_OK; -+ break; -+ } -+ -+ DBG_DEBUG(DBG_VERBOSE, "calc temp:%d \n", temp_value); -+ *value = temp_value; -+ -+ return rv; -+} -+ -+static int dfd_info_get_sensor_value(int key, uint8_t *buf, int buf_len, info_hwmon_buf_f pfun) -+{ -+ int rv, buf_real_len; -+ uint32_t value; -+ uint8_t buf_tmp[INFO_BUF_MAX_LEN]; -+ info_ctrl_t *info_ctrl; -+ -+ info_ctrl = dfd_ko_cfg_get_item(key); -+ if (info_ctrl == NULL) { -+ DBG_DEBUG(DBG_ERROR, "get info ctrl fail, key=0x%08x\n", key); -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ -+ if ( DFD_CFG_ITEM_ID(key) == DFD_CFG_ITEM_HWMON_IN && info_ctrl->src == INFO_SRC_CPLD) { -+ rv = dfd_info_get_cpld_voltage(key, &value); -+ if(rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "get cpld voltage failed.key=0x%08x, rv:%d\n", key, rv); -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ DBG_DEBUG(DBG_VERBOSE, "get cpld voltage ok, value:%u\n", value); -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ snprintf(buf_tmp, sizeof(buf_tmp), "%u\n", value); -+ buf_real_len = strlen(buf_tmp); -+ if(buf_len <= buf_real_len) { -+ DBG_DEBUG(DBG_ERROR, "length not enough.buf_len:%d,need length:%d\n", buf_len, buf_real_len); -+ return -DFD_RV_DEV_FAIL; -+ } -+ if (pfun) { -+ buf_real_len = buf_len; -+ rv = pfun(buf_tmp, strlen(buf_tmp), buf, &buf_real_len, info_ctrl); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "deal date error.org value:%s, buf_len:%d, rv=%d\n", -+ buf_tmp, buf_len, rv); -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ } else { -+ memcpy(buf, buf_tmp, buf_real_len); -+ } -+ return buf_real_len; -+ } else if ( DFD_CFG_ITEM_ID(key) == DFD_CFG_ITEM_HWMON_TEMP && info_ctrl->src == INFO_SRC_CPLD ) { -+ rv = dfd_info_get_cpld_temperature(key, &value); -+ if(rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "get cpld temperature failed.key=0x%08x, rv:%d\n", key, rv); -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ DBG_DEBUG(DBG_VERBOSE, "get cpld temperature ok, value:%d buf_len %d\n", value, buf_len); -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ snprintf(buf_tmp, sizeof(buf_tmp), "%d\n", value); -+ buf_real_len = strlen(buf_tmp); -+ if(buf_len <= buf_real_len) { -+ DBG_DEBUG(DBG_ERROR, "length not enough.buf_len:%d,need length:%d\n", buf_len, buf_real_len); -+ return -DFD_RV_DEV_FAIL; -+ } -+ DBG_DEBUG(DBG_VERBOSE, "buf_real_len %d\n", buf_real_len); -+ memcpy(buf, buf_tmp, buf_real_len); -+ return buf_real_len; -+ } -+ -+ DBG_DEBUG(DBG_ERROR, "not support mode. key:0x%08x\n", key); -+ return -DFD_RV_MODE_NOTSUPPORT; -+} -+ -+int dfd_info_get_sensor(uint32_t key, char *buf, int buf_len, info_hwmon_buf_f pfun) -+{ -+ info_ctrl_t *key_info_ctrl; -+ int rv; -+ -+ if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key)) || -+ (buf == NULL) || buf_len <= 0) { -+ DBG_DEBUG(DBG_ERROR, "input arguments error, key_path=0x%08x, buf_len:%d.\n", -+ key, buf_len); -+ return -DFD_RV_INVALID_VALUE; -+ } -+ -+ key_info_ctrl = dfd_ko_cfg_get_item(key); -+ if (key_info_ctrl == NULL) { -+ DBG_DEBUG(DBG_ERROR, "key_path info error, key=0x%08x\n", key); -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ mem_clear(buf, buf_len); -+ -+ if (key_info_ctrl->mode == INFO_CTRL_MODE_SRT_CONS) { -+ snprintf(buf, buf_len, "%s\n", key_info_ctrl->str_cons); -+ DBG_DEBUG(DBG_VERBOSE, "get sensor value through string config, key=0x%08x, value:%s\n", key, buf); -+ return strlen(buf); -+ } -+ -+ if (key_info_ctrl->mode == INFO_CTRL_MODE_CFG && key_info_ctrl->src == INFO_SRC_FILE) { -+ DBG_DEBUG(DBG_VERBOSE, "get sensor value through hwmon, key:0x%08x\n", key); -+ rv = dfd_2key_info_get_buf(key_info_ctrl, buf, buf_len, pfun); -+ if (rv < 0) { -+ DBG_DEBUG(DBG_VERBOSE, "get sensor value through hwmon failed, key:0x%08x, rv:%d\n", key, rv); -+ } -+ return rv; -+ } -+ rv = dfd_info_get_sensor_value(key, buf, buf_len, pfun); -+ if( rv < 0) { -+ DBG_DEBUG(DBG_ERROR, "get sensor value failed, key=0x%08x, rv:%d.\n", key, rv); -+ } -+ return rv; -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c -new file mode 100644 -index 000000000..d6fd7e104 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c -@@ -0,0 +1,82 @@ -+#include -+#include -+ -+#include "../include/dfd_cfg_listnode.h" -+#include "../../dev_sysfs/include/sysfs_common.h" -+ -+void *lnode_find_node(lnode_root_t *root, int key) -+{ -+ lnode_node_t *lnode; -+ -+ if (root == NULL){ -+ return NULL; -+ } -+ -+ list_for_each_entry(lnode, &(root->root), lst) { -+ if (lnode->key == key) { -+ return lnode->data; -+ } -+ } -+ -+ return NULL; -+} -+ -+int lnode_insert_node(lnode_root_t *root, int key, void *data) -+{ -+ lnode_node_t *lnode; -+ void *data_tmp; -+ -+ if ((root == NULL) || (data == NULL)) { -+ return LNODE_RV_INPUT_ERR; -+ } -+ -+ data_tmp = lnode_find_node(root, key); -+ if (data_tmp != NULL) { -+ return LNODE_RV_NODE_EXIST; -+ } -+ -+ lnode = kmalloc(sizeof(lnode_node_t), GFP_KERNEL); -+ if (lnode == NULL) { -+ return LNODE_RV_NOMEM; -+ } -+ -+ lnode->key = key; -+ lnode->data = data; -+ list_add_tail(&(lnode->lst), &(root->root)); -+ -+ return LNODE_RV_OK; -+} -+ -+int lnode_init_root(lnode_root_t *root) -+{ -+ if (root == NULL) { -+ return LNODE_RV_INPUT_ERR; -+ } -+ -+ INIT_LIST_HEAD(&(root->root)); -+ -+ return LNODE_RV_OK; -+} -+ -+void lnode_free_list(lnode_root_t *root) -+{ -+ lnode_node_t *lnode, *lnode_next; -+ -+ if (root == NULL){ -+ return ; -+ } -+ -+ list_for_each_entry_safe(lnode, lnode_next, &(root->root), lst) { -+ if ( lnode->data ) { -+ kfree(lnode->data); -+ lnode->data = NULL; -+ lnode->key = 0; -+ } -+ list_del(&lnode->lst); -+ kfree(lnode); -+ lnode = NULL; -+ } -+ -+ return ; -+ -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_fan_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_fan_driver.c -new file mode 100644 -index 000000000..d8965d75c ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_fan_driver.c -@@ -0,0 +1,201 @@ -+#include -+#include -+ -+#include "./include/dfd_module.h" -+#include "./include/dfd_cfg.h" -+#include "./include/dfd_cfg_adapter.h" -+#include "./include/dfd_cfg_info.h" -+#include "../dev_sysfs/include/sysfs_common.h" -+ -+#define FAN_SIZE (256) -+ -+int g_dfd_fan_dbg_level = 0; -+module_param(g_dfd_fan_dbg_level, int, S_IRUGO | S_IWUSR); -+ -+typedef enum fan_speed_format_mem_s { -+ LINEAR120 = 1, -+} fan_speed_format_mem_t; -+ -+int dfd_get_fan_roll_status(unsigned int fan_index, unsigned int motor_index) -+{ -+ int key, ret; -+ int status; -+ -+ key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_ROLL_STATUS, fan_index, motor_index); -+ ret = dfd_info_get_int(key, &status, NULL); -+ if (ret < 0) { -+ DFD_FAN_DEBUG(DBG_ERROR, "get fan roll status error, fan:%d,motor:%d\n", -+ fan_index, motor_index); -+ return ret; -+ } -+ -+ DFD_FAN_DEBUG(DBG_VERBOSE, "fan%u motor%u get fan roll status success, status:%d.\n", -+ fan_index, motor_index, status); -+ return status; -+} -+ -+int dfd_get_fan_present_status(unsigned int fan_index) -+{ -+ int key, ret; -+ int status; -+ -+ key = DFD_CFG_KEY(DFD_CFG_ITEM_DEV_PRESENT_STATUS, WB_MAIN_DEV_FAN, fan_index); -+ ret = dfd_info_get_int(key, &status, NULL); -+ if (ret < 0) { -+ DFD_FAN_DEBUG(DBG_ERROR, "fan%u get present status error, key:0x%x\n", fan_index, key); -+ return ret; -+ } -+ -+ DFD_FAN_DEBUG(DBG_VERBOSE, "fan%u get present status success, status:%d.\n", fan_index, status); -+ return status; -+} -+ -+static int dfd_get_fan_speed_linear120(int origin_data, int *speed) -+{ -+ *speed = origin_data * 120; -+ DFD_FAN_DEBUG(DBG_VERBOSE, "get fan speed by linear120 origin_data: %d, speed: %d\n", -+ origin_data, *speed); -+ return 0; -+} -+ -+static int dfd_get_fan_speed_default(int origin_data, int *speed) -+{ -+ if (origin_data == 0 || origin_data == 0xffff) { -+ *speed = 0; -+ } else { -+ *speed = 15000000 / origin_data; -+ } -+ DFD_FAN_DEBUG(DBG_VERBOSE, "get fan speed by default origin_data: %d, speed: %d\n", -+ origin_data, *speed); -+ return 0; -+} -+ -+ssize_t dfd_get_fan_speed(unsigned int fan_index, unsigned int motor_index,unsigned int *speed) -+{ -+ int key, ret, speed_tmp; -+ info_ctrl_t *info_ctrl; -+ -+ if (speed == NULL) { -+ DFD_FAN_DEBUG(DBG_ERROR, "param error. fan index:%d, motor index:%d.\n", -+ fan_index, motor_index); -+ return -DFD_RV_INVALID_VALUE; -+ } -+ -+ key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_SPEED, fan_index, motor_index); -+ ret = dfd_info_get_int(key, &speed_tmp, NULL); -+ if (ret < 0) { -+ DFD_FAN_DEBUG(DBG_ERROR, "get fan speed error, key:0x%x,ret:%d\n",key, ret); -+ return ret; -+ } -+ DFD_FAN_DEBUG(DBG_VERBOSE, "get fan origin data: 0x%x\n", speed_tmp); -+ -+ info_ctrl = dfd_ko_cfg_get_item(key); -+ switch (info_ctrl->int_extra1) { -+ case LINEAR120: -+ ret = dfd_get_fan_speed_linear120(speed_tmp, speed); -+ break; -+ default: -+ ret = dfd_get_fan_speed_default(speed_tmp, speed); -+ break; -+ } -+ -+ return ret; -+} -+ -+int dfd_set_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int level) -+{ -+ int key, ret; -+ -+ if (level < 0 || level > 0xff) { -+ DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, can not set fan speed level: %d.\n", -+ fan_index, motor_index, level); -+ return -DFD_RV_INVALID_VALUE; -+ } -+ -+ key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_RATIO, fan_index, motor_index); -+ ret = dfd_info_set_int(key, level); -+ if (ret < 0) { -+ DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, set fan level 0x%02x error, key:0x%x,ret:%d\n", -+ fan_index, motor_index, level, key, ret); -+ return ret; -+ } -+ -+ DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, set fan speed level 0x%02x success.\n", -+ fan_index, motor_index, level); -+ return DFD_RV_OK; -+} -+ -+int dfd_set_fan_pwm(unsigned int fan_index, unsigned int motor_index, int pwm) -+{ -+ int ret, data; -+ -+ if (pwm < 0 || pwm > 100) { -+ DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, can't set pwm: %d.\n", -+ fan_index, motor_index, pwm); -+ return -DFD_RV_INVALID_VALUE; -+ } -+ -+ data = pwm * 255 / 100; -+ ret = dfd_set_fan_speed_level(fan_index, motor_index, data); -+ if (ret < 0) { -+ DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, set fan ratio:%d error, ret:%d\n", -+ fan_index, motor_index, data, ret); -+ return ret; -+ } -+ -+ DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, set fan ratio %d success.\n", -+ fan_index, motor_index, data); -+ return DFD_RV_OK; -+} -+ -+int dfd_get_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int *level) -+{ -+ int key, ret, speed_level; -+ -+ if (level == NULL) { -+ DFD_FAN_DEBUG(DBG_ERROR, "param error. fan index:%d, motor index:%d.\n", -+ fan_index, motor_index); -+ return -DFD_RV_INVALID_VALUE; -+ } -+ -+ key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_RATIO, fan_index, motor_index); -+ ret = dfd_info_get_int(key, &speed_level, NULL); -+ if (ret < 0) { -+ DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, get fan speed level error, key:0x%x,ret:%d\n", -+ fan_index, motor_index, key, ret); -+ return ret; -+ } -+ -+ DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, get fan speed level success, value:0x%02x.\n", -+ fan_index, motor_index, speed_level); -+ *level = speed_level; -+ return DFD_RV_OK; -+} -+ -+int dfd_get_fan_pwm(unsigned int fan_index, unsigned int motor_index, int *pwm) -+{ -+ int ret, level; -+ -+ if (pwm == NULL) { -+ DFD_FAN_DEBUG(DBG_ERROR, "param error. fan index:%d, motor index:%d.\n", -+ fan_index, motor_index); -+ return -DFD_RV_INVALID_VALUE; -+ } -+ -+ ret = dfd_get_fan_speed_level(fan_index, motor_index, &level); -+ if (ret < 0) { -+ DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, get fan pwm error, ret:%d\n", -+ fan_index, motor_index, ret); -+ return ret; -+ } -+ -+ if ((level * 100) % 255 > 0) { -+ *pwm = level * 100 / 255 + 1; -+ } else { -+ *pwm = level * 100 / 255; -+ } -+ -+ DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, get fan pwm success, value:%d.\n", -+ fan_index, motor_index, *pwm); -+ return DFD_RV_OK; -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_module.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_module.c -new file mode 100644 -index 000000000..9e5b00b79 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_module.c -@@ -0,0 +1,95 @@ -+#include -+ -+#include "../dev_sysfs/include/sysfs_common.h" -+#include "./include/dfd_module.h" -+#include "./include/dfd_cfg.h" -+#include "./include/dfd_fan_driver.h" -+#include "./include/dfd_slot_driver.h" -+#include "./include/dfd_sensors_driver.h" -+#include "./include/dfd_psu_driver.h" -+#include "./include/dfd_sff_driver.h" -+ -+typedef enum dfd_dev_init_fail_s { -+ DFD_KO_INIT_CPLD_FAIL = 1, -+ DFD_KO_INIT_FPGA_FAIL = 2, -+ DFD_KO_INIT_IRQ_FAIL = 3, -+ DFD_KO_INIT_CFG_FAIL = 4, -+ DFD_KO_INIT_DATA_FAIL = 5, -+} dfd_dev_init_fail_t; -+ -+int g_dfd_dbg_level = 0; -+ -+int dfd_get_dev_number(unsigned int main_dev_id, unsigned int minor_dev_id) -+{ -+ int key,dev_num; -+ int *p_dev_num; -+ -+ key = DFD_CFG_KEY(DFD_CFG_ITEM_DEV_NUM, main_dev_id, minor_dev_id); -+ p_dev_num = dfd_ko_cfg_get_item(key); -+ if (p_dev_num == NULL) { -+ DBG_DEBUG(DBG_ERROR, "get device number failed, key:0x%x\n",key); -+ return -DFD_RV_DEV_NOTSUPPORT; -+ } -+ dev_num = *p_dev_num; -+ DBG_DEBUG(DBG_VERBOSE, "get device number ok, number:%d\n",dev_num); -+ return dev_num; -+} -+ -+static struct switch_drivers_t switch_drivers= { -+ .get_dev_number = dfd_get_dev_number, -+ /* fan */ -+ .get_fan_speed = dfd_get_fan_speed, -+ .get_fan_pwm = dfd_get_fan_pwm, -+ .set_fan_pwm = dfd_set_fan_pwm, -+ .get_fan_present_status = dfd_get_fan_present_status, -+ .get_fan_roll_status = dfd_get_fan_roll_status, -+ .get_fan_speed_level = dfd_get_fan_speed_level, -+ .set_fan_speed_level = dfd_set_fan_speed_level, -+ /* slot */ -+ .get_slot_present_status = dfd_get_slot_present_status, -+ /* sensors */ -+ .get_temp_info = dfd_get_temp_info, -+ .get_voltage_info = dfd_get_voltage_info, -+ /* psu */ -+ .get_psu_present_status = dfd_get_psu_present_status, -+ .get_psu_output_status = dfd_get_psu_output_status, -+ .get_psu_alert_status = dfd_get_psu_alert_status, -+ /* sff */ -+ .get_sff_cpld_info = dfd_get_sff_cpld_info, -+ .get_sff_dir_name = dfd_get_sff_dir_name, -+}; -+ -+struct switch_drivers_t * dfd_plat_driver_get(void) { -+ return &switch_drivers; -+} -+ -+static int32_t __init dfd_dev_init(void) -+{ -+ int ret; -+ -+ DBG_DEBUG(DBG_VERBOSE, "Enter.\n"); -+ -+ ret = dfd_dev_cfg_init(); -+ if (ret != 0) { -+ DBG_DEBUG(DBG_ERROR, "dfd_dev_cfg_init failed ret %d.\n", ret); -+ ret = -DFD_KO_INIT_CFG_FAIL; -+ return ret; -+ } -+ -+ DBG_DEBUG(DBG_VERBOSE, "success.\n"); -+ return 0; -+} -+ -+static void __exit dfd_dev_exit(void) -+{ -+ DBG_DEBUG(DBG_VERBOSE, "dfd_dev_exit.\n"); -+ dfd_dev_cfg_exit(); -+ return ; -+} -+ -+module_init(dfd_dev_init); -+module_exit(dfd_dev_exit); -+module_param(g_dfd_dbg_level, int, S_IRUGO | S_IWUSR); -+EXPORT_SYMBOL(dfd_plat_driver_get); -+MODULE_AUTHOR("support"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_psu_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_psu_driver.c -new file mode 100644 -index 000000000..55e2e4339 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_psu_driver.c -@@ -0,0 +1,70 @@ -+#include -+#include -+ -+#include "./include/dfd_module.h" -+#include "./include/dfd_cfg.h" -+#include "./include/dfd_cfg_adapter.h" -+#include "./include/dfd_cfg_info.h" -+#include "../dev_sysfs/include/sysfs_common.h" -+ -+#define PSU_SIZE (256) -+ -+typedef enum dfd_psu_status_e { -+ DFD_PSU_PRESENT_STATUS = 0, -+ DFD_PSU_OUTPUT_STATUS = 1, -+ DFD_PSU_ALERT_STATUS = 2, -+} dfd_psu_status_t; -+ -+int g_dfd_psu_dbg_level = 0; -+module_param(g_dfd_psu_dbg_level, int, S_IRUGO | S_IWUSR); -+ -+int dfd_get_psu_present_status(unsigned int psu_index) -+{ -+ int ret, present_key, present_status; -+ -+ present_key = DFD_CFG_KEY(DFD_CFG_ITEM_PSU_STATUS, psu_index, DFD_PSU_PRESENT_STATUS); -+ ret = dfd_info_get_int(present_key, &present_status, NULL); -+ if (ret < 0) { -+ DFD_PSU_DEBUG(DBG_ERROR, "dfd_get_psu_present_status error. psu_index:%d, ret:%d\n", -+ psu_index, ret); -+ return ret; -+ } -+ -+ DFD_PSU_DEBUG(DBG_VERBOSE, "dfd_get_psu_present_status success. psu_index:%d, status:%d\n", -+ psu_index, present_status); -+ return present_status; -+} -+ -+int dfd_get_psu_output_status(unsigned int psu_index) -+{ -+ int ret, output_key, output_status; -+ -+ output_key = DFD_CFG_KEY(DFD_CFG_ITEM_PSU_STATUS, psu_index, DFD_PSU_OUTPUT_STATUS); -+ ret = dfd_info_get_int(output_key, &output_status, NULL); -+ if (ret < 0) { -+ DFD_PSU_DEBUG(DBG_ERROR, "dfd_get_psu_output_status error. psu_index:%d, ret:%d\n", -+ psu_index, ret); -+ return ret; -+ } -+ -+ DFD_PSU_DEBUG(DBG_VERBOSE, "dfd_get_psu_output_status success. psu_index:%d, status:%d\n", -+ psu_index, output_status); -+ return output_status; -+} -+ -+int dfd_get_psu_alert_status(unsigned int psu_index) -+{ -+ int ret, alert_key, alert_status; -+ -+ alert_key = DFD_CFG_KEY(DFD_CFG_ITEM_PSU_STATUS, psu_index, DFD_PSU_ALERT_STATUS); -+ ret = dfd_info_get_int(alert_key, &alert_status, NULL); -+ if (ret < 0) { -+ DFD_PSU_DEBUG(DBG_ERROR, "dfd_get_psu_alert_status error. psu_index:%d, ret:%d\n", -+ psu_index, ret); -+ return ret; -+ } -+ -+ DFD_PSU_DEBUG(DBG_VERBOSE, "dfd_get_psu_alert_status success. psu_index:%d, status:%d\n", -+ psu_index, alert_status); -+ return alert_status; -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sensors_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sensors_driver.c -new file mode 100644 -index 000000000..bfca20290 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sensors_driver.c -@@ -0,0 +1,149 @@ -+#include -+#include -+ -+#include "./include/dfd_module.h" -+#include "./include/dfd_cfg.h" -+#include "./include/dfd_cfg_adapter.h" -+#include "./include/dfd_cfg_info.h" -+#include "./include/dfd_cfg_file.h" -+#include "../dev_sysfs/include/sysfs_common.h" -+ -+#define DFD_GET_TEMP_SENSOR_KEY1(dev_index, temp_index) \ -+ (((dev_index & 0xff) << 8) | (temp_index & 0xff)) -+#define DFD_GET_TEMP_SENSOR_KEY2(main_dev_id, temp_type) \ -+ (((main_dev_id & 0x0f) << 4) | (temp_type & 0x0f)) -+#define DFD_FORMAT_STR_MAX_LEN (32) -+ -+int g_dfd_sensor_dbg_level = 0; -+module_param(g_dfd_sensor_dbg_level, int, S_IRUGO | S_IWUSR); -+ -+static int dfd_deal_hwmon_buf(uint8_t *buf, int buf_len, uint8_t *buf_new, int *buf_len_new, info_ctrl_t *info_ctrl) -+{ -+ int i, tmp_len; -+ int exp, decimal, divisor; -+ int org_value, tmp_value; -+ int div_result, div_mod; -+ char fmt_str[DFD_FORMAT_STR_MAX_LEN]; -+ -+ exp = info_ctrl->int_cons; -+ decimal = info_ctrl->bit_offset; -+ -+ if (exp <= 0) { -+ DBG_DEBUG(DBG_VERBOSE, "exponent %d, don't need transform. buf_len:%d, buf_len_new:%d\n", -+ exp, buf_len, *buf_len_new); -+ snprintf(buf_new, *buf_len_new, "%s", buf); -+ *buf_len_new = strlen(buf_new); -+ return DFD_RV_OK; -+ } -+ divisor = 1; -+ for (i = 0; i < exp; i++) { -+ divisor *= 10; -+ } -+ org_value = simple_strtol(buf, NULL, 10); -+ if (org_value < 0) { -+ tmp_value = 0 - org_value; -+ } else { -+ tmp_value = org_value; -+ } -+ div_result = tmp_value / divisor; -+ div_mod = tmp_value % divisor; -+ DBG_DEBUG(DBG_VERBOSE, "exp:%d, decimal:%d, original value:%d, divisor:%d, result :%d, mod:%d\n", -+ exp, decimal, org_value, divisor, div_result, div_mod); -+ -+ mem_clear(fmt_str, sizeof(fmt_str)); -+ if (org_value < 0) { -+ snprintf(fmt_str, sizeof(fmt_str), "-%%d.%%0%dd\n",exp); -+ } else { -+ snprintf(fmt_str, sizeof(fmt_str), "%%d.%%0%dd\n",exp); -+ } -+ DBG_DEBUG(DBG_VERBOSE, "format string:%s",fmt_str); -+ snprintf(buf_new, *buf_len_new, fmt_str, div_result, div_mod); -+ *buf_len_new = strlen(buf_new); -+ tmp_len = *buf_len_new; -+ -+ if ( decimal > 0) { -+ for(i = 0; i < *buf_len_new; i++) { -+ if (buf_new[i] == '.') { -+ if( i + decimal + 2 <= *buf_len_new ) { -+ buf_new[i + decimal + 1 ] = '\n'; -+ buf_new[i + decimal + 2 ] = '\0'; -+ *buf_len_new = strlen(buf_new); -+ DBG_DEBUG(DBG_VERBOSE, "deal decimal[%d] ok, str len:%d, value:%s\n", -+ decimal, *buf_len_new, buf_new); -+ } -+ break; -+ } -+ } -+ if (tmp_len == *buf_len_new) { -+ DBG_DEBUG(DBG_WARN, "deal decimal[%d] failed, use original value:%s\n", decimal, buf_new); -+ } -+ } -+ return DFD_RV_OK; -+} -+ -+static int dfd_get_sensor_info(uint8_t main_dev_id, uint8_t dev_index, uint8_t sensor_type, -+ uint8_t sensor_index, uint8_t sensor_attr, char *buf) -+{ -+ uint32_t key; -+ uint16_t key_index1; -+ uint8_t key_index2; -+ int rv; -+ info_hwmon_buf_f pfunc; -+ -+ key_index1 = DFD_GET_TEMP_SENSOR_KEY1(dev_index, sensor_index); -+ key_index2 = DFD_GET_TEMP_SENSOR_KEY2(main_dev_id, sensor_attr); -+ if (sensor_type == WB_MINOR_DEV_TEMP ) { -+ key = DFD_CFG_KEY(DFD_CFG_ITEM_HWMON_TEMP, key_index1, key_index2); -+ } else if (sensor_type == WB_MINOR_DEV_IN) { -+ key = DFD_CFG_KEY(DFD_CFG_ITEM_HWMON_IN, key_index1, key_index2); -+ } else { -+ DFD_SENSOR_DEBUG(DBG_ERROR, "unknow sensor type:%d.\n",sensor_type); -+ return -DFD_RV_INVALID_VALUE; -+ } -+ -+ DFD_SENSOR_DEBUG(DBG_VERBOSE, "get sensor info.main_dev_id:%d, dev_index:0x%x, sensor_index:0x%x, sensor_attr:0x%x, key:0x%x,\n", -+ main_dev_id, dev_index, sensor_index, sensor_attr, key); -+ -+ pfunc = dfd_deal_hwmon_buf; -+ mem_clear(buf, PAGE_SIZE); -+ rv = dfd_info_get_sensor(key, buf, PAGE_SIZE, pfunc); -+ return rv; -+} -+ -+ssize_t dfd_get_temp_info(uint8_t main_dev_id, uint8_t dev_index, -+ uint8_t temp_index, uint8_t temp_attr, char *buf) -+{ -+ int rv; -+ -+ if (buf == NULL) { -+ DFD_SENSOR_DEBUG(DBG_ERROR, "param error. buf is NULL.\n"); -+ return -DFD_RV_INVALID_VALUE; -+ } -+ -+ rv = dfd_get_sensor_info(main_dev_id, dev_index, WB_MINOR_DEV_TEMP, temp_index, temp_attr, buf); -+ if (rv < 0) { -+ DFD_SENSOR_DEBUG(DBG_ERROR, "get temp info error. rv:%d\n", rv); -+ } else { -+ DFD_SENSOR_DEBUG(DBG_VERBOSE, "get temp info ok.value:%s\n", buf); -+ } -+ return rv; -+} -+ -+ssize_t dfd_get_voltage_info(uint8_t main_dev_id, uint8_t dev_index, -+ uint8_t in_index, uint8_t in_attr, char *buf) -+{ -+ int rv; -+ -+ if (buf == NULL) { -+ DFD_SENSOR_DEBUG(DBG_ERROR, "param error. buf is NULL.\n"); -+ return -DFD_RV_INVALID_VALUE; -+ } -+ -+ rv = dfd_get_sensor_info(main_dev_id, dev_index, WB_MINOR_DEV_IN, in_index, in_attr, buf); -+ if (rv < 0) { -+ DFD_SENSOR_DEBUG(DBG_ERROR, "get voltage info error. rv:%d\n", rv); -+ } else { -+ DFD_SENSOR_DEBUG(DBG_VERBOSE, "get voltage info ok.value:%s\n", buf); -+ } -+ return rv; -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sff_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sff_driver.c -new file mode 100644 -index 000000000..5c1faff97 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sff_driver.c -@@ -0,0 +1,56 @@ -+#include -+ -+#include "./include/dfd_module.h" -+#include "./include/dfd_cfg.h" -+#include "./include/dfd_cfg_info.h" -+#include "./include/dfd_cfg_adapter.h" -+#include "../dev_sysfs/include/sysfs_common.h" -+ -+int g_dfd_sff_dbg_level = 0; -+module_param(g_dfd_sff_dbg_level, int, S_IRUGO | S_IWUSR); -+ -+ssize_t dfd_get_sff_cpld_info(unsigned int sff_index, int cpld_reg_type, char *buf, int len) -+{ -+ int key, ret, value; -+ -+ if(buf == NULL) { -+ DFD_SFF_DEBUG(DBG_ERROR, "param error, buf is NULL. sff_index:%d, cpld_reg_type:%d.\n", -+ sff_index, cpld_reg_type); -+ return -DFD_RV_INVALID_VALUE; -+ } -+ -+ key = DFD_CFG_KEY(DFD_CFG_ITEM_SFF_CPLD_REG, sff_index, cpld_reg_type); -+ ret = dfd_info_get_int(key, &value, NULL); -+ if (ret < 0) { -+ DFD_SFF_DEBUG(DBG_ERROR, "get sff cpld reg error, key:0x%x,ret:%d.\n", key, ret); -+ return ret; -+ } -+ -+ mem_clear(buf, len); -+ return (ssize_t)snprintf(buf, len, "%d\n", value); -+} -+ -+ssize_t dfd_get_sff_dir_name(unsigned int sff_index, char *buf, int buf_len) -+{ -+ int key; -+ char *sff_dir_name; -+ -+ if (buf == NULL) { -+ DFD_SFF_DEBUG(DBG_ERROR, "param error. buf is NULL.sff index:%d", sff_index); -+ return -DFD_RV_INVALID_VALUE; -+ } -+ -+ mem_clear(buf, buf_len); -+ -+ key = DFD_CFG_KEY(DFD_CFG_ITEM_SFF_DIR_NAME, sff_index, 0); -+ sff_dir_name = dfd_ko_cfg_get_item(key); -+ if (sff_dir_name == NULL) { -+ DFD_SFF_DEBUG(DBG_ERROR, "sff dir name config error, key=0x%08x\n", key); -+ return -DFD_RV_NODE_FAIL; -+ } -+ -+ DFD_SFF_DEBUG(DBG_VERBOSE, "%s\n", sff_dir_name); -+ snprintf(buf, buf_len, "%s", sff_dir_name); -+ return strlen(buf); -+ -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_slot_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_slot_driver.c -new file mode 100644 -index 000000000..69c82adab ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_slot_driver.c -@@ -0,0 +1,27 @@ -+#include -+#include -+ -+#include "./include/dfd_module.h" -+#include "./include/dfd_cfg.h" -+#include "./include/dfd_cfg_adapter.h" -+#include "./include/dfd_cfg_info.h" -+#include "../dev_sysfs/include/sysfs_common.h" -+ -+#define SLOT_SIZE (256) -+ -+int g_dfd_slot_dbg_level = 0; -+module_param(g_dfd_slot_dbg_level, int, S_IRUGO | S_IWUSR); -+ -+int dfd_get_slot_present_status(unsigned int slot_index) -+{ -+ int key, ret; -+ int status; -+ -+ key = DFD_CFG_KEY(DFD_CFG_ITEM_DEV_PRESENT_STATUS, WB_MAIN_DEV_SLOT, slot_index); -+ ret = dfd_info_get_int(key, &status, NULL); -+ if (ret < 0) { -+ DFD_SLOT_DEBUG(DBG_ERROR, "get slot status error, key:0x%x\n",key); -+ return ret; -+ } -+ return status; -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg.h -new file mode 100644 -index 000000000..af3de1ca9 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg.h -@@ -0,0 +1,99 @@ -+#ifndef __DFD_CFG_H__ -+#define __DFD_CFG_H__ -+ -+#include -+ -+#define DFD_KO_CFG_FILE_NAME "/etc/plat_sysfs_cfg/cfg_file_name" -+#define DFD_KO_CFG_FILE_DIR "/etc/plat_sysfs_cfg/" -+#define DFD_PUB_CARDTYPE_FILE "/sys/module/platform_common/parameters/dfd_my_type" -+ -+#define DFD_CFG_CMDLINE_MAX_LEN (256) -+#define DFD_CFG_NAME_MAX_LEN (256) -+#define DFD_CFG_VALUE_MAX_LEN (256) -+#define DFD_CFG_STR_MAX_LEN (64) -+#define DFD_CFG_CPLD_NUM_MAX (16) -+#define DFD_PRODUCT_ID_LENGTH (8) -+#define DFD_PID_BUF_LEN (32) -+#define DFD_TEMP_NAME_BUF_LEN (32) -+ -+#define DFD_CFG_EMPTY_VALUE (-1) -+#define DFD_CFG_INVALID_VALUE (0) -+ -+#define DFD_CFG_KEY(item, index1, index2) \ -+ ((((item) & 0xff) << 24) | (((index1) & 0xffff) << 8) | ((index2) & 0xff)) -+#define DFD_CFG_ITEM_ID(key) (((key) >> 24) & 0xff) -+#define DFD_CFG_INDEX1(key) (((key) >> 8) & 0xffff) -+#define DFD_CFG_INDEX2(key) ((key)& 0xff) -+ -+#define INDEX_NOT_EXIST (-1) -+#define INDEX1_MAX (0xffff) -+#define INDEX2_MAX (0xff) -+#define READ_TEMP_FAIL 1000000 -+ -+#define DFD_CFG_ITEM_ALL \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_NONE, "none", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_DEV_NUM, "dev_num", INDEX1_MAX, INDEX2_MAX) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_CPLD_LPC_DEV, "cpld_lpc_dev", INDEX1_MAX, DFD_CFG_CPLD_NUM_MAX) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_INT_END, "end_int", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ -+ \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_CPLD_MODE, "mode_cpld", INDEX1_MAX, DFD_CFG_CPLD_NUM_MAX) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_SFF_DIR_NAME, "sff_dir_name", INDEX1_MAX, INDEX_NOT_EXIST) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_STRING_END, "end_string", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ -+ \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_CPLD_I2C_DEV, "cpld_i2c_dev", INDEX1_MAX, INDEX2_MAX) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_OTHER_I2C_DEV, "other_i2c_dev", INDEX1_MAX, INDEX2_MAX) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_I2C_DEV_END, "end_i2c_dev", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ -+ \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_FAN_ROLL_STATUS, "fan_roll_status", INDEX1_MAX, INDEX2_MAX) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_FAN_SPEED, "fan_speed", INDEX1_MAX, INDEX2_MAX) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_FAN_RATIO, "fan_ratio", INDEX1_MAX, INDEX2_MAX) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_DEV_PRESENT_STATUS, "dev_present_status", INDEX1_MAX, INDEX2_MAX) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_PSU_STATUS, "psu_status", INDEX1_MAX, INDEX2_MAX) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_HWMON_TEMP, "hwmon_temp", INDEX1_MAX, INDEX2_MAX) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_HWMON_IN, "hwmon_in", INDEX1_MAX, INDEX2_MAX) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_SFF_CPLD_REG, "sff_cpld_reg", INDEX1_MAX, INDEX2_MAX) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_INFO_CTRL_END, "end_info_ctrl", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ -+ DFD_CFG_ITEM(DFD_CFG_ITEM_HWMON_POWER, "hwmon_power", INDEX1_MAX, INDEX2_MAX) \ -+ -+#ifdef DFD_CFG_ITEM -+#undef DFD_CFG_ITEM -+#endif -+#define DFD_CFG_ITEM(_id, _name, _index_min, _index_max) _id, -+typedef enum dfd_cfg_item_id_s { -+ DFD_CFG_ITEM_ALL -+} dfd_cfg_item_id_t; -+ -+#define DFD_CFG_ITEM_IS_INT(item_id) \ -+ (((item_id) > DFD_CFG_ITEM_NONE) && ((item_id) < DFD_CFG_ITEM_INT_END)) -+ -+#define DFD_CFG_ITEM_IS_STRING(item_id) \ -+ (((item_id) > DFD_CFG_ITEM_INT_END) && ((item_id) < DFD_CFG_ITEM_STRING_END)) -+ -+#define DFD_CFG_ITEM_IS_I2C_DEV(item_id) \ -+ (((item_id) > DFD_CFG_ITEM_STRING_END) && ((item_id) < DFD_CFG_ITEM_I2C_DEV_END)) -+ -+#define DFD_CFG_ITEM_IS_INFO_CTRL(item_id) \ -+ (((item_id) > DFD_CFG_ITEM_I2C_DEV_END) && ((item_id) < DFD_CFG_ITEM_INFO_CTRL_END)) -+ -+typedef struct index_range_s { -+ int index1_max; -+ int index2_max; -+} index_range_t; -+ -+typedef struct val_convert_node_s { -+ struct list_head lst; -+ int int_val; -+ char str_val[DFD_CFG_STR_MAX_LEN]; -+ int index1; -+ int index2; -+} val_convert_node_t; -+ -+void *dfd_ko_cfg_get_item(int key); -+ -+void dfd_ko_cfg_show_item(int key); -+ -+int32_t dfd_dev_cfg_init(void); -+ -+void dfd_dev_cfg_exit(void); -+ -+#endif /* __DFD_CFG_H__ */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_adapter.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_adapter.h -new file mode 100644 -index 000000000..70d8b536c ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_adapter.h -@@ -0,0 +1,46 @@ -+#ifndef __DFD_CFG_ADAPTER_H__ -+#define __DFD_CFG_ADAPTER_H__ -+ -+#define DFD_KO_CPLD_I2C_RETRY_SLEEP (10) /* ms */ -+#define DFD_KO_CPLD_I2C_RETRY_TIMES (50 / DFD_KO_CPLD_I2C_RETRY_SLEEP) -+ -+#define DFD_KO_CPLD_GET_SLOT(addr) ((addr >> 24) & 0xff) -+#define DFD_KO_CPLD_GET_ID(addr) ((addr >> 16) & 0xff) -+#define DFD_KO_CPLD_GET_INDEX(addr) (addr & 0xffff) -+#define DFD_KO_CPLD_MODE_I2C_STRING "i2c" -+#define DFD_KO_CPLD_MODE_LPC_STRING "lpc" -+ -+typedef struct dfd_i2c_dev_s { -+ int bus; -+ int addr; -+} dfd_i2c_dev_t; -+ -+typedef enum dfd_i2c_dev_mem_s { -+ DFD_I2C_DEV_MEM_BUS, -+ DFD_I2C_DEV_MEM_ADDR, -+ DFD_I2C_DEV_MEM_END -+} dfd_i2c_dev_mem_t; -+ -+typedef enum cpld_mode_e { -+ DFD_CPLD_MODE_I2C, -+ DFD_CPLD_MODE_LPC, -+} cpld_mode_t; -+ -+typedef enum i2c_mode_e { -+ DFD_I2C_MODE_NORMAL_I2C, -+ DFD_I2C_MODE_SMBUS, -+} i2c_mode_t; -+ -+extern char *g_dfd_i2c_dev_mem_str[DFD_I2C_DEV_MEM_END]; -+ -+int32_t dfd_ko_cpld_read(int32_t addr, uint8_t *buf); -+ -+int32_t dfd_ko_cpld_write(int32_t addr, uint8_t val); -+ -+int32_t dfd_ko_i2c_read(int bus, int addr, int offset, uint8_t *buf, uint32_t size); -+ -+int32_t dfd_ko_i2c_write(int bus, int addr, int offset, uint8_t *buf, uint32_t size); -+ -+int32_t dfd_ko_read_file(char *fpath, int32_t addr, uint8_t *val, int32_t read_bytes); -+ -+#endif /* __DFD_CFG_ADAPTER_H__ */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_file.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_file.h -new file mode 100644 -index 000000000..50d7a42d5 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_file.h -@@ -0,0 +1,37 @@ -+#ifndef __DFD_CFG_FILE_H__ -+#define __DFD_CFG_FILE_H__ -+ -+#include -+ -+#define KFILE_RV_OK (0) -+#define KFILE_RV_INPUT_ERR (-1) -+#define KFILE_RV_STAT_FAIL (-2) -+#define KFILE_RV_OPEN_FAIL (-3) -+#define KFILE_RV_MALLOC_FAIL (-4) -+#define KFILE_RV_RD_FAIL (-5) -+#define KFILE_RV_ADDR_ERR (-6) -+#define KFILE_RV_WR_FAIL (-7) -+ -+#define IS_CR(c) ((c) == '\n') -+ -+typedef struct kfile_ctrl_s { -+ int32_t size; -+ int32_t pos; -+ char *buf; -+} kfile_ctrl_t; -+ -+int kfile_open(char *fname, kfile_ctrl_t *kfile_ctrl); -+ -+void kfile_close(kfile_ctrl_t *kfile_ctrl); -+ -+int kfile_gets(char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl); -+ -+int kfile_read(int32_t addr, char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl); -+ -+int kfile_iterate_dir(const char *dir_path, const char *obj_name, char *match_name, int len); -+ -+#if 0 -+ -+int kfile_write(char *fpath, int32_t addr, char *buf, int buf_size); -+#endif -+#endif /* __DFD_CFG_FILE_H__ */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_info.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_info.h -new file mode 100644 -index 000000000..88e8f92c1 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_info.h -@@ -0,0 +1,119 @@ -+#ifndef __DFD_CFG_INFO_H__ -+#define __DFD_CFG_INFO_H__ -+ -+#include -+ -+typedef int (*info_num_buf_to_value_f)(uint8_t *num_buf, int buf_len, int *num_val); -+ -+typedef int (*info_buf_to_buf_f)(uint8_t *buf, int buf_len, uint8_t *buf_new, int *buf_len_new); -+ -+#define IS_INFO_FRMT_BIT(frmt) ((frmt) == INFO_FRMT_BIT) -+#define IS_INFO_FRMT_BYTE(frmt) (((frmt) == INFO_FRMT_BYTE) || ((frmt) == INFO_FRMT_NUM_BYTES)) -+#define IS_INFO_FRMT_NUM_STR(frmt) ((frmt) == INFO_FRMT_NUM_STR) -+#define IS_INFO_FRMT_NUM_BUF(frmt) ((frmt) == INFO_FRMT_NUM_BUF) -+#define IS_INFO_FRMT_BUF(frmt) ((frmt) == INFO_FRMT_BUF) -+ -+#define INFO_INT_MAX_LEN (32) -+#define INFO_INT_LEN_VALAID(len) (((len) > 0) && ((len) < INFO_INT_MAX_LEN)) -+ -+#define INFO_BUF_MAX_LEN (128) -+#define INFO_BUF_LEN_VALAID(len) (((len) > 0) && ((len) < INFO_BUF_MAX_LEN)) -+ -+#define INFO_BIT_OFFSET_VALID(bit_offset) (((bit_offset) >= 0) && ((bit_offset) < 8)) -+ -+typedef enum info_ctrl_mode_e { -+ INFO_CTRL_MODE_NONE, -+ INFO_CTRL_MODE_CFG, -+ INFO_CTRL_MODE_CONS, -+ INFO_CTRL_MODE_TLV, -+ INFO_CTRL_MODE_SRT_CONS, -+ INFO_CTRL_MODE_END -+} info_ctrl_mode_t; -+ -+typedef enum info_frmt_e { -+ INFO_FRMT_NONE, -+ INFO_FRMT_BIT, -+ INFO_FRMT_BYTE, -+ INFO_FRMT_NUM_BYTES, -+ INFO_FRMT_NUM_STR, -+ INFO_FRMT_NUM_BUF, -+ INFO_FRMT_BUF, -+ INFO_FRMT_END -+} info_frmt_t; -+ -+typedef enum info_src_e { -+ INFO_SRC_NONE, -+ INFO_SRC_CPLD, -+ INFO_SRC_FPGA, -+ INFO_SRC_OTHER_I2C, -+ INFO_SRC_FILE, -+ INFO_SRC_END -+} info_src_t; -+ -+typedef enum info_pola_e { -+ INFO_POLA_NONE, -+ INFO_POLA_POSI, -+ INFO_POLA_NEGA, -+ INFO_POLA_END -+} info_pola_t; -+ -+#define INFO_FPATH_MAX_LEN (128) -+#define INFO_STR_CONS_MAX_LEN (64) -+typedef struct info_ctrl_s { -+ info_ctrl_mode_t mode; -+ int32_t int_cons; -+ info_src_t src; -+ info_frmt_t frmt; -+ info_pola_t pola; -+ char fpath[INFO_FPATH_MAX_LEN]; -+ int32_t addr; -+ int32_t len; -+ int32_t bit_offset; -+ char str_cons[INFO_STR_CONS_MAX_LEN]; -+ int32_t int_extra1; -+ int32_t int_extra2; -+ int32_t int_extra3; /* cpld voltage mode */ -+} info_ctrl_t; -+ -+typedef enum info_ctrl_mem_s { -+ INFO_CTRL_MEM_MODE, -+ INFO_CTRL_MEM_INT_CONS, -+ INFO_CTRL_MEM_SRC, -+ INFO_CTRL_MEM_FRMT, -+ INFO_CTRL_MEM_POLA, -+ INFO_CTRL_MEM_FPATH, -+ INFO_CTRL_MEM_ADDR, -+ INFO_CTRL_MEM_LEN, -+ INFO_CTRL_MEM_BIT_OFFSET, -+ INFO_CTRL_MEM_STR_CONS, -+ INFO_CTRL_MEM_INT_EXTRA1, -+ INFO_CTRL_MEM_INT_EXTRA2, -+ INFO_CTRL_MEM_INT_EXTRA3, -+ INFO_CTRL_MEM_END -+} info_ctrl_mem_t; -+ -+typedef enum sensor_format_mem_s { -+ LINEAR11 = 1, -+ LINEAR16, -+ TMP464, -+ MAC_TH5, -+ MAC_TD3 -+} sensor_format_mem_t; -+ -+typedef int (*info_hwmon_buf_f)(uint8_t *buf, int buf_len, uint8_t *buf_new, int *buf_len_new, info_ctrl_t *info_ctrl); -+ -+extern char *g_info_ctrl_mem_str[INFO_CTRL_MEM_END]; -+extern char *g_info_src_str[INFO_SRC_END]; -+extern char *g_info_frmt_str[INFO_FRMT_END]; -+extern char *g_info_pola_str[INFO_POLA_END]; -+extern char *g_info_ctrl_mode_str[INFO_CTRL_MODE_END]; -+ -+int dfd_info_get_int(int key, int *ret, info_num_buf_to_value_f pfun); -+ -+int dfd_info_get_buf(int key, uint8_t *buf, int buf_len, info_buf_to_buf_f pfun); -+ -+int dfd_info_set_int(int key, int val); -+ -+int dfd_info_get_sensor(uint32_t key, char *buf, int buf_len, info_hwmon_buf_f pfun); -+ -+#endif /* __DFD_CFG_INFO_H__ */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_listnode.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_listnode.h -new file mode 100644 -index 000000000..955dfa96e ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_listnode.h -@@ -0,0 +1,30 @@ -+#ifndef __DFD_CFG_LISTNODE_H__ -+#define __DFD_CFG_LISTNODE_H__ -+ -+#include -+ -+#define LNODE_RV_OK (0) -+#define LNODE_RV_INPUT_ERR (-1) -+#define LNODE_RV_NODE_EXIST (-2) -+#define LNODE_RV_NOMEM (-3) -+ -+typedef struct lnode_root_s { -+ struct list_head root; -+} lnode_root_t; -+ -+typedef struct lnode_node_s { -+ struct list_head lst; -+ -+ int key; -+ void *data; -+} lnode_node_t; -+ -+void *lnode_find_node(lnode_root_t *root, int key); -+ -+int lnode_insert_node(lnode_root_t *root, int key, void *data); -+ -+int lnode_init_root(lnode_root_t *root); -+ -+void lnode_free_list(lnode_root_t *root); -+ -+#endif /* __DFD_CFG_LISTNODE_H__ */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_fan_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_fan_driver.h -new file mode 100644 -index 000000000..1065fd9ee ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_fan_driver.h -@@ -0,0 +1,18 @@ -+#ifndef _DFD_FAN_DRIVER_H_ -+#define _DFD_FAN_DRIVER_H_ -+ -+ssize_t dfd_get_fan_speed(unsigned int fan_index, unsigned int motor_index,unsigned int *speed); -+ -+int dfd_set_fan_pwm(unsigned int fan_index, unsigned int motor_index, int pwm); -+ -+int dfd_get_fan_pwm(unsigned int fan_index, unsigned int motor_index, int *pwm); -+ -+int dfd_get_fan_present_status(unsigned int fan_index); -+ -+int dfd_get_fan_roll_status(unsigned int fan_index, unsigned int motor_index); -+ -+int dfd_get_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int *level); -+ -+int dfd_set_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int level); -+ -+#endif /* _DFD_FAN_DRIVER_H_ */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_module.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_module.h -new file mode 100644 -index 000000000..a547255cf ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_module.h -@@ -0,0 +1,96 @@ -+#ifndef __DFD_MODULE_H__ -+#define __DFD_MODULE_H__ -+ -+typedef enum dfd_rv_s { -+ DFD_RV_OK = 0, -+ DFD_RV_INIT_ERR = 1, -+ DFD_RV_SLOT_INVALID = 2, -+ DFD_RV_MODE_INVALID = 3, -+ DFD_RV_MODE_NOTSUPPORT = 4, -+ DFD_RV_TYPE_ERR = 5, -+ DFD_RV_DEV_NOTSUPPORT = 6, -+ DFD_RV_DEV_FAIL = 7, -+ DFD_RV_INDEX_INVALID = 8, -+ DFD_RV_NO_INTF = 9, -+ DFD_RV_NO_NODE = 10, -+ DFD_RV_NODE_FAIL = 11, -+ DFD_RV_INVALID_VALUE = 12, -+ DFD_RV_NO_MEMORY = 13, -+} dfd_rv_t; -+ -+typedef enum { -+ DBG_VERBOSE = 0x01, -+ DBG_WARN = 0x02, -+ DBG_ERROR = 0x04, -+} dbg_level_t; -+ -+extern int g_dfd_dbg_level; -+extern int g_dfd_fan_dbg_level; -+extern int g_dfd_slot_dbg_level; -+extern int g_dfd_sensor_dbg_level; -+extern int g_dfd_psu_dbg_level; -+extern int g_dfd_sff_dbg_level; -+ -+#define DBG_DEBUG(level, fmt, arg...) do { \ -+ if (g_dfd_dbg_level & level) { \ -+ if(level >= DBG_ERROR) { \ -+ printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ -+ } else { \ -+ printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ -+ } \ -+ } \ -+} while (0) -+ -+#define DFD_FAN_DEBUG(level, fmt, arg...) do { \ -+ if (g_dfd_fan_dbg_level & level) { \ -+ if(level >= DBG_ERROR) { \ -+ printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ -+ } else { \ -+ printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ -+ } \ -+ } \ -+} while (0) -+ -+#define DFD_SLOT_DEBUG(level, fmt, arg...) do { \ -+ if (g_dfd_slot_dbg_level & level) { \ -+ if(level >= DBG_ERROR) { \ -+ printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ -+ } else { \ -+ printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ -+ } \ -+ } \ -+} while (0) -+ -+#define DFD_SENSOR_DEBUG(level, fmt, arg...) do { \ -+ if (g_dfd_sensor_dbg_level & level) { \ -+ if(level >= DBG_ERROR) { \ -+ printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ -+ } else { \ -+ printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ -+ } \ -+ } \ -+} while (0) -+ -+#define DFD_PSU_DEBUG(level, fmt, arg...) do { \ -+ if (g_dfd_psu_dbg_level & level) { \ -+ if(level >= DBG_ERROR) { \ -+ printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ -+ } else { \ -+ printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ -+ } \ -+ } \ -+} while (0) -+ -+#define DFD_SFF_DEBUG(level, fmt, arg...) do { \ -+ if (g_dfd_sff_dbg_level & level) { \ -+ if(level >= DBG_ERROR) { \ -+ printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ -+ } else { \ -+ printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ -+ } \ -+ } \ -+} while (0) -+ -+int dfd_get_dev_number(unsigned int main_dev_id, unsigned int minor_dev_id); -+ -+#endif /* __DFD_MODULE_H__ */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_psu_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_psu_driver.h -new file mode 100644 -index 000000000..ce7199660 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_psu_driver.h -@@ -0,0 +1,10 @@ -+#ifndef _DFD_PSU_DRIVER_H_ -+#define _DFD_PSU_DRIVER_H_ -+ -+int dfd_get_psu_present_status(unsigned int psu_index); -+ -+int dfd_get_psu_output_status(unsigned int psu_index); -+ -+int dfd_get_psu_alert_status(unsigned int psu_index); -+ -+#endif /* _DFD_PSU_DRIVER_H_ */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sensors_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sensors_driver.h -new file mode 100644 -index 000000000..16733b260 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sensors_driver.h -@@ -0,0 +1,10 @@ -+#ifndef _DFD_SENSORS_DRIVER_H_ -+#define _DFD_SENSORS_DRIVER_H_ -+ -+ssize_t dfd_get_temp_info(uint8_t main_dev_id, uint8_t dev_index, -+ uint8_t temp_index, uint8_t temp_attr, char *buf); -+ -+ssize_t dfd_get_voltage_info(uint8_t main_dev_id, uint8_t dev_index, -+ uint8_t in_index, uint8_t in_attr, char *buf); -+ -+#endif /* _DFD_SENSORS_DRIVER_H_ */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sff_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sff_driver.h -new file mode 100644 -index 000000000..7107b72ee ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sff_driver.h -@@ -0,0 +1,8 @@ -+#ifndef _DFD_SFF_DRIVER_H_ -+#define _DFD_SFF_DRIVER_H_ -+ -+ssize_t dfd_get_sff_cpld_info(unsigned int sff_index, int cpld_reg_type, char *buf, int len); -+ -+ssize_t dfd_get_sff_dir_name(unsigned int sff_index, char *buf, int buf_len); -+ -+#endif /* _DFD_SFF_DRIVER_H_ */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_slot_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_slot_driver.h -new file mode 100644 -index 000000000..c68caecd2 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_slot_driver.h -@@ -0,0 +1,6 @@ -+#ifndef _DFD_SLOT_DRIVER_H_ -+#define _DFD_SLOT_DRIVER_H_ -+ -+int dfd_get_slot_present_status(unsigned int slot_index); -+ -+#endif /* _DFD_SLOT_DRIVER_H_ */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/Makefile -new file mode 100644 -index 000000000..1a1044bb1 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/Makefile -@@ -0,0 +1,21 @@ -+PWD = $(shell pwd) -+ -+EXTRA_CFLAGS:= -I$(M)/include -+EXTRA_CFLAGS+= -Wall -+KBUILD_EXTRA_SYMBOLS += $(PLAT_SYSFS_DIR)/dev_cfg/Module.symvers -+ -+obj-m := plat_switch.o -+obj-m += plat_fan.o -+obj-m += plat_psu.o -+obj-m += plat_sff.o -+obj-m += plat_sensor.o -+obj-m += plat_slot.o -+ -+all: -+ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules -+ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi -+ cp -p $(PWD)/*.ko $(module_out_put_dir) -+clean: -+ rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/*.mod -+ rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order -+ rm -rf $(PWD)/.tmp_versions -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/plat_switch.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/plat_switch.h -new file mode 100644 -index 000000000..bbd813e87 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/plat_switch.h -@@ -0,0 +1,86 @@ -+#ifndef _PLAT_SWITCH_H_ -+#define _PLAT_SWITCH_H_ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+enum LOG_LEVEL{ -+ INFO = 0x1, -+ ERR = 0x2, -+ DBG = 0x4, -+ ALL = 0xf -+}; -+ -+#define LOG_INFO(_prefix, fmt, args...) \ -+ do { \ -+ if (g_loglevel & INFO) \ -+ { \ -+ printk( KERN_INFO _prefix "%s "fmt, __FUNCTION__, ##args); \ -+ } \ -+ } while (0) -+ -+#define LOG_ERR(_prefix, fmt, args...) \ -+ do { \ -+ if (g_loglevel & ERR) \ -+ { \ -+ printk( KERN_ERR _prefix "%s "fmt, __FUNCTION__, ##args); \ -+ } \ -+ } while (0) -+ -+#define LOG_DBG(_prefix, fmt, args...) \ -+ do { \ -+ if (g_loglevel & DBG) \ -+ { \ -+ printk( KERN_DEBUG _prefix "%s "fmt, __FUNCTION__, ##args); \ -+ } \ -+ } while (0) -+ -+#define check_pfun(p) \ -+ do { \ -+ if (p == NULL) { \ -+ printk( KERN_ERR "%s, %s = NULL.\n", __FUNCTION__, #p); \ -+ return -ENOSYS; \ -+ } \ -+ }while(0) -+ -+#define check_p(p) check_pfun(p) -+ -+#define to_switch_obj(x) container_of(x, struct switch_obj, kobj) -+#define to_switch_attr(x) container_of(x, struct switch_attribute, attr) -+#define to_switch_device_attr(x) container_of(x, struct switch_device_attribute, switch_attr) -+ -+#define SWITCH_ATTR(_name, _mode, _show, _store, _type) \ -+ { .switch_attr = __ATTR(_name, _mode, _show, _store), \ -+ .type = _type } -+ -+#define SWITCH_DEVICE_ATTR(_name, _mode, _show, _store, _type) \ -+struct switch_device_attribute switch_dev_attr_##_name \ -+ = SWITCH_ATTR(_name, _mode, _show, _store, _type) -+ -+struct switch_obj { -+ struct kobject kobj; -+ unsigned int index; -+}; -+ -+/* a custom attribute that works just for a struct switch_obj. */ -+struct switch_attribute { -+ struct attribute attr; -+ ssize_t (*show)(struct switch_obj *foo, struct switch_attribute *attr, char *buf); -+ ssize_t (*store)(struct switch_obj *foo, struct switch_attribute *attr, const char *buf, size_t count); -+}; -+ -+struct switch_device_attribute { -+ struct switch_attribute switch_attr; -+ int type; -+}; -+ -+extern struct switch_obj *wb_plat_kobject_create(const char *name, struct kobject *parent); -+extern void wb_plat_kobject_delete(struct switch_obj **obj); -+ -+#endif /* _PLAT_SWITCH_H_ */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/sysfs_common.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/sysfs_common.h -new file mode 100644 -index 000000000..5b73731e1 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/sysfs_common.h -@@ -0,0 +1,90 @@ -+#ifndef _SYSFS_COMMON_H_ -+#define _SYSFS_COMMON_H_ -+ -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+ -+#define DIR_NAME_MAX_LEN (64) -+ -+#define WB_SYSFS_DEV_ERROR "NA" -+/* sysfs directory name */ -+#define FAN_SYSFS_NAME "fan" -+#define PSU_SYSFS_NAME "psu" -+#define SLOT_SYSFS_NAME "slot" -+#define VOLTAGE_SYSFS_NAME "in" -+#define TEMP_SYSFS_NAME "temp" -+#define SFF_SYSFS_NAME "sff" -+ -+typedef enum wb_main_dev_type_e { -+ WB_MAIN_DEV_MAINBOARD = 0, -+ WB_MAIN_DEV_FAN = 1, -+ WB_MAIN_DEV_PSU = 2, -+ WB_MAIN_DEV_SFF = 3, -+ WB_MAIN_DEV_CPLD = 4, -+ WB_MAIN_DEV_SLOT = 5, -+} wb_main_dev_type_t; -+ -+typedef enum wb_minor_dev_type_e { -+ WB_MINOR_DEV_NONE = 0, /* None */ -+ WB_MINOR_DEV_TEMP = 1, -+ WB_MINOR_DEV_IN = 2, -+ WB_MINOR_DEV_CURR = 3, -+ WB_MINOR_DEV_POWER = 4, -+ WB_MINOR_DEV_MOTOR = 5, -+ WB_MINOR_DEV_PSU = 6, -+} wb_minor_dev_type_t; -+ -+typedef enum wb_sensor_type_e { -+ WB_SENSOR_INPUT = 0, -+ WB_SENSOR_ALIAS = 1, -+ WB_SENSOR_TYPE = 2, -+ WB_SENSOR_MAX = 3, -+ WB_SENSOR_MAX_HYST = 4, -+ WB_SENSOR_MIN = 5, -+ WB_SENSOR_CRIT = 6, -+} wb_sensor_type_t; -+ -+typedef enum wb_sff_cpld_attr_e { -+ WB_SFF_POWER_ON = 0x01, -+ WB_SFF_TX_FAULT, -+ WB_SFF_TX_DIS, -+ WB_SFF_PRE_N, -+ WB_SFF_RX_LOS, -+ WB_SFF_RESET, -+ WB_SFF_LPMODE, -+ WB_SFF_MODULE_PRESENT, -+ WB_SFF_INTERRUPT, -+} wb_sff_cpld_attr_t; -+ -+struct switch_drivers_t{ -+ /* device */ -+ int (*get_dev_number) (unsigned int main_dev_id, unsigned int minor_dev_id); -+ /* fan */ -+ int (*get_fan_number) (void); -+ ssize_t (*get_fan_speed) (unsigned int fan_index, unsigned int motor_index, unsigned int *speed); -+ int (*get_fan_pwm) (unsigned int fan_index, unsigned int motor_index, int *pwm); -+ int (*set_fan_pwm) (unsigned int fan_index, unsigned int motor_index, int pwm); -+ int (*get_fan_present_status)(unsigned int fan_index); -+ int (*get_fan_roll_status)(unsigned int fan_index, unsigned int motor_index); -+ int (*get_fan_speed_level)(unsigned int fan_index, unsigned int motor_index, int *level); -+ int (*set_fan_speed_level)(unsigned int fan_index, unsigned int motor_index, int level); -+ /* slot */ -+ int (*get_slot_present_status) (unsigned int slot_index); -+ /* sensors */ -+ ssize_t (*get_temp_info)( uint8_t main_dev_id, uint8_t dev_index, -+ uint8_t temp_index, uint8_t temp_attr, char *buf); -+ ssize_t (*get_voltage_info)( uint8_t main_dev_id, uint8_t dev_index, -+ uint8_t in_index, uint8_t in_attr, char *buf); -+ /* psu */ -+ int (*get_psu_present_status)(unsigned int psu_index); -+ int (*get_psu_output_status)(unsigned int psu_index); -+ int (*get_psu_alert_status)(unsigned int psu_index); -+ /* sff */ -+ ssize_t (*get_sff_cpld_info)( unsigned int sff_index, int cpld_reg_type, char *buf, int len); -+ ssize_t (*get_sff_dir_name)(unsigned int sff_index, char *buf, int buf_len); -+}; -+ -+extern struct switch_drivers_t * dfd_plat_driver_get(void); -+ -+#endif /*_SYSFS_COMMON_H_ */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_fan.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_fan.c -new file mode 100644 -index 000000000..931c7c243 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_fan.c -@@ -0,0 +1,501 @@ -+/* -+ * plat_fan.c -+ * -+ * This module create fan kobjects and attributes in /sys/wb_plat/fan -+ * -+ */ -+ -+#include -+ -+#include "./include/plat_switch.h" -+#include "./include/sysfs_common.h" -+ -+#define FAN_INFO(fmt, args...) LOG_INFO("fan: ", fmt, ##args) -+#define FAN_ERR(fmt, args...) LOG_ERR("fan: ", fmt, ##args) -+#define FAN_DBG(fmt, args...) LOG_DBG("fan: ", fmt, ##args) -+ -+struct motor_obj_t{ -+ struct switch_obj *obj; -+}; -+ -+struct fan_obj_t{ -+ unsigned int motor_number; -+ struct motor_obj_t *motor; -+ struct switch_obj *obj; -+}; -+ -+struct fan_t{ -+ unsigned int fan_number; -+ struct fan_obj_t *fan; -+}; -+ -+static int g_loglevel = 0; -+static struct fan_t g_fan; -+static struct switch_obj *g_fan_obj = NULL; -+static struct switch_drivers_t *g_drv = NULL; -+ -+static ssize_t fan_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_fan.fan_number); -+} -+ -+static ssize_t fan_motor_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int index; -+ -+ index = obj->index; -+ FAN_DBG("fan_motor_number_show,fan index:%d\n",index); -+ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_fan.fan[index-1].motor_number); -+} -+ -+static ssize_t fan_roll_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int fan_index, motor_index; -+ struct switch_obj *p_obj; -+ int ret; -+ -+ check_p(g_drv); -+ check_p(g_drv->get_fan_roll_status); -+ -+ p_obj = to_switch_obj(obj->kobj.parent); -+ check_p(p_obj); -+ -+ fan_index = p_obj->index; -+ motor_index = obj->index; -+ -+ ret = g_drv->get_fan_roll_status(fan_index, motor_index); -+ if (ret < 0 ) { -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); -+ } -+ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); -+} -+ -+static ssize_t fan_present_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int fan_index; -+ int ret; -+ -+ fan_index = obj->index; -+ FAN_DBG("fan_present_status_show, fan index:%d\n",fan_index); -+ check_p(g_drv); -+ check_p(g_drv->get_fan_present_status); -+ -+ ret = g_drv->get_fan_present_status(fan_index); -+ if(ret < 0) { -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); -+ } -+ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); -+} -+ -+static ssize_t fan_speed_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int fan_index, motor_index, speed; -+ int ret; -+ struct switch_obj *p_obj; -+ -+ check_p(g_drv); -+ check_p(g_drv->get_fan_speed); -+ -+ p_obj = to_switch_obj(obj->kobj.parent); -+ check_p(p_obj); -+ -+ fan_index = p_obj->index; -+ motor_index = obj->index; -+ -+ ret = g_drv->get_fan_speed(fan_index, motor_index, &speed); -+ if(ret < 0) { -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); -+ } -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", speed); -+} -+ -+static ssize_t fan_motor_ratio_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int fan_index, motor_index; -+ struct switch_obj *p_obj; -+ int ret, pwm; -+ -+ check_p(g_drv); -+ check_p(g_drv->get_fan_pwm); -+ -+ p_obj = to_switch_obj(obj->kobj.parent); -+ check_p(p_obj); -+ fan_index = p_obj->index; -+ motor_index = obj->index; -+ ret = g_drv->get_fan_pwm(fan_index, motor_index, &pwm); -+ -+ if (ret < 0 ) { -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); -+ } -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", pwm); -+} -+ -+static ssize_t fan_motor_ratio_store(struct switch_obj *obj, struct switch_attribute *attr, -+ const char* buf, size_t count) -+{ -+ unsigned int fan_index, motor_index; -+ struct switch_obj *p_obj; -+ int ret, pwm; -+ -+ check_p(g_drv); -+ check_p(g_drv->set_fan_pwm); -+ -+ p_obj = to_switch_obj(obj->kobj.parent); -+ check_p(p_obj); -+ -+ fan_index = p_obj->index; -+ motor_index = obj->index; -+ sscanf(buf, "%d", &pwm); -+ -+ if (pwm < 0 || pwm > 100) { -+ FAN_ERR("can not set pwm = %d.\n", pwm); -+ return -EINVAL; -+ } -+ ret = g_drv->set_fan_pwm(fan_index, motor_index, pwm); -+ if (ret < 0) { -+ FAN_ERR("can not set pwm = %d.\n", pwm); -+ return -EIO; -+ } -+ return count; -+} -+ -+/************************************fan dir and attrs*******************************************/ -+static struct switch_attribute fan_number_att = __ATTR(num_fans, S_IRUGO, fan_number_show, NULL); -+ -+static struct attribute *fan_dir_attrs[] = { -+ &fan_number_att.attr, -+ NULL, -+}; -+ -+static struct attribute_group fan_root_attr_group = { -+ .attrs = fan_dir_attrs, -+}; -+ -+/*******************************fan1 fan2 dir and attrs*******************************************/ -+static struct switch_attribute fan_num_motors_att = __ATTR(num_motors, S_IRUGO, fan_motor_number_show, NULL); -+static struct switch_attribute fan_present_att = __ATTR(present, S_IRUGO, fan_present_status_show, NULL); -+ -+static struct attribute *fan_attrs[] = { -+ &fan_num_motors_att.attr, -+ &fan_present_att.attr, -+ NULL, -+}; -+ -+static struct attribute_group fan_attr_group = { -+ .attrs = fan_attrs, -+}; -+ -+/*******************************motor0 motor1 dir and attrs*******************************************/ -+static struct switch_attribute motor_speed_att = __ATTR(speed, S_IRUGO, fan_speed_show, NULL); -+static struct switch_attribute motor_status_att = __ATTR(status, S_IRUGO, fan_roll_status_show, NULL); -+static struct switch_attribute motor_ratio_att = __ATTR(ratio, S_IRUGO | S_IWUSR, fan_motor_ratio_show, fan_motor_ratio_store); -+ -+static struct attribute *motor_attrs[] = { -+ &motor_speed_att.attr, -+ &motor_status_att.attr, -+ &motor_ratio_att.attr, -+ NULL, -+}; -+ -+static struct attribute_group motor_attr_group = { -+ .attrs = motor_attrs, -+}; -+ -+static void fanindex_single_motor_remove_kobj_and_attrs(struct fan_obj_t * curr_fan, unsigned int motor_index) -+{ -+ struct motor_obj_t *curr_motor; /* point to motor0 motor1...*/ -+ -+ curr_motor = &curr_fan->motor[motor_index]; -+ if (curr_motor->obj) { -+ sysfs_remove_group(&curr_motor->obj->kobj, &motor_attr_group); -+ wb_plat_kobject_delete(&curr_motor->obj); -+ FAN_DBG("delete fan:%d motor%d.\n", curr_fan->obj->index, motor_index); -+ } -+ return; -+} -+ -+static int fanindex_single_motor_create_kobj_and_attrs(struct fan_obj_t * curr_fan, unsigned int motor_index) -+{ -+ char name[DIR_NAME_MAX_LEN]; -+ struct motor_obj_t *curr_motor; /* point to motor0 motor1...*/ -+ -+ FAN_DBG("create fan_index:%d, motor%d ...\n", curr_fan->obj->index, motor_index); -+ -+ curr_motor = &curr_fan->motor[motor_index]; -+ mem_clear(name, sizeof(name)); -+ snprintf(name, sizeof(name), "motor%d", motor_index); -+ curr_motor->obj = wb_plat_kobject_create(name, &curr_fan->obj->kobj); -+ if (!curr_motor->obj) { -+ FAN_ERR("create fan_index:%d, motor%d object error!\n", curr_fan->obj->index, motor_index); -+ return -EBADRQC; -+ } -+ curr_motor->obj->index = motor_index; -+ if (sysfs_create_group(&curr_motor->obj->kobj, &motor_attr_group) != 0) { -+ FAN_ERR("create fan_index:%d, motor%d attrs error.\n", curr_fan->obj->index, motor_index); -+ wb_plat_kobject_delete(&curr_motor->obj); -+ return -EBADRQC; -+ } -+ FAN_DBG("create fan_index:%d, motor%d ok.\n", curr_fan->obj->index, motor_index); -+ return 0; -+} -+ -+static int fanindex_motor_create_kobj_and_attrs(struct fan_obj_t * curr_fan, int motor_num) -+{ -+ int motor_index, i; -+ -+ curr_fan->motor = kzalloc(sizeof(struct motor_obj_t) * motor_num, GFP_KERNEL); -+ if (!curr_fan->motor) { -+ FAN_ERR("kzalloc motor error, fan index = %d, motor number = %d.\n", curr_fan->obj->index, motor_num); -+ return -ENOMEM; -+ } -+ curr_fan->motor_number = motor_num; -+ for (motor_index = 0; motor_index < motor_num; motor_index++) { -+ if (fanindex_single_motor_create_kobj_and_attrs(curr_fan, motor_index) != 0) { -+ goto motor_error; -+ } -+ } -+ return 0; -+motor_error: -+ for(i = motor_index - 1; i >= 0; i--) { -+ fanindex_single_motor_remove_kobj_and_attrs(curr_fan, i); -+ } -+ if(curr_fan->motor) { -+ kfree(curr_fan->motor); -+ curr_fan->motor = NULL; -+ } -+ return -EBADRQC; -+} -+ -+static void fanindex_motor_remove_kobj_and_attrs(struct fan_obj_t *curr_fan, int motor_num) -+{ -+ int motor_index; -+ -+ for (motor_index = motor_num - 1; motor_index >= 0; motor_index--) { -+ fanindex_single_motor_remove_kobj_and_attrs(curr_fan, motor_index); -+ } -+ return; -+} -+ -+static int fan_motor_create(void) -+{ -+ int fan_num, motor_num; -+ unsigned int fan_index, i; -+ struct fan_obj_t *curr_fan; /* point to fan1 fan2...*/ -+ -+ check_p(g_drv->get_dev_number); -+ -+ motor_num = g_drv->get_dev_number(WB_MAIN_DEV_FAN, WB_MINOR_DEV_MOTOR); -+ if (motor_num <= 0) { -+ FAN_ERR("get fan motor number error, motor_num:%d error.\n", motor_num); -+ return -ENODEV; -+ } -+ -+ fan_num = g_fan.fan_number; -+ for (fan_index = 1; fan_index <= fan_num; fan_index++) { -+ curr_fan = &g_fan.fan[fan_index - 1]; -+ if (fanindex_motor_create_kobj_and_attrs(curr_fan, motor_num) != 0) { -+ goto error; -+ } -+ } -+ return 0; -+error: -+ for (i = fan_index - 1; i > 0; i--) { -+ curr_fan = &g_fan.fan[i - 1]; -+ motor_num = curr_fan->motor_number; -+ fanindex_motor_remove_kobj_and_attrs(curr_fan, motor_num); -+ } -+ return -EBADRQC; -+} -+ -+static void fan_motor_remove(void) -+{ -+ unsigned int fan_index; -+ struct fan_obj_t *curr_fan; -+ -+ if (g_fan.fan) { -+ for (fan_index = g_fan.fan_number; fan_index > 0; fan_index--) { -+ curr_fan = &g_fan.fan[fan_index - 1]; -+ if (curr_fan->motor) { -+ fanindex_motor_remove_kobj_and_attrs(curr_fan, curr_fan->motor_number); -+ kfree(curr_fan->motor); -+ curr_fan->motor = NULL; -+ curr_fan->motor_number = 0; -+ } -+ } -+ } -+ return; -+} -+ -+static void fan_sub_single_remove_kobj_and_attrs(unsigned int index) -+{ -+ struct fan_obj_t *curr_fan; -+ -+ curr_fan = &g_fan.fan[index - 1]; -+ if (curr_fan->obj) { -+ sysfs_remove_group(&curr_fan->obj->kobj, &fan_attr_group); -+ wb_plat_kobject_delete(&curr_fan->obj); -+ FAN_DBG("delete fan%d.\n", index); -+ } -+ return; -+} -+ -+static int fan_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) -+{ -+ char name[DIR_NAME_MAX_LEN]; -+ struct fan_obj_t *curr_fan; -+ -+ curr_fan = &g_fan.fan[index - 1]; -+ FAN_DBG("create fan%d ...\n", index); -+ mem_clear(name, sizeof(name)); -+ snprintf(name, sizeof(name), "fan%d", index); -+ curr_fan->obj = wb_plat_kobject_create(name, parent); -+ if (!curr_fan->obj) { -+ FAN_ERR("create fan%d object error!\n", index); -+ return -EBADRQC; -+ } -+ curr_fan->obj->index = index; -+ if (sysfs_create_group(&curr_fan->obj->kobj, &fan_attr_group) != 0) { -+ FAN_ERR("create fan%d attrs error.\n", index); -+ wb_plat_kobject_delete(&curr_fan->obj); -+ return -EBADRQC; -+ } -+ FAN_DBG("create fan%d ok.\n", index); -+ return 0; -+} -+ -+static int fan_sub_create_kobj_and_attrs(struct kobject *parent, int fan_num) -+{ -+ unsigned int fan_index, i; -+ -+ g_fan.fan = kzalloc(sizeof(struct fan_obj_t) * fan_num, GFP_KERNEL); -+ if (!g_fan.fan) { -+ FAN_ERR("kzalloc fan.fan error, fan number = %d.\n", fan_num); -+ return -ENOMEM; -+ } -+ -+ for (fan_index = 1; fan_index <= fan_num; fan_index++) { -+ if(fan_sub_single_create_kobj_and_attrs(parent, fan_index) != 0 ) { -+ goto error; -+ } -+ } -+ return 0; -+error: -+ for (i = fan_index - 1; i > 0; i--) { -+ fan_sub_single_remove_kobj_and_attrs(i); -+ } -+ if (g_fan.fan) { -+ kfree(g_fan.fan); -+ g_fan.fan = NULL; -+ } -+ return -EBADRQC; -+} -+ -+static int fan_sub_create(void) -+{ -+ int ret, fan_num; -+ -+ check_p(g_drv->get_dev_number); -+ fan_num = g_drv->get_dev_number(WB_MAIN_DEV_FAN, WB_MINOR_DEV_NONE); -+ if (fan_num < 0) { -+ FAN_ERR("fan number = %d error.\n", fan_num); -+ return -EINVAL; -+ } -+ g_fan.fan_number = fan_num; -+ ret = fan_sub_create_kobj_and_attrs(&g_fan_obj->kobj, fan_num); -+ return ret; -+} -+ -+static void fan_sub_remove(void) -+{ -+ unsigned int fan_index; -+ -+ if (g_fan.fan) { -+ for (fan_index = g_fan.fan_number; fan_index > 0; fan_index--) { -+ fan_sub_single_remove_kobj_and_attrs(fan_index); -+ } -+ kfree(g_fan.fan); -+ } -+ mem_clear(&g_fan, sizeof(struct fan_t)); -+ return; -+} -+ -+static int fan_root_create(void) -+{ -+ g_fan_obj = wb_plat_kobject_create("fan", NULL); -+ if (!g_fan_obj) { -+ FAN_ERR("wb_plat_kobject_create fan error!\n"); -+ return -ENOMEM; -+ } -+ -+ if (sysfs_create_group(&g_fan_obj->kobj, &fan_root_attr_group) != 0) { -+ wb_plat_kobject_delete(&g_fan_obj); -+ FAN_ERR("create fan dir attrs error!\n"); -+ return -EBADRQC; -+ } -+ FAN_DBG("wb_plat_kobject_create fan directory and attribute success.\n"); -+ return 0; -+} -+ -+static void fan_root_remove(void) -+{ -+ if (g_fan_obj) { -+ sysfs_remove_group(&g_fan_obj->kobj, &fan_root_attr_group); -+ wb_plat_kobject_delete(&g_fan_obj); -+ FAN_DBG("delete fan root success\n"); -+ } -+ -+ return; -+} -+ -+static int fan_init(void) -+{ -+ int ret; -+ -+ FAN_INFO("fan_init...\n"); -+ g_drv = dfd_plat_driver_get(); -+ check_p(g_drv); -+ -+ ret = fan_root_create(); -+ if (ret < 0) { -+ goto fan_root_error; -+ } -+ -+ ret = fan_sub_create(); -+ if (ret < 0) { -+ goto fan_sub_error; -+ } -+ -+ ret = fan_motor_create(); -+ if (ret < 0) { -+ goto fan_motor_error; -+ } -+ -+ FAN_INFO("fan_init ok.\n"); -+ return 0; -+fan_motor_error: -+ fan_sub_remove(); -+fan_sub_error: -+ fan_root_remove(); -+fan_root_error: -+ return ret; -+} -+ -+static void fan_exit(void) -+{ -+ fan_motor_remove(); -+ fan_sub_remove(); -+ fan_root_remove(); -+ FAN_INFO("fan_exit ok.\n"); -+ return ; -+} -+ -+module_init(fan_init); -+module_exit(fan_exit); -+module_param(g_loglevel, int, 0644); -+MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("fan sysfs driver"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_psu.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_psu.c -new file mode 100644 -index 000000000..197f94b64 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_psu.c -@@ -0,0 +1,426 @@ -+/* -+ * plat_psu.c -+ * -+ * This module create psu kobjects and attributes in /sys/wb_plat/psu -+ * -+ */ -+ -+#include -+ -+#include "./include/plat_switch.h" -+#include "./include/sysfs_common.h" -+ -+#define PSU_INFO(fmt, args...) LOG_INFO("psu: ", fmt, ##args) -+#define PSU_ERR(fmt, args...) LOG_ERR("psu: ", fmt, ##args) -+#define PSU_DBG(fmt, args...) LOG_DBG("psu: ", fmt, ##args) -+ -+struct temp_obj_t{ -+ struct switch_obj *obj; -+}; -+ -+struct psu_obj_t{ -+ unsigned int temp_number; -+ struct temp_obj_t *temp; -+ struct switch_obj *obj; -+}; -+ -+struct psu_t{ -+ unsigned int psu_number; -+ struct psu_obj_t *psu; -+}; -+ -+static int g_loglevel = 0; -+static struct psu_t g_psu; -+static struct switch_obj *g_psu_obj = NULL; -+static struct switch_drivers_t *g_drv = NULL; -+ -+static ssize_t psu_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_psu.psu_number); -+} -+ -+static ssize_t psu_present_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int psu_index; -+ int ret; -+ -+ psu_index = obj->index; -+ PSU_DBG("psu_present_status_show, psu index:%d\n",psu_index); -+ check_p(g_drv); -+ check_p(g_drv->get_psu_present_status); -+ -+ ret = g_drv->get_psu_present_status(psu_index); -+ if(ret < 0) { -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); -+ } -+ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); -+} -+ -+static ssize_t psu_output_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int psu_index; -+ int ret; -+ -+ psu_index = obj->index; -+ PSU_DBG("psu_output_status_show, psu index:%d\n",psu_index); -+ check_p(g_drv); -+ check_p(g_drv->get_psu_output_status); -+ -+ ret = g_drv->get_psu_output_status(psu_index); -+ if(ret < 0) { -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); -+ } -+ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); -+} -+ -+static ssize_t psu_alert_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int psu_index; -+ int ret; -+ -+ psu_index = obj->index; -+ PSU_DBG("psu_alert_status_show, psu index:%d\n",psu_index); -+ check_p(g_drv); -+ check_p(g_drv->get_psu_alert_status); -+ -+ ret = g_drv->get_psu_alert_status(psu_index); -+ if(ret < 0) { -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); -+ } -+ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); -+} -+ -+/************************************psu dir and attrs*******************************************/ -+static struct switch_attribute psu_number_att = __ATTR(num_psus, S_IRUGO, psu_number_show, NULL); -+ -+static struct attribute *psu_dir_attrs[] = { -+ &psu_number_att.attr, -+ NULL, -+}; -+ -+static struct attribute_group psu_root_attr_group = { -+ .attrs = psu_dir_attrs, -+}; -+ -+/*******************************psu1 psu2 dir and attrs*******************************************/ -+static struct switch_attribute psu_present_status_att = __ATTR(present, S_IRUGO, psu_present_status_show, NULL); -+static struct switch_attribute psu_output_status_att = __ATTR(output, S_IRUGO, psu_output_status_show, NULL); -+static struct switch_attribute psu_alert_status_att = __ATTR(alert, S_IRUGO, psu_alert_status_show, NULL); -+ -+static struct attribute *psu_attrs[] = { -+ &psu_present_status_att.attr, -+ &psu_output_status_att.attr, -+ &psu_alert_status_att.attr, -+ NULL, -+}; -+ -+static struct attribute_group psu_attr_group = { -+ .attrs = psu_attrs, -+}; -+ -+/*******************************psu temp0 temp1 dir and attrs*******************************************/ -+static struct attribute *psu_temp_attrs[] = { -+ NULL, -+}; -+ -+static struct attribute_group psu_temp_attr_group = { -+ .attrs = psu_temp_attrs, -+}; -+ -+static void psuindex_single_temp_remove_kobj_and_attrs(struct psu_obj_t * curr_psu, unsigned int temp_index) -+{ -+ -+ struct temp_obj_t *curr_temp; /* point to temp0 temp1...*/ -+ -+ curr_temp = &curr_psu->temp[temp_index]; -+ if (curr_temp->obj) { -+ sysfs_remove_group(&curr_temp->obj->kobj, &psu_temp_attr_group); -+ wb_plat_kobject_delete(&curr_temp->obj); -+ PSU_DBG("delete psu:%d temp%d.\n", curr_psu->obj->index, temp_index); -+ } -+ return; -+} -+ -+static int psuindex_single_temp_create_kobj_and_attrs(struct psu_obj_t * curr_psu, unsigned int temp_index) -+{ -+ char name[DIR_NAME_MAX_LEN]; -+ struct temp_obj_t *curr_temp; /* point to temp0 temp1...*/ -+ -+ PSU_DBG("create psu_index:%d, temp%d ...\n", curr_psu->obj->index, temp_index); -+ -+ curr_temp = &curr_psu->temp[temp_index]; -+ mem_clear(name, sizeof(name)); -+ snprintf(name, sizeof(name), "temp%d", temp_index); -+ curr_temp->obj = wb_plat_kobject_create(name, &curr_psu->obj->kobj); -+ if (!curr_temp->obj) { -+ PSU_ERR("create psu_index:%d, temp%d object error!\n", curr_psu->obj->index, temp_index); -+ return -EBADRQC; -+ } -+ curr_temp->obj->index = temp_index; -+ if (sysfs_create_group(&curr_temp->obj->kobj, &psu_temp_attr_group) != 0) { -+ PSU_ERR("create psu_index:%d, temp%d attrs error.\n", curr_psu->obj->index, temp_index); -+ wb_plat_kobject_delete(&curr_temp->obj); -+ return -EBADRQC; -+ } -+ PSU_DBG("create psu_index:%d, temp%d ok.\n", curr_psu->obj->index, temp_index); -+ return 0; -+} -+ -+static int psuindex_temp_create_kobj_and_attrs(struct psu_obj_t * curr_psu, int temp_num) -+{ -+ int temp_index, i; -+ -+ curr_psu->temp = kzalloc(sizeof(struct temp_obj_t) * temp_num, GFP_KERNEL); -+ if (!curr_psu->temp) { -+ PSU_ERR("kzalloc temp error, psu index = %d, temp number = %d.\n", curr_psu->obj->index, temp_num); -+ return -ENOMEM; -+ } -+ curr_psu->temp_number = temp_num; -+ for (temp_index = 0; temp_index < temp_num; temp_index++) { -+ if (psuindex_single_temp_create_kobj_and_attrs(curr_psu, temp_index) != 0) { -+ goto temp_error; -+ } -+ } -+ return 0; -+temp_error: -+ for (i = temp_index - 1; i >= 0; i--) { -+ psuindex_single_temp_remove_kobj_and_attrs(curr_psu, i); -+ } -+ if (curr_psu->temp) { -+ kfree(curr_psu->temp); -+ curr_psu->temp = NULL; -+ } -+ return -EBADRQC; -+} -+ -+static void psuindex_temp_remove_kobj_and_attrs(struct psu_obj_t * curr_psu, int temp_num) -+{ -+ unsigned int temp_index; -+ -+ for (temp_index = temp_num - 1; temp_index >= 0; temp_index--) { -+ psuindex_single_temp_remove_kobj_and_attrs(curr_psu, temp_index); -+ } -+ return; -+} -+ -+static int psu_temp_create(void) -+{ -+ int psu_num, temp_num; -+ unsigned int psu_index, i; -+ struct psu_obj_t *curr_psu; /* point to psu1 psu2...*/ -+ -+ check_p(g_drv->get_dev_number); -+ temp_num = g_drv->get_dev_number(WB_MAIN_DEV_PSU, WB_MINOR_DEV_TEMP); -+ if (temp_num <= 0) { -+ PSU_INFO("psu temp_num:%d, don't need creat temp directory.\n", temp_num); -+ return 0; -+ } -+ -+ psu_num = g_psu.psu_number; -+ for(psu_index = 1; psu_index <= psu_num; psu_index++) { -+ curr_psu = &g_psu.psu[psu_index - 1]; -+ if(psuindex_temp_create_kobj_and_attrs(curr_psu, temp_num) != 0) { -+ goto error; -+ } -+ } -+ return 0; -+error: -+ for(i = psu_index - 1; i > 0; i--) { -+ curr_psu = &g_psu.psu[i - 1]; -+ temp_num = curr_psu->temp_number; -+ psuindex_temp_remove_kobj_and_attrs(curr_psu, temp_num); -+ } -+ return -EBADRQC; -+} -+ -+static void psu_temp_remove(void) -+{ -+ unsigned int psu_index; -+ struct psu_obj_t *curr_psu; -+ -+ if (g_psu.psu) { -+ for (psu_index = g_psu.psu_number; psu_index > 0; psu_index--) { -+ curr_psu = &g_psu.psu[psu_index - 1]; -+ if (curr_psu->temp) { -+ psuindex_temp_remove_kobj_and_attrs(curr_psu,curr_psu->temp_number); -+ kfree(curr_psu->temp); -+ curr_psu->temp = NULL; -+ curr_psu->temp_number = 0; -+ } -+ } -+ } -+ return; -+} -+ -+static void psu_sub_single_remove_kobj_and_attrs(unsigned int index) -+{ -+ struct psu_obj_t *curr_psu; -+ -+ curr_psu = &g_psu.psu[index - 1]; -+ if (curr_psu->obj) { -+ sysfs_remove_group(&curr_psu->obj->kobj, &psu_attr_group); -+ wb_plat_kobject_delete(&curr_psu->obj); -+ PSU_DBG("delete psu%d.\n", index); -+ } -+ return; -+} -+ -+static int psu_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) -+{ -+ char name[DIR_NAME_MAX_LEN]; -+ struct psu_obj_t *curr_psu; -+ -+ curr_psu = &g_psu.psu[index-1]; -+ PSU_DBG("create psu%d ...\n", index); -+ mem_clear(name, sizeof(name)); -+ snprintf(name, sizeof(name), "%s%d",PSU_SYSFS_NAME, index); -+ curr_psu->obj = wb_plat_kobject_create(name, parent); -+ if (!curr_psu->obj) { -+ PSU_ERR("create psu%d object error!\n", index); -+ return -EBADRQC; -+ } -+ curr_psu->obj->index = index; -+ if (sysfs_create_group(&curr_psu->obj->kobj, &psu_attr_group) != 0) { -+ PSU_ERR("create psu%d attrs error.\n", index); -+ wb_plat_kobject_delete(&curr_psu->obj); -+ return -EBADRQC; -+ } -+ PSU_DBG("create psu%d ok.\n", index); -+ return 0; -+} -+ -+static int psu_sub_create_kobj_and_attrs(struct kobject *parent, int psu_num) -+{ -+ unsigned int psu_index, i; -+ -+ g_psu.psu = kzalloc(sizeof(struct psu_obj_t) * psu_num, GFP_KERNEL); -+ if (!g_psu.psu) { -+ PSU_ERR("kzalloc psu.psu error, psu number = %d.\n", psu_num); -+ return -ENOMEM; -+ } -+ -+ for (psu_index = 1; psu_index <= psu_num; psu_index++) { -+ if (psu_sub_single_create_kobj_and_attrs(parent, psu_index) != 0) { -+ goto error; -+ } -+ } -+ return 0; -+error: -+ for(i = psu_index - 1; i > 0; i--) { -+ psu_sub_single_remove_kobj_and_attrs(i); -+ } -+ if(g_psu.psu) { -+ kfree(g_psu.psu); -+ g_psu.psu = NULL; -+ } -+ return -EBADRQC; -+} -+ -+static int psu_sub_create(void) -+{ -+ int ret, psu_num; -+ -+ check_p(g_drv->get_dev_number); -+ psu_num = g_drv->get_dev_number(WB_MAIN_DEV_PSU, WB_MINOR_DEV_NONE); -+ if (psu_num < 0) { -+ PSU_ERR("psu number = %d error.\n", psu_num); -+ return -EINVAL; -+ } -+ g_psu.psu_number = psu_num; -+ ret = psu_sub_create_kobj_and_attrs(&g_psu_obj->kobj, psu_num); -+ return ret; -+} -+ -+static void psu_sub_remove(void) -+{ -+ unsigned int psu_index; -+ -+ if (g_psu.psu) { -+ for (psu_index = g_psu.psu_number; psu_index > 0; psu_index--) { -+ psu_sub_single_remove_kobj_and_attrs(psu_index); -+ } -+ kfree(g_psu.psu); -+ } -+ mem_clear(&g_psu, sizeof(struct psu_t)); -+ return ; -+} -+ -+static int psu_root_create(void) -+{ -+ g_psu_obj = wb_plat_kobject_create(PSU_SYSFS_NAME, NULL); -+ if (!g_psu_obj) { -+ PSU_ERR("wb_plat_kobject_create psu error!\n"); -+ return -ENOMEM; -+ } -+ -+ if (sysfs_create_group(&g_psu_obj->kobj, &psu_root_attr_group) != 0) { -+ wb_plat_kobject_delete(&g_psu_obj); -+ PSU_ERR("create psu dir attrs error!\n"); -+ return -EBADRQC; -+ } -+ PSU_DBG("wb_plat_kobject_create psu directory and attribute success.\n"); -+ return 0; -+} -+ -+static void psu_root_remove(void) -+{ -+ if (g_psu_obj) { -+ sysfs_remove_group(&g_psu_obj->kobj, &psu_root_attr_group); -+ wb_plat_kobject_delete(&g_psu_obj); -+ PSU_DBG("delete psu root success\n"); -+ } -+ return; -+} -+ -+static int wb_psu_init(void) -+{ -+ int ret; -+ -+ PSU_INFO("wb_psu_init...\n"); -+ g_drv = dfd_plat_driver_get(); -+ check_p(g_drv); -+ -+ ret = psu_root_create(); -+ if (ret < 0) { -+ goto psu_root_error; -+ } -+ -+ ret = psu_sub_create(); -+ if (ret < 0) { -+ goto psu_sub_error; -+ } -+ -+ ret = psu_temp_create(); -+ if (ret < 0) { -+ goto psu_temp_error; -+ } -+ -+ PSU_INFO("wb_psu_init ok.\n"); -+ return 0; -+psu_temp_error: -+ psu_sub_remove(); -+psu_sub_error: -+ psu_root_remove(); -+psu_root_error: -+ return ret; -+} -+ -+static void wb_psu_exit(void) -+{ -+ psu_temp_remove(); -+ psu_sub_remove(); -+ psu_root_remove(); -+ PSU_INFO("wb_psu_exit ok.\n"); -+ return ; -+} -+ -+module_init(wb_psu_init); -+module_exit(wb_psu_exit); -+module_param(g_loglevel, int, 0644); -+MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("psu sysfs driver"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sensor.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sensor.c -new file mode 100644 -index 000000000..aaf62f4c1 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sensor.c -@@ -0,0 +1,452 @@ -+/* -+ * plat_sensor.c -+ * -+ * This module create sensor kobjects and attributes in /sys/wb_plat/sensor -+ */ -+ -+#include -+ -+#include "./include/plat_switch.h" -+#include "./include/sysfs_common.h" -+ -+#define SENSOR_INFO(fmt, args...) LOG_INFO("sensor: ", fmt, ##args) -+#define SENSOR_ERR(fmt, args...) LOG_ERR("sensor: ", fmt, ##args) -+#define SENSOR_DBG(fmt, args...) LOG_DBG("sensor: ", fmt, ##args) -+ -+struct sensor_t { -+ unsigned int in_number; -+ unsigned int temp_number; -+ struct sensor_in_t *in; -+ struct sensor_temp_t *temp; -+}; -+ -+struct sensor_temp_t { -+ struct switch_obj *obj; -+}; -+ -+struct sensor_in_t { -+ struct switch_obj *obj; -+}; -+ -+static int g_loglevel = 0; -+static struct switch_drivers_t *g_drv = NULL; -+static struct sensor_t g_sensor; -+static struct switch_obj *g_sensor_obj = NULL; -+ -+static ssize_t sensor_temp_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_sensor.temp_number); -+} -+ -+static ssize_t sensor_in_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_sensor.in_number); -+} -+ -+static ssize_t sensor_voltage_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int in_index; -+ int ret; -+ struct switch_device_attribute *in_attr; -+ -+ check_p(g_drv); -+ check_p(g_drv->get_voltage_info); -+ in_index = obj->index; -+ -+ in_attr = to_switch_device_attr(attr); -+ check_p(in_attr); -+ SENSOR_DBG("sensor_in_show, in index:0x%x, in type:0x%x\n",in_index, in_attr->type); -+ ret = g_drv->get_voltage_info(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_NONE, in_index, in_attr->type, buf); -+ if (ret < 0) { -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); -+ } -+ return ret; -+} -+ -+static ssize_t sensor_temp_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int temp_index; -+ int ret; -+ struct switch_device_attribute *temp_attr; -+ -+ check_p(g_drv); -+ check_p(g_drv->get_temp_info); -+ temp_index = obj->index; -+ -+ temp_attr = to_switch_device_attr(attr); -+ check_p(temp_attr); -+ SENSOR_DBG("sensor_temp_show, temp index:0x%x, temp type:0x%x\n", temp_index, temp_attr->type); -+ ret = g_drv->get_temp_info(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_NONE, temp_index, temp_attr->type, buf); -+ if (ret < 0) { -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); -+ } -+ return ret; -+} -+ -+/************************************sensor dir and attrs*******************************************/ -+static struct switch_attribute num_temp_att = __ATTR(num_temp_sensors, S_IRUGO, sensor_temp_number_show, NULL); -+static struct switch_attribute num_in_att = __ATTR(num_in_sensors, S_IRUGO, sensor_in_number_show, NULL); -+ -+static struct attribute *sensor_dir_attrs[] = { -+ &num_temp_att.attr, -+ &num_in_att.attr, -+ NULL, -+}; -+ -+static struct attribute_group sensor_root_attr_group = { -+ .attrs = sensor_dir_attrs, -+}; -+ -+/*******************************temp0 temp1 dir and attrs*******************************************/ -+static SWITCH_DEVICE_ATTR(temp_input, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_INPUT); -+static SWITCH_DEVICE_ATTR(temp_alias, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_ALIAS); -+static SWITCH_DEVICE_ATTR(temp_type, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_TYPE); -+static SWITCH_DEVICE_ATTR(temp_max, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_MAX); -+static SWITCH_DEVICE_ATTR(temp_max_hyst, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_MAX_HYST); -+static SWITCH_DEVICE_ATTR(temp_min, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_MIN); -+ -+static struct attribute *sensor_temp_attrs[] = { -+ &switch_dev_attr_temp_input.switch_attr.attr, -+ &switch_dev_attr_temp_alias.switch_attr.attr, -+ &switch_dev_attr_temp_type.switch_attr.attr, -+ &switch_dev_attr_temp_max.switch_attr.attr, -+ &switch_dev_attr_temp_max_hyst.switch_attr.attr, -+ &switch_dev_attr_temp_min.switch_attr.attr, -+ NULL, -+}; -+ -+static struct attribute_group sensor_temp_attr_group = { -+ .attrs = sensor_temp_attrs, -+}; -+ -+/*******************************in0 in1 dir and attrs*******************************************/ -+static SWITCH_DEVICE_ATTR(in_input, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_INPUT); -+static SWITCH_DEVICE_ATTR(in_alias, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_ALIAS); -+static SWITCH_DEVICE_ATTR(in_type, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_TYPE); -+static SWITCH_DEVICE_ATTR(in_max, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_MAX); -+static SWITCH_DEVICE_ATTR(in_min, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_MIN); -+static SWITCH_DEVICE_ATTR(in_crit, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_CRIT); -+ -+static struct attribute *sensor_in_attrs[] = { -+ &switch_dev_attr_in_input.switch_attr.attr, -+ &switch_dev_attr_in_alias.switch_attr.attr, -+ &switch_dev_attr_in_type.switch_attr.attr, -+ &switch_dev_attr_in_max.switch_attr.attr, -+ &switch_dev_attr_in_min.switch_attr.attr, -+ &switch_dev_attr_in_crit.switch_attr.attr, -+ NULL, -+}; -+ -+static struct attribute_group sensor_in_attr_group = { -+ .attrs = sensor_in_attrs, -+}; -+ -+static int sensor_in_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) -+{ -+ char name[DIR_NAME_MAX_LEN]; -+ struct sensor_in_t *curr_sensor; -+ -+ curr_sensor = &g_sensor.in[index - 1]; -+ SENSOR_DBG("create sensor in%d ...\n", index); -+ mem_clear(name, sizeof(name)); -+ snprintf(name, sizeof(name), "in%d", index); -+ curr_sensor->obj = wb_plat_kobject_create(name, parent); -+ if (!curr_sensor->obj) { -+ SENSOR_ERR("create sensor in%d object error!\n", index); -+ return -EBADRQC; -+ } -+ curr_sensor->obj->index = index; -+ if (sysfs_create_group(&curr_sensor->obj->kobj, &sensor_in_attr_group) != 0) { -+ SENSOR_ERR("create sensor in%d attrs error.\n", index); -+ wb_plat_kobject_delete(&curr_sensor->obj); -+ return -EBADRQC; -+ } -+ SENSOR_DBG("create sensor in%d ok.\n", index); -+ return 0; -+ -+} -+ -+static void sensor_in_sub_single_remove_kobj_and_attrs(unsigned int index) -+{ -+ struct sensor_in_t *curr_in; -+ -+ curr_in = &g_sensor.in[index - 1]; -+ if (curr_in->obj) { -+ sysfs_remove_group(&curr_in->obj->kobj, &sensor_in_attr_group); -+ wb_plat_kobject_delete(&curr_in->obj); -+ SENSOR_DBG("delete in%d.\n", index); -+ } -+ return; -+} -+ -+static int sensor_temp_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) -+{ -+ char name[DIR_NAME_MAX_LEN]; -+ struct sensor_temp_t *curr_sensor; -+ -+ curr_sensor = &g_sensor.temp[index - 1]; -+ SENSOR_DBG("create sensor temp%d ...\n", index); -+ mem_clear(name, sizeof(name)); -+ snprintf(name, sizeof(name), "temp%d", index); -+ curr_sensor->obj = wb_plat_kobject_create(name, parent); -+ if (!curr_sensor->obj) { -+ SENSOR_ERR("create sensor temp%d object error!\n", index); -+ return -EBADRQC; -+ } -+ curr_sensor->obj->index = index; -+ if (sysfs_create_group(&curr_sensor->obj->kobj, &sensor_temp_attr_group) != 0) { -+ SENSOR_ERR("create sensor temp%d attrs error.\n", index); -+ wb_plat_kobject_delete(&curr_sensor->obj); -+ return -EBADRQC; -+ } -+ SENSOR_DBG("create sensor temp%d ok.\n", index); -+ return 0; -+ -+} -+ -+static void sensor_temp_sub_single_remove_kobj_and_attrs(unsigned int index) -+{ -+ struct sensor_temp_t *curr_temp; -+ -+ curr_temp = &g_sensor.temp[index - 1]; -+ if (curr_temp->obj) { -+ sysfs_remove_group(&curr_temp->obj->kobj, &sensor_temp_attr_group); -+ wb_plat_kobject_delete(&curr_temp->obj); -+ SENSOR_DBG("delete temp%d.\n", index); -+ } -+ return; -+} -+ -+static int sensor_temp_sub_create_kobj_and_attrs(struct kobject *parent, int temp_num) -+{ -+ unsigned int temp_index, i; -+ -+ g_sensor.temp = kzalloc(sizeof(struct sensor_temp_t) * temp_num, GFP_KERNEL); -+ if (!g_sensor.temp ) { -+ SENSOR_ERR("kzalloc g_sensor.temp error, temp number = %d.\n", temp_num); -+ return -ENOMEM; -+ } -+ for (temp_index = 1; temp_index <= temp_num; temp_index++) { -+ if (sensor_temp_sub_single_create_kobj_and_attrs(parent, temp_index) != 0 ) { -+ goto error; -+ } -+ } -+ return 0; -+error: -+ for (i = temp_index - 1; i > 0; i--) { -+ sensor_temp_sub_single_remove_kobj_and_attrs(i); -+ } -+ -+ if (g_sensor.temp) { -+ kfree(g_sensor.temp); -+ g_sensor.temp = NULL; -+ } -+ return -EBADRQC; -+} -+ -+static int sensor_in_sub_create_kobj_and_attrs(struct kobject *parent, int in_num) -+{ -+ unsigned int in_index, i; -+ -+ g_sensor.in = kzalloc(sizeof(struct sensor_in_t) * in_num, GFP_KERNEL); -+ if (!g_sensor.in) { -+ SENSOR_ERR("kzalloc g_sensor.in error, in number = %d.\n", in_num); -+ return -ENOMEM; -+ } -+ -+ for (in_index = 1; in_index <= in_num; in_index++) { -+ if (sensor_in_sub_single_create_kobj_and_attrs(parent, in_index) != 0 ) { -+ goto error; -+ } -+ } -+ return 0; -+error: -+ for (i = in_index - 1; i > 0; i--) { -+ sensor_in_sub_single_remove_kobj_and_attrs(i); -+ } -+ -+ if (g_sensor.in) { -+ kfree(g_sensor.in); -+ g_sensor.in = NULL; -+ } -+ return -EBADRQC; -+} -+ -+static int sensor_temp_sub_create(void) -+{ -+ int ret, temp_num; -+ -+ check_p(g_drv->get_dev_number); -+ temp_num = g_drv->get_dev_number(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_TEMP); -+ g_sensor.temp_number = temp_num; -+ if (temp_num <= 0) { -+ SENSOR_DBG("Warning:sensor temp number = %d \n", temp_num); -+ return 0; -+ } -+ ret = sensor_temp_sub_create_kobj_and_attrs(&g_sensor_obj->kobj, temp_num); -+ return ret; -+} -+ -+static int sensor_in_sub_create(void) -+{ -+ int ret, in_num; -+ -+ check_p(g_drv->get_dev_number); -+ in_num = g_drv->get_dev_number(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_IN); -+ g_sensor.in_number = in_num; -+ -+ if (in_num <= 0) { -+ SENSOR_DBG("Warning:sensor in number = %d \n", in_num); -+ return 0; -+ } -+ ret = sensor_in_sub_create_kobj_and_attrs(&g_sensor_obj->kobj, in_num); -+ return ret; -+} -+ -+static void temp_sub_single_remove_kobj_and_attrs(unsigned int index) -+{ -+ struct sensor_temp_t * curr_temp; -+ -+ curr_temp = &g_sensor.temp[index - 1]; -+ if (curr_temp->obj) { -+ sysfs_remove_group(&curr_temp->obj->kobj, &sensor_temp_attr_group); -+ wb_plat_kobject_delete(&curr_temp->obj); -+ SENSOR_DBG("delete sensor temp%d.\n", index); -+ } -+ return; -+} -+ -+static void in_sub_single_remove_kobj_and_attrs(unsigned int index) -+{ -+ struct sensor_in_t * curr_in; -+ -+ curr_in = &g_sensor.in[index - 1]; -+ if (curr_in->obj) { -+ sysfs_remove_group(&curr_in->obj->kobj, &sensor_in_attr_group); -+ wb_plat_kobject_delete(&curr_in->obj); -+ SENSOR_DBG("delete sensor in%d.\n", index); -+ } -+ return; -+} -+ -+static void sensor_temp_sub_remove(void) -+{ -+ unsigned int temp_index; -+ -+ if (g_sensor.temp) { -+ for (temp_index = g_sensor.temp_number; temp_index > 0; temp_index--) { -+ temp_sub_single_remove_kobj_and_attrs(temp_index); -+ } -+ kfree(g_sensor.temp); -+ g_sensor.temp = NULL; -+ } -+ return; -+} -+ -+static void sensor_in_sub_remove(void) -+{ -+ unsigned int in_index; -+ -+ if (g_sensor.in) { -+ for (in_index = g_sensor.in_number; in_index > 0; in_index--) { -+ in_sub_single_remove_kobj_and_attrs(in_index); -+ } -+ kfree(g_sensor.in); -+ g_sensor.in = NULL; -+ } -+ return; -+} -+ -+static void sensor_sub_remove(void) -+{ -+ sensor_temp_sub_remove(); -+ sensor_in_sub_remove(); -+} -+ -+static int sensor_sub_create(void) -+{ -+ int ret; -+ /* temp creat */ -+ ret = sensor_temp_sub_create(); -+ if (ret < 0) { -+ goto temp_err; -+ } -+ /* Voltage creat */ -+ ret = sensor_in_sub_create(); -+ if (ret < 0) { -+ goto in_err; -+ } -+ return 0; -+in_err: -+ sensor_temp_sub_remove(); -+temp_err: -+ return ret; -+} -+static void sensor_root_remove(void) -+{ -+ if (g_sensor_obj) { -+ sysfs_remove_group(&g_sensor_obj->kobj, &sensor_root_attr_group); -+ wb_plat_kobject_delete(&g_sensor_obj); -+ SENSOR_DBG("delete sensor root success\n"); -+ } -+ -+ return; -+} -+ -+static int sensor_root_create(void) -+{ -+ g_sensor_obj = wb_plat_kobject_create("sensor", NULL); -+ if (!g_sensor_obj) { -+ SENSOR_ERR("wb_plat_kobject_create sensor error!\n"); -+ return -ENOMEM; -+ } -+ -+ if (sysfs_create_group(&g_sensor_obj->kobj, &sensor_root_attr_group) != 0) { -+ wb_plat_kobject_delete(&g_sensor_obj); -+ SENSOR_ERR("create sensor dir attrs error!\n"); -+ return -EBADRQC; -+ } -+ SENSOR_DBG("wb_plat_kobject_create sensor directory and attribute success.\n"); -+ return 0; -+} -+ -+static int wb_sensor_init(void) -+{ -+ int ret; -+ -+ SENSOR_INFO("wb_sensor_init...\n"); -+ g_drv = dfd_plat_driver_get(); -+ check_p(g_drv); -+ -+ ret = sensor_root_create(); -+ if (ret < 0) { -+ goto sensor_root_error; -+ } -+ -+ ret = sensor_sub_create(); -+ if (ret < 0) { -+ goto sensor_sub_error; -+ } -+ SENSOR_INFO("sensor_init ok.\n"); -+ return 0; -+sensor_sub_error: -+ sensor_root_remove(); -+sensor_root_error: -+ return ret; -+} -+ -+static void wb_sensor_exit(void) -+{ -+ sensor_sub_remove(); -+ sensor_root_remove(); -+ SENSOR_INFO("sensor_exit ok.\n"); -+ return; -+} -+ -+module_init(wb_sensor_init); -+module_exit(wb_sensor_exit); -+module_param(g_loglevel, int, 0644); -+MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("sensors sysfs driver"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sff.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sff.c -new file mode 100644 -index 000000000..50c0f78ae ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sff.c -@@ -0,0 +1,287 @@ -+/* -+ * plat_sff.c -+ * -+ * This module create sff kobjects and attributes in /sys/wb_plat/sff -+ * -+ */ -+ -+#include -+ -+#include "./include/plat_switch.h" -+#include "./include/sysfs_common.h" -+ -+#define SFF_INFO(fmt, args...) LOG_INFO("sff: ", fmt, ##args) -+#define SFF_ERR(fmt, args...) LOG_ERR("sff: ", fmt, ##args) -+#define SFF_DBG(fmt, args...) LOG_DBG("sff: ", fmt, ##args) -+ -+struct sff_obj_t{ -+ struct switch_obj *sff_obj; -+ struct bin_attribute bin; -+ int sff_creat_bin_flag; -+}; -+ -+struct sff_t{ -+ unsigned int sff_number; -+ struct sff_obj_t *sff; -+}; -+ -+static int g_loglevel = 0; -+static struct sff_t g_sff; -+static struct switch_obj *g_sff_obj = NULL; -+static struct switch_drivers_t *g_drv = NULL; -+ -+static ssize_t sff_cpld_info_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int sff_index; -+ int ret; -+ struct switch_device_attribute *sff_cpld_attr; -+ -+ check_p(g_drv); -+ check_p(g_drv->get_sff_cpld_info); -+ -+ sff_index = obj->index; -+ sff_cpld_attr = to_switch_device_attr(attr); -+ check_p(sff_cpld_attr); -+ SFF_DBG("sff_cpld_info_show, sff index:0x%x, sff cpld attr type:0x%x\n", sff_index, sff_cpld_attr->type); -+ ret = g_drv->get_sff_cpld_info(sff_index, sff_cpld_attr->type, buf, PAGE_SIZE); -+ if(ret < 0) { -+ SFF_ERR("sff_cpld_info_show error. sff index:0x%x, sff cpld attr type:0x%x, ret:%d\n", -+ sff_index, sff_cpld_attr->type,ret ); -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); -+ } -+ SFF_DBG("sff_cpld_info_show ok. sff index:0x%x, sff cpld attr type:0x%x, ret:%d\n", sff_index, sff_cpld_attr->type, ret); -+ return ret; -+} -+ -+static ssize_t sff_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_sff.sff_number); -+} -+ -+/************************************sff attrs*******************************************/ -+static struct switch_attribute sff_number_att = __ATTR(num_sffs, S_IRUGO, sff_number_show, NULL); -+static SWITCH_DEVICE_ATTR(present, S_IRUGO, sff_cpld_info_show, NULL, WB_SFF_MODULE_PRESENT); -+ -+/*******************************xcvr dir and attrs*******************************************/ -+static struct attribute *xcvr_dir_attrs[] = { -+ &sff_number_att.attr, -+ NULL, -+}; -+ -+static struct attribute_group sff_xcvr_attr_group = { -+ .attrs = xcvr_dir_attrs, -+}; -+ -+/*******************************sff dir and attrs*******************************************/ -+static struct attribute *sff_attrs[] = { -+ &switch_dev_attr_present.switch_attr.attr, -+ NULL, -+}; -+ -+static struct attribute_group sff_attr_group = { -+ .attrs = sff_attrs, -+}; -+ -+static int sff_sub_single_create_attrs(unsigned int index) -+{ -+ struct sff_obj_t *curr_sff; -+ -+ curr_sff = &g_sff.sff[index-1]; -+ if (sysfs_create_group(&curr_sff->sff_obj->kobj, &sff_attr_group) != 0) { -+ SFF_ERR("create sff%d dir attrs error!\n", index); -+ wb_plat_kobject_delete(&curr_sff->sff_obj); -+ return -EBADRQC; -+ } -+ SFF_DBG("create sff%d dir attrs ok!\n", index); -+ return 0; -+} -+ -+static int sff_sub_single_create_kobj(struct kobject *parent, unsigned int index) -+{ -+ struct sff_obj_t *curr_sff; -+ char sff_dir_name[DIR_NAME_MAX_LEN]; -+ int ret; -+ -+ check_p(g_drv->get_sff_dir_name); -+ ret = g_drv->get_sff_dir_name(index, sff_dir_name, sizeof(sff_dir_name)); -+ if (ret < 0) { -+ SFF_ERR("sff index:%d, get sff dir name error. please check sff config.\n", index); -+ return -ENOSYS; -+ } -+ -+ curr_sff = &g_sff.sff[index - 1]; -+ -+ curr_sff->sff_obj = wb_plat_kobject_create(sff_dir_name, parent); -+ if (!curr_sff->sff_obj) { -+ SFF_ERR("sff index:%d, create %s object error! \n", index, sff_dir_name); -+ return -EBADRQC; -+ } -+ -+ SFF_DBG("create sff kobj ok. sff index:%d, dir name:%s\n",index, sff_dir_name); -+ curr_sff->sff_obj->index = index; -+ -+ return 0; -+} -+ -+static void sff_sub_single_remove_kobj_and_attrs(unsigned int index) -+{ -+ struct sff_obj_t *curr_sff; -+ -+ curr_sff = &g_sff.sff[index - 1]; -+ /* remove sff dir and attr */ -+ if (curr_sff->sff_obj) { -+ SFF_DBG("delete sff%d attrs.\n", curr_sff->sff_obj->index); -+ curr_sff->sff_obj->index = 0; -+ sysfs_remove_group(&curr_sff->sff_obj->kobj, &sff_attr_group); -+ wb_plat_kobject_delete(&curr_sff->sff_obj); -+ } -+ -+ return; -+} -+ -+static int sff_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) -+{ -+ int ret; -+ -+ ret = sff_sub_single_create_kobj(parent, index); -+ if (ret < 0) { -+ SFF_ERR("sff index:%d, create sff dir error.\n", index); -+ return ret; -+ } -+ -+ ret = sff_sub_single_create_attrs(index); -+ if (ret < 0) { -+ SFF_ERR("sff index:%d, create sff attr error.\n", index); -+ return ret; -+ } -+ return 0; -+} -+ -+static int sff_sub_create_kobj_and_attrs(struct kobject *parent, int sff_num) -+{ -+ unsigned int sff_index, i; -+ -+ g_sff.sff = kzalloc(sizeof(struct sff_obj_t) * sff_num, GFP_KERNEL); -+ if (!g_sff.sff) { -+ SFF_ERR("kzalloc g_sff.sff error, sff number = %d.\n", sff_num); -+ return -ENOMEM; -+ } -+ -+ for (sff_index = 1; sff_index <= sff_num; sff_index++) { -+ if (sff_sub_single_create_kobj_and_attrs(parent, sff_index) != 0 ) { -+ goto error; -+ } -+ } -+ return 0; -+error: -+ for (i = sff_index - 1; i > 0; i--) { -+ sff_sub_single_remove_kobj_and_attrs(i); -+ } -+ if (g_sff.sff) { -+ kfree(g_sff.sff); -+ g_sff.sff = NULL; -+ } -+ return -EBADRQC; -+} -+ -+static int sff_sub_create(void) -+{ -+ int ret, sff_num; -+ -+ check_p(g_drv->get_dev_number); -+ sff_num = g_drv->get_dev_number(WB_MAIN_DEV_SFF, WB_MINOR_DEV_NONE); -+ g_sff.sff_number = sff_num; -+ if (sff_num <= 0) { -+ SFF_ERR("ERROR. port number:%d\n", sff_num); -+ return -EINVAL; -+ } -+ -+ ret = sff_sub_create_kobj_and_attrs(&g_sff_obj->kobj, sff_num); -+ -+ return ret; -+} -+ -+static void sff_sub_remove(void) -+{ -+ unsigned int sff_index; -+ -+ if (g_sff.sff) { -+ for (sff_index = g_sff.sff_number; sff_index > 0; sff_index--) { -+ sff_sub_single_remove_kobj_and_attrs(sff_index); -+ } -+ kfree(g_sff.sff); -+ } -+ mem_clear(&g_sff, sizeof(struct sff_t)); -+ return ; -+} -+ -+static int sff_xcvr_create(void) -+{ -+ g_sff_obj = wb_plat_kobject_create(SFF_SYSFS_NAME, NULL); -+ if (!g_sff_obj) { -+ SFF_ERR("wb_plat_kobject_create sff error!\n"); -+ return -ENOMEM; -+ } -+ -+ g_sff_obj->index = 0; -+ if (sysfs_create_group(&g_sff_obj->kobj, &sff_xcvr_attr_group) != 0) { -+ wb_plat_kobject_delete(&g_sff_obj); -+ SFF_ERR("create sff dir attrs error!\n"); -+ return -EBADRQC; -+ } -+ SFF_DBG("wb_plat_kobject_create sff directory and attribute success.\n"); -+ return 0; -+} -+ -+static void sff_xcvr_remove(void) -+{ -+ if (g_sff_obj) { -+ sysfs_remove_group(&g_sff_obj->kobj, &sff_xcvr_attr_group); -+ wb_plat_kobject_delete(&g_sff_obj); -+ SFF_DBG("delete sff root success\n"); -+ } -+ -+ return; -+} -+ -+static int wb_sff_init(void) -+{ -+ int ret; -+ -+ SFF_INFO("wb_sff_init...\n"); -+ g_drv = dfd_plat_driver_get(); -+ check_p(g_drv); -+ -+ ret = sff_xcvr_create(); -+ if (ret < 0) { -+ goto sff_root_error; -+ } -+ -+ ret = sff_sub_create(); -+ if (ret < 0) { -+ goto sff_sub_error; -+ } -+ SFF_INFO("wb_sff_init ok.\n"); -+ return 0; -+ -+sff_sub_error: -+ sff_xcvr_remove(); -+sff_root_error: -+ return ret; -+} -+ -+static void wb_sff_exit(void) -+{ -+ sff_sub_remove(); -+ sff_xcvr_remove(); -+ SFF_INFO("wb_sff_exit ok.\n"); -+ return ; -+} -+ -+module_init(wb_sff_init); -+module_exit(wb_sff_exit); -+module_param(g_loglevel, int, 0644); -+MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("sff sysfs driver"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_slot.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_slot.c -new file mode 100644 -index 000000000..7c50f283b ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_slot.c -@@ -0,0 +1,663 @@ -+/* -+ * plat_slot.c -+ * -+ * This module create sff kobjects and attributes in /sys/wb_plat/slot -+ * -+ */ -+ -+#include -+ -+#include "./include/plat_switch.h" -+#include "./include/sysfs_common.h" -+ -+#define SLOT_INFO(fmt, args...) LOG_INFO("slot: ", fmt, ##args) -+#define SLOT_ERR(fmt, args...) LOG_ERR("slot: ", fmt, ##args) -+#define SLOT_DBG(fmt, args...) LOG_DBG("slot: ", fmt, ##args) -+ -+struct slot_temp_obj_t{ -+ struct switch_obj *obj; -+}; -+ -+struct slot_in_obj_t{ -+ struct switch_obj *obj; -+}; -+ -+struct slot_obj_t{ -+ unsigned int temp_number; -+ unsigned int in_number; -+ struct slot_temp_obj_t *temp; -+ struct slot_in_obj_t *in; -+ struct switch_obj *obj; -+}; -+ -+struct slot_t{ -+ unsigned int slot_number; -+ struct slot_obj_t *slot; -+}; -+ -+static int g_loglevel = 0; -+static struct slot_t g_slot; -+static struct switch_obj *g_slot_obj = NULL; -+static struct switch_drivers_t *g_drv = NULL; -+ -+static ssize_t slot_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_slot.slot_number); -+} -+ -+static ssize_t slot_temp_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int index; -+ -+ index = obj->index; -+ SLOT_DBG("slot_temp_number_show,slot index:%d\n",index); -+ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_slot.slot[index-1].temp_number); -+} -+ -+static ssize_t slot_in_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int index; -+ -+ index = obj->index; -+ SLOT_DBG("slot_in_number_show,slot index:%d\n",index); -+ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_slot.slot[index-1].in_number); -+} -+ -+static ssize_t slot_present_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int slot_index; -+ int ret; -+ -+ slot_index = obj->index; -+ SLOT_DBG("slot_present_status_show, slot index:%d\n",slot_index); -+ check_p(g_drv); -+ check_p(g_drv->get_slot_present_status); -+ -+ ret = g_drv->get_slot_present_status(slot_index); -+ if(ret < 0) { -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); -+ } -+ -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); -+} -+ -+static ssize_t slot_voltage_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int slot_index, in_index; -+ int ret; -+ struct switch_obj *p_obj; -+ struct switch_device_attribute *in_attr; -+ -+ check_p(g_drv); -+ check_p(g_drv->get_voltage_info); -+ -+ p_obj = to_switch_obj(obj->kobj.parent); -+ check_p(p_obj); -+ -+ slot_index = p_obj->index; -+ in_index = obj->index; -+ -+ in_attr = to_switch_device_attr(attr); -+ check_p(in_attr); -+ SLOT_DBG("slot_voltage_show, slot index:0x%x, temp index:0x%x, temp type:0x%x\n",slot_index, in_index, in_attr->type); -+ ret = g_drv->get_voltage_info(WB_MAIN_DEV_SLOT, slot_index, in_index, in_attr->type, buf); -+ if(ret < 0) { -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); -+ } -+ return ret; -+} -+ -+static ssize_t slot_temp_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) -+{ -+ unsigned int slot_index, temp_index; -+ int ret; -+ struct switch_obj *p_obj; -+ struct switch_device_attribute *temp_attr; -+ -+ check_p(g_drv); -+ check_p(g_drv->get_temp_info); -+ -+ p_obj = to_switch_obj(obj->kobj.parent); -+ check_p(p_obj); -+ -+ slot_index = p_obj->index; -+ temp_index = obj->index; -+ -+ temp_attr = to_switch_device_attr(attr); -+ check_p(temp_attr); -+ SLOT_DBG("slot_temp_show, slot index:0x%x, temp index:0x%x, temp type:0x%x\n",slot_index, temp_index, temp_attr->type); -+ ret = g_drv->get_temp_info(WB_MAIN_DEV_SLOT, slot_index, temp_index, temp_attr->type, buf); -+ if(ret < 0) { -+ return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); -+ } -+ return ret; -+} -+ -+/************************************slot dir and attrs*******************************************/ -+static struct switch_attribute slot_number_att = __ATTR(num_slots, S_IRUGO, slot_number_show, NULL); -+ -+static struct attribute *slot_dir_attrs[] = { -+ &slot_number_att.attr, -+ NULL, -+}; -+ -+static struct attribute_group slot_root_attr_group = { -+ .attrs = slot_dir_attrs, -+}; -+ -+/*******************************slot1 slot2 dir and attrs*******************************************/ -+static struct switch_attribute num_temp_sensors_att = __ATTR(num_temp_sensors, S_IRUGO, slot_temp_number_show, NULL); -+static struct switch_attribute num_in_sensors_att = __ATTR(num_in_sensors, S_IRUGO, slot_in_number_show, NULL); -+static struct switch_attribute slot_present_status_att = __ATTR(present, S_IRUGO, slot_present_status_show, NULL); -+ -+static struct attribute *slot_attrs[] = { -+ &num_temp_sensors_att.attr, -+ &num_in_sensors_att.attr, -+ &slot_present_status_att.attr, -+ NULL, -+}; -+ -+static struct attribute_group slot_attr_group = { -+ .attrs = slot_attrs, -+}; -+ -+/*******************************temp dir and attrs*******************************************/ -+static SWITCH_DEVICE_ATTR(temp_alias, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_ALIAS); -+static SWITCH_DEVICE_ATTR(temp_type, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_TYPE); -+static SWITCH_DEVICE_ATTR(temp_max, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_MAX); -+static SWITCH_DEVICE_ATTR(temp_max_hyst, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_MAX_HYST); -+static SWITCH_DEVICE_ATTR(temp_min, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_MIN); -+static SWITCH_DEVICE_ATTR(temp_input, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_INPUT); -+ -+static struct attribute *temp_attrs[] = { -+ &switch_dev_attr_temp_alias.switch_attr.attr, -+ &switch_dev_attr_temp_type.switch_attr.attr, -+ &switch_dev_attr_temp_max.switch_attr.attr, -+ &switch_dev_attr_temp_max_hyst.switch_attr.attr, -+ &switch_dev_attr_temp_min.switch_attr.attr, -+ &switch_dev_attr_temp_input.switch_attr.attr, -+ NULL, -+}; -+ -+static struct attribute_group temp_attr_group = { -+ .attrs = temp_attrs, -+}; -+ -+/*******************************Voltage dir and attrs*******************************************/ -+static SWITCH_DEVICE_ATTR(in_alias, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_ALIAS); -+static SWITCH_DEVICE_ATTR(in_type, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_TYPE); -+static SWITCH_DEVICE_ATTR(in_max, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_MAX); -+static SWITCH_DEVICE_ATTR(in_crit, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_CRIT); -+static SWITCH_DEVICE_ATTR(in_min, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_MIN); -+static SWITCH_DEVICE_ATTR(in_input, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_INPUT); -+ -+static struct attribute *in_attrs[] = { -+ &switch_dev_attr_in_alias.switch_attr.attr, -+ &switch_dev_attr_in_type.switch_attr.attr, -+ &switch_dev_attr_in_max.switch_attr.attr, -+ &switch_dev_attr_in_crit.switch_attr.attr, -+ &switch_dev_attr_in_min.switch_attr.attr, -+ &switch_dev_attr_in_input.switch_attr.attr, -+ NULL, -+}; -+ -+static struct attribute_group in_attr_group = { -+ .attrs = in_attrs, -+}; -+ -+static void slotindex_single_temp_remove_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int temp_index) -+{ -+ -+ struct slot_temp_obj_t *curr_temp; /* point to temp1 temp2...*/ -+ -+ curr_temp = &curr_slot->temp[temp_index - 1]; -+ if (curr_temp->obj) { -+ sysfs_remove_group(&curr_temp->obj->kobj, &temp_attr_group); -+ wb_plat_kobject_delete(&curr_temp->obj); -+ SLOT_DBG("delete slot:%d temp%d.\n", curr_slot->obj->index, temp_index); -+ } -+ return; -+} -+ -+static int slotindex_single_temp_create_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int temp_index) -+{ -+ char name[DIR_NAME_MAX_LEN]; -+ struct slot_temp_obj_t *curr_temp; /* point to temp1 temp2...*/ -+ -+ curr_temp = &curr_slot->temp[temp_index - 1]; -+ mem_clear(name, sizeof(name)); -+ snprintf(name, sizeof(name), "%s%d", TEMP_SYSFS_NAME, temp_index); -+ -+ curr_temp->obj = wb_plat_kobject_create(name, &curr_slot->obj->kobj); -+ if (!curr_temp->obj) { -+ SLOT_ERR("create slot_index:%d, temp%d object error!\n", curr_slot->obj->index, temp_index); -+ return -EBADRQC; -+ } -+ curr_temp->obj->index = temp_index; -+ if (sysfs_create_group(&curr_temp->obj->kobj, &temp_attr_group) != 0) { -+ SLOT_ERR("create slot_index:%d, temp%d attrs error.\n", curr_slot->obj->index, temp_index); -+ wb_plat_kobject_delete(&curr_temp->obj); -+ return -EBADRQC; -+ } -+ SLOT_DBG("create slot_index:%d, temp%d ok.\n", curr_slot->obj->index, temp_index); -+ return 0; -+} -+ -+static void slotindex_temp_remove_kobj_and_attrs(struct slot_obj_t * curr_slot) -+{ -+ int temp_index; -+ -+ for(temp_index = curr_slot->temp_number; temp_index > 0; temp_index--) { -+ slotindex_single_temp_remove_kobj_and_attrs(curr_slot, temp_index); -+ } -+ -+ if(curr_slot->temp) { -+ kfree(curr_slot->temp); -+ curr_slot->temp = NULL; -+ curr_slot->temp_number = 0; -+ } -+ return; -+} -+ -+static int slotindex_temp_create_kobj_and_attrs(struct slot_obj_t * curr_slot, int temp_num) -+{ -+ int temp_index, i; -+ -+ curr_slot->temp_number = temp_num; -+ curr_slot->temp = kzalloc(sizeof(struct slot_temp_obj_t) * temp_num, GFP_KERNEL); -+ if (!curr_slot->temp) { -+ SLOT_ERR("kzalloc slot temp error, slot index = %d, temp number = %d.\n", curr_slot->obj->index, temp_num); -+ return -ENOMEM; -+ } -+ -+ for (temp_index = 1; temp_index <= temp_num; temp_index++) { -+ if (slotindex_single_temp_create_kobj_and_attrs(curr_slot, temp_index) != 0) { -+ goto error; -+ } -+ } -+ return 0; -+error: -+ for (i = temp_index - 1; i > 0; i--) { -+ slotindex_single_temp_remove_kobj_and_attrs(curr_slot, i); -+ } -+ -+ if (curr_slot->temp) { -+ kfree(curr_slot->temp); -+ curr_slot->temp = NULL; -+ curr_slot->temp_number = 0; -+ } -+ return -EBADRQC; -+} -+ -+static void slotindex_single_in_remove_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int in_index) -+{ -+ -+ struct slot_in_obj_t *curr_in; /* point to in1 in2...*/ -+ -+ curr_in = &curr_slot->in[in_index - 1]; -+ if (curr_in->obj) { -+ sysfs_remove_group(&curr_in->obj->kobj, &in_attr_group); -+ wb_plat_kobject_delete(&curr_in->obj); -+ SLOT_DBG("delete slot:%d in%d.\n", curr_slot->obj->index, in_index); -+ } -+ return; -+} -+ -+static int slotindex_single_in_create_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int in_index) -+{ -+ char name[DIR_NAME_MAX_LEN]; -+ struct slot_in_obj_t *curr_in; /* point to in1 in2...*/ -+ -+ curr_in = &curr_slot->in[in_index - 1]; -+ mem_clear(name, sizeof(name)); -+ snprintf(name, sizeof(name), "%s%d", VOLTAGE_SYSFS_NAME, in_index); -+ curr_in->obj = wb_plat_kobject_create(name, &curr_slot->obj->kobj); -+ if (!curr_in->obj) { -+ SLOT_ERR("create slot_index:%d, in%d object error!\n", curr_slot->obj->index, in_index); -+ return -EBADRQC; -+ } -+ curr_in->obj->index = in_index; -+ if (sysfs_create_group(&curr_in->obj->kobj, &in_attr_group) != 0) { -+ SLOT_ERR("create slot_index:%d, in%d attrs error.\n", curr_slot->obj->index, in_index); -+ wb_plat_kobject_delete(&curr_in->obj); -+ return -EBADRQC; -+ } -+ SLOT_DBG("create slot_index:%d, in%d ok.\n", curr_slot->obj->index, in_index); -+ return 0; -+} -+ -+static void slotindex_in_remove_kobj_and_attrs(struct slot_obj_t * curr_slot) -+{ -+ int in_index; -+ -+ for(in_index = curr_slot->in_number; in_index > 0; in_index--) { -+ slotindex_single_in_remove_kobj_and_attrs(curr_slot, in_index); -+ } -+ -+ if(curr_slot->in) { -+ kfree(curr_slot->in); -+ curr_slot->in = NULL; -+ curr_slot->in_number = 0; -+ } -+ return; -+} -+ -+static int slotindex_in_create_kobj_and_attrs(struct slot_obj_t * curr_slot, int in_num) -+{ -+ int in_index, i; -+ -+ curr_slot->in_number = in_num; -+ curr_slot->in = kzalloc(sizeof(struct slot_in_obj_t) * in_num, GFP_KERNEL); -+ if (!curr_slot->in) { -+ SLOT_ERR("kzalloc slot Voltage error, slot index = %d, Voltage number = %d.\n", curr_slot->obj->index, in_num); -+ return -ENOMEM; -+ } -+ -+ for (in_index = 1; in_index <= in_num; in_index++) { -+ if (slotindex_single_in_create_kobj_and_attrs(curr_slot, in_index) != 0 ) { -+ goto error; -+ } -+ } -+ return 0; -+error: -+ for (i = in_index - 1; i > 0; i++) { -+ slotindex_single_in_remove_kobj_and_attrs(curr_slot, i); -+ } -+ -+ if (curr_slot->in) { -+ kfree(curr_slot->in); -+ curr_slot->in = NULL; -+ curr_slot->in_number = 0; -+ } -+ return -EBADRQC; -+} -+ -+static void slotindex_obj_remove_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int obj_id) -+{ -+ switch (obj_id) { -+ case WB_MINOR_DEV_TEMP: -+ slotindex_temp_remove_kobj_and_attrs(curr_slot); -+ break; -+ case WB_MINOR_DEV_IN: -+ slotindex_in_remove_kobj_and_attrs(curr_slot); -+ break; -+ default: -+ SLOT_ERR("Unknow obj id:%d\n", obj_id); -+ } -+ return ; -+} -+ -+static int slotindex_obj_create_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int obj_id, int obj_num) -+{ -+ int ret; -+ -+ switch (obj_id) { -+ case WB_MINOR_DEV_TEMP: -+ ret = slotindex_temp_create_kobj_and_attrs(curr_slot, obj_num); -+ break; -+ case WB_MINOR_DEV_IN: -+ ret = slotindex_in_create_kobj_and_attrs(curr_slot, obj_num); -+ break; -+ default: -+ SLOT_ERR("Unknow obj id:%d\n", obj_id); -+ ret = -EINVAL; -+ } -+ return ret; -+} -+ -+static void slot_child_obj_remove_by_id(unsigned int obj_id) -+{ -+ int slot_num; -+ unsigned int slot_index; -+ struct slot_obj_t *curr_slot; /* point to slot1 slot2...*/ -+ -+ slot_num = g_slot.slot_number; -+ if (slot_num <= 0 || !g_slot.slot) { -+ SLOT_DBG("Warning:slot number = %d\n", slot_num); -+ return; -+ } -+ -+ for(slot_index = slot_num; slot_index > 0; slot_index--) { -+ curr_slot = &g_slot.slot[slot_index - 1]; -+ slotindex_obj_remove_kobj_and_attrs(curr_slot, obj_id); -+ } -+ return; -+} -+ -+static int slot_child_obj_create_by_id(unsigned int obj_id) -+{ -+ int slot_num, obj_num; -+ unsigned int slot_index, i; -+ struct slot_obj_t *curr_slot; /* point to slot1 slot2...*/ -+ -+ check_p(g_drv->get_dev_number); -+ obj_num = g_drv->get_dev_number(WB_MAIN_DEV_SLOT,obj_id); -+ slot_num = g_slot.slot_number; -+ if (obj_num <= 0 || slot_num <= 0 || !g_slot.slot) { -+ SLOT_DBG("Warning:slot number = %d, object number:%d.obj_id:%d\n", slot_num, obj_num, obj_id); -+ return 0; -+ } -+ -+ for (slot_index = 1; slot_index <= slot_num; slot_index++) { -+ curr_slot = &g_slot.slot[slot_index - 1]; -+ if (slotindex_obj_create_kobj_and_attrs(curr_slot, obj_id, obj_num) != 0) { -+ goto error; -+ } -+ } -+ return 0; -+error: -+ for(i = slot_index - 1; i > 0; i++) { -+ curr_slot = &g_slot.slot[i - 1]; -+ slotindex_obj_remove_kobj_and_attrs(curr_slot, obj_id); -+ } -+ return -EBADRQC; -+} -+ -+static void slot_child_obj_remove(void) -+{ -+ /* temp remove */ -+ slot_child_obj_remove_by_id(WB_MINOR_DEV_TEMP); -+ -+ /* in creat */ -+ slot_child_obj_remove_by_id(WB_MINOR_DEV_IN); -+ return; -+} -+ -+static int slot_child_obj_create(void) -+{ -+ int ret; -+ -+ /* temp creat */ -+ ret = slot_child_obj_create_by_id(WB_MINOR_DEV_TEMP); -+ if (ret < 0) { -+ goto temp_err; -+ } -+ /* Voltage creat */ -+ ret = slot_child_obj_create_by_id(WB_MINOR_DEV_IN); -+ if(ret < 0) { -+ goto in_err; -+ } -+ return 0; -+in_err: -+ slot_child_obj_remove_by_id(WB_MINOR_DEV_TEMP); -+temp_err: -+ return ret; -+} -+ -+static void slot_sub_single_remove_kobj_and_attrs(unsigned int index) -+{ -+ struct slot_obj_t *curr_slot; -+ -+ curr_slot = &g_slot.slot[index - 1]; -+ if (curr_slot->obj) { -+ sysfs_remove_group(&curr_slot->obj->kobj, &slot_attr_group); -+ wb_plat_kobject_delete(&curr_slot->obj); -+ SLOT_DBG("delete slot%d.\n", index); -+ } -+ return; -+} -+ -+static int slot_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) -+{ -+ char name[DIR_NAME_MAX_LEN]; -+ struct slot_obj_t *curr_slot; -+ -+ curr_slot = &g_slot.slot[index - 1]; -+ SLOT_DBG("create %s%d ...\n", SLOT_SYSFS_NAME, index); -+ mem_clear(name, sizeof(name)); -+ snprintf(name, sizeof(name), "%s%d", SLOT_SYSFS_NAME, index); -+ curr_slot->obj = wb_plat_kobject_create(name, parent); -+ if (!curr_slot->obj) { -+ SLOT_ERR("create slot%d object error!\n", index); -+ return -EBADRQC; -+ } -+ curr_slot->obj->index = index; -+ if (sysfs_create_group(&curr_slot->obj->kobj, &slot_attr_group) != 0) { -+ SLOT_ERR("create slot%d attrs error.\n", index); -+ wb_plat_kobject_delete(&curr_slot->obj); -+ return -EBADRQC; -+ } -+ SLOT_DBG("create slot%d ok.\n", index); -+ return 0; -+} -+ -+static int slot_sub_create_kobj_and_attrs(struct kobject *parent, int slot_num) -+{ -+ unsigned int slot_index, i; -+ -+ g_slot.slot = kzalloc(sizeof(struct slot_obj_t) * slot_num, GFP_KERNEL); -+ if (!g_slot.slot) { -+ SLOT_ERR("kzalloc slot.slot error, slot number = %d.\n", slot_num); -+ return -ENOMEM; -+ } -+ -+ for (slot_index = 1; slot_index <= slot_num; slot_index++) { -+ if (slot_sub_single_create_kobj_and_attrs(parent, slot_index) != 0) { -+ goto error; -+ } -+ } -+ return 0; -+error: -+ for (i = slot_index - 1; i > 0; i--) { -+ slot_sub_single_remove_kobj_and_attrs(i); -+ } -+ if (g_slot.slot) { -+ kfree(g_slot.slot); -+ g_slot.slot = NULL; -+ } -+ return -EBADRQC; -+} -+ -+/* create slot1 slot2...dir and attrs */ -+static int slot_sub_create(void) -+{ -+ int ret, slot_num; -+ -+ check_p(g_drv->get_dev_number); -+ slot_num = g_drv->get_dev_number(WB_MAIN_DEV_SLOT, WB_MINOR_DEV_NONE); -+ g_slot.slot_number = slot_num; -+ if (slot_num <= 0) { -+ SLOT_DBG("Warning:slot number = %d \n", slot_num); -+ return 0; -+ } -+ ret = slot_sub_create_kobj_and_attrs(&g_slot_obj->kobj, slot_num); -+ return ret; -+} -+ -+/** -+ * slot_sub_remove - delete slot1 slot2...dir and attrs -+ */ -+static void slot_sub_remove(void) -+{ -+ unsigned int slot_index; -+ -+ if (g_slot.slot) { -+ for (slot_index = g_slot.slot_number; slot_index > 0; slot_index--) { -+ slot_sub_single_remove_kobj_and_attrs(slot_index); -+ } -+ kfree(g_slot.slot); -+ } -+ mem_clear(&g_slot, sizeof(struct slot_t)); -+ return ; -+} -+ -+/* create slot dir and num_slots attr */ -+static int slot_root_create(void) -+{ -+ g_slot_obj = wb_plat_kobject_create(SLOT_SYSFS_NAME, NULL); -+ if (!g_slot_obj) { -+ SLOT_ERR("wb_plat_kobject_create slot error!\n"); -+ return -ENOMEM; -+ } -+ -+ if (sysfs_create_group(&g_slot_obj->kobj, &slot_root_attr_group) != 0) { -+ wb_plat_kobject_delete(&g_slot_obj); -+ SLOT_ERR("create slot dir attrs error!\n"); -+ return -EBADRQC; -+ } -+ SLOT_DBG("wb_plat_kobject_create slot directory and attribute success.\n"); -+ return 0; -+} -+ -+static void slot_root_remove(void) -+{ -+ if (g_slot_obj) { -+ sysfs_remove_group(&g_slot_obj->kobj, &slot_root_attr_group); -+ wb_plat_kobject_delete(&g_slot_obj); -+ SLOT_DBG("delete slot root success\n"); -+ } -+ -+ return; -+} -+ -+static int wb_slot_init(void) -+{ -+ int ret; -+ -+ SLOT_INFO("wb_slot_init...\n"); -+ g_drv = dfd_plat_driver_get(); -+ check_p(g_drv); -+ -+ ret = slot_root_create(); -+ if (ret < 0) { -+ goto slot_root_error; -+ } -+ -+ ret = slot_sub_create(); -+ if (ret < 0) { -+ goto slot_sub_error; -+ } -+ -+ ret = slot_child_obj_create(); -+ if (ret < 0) { -+ goto slot_child_obj_error; -+ } -+ -+ SLOT_INFO("wb_slot_init ok.\n"); -+ return 0; -+slot_child_obj_error: -+ slot_sub_remove(); -+slot_sub_error: -+ slot_root_remove(); -+slot_root_error: -+ return ret; -+} -+ -+static void wb_slot_exit(void) -+{ -+ slot_child_obj_remove(); -+ slot_sub_remove(); -+ slot_root_remove(); -+ SLOT_INFO("wb_slot_exit ok.\n"); -+ return ; -+} -+ -+module_init(wb_slot_init); -+module_exit(wb_slot_exit); -+module_param(g_loglevel, int, 0644); -+MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("slot sysfs driver"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_switch.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_switch.c -new file mode 100644 -index 000000000..9563260f3 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_switch.c -@@ -0,0 +1,131 @@ -+/* -+ * plat_switch.c -+ * -+ * This module create a kset in sysfs called /sys/wb_plat -+ * Then other switch kobjects are created and assigned to this kset, -+ * such as "board", "cpld", "fan", "psu", "sff", ... -+ * -+ */ -+#include "./include/plat_switch.h" -+ -+#define SWITCH_INFO(fmt, args...) LOG_INFO("switch: ", fmt, ##args) -+#define SWITCH_ERR(fmt, args...) LOG_ERR("switch: ", fmt, ##args) -+#define SWITCH_DBG(fmt, args...) LOG_DBG("switch: ", fmt, ##args) -+ -+static int g_loglevel = 0; -+ -+static ssize_t switch_attr_show(struct kobject *kobj, -+ struct attribute *attr, char *buf) -+{ -+ struct switch_attribute *attribute; -+ struct switch_obj *device; -+ -+ attribute = to_switch_attr(attr); -+ device = to_switch_obj(kobj); -+ -+ if (!attribute->show) -+ return -ENOSYS; -+ -+ return attribute->show(device, attribute, buf); -+} -+ -+static ssize_t switch_attr_store(struct kobject *kobj, -+ struct attribute *attr, const char *buf, size_t len) -+{ -+ struct switch_attribute *attribute; -+ struct switch_obj *obj; -+ -+ attribute = to_switch_attr(attr); -+ obj = to_switch_obj(kobj); -+ -+ if (!attribute->store) -+ return -ENOSYS; -+ -+ return attribute->store(obj, attribute, buf, len); -+} -+ -+static const struct sysfs_ops switch_sysfs_ops = { -+ .show = switch_attr_show, -+ .store = switch_attr_store, -+}; -+ -+static void switch_obj_release(struct kobject *kobj) -+{ -+ struct switch_obj *obj; -+ -+ obj = to_switch_obj(kobj); -+ kfree(obj); -+} -+ -+static struct kobj_type switch_ktype = { -+ .sysfs_ops = &switch_sysfs_ops, -+ .release = switch_obj_release, -+ .default_attrs = NULL, -+}; -+ -+static struct kset *switch_kset; -+ -+struct switch_obj *wb_plat_kobject_create(const char *name, struct kobject *parent) -+{ -+ struct switch_obj *obj = NULL; -+ int ret = 0; -+ -+ obj = kzalloc(sizeof(*obj), GFP_KERNEL); -+ if (!obj) { -+ SWITCH_DBG("wb_plat_kobject_create %s kzalloc error", name); -+ return NULL; -+ } -+ -+ obj->kobj.kset = switch_kset; -+ -+ ret = kobject_init_and_add(&obj->kobj, &switch_ktype, parent, "%s", name); -+ if (ret) { -+ kobject_put(&obj->kobj); -+ SWITCH_DBG("kobject_init_and_add %s error", name); -+ return NULL; -+ } -+ -+ return obj; -+} -+ -+void wb_plat_kobject_delete(struct switch_obj **obj) -+{ -+ if (*obj) { -+ SWITCH_DBG("%s delete %s.\n", (*obj)->kobj.parent->name, (*obj)->kobj.name); -+ kobject_put(&((*obj)->kobj)); -+ *obj = NULL; -+ } -+} -+ -+static int __init switch_init(void) -+{ -+ SWITCH_INFO("...\n"); -+ -+ switch_kset = kset_create_and_add("wb_plat", NULL, NULL); -+ if (!switch_kset) { -+ SWITCH_ERR("create switch_kset error.\n"); -+ return -ENOMEM; -+ } -+ -+ SWITCH_INFO("ok.\n"); -+ return 0; -+} -+ -+static void __exit switch_exit(void) -+{ -+ if (switch_kset) { -+ kset_unregister(switch_kset); -+ } -+ -+ SWITCH_INFO("ok.\n"); -+} -+ -+module_init(switch_init); -+module_exit(switch_exit); -+EXPORT_SYMBOL(wb_plat_kobject_create); -+EXPORT_SYMBOL(wb_plat_kobject_delete); -+module_param(g_loglevel, int, 0644); -+MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("Switch driver"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common.h -new file mode 100644 -index 000000000..9e4a4fae0 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common.h -@@ -0,0 +1,74 @@ -+#ifndef __PLATFORM_COMMON_H__ -+#define __PLATFORM_COMMON_H__ -+ -+#include -+#include -+#include -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+ -+typedef enum { -+ DBG_START, -+ DBG_VERBOSE, -+ DBG_KEY, -+ DBG_WARN, -+ DBG_ERROR, -+ DBG_END, -+} dbg_level_t; -+ -+ typedef struct dfd_i2c_dev_s { -+ int bus; -+ int addr; -+ } dfd_i2c_dev_t; -+ -+typedef struct dfd_dev_head_info_s { -+ uint8_t ver; -+ uint8_t flag; -+ uint8_t hw_ver; -+ uint8_t type; -+ int16_t tlv_len; -+} dfd_dev_head_info_t; -+ -+typedef struct dfd_dev_tlv_info_s { -+ uint8_t type; -+ uint8_t len; -+ uint8_t data[0]; -+} dfd_dev_tlv_info_t; -+ -+typedef enum dfd_dev_info_type_e { -+ DFD_DEV_INFO_TYPE_MAC = 1, -+ DFD_DEV_INFO_TYPE_NAME = 2, -+ DFD_DEV_INFO_TYPE_SN = 3, -+ DFD_DEV_INFO_TYPE_PWR_CONS = 4, -+ DFD_DEV_INFO_TYPE_HW_INFO = 5, -+ DFD_DEV_INFO_TYPE_DEV_TYPE = 6, -+} dfd_dev_tlv_type_t; -+ -+extern int debuglevel; -+extern s32 platform_i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command); -+extern s32 platform_i2c_smbus_read_i2c_block_data(const struct i2c_client *client, -+ u8 command, u8 length, u8 *values); -+extern s32 platform_i2c_smbus_read_word_data(const struct i2c_client *client, u8 command); -+ -+#define DBG_DEBUG(fmt, arg...) do { \ -+ if ( debuglevel > DBG_START && debuglevel < DBG_ERROR) { \ -+ printk(KERN_INFO "[DEBUG]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ -+ } else if ( debuglevel >= DBG_ERROR ) { \ -+ printk(KERN_ERR "[DEBUG]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ -+ } else { } \ -+} while (0) -+ -+#define DBG_INFO(fmt, arg...) do { \ -+ if ( debuglevel > DBG_KEY) { \ -+ printk(KERN_INFO "[INFO]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ -+ } \ -+ } while (0) -+ -+#define DBG_ERROR(fmt, arg...) do { \ -+ if ( debuglevel > DBG_START) { \ -+ printk(KERN_ERR "[ERROR]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ -+ } \ -+ } while (0) -+ -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common_module.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common_module.c -new file mode 100644 -index 000000000..189a3aa05 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common_module.c -@@ -0,0 +1,210 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,152) -+#include -+#else -+#include -+#endif -+#include -+#include -+#include -+#include -+#include "platform_common.h" -+#include "dfd_tlveeprom.h" -+ -+#define PLATFORM_I2C_RETRY_TIMES 3 -+ -+#define DFD_TLVEEPROM_I2C_BUS (0) -+#define DFD_TLVEEPROM_I2C_ADDR (0x56) -+#define DFD_E2PROM_MAX_LEN (256) -+#define DFD_CARDTYPE_EXT_TLVLEN (4) -+ -+#define PLATFORM_CARDTYPE_RETRY_CNT (10) -+#define PLATFORM_CARDTYPE_RETRY_TIMES (1000) -+ -+int debuglevel = 0; -+module_param(debuglevel, int, S_IRUGO | S_IWUSR); -+ -+static int dfd_my_type = 0; -+module_param(dfd_my_type, int, S_IRUGO | S_IWUSR); -+ -+int g_common_debug_error = 0; -+module_param(g_common_debug_error, int, S_IRUGO | S_IWUSR); -+ -+int g_common_debug_verbose = 0; -+module_param(g_common_debug_verbose, int, S_IRUGO | S_IWUSR); -+ -+uint32_t dfd_my_type_i2c_bus = 0; -+module_param(dfd_my_type_i2c_bus, int, S_IRUGO | S_IWUSR); -+ -+uint32_t dfd_my_type_i2c_addr = 0; -+module_param(dfd_my_type_i2c_addr, int, S_IRUGO | S_IWUSR); -+ -+#define PLATFORM_COMMON_DEBUG_VERBOSE(fmt, args...) do { \ -+ if (g_common_debug_verbose) { \ -+ printk(KERN_ERR "[PLATFORM_COMMON][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define PLATFORM_COMMON_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_common_debug_error) { \ -+ printk(KERN_ERR "[PLATFORM_COMMON][ERROR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static int32_t dfd_i2c_read(char *dev, uint32_t addr, uint32_t offset_addr, unsigned char * -+buf, int32_t size) -+{ -+ struct file *fp; -+ struct i2c_client client; -+ int i ,j; -+ int rv; -+ s32 val_t; -+ -+ val_t = -1; -+ rv = 0; -+ fp = filp_open(dev, O_RDWR, S_IRUSR | S_IWUSR); -+ if (IS_ERR(fp)) { -+ DBG_ERROR("i2c open fail.\n"); -+ PLATFORM_COMMON_DEBUG_ERROR("i2c open fail.\n"); -+ return -1; -+ } -+ memcpy(&client, fp->private_data, sizeof(struct i2c_client)); -+ client.addr = addr; -+ for (j = 0 ;j < size ;j++){ -+ for (i = 0; i < PLATFORM_I2C_RETRY_TIMES; i++) { -+ if ((val_t = i2c_smbus_read_byte_data(&client, (offset_addr + j)))< 0) { -+ DBG_DEBUG("read try(%d)time offset_addr:%x \n", i, offset_addr); -+ continue; -+ } else { -+ * (buf + j) = val_t; -+ break; -+ } -+ } -+ if (val_t < 0) { -+ rv = -1; -+ break; -+ } -+ } -+ filp_close(fp, NULL); -+ return rv; -+} -+ -+static int dfd_tlvinfo_get_cardtype(void) -+{ -+ char i2c_path[16] = {0}; -+ int ret; -+ int cardtype; -+ u_int8_t eeprom[DFD_E2PROM_MAX_LEN]; -+ dfd_i2c_dev_t i2c_dev; -+ uint8_t buf[DFD_CARDTYPE_EXT_TLVLEN]; -+ uint8_t len; -+ dfd_tlv_type_t tlv_type; -+ -+ if (dfd_my_type_i2c_bus != 0) { -+ i2c_dev.bus = dfd_my_type_i2c_bus; -+ } else { -+ i2c_dev.bus = DFD_TLVEEPROM_I2C_BUS; -+ } -+ -+ if (dfd_my_type_i2c_addr != 0) { -+ i2c_dev.addr = dfd_my_type_i2c_addr; -+ } else { -+ i2c_dev.addr = DFD_TLVEEPROM_I2C_ADDR; -+ } -+ snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_dev.bus); -+ PLATFORM_COMMON_DEBUG_VERBOSE("Read device eeprom info:(dev:%s, addr:%02x).\n", i2c_path, i2c_dev.addr); -+ -+ ret = dfd_i2c_read(i2c_path, i2c_dev.addr, 0, eeprom, DFD_E2PROM_MAX_LEN); -+ if (ret != 0) { -+ DBG_ERROR("Read eeprom info error(dev: %s, addr: %02x).\n", i2c_path, i2c_dev.addr); -+ PLATFORM_COMMON_DEBUG_ERROR("Read eeprom info error(dev: %s, addr: %02x).\n", i2c_path, i2c_dev.addr); -+ return ret; -+ } -+ -+ tlv_type.main_type = TLV_CODE_VENDOR_EXT; -+ tlv_type.ext_type = DFD_TLVINFO_EXT_TLV_TYPE_DEV_TYPE; -+ len = sizeof(buf); -+ mem_clear(buf, len); -+ ret = dfd_tlvinfo_get_e2prom_info(eeprom, DFD_E2PROM_MAX_LEN, &tlv_type, buf, &len); -+ if (ret) { -+ DBG_ERROR("dfd_tlvinfo_get_e2prom_info failed ret %d.\n", ret); -+ return -1; -+ } -+ for (ret = 0; ret < 4; ret++) { -+ DBG_DEBUG("buf 0x%02x.\n", buf[ret]); -+ } -+ -+ cardtype = ntohl(*((uint32_t *)buf)); -+ DBG_DEBUG("cardtype 0x%x.\n", cardtype); -+ return cardtype; -+} -+ -+static int __dfd_get_my_card_type(void) -+{ -+ return dfd_tlvinfo_get_cardtype(); -+} -+ -+int dfd_get_my_card_type(void) -+{ -+ int type; -+ int cnt; -+ -+ if (dfd_my_type != 0) { -+ DBG_DEBUG("my_type = 0x%x\r\n", dfd_my_type); -+ return dfd_my_type; -+ } -+ -+ cnt = PLATFORM_CARDTYPE_RETRY_CNT; -+ while (cnt--) { -+ type = __dfd_get_my_card_type(); -+ if (type < 0) { -+ PLATFORM_COMMON_DEBUG_ERROR("__dfd_get_my_card_type fail cnt %d, ret %d.\n", cnt, type); -+ msleep(PLATFORM_CARDTYPE_RETRY_TIMES); -+ continue; -+ } -+ PLATFORM_COMMON_DEBUG_VERBOSE("success to get type 0x%x.\n", type); -+ break; -+ } -+ -+ dfd_my_type = type; -+ return dfd_my_type; -+} -+EXPORT_SYMBOL(dfd_get_my_card_type); -+ -+static int __init platform_common_init(void) -+{ -+ int ret; -+ -+ PLATFORM_COMMON_DEBUG_VERBOSE("Enter.\n"); -+ ret = dfd_get_my_card_type(); -+ if (ret <= 0) { -+ PLATFORM_COMMON_DEBUG_ERROR("dfd_get_my_card_type failed, ret %d.\n", ret); -+ printk(KERN_ERR "Warning: Device type get failed, please check the TLV-EEPROM!\n"); -+ return -1; -+ } -+ -+ PLATFORM_COMMON_DEBUG_VERBOSE("Leave success type 0x%x.\n", ret); -+ return 0; -+} -+ -+static void __exit platform_common_exit(void) -+{ -+ PLATFORM_COMMON_DEBUG_VERBOSE("Exit.\n"); -+} -+ -+module_init(platform_common_init); -+module_exit(platform_common_exit); -+ -+MODULE_DESCRIPTION("Platform Support"); -+MODULE_AUTHOR("support"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/Makefile -new file mode 100644 -index 000000000..6831a03a6 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/Makefile -@@ -0,0 +1,18 @@ -+PWD = $(shell pwd) -+ -+EXTRA_CFLAGS:= -I$(M)/include -+EXTRA_CFLAGS+= -Wall -+ -+sdhci_pci-objs := sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \ -+ sdhci-pci-dwc-mshc.o sdhci-pci-gli.o -+obj-m += sdhci_pci.o -+ -+ -+all: -+ $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules -+ @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi -+ @if [ -f $(PWD)/*.ko ]; then cp -p $(PWD)/*.ko $(module_out_put_dir);fi -+clean: -+ rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd -+ rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order -+ rm -rf $(PWD)/.tmp_versions -\ No newline at end of file -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/cqhci.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/cqhci.h -new file mode 100644 -index 000000000..89bf6adbc ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/cqhci.h -@@ -0,0 +1,242 @@ -+/* SPDX-License-Identifier: GPL-2.0-only */ -+/* Copyright (c) 2015, The Linux Foundation. All rights reserved. -+ */ -+#ifndef LINUX_MMC_CQHCI_H -+#define LINUX_MMC_CQHCI_H -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* registers */ -+/* version */ -+#define CQHCI_VER 0x00 -+#define CQHCI_VER_MAJOR(x) (((x) & GENMASK(11, 8)) >> 8) -+#define CQHCI_VER_MINOR1(x) (((x) & GENMASK(7, 4)) >> 4) -+#define CQHCI_VER_MINOR2(x) ((x) & GENMASK(3, 0)) -+ -+/* capabilities */ -+#define CQHCI_CAP 0x04 -+/* configuration */ -+#define CQHCI_CFG 0x08 -+#define CQHCI_DCMD 0x00001000 -+#define CQHCI_TASK_DESC_SZ 0x00000100 -+#define CQHCI_ENABLE 0x00000001 -+ -+/* control */ -+#define CQHCI_CTL 0x0C -+#define CQHCI_CLEAR_ALL_TASKS 0x00000100 -+#define CQHCI_HALT 0x00000001 -+ -+/* interrupt status */ -+#define CQHCI_IS 0x10 -+#define CQHCI_IS_HAC BIT(0) -+#define CQHCI_IS_TCC BIT(1) -+#define CQHCI_IS_RED BIT(2) -+#define CQHCI_IS_TCL BIT(3) -+ -+#define CQHCI_IS_MASK (CQHCI_IS_TCC | CQHCI_IS_RED) -+ -+/* interrupt status enable */ -+#define CQHCI_ISTE 0x14 -+ -+/* interrupt signal enable */ -+#define CQHCI_ISGE 0x18 -+ -+/* interrupt coalescing */ -+#define CQHCI_IC 0x1C -+#define CQHCI_IC_ENABLE BIT(31) -+#define CQHCI_IC_RESET BIT(16) -+#define CQHCI_IC_ICCTHWEN BIT(15) -+#define CQHCI_IC_ICCTH(x) (((x) & 0x1F) << 8) -+#define CQHCI_IC_ICTOVALWEN BIT(7) -+#define CQHCI_IC_ICTOVAL(x) ((x) & 0x7F) -+ -+/* task list base address */ -+#define CQHCI_TDLBA 0x20 -+ -+/* task list base address upper */ -+#define CQHCI_TDLBAU 0x24 -+ -+/* door-bell */ -+#define CQHCI_TDBR 0x28 -+ -+/* task completion notification */ -+#define CQHCI_TCN 0x2C -+ -+/* device queue status */ -+#define CQHCI_DQS 0x30 -+ -+/* device pending tasks */ -+#define CQHCI_DPT 0x34 -+ -+/* task clear */ -+#define CQHCI_TCLR 0x38 -+ -+/* send status config 1 */ -+#define CQHCI_SSC1 0x40 -+#define CQHCI_SSC1_CBC_MASK GENMASK(19, 16) -+ -+/* send status config 2 */ -+#define CQHCI_SSC2 0x44 -+ -+/* response for dcmd */ -+#define CQHCI_CRDCT 0x48 -+ -+/* response mode error mask */ -+#define CQHCI_RMEM 0x50 -+ -+/* task error info */ -+#define CQHCI_TERRI 0x54 -+ -+#define CQHCI_TERRI_C_INDEX(x) ((x) & GENMASK(5, 0)) -+#define CQHCI_TERRI_C_TASK(x) (((x) & GENMASK(12, 8)) >> 8) -+#define CQHCI_TERRI_C_VALID(x) ((x) & BIT(15)) -+#define CQHCI_TERRI_D_INDEX(x) (((x) & GENMASK(21, 16)) >> 16) -+#define CQHCI_TERRI_D_TASK(x) (((x) & GENMASK(28, 24)) >> 24) -+#define CQHCI_TERRI_D_VALID(x) ((x) & BIT(31)) -+ -+/* command response index */ -+#define CQHCI_CRI 0x58 -+ -+/* command response argument */ -+#define CQHCI_CRA 0x5C -+ -+#define CQHCI_INT_ALL 0xF -+#define CQHCI_IC_DEFAULT_ICCTH 31 -+#define CQHCI_IC_DEFAULT_ICTOVAL 1 -+ -+/* attribute fields */ -+#define CQHCI_VALID(x) (((x) & 1) << 0) -+#define CQHCI_END(x) (((x) & 1) << 1) -+#define CQHCI_INT(x) (((x) & 1) << 2) -+#define CQHCI_ACT(x) (((x) & 0x7) << 3) -+ -+/* data command task descriptor fields */ -+#define CQHCI_FORCED_PROG(x) (((x) & 1) << 6) -+#define CQHCI_CONTEXT(x) (((x) & 0xF) << 7) -+#define CQHCI_DATA_TAG(x) (((x) & 1) << 11) -+#define CQHCI_DATA_DIR(x) (((x) & 1) << 12) -+#define CQHCI_PRIORITY(x) (((x) & 1) << 13) -+#define CQHCI_QBAR(x) (((x) & 1) << 14) -+#define CQHCI_REL_WRITE(x) (((x) & 1) << 15) -+#define CQHCI_BLK_COUNT(x) (((x) & 0xFFFF) << 16) -+#define CQHCI_BLK_ADDR(x) (((x) & 0xFFFFFFFF) << 32) -+ -+/* direct command task descriptor fields */ -+#define CQHCI_CMD_INDEX(x) (((x) & 0x3F) << 16) -+#define CQHCI_CMD_TIMING(x) (((x) & 1) << 22) -+#define CQHCI_RESP_TYPE(x) (((x) & 0x3) << 23) -+ -+/* transfer descriptor fields */ -+#define CQHCI_DAT_LENGTH(x) (((x) & 0xFFFF) << 16) -+#define CQHCI_DAT_ADDR_LO(x) (((x) & 0xFFFFFFFF) << 32) -+#define CQHCI_DAT_ADDR_HI(x) (((x) & 0xFFFFFFFF) << 0) -+ -+struct cqhci_host_ops; -+struct mmc_host; -+struct mmc_request; -+struct cqhci_slot; -+ -+struct cqhci_host { -+ const struct cqhci_host_ops *ops; -+ void __iomem *mmio; -+ struct mmc_host *mmc; -+ -+ spinlock_t lock; -+ -+ /* relative card address of device */ -+ unsigned int rca; -+ -+ /* 64 bit DMA */ -+ bool dma64; -+ int num_slots; -+ int qcnt; -+ -+ u32 dcmd_slot; -+ u32 caps; -+#define CQHCI_TASK_DESC_SZ_128 0x1 -+ -+ u32 quirks; -+#define CQHCI_QUIRK_SHORT_TXFR_DESC_SZ 0x1 -+ -+ bool enabled; -+ bool halted; -+ bool init_done; -+ bool activated; -+ bool waiting_for_idle; -+ bool recovery_halt; -+ -+ size_t desc_size; -+ size_t data_size; -+ -+ u8 *desc_base; -+ -+ /* total descriptor size */ -+ u8 slot_sz; -+ -+ /* 64/128 bit depends on CQHCI_CFG */ -+ u8 task_desc_len; -+ -+ /* 64 bit on 32-bit arch, 128 bit on 64-bit */ -+ u8 link_desc_len; -+ -+ u8 *trans_desc_base; -+ /* same length as transfer descriptor */ -+ u8 trans_desc_len; -+ -+ dma_addr_t desc_dma_base; -+ dma_addr_t trans_desc_dma_base; -+ -+ struct completion halt_comp; -+ wait_queue_head_t wait_queue; -+ struct cqhci_slot *slot; -+}; -+ -+struct cqhci_host_ops { -+ void (*dumpregs)(struct mmc_host *mmc); -+ void (*write_l)(struct cqhci_host *host, u32 val, int reg); -+ u32 (*read_l)(struct cqhci_host *host, int reg); -+ void (*enable)(struct mmc_host *mmc); -+ void (*disable)(struct mmc_host *mmc, bool recovery); -+ void (*update_dcmd_desc)(struct mmc_host *mmc, struct mmc_request *mrq, -+ u64 *data); -+ void (*pre_enable)(struct mmc_host *mmc); -+ void (*post_disable)(struct mmc_host *mmc); -+}; -+ -+static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg) -+{ -+ if (unlikely(host->ops->write_l)) -+ host->ops->write_l(host, val, reg); -+ else -+ writel_relaxed(val, host->mmio + reg); -+} -+ -+static inline u32 cqhci_readl(struct cqhci_host *host, int reg) -+{ -+ if (unlikely(host->ops->read_l)) -+ return host->ops->read_l(host, reg); -+ else -+ return readl_relaxed(host->mmio + reg); -+} -+ -+struct platform_device; -+ -+irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error, -+ int data_error); -+int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc, bool dma64); -+struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev); -+int cqhci_deactivate(struct mmc_host *mmc); -+static inline int cqhci_suspend(struct mmc_host *mmc) -+{ -+ return cqhci_deactivate(mmc); -+} -+int cqhci_resume(struct mmc_host *mmc); -+ -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-arasan.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-arasan.c -new file mode 100644 -index 000000000..499f3205e ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-arasan.c -@@ -0,0 +1,331 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * sdhci-pci-arasan.c - Driver for Arasan PCI Controller with -+ * integrated phy. -+ * -+ * Copyright (C) 2017 Arasan Chip Systems Inc. -+ * -+ * Author: Atul Garg -+ */ -+ -+#include -+#include -+ -+#include "sdhci.h" -+#include "sdhci-pci.h" -+ -+/* Extra registers for Arasan SD/SDIO/MMC Host Controller with PHY */ -+#define PHY_ADDR_REG 0x300 -+#define PHY_DAT_REG 0x304 -+ -+#define PHY_WRITE BIT(8) -+#define PHY_BUSY BIT(9) -+#define DATA_MASK 0xFF -+ -+/* PHY Specific Registers */ -+#define DLL_STATUS 0x00 -+#define IPAD_CTRL1 0x01 -+#define IPAD_CTRL2 0x02 -+#define IPAD_STS 0x03 -+#define IOREN_CTRL1 0x06 -+#define IOREN_CTRL2 0x07 -+#define IOPU_CTRL1 0x08 -+#define IOPU_CTRL2 0x09 -+#define ITAP_DELAY 0x0C -+#define OTAP_DELAY 0x0D -+#define STRB_SEL 0x0E -+#define CLKBUF_SEL 0x0F -+#define MODE_CTRL 0x11 -+#define DLL_TRIM 0x12 -+#define CMD_CTRL 0x20 -+#define DATA_CTRL 0x21 -+#define STRB_CTRL 0x22 -+#define CLK_CTRL 0x23 -+#define PHY_CTRL 0x24 -+ -+#define DLL_ENBL BIT(3) -+#define RTRIM_EN BIT(1) -+#define PDB_ENBL BIT(1) -+#define RETB_ENBL BIT(6) -+#define ODEN_CMD BIT(1) -+#define ODEN_DAT 0xFF -+#define REN_STRB BIT(0) -+#define REN_CMND BIT(1) -+#define REN_DATA 0xFF -+#define PU_CMD BIT(1) -+#define PU_DAT 0xFF -+#define ITAPDLY_EN BIT(0) -+#define OTAPDLY_EN BIT(0) -+#define OD_REL_CMD BIT(1) -+#define OD_REL_DAT 0xFF -+#define DLLTRM_ICP 0x8 -+#define PDB_CMND BIT(0) -+#define PDB_DATA 0xFF -+#define PDB_STRB BIT(0) -+#define PDB_CLOCK BIT(0) -+#define CALDONE_MASK 0x10 -+#define DLL_RDY_MASK 0x10 -+#define MAX_CLK_BUF 0x7 -+ -+/* Mode Controls */ -+#define ENHSTRB_MODE BIT(0) -+#define HS400_MODE BIT(1) -+#define LEGACY_MODE BIT(2) -+#define DDR50_MODE BIT(3) -+ -+/* -+ * Controller has no specific bits for HS200/HS. -+ * Used BIT(4), BIT(5) for software programming. -+ */ -+#define HS200_MODE BIT(4) -+#define HISPD_MODE BIT(5) -+ -+#define OTAPDLY(x) (((x) << 1) | OTAPDLY_EN) -+#define ITAPDLY(x) (((x) << 1) | ITAPDLY_EN) -+#define FREQSEL(x) (((x) << 5) | DLL_ENBL) -+#define IOPAD(x, y) ((x) | ((y) << 2)) -+ -+/* Arasan private data */ -+struct arasan_host { -+ u32 chg_clk; -+}; -+ -+static int arasan_phy_addr_poll(struct sdhci_host *host, u32 offset, u32 mask) -+{ -+ ktime_t timeout = ktime_add_us(ktime_get(), 100); -+ bool failed; -+ u8 val = 0; -+ -+ while (1) { -+ failed = ktime_after(ktime_get(), timeout); -+ val = sdhci_readw(host, PHY_ADDR_REG); -+ if (!(val & mask)) -+ return 0; -+ if (failed) -+ return -EBUSY; -+ } -+} -+ -+static int arasan_phy_write(struct sdhci_host *host, u8 data, u8 offset) -+{ -+ sdhci_writew(host, data, PHY_DAT_REG); -+ sdhci_writew(host, (PHY_WRITE | offset), PHY_ADDR_REG); -+ return arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY); -+} -+ -+static int arasan_phy_read(struct sdhci_host *host, u8 offset, u8 *data) -+{ -+ int ret; -+ -+ sdhci_writew(host, 0, PHY_DAT_REG); -+ sdhci_writew(host, offset, PHY_ADDR_REG); -+ ret = arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY); -+ -+ /* Masking valid data bits */ -+ *data = sdhci_readw(host, PHY_DAT_REG) & DATA_MASK; -+ return ret; -+} -+ -+static int arasan_phy_sts_poll(struct sdhci_host *host, u32 offset, u32 mask) -+{ -+ int ret; -+ ktime_t timeout = ktime_add_us(ktime_get(), 100); -+ bool failed; -+ u8 val = 0; -+ -+ while (1) { -+ failed = ktime_after(ktime_get(), timeout); -+ ret = arasan_phy_read(host, offset, &val); -+ if (ret) -+ return -EBUSY; -+ else if (val & mask) -+ return 0; -+ if (failed) -+ return -EBUSY; -+ } -+} -+ -+/* Initialize the Arasan PHY */ -+static int arasan_phy_init(struct sdhci_host *host) -+{ -+ int ret; -+ u8 val; -+ -+ /* Program IOPADs and wait for calibration to be done */ -+ if (arasan_phy_read(host, IPAD_CTRL1, &val) || -+ arasan_phy_write(host, val | RETB_ENBL | PDB_ENBL, IPAD_CTRL1) || -+ arasan_phy_read(host, IPAD_CTRL2, &val) || -+ arasan_phy_write(host, val | RTRIM_EN, IPAD_CTRL2)) -+ return -EBUSY; -+ ret = arasan_phy_sts_poll(host, IPAD_STS, CALDONE_MASK); -+ if (ret) -+ return -EBUSY; -+ -+ /* Program CMD/Data lines */ -+ if (arasan_phy_read(host, IOREN_CTRL1, &val) || -+ arasan_phy_write(host, val | REN_CMND | REN_STRB, IOREN_CTRL1) || -+ arasan_phy_read(host, IOPU_CTRL1, &val) || -+ arasan_phy_write(host, val | PU_CMD, IOPU_CTRL1) || -+ arasan_phy_read(host, CMD_CTRL, &val) || -+ arasan_phy_write(host, val | PDB_CMND, CMD_CTRL) || -+ arasan_phy_read(host, IOREN_CTRL2, &val) || -+ arasan_phy_write(host, val | REN_DATA, IOREN_CTRL2) || -+ arasan_phy_read(host, IOPU_CTRL2, &val) || -+ arasan_phy_write(host, val | PU_DAT, IOPU_CTRL2) || -+ arasan_phy_read(host, DATA_CTRL, &val) || -+ arasan_phy_write(host, val | PDB_DATA, DATA_CTRL) || -+ arasan_phy_read(host, STRB_CTRL, &val) || -+ arasan_phy_write(host, val | PDB_STRB, STRB_CTRL) || -+ arasan_phy_read(host, CLK_CTRL, &val) || -+ arasan_phy_write(host, val | PDB_CLOCK, CLK_CTRL) || -+ arasan_phy_read(host, CLKBUF_SEL, &val) || -+ arasan_phy_write(host, val | MAX_CLK_BUF, CLKBUF_SEL) || -+ arasan_phy_write(host, LEGACY_MODE, MODE_CTRL)) -+ return -EBUSY; -+ return 0; -+} -+ -+/* Set Arasan PHY for different modes */ -+static int arasan_phy_set(struct sdhci_host *host, u8 mode, u8 otap, -+ u8 drv_type, u8 itap, u8 trim, u8 clk) -+{ -+ u8 val; -+ int ret; -+ -+ if (mode == HISPD_MODE || mode == HS200_MODE) -+ ret = arasan_phy_write(host, 0x0, MODE_CTRL); -+ else -+ ret = arasan_phy_write(host, mode, MODE_CTRL); -+ if (ret) -+ return ret; -+ if (mode == HS400_MODE || mode == HS200_MODE) { -+ ret = arasan_phy_read(host, IPAD_CTRL1, &val); -+ if (ret) -+ return ret; -+ ret = arasan_phy_write(host, IOPAD(val, drv_type), IPAD_CTRL1); -+ if (ret) -+ return ret; -+ } -+ if (mode == LEGACY_MODE) { -+ ret = arasan_phy_write(host, 0x0, OTAP_DELAY); -+ if (ret) -+ return ret; -+ ret = arasan_phy_write(host, 0x0, ITAP_DELAY); -+ } else { -+ ret = arasan_phy_write(host, OTAPDLY(otap), OTAP_DELAY); -+ if (ret) -+ return ret; -+ if (mode != HS200_MODE) -+ ret = arasan_phy_write(host, ITAPDLY(itap), ITAP_DELAY); -+ else -+ ret = arasan_phy_write(host, 0x0, ITAP_DELAY); -+ } -+ if (ret) -+ return ret; -+ if (mode != LEGACY_MODE) { -+ ret = arasan_phy_write(host, trim, DLL_TRIM); -+ if (ret) -+ return ret; -+ } -+ ret = arasan_phy_write(host, 0, DLL_STATUS); -+ if (ret) -+ return ret; -+ if (mode != LEGACY_MODE) { -+ ret = arasan_phy_write(host, FREQSEL(clk), DLL_STATUS); -+ if (ret) -+ return ret; -+ ret = arasan_phy_sts_poll(host, DLL_STATUS, DLL_RDY_MASK); -+ if (ret) -+ return -EBUSY; -+ } -+ return 0; -+} -+ -+static int arasan_select_phy_clock(struct sdhci_host *host) -+{ -+ struct sdhci_pci_slot *slot = sdhci_priv(host); -+ struct arasan_host *arasan_host = sdhci_pci_priv(slot); -+ u8 clk; -+ -+ if (arasan_host->chg_clk == host->mmc->ios.clock) -+ return 0; -+ -+ arasan_host->chg_clk = host->mmc->ios.clock; -+ if (host->mmc->ios.clock == 200000000) -+ clk = 0x0; -+ else if (host->mmc->ios.clock == 100000000) -+ clk = 0x2; -+ else if (host->mmc->ios.clock == 50000000) -+ clk = 0x1; -+ else -+ clk = 0x0; -+ -+ if (host->mmc_host_ops.hs400_enhanced_strobe) { -+ arasan_phy_set(host, ENHSTRB_MODE, 1, 0x0, 0x0, -+ DLLTRM_ICP, clk); -+ } else { -+ switch (host->mmc->ios.timing) { -+ case MMC_TIMING_LEGACY: -+ arasan_phy_set(host, LEGACY_MODE, 0x0, 0x0, 0x0, -+ 0x0, 0x0); -+ break; -+ case MMC_TIMING_MMC_HS: -+ case MMC_TIMING_SD_HS: -+ arasan_phy_set(host, HISPD_MODE, 0x3, 0x0, 0x2, -+ DLLTRM_ICP, clk); -+ break; -+ case MMC_TIMING_MMC_HS200: -+ case MMC_TIMING_UHS_SDR104: -+ arasan_phy_set(host, HS200_MODE, 0x2, -+ host->mmc->ios.drv_type, 0x0, -+ DLLTRM_ICP, clk); -+ break; -+ case MMC_TIMING_MMC_DDR52: -+ case MMC_TIMING_UHS_DDR50: -+ arasan_phy_set(host, DDR50_MODE, 0x1, 0x0, -+ 0x0, DLLTRM_ICP, clk); -+ break; -+ case MMC_TIMING_MMC_HS400: -+ arasan_phy_set(host, HS400_MODE, 0x1, -+ host->mmc->ios.drv_type, 0xa, -+ DLLTRM_ICP, clk); -+ break; -+ default: -+ break; -+ } -+ } -+ return 0; -+} -+ -+static int arasan_pci_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ int err; -+ -+ slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | MMC_CAP_8_BIT_DATA; -+ err = arasan_phy_init(slot->host); -+ if (err) -+ return -ENODEV; -+ return 0; -+} -+ -+static void arasan_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) -+{ -+ sdhci_set_clock(host, clock); -+ -+ /* Change phy settings for the new clock */ -+ arasan_select_phy_clock(host); -+} -+ -+static const struct sdhci_ops arasan_sdhci_pci_ops = { -+ .set_clock = arasan_sdhci_set_clock, -+ .enable_dma = sdhci_pci_enable_dma, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, -+}; -+ -+const struct sdhci_pci_fixes sdhci_arasan = { -+ .probe_slot = arasan_pci_probe_slot, -+ .ops = &arasan_sdhci_pci_ops, -+ .priv_size = sizeof(struct arasan_host), -+}; -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-core.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-core.c -new file mode 100644 -index 000000000..5fe00b537 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-core.c -@@ -0,0 +1,2566 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* linux/drivers/mmc/host/sdhci-pci.c - SDHCI on PCI bus interface -+ * -+ * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. -+ * -+ * Thanks to the following companies for their support: -+ * -+ * - JMicron (hardware and technical support) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_X86 -+#include -+#endif -+ -+#include "cqhci.h" -+ -+#include "sdhci.h" -+#include "sdhci-pci.h" -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+ -+static int wb_sdhci_pci = 0; -+module_param(wb_sdhci_pci, int, S_IRUGO); -+ -+static void sdhci_pci_hw_reset(struct sdhci_host *host); -+ -+#ifdef CONFIG_PM_SLEEP -+static int sdhci_pci_init_wakeup(struct sdhci_pci_chip *chip) -+{ -+ mmc_pm_flag_t pm_flags = 0; -+ bool cap_cd_wake = false; -+ int i; -+ -+ for (i = 0; i < chip->num_slots; i++) { -+ struct sdhci_pci_slot *slot = chip->slots[i]; -+ -+ if (slot) { -+ pm_flags |= slot->host->mmc->pm_flags; -+ if (slot->host->mmc->caps & MMC_CAP_CD_WAKE) -+ cap_cd_wake = true; -+ } -+ } -+ -+ if ((pm_flags & MMC_PM_KEEP_POWER) && (pm_flags & MMC_PM_WAKE_SDIO_IRQ)) -+ return device_wakeup_enable(&chip->pdev->dev); -+ else if (!cap_cd_wake) -+ return device_wakeup_disable(&chip->pdev->dev); -+ -+ return 0; -+} -+ -+static int sdhci_pci_suspend_host(struct sdhci_pci_chip *chip) -+{ -+ int i, ret; -+ -+ sdhci_pci_init_wakeup(chip); -+ -+ for (i = 0; i < chip->num_slots; i++) { -+ struct sdhci_pci_slot *slot = chip->slots[i]; -+ struct sdhci_host *host; -+ -+ if (!slot) -+ continue; -+ -+ host = slot->host; -+ -+ if (chip->pm_retune && host->tuning_mode != SDHCI_TUNING_MODE_3) -+ mmc_retune_needed(host->mmc); -+ -+ ret = sdhci_suspend_host(host); -+ if (ret) -+ goto err_pci_suspend; -+ -+ if (device_may_wakeup(&chip->pdev->dev)) -+ mmc_gpio_set_cd_wake(host->mmc, true); -+ } -+ -+ return 0; -+ -+err_pci_suspend: -+ while (--i >= 0) -+ sdhci_resume_host(chip->slots[i]->host); -+ return ret; -+} -+ -+int sdhci_pci_resume_host(struct sdhci_pci_chip *chip) -+{ -+ struct sdhci_pci_slot *slot; -+ int i, ret; -+ -+ for (i = 0; i < chip->num_slots; i++) { -+ slot = chip->slots[i]; -+ if (!slot) -+ continue; -+ -+ ret = sdhci_resume_host(slot->host); -+ if (ret) -+ return ret; -+ -+ mmc_gpio_set_cd_wake(slot->host->mmc, false); -+ } -+ -+ return 0; -+} -+ -+static int sdhci_cqhci_suspend(struct sdhci_pci_chip *chip) -+{ -+ int ret; -+ -+ ret = cqhci_suspend(chip->slots[0]->host->mmc); -+ if (ret) -+ return ret; -+ -+ return sdhci_pci_suspend_host(chip); -+} -+ -+static int sdhci_cqhci_resume(struct sdhci_pci_chip *chip) -+{ -+ int ret; -+ -+ ret = sdhci_pci_resume_host(chip); -+ if (ret) -+ return ret; -+ -+ return cqhci_resume(chip->slots[0]->host->mmc); -+} -+#endif -+ -+#ifdef CONFIG_PM -+static int sdhci_pci_runtime_suspend_host(struct sdhci_pci_chip *chip) -+{ -+ struct sdhci_pci_slot *slot; -+ struct sdhci_host *host; -+ int i, ret; -+ -+ for (i = 0; i < chip->num_slots; i++) { -+ slot = chip->slots[i]; -+ if (!slot) -+ continue; -+ -+ host = slot->host; -+ -+ ret = sdhci_runtime_suspend_host(host); -+ if (ret) -+ goto err_pci_runtime_suspend; -+ -+ if (chip->rpm_retune && -+ host->tuning_mode != SDHCI_TUNING_MODE_3) -+ mmc_retune_needed(host->mmc); -+ } -+ -+ return 0; -+ -+err_pci_runtime_suspend: -+ while (--i >= 0) -+ sdhci_runtime_resume_host(chip->slots[i]->host, 0); -+ return ret; -+} -+ -+static int sdhci_pci_runtime_resume_host(struct sdhci_pci_chip *chip) -+{ -+ struct sdhci_pci_slot *slot; -+ int i, ret; -+ -+ for (i = 0; i < chip->num_slots; i++) { -+ slot = chip->slots[i]; -+ if (!slot) -+ continue; -+ -+ ret = sdhci_runtime_resume_host(slot->host, 0); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int sdhci_cqhci_runtime_suspend(struct sdhci_pci_chip *chip) -+{ -+ int ret; -+ -+ ret = cqhci_suspend(chip->slots[0]->host->mmc); -+ if (ret) -+ return ret; -+ -+ return sdhci_pci_runtime_suspend_host(chip); -+} -+ -+static int sdhci_cqhci_runtime_resume(struct sdhci_pci_chip *chip) -+{ -+ int ret; -+ -+ ret = sdhci_pci_runtime_resume_host(chip); -+ if (ret) -+ return ret; -+ -+ return cqhci_resume(chip->slots[0]->host->mmc); -+} -+#endif -+ -+static u32 sdhci_cqhci_irq(struct sdhci_host *host, u32 intmask) -+{ -+ int cmd_error = 0; -+ int data_error = 0; -+ -+ if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) -+ return intmask; -+ -+ cqhci_irq(host->mmc, intmask, cmd_error, data_error); -+ -+ return 0; -+} -+ -+static void sdhci_pci_dumpregs(struct mmc_host *mmc) -+{ -+ sdhci_dumpregs(mmc_priv(mmc)); -+} -+ -+static void sdhci_cqhci_reset(struct sdhci_host *host, u8 mask) -+{ -+ if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) && -+ host->mmc->cqe_private) -+ cqhci_deactivate(host->mmc); -+ sdhci_reset(host, mask); -+} -+ -+/*****************************************************************************\ -+ * * -+ * Hardware specific quirk handling * -+ * * -+\*****************************************************************************/ -+ -+static int ricoh_probe(struct sdhci_pci_chip *chip) -+{ -+ if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG || -+ chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SONY) -+ chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET; -+ return 0; -+} -+ -+static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ slot->host->caps = -+ FIELD_PREP(SDHCI_TIMEOUT_CLK_MASK, 0x21) | -+ FIELD_PREP(SDHCI_CLOCK_BASE_MASK, 0x21) | -+ SDHCI_TIMEOUT_CLK_UNIT | -+ SDHCI_CAN_VDD_330 | -+ SDHCI_CAN_DO_HISPD | -+ SDHCI_CAN_DO_SDMA; -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int ricoh_mmc_resume(struct sdhci_pci_chip *chip) -+{ -+ /* Apply a delay to allow controller to settle */ -+ /* Otherwise it becomes confused if card state changed -+ during suspend */ -+ msleep(500); -+ return sdhci_pci_resume_host(chip); -+} -+#endif -+ -+static const struct sdhci_pci_fixes sdhci_ricoh = { -+ .probe = ricoh_probe, -+ .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | -+ SDHCI_QUIRK_FORCE_DMA | -+ SDHCI_QUIRK_CLOCK_BEFORE_RESET, -+}; -+ -+static const struct sdhci_pci_fixes sdhci_ricoh_mmc = { -+ .probe_slot = ricoh_mmc_probe_slot, -+#ifdef CONFIG_PM_SLEEP -+ .resume = ricoh_mmc_resume, -+#endif -+ .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | -+ SDHCI_QUIRK_CLOCK_BEFORE_RESET | -+ SDHCI_QUIRK_NO_CARD_NO_RESET | -+ SDHCI_QUIRK_MISSING_CAPS -+}; -+ -+static const struct sdhci_pci_fixes sdhci_ene_712 = { -+ .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE | -+ SDHCI_QUIRK_BROKEN_DMA, -+}; -+ -+static const struct sdhci_pci_fixes sdhci_ene_714 = { -+ .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE | -+ SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS | -+ SDHCI_QUIRK_BROKEN_DMA, -+}; -+ -+static const struct sdhci_pci_fixes sdhci_cafe = { -+ .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | -+ SDHCI_QUIRK_NO_BUSY_IRQ | -+ SDHCI_QUIRK_BROKEN_CARD_DETECTION | -+ SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, -+}; -+ -+static const struct sdhci_pci_fixes sdhci_intel_qrk = { -+ .quirks = SDHCI_QUIRK_NO_HISPD_BIT, -+}; -+ -+static int mrst_hc_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; -+ return 0; -+} -+ -+/* -+ * ADMA operation is disabled for Moorestown platform due to -+ * hardware bugs. -+ */ -+static int mrst_hc_probe(struct sdhci_pci_chip *chip) -+{ -+ /* -+ * slots number is fixed here for MRST as SDIO3/5 are never used and -+ * have hardware bugs. -+ */ -+ chip->num_slots = 1; -+ return 0; -+} -+ -+static int pch_hc_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+ -+static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id) -+{ -+ struct sdhci_pci_slot *slot = dev_id; -+ struct sdhci_host *host = slot->host; -+ -+ mmc_detect_change(host->mmc, msecs_to_jiffies(200)); -+ return IRQ_HANDLED; -+} -+ -+static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) -+{ -+ int err, irq, gpio = slot->cd_gpio; -+ -+ slot->cd_gpio = -EINVAL; -+ slot->cd_irq = -EINVAL; -+ -+ if (!gpio_is_valid(gpio)) -+ return; -+ -+ err = devm_gpio_request(&slot->chip->pdev->dev, gpio, "sd_cd"); -+ if (err < 0) -+ goto out; -+ -+ err = gpio_direction_input(gpio); -+ if (err < 0) -+ goto out_free; -+ -+ irq = gpio_to_irq(gpio); -+ if (irq < 0) -+ goto out_free; -+ -+ err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING | -+ IRQF_TRIGGER_FALLING, "sd_cd", slot); -+ if (err) -+ goto out_free; -+ -+ slot->cd_gpio = gpio; -+ slot->cd_irq = irq; -+ -+ return; -+ -+out_free: -+ devm_gpio_free(&slot->chip->pdev->dev, gpio); -+out: -+ dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n"); -+} -+ -+static void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) -+{ -+ if (slot->cd_irq >= 0) -+ free_irq(slot->cd_irq, slot); -+} -+ -+#else -+ -+static inline void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) -+{ -+} -+ -+static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) -+{ -+} -+ -+#endif -+ -+static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE; -+ slot->host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC; -+ return 0; -+} -+ -+static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE; -+ return 0; -+} -+ -+static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = { -+ .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, -+ .probe_slot = mrst_hc_probe_slot, -+}; -+ -+static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = { -+ .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, -+ .probe = mrst_hc_probe, -+}; -+ -+static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { -+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, -+ .allow_runtime_pm = true, -+ .own_cd_for_runtime_pm = true, -+}; -+ -+static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { -+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, -+ .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, -+ .allow_runtime_pm = true, -+ .probe_slot = mfd_sdio_probe_slot, -+}; -+ -+static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = { -+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, -+ .allow_runtime_pm = true, -+ .probe_slot = mfd_emmc_probe_slot, -+}; -+ -+static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = { -+ .quirks = SDHCI_QUIRK_BROKEN_ADMA, -+ .probe_slot = pch_hc_probe_slot, -+}; -+ -+#ifdef CONFIG_X86 -+ -+#define BYT_IOSF_SCCEP 0x63 -+#define BYT_IOSF_OCP_NETCTRL0 0x1078 -+#define BYT_IOSF_OCP_TIMEOUT_BASE GENMASK(10, 8) -+ -+static void byt_ocp_setting(struct pci_dev *pdev) -+{ -+ u32 val = 0; -+ -+ if (pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC && -+ pdev->device != PCI_DEVICE_ID_INTEL_BYT_SDIO && -+ pdev->device != PCI_DEVICE_ID_INTEL_BYT_SD && -+ pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC2) -+ return; -+ -+ if (iosf_mbi_read(BYT_IOSF_SCCEP, MBI_CR_READ, BYT_IOSF_OCP_NETCTRL0, -+ &val)) { -+ dev_err(&pdev->dev, "%s read error\n", __func__); -+ return; -+ } -+ -+ if (!(val & BYT_IOSF_OCP_TIMEOUT_BASE)) -+ return; -+ -+ val &= ~BYT_IOSF_OCP_TIMEOUT_BASE; -+ -+ if (iosf_mbi_write(BYT_IOSF_SCCEP, MBI_CR_WRITE, BYT_IOSF_OCP_NETCTRL0, -+ val)) { -+ dev_err(&pdev->dev, "%s write error\n", __func__); -+ return; -+ } -+ -+ dev_dbg(&pdev->dev, "%s completed\n", __func__); -+} -+ -+#else -+ -+static inline void byt_ocp_setting(struct pci_dev *pdev) -+{ -+} -+ -+#endif -+ -+enum { -+ INTEL_DSM_FNS = 0, -+ INTEL_DSM_V18_SWITCH = 3, -+ INTEL_DSM_V33_SWITCH = 4, -+ INTEL_DSM_DRV_STRENGTH = 9, -+ INTEL_DSM_D3_RETUNE = 10, -+}; -+ -+struct intel_host { -+ u32 dsm_fns; -+ int drv_strength; -+ bool d3_retune; -+ bool rpm_retune_ok; -+ bool needs_pwr_off; -+ u32 glk_rx_ctrl1; -+ u32 glk_tun_val; -+ u32 active_ltr; -+ u32 idle_ltr; -+}; -+ -+static const guid_t intel_dsm_guid = -+ GUID_INIT(0xF6C13EA5, 0x65CD, 0x461F, -+ 0xAB, 0x7A, 0x29, 0xF7, 0xE8, 0xD5, 0xBD, 0x61); -+ -+static int __intel_dsm(struct intel_host *intel_host, struct device *dev, -+ unsigned int fn, u32 *result) -+{ -+ union acpi_object *obj; -+ int err = 0; -+ size_t len; -+ -+ obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &intel_dsm_guid, 0, fn, NULL); -+ if (!obj) -+ return -EOPNOTSUPP; -+ -+ if (obj->type != ACPI_TYPE_BUFFER || obj->buffer.length < 1) { -+ err = -EINVAL; -+ goto out; -+ } -+ -+ len = min_t(size_t, obj->buffer.length, 4); -+ -+ *result = 0; -+ memcpy(result, obj->buffer.pointer, len); -+out: -+ ACPI_FREE(obj); -+ -+ return err; -+} -+ -+static int intel_dsm(struct intel_host *intel_host, struct device *dev, -+ unsigned int fn, u32 *result) -+{ -+ if (fn > 31 || !(intel_host->dsm_fns & (1 << fn))) -+ return -EOPNOTSUPP; -+ -+ return __intel_dsm(intel_host, dev, fn, result); -+} -+ -+static void intel_dsm_init(struct intel_host *intel_host, struct device *dev, -+ struct mmc_host *mmc) -+{ -+ int err; -+ u32 val; -+ -+ intel_host->d3_retune = true; -+ -+ err = __intel_dsm(intel_host, dev, INTEL_DSM_FNS, &intel_host->dsm_fns); -+ if (err) { -+ pr_debug("%s: DSM not supported, error %d\n", -+ mmc_hostname(mmc), err); -+ return; -+ } -+ -+ pr_debug("%s: DSM function mask %#x\n", -+ mmc_hostname(mmc), intel_host->dsm_fns); -+ -+ err = intel_dsm(intel_host, dev, INTEL_DSM_DRV_STRENGTH, &val); -+ intel_host->drv_strength = err ? 0 : val; -+ -+ err = intel_dsm(intel_host, dev, INTEL_DSM_D3_RETUNE, &val); -+ intel_host->d3_retune = err ? true : !!val; -+} -+ -+static void sdhci_pci_int_hw_reset(struct sdhci_host *host) -+{ -+ u8 reg; -+ -+ reg = sdhci_readb(host, SDHCI_POWER_CONTROL); -+ reg |= 0x10; -+ sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); -+ /* For eMMC, minimum is 1us but give it 9us for good measure */ -+ udelay(9); -+ reg &= ~0x10; -+ sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); -+ /* For eMMC, minimum is 200us but give it 300us for good measure */ -+ usleep_range(300, 1000); -+} -+ -+static int intel_select_drive_strength(struct mmc_card *card, -+ unsigned int max_dtr, int host_drv, -+ int card_drv, int *drv_type) -+{ -+ struct sdhci_host *host = mmc_priv(card->host); -+ struct sdhci_pci_slot *slot = sdhci_priv(host); -+ struct intel_host *intel_host = sdhci_pci_priv(slot); -+ -+ if (!(mmc_driver_type_mask(intel_host->drv_strength) & card_drv)) -+ return 0; -+ -+ return intel_host->drv_strength; -+} -+ -+static int bxt_get_cd(struct mmc_host *mmc) -+{ -+ int gpio_cd = mmc_gpio_get_cd(mmc); -+ struct sdhci_host *host = mmc_priv(mmc); -+ unsigned long flags; -+ int ret = 0; -+ -+ if (!gpio_cd) -+ return 0; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ -+ if (host->flags & SDHCI_DEVICE_DEAD) -+ goto out; -+ -+ ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); -+out: -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ return ret; -+} -+ -+#define SDHCI_INTEL_PWR_TIMEOUT_CNT 20 -+#define SDHCI_INTEL_PWR_TIMEOUT_UDELAY 100 -+ -+static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode, -+ unsigned short vdd) -+{ -+ struct sdhci_pci_slot *slot = sdhci_priv(host); -+ struct intel_host *intel_host = sdhci_pci_priv(slot); -+ int cntr; -+ u8 reg; -+ -+ /* -+ * Bus power may control card power, but a full reset still may not -+ * reset the power, whereas a direct write to SDHCI_POWER_CONTROL can. -+ * That might be needed to initialize correctly, if the card was left -+ * powered on previously. -+ */ -+ if (intel_host->needs_pwr_off) { -+ intel_host->needs_pwr_off = false; -+ if (mode != MMC_POWER_OFF) { -+ sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); -+ usleep_range(10000, 12500); -+ } -+ } -+ -+ sdhci_set_power(host, mode, vdd); -+ -+ if (mode == MMC_POWER_OFF) -+ return; -+ -+ /* -+ * Bus power might not enable after D3 -> D0 transition due to the -+ * present state not yet having propagated. Retry for up to 2ms. -+ */ -+ for (cntr = 0; cntr < SDHCI_INTEL_PWR_TIMEOUT_CNT; cntr++) { -+ reg = sdhci_readb(host, SDHCI_POWER_CONTROL); -+ if (reg & SDHCI_POWER_ON) -+ break; -+ udelay(SDHCI_INTEL_PWR_TIMEOUT_UDELAY); -+ reg |= SDHCI_POWER_ON; -+ sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); -+ } -+} -+ -+static void sdhci_intel_set_uhs_signaling(struct sdhci_host *host, -+ unsigned int timing) -+{ -+ /* Set UHS timing to SDR25 for High Speed mode */ -+ if (timing == MMC_TIMING_MMC_HS || timing == MMC_TIMING_SD_HS) -+ timing = MMC_TIMING_UHS_SDR25; -+ sdhci_set_uhs_signaling(host, timing); -+} -+ -+#define INTEL_HS400_ES_REG 0x78 -+#define INTEL_HS400_ES_BIT BIT(0) -+ -+static void intel_hs400_enhanced_strobe(struct mmc_host *mmc, -+ struct mmc_ios *ios) -+{ -+ struct sdhci_host *host = mmc_priv(mmc); -+ u32 val; -+ -+ val = sdhci_readl(host, INTEL_HS400_ES_REG); -+ if (ios->enhanced_strobe) -+ val |= INTEL_HS400_ES_BIT; -+ else -+ val &= ~INTEL_HS400_ES_BIT; -+ sdhci_writel(host, val, INTEL_HS400_ES_REG); -+} -+ -+static int intel_start_signal_voltage_switch(struct mmc_host *mmc, -+ struct mmc_ios *ios) -+{ -+ struct device *dev = mmc_dev(mmc); -+ struct sdhci_host *host = mmc_priv(mmc); -+ struct sdhci_pci_slot *slot = sdhci_priv(host); -+ struct intel_host *intel_host = sdhci_pci_priv(slot); -+ unsigned int fn; -+ u32 result = 0; -+ int err; -+ -+ err = sdhci_start_signal_voltage_switch(mmc, ios); -+ if (err) -+ return err; -+ -+ switch (ios->signal_voltage) { -+ case MMC_SIGNAL_VOLTAGE_330: -+ fn = INTEL_DSM_V33_SWITCH; -+ break; -+ case MMC_SIGNAL_VOLTAGE_180: -+ fn = INTEL_DSM_V18_SWITCH; -+ break; -+ default: -+ return 0; -+ } -+ -+ err = intel_dsm(intel_host, dev, fn, &result); -+ pr_debug("%s: %s DSM fn %u error %d result %u\n", -+ mmc_hostname(mmc), __func__, fn, err, result); -+ -+ return 0; -+} -+ -+static const struct sdhci_ops sdhci_intel_byt_ops = { -+ .set_clock = sdhci_set_clock, -+ .set_power = sdhci_intel_set_power, -+ .enable_dma = sdhci_pci_enable_dma, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_intel_set_uhs_signaling, -+ .hw_reset = sdhci_pci_hw_reset, -+}; -+ -+static const struct sdhci_ops sdhci_intel_glk_ops = { -+ .set_clock = sdhci_set_clock, -+ .set_power = sdhci_intel_set_power, -+ .enable_dma = sdhci_pci_enable_dma, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_cqhci_reset, -+ .set_uhs_signaling = sdhci_intel_set_uhs_signaling, -+ .hw_reset = sdhci_pci_hw_reset, -+ .irq = sdhci_cqhci_irq, -+}; -+ -+static void byt_read_dsm(struct sdhci_pci_slot *slot) -+{ -+ struct intel_host *intel_host = sdhci_pci_priv(slot); -+ struct device *dev = &slot->chip->pdev->dev; -+ struct mmc_host *mmc = slot->host->mmc; -+ -+ intel_dsm_init(intel_host, dev, mmc); -+ slot->chip->rpm_retune = intel_host->d3_retune; -+} -+ -+static int intel_execute_tuning(struct mmc_host *mmc, u32 opcode) -+{ -+ int err = sdhci_execute_tuning(mmc, opcode); -+ struct sdhci_host *host = mmc_priv(mmc); -+ -+ if (err) -+ return err; -+ -+ /* -+ * Tuning can leave the IP in an active state (Buffer Read Enable bit -+ * set) which prevents the entry to low power states (i.e. S0i3). Data -+ * reset will clear it. -+ */ -+ sdhci_reset(host, SDHCI_RESET_DATA); -+ -+ return 0; -+} -+ -+#define INTEL_ACTIVELTR 0x804 -+#define INTEL_IDLELTR 0x808 -+ -+#define INTEL_LTR_REQ BIT(15) -+#define INTEL_LTR_SCALE_MASK GENMASK(11, 10) -+#define INTEL_LTR_SCALE_1US (2 << 10) -+#define INTEL_LTR_SCALE_32US (3 << 10) -+#define INTEL_LTR_VALUE_MASK GENMASK(9, 0) -+ -+static void intel_cache_ltr(struct sdhci_pci_slot *slot) -+{ -+ struct intel_host *intel_host = sdhci_pci_priv(slot); -+ struct sdhci_host *host = slot->host; -+ -+ intel_host->active_ltr = readl(host->ioaddr + INTEL_ACTIVELTR); -+ intel_host->idle_ltr = readl(host->ioaddr + INTEL_IDLELTR); -+} -+ -+static void intel_ltr_set(struct device *dev, s32 val) -+{ -+ struct sdhci_pci_chip *chip = dev_get_drvdata(dev); -+ struct sdhci_pci_slot *slot = chip->slots[0]; -+ struct intel_host *intel_host = sdhci_pci_priv(slot); -+ struct sdhci_host *host = slot->host; -+ u32 ltr; -+ -+ pm_runtime_get_sync(dev); -+ -+ /* -+ * Program latency tolerance (LTR) accordingly what has been asked -+ * by the PM QoS layer or disable it in case we were passed -+ * negative value or PM_QOS_LATENCY_ANY. -+ */ -+ ltr = readl(host->ioaddr + INTEL_ACTIVELTR); -+ -+ if (val == PM_QOS_LATENCY_ANY || val < 0) { -+ ltr &= ~INTEL_LTR_REQ; -+ } else { -+ ltr |= INTEL_LTR_REQ; -+ ltr &= ~INTEL_LTR_SCALE_MASK; -+ ltr &= ~INTEL_LTR_VALUE_MASK; -+ -+ if (val > INTEL_LTR_VALUE_MASK) { -+ val >>= 5; -+ if (val > INTEL_LTR_VALUE_MASK) -+ val = INTEL_LTR_VALUE_MASK; -+ ltr |= INTEL_LTR_SCALE_32US | val; -+ } else { -+ ltr |= INTEL_LTR_SCALE_1US | val; -+ } -+ } -+ -+ if (ltr == intel_host->active_ltr) -+ goto out; -+ -+ writel(ltr, host->ioaddr + INTEL_ACTIVELTR); -+ writel(ltr, host->ioaddr + INTEL_IDLELTR); -+ -+ /* Cache the values into lpss structure */ -+ intel_cache_ltr(slot); -+out: -+ pm_runtime_put_autosuspend(dev); -+} -+ -+static bool intel_use_ltr(struct sdhci_pci_chip *chip) -+{ -+ switch (chip->pdev->device) { -+ case PCI_DEVICE_ID_INTEL_BYT_EMMC: -+ case PCI_DEVICE_ID_INTEL_BYT_EMMC2: -+ case PCI_DEVICE_ID_INTEL_BYT_SDIO: -+ case PCI_DEVICE_ID_INTEL_BYT_SD: -+ case PCI_DEVICE_ID_INTEL_BSW_EMMC: -+ case PCI_DEVICE_ID_INTEL_BSW_SDIO: -+ case PCI_DEVICE_ID_INTEL_BSW_SD: -+ return false; -+ default: -+ return true; -+ } -+} -+ -+static void intel_ltr_expose(struct sdhci_pci_chip *chip) -+{ -+ struct device *dev = &chip->pdev->dev; -+ -+ if (!intel_use_ltr(chip)) -+ return; -+ -+ dev->power.set_latency_tolerance = intel_ltr_set; -+ dev_pm_qos_expose_latency_tolerance(dev); -+} -+ -+static void intel_ltr_hide(struct sdhci_pci_chip *chip) -+{ -+ struct device *dev = &chip->pdev->dev; -+ -+ if (!intel_use_ltr(chip)) -+ return; -+ -+ dev_pm_qos_hide_latency_tolerance(dev); -+ dev->power.set_latency_tolerance = NULL; -+} -+ -+static void byt_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ struct mmc_host_ops *ops = &slot->host->mmc_host_ops; -+ struct device *dev = &slot->chip->pdev->dev; -+ struct mmc_host *mmc = slot->host->mmc; -+ -+ byt_read_dsm(slot); -+ -+ byt_ocp_setting(slot->chip->pdev); -+ -+ ops->execute_tuning = intel_execute_tuning; -+ ops->start_signal_voltage_switch = intel_start_signal_voltage_switch; -+ -+ device_property_read_u32(dev, "max-frequency", &mmc->f_max); -+ -+ if (!mmc->slotno) { -+ slot->chip->slots[mmc->slotno] = slot; -+ intel_ltr_expose(slot->chip); -+ } -+} -+ -+static void byt_add_debugfs(struct sdhci_pci_slot *slot) -+{ -+ struct intel_host *intel_host = sdhci_pci_priv(slot); -+ struct mmc_host *mmc = slot->host->mmc; -+ struct dentry *dir = mmc->debugfs_root; -+ -+ if (!intel_use_ltr(slot->chip)) -+ return; -+ -+ debugfs_create_x32("active_ltr", 0444, dir, &intel_host->active_ltr); -+ debugfs_create_x32("idle_ltr", 0444, dir, &intel_host->idle_ltr); -+ -+ intel_cache_ltr(slot); -+} -+ -+static int byt_add_host(struct sdhci_pci_slot *slot) -+{ -+ int ret = sdhci_add_host(slot->host); -+ -+ if (!ret) -+ byt_add_debugfs(slot); -+ return ret; -+} -+ -+static void byt_remove_slot(struct sdhci_pci_slot *slot, int dead) -+{ -+ struct mmc_host *mmc = slot->host->mmc; -+ -+ if (!mmc->slotno) -+ intel_ltr_hide(slot->chip); -+} -+ -+static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ byt_probe_slot(slot); -+ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | -+ MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR | -+ MMC_CAP_CMD_DURING_TFR | -+ MMC_CAP_WAIT_WHILE_BUSY; -+ slot->hw_reset = sdhci_pci_int_hw_reset; -+ if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BSW_EMMC) -+ slot->host->timeout_clk = 1000; /* 1000 kHz i.e. 1 MHz */ -+ slot->host->mmc_host_ops.select_drive_strength = -+ intel_select_drive_strength; -+ return 0; -+} -+ -+static int dnv_emmc_hs_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ /* Remove 1.8V capability, if 1.8V is supported, it will be negotiated to DDR mode */ -+ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | -+ MMC_CAP_HW_RESET | -+ MMC_CAP_CMD_DURING_TFR | -+ MMC_CAP_WAIT_WHILE_BUSY; -+ slot->hw_reset = sdhci_pci_int_hw_reset; -+ return 0; -+} -+ -+static bool glk_broken_cqhci(struct sdhci_pci_slot *slot) -+{ -+ return slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC && -+ (dmi_match(DMI_BIOS_VENDOR, "LENOVO") || -+ dmi_match(DMI_SYS_VENDOR, "IRBIS")); -+} -+ -+static int glk_emmc_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ int ret = byt_emmc_probe_slot(slot); -+ -+ if (!glk_broken_cqhci(slot)) -+ slot->host->mmc->caps2 |= MMC_CAP2_CQE; -+ -+ if (slot->chip->pdev->device != PCI_DEVICE_ID_INTEL_GLK_EMMC) { -+ slot->host->mmc->caps2 |= MMC_CAP2_HS400_ES, -+ slot->host->mmc_host_ops.hs400_enhanced_strobe = -+ intel_hs400_enhanced_strobe; -+ slot->host->mmc->caps2 |= MMC_CAP2_CQE_DCMD; -+ } -+ -+ return ret; -+} -+ -+static const struct cqhci_host_ops glk_cqhci_ops = { -+ .enable = sdhci_cqe_enable, -+ .disable = sdhci_cqe_disable, -+ .dumpregs = sdhci_pci_dumpregs, -+}; -+ -+static int glk_emmc_add_host(struct sdhci_pci_slot *slot) -+{ -+ struct device *dev = &slot->chip->pdev->dev; -+ struct sdhci_host *host = slot->host; -+ struct cqhci_host *cq_host; -+ bool dma64; -+ int ret; -+ -+ ret = sdhci_setup_host(host); -+ if (ret) -+ return ret; -+ -+ cq_host = devm_kzalloc(dev, sizeof(*cq_host), GFP_KERNEL); -+ if (!cq_host) { -+ ret = -ENOMEM; -+ goto cleanup; -+ } -+ -+ cq_host->mmio = host->ioaddr + 0x200; -+ cq_host->quirks |= CQHCI_QUIRK_SHORT_TXFR_DESC_SZ; -+ cq_host->ops = &glk_cqhci_ops; -+ -+ dma64 = host->flags & SDHCI_USE_64_BIT_DMA; -+ if (dma64) -+ cq_host->caps |= CQHCI_TASK_DESC_SZ_128; -+ -+ ret = cqhci_init(cq_host, host->mmc, dma64); -+ if (ret) -+ goto cleanup; -+ -+ ret = __sdhci_add_host(host); -+ if (ret) -+ goto cleanup; -+ -+ byt_add_debugfs(slot); -+ -+ return 0; -+ -+cleanup: -+ sdhci_cleanup_host(host); -+ return ret; -+} -+ -+#ifdef CONFIG_PM -+#define GLK_RX_CTRL1 0x834 -+#define GLK_TUN_VAL 0x840 -+#define GLK_PATH_PLL GENMASK(13, 8) -+#define GLK_DLY GENMASK(6, 0) -+/* Workaround firmware failing to restore the tuning value */ -+static void glk_rpm_retune_wa(struct sdhci_pci_chip *chip, bool susp) -+{ -+ struct sdhci_pci_slot *slot = chip->slots[0]; -+ struct intel_host *intel_host = sdhci_pci_priv(slot); -+ struct sdhci_host *host = slot->host; -+ u32 glk_rx_ctrl1; -+ u32 glk_tun_val; -+ u32 dly; -+ -+ if (intel_host->rpm_retune_ok || !mmc_can_retune(host->mmc)) -+ return; -+ -+ glk_rx_ctrl1 = sdhci_readl(host, GLK_RX_CTRL1); -+ glk_tun_val = sdhci_readl(host, GLK_TUN_VAL); -+ -+ if (susp) { -+ intel_host->glk_rx_ctrl1 = glk_rx_ctrl1; -+ intel_host->glk_tun_val = glk_tun_val; -+ return; -+ } -+ -+ if (!intel_host->glk_tun_val) -+ return; -+ -+ if (glk_rx_ctrl1 != intel_host->glk_rx_ctrl1) { -+ intel_host->rpm_retune_ok = true; -+ return; -+ } -+ -+ dly = FIELD_PREP(GLK_DLY, FIELD_GET(GLK_PATH_PLL, glk_rx_ctrl1) + -+ (intel_host->glk_tun_val << 1)); -+ if (dly == FIELD_GET(GLK_DLY, glk_rx_ctrl1)) -+ return; -+ -+ glk_rx_ctrl1 = (glk_rx_ctrl1 & ~GLK_DLY) | dly; -+ sdhci_writel(host, glk_rx_ctrl1, GLK_RX_CTRL1); -+ -+ intel_host->rpm_retune_ok = true; -+ chip->rpm_retune = true; -+ mmc_retune_needed(host->mmc); -+ pr_info("%s: Requiring re-tune after rpm resume", mmc_hostname(host->mmc)); -+} -+ -+static void glk_rpm_retune_chk(struct sdhci_pci_chip *chip, bool susp) -+{ -+ if (chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC && -+ !chip->rpm_retune) -+ glk_rpm_retune_wa(chip, susp); -+} -+ -+static int glk_runtime_suspend(struct sdhci_pci_chip *chip) -+{ -+ glk_rpm_retune_chk(chip, true); -+ -+ return sdhci_cqhci_runtime_suspend(chip); -+} -+ -+static int glk_runtime_resume(struct sdhci_pci_chip *chip) -+{ -+ glk_rpm_retune_chk(chip, false); -+ -+ return sdhci_cqhci_runtime_resume(chip); -+} -+#endif -+ -+#ifdef CONFIG_ACPI -+static int ni_set_max_freq(struct sdhci_pci_slot *slot) -+{ -+ acpi_status status; -+ unsigned long long max_freq; -+ -+ status = acpi_evaluate_integer(ACPI_HANDLE(&slot->chip->pdev->dev), -+ "MXFQ", NULL, &max_freq); -+ if (ACPI_FAILURE(status)) { -+ dev_err(&slot->chip->pdev->dev, -+ "MXFQ not found in acpi table\n"); -+ return -EINVAL; -+ } -+ -+ slot->host->mmc->f_max = max_freq * 1000000; -+ -+ return 0; -+} -+#else -+static inline int ni_set_max_freq(struct sdhci_pci_slot *slot) -+{ -+ return 0; -+} -+#endif -+ -+static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ int err; -+ -+ byt_probe_slot(slot); -+ -+ err = ni_set_max_freq(slot); -+ if (err) -+ return err; -+ -+ slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE | -+ MMC_CAP_WAIT_WHILE_BUSY; -+ return 0; -+} -+ -+static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ byt_probe_slot(slot); -+ slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE | -+ MMC_CAP_WAIT_WHILE_BUSY; -+ return 0; -+} -+ -+static void byt_needs_pwr_off(struct sdhci_pci_slot *slot) -+{ -+ struct intel_host *intel_host = sdhci_pci_priv(slot); -+ u8 reg = sdhci_readb(slot->host, SDHCI_POWER_CONTROL); -+ -+ intel_host->needs_pwr_off = reg & SDHCI_POWER_ON; -+} -+ -+static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ byt_probe_slot(slot); -+ slot->host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | -+ MMC_CAP_AGGRESSIVE_PM | MMC_CAP_CD_WAKE; -+ slot->cd_idx = 0; -+ slot->cd_override_level = true; -+ if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXT_SD || -+ slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXTM_SD || -+ slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_APL_SD || -+ slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_SD) -+ slot->host->mmc_host_ops.get_cd = bxt_get_cd; -+ -+ if (slot->chip->pdev->subsystem_vendor == PCI_VENDOR_ID_NI && -+ slot->chip->pdev->subsystem_device == PCI_SUBDEVICE_ID_NI_78E3) -+ slot->host->mmc->caps2 |= MMC_CAP2_AVOID_3_3V; -+ -+ byt_needs_pwr_off(slot); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+ -+static int byt_resume(struct sdhci_pci_chip *chip) -+{ -+ byt_ocp_setting(chip->pdev); -+ -+ return sdhci_pci_resume_host(chip); -+} -+ -+#endif -+ -+#ifdef CONFIG_PM -+ -+static int byt_runtime_resume(struct sdhci_pci_chip *chip) -+{ -+ byt_ocp_setting(chip->pdev); -+ -+ return sdhci_pci_runtime_resume_host(chip); -+} -+ -+#endif -+ -+static struct sdhci_pci_fixes sdhci_intel_dnv_emmc = { -+#ifdef CONFIG_PM_SLEEP -+ .resume = byt_resume, -+#endif -+#ifdef CONFIG_PM -+ .runtime_resume = byt_runtime_resume, -+#endif -+ .allow_runtime_pm = true, -+ .probe_slot = byt_emmc_probe_slot, -+ .add_host = byt_add_host, -+ .remove_slot = byt_remove_slot, -+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | -+ SDHCI_QUIRK_NO_LED, -+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | -+ SDHCI_QUIRK2_STOP_WITH_TC, -+ .ops = &sdhci_intel_byt_ops, -+ .priv_size = sizeof(struct intel_host), -+}; -+ -+static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = { -+#ifdef CONFIG_PM_SLEEP -+ .resume = byt_resume, -+#endif -+#ifdef CONFIG_PM -+ .runtime_resume = byt_runtime_resume, -+#endif -+ .allow_runtime_pm = true, -+ .probe_slot = byt_emmc_probe_slot, -+ .add_host = byt_add_host, -+ .remove_slot = byt_remove_slot, -+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | -+ SDHCI_QUIRK_NO_LED, -+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | -+ SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 | -+ SDHCI_QUIRK2_STOP_WITH_TC, -+ .ops = &sdhci_intel_byt_ops, -+ .priv_size = sizeof(struct intel_host), -+}; -+ -+static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = { -+ .allow_runtime_pm = true, -+ .probe_slot = glk_emmc_probe_slot, -+ .add_host = glk_emmc_add_host, -+ .remove_slot = byt_remove_slot, -+#ifdef CONFIG_PM_SLEEP -+ .suspend = sdhci_cqhci_suspend, -+ .resume = sdhci_cqhci_resume, -+#endif -+#ifdef CONFIG_PM -+ .runtime_suspend = glk_runtime_suspend, -+ .runtime_resume = glk_runtime_resume, -+#endif -+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | -+ SDHCI_QUIRK_NO_LED, -+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | -+ SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 | -+ SDHCI_QUIRK2_STOP_WITH_TC, -+ .ops = &sdhci_intel_glk_ops, -+ .priv_size = sizeof(struct intel_host), -+}; -+ -+static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = { -+#ifdef CONFIG_PM_SLEEP -+ .resume = byt_resume, -+#endif -+#ifdef CONFIG_PM -+ .runtime_resume = byt_runtime_resume, -+#endif -+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | -+ SDHCI_QUIRK_NO_LED, -+ .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON | -+ SDHCI_QUIRK2_PRESET_VALUE_BROKEN, -+ .allow_runtime_pm = true, -+ .probe_slot = ni_byt_sdio_probe_slot, -+ .add_host = byt_add_host, -+ .remove_slot = byt_remove_slot, -+ .ops = &sdhci_intel_byt_ops, -+ .priv_size = sizeof(struct intel_host), -+}; -+ -+static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { -+#ifdef CONFIG_PM_SLEEP -+ .resume = byt_resume, -+#endif -+#ifdef CONFIG_PM -+ .runtime_resume = byt_runtime_resume, -+#endif -+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | -+ SDHCI_QUIRK_NO_LED, -+ .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON | -+ SDHCI_QUIRK2_PRESET_VALUE_BROKEN, -+ .allow_runtime_pm = true, -+ .probe_slot = byt_sdio_probe_slot, -+ .add_host = byt_add_host, -+ .remove_slot = byt_remove_slot, -+ .ops = &sdhci_intel_byt_ops, -+ .priv_size = sizeof(struct intel_host), -+}; -+ -+static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { -+#ifdef CONFIG_PM_SLEEP -+ .resume = byt_resume, -+#endif -+#ifdef CONFIG_PM -+ .runtime_resume = byt_runtime_resume, -+#endif -+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | -+ SDHCI_QUIRK_NO_LED, -+ .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | -+ SDHCI_QUIRK2_PRESET_VALUE_BROKEN | -+ SDHCI_QUIRK2_STOP_WITH_TC, -+ .allow_runtime_pm = true, -+ .own_cd_for_runtime_pm = true, -+ .probe_slot = byt_sd_probe_slot, -+ .add_host = byt_add_host, -+ .remove_slot = byt_remove_slot, -+ .ops = &sdhci_intel_byt_ops, -+ .priv_size = sizeof(struct intel_host), -+}; -+ -+/* Define Host controllers for Intel Merrifield platform */ -+#define INTEL_MRFLD_EMMC_0 0 -+#define INTEL_MRFLD_EMMC_1 1 -+#define INTEL_MRFLD_SD 2 -+#define INTEL_MRFLD_SDIO 3 -+ -+#ifdef CONFIG_ACPI -+static void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot) -+{ -+ struct acpi_device *device, *child; -+ -+ device = ACPI_COMPANION(&slot->chip->pdev->dev); -+ if (!device) -+ return; -+ -+ acpi_device_fix_up_power(device); -+ list_for_each_entry(child, &device->children, node) -+ if (child->status.present && child->status.enabled) -+ acpi_device_fix_up_power(child); -+} -+#else -+static inline void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot) {} -+#endif -+ -+static int intel_mrfld_mmc_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ unsigned int func = PCI_FUNC(slot->chip->pdev->devfn); -+ -+ switch (func) { -+ case INTEL_MRFLD_EMMC_0: -+ case INTEL_MRFLD_EMMC_1: -+ slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | -+ MMC_CAP_8_BIT_DATA | -+ MMC_CAP_1_8V_DDR; -+ break; -+ case INTEL_MRFLD_SD: -+ slot->host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; -+ break; -+ case INTEL_MRFLD_SDIO: -+ /* Advertise 2.0v for compatibility with the SDIO card's OCR */ -+ slot->host->ocr_mask = MMC_VDD_20_21 | MMC_VDD_165_195; -+ slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | -+ MMC_CAP_POWER_OFF_CARD; -+ break; -+ default: -+ return -ENODEV; -+ } -+ -+ intel_mrfld_mmc_fix_up_power_slot(slot); -+ return 0; -+} -+ -+static const struct sdhci_pci_fixes sdhci_intel_mrfld_mmc = { -+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, -+ .quirks2 = SDHCI_QUIRK2_BROKEN_HS200 | -+ SDHCI_QUIRK2_PRESET_VALUE_BROKEN, -+ .allow_runtime_pm = true, -+ .probe_slot = intel_mrfld_mmc_probe_slot, -+}; -+ -+static int jmicron_pmos(struct sdhci_pci_chip *chip, int on) -+{ -+ u8 scratch; -+ int ret; -+ -+ ret = pci_read_config_byte(chip->pdev, 0xAE, &scratch); -+ if (ret) -+ return ret; -+ -+ /* -+ * Turn PMOS on [bit 0], set over current detection to 2.4 V -+ * [bit 1:2] and enable over current debouncing [bit 6]. -+ */ -+ if (on) -+ scratch |= 0x47; -+ else -+ scratch &= ~0x47; -+ -+ return pci_write_config_byte(chip->pdev, 0xAE, scratch); -+} -+ -+static int jmicron_probe(struct sdhci_pci_chip *chip) -+{ -+ int ret; -+ u16 mmcdev = 0; -+ -+ if (chip->pdev->revision == 0) { -+ chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR | -+ SDHCI_QUIRK_32BIT_DMA_SIZE | -+ SDHCI_QUIRK_32BIT_ADMA_SIZE | -+ SDHCI_QUIRK_RESET_AFTER_REQUEST | -+ SDHCI_QUIRK_BROKEN_SMALL_PIO; -+ } -+ -+ /* -+ * JMicron chips can have two interfaces to the same hardware -+ * in order to work around limitations in Microsoft's driver. -+ * We need to make sure we only bind to one of them. -+ * -+ * This code assumes two things: -+ * -+ * 1. The PCI code adds subfunctions in order. -+ * -+ * 2. The MMC interface has a lower subfunction number -+ * than the SD interface. -+ */ -+ if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_SD) -+ mmcdev = PCI_DEVICE_ID_JMICRON_JMB38X_MMC; -+ else if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD) -+ mmcdev = PCI_DEVICE_ID_JMICRON_JMB388_ESD; -+ -+ if (mmcdev) { -+ struct pci_dev *sd_dev; -+ -+ sd_dev = NULL; -+ while ((sd_dev = pci_get_device(PCI_VENDOR_ID_JMICRON, -+ mmcdev, sd_dev)) != NULL) { -+ if ((PCI_SLOT(chip->pdev->devfn) == -+ PCI_SLOT(sd_dev->devfn)) && -+ (chip->pdev->bus == sd_dev->bus)) -+ break; -+ } -+ -+ if (sd_dev) { -+ pci_dev_put(sd_dev); -+ dev_info(&chip->pdev->dev, "Refusing to bind to " -+ "secondary interface.\n"); -+ return -ENODEV; -+ } -+ } -+ -+ /* -+ * JMicron chips need a bit of a nudge to enable the power -+ * output pins. -+ */ -+ ret = jmicron_pmos(chip, 1); -+ if (ret) { -+ dev_err(&chip->pdev->dev, "Failure enabling card power\n"); -+ return ret; -+ } -+ -+ /* quirk for unsable RO-detection on JM388 chips */ -+ if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD || -+ chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) -+ chip->quirks |= SDHCI_QUIRK_UNSTABLE_RO_DETECT; -+ -+ return 0; -+} -+ -+static void jmicron_enable_mmc(struct sdhci_host *host, int on) -+{ -+ u8 scratch; -+ -+ scratch = readb(host->ioaddr + 0xC0); -+ -+ if (on) -+ scratch |= 0x01; -+ else -+ scratch &= ~0x01; -+ -+ writeb(scratch, host->ioaddr + 0xC0); -+} -+ -+static int jmicron_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ if (slot->chip->pdev->revision == 0) { -+ u16 version; -+ -+ version = readl(slot->host->ioaddr + SDHCI_HOST_VERSION); -+ version = (version & SDHCI_VENDOR_VER_MASK) >> -+ SDHCI_VENDOR_VER_SHIFT; -+ -+ /* -+ * Older versions of the chip have lots of nasty glitches -+ * in the ADMA engine. It's best just to avoid it -+ * completely. -+ */ -+ if (version < 0xAC) -+ slot->host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; -+ } -+ -+ /* JM388 MMC doesn't support 1.8V while SD supports it */ -+ if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) { -+ slot->host->ocr_avail_sd = MMC_VDD_32_33 | MMC_VDD_33_34 | -+ MMC_VDD_29_30 | MMC_VDD_30_31 | -+ MMC_VDD_165_195; /* allow 1.8V */ -+ slot->host->ocr_avail_mmc = MMC_VDD_32_33 | MMC_VDD_33_34 | -+ MMC_VDD_29_30 | MMC_VDD_30_31; /* no 1.8V for MMC */ -+ } -+ -+ /* -+ * The secondary interface requires a bit set to get the -+ * interrupts. -+ */ -+ if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || -+ slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) -+ jmicron_enable_mmc(slot->host, 1); -+ -+ slot->host->mmc->caps |= MMC_CAP_BUS_WIDTH_TEST; -+ -+ return 0; -+} -+ -+static void jmicron_remove_slot(struct sdhci_pci_slot *slot, int dead) -+{ -+ if (dead) -+ return; -+ -+ if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || -+ slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) -+ jmicron_enable_mmc(slot->host, 0); -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int jmicron_suspend(struct sdhci_pci_chip *chip) -+{ -+ int i, ret; -+ -+ ret = sdhci_pci_suspend_host(chip); -+ if (ret) -+ return ret; -+ -+ if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || -+ chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) { -+ for (i = 0; i < chip->num_slots; i++) -+ jmicron_enable_mmc(chip->slots[i]->host, 0); -+ } -+ -+ return 0; -+} -+ -+static int jmicron_resume(struct sdhci_pci_chip *chip) -+{ -+ int ret, i; -+ -+ if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || -+ chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) { -+ for (i = 0; i < chip->num_slots; i++) -+ jmicron_enable_mmc(chip->slots[i]->host, 1); -+ } -+ -+ ret = jmicron_pmos(chip, 1); -+ if (ret) { -+ dev_err(&chip->pdev->dev, "Failure enabling card power\n"); -+ return ret; -+ } -+ -+ return sdhci_pci_resume_host(chip); -+} -+#endif -+ -+static const struct sdhci_pci_fixes sdhci_jmicron = { -+ .probe = jmicron_probe, -+ -+ .probe_slot = jmicron_probe_slot, -+ .remove_slot = jmicron_remove_slot, -+ -+#ifdef CONFIG_PM_SLEEP -+ .suspend = jmicron_suspend, -+ .resume = jmicron_resume, -+#endif -+}; -+ -+/* SysKonnect CardBus2SDIO extra registers */ -+#define SYSKT_CTRL 0x200 -+#define SYSKT_RDFIFO_STAT 0x204 -+#define SYSKT_WRFIFO_STAT 0x208 -+#define SYSKT_POWER_DATA 0x20c -+#define SYSKT_POWER_330 0xef -+#define SYSKT_POWER_300 0xf8 -+#define SYSKT_POWER_184 0xcc -+#define SYSKT_POWER_CMD 0x20d -+#define SYSKT_POWER_START (1 << 7) -+#define SYSKT_POWER_STATUS 0x20e -+#define SYSKT_POWER_STATUS_OK (1 << 0) -+#define SYSKT_BOARD_REV 0x210 -+#define SYSKT_CHIP_REV 0x211 -+#define SYSKT_CONF_DATA 0x212 -+#define SYSKT_CONF_DATA_1V8 (1 << 2) -+#define SYSKT_CONF_DATA_2V5 (1 << 1) -+#define SYSKT_CONF_DATA_3V3 (1 << 0) -+ -+static int syskt_probe(struct sdhci_pci_chip *chip) -+{ -+ if ((chip->pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) { -+ chip->pdev->class &= ~0x0000FF; -+ chip->pdev->class |= PCI_SDHCI_IFDMA; -+ } -+ return 0; -+} -+ -+static int syskt_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ int tm, ps; -+ -+ u8 board_rev = readb(slot->host->ioaddr + SYSKT_BOARD_REV); -+ u8 chip_rev = readb(slot->host->ioaddr + SYSKT_CHIP_REV); -+ dev_info(&slot->chip->pdev->dev, "SysKonnect CardBus2SDIO, " -+ "board rev %d.%d, chip rev %d.%d\n", -+ board_rev >> 4, board_rev & 0xf, -+ chip_rev >> 4, chip_rev & 0xf); -+ if (chip_rev >= 0x20) -+ slot->host->quirks |= SDHCI_QUIRK_FORCE_DMA; -+ -+ writeb(SYSKT_POWER_330, slot->host->ioaddr + SYSKT_POWER_DATA); -+ writeb(SYSKT_POWER_START, slot->host->ioaddr + SYSKT_POWER_CMD); -+ udelay(50); -+ tm = 10; /* Wait max 1 ms */ -+ do { -+ ps = readw(slot->host->ioaddr + SYSKT_POWER_STATUS); -+ if (ps & SYSKT_POWER_STATUS_OK) -+ break; -+ udelay(100); -+ } while (--tm); -+ if (!tm) { -+ dev_err(&slot->chip->pdev->dev, -+ "power regulator never stabilized"); -+ writeb(0, slot->host->ioaddr + SYSKT_POWER_CMD); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static const struct sdhci_pci_fixes sdhci_syskt = { -+ .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER, -+ .probe = syskt_probe, -+ .probe_slot = syskt_probe_slot, -+}; -+ -+static int via_probe(struct sdhci_pci_chip *chip) -+{ -+ if (chip->pdev->revision == 0x10) -+ chip->quirks |= SDHCI_QUIRK_DELAY_AFTER_POWER; -+ -+ return 0; -+} -+ -+static const struct sdhci_pci_fixes sdhci_via = { -+ .probe = via_probe, -+}; -+ -+static int rtsx_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ slot->host->mmc->caps2 |= MMC_CAP2_HS200; -+ return 0; -+} -+ -+static const struct sdhci_pci_fixes sdhci_rtsx = { -+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | -+ SDHCI_QUIRK2_BROKEN_64_BIT_DMA | -+ SDHCI_QUIRK2_BROKEN_DDR50, -+ .probe_slot = rtsx_probe_slot, -+}; -+ -+/*AMD chipset generation*/ -+enum amd_chipset_gen { -+ AMD_CHIPSET_BEFORE_ML, -+ AMD_CHIPSET_CZ, -+ AMD_CHIPSET_NL, -+ AMD_CHIPSET_UNKNOWN, -+}; -+ -+/* AMD registers */ -+#define AMD_SD_AUTO_PATTERN 0xB8 -+#define AMD_MSLEEP_DURATION 4 -+#define AMD_SD_MISC_CONTROL 0xD0 -+#define AMD_MAX_TUNE_VALUE 0x0B -+#define AMD_AUTO_TUNE_SEL 0x10800 -+#define AMD_FIFO_PTR 0x30 -+#define AMD_BIT_MASK 0x1F -+ -+static void amd_tuning_reset(struct sdhci_host *host) -+{ -+ unsigned int val; -+ -+ val = sdhci_readw(host, SDHCI_HOST_CONTROL2); -+ val |= SDHCI_CTRL_PRESET_VAL_ENABLE | SDHCI_CTRL_EXEC_TUNING; -+ sdhci_writew(host, val, SDHCI_HOST_CONTROL2); -+ -+ val = sdhci_readw(host, SDHCI_HOST_CONTROL2); -+ val &= ~SDHCI_CTRL_EXEC_TUNING; -+ sdhci_writew(host, val, SDHCI_HOST_CONTROL2); -+} -+ -+static void amd_config_tuning_phase(struct pci_dev *pdev, u8 phase) -+{ -+ unsigned int val; -+ -+ pci_read_config_dword(pdev, AMD_SD_AUTO_PATTERN, &val); -+ val &= ~AMD_BIT_MASK; -+ val |= (AMD_AUTO_TUNE_SEL | (phase << 1)); -+ pci_write_config_dword(pdev, AMD_SD_AUTO_PATTERN, val); -+} -+ -+static void amd_enable_manual_tuning(struct pci_dev *pdev) -+{ -+ unsigned int val; -+ -+ pci_read_config_dword(pdev, AMD_SD_MISC_CONTROL, &val); -+ val |= AMD_FIFO_PTR; -+ pci_write_config_dword(pdev, AMD_SD_MISC_CONTROL, val); -+} -+ -+static int amd_execute_tuning_hs200(struct sdhci_host *host, u32 opcode) -+{ -+ struct sdhci_pci_slot *slot = sdhci_priv(host); -+ struct pci_dev *pdev = slot->chip->pdev; -+ u8 valid_win = 0; -+ u8 valid_win_max = 0; -+ u8 valid_win_end = 0; -+ u8 ctrl, tune_around; -+ -+ amd_tuning_reset(host); -+ -+ for (tune_around = 0; tune_around < 12; tune_around++) { -+ amd_config_tuning_phase(pdev, tune_around); -+ -+ if (mmc_send_tuning(host->mmc, opcode, NULL)) { -+ valid_win = 0; -+ msleep(AMD_MSLEEP_DURATION); -+ ctrl = SDHCI_RESET_CMD | SDHCI_RESET_DATA; -+ sdhci_writeb(host, ctrl, SDHCI_SOFTWARE_RESET); -+ } else if (++valid_win > valid_win_max) { -+ valid_win_max = valid_win; -+ valid_win_end = tune_around; -+ } -+ } -+ -+ if (!valid_win_max) { -+ dev_err(&pdev->dev, "no tuning point found\n"); -+ return -EIO; -+ } -+ -+ amd_config_tuning_phase(pdev, valid_win_end - valid_win_max / 2); -+ -+ amd_enable_manual_tuning(pdev); -+ -+ host->mmc->retune_period = 0; -+ -+ return 0; -+} -+ -+static int amd_execute_tuning(struct mmc_host *mmc, u32 opcode) -+{ -+ struct sdhci_host *host = mmc_priv(mmc); -+ -+ /* AMD requires custom HS200 tuning */ -+ if (host->timing == MMC_TIMING_MMC_HS200) -+ return amd_execute_tuning_hs200(host, opcode); -+ -+ /* Otherwise perform standard SDHCI tuning */ -+ return sdhci_execute_tuning(mmc, opcode); -+} -+ -+static int amd_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ struct mmc_host_ops *ops = &slot->host->mmc_host_ops; -+ -+ ops->execute_tuning = amd_execute_tuning; -+ -+ return 0; -+} -+ -+static int amd_probe(struct sdhci_pci_chip *chip) -+{ -+ struct pci_dev *smbus_dev; -+ enum amd_chipset_gen gen; -+ -+ smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, -+ PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL); -+ if (smbus_dev) { -+ gen = AMD_CHIPSET_BEFORE_ML; -+ } else { -+ smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, -+ PCI_DEVICE_ID_AMD_KERNCZ_SMBUS, NULL); -+ if (smbus_dev) { -+ if (smbus_dev->revision < 0x51) -+ gen = AMD_CHIPSET_CZ; -+ else -+ gen = AMD_CHIPSET_NL; -+ } else { -+ gen = AMD_CHIPSET_UNKNOWN; -+ } -+ } -+ -+ if (smbus_dev) { -+ pci_dev_put(smbus_dev); -+ } -+ -+ if (gen == AMD_CHIPSET_BEFORE_ML || gen == AMD_CHIPSET_CZ) -+ chip->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD; -+ -+ return 0; -+} -+ -+static u32 sdhci_read_present_state(struct sdhci_host *host) -+{ -+ return sdhci_readl(host, SDHCI_PRESENT_STATE); -+} -+ -+static void amd_sdhci_reset(struct sdhci_host *host, u8 mask) -+{ -+ struct sdhci_pci_slot *slot = sdhci_priv(host); -+ struct pci_dev *pdev = slot->chip->pdev; -+ u32 present_state; -+ -+ /* -+ * SDHC 0x7906 requires a hard reset to clear all internal state. -+ * Otherwise it can get into a bad state where the DATA lines are always -+ * read as zeros. -+ */ -+ if (pdev->device == 0x7906 && (mask & SDHCI_RESET_ALL)) { -+ pci_clear_master(pdev); -+ -+ pci_save_state(pdev); -+ -+ pci_set_power_state(pdev, PCI_D3cold); -+ pr_debug("%s: power_state=%u\n", mmc_hostname(host->mmc), -+ pdev->current_state); -+ pci_set_power_state(pdev, PCI_D0); -+ -+ pci_restore_state(pdev); -+ -+ /* -+ * SDHCI_RESET_ALL says the card detect logic should not be -+ * reset, but since we need to reset the entire controller -+ * we should wait until the card detect logic has stabilized. -+ * -+ * This normally takes about 40ms. -+ */ -+ readx_poll_timeout( -+ sdhci_read_present_state, -+ host, -+ present_state, -+ present_state & SDHCI_CD_STABLE, -+ 10000, -+ 100000 -+ ); -+ } -+ -+ return sdhci_reset(host, mask); -+} -+ -+static const struct sdhci_ops amd_sdhci_pci_ops = { -+ .set_clock = sdhci_set_clock, -+ .enable_dma = sdhci_pci_enable_dma, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = amd_sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, -+}; -+ -+static const struct sdhci_pci_fixes sdhci_amd = { -+ .probe = amd_probe, -+ .ops = &amd_sdhci_pci_ops, -+ .probe_slot = amd_probe_slot, -+}; -+ -+static const struct pci_device_id pci_ids[] = { -+ SDHCI_PCI_DEVICE(RICOH, R5C822, ricoh), -+ SDHCI_PCI_DEVICE(RICOH, R5C843, ricoh_mmc), -+ SDHCI_PCI_DEVICE(RICOH, R5CE822, ricoh_mmc), -+ SDHCI_PCI_DEVICE(RICOH, R5CE823, ricoh_mmc), -+ SDHCI_PCI_DEVICE(ENE, CB712_SD, ene_712), -+ SDHCI_PCI_DEVICE(ENE, CB712_SD_2, ene_712), -+ SDHCI_PCI_DEVICE(ENE, CB714_SD, ene_714), -+ SDHCI_PCI_DEVICE(ENE, CB714_SD_2, ene_714), -+ SDHCI_PCI_DEVICE(MARVELL, 88ALP01_SD, cafe), -+ SDHCI_PCI_DEVICE(JMICRON, JMB38X_SD, jmicron), -+ SDHCI_PCI_DEVICE(JMICRON, JMB38X_MMC, jmicron), -+ SDHCI_PCI_DEVICE(JMICRON, JMB388_SD, jmicron), -+ SDHCI_PCI_DEVICE(JMICRON, JMB388_ESD, jmicron), -+ SDHCI_PCI_DEVICE(SYSKONNECT, 8000, syskt), -+ SDHCI_PCI_DEVICE(VIA, 95D0, via), -+ SDHCI_PCI_DEVICE(REALTEK, 5250, rtsx), -+ SDHCI_PCI_DEVICE(INTEL, QRK_SD, intel_qrk), -+ SDHCI_PCI_DEVICE(INTEL, MRST_SD0, intel_mrst_hc0), -+ SDHCI_PCI_DEVICE(INTEL, MRST_SD1, intel_mrst_hc1_hc2), -+ SDHCI_PCI_DEVICE(INTEL, MRST_SD2, intel_mrst_hc1_hc2), -+ SDHCI_PCI_DEVICE(INTEL, MFD_SD, intel_mfd_sd), -+ SDHCI_PCI_DEVICE(INTEL, MFD_SDIO1, intel_mfd_sdio), -+ SDHCI_PCI_DEVICE(INTEL, MFD_SDIO2, intel_mfd_sdio), -+ SDHCI_PCI_DEVICE(INTEL, MFD_EMMC0, intel_mfd_emmc), -+ SDHCI_PCI_DEVICE(INTEL, MFD_EMMC1, intel_mfd_emmc), -+ SDHCI_PCI_DEVICE(INTEL, PCH_SDIO0, intel_pch_sdio), -+ SDHCI_PCI_DEVICE(INTEL, PCH_SDIO1, intel_pch_sdio), -+ SDHCI_PCI_DEVICE(INTEL, BYT_EMMC, intel_byt_emmc), -+ SDHCI_PCI_SUBDEVICE(INTEL, BYT_SDIO, NI, 7884, ni_byt_sdio), -+ SDHCI_PCI_DEVICE(INTEL, BYT_SDIO, intel_byt_sdio), -+ SDHCI_PCI_DEVICE(INTEL, BYT_SD, intel_byt_sd), -+ SDHCI_PCI_DEVICE(INTEL, BYT_EMMC2, intel_byt_emmc), -+ SDHCI_PCI_DEVICE(INTEL, BSW_EMMC, intel_byt_emmc), -+ SDHCI_PCI_DEVICE(INTEL, BSW_SDIO, intel_byt_sdio), -+ SDHCI_PCI_DEVICE(INTEL, BSW_SD, intel_byt_sd), -+ SDHCI_PCI_DEVICE(INTEL, CLV_SDIO0, intel_mfd_sd), -+ SDHCI_PCI_DEVICE(INTEL, CLV_SDIO1, intel_mfd_sdio), -+ SDHCI_PCI_DEVICE(INTEL, CLV_SDIO2, intel_mfd_sdio), -+ SDHCI_PCI_DEVICE(INTEL, CLV_EMMC0, intel_mfd_emmc), -+ SDHCI_PCI_DEVICE(INTEL, CLV_EMMC1, intel_mfd_emmc), -+ SDHCI_PCI_DEVICE(INTEL, MRFLD_MMC, intel_mrfld_mmc), -+ SDHCI_PCI_DEVICE(INTEL, SPT_EMMC, intel_byt_emmc), -+ SDHCI_PCI_DEVICE(INTEL, SPT_SDIO, intel_byt_sdio), -+ SDHCI_PCI_DEVICE(INTEL, SPT_SD, intel_byt_sd), -+ SDHCI_PCI_DEVICE(INTEL, DNV_EMMC, intel_dnv_emmc), -+ SDHCI_PCI_DEVICE(INTEL, CDF_EMMC, intel_glk_emmc), -+ SDHCI_PCI_DEVICE(INTEL, BXT_EMMC, intel_byt_emmc), -+ SDHCI_PCI_DEVICE(INTEL, BXT_SDIO, intel_byt_sdio), -+ SDHCI_PCI_DEVICE(INTEL, BXT_SD, intel_byt_sd), -+ SDHCI_PCI_DEVICE(INTEL, BXTM_EMMC, intel_byt_emmc), -+ SDHCI_PCI_DEVICE(INTEL, BXTM_SDIO, intel_byt_sdio), -+ SDHCI_PCI_DEVICE(INTEL, BXTM_SD, intel_byt_sd), -+ SDHCI_PCI_DEVICE(INTEL, APL_EMMC, intel_byt_emmc), -+ SDHCI_PCI_DEVICE(INTEL, APL_SDIO, intel_byt_sdio), -+ SDHCI_PCI_DEVICE(INTEL, APL_SD, intel_byt_sd), -+ SDHCI_PCI_DEVICE(INTEL, GLK_EMMC, intel_glk_emmc), -+ SDHCI_PCI_DEVICE(INTEL, GLK_SDIO, intel_byt_sdio), -+ SDHCI_PCI_DEVICE(INTEL, GLK_SD, intel_byt_sd), -+ SDHCI_PCI_DEVICE(INTEL, CNP_EMMC, intel_glk_emmc), -+ SDHCI_PCI_DEVICE(INTEL, CNP_SD, intel_byt_sd), -+ SDHCI_PCI_DEVICE(INTEL, CNPH_SD, intel_byt_sd), -+ SDHCI_PCI_DEVICE(INTEL, ICP_EMMC, intel_glk_emmc), -+ SDHCI_PCI_DEVICE(INTEL, ICP_SD, intel_byt_sd), -+ SDHCI_PCI_DEVICE(INTEL, EHL_EMMC, intel_glk_emmc), -+ SDHCI_PCI_DEVICE(INTEL, EHL_SD, intel_byt_sd), -+ SDHCI_PCI_DEVICE(INTEL, CML_EMMC, intel_glk_emmc), -+ SDHCI_PCI_DEVICE(INTEL, CML_SD, intel_byt_sd), -+ SDHCI_PCI_DEVICE(INTEL, CMLH_SD, intel_byt_sd), -+ SDHCI_PCI_DEVICE(INTEL, JSL_EMMC, intel_glk_emmc), -+ SDHCI_PCI_DEVICE(INTEL, JSL_SD, intel_byt_sd), -+ SDHCI_PCI_DEVICE(INTEL, LKF_EMMC, intel_glk_emmc), -+ SDHCI_PCI_DEVICE(INTEL, LKF_SD, intel_byt_sd), -+ SDHCI_PCI_DEVICE(O2, 8120, o2), -+ SDHCI_PCI_DEVICE(O2, 8220, o2), -+ SDHCI_PCI_DEVICE(O2, 8221, o2), -+ SDHCI_PCI_DEVICE(O2, 8320, o2), -+ SDHCI_PCI_DEVICE(O2, 8321, o2), -+ SDHCI_PCI_DEVICE(O2, FUJIN2, o2), -+ SDHCI_PCI_DEVICE(O2, SDS0, o2), -+ SDHCI_PCI_DEVICE(O2, SDS1, o2), -+ SDHCI_PCI_DEVICE(O2, SEABIRD0, o2), -+ SDHCI_PCI_DEVICE(O2, SEABIRD1, o2), -+ SDHCI_PCI_DEVICE(ARASAN, PHY_EMMC, arasan), -+ SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps), -+ SDHCI_PCI_DEVICE(GLI, 9750, gl9750), -+ SDHCI_PCI_DEVICE(GLI, 9755, gl9755), -+ SDHCI_PCI_DEVICE(GLI, 9763E, gl9763e), -+ SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd), -+ /* Generic SD host controller */ -+ {PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)}, -+ { /* end: all zeroes */ }, -+}; -+ -+MODULE_DEVICE_TABLE(pci, pci_ids); -+ -+/*****************************************************************************\ -+ * * -+ * SDHCI core callbacks * -+ * * -+\*****************************************************************************/ -+ -+int sdhci_pci_enable_dma(struct sdhci_host *host) -+{ -+ struct sdhci_pci_slot *slot; -+ struct pci_dev *pdev; -+ -+ slot = sdhci_priv(host); -+ pdev = slot->chip->pdev; -+ -+ if (((pdev->class & 0xFFFF00) == (PCI_CLASS_SYSTEM_SDHCI << 8)) && -+ ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) && -+ (host->flags & SDHCI_USE_SDMA)) { -+ dev_warn(&pdev->dev, "Will use DMA mode even though HW " -+ "doesn't fully claim to support it.\n"); -+ } -+ -+ pci_set_master(pdev); -+ -+ return 0; -+} -+ -+static void sdhci_pci_gpio_hw_reset(struct sdhci_host *host) -+{ -+ struct sdhci_pci_slot *slot = sdhci_priv(host); -+ int rst_n_gpio = slot->rst_n_gpio; -+ -+ if (!gpio_is_valid(rst_n_gpio)) -+ return; -+ gpio_set_value_cansleep(rst_n_gpio, 0); -+ /* For eMMC, minimum is 1us but give it 10us for good measure */ -+ udelay(10); -+ gpio_set_value_cansleep(rst_n_gpio, 1); -+ /* For eMMC, minimum is 200us but give it 300us for good measure */ -+ usleep_range(300, 1000); -+} -+ -+static void sdhci_pci_hw_reset(struct sdhci_host *host) -+{ -+ struct sdhci_pci_slot *slot = sdhci_priv(host); -+ -+ if (slot->hw_reset) -+ slot->hw_reset(host); -+} -+ -+static const struct sdhci_ops sdhci_pci_ops = { -+ .set_clock = sdhci_set_clock, -+ .enable_dma = sdhci_pci_enable_dma, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, -+ .hw_reset = sdhci_pci_hw_reset, -+}; -+ -+/*****************************************************************************\ -+ * * -+ * Suspend/resume * -+ * * -+\*****************************************************************************/ -+ -+#ifdef CONFIG_PM_SLEEP -+static int sdhci_pci_suspend(struct device *dev) -+{ -+ struct sdhci_pci_chip *chip = dev_get_drvdata(dev); -+ -+ if (!chip) -+ return 0; -+ -+ if (chip->fixes && chip->fixes->suspend) -+ return chip->fixes->suspend(chip); -+ -+ return sdhci_pci_suspend_host(chip); -+} -+ -+static int sdhci_pci_resume(struct device *dev) -+{ -+ struct sdhci_pci_chip *chip = dev_get_drvdata(dev); -+ -+ if (!chip) -+ return 0; -+ -+ if (chip->fixes && chip->fixes->resume) -+ return chip->fixes->resume(chip); -+ -+ return sdhci_pci_resume_host(chip); -+} -+#endif -+ -+#ifdef CONFIG_PM -+static int sdhci_pci_runtime_suspend(struct device *dev) -+{ -+ struct sdhci_pci_chip *chip = dev_get_drvdata(dev); -+ -+ if (!chip) -+ return 0; -+ -+ if (chip->fixes && chip->fixes->runtime_suspend) -+ return chip->fixes->runtime_suspend(chip); -+ -+ return sdhci_pci_runtime_suspend_host(chip); -+} -+ -+static int sdhci_pci_runtime_resume(struct device *dev) -+{ -+ struct sdhci_pci_chip *chip = dev_get_drvdata(dev); -+ -+ if (!chip) -+ return 0; -+ -+ if (chip->fixes && chip->fixes->runtime_resume) -+ return chip->fixes->runtime_resume(chip); -+ -+ return sdhci_pci_runtime_resume_host(chip); -+} -+#endif -+ -+static const struct dev_pm_ops sdhci_pci_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(sdhci_pci_suspend, sdhci_pci_resume) -+ SET_RUNTIME_PM_OPS(sdhci_pci_runtime_suspend, -+ sdhci_pci_runtime_resume, NULL) -+}; -+ -+/*****************************************************************************\ -+ * * -+ * Device probing/removal * -+ * * -+\*****************************************************************************/ -+ -+static struct sdhci_pci_slot *sdhci_pci_probe_slot( -+ struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar, -+ int slotno) -+{ -+ struct sdhci_pci_slot *slot; -+ struct sdhci_host *host; -+ int ret, bar = first_bar + slotno; -+ size_t priv_size = chip->fixes ? chip->fixes->priv_size : 0; -+ -+ if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { -+ dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar); -+ return ERR_PTR(-ENODEV); -+ } -+ -+ if (pci_resource_len(pdev, bar) < 0x100) { -+ dev_err(&pdev->dev, "Invalid iomem size. You may " -+ "experience problems.\n"); -+ } -+ -+ if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) { -+ dev_err(&pdev->dev, "Vendor specific interface. Aborting.\n"); -+ return ERR_PTR(-ENODEV); -+ } -+ -+ if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) { -+ dev_err(&pdev->dev, "Unknown interface. Aborting.\n"); -+ return ERR_PTR(-ENODEV); -+ } -+ -+ host = sdhci_alloc_host(&pdev->dev, sizeof(*slot) + priv_size); -+ if (IS_ERR(host)) { -+ dev_err(&pdev->dev, "cannot allocate host\n"); -+ return ERR_CAST(host); -+ } -+ -+ slot = sdhci_priv(host); -+ -+ slot->chip = chip; -+ slot->host = host; -+ slot->rst_n_gpio = -EINVAL; -+ slot->cd_gpio = -EINVAL; -+ slot->cd_idx = -1; -+ -+ /* Retrieve platform data if there is any */ -+ if (*sdhci_pci_get_data) -+ slot->data = sdhci_pci_get_data(pdev, slotno); -+ -+ if (slot->data) { -+ if (slot->data->setup) { -+ ret = slot->data->setup(slot->data); -+ if (ret) { -+ dev_err(&pdev->dev, "platform setup failed\n"); -+ goto free; -+ } -+ } -+ slot->rst_n_gpio = slot->data->rst_n_gpio; -+ slot->cd_gpio = slot->data->cd_gpio; -+ } -+ -+ host->hw_name = "PCI"; -+ host->ops = chip->fixes && chip->fixes->ops ? -+ chip->fixes->ops : -+ &sdhci_pci_ops; -+ host->quirks = chip->quirks; -+ host->quirks2 = chip->quirks2; -+ -+ host->irq = pdev->irq; -+ -+ ret = pcim_iomap_regions(pdev, BIT(bar), mmc_hostname(host->mmc)); -+ if (ret) { -+ dev_err(&pdev->dev, "cannot request region\n"); -+ goto cleanup; -+ } -+ -+ host->ioaddr = pcim_iomap_table(pdev)[bar]; -+ -+ if (chip->fixes && chip->fixes->probe_slot) { -+ ret = chip->fixes->probe_slot(slot); -+ if (ret) -+ goto cleanup; -+ } -+ -+ if (gpio_is_valid(slot->rst_n_gpio)) { -+ if (!devm_gpio_request(&pdev->dev, slot->rst_n_gpio, "eMMC_reset")) { -+ gpio_direction_output(slot->rst_n_gpio, 1); -+ slot->host->mmc->caps |= MMC_CAP_HW_RESET; -+ slot->hw_reset = sdhci_pci_gpio_hw_reset; -+ } else { -+ dev_warn(&pdev->dev, "failed to request rst_n_gpio\n"); -+ slot->rst_n_gpio = -EINVAL; -+ } -+ } -+ -+ host->mmc->pm_caps = MMC_PM_KEEP_POWER; -+ host->mmc->slotno = slotno; -+ host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP; -+ -+ if (device_can_wakeup(&pdev->dev)) -+ host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; -+ -+ if (host->mmc->caps & MMC_CAP_CD_WAKE) -+ device_init_wakeup(&pdev->dev, true); -+ -+ if (slot->cd_idx >= 0) { -+ ret = mmc_gpiod_request_cd(host->mmc, "cd", slot->cd_idx, -+ slot->cd_override_level, 0); -+ if (ret && ret != -EPROBE_DEFER) -+ ret = mmc_gpiod_request_cd(host->mmc, NULL, -+ slot->cd_idx, -+ slot->cd_override_level, -+ 0); -+ if (ret == -EPROBE_DEFER) -+ goto remove; -+ -+ if (ret) { -+ dev_warn(&pdev->dev, "failed to setup card detect gpio\n"); -+ slot->cd_idx = -1; -+ } -+ } -+ -+ if (chip->fixes && chip->fixes->add_host) -+ ret = chip->fixes->add_host(slot); -+ else -+ ret = sdhci_add_host(host); -+ if (ret) -+ goto remove; -+ -+ sdhci_pci_add_own_cd(slot); -+ -+ /* -+ * Check if the chip needs a separate GPIO for card detect to wake up -+ * from runtime suspend. If it is not there, don't allow runtime PM. -+ * Note sdhci_pci_add_own_cd() sets slot->cd_gpio to -EINVAL on failure. -+ */ -+ if (chip->fixes && chip->fixes->own_cd_for_runtime_pm && -+ !gpio_is_valid(slot->cd_gpio) && slot->cd_idx < 0) -+ chip->allow_runtime_pm = false; -+ -+ return slot; -+ -+remove: -+ if (chip->fixes && chip->fixes->remove_slot) -+ chip->fixes->remove_slot(slot, 0); -+ -+cleanup: -+ if (slot->data && slot->data->cleanup) -+ slot->data->cleanup(slot->data); -+ -+free: -+ sdhci_free_host(host); -+ -+ return ERR_PTR(ret); -+} -+ -+static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) -+{ -+ int dead; -+ u32 scratch; -+ -+ sdhci_pci_remove_own_cd(slot); -+ -+ dead = 0; -+ scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS); -+ if (scratch == (u32)-1) -+ dead = 1; -+ -+ sdhci_remove_host(slot->host, dead); -+ -+ if (slot->chip->fixes && slot->chip->fixes->remove_slot) -+ slot->chip->fixes->remove_slot(slot, dead); -+ -+ if (slot->data && slot->data->cleanup) -+ slot->data->cleanup(slot->data); -+ -+ sdhci_free_host(slot->host); -+} -+ -+static void sdhci_pci_runtime_pm_allow(struct device *dev) -+{ -+ pm_suspend_ignore_children(dev, 1); -+ pm_runtime_set_autosuspend_delay(dev, 50); -+ pm_runtime_use_autosuspend(dev); -+ pm_runtime_allow(dev); -+ /* Stay active until mmc core scans for a card */ -+ pm_runtime_put_noidle(dev); -+} -+ -+static void sdhci_pci_runtime_pm_forbid(struct device *dev) -+{ -+ pm_runtime_forbid(dev); -+ pm_runtime_get_noresume(dev); -+} -+ -+/* define by gohi, set in bios acpi dsdt table */ -+#define EMMC_DSDT_MODE_HS400 0 -+#define EMMC_DSDT_MODE_HS200 1 -+#define EMMC_DSDT_MODE_DDR52 2 -+#define EMMC_DSDT_MODE_SDR52 3 -+ -+static int sdhci_set_quirks2_by_dsdt(struct pci_dev *pdev) -+{ -+ struct acpi_device *acpi_dev; -+ struct fwnode_handle *pfwnod = pdev->dev.fwnode; -+ u64 mode; -+ int ret; -+ -+ /* Find acpi node through pci, -+ * the relationship between pci and acpi devices can be viewed through the /sys/bus file */ -+ acpi_dev = container_of(pfwnod, struct acpi_device, fwnode); -+ -+ /* DSDT need take node as: "Name (MODE, 0x0-)" */ -+ ret = acpi_evaluate_integer(acpi_dev->handle, "MODE", NULL, &mode); -+ if (ACPI_SUCCESS(ret)) { -+ dev_info(&pdev->dev, "SD controller get bus mode:0x%lld from dsts success.\n", mode); -+ switch(mode) { -+ case EMMC_DSDT_MODE_SDR52: -+ sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_BROKEN_DDR50 | SDHCI_QUIRK2_BROKEN_HS200; -+ sdhci_intel_dnv_emmc.probe_slot = dnv_emmc_hs_probe_slot; -+ dev_info(&pdev->dev, "Configure SDHCI as SDR52 attribute through dsdt.\n"); -+ break; -+ case EMMC_DSDT_MODE_DDR52: -+ sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; -+ dev_info(&pdev->dev, "Configure SDHCI as DDR52 attribute through dsdt.\n"); -+ break; -+ case EMMC_DSDT_MODE_HS200: -+ dev_info(&pdev->dev, "Configure SDHCI as HS200 attribute through dsdt.\n"); -+ break; -+ case EMMC_DSDT_MODE_HS400: -+ sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400; -+ dev_info(&pdev->dev, "Configure SDHCI as HS400 attribute through dsdt.\n"); -+ break; -+ default: -+ ret = EINVAL; -+ break; -+ } -+ } else { -+ ret = EINVAL; -+ } -+ -+ return ret; -+} -+ -+#ifndef COMMAND_LINE_SIZE -+#define COMMAND_LINE_SIZE 1024 -+#endif -+ -+int sdhci_cmdline_read(char *cmdline) -+{ -+ struct file *filp; -+ int ret = 0; -+ loff_t pos; -+ -+ /* Basically, the kernel parameters with arch are not exported. -+ * In order to not have too much influence and generalization, -+ * use the proc file to obtain parameter information. */ -+ filp = filp_open("/proc/cmdline", O_RDONLY, 0); -+ if (IS_ERR(filp)) { -+ filp = NULL; -+ goto exit; -+ } -+ pos = 0; -+ ret = kernel_read(filp, cmdline, COMMAND_LINE_SIZE, &pos); -+ if (ret < 0) { -+ goto exit; -+ } -+ filp_close(filp, NULL); -+ -+ return 0; -+ -+exit: -+ if (filp != NULL) { -+ filp_close(filp, NULL); -+ } -+ return -1; -+} -+ -+static int sdhci_set_quirks2_by_cmdline(struct pci_dev *pdev) -+{ -+ char *option, cmdline[COMMAND_LINE_SIZE]; -+ int ret = 0; -+ -+ mem_clear(cmdline, COMMAND_LINE_SIZE); -+ -+ ret = sdhci_cmdline_read(cmdline); -+ if (ret) { -+ return ret; -+ } -+ -+ option = strstr(cmdline, "sdhcimode="); -+ if (option == NULL) { -+ return EINVAL; -+ } -+ -+ /* Count, sdhcimode= is it 10 bytes? */ -+ option += 10; -+ -+ if (!strncmp(option, "sdr52", 5)) { -+ sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_BROKEN_DDR50 | SDHCI_QUIRK2_BROKEN_HS200; -+ /* Remove 1.8V ability */ -+ sdhci_intel_dnv_emmc.probe_slot = dnv_emmc_hs_probe_slot; -+ dev_info(&pdev->dev, "Configure SDHCI as SDR52 attribute through cmdline.\n"); -+ } else if (!strncmp(option, "ddr52", 5)) { -+ sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; -+ dev_info(&pdev->dev, "Configure SDHCI as DDR52 attribute through cmdline.\n"); -+ } else if (!strncmp(option, "hs200", 5)) { -+ dev_info(&pdev->dev, "Configure SDHCI as HS200 attribute through cmdline.\n"); -+ ; -+ } else if (!strncmp(option, "hs400", 5)) { -+ sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400; -+ dev_info(&pdev->dev, "Configure SDHCI as HS400 attribute through cmdline.\n"); -+ } else { -+ dev_info(&pdev->dev, "CSDHCI: Unknown cmdline option.\n"); -+ return EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int sdhci_pci_probe(struct pci_dev *pdev, -+ const struct pci_device_id *ent) -+{ -+ struct sdhci_pci_chip *chip; -+ struct sdhci_pci_slot *slot; -+ -+ u8 slots, first_bar; -+ int ret, i; -+ -+ BUG_ON(pdev == NULL); -+ BUG_ON(ent == NULL); -+ -+ dev_info(&pdev->dev, "SDHCI controller found [%04x:%04x] (rev %x)\n", -+ (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); -+ -+ /* cmdline setting priority, the kernel parameters can be changed flexibly, -+ * and Bios upgrades are not convenient or secure. */ -+ ret = sdhci_set_quirks2_by_cmdline(pdev); -+ if (ret) { -+ ret = sdhci_set_quirks2_by_dsdt(pdev); -+ if (ret) { -+ sdhci_intel_dnv_emmc.quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400; -+ dev_info(&pdev->dev, "Configure SDHCI as default[HS400].\n"); -+ } -+ } -+ -+ ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots); -+ if (ret) -+ return ret; -+ -+ slots = PCI_SLOT_INFO_SLOTS(slots) + 1; -+ dev_dbg(&pdev->dev, "found %d slot(s)\n", slots); -+ -+ BUG_ON(slots > MAX_SLOTS); -+ -+ ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar); -+ if (ret) -+ return ret; -+ -+ first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK; -+ -+ if (first_bar > 5) { -+ dev_err(&pdev->dev, "Invalid first BAR. Aborting.\n"); -+ return -ENODEV; -+ } -+ -+ ret = pcim_enable_device(pdev); -+ if (ret) -+ return ret; -+ -+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); -+ if (!chip) -+ return -ENOMEM; -+ -+ chip->pdev = pdev; -+ chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data; -+ if (chip->fixes) { -+ chip->quirks = chip->fixes->quirks; -+ chip->quirks2 = chip->fixes->quirks2; -+ chip->allow_runtime_pm = chip->fixes->allow_runtime_pm; -+ } -+ chip->num_slots = slots; -+ chip->pm_retune = true; -+ chip->rpm_retune = true; -+ -+ pci_set_drvdata(pdev, chip); -+ -+ if (chip->fixes && chip->fixes->probe) { -+ ret = chip->fixes->probe(chip); -+ if (ret) -+ return ret; -+ } -+ -+ slots = chip->num_slots; /* Quirk may have changed this */ -+ -+ for (i = 0; i < slots; i++) { -+ slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i); -+ if (IS_ERR(slot)) { -+ for (i--; i >= 0; i--) -+ sdhci_pci_remove_slot(chip->slots[i]); -+ return PTR_ERR(slot); -+ } -+ -+ chip->slots[i] = slot; -+ } -+ -+ if (chip->allow_runtime_pm) -+ sdhci_pci_runtime_pm_allow(&pdev->dev); -+ -+ return 0; -+} -+ -+static void sdhci_pci_remove(struct pci_dev *pdev) -+{ -+ int i; -+ struct sdhci_pci_chip *chip = pci_get_drvdata(pdev); -+ -+ if (chip->allow_runtime_pm) -+ sdhci_pci_runtime_pm_forbid(&pdev->dev); -+ -+ for (i = 0; i < chip->num_slots; i++) -+ sdhci_pci_remove_slot(chip->slots[i]); -+} -+ -+static struct pci_driver sdhci_driver = { -+ .name = "sdhci-pci", -+ .id_table = pci_ids, -+ .probe = sdhci_pci_probe, -+ .remove = sdhci_pci_remove, -+ .driver = { -+ .pm = &sdhci_pci_pm_ops -+ }, -+}; -+ -+module_pci_driver(sdhci_driver); -+ -+MODULE_AUTHOR("Pierre Ossman "); -+MODULE_DESCRIPTION("Secure Digital Host Controller Interface PCI driver"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-dwc-mshc.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-dwc-mshc.c -new file mode 100644 -index 000000000..f78d65448 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-dwc-mshc.c -@@ -0,0 +1,84 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * SDHCI driver for Synopsys DWC_MSHC controller -+ * -+ * Copyright (C) 2018 Synopsys, Inc. (www.synopsys.com) -+ * -+ * Authors: -+ * Prabu Thangamuthu -+ * Manjunath M B -+ */ -+ -+#include "sdhci.h" -+#include "sdhci-pci.h" -+ -+#define SDHCI_VENDOR_PTR_R 0xE8 -+ -+/* Synopsys vendor specific registers */ -+#define SDHC_GPIO_OUT 0x34 -+#define SDHC_AT_CTRL_R 0x40 -+#define SDHC_SW_TUNE_EN 0x00000010 -+ -+/* MMCM DRP */ -+#define SDHC_MMCM_DIV_REG 0x1020 -+#define DIV_REG_100_MHZ 0x1145 -+#define DIV_REG_200_MHZ 0x1083 -+#define SDHC_MMCM_CLKFBOUT 0x1024 -+#define CLKFBOUT_100_MHZ 0x0000 -+#define CLKFBOUT_200_MHZ 0x0080 -+#define SDHC_CCLK_MMCM_RST 0x00000001 -+ -+static void sdhci_snps_set_clock(struct sdhci_host *host, unsigned int clock) -+{ -+ u16 clk; -+ u32 reg, vendor_ptr; -+ -+ vendor_ptr = sdhci_readw(host, SDHCI_VENDOR_PTR_R); -+ -+ /* Disable software managed rx tuning */ -+ reg = sdhci_readl(host, (SDHC_AT_CTRL_R + vendor_ptr)); -+ reg &= ~SDHC_SW_TUNE_EN; -+ sdhci_writel(host, reg, (SDHC_AT_CTRL_R + vendor_ptr)); -+ -+ if (clock <= 52000000) { -+ sdhci_set_clock(host, clock); -+ } else { -+ /* Assert reset to MMCM */ -+ reg = sdhci_readl(host, (SDHC_GPIO_OUT + vendor_ptr)); -+ reg |= SDHC_CCLK_MMCM_RST; -+ sdhci_writel(host, reg, (SDHC_GPIO_OUT + vendor_ptr)); -+ -+ /* Configure MMCM */ -+ if (clock == 100000000) { -+ sdhci_writel(host, DIV_REG_100_MHZ, SDHC_MMCM_DIV_REG); -+ sdhci_writel(host, CLKFBOUT_100_MHZ, -+ SDHC_MMCM_CLKFBOUT); -+ } else { -+ sdhci_writel(host, DIV_REG_200_MHZ, SDHC_MMCM_DIV_REG); -+ sdhci_writel(host, CLKFBOUT_200_MHZ, -+ SDHC_MMCM_CLKFBOUT); -+ } -+ -+ /* De-assert reset to MMCM */ -+ reg = sdhci_readl(host, (SDHC_GPIO_OUT + vendor_ptr)); -+ reg &= ~SDHC_CCLK_MMCM_RST; -+ sdhci_writel(host, reg, (SDHC_GPIO_OUT + vendor_ptr)); -+ -+ /* Enable clock */ -+ clk = SDHCI_PROG_CLOCK_MODE | SDHCI_CLOCK_INT_EN | -+ SDHCI_CLOCK_CARD_EN; -+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); -+ } -+} -+ -+static const struct sdhci_ops sdhci_snps_ops = { -+ .set_clock = sdhci_snps_set_clock, -+ .enable_dma = sdhci_pci_enable_dma, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, -+}; -+ -+const struct sdhci_pci_fixes sdhci_snps = { -+ .ops = &sdhci_snps_ops, -+}; -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-gli.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-gli.c -new file mode 100644 -index 000000000..23b89b4ca ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-gli.c -@@ -0,0 +1,865 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2019 Genesys Logic, Inc. -+ * -+ * Authors: Ben Chuang -+ * -+ * Version: v0.9.0 (2019-08-08) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "sdhci.h" -+#include "sdhci-pci.h" -+#include "cqhci.h" -+ -+/* Genesys Logic extra registers */ -+#define SDHCI_GLI_9750_WT 0x800 -+#define SDHCI_GLI_9750_WT_EN BIT(0) -+#define GLI_9750_WT_EN_ON 0x1 -+#define GLI_9750_WT_EN_OFF 0x0 -+ -+#define SDHCI_GLI_9750_DRIVING 0x860 -+#define SDHCI_GLI_9750_DRIVING_1 GENMASK(11, 0) -+#define SDHCI_GLI_9750_DRIVING_2 GENMASK(27, 26) -+#define GLI_9750_DRIVING_1_VALUE 0xFFF -+#define GLI_9750_DRIVING_2_VALUE 0x3 -+#define SDHCI_GLI_9750_SEL_1 BIT(29) -+#define SDHCI_GLI_9750_SEL_2 BIT(31) -+#define SDHCI_GLI_9750_ALL_RST (BIT(24)|BIT(25)|BIT(28)|BIT(30)) -+ -+#define SDHCI_GLI_9750_PLL 0x864 -+#define SDHCI_GLI_9750_PLL_LDIV GENMASK(9, 0) -+#define SDHCI_GLI_9750_PLL_PDIV GENMASK(14, 12) -+#define SDHCI_GLI_9750_PLL_DIR BIT(15) -+#define SDHCI_GLI_9750_PLL_TX2_INV BIT(23) -+#define SDHCI_GLI_9750_PLL_TX2_DLY GENMASK(22, 20) -+#define GLI_9750_PLL_TX2_INV_VALUE 0x1 -+#define GLI_9750_PLL_TX2_DLY_VALUE 0x0 -+#define SDHCI_GLI_9750_PLLSSC_STEP GENMASK(28, 24) -+#define SDHCI_GLI_9750_PLLSSC_EN BIT(31) -+ -+#define SDHCI_GLI_9750_PLLSSC 0x86C -+#define SDHCI_GLI_9750_PLLSSC_PPM GENMASK(31, 16) -+ -+#define SDHCI_GLI_9750_SW_CTRL 0x874 -+#define SDHCI_GLI_9750_SW_CTRL_4 GENMASK(7, 6) -+#define GLI_9750_SW_CTRL_4_VALUE 0x3 -+ -+#define SDHCI_GLI_9750_MISC 0x878 -+#define SDHCI_GLI_9750_MISC_TX1_INV BIT(2) -+#define SDHCI_GLI_9750_MISC_RX_INV BIT(3) -+#define SDHCI_GLI_9750_MISC_TX1_DLY GENMASK(6, 4) -+#define GLI_9750_MISC_TX1_INV_VALUE 0x0 -+#define GLI_9750_MISC_RX_INV_ON 0x1 -+#define GLI_9750_MISC_RX_INV_OFF 0x0 -+#define GLI_9750_MISC_RX_INV_VALUE GLI_9750_MISC_RX_INV_OFF -+#define GLI_9750_MISC_TX1_DLY_VALUE 0x5 -+ -+#define SDHCI_GLI_9750_TUNING_CONTROL 0x540 -+#define SDHCI_GLI_9750_TUNING_CONTROL_EN BIT(4) -+#define GLI_9750_TUNING_CONTROL_EN_ON 0x1 -+#define GLI_9750_TUNING_CONTROL_EN_OFF 0x0 -+#define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1 BIT(16) -+#define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2 GENMASK(20, 19) -+#define GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE 0x1 -+#define GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE 0x2 -+ -+#define SDHCI_GLI_9750_TUNING_PARAMETERS 0x544 -+#define SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY GENMASK(2, 0) -+#define GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE 0x1 -+ -+#define SDHCI_GLI_9763E_CTRL_HS400 0x7 -+ -+#define SDHCI_GLI_9763E_HS400_ES_REG 0x52C -+#define SDHCI_GLI_9763E_HS400_ES_BIT BIT(8) -+ -+#define PCIE_GLI_9763E_VHS 0x884 -+#define GLI_9763E_VHS_REV GENMASK(19, 16) -+#define GLI_9763E_VHS_REV_R 0x0 -+#define GLI_9763E_VHS_REV_M 0x1 -+#define GLI_9763E_VHS_REV_W 0x2 -+#define PCIE_GLI_9763E_MB 0x888 -+#define GLI_9763E_MB_CMDQ_OFF BIT(19) -+#define PCIE_GLI_9763E_SCR 0x8E0 -+#define GLI_9763E_SCR_AXI_REQ BIT(9) -+ -+#define SDHCI_GLI_9763E_CQE_BASE_ADDR 0x200 -+#define GLI_9763E_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \ -+ SDHCI_TRNS_BLK_CNT_EN | \ -+ SDHCI_TRNS_DMA) -+ -+#define PCI_GLI_9755_WT 0x800 -+#define PCI_GLI_9755_WT_EN BIT(0) -+#define GLI_9755_WT_EN_ON 0x1 -+#define GLI_9755_WT_EN_OFF 0x0 -+ -+#define PCI_GLI_9755_PLL 0x64 -+#define PCI_GLI_9755_PLL_LDIV GENMASK(9, 0) -+#define PCI_GLI_9755_PLL_PDIV GENMASK(14, 12) -+#define PCI_GLI_9755_PLL_DIR BIT(15) -+#define PCI_GLI_9755_PLLSSC_STEP GENMASK(28, 24) -+#define PCI_GLI_9755_PLLSSC_EN BIT(31) -+ -+#define PCI_GLI_9755_PLLSSC 0x68 -+#define PCI_GLI_9755_PLLSSC_PPM GENMASK(15, 0) -+ -+#define GLI_MAX_TUNING_LOOP 40 -+ -+/* Genesys Logic chipset */ -+static inline void gl9750_wt_on(struct sdhci_host *host) -+{ -+ u32 wt_value; -+ u32 wt_enable; -+ -+ wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT); -+ wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value); -+ -+ if (wt_enable == GLI_9750_WT_EN_ON) -+ return; -+ -+ wt_value &= ~SDHCI_GLI_9750_WT_EN; -+ wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_ON); -+ -+ sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT); -+} -+ -+static inline void gl9750_wt_off(struct sdhci_host *host) -+{ -+ u32 wt_value; -+ u32 wt_enable; -+ -+ wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT); -+ wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value); -+ -+ if (wt_enable == GLI_9750_WT_EN_OFF) -+ return; -+ -+ wt_value &= ~SDHCI_GLI_9750_WT_EN; -+ wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_OFF); -+ -+ sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT); -+} -+ -+static void gli_set_9750(struct sdhci_host *host) -+{ -+ u32 driving_value; -+ u32 pll_value; -+ u32 sw_ctrl_value; -+ u32 misc_value; -+ u32 parameter_value; -+ u32 control_value; -+ u16 ctrl2; -+ -+ gl9750_wt_on(host); -+ -+ driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING); -+ pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL); -+ sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL); -+ misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC); -+ parameter_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_PARAMETERS); -+ control_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_CONTROL); -+ -+ driving_value &= ~(SDHCI_GLI_9750_DRIVING_1); -+ driving_value &= ~(SDHCI_GLI_9750_DRIVING_2); -+ driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_1, -+ GLI_9750_DRIVING_1_VALUE); -+ driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_2, -+ GLI_9750_DRIVING_2_VALUE); -+ driving_value &= ~(SDHCI_GLI_9750_SEL_1|SDHCI_GLI_9750_SEL_2|SDHCI_GLI_9750_ALL_RST); -+ driving_value |= SDHCI_GLI_9750_SEL_2; -+ sdhci_writel(host, driving_value, SDHCI_GLI_9750_DRIVING); -+ -+ sw_ctrl_value &= ~SDHCI_GLI_9750_SW_CTRL_4; -+ sw_ctrl_value |= FIELD_PREP(SDHCI_GLI_9750_SW_CTRL_4, -+ GLI_9750_SW_CTRL_4_VALUE); -+ sdhci_writel(host, sw_ctrl_value, SDHCI_GLI_9750_SW_CTRL); -+ -+ /* reset the tuning flow after reinit and before starting tuning */ -+ pll_value &= ~SDHCI_GLI_9750_PLL_TX2_INV; -+ pll_value &= ~SDHCI_GLI_9750_PLL_TX2_DLY; -+ pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_INV, -+ GLI_9750_PLL_TX2_INV_VALUE); -+ pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_DLY, -+ GLI_9750_PLL_TX2_DLY_VALUE); -+ -+ misc_value &= ~SDHCI_GLI_9750_MISC_TX1_INV; -+ misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV; -+ misc_value &= ~SDHCI_GLI_9750_MISC_TX1_DLY; -+ misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_INV, -+ GLI_9750_MISC_TX1_INV_VALUE); -+ misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, -+ GLI_9750_MISC_RX_INV_VALUE); -+ misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_DLY, -+ GLI_9750_MISC_TX1_DLY_VALUE); -+ -+ parameter_value &= ~SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY; -+ parameter_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY, -+ GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE); -+ -+ control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1; -+ control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2; -+ control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1, -+ GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE); -+ control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2, -+ GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE); -+ -+ sdhci_writel(host, pll_value, SDHCI_GLI_9750_PLL); -+ sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC); -+ -+ /* disable tuned clk */ -+ ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); -+ ctrl2 &= ~SDHCI_CTRL_TUNED_CLK; -+ sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); -+ -+ /* enable tuning parameters control */ -+ control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN; -+ control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN, -+ GLI_9750_TUNING_CONTROL_EN_ON); -+ sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL); -+ -+ /* write tuning parameters */ -+ sdhci_writel(host, parameter_value, SDHCI_GLI_9750_TUNING_PARAMETERS); -+ -+ /* disable tuning parameters control */ -+ control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN; -+ control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN, -+ GLI_9750_TUNING_CONTROL_EN_OFF); -+ sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL); -+ -+ /* clear tuned clk */ -+ ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); -+ ctrl2 &= ~SDHCI_CTRL_TUNED_CLK; -+ sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); -+ -+ gl9750_wt_off(host); -+} -+ -+static void gli_set_9750_rx_inv(struct sdhci_host *host, bool b) -+{ -+ u32 misc_value; -+ -+ gl9750_wt_on(host); -+ -+ misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC); -+ misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV; -+ if (b) { -+ misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, -+ GLI_9750_MISC_RX_INV_ON); -+ } else { -+ misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, -+ GLI_9750_MISC_RX_INV_OFF); -+ } -+ sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC); -+ -+ gl9750_wt_off(host); -+} -+ -+static int __sdhci_execute_tuning_9750(struct sdhci_host *host, u32 opcode) -+{ -+ int i; -+ int rx_inv; -+ -+ for (rx_inv = 0; rx_inv < 2; rx_inv++) { -+ gli_set_9750_rx_inv(host, !!rx_inv); -+ sdhci_start_tuning(host); -+ -+ for (i = 0; i < GLI_MAX_TUNING_LOOP; i++) { -+ u16 ctrl; -+ -+ sdhci_send_tuning(host, opcode); -+ -+ if (!host->tuning_done) { -+ sdhci_abort_tuning(host, opcode); -+ break; -+ } -+ -+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); -+ if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { -+ if (ctrl & SDHCI_CTRL_TUNED_CLK) -+ return 0; /* Success! */ -+ break; -+ } -+ } -+ } -+ if (!host->tuning_done) { -+ pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n", -+ mmc_hostname(host->mmc)); -+ return -ETIMEDOUT; -+ } -+ -+ pr_info("%s: Tuning failed, falling back to fixed sampling clock\n", -+ mmc_hostname(host->mmc)); -+ sdhci_reset_tuning(host); -+ -+ return -EAGAIN; -+} -+ -+static int gl9750_execute_tuning(struct sdhci_host *host, u32 opcode) -+{ -+ host->mmc->retune_period = 0; -+ if (host->tuning_mode == SDHCI_TUNING_MODE_1) -+ host->mmc->retune_period = host->tuning_count; -+ -+ gli_set_9750(host); -+ host->tuning_err = __sdhci_execute_tuning_9750(host, opcode); -+ sdhci_end_tuning(host); -+ -+ return 0; -+} -+ -+static void gl9750_disable_ssc_pll(struct sdhci_host *host) -+{ -+ u32 pll; -+ -+ gl9750_wt_on(host); -+ pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); -+ pll &= ~(SDHCI_GLI_9750_PLL_DIR | SDHCI_GLI_9750_PLLSSC_EN); -+ sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); -+ gl9750_wt_off(host); -+} -+ -+static void gl9750_set_pll(struct sdhci_host *host, u8 dir, u16 ldiv, u8 pdiv) -+{ -+ u32 pll; -+ -+ gl9750_wt_on(host); -+ pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); -+ pll &= ~(SDHCI_GLI_9750_PLL_LDIV | -+ SDHCI_GLI_9750_PLL_PDIV | -+ SDHCI_GLI_9750_PLL_DIR); -+ pll |= FIELD_PREP(SDHCI_GLI_9750_PLL_LDIV, ldiv) | -+ FIELD_PREP(SDHCI_GLI_9750_PLL_PDIV, pdiv) | -+ FIELD_PREP(SDHCI_GLI_9750_PLL_DIR, dir); -+ sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); -+ gl9750_wt_off(host); -+ -+ /* wait for pll stable */ -+ mdelay(1); -+} -+ -+static void gl9750_set_ssc(struct sdhci_host *host, u8 enable, u8 step, u16 ppm) -+{ -+ u32 pll; -+ u32 ssc; -+ -+ gl9750_wt_on(host); -+ pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); -+ ssc = sdhci_readl(host, SDHCI_GLI_9750_PLLSSC); -+ pll &= ~(SDHCI_GLI_9750_PLLSSC_STEP | -+ SDHCI_GLI_9750_PLLSSC_EN); -+ ssc &= ~SDHCI_GLI_9750_PLLSSC_PPM; -+ pll |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_STEP, step) | -+ FIELD_PREP(SDHCI_GLI_9750_PLLSSC_EN, enable); -+ ssc |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_PPM, ppm); -+ sdhci_writel(host, ssc, SDHCI_GLI_9750_PLLSSC); -+ sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); -+ gl9750_wt_off(host); -+} -+ -+static void gl9750_set_ssc_pll_205mhz(struct sdhci_host *host) -+{ -+ /* set pll to 205MHz and enable ssc */ -+ gl9750_set_ssc(host, 0x1, 0x1F, 0xFFE7); -+ gl9750_set_pll(host, 0x1, 0x246, 0x0); -+} -+ -+static void sdhci_gl9750_set_clock(struct sdhci_host *host, unsigned int clock) -+{ -+ struct mmc_ios *ios = &host->mmc->ios; -+ u16 clk; -+ -+ host->mmc->actual_clock = 0; -+ -+ gl9750_disable_ssc_pll(host); -+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); -+ -+ if (clock == 0) -+ return; -+ -+ clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); -+ if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) { -+ host->mmc->actual_clock = 205000000; -+ gl9750_set_ssc_pll_205mhz(host); -+ } -+ -+ sdhci_enable_clk(host, clk); -+} -+ -+static void gli_pcie_enable_msi(struct sdhci_pci_slot *slot) -+{ -+ int ret; -+ -+ ret = pci_alloc_irq_vectors(slot->chip->pdev, 1, 1, -+ PCI_IRQ_MSI | PCI_IRQ_MSIX); -+ if (ret < 0) { -+ pr_warn("%s: enable PCI MSI failed, error=%d\n", -+ mmc_hostname(slot->host->mmc), ret); -+ return; -+ } -+ -+ slot->host->irq = pci_irq_vector(slot->chip->pdev, 0); -+} -+ -+static inline void gl9755_wt_on(struct pci_dev *pdev) -+{ -+ u32 wt_value; -+ u32 wt_enable; -+ -+ pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value); -+ wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value); -+ -+ if (wt_enable == GLI_9755_WT_EN_ON) -+ return; -+ -+ wt_value &= ~PCI_GLI_9755_WT_EN; -+ wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_ON); -+ -+ pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value); -+} -+ -+static inline void gl9755_wt_off(struct pci_dev *pdev) -+{ -+ u32 wt_value; -+ u32 wt_enable; -+ -+ pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value); -+ wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value); -+ -+ if (wt_enable == GLI_9755_WT_EN_OFF) -+ return; -+ -+ wt_value &= ~PCI_GLI_9755_WT_EN; -+ wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_OFF); -+ -+ pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value); -+} -+ -+static void gl9755_disable_ssc_pll(struct pci_dev *pdev) -+{ -+ u32 pll; -+ -+ gl9755_wt_on(pdev); -+ pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); -+ pll &= ~(PCI_GLI_9755_PLL_DIR | PCI_GLI_9755_PLLSSC_EN); -+ pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); -+ gl9755_wt_off(pdev); -+} -+ -+static void gl9755_set_pll(struct pci_dev *pdev, u8 dir, u16 ldiv, u8 pdiv) -+{ -+ u32 pll; -+ -+ gl9755_wt_on(pdev); -+ pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); -+ pll &= ~(PCI_GLI_9755_PLL_LDIV | -+ PCI_GLI_9755_PLL_PDIV | -+ PCI_GLI_9755_PLL_DIR); -+ pll |= FIELD_PREP(PCI_GLI_9755_PLL_LDIV, ldiv) | -+ FIELD_PREP(PCI_GLI_9755_PLL_PDIV, pdiv) | -+ FIELD_PREP(PCI_GLI_9755_PLL_DIR, dir); -+ pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); -+ gl9755_wt_off(pdev); -+ -+ /* wait for pll stable */ -+ mdelay(1); -+} -+ -+static void gl9755_set_ssc(struct pci_dev *pdev, u8 enable, u8 step, u16 ppm) -+{ -+ u32 pll; -+ u32 ssc; -+ -+ gl9755_wt_on(pdev); -+ pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); -+ pci_read_config_dword(pdev, PCI_GLI_9755_PLLSSC, &ssc); -+ pll &= ~(PCI_GLI_9755_PLLSSC_STEP | -+ PCI_GLI_9755_PLLSSC_EN); -+ ssc &= ~PCI_GLI_9755_PLLSSC_PPM; -+ pll |= FIELD_PREP(PCI_GLI_9755_PLLSSC_STEP, step) | -+ FIELD_PREP(PCI_GLI_9755_PLLSSC_EN, enable); -+ ssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_PPM, ppm); -+ pci_write_config_dword(pdev, PCI_GLI_9755_PLLSSC, ssc); -+ pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); -+ gl9755_wt_off(pdev); -+} -+ -+static void gl9755_set_ssc_pll_205mhz(struct pci_dev *pdev) -+{ -+ /* set pll to 205MHz and enable ssc */ -+ gl9755_set_ssc(pdev, 0x1, 0x1F, 0xFFE7); -+ gl9755_set_pll(pdev, 0x1, 0x246, 0x0); -+} -+ -+static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock) -+{ -+ struct sdhci_pci_slot *slot = sdhci_priv(host); -+ struct mmc_ios *ios = &host->mmc->ios; -+ struct pci_dev *pdev; -+ u16 clk; -+ -+ pdev = slot->chip->pdev; -+ host->mmc->actual_clock = 0; -+ -+ gl9755_disable_ssc_pll(pdev); -+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); -+ -+ if (clock == 0) -+ return; -+ -+ clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); -+ if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) { -+ host->mmc->actual_clock = 205000000; -+ gl9755_set_ssc_pll_205mhz(pdev); -+ } -+ -+ sdhci_enable_clk(host, clk); -+} -+ -+static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot) -+{ -+ struct sdhci_host *host = slot->host; -+ -+ gli_pcie_enable_msi(slot); -+ slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO; -+ sdhci_enable_v4_mode(host); -+ -+ return 0; -+} -+ -+static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot) -+{ -+ struct sdhci_host *host = slot->host; -+ -+ gli_pcie_enable_msi(slot); -+ slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO; -+ sdhci_enable_v4_mode(host); -+ -+ return 0; -+} -+ -+static void sdhci_gli_voltage_switch(struct sdhci_host *host) -+{ -+ /* -+ * According to Section 3.6.1 signal voltage switch procedure in -+ * SD Host Controller Simplified Spec. 4.20, steps 6~8 are as -+ * follows: -+ * (6) Set 1.8V Signal Enable in the Host Control 2 register. -+ * (7) Wait 5ms. 1.8V voltage regulator shall be stable within this -+ * period. -+ * (8) If 1.8V Signal Enable is cleared by Host Controller, go to -+ * step (12). -+ * -+ * Wait 5ms after set 1.8V signal enable in Host Control 2 register -+ * to ensure 1.8V signal enable bit is set by GL9750/GL9755. -+ * -+ * ...however, the controller in the NUC10i3FNK4 (a 9755) requires -+ * slightly longer than 5ms before the control register reports that -+ * 1.8V is ready, and far longer still before the card will actually -+ * work reliably. -+ */ -+ usleep_range(100000, 110000); -+} -+ -+static void sdhci_gl9750_reset(struct sdhci_host *host, u8 mask) -+{ -+ sdhci_reset(host, mask); -+ gli_set_9750(host); -+} -+ -+static u32 sdhci_gl9750_readl(struct sdhci_host *host, int reg) -+{ -+ u32 value; -+ -+ value = readl(host->ioaddr + reg); -+ if (unlikely(reg == SDHCI_MAX_CURRENT && !(value & 0xff))) -+ value |= 0xc8; -+ -+ return value; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip) -+{ -+ struct sdhci_pci_slot *slot = chip->slots[0]; -+ -+ pci_free_irq_vectors(slot->chip->pdev); -+ gli_pcie_enable_msi(slot); -+ -+ return sdhci_pci_resume_host(chip); -+} -+ -+static int sdhci_cqhci_gli_resume(struct sdhci_pci_chip *chip) -+{ -+ struct sdhci_pci_slot *slot = chip->slots[0]; -+ int ret; -+ -+ ret = sdhci_pci_gli_resume(chip); -+ if (ret) -+ return ret; -+ -+ return cqhci_resume(slot->host->mmc); -+} -+ -+static int sdhci_cqhci_gli_suspend(struct sdhci_pci_chip *chip) -+{ -+ struct sdhci_pci_slot *slot = chip->slots[0]; -+ int ret; -+ -+ ret = cqhci_suspend(slot->host->mmc); -+ if (ret) -+ return ret; -+ -+ return sdhci_suspend_host(slot->host); -+} -+#endif -+ -+static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc, -+ struct mmc_ios *ios) -+{ -+ struct sdhci_host *host = mmc_priv(mmc); -+ u32 val; -+ -+ val = sdhci_readl(host, SDHCI_GLI_9763E_HS400_ES_REG); -+ if (ios->enhanced_strobe) -+ val |= SDHCI_GLI_9763E_HS400_ES_BIT; -+ else -+ val &= ~SDHCI_GLI_9763E_HS400_ES_BIT; -+ -+ sdhci_writel(host, val, SDHCI_GLI_9763E_HS400_ES_REG); -+} -+ -+static void sdhci_set_gl9763e_signaling(struct sdhci_host *host, -+ unsigned int timing) -+{ -+ u16 ctrl_2; -+ -+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); -+ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; -+ if (timing == MMC_TIMING_MMC_HS200) -+ ctrl_2 |= SDHCI_CTRL_UHS_SDR104; -+ else if (timing == MMC_TIMING_MMC_HS) -+ ctrl_2 |= SDHCI_CTRL_UHS_SDR25; -+ else if (timing == MMC_TIMING_MMC_DDR52) -+ ctrl_2 |= SDHCI_CTRL_UHS_DDR50; -+ else if (timing == MMC_TIMING_MMC_HS400) -+ ctrl_2 |= SDHCI_GLI_9763E_CTRL_HS400; -+ -+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); -+} -+ -+static void sdhci_gl9763e_dumpregs(struct mmc_host *mmc) -+{ -+ sdhci_dumpregs(mmc_priv(mmc)); -+} -+ -+static void sdhci_gl9763e_cqe_pre_enable(struct mmc_host *mmc) -+{ -+ struct cqhci_host *cq_host = mmc->cqe_private; -+ u32 value; -+ -+ value = cqhci_readl(cq_host, CQHCI_CFG); -+ value |= CQHCI_ENABLE; -+ cqhci_writel(cq_host, value, CQHCI_CFG); -+} -+ -+static void sdhci_gl9763e_cqe_enable(struct mmc_host *mmc) -+{ -+ struct sdhci_host *host = mmc_priv(mmc); -+ -+ sdhci_writew(host, GLI_9763E_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE); -+ sdhci_cqe_enable(mmc); -+} -+ -+static u32 sdhci_gl9763e_cqhci_irq(struct sdhci_host *host, u32 intmask) -+{ -+ int cmd_error = 0; -+ int data_error = 0; -+ -+ if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) -+ return intmask; -+ -+ cqhci_irq(host->mmc, intmask, cmd_error, data_error); -+ -+ return 0; -+} -+ -+static void sdhci_gl9763e_cqe_post_disable(struct mmc_host *mmc) -+{ -+ struct sdhci_host *host = mmc_priv(mmc); -+ struct cqhci_host *cq_host = mmc->cqe_private; -+ u32 value; -+ -+ value = cqhci_readl(cq_host, CQHCI_CFG); -+ value &= ~CQHCI_ENABLE; -+ cqhci_writel(cq_host, value, CQHCI_CFG); -+ sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE); -+} -+ -+static const struct cqhci_host_ops sdhci_gl9763e_cqhci_ops = { -+ .enable = sdhci_gl9763e_cqe_enable, -+ .disable = sdhci_cqe_disable, -+ .dumpregs = sdhci_gl9763e_dumpregs, -+ .pre_enable = sdhci_gl9763e_cqe_pre_enable, -+ .post_disable = sdhci_gl9763e_cqe_post_disable, -+}; -+ -+static int gl9763e_add_host(struct sdhci_pci_slot *slot) -+{ -+ struct device *dev = &slot->chip->pdev->dev; -+ struct sdhci_host *host = slot->host; -+ struct cqhci_host *cq_host; -+ bool dma64; -+ int ret; -+ -+ ret = sdhci_setup_host(host); -+ if (ret) -+ return ret; -+ -+ cq_host = devm_kzalloc(dev, sizeof(*cq_host), GFP_KERNEL); -+ if (!cq_host) { -+ ret = -ENOMEM; -+ goto cleanup; -+ } -+ -+ cq_host->mmio = host->ioaddr + SDHCI_GLI_9763E_CQE_BASE_ADDR; -+ cq_host->ops = &sdhci_gl9763e_cqhci_ops; -+ -+ dma64 = host->flags & SDHCI_USE_64_BIT_DMA; -+ if (dma64) -+ cq_host->caps |= CQHCI_TASK_DESC_SZ_128; -+ -+ ret = cqhci_init(cq_host, host->mmc, dma64); -+ if (ret) -+ goto cleanup; -+ -+ ret = __sdhci_add_host(host); -+ if (ret) -+ goto cleanup; -+ -+ return 0; -+ -+cleanup: -+ sdhci_cleanup_host(host); -+ return ret; -+} -+ -+static void sdhci_gl9763e_reset(struct sdhci_host *host, u8 mask) -+{ -+ if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) && -+ host->mmc->cqe_private) -+ cqhci_deactivate(host->mmc); -+ sdhci_reset(host, mask); -+} -+ -+static void gli_set_gl9763e(struct sdhci_pci_slot *slot) -+{ -+ struct pci_dev *pdev = slot->chip->pdev; -+ u32 value; -+ -+ pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); -+ value &= ~GLI_9763E_VHS_REV; -+ value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_W); -+ pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); -+ -+ pci_read_config_dword(pdev, PCIE_GLI_9763E_SCR, &value); -+ value |= GLI_9763E_SCR_AXI_REQ; -+ pci_write_config_dword(pdev, PCIE_GLI_9763E_SCR, value); -+ -+ pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); -+ value &= ~GLI_9763E_VHS_REV; -+ value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R); -+ pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); -+} -+ -+static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot) -+{ -+ struct pci_dev *pdev = slot->chip->pdev; -+ struct sdhci_host *host = slot->host; -+ u32 value; -+ -+ host->mmc->caps |= MMC_CAP_8_BIT_DATA | -+ MMC_CAP_1_8V_DDR | -+ MMC_CAP_NONREMOVABLE; -+ host->mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR | -+ MMC_CAP2_HS400_1_8V | -+ MMC_CAP2_HS400_ES | -+ MMC_CAP2_NO_SDIO | -+ MMC_CAP2_NO_SD; -+ -+ pci_read_config_dword(pdev, PCIE_GLI_9763E_MB, &value); -+ if (!(value & GLI_9763E_MB_CMDQ_OFF)) -+ host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; -+ -+ gli_pcie_enable_msi(slot); -+ host->mmc_host_ops.hs400_enhanced_strobe = -+ gl9763e_hs400_enhanced_strobe; -+ gli_set_gl9763e(slot); -+ sdhci_enable_v4_mode(host); -+ -+ return 0; -+} -+ -+static const struct sdhci_ops sdhci_gl9755_ops = { -+ .set_clock = sdhci_gl9755_set_clock, -+ .enable_dma = sdhci_pci_enable_dma, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, -+ .voltage_switch = sdhci_gli_voltage_switch, -+}; -+ -+const struct sdhci_pci_fixes sdhci_gl9755 = { -+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, -+ .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, -+ .probe_slot = gli_probe_slot_gl9755, -+ .ops = &sdhci_gl9755_ops, -+#ifdef CONFIG_PM_SLEEP -+ .resume = sdhci_pci_gli_resume, -+#endif -+}; -+ -+static const struct sdhci_ops sdhci_gl9750_ops = { -+ .read_l = sdhci_gl9750_readl, -+ .set_clock = sdhci_gl9750_set_clock, -+ .enable_dma = sdhci_pci_enable_dma, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_gl9750_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, -+ .voltage_switch = sdhci_gli_voltage_switch, -+ .platform_execute_tuning = gl9750_execute_tuning, -+}; -+ -+const struct sdhci_pci_fixes sdhci_gl9750 = { -+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, -+ .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, -+ .probe_slot = gli_probe_slot_gl9750, -+ .ops = &sdhci_gl9750_ops, -+#ifdef CONFIG_PM_SLEEP -+ .resume = sdhci_pci_gli_resume, -+#endif -+}; -+ -+static const struct sdhci_ops sdhci_gl9763e_ops = { -+ .set_clock = sdhci_set_clock, -+ .enable_dma = sdhci_pci_enable_dma, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_gl9763e_reset, -+ .set_uhs_signaling = sdhci_set_gl9763e_signaling, -+ .voltage_switch = sdhci_gli_voltage_switch, -+ .irq = sdhci_gl9763e_cqhci_irq, -+}; -+ -+const struct sdhci_pci_fixes sdhci_gl9763e = { -+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, -+ .probe_slot = gli_probe_slot_gl9763e, -+ .ops = &sdhci_gl9763e_ops, -+#ifdef CONFIG_PM_SLEEP -+ .resume = sdhci_cqhci_gli_resume, -+ .suspend = sdhci_cqhci_gli_suspend, -+#endif -+ .add_host = gl9763e_add_host, -+}; -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-o2micro.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-o2micro.c -new file mode 100644 -index 000000000..94e3f72f6 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci-o2micro.c -@@ -0,0 +1,862 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Copyright (C) 2013 BayHub Technology Ltd. -+ * -+ * Authors: Peter Guo -+ * Adam Lee -+ * Ernest Zhang -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "sdhci.h" -+#include "sdhci-pci.h" -+ -+/* -+ * O2Micro device registers -+ */ -+ -+#define O2_SD_MISC_REG5 0x64 -+#define O2_SD_LD0_CTRL 0x68 -+#define O2_SD_DEV_CTRL 0x88 -+#define O2_SD_LOCK_WP 0xD3 -+#define O2_SD_TEST_REG 0xD4 -+#define O2_SD_FUNC_REG0 0xDC -+#define O2_SD_MULTI_VCC3V 0xEE -+#define O2_SD_CLKREQ 0xEC -+#define O2_SD_CAPS 0xE0 -+#define O2_SD_ADMA1 0xE2 -+#define O2_SD_ADMA2 0xE7 -+#define O2_SD_INF_MOD 0xF1 -+#define O2_SD_MISC_CTRL4 0xFC -+#define O2_SD_MISC_CTRL 0x1C0 -+#define O2_SD_PWR_FORCE_L0 0x0002 -+#define O2_SD_TUNING_CTRL 0x300 -+#define O2_SD_PLL_SETTING 0x304 -+#define O2_SD_MISC_SETTING 0x308 -+#define O2_SD_CLK_SETTING 0x328 -+#define O2_SD_CAP_REG2 0x330 -+#define O2_SD_CAP_REG0 0x334 -+#define O2_SD_UHS1_CAP_SETTING 0x33C -+#define O2_SD_DELAY_CTRL 0x350 -+#define O2_SD_UHS2_L1_CTRL 0x35C -+#define O2_SD_FUNC_REG3 0x3E0 -+#define O2_SD_FUNC_REG4 0x3E4 -+#define O2_SD_LED_ENABLE BIT(6) -+#define O2_SD_FREG0_LEDOFF BIT(13) -+#define O2_SD_FREG4_ENABLE_CLK_SET BIT(22) -+ -+#define O2_SD_VENDOR_SETTING 0x110 -+#define O2_SD_VENDOR_SETTING2 0x1C8 -+#define O2_SD_HW_TUNING_DISABLE BIT(4) -+ -+#define O2_PLL_DLL_WDT_CONTROL1 0x1CC -+#define O2_PLL_FORCE_ACTIVE BIT(18) -+#define O2_PLL_LOCK_STATUS BIT(14) -+#define O2_PLL_SOFT_RESET BIT(12) -+#define O2_DLL_LOCK_STATUS BIT(11) -+ -+#define O2_SD_DETECT_SETTING 0x324 -+ -+static const u32 dmdn_table[] = {0x2B1C0000, -+ 0x2C1A0000, 0x371B0000, 0x35100000}; -+#define DMDN_SZ ARRAY_SIZE(dmdn_table) -+ -+struct o2_host { -+ u8 dll_adjust_count; -+}; -+ -+static void sdhci_o2_wait_card_detect_stable(struct sdhci_host *host) -+{ -+ ktime_t timeout; -+ u32 scratch32; -+ -+ /* Wait max 50 ms */ -+ timeout = ktime_add_ms(ktime_get(), 50); -+ while (1) { -+ bool timedout = ktime_after(ktime_get(), timeout); -+ -+ scratch32 = sdhci_readl(host, SDHCI_PRESENT_STATE); -+ if ((scratch32 & SDHCI_CARD_PRESENT) >> SDHCI_CARD_PRES_SHIFT -+ == (scratch32 & SDHCI_CD_LVL) >> SDHCI_CD_LVL_SHIFT) -+ break; -+ -+ if (timedout) { -+ pr_err("%s: Card Detect debounce never finished.\n", -+ mmc_hostname(host->mmc)); -+ sdhci_dumpregs(host); -+ return; -+ } -+ udelay(10); -+ } -+} -+ -+static void sdhci_o2_enable_internal_clock(struct sdhci_host *host) -+{ -+ ktime_t timeout; -+ u16 scratch; -+ u32 scratch32; -+ -+ /* PLL software reset */ -+ scratch32 = sdhci_readl(host, O2_PLL_DLL_WDT_CONTROL1); -+ scratch32 |= O2_PLL_SOFT_RESET; -+ sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); -+ udelay(1); -+ scratch32 &= ~(O2_PLL_SOFT_RESET); -+ sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); -+ -+ /* PLL force active */ -+ scratch32 |= O2_PLL_FORCE_ACTIVE; -+ sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); -+ -+ /* Wait max 20 ms */ -+ timeout = ktime_add_ms(ktime_get(), 20); -+ while (1) { -+ bool timedout = ktime_after(ktime_get(), timeout); -+ -+ scratch = sdhci_readw(host, O2_PLL_DLL_WDT_CONTROL1); -+ if (scratch & O2_PLL_LOCK_STATUS) -+ break; -+ if (timedout) { -+ pr_err("%s: Internal clock never stabilised.\n", -+ mmc_hostname(host->mmc)); -+ sdhci_dumpregs(host); -+ goto out; -+ } -+ udelay(10); -+ } -+ -+ /* Wait for card detect finish */ -+ udelay(1); -+ sdhci_o2_wait_card_detect_stable(host); -+ -+out: -+ /* Cancel PLL force active */ -+ scratch32 = sdhci_readl(host, O2_PLL_DLL_WDT_CONTROL1); -+ scratch32 &= ~O2_PLL_FORCE_ACTIVE; -+ sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); -+} -+ -+static int sdhci_o2_get_cd(struct mmc_host *mmc) -+{ -+ struct sdhci_host *host = mmc_priv(mmc); -+ -+ if (!(sdhci_readw(host, O2_PLL_DLL_WDT_CONTROL1) & O2_PLL_LOCK_STATUS)) -+ sdhci_o2_enable_internal_clock(host); -+ -+ return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); -+} -+ -+static void o2_pci_set_baseclk(struct sdhci_pci_chip *chip, u32 value) -+{ -+ u32 scratch_32; -+ -+ pci_read_config_dword(chip->pdev, -+ O2_SD_PLL_SETTING, &scratch_32); -+ -+ scratch_32 &= 0x0000FFFF; -+ scratch_32 |= value; -+ -+ pci_write_config_dword(chip->pdev, -+ O2_SD_PLL_SETTING, scratch_32); -+} -+ -+static u32 sdhci_o2_pll_dll_wdt_control(struct sdhci_host *host) -+{ -+ return sdhci_readl(host, O2_PLL_DLL_WDT_CONTROL1); -+} -+ -+/* -+ * This function is used to detect dll lock status. -+ * Since the dll lock status bit will toggle randomly -+ * with very short interval which needs to be polled -+ * as fast as possible. Set sleep_us as 1 microsecond. -+ */ -+static int sdhci_o2_wait_dll_detect_lock(struct sdhci_host *host) -+{ -+ u32 scratch32 = 0; -+ -+ return readx_poll_timeout(sdhci_o2_pll_dll_wdt_control, host, -+ scratch32, !(scratch32 & O2_DLL_LOCK_STATUS), 1, 1000000); -+} -+ -+static void sdhci_o2_set_tuning_mode(struct sdhci_host *host) -+{ -+ u16 reg; -+ -+ /* enable hardware tuning */ -+ reg = sdhci_readw(host, O2_SD_VENDOR_SETTING); -+ reg &= ~O2_SD_HW_TUNING_DISABLE; -+ sdhci_writew(host, reg, O2_SD_VENDOR_SETTING); -+} -+ -+static void __sdhci_o2_execute_tuning(struct sdhci_host *host, u32 opcode) -+{ -+ int i; -+ -+ sdhci_send_tuning(host, opcode); -+ -+ for (i = 0; i < 150; i++) { -+ u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); -+ -+ if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { -+ if (ctrl & SDHCI_CTRL_TUNED_CLK) { -+ host->tuning_done = true; -+ return; -+ } -+ pr_warn("%s: HW tuning failed !\n", -+ mmc_hostname(host->mmc)); -+ break; -+ } -+ -+ mdelay(1); -+ } -+ -+ pr_info("%s: Tuning failed, falling back to fixed sampling clock\n", -+ mmc_hostname(host->mmc)); -+ sdhci_reset_tuning(host); -+} -+ -+/* -+ * This function is used to fix o2 dll shift issue. -+ * It isn't necessary to detect card present before recovery. -+ * Firstly, it is used by bht emmc card, which is embedded. -+ * Second, before call recovery card present will be detected -+ * outside of the execute tuning function. -+ */ -+static int sdhci_o2_dll_recovery(struct sdhci_host *host) -+{ -+ int ret = 0; -+ u8 scratch_8 = 0; -+ u32 scratch_32 = 0; -+ struct sdhci_pci_slot *slot = sdhci_priv(host); -+ struct sdhci_pci_chip *chip = slot->chip; -+ struct o2_host *o2_host = sdhci_pci_priv(slot); -+ -+ /* UnLock WP */ -+ pci_read_config_byte(chip->pdev, -+ O2_SD_LOCK_WP, &scratch_8); -+ scratch_8 &= 0x7f; -+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8); -+ while (o2_host->dll_adjust_count < DMDN_SZ && !ret) { -+ /* Disable clock */ -+ sdhci_writeb(host, 0, SDHCI_CLOCK_CONTROL); -+ -+ /* PLL software reset */ -+ scratch_32 = sdhci_readl(host, O2_PLL_DLL_WDT_CONTROL1); -+ scratch_32 |= O2_PLL_SOFT_RESET; -+ sdhci_writel(host, scratch_32, O2_PLL_DLL_WDT_CONTROL1); -+ -+ pci_read_config_dword(chip->pdev, -+ O2_SD_FUNC_REG4, -+ &scratch_32); -+ /* Enable Base Clk setting change */ -+ scratch_32 |= O2_SD_FREG4_ENABLE_CLK_SET; -+ pci_write_config_dword(chip->pdev, O2_SD_FUNC_REG4, scratch_32); -+ o2_pci_set_baseclk(chip, dmdn_table[o2_host->dll_adjust_count]); -+ -+ /* Enable internal clock */ -+ scratch_8 = SDHCI_CLOCK_INT_EN; -+ sdhci_writeb(host, scratch_8, SDHCI_CLOCK_CONTROL); -+ -+ if (sdhci_o2_get_cd(host->mmc)) { -+ /* -+ * need wait at least 5ms for dll status stable, -+ * after enable internal clock -+ */ -+ usleep_range(5000, 6000); -+ if (sdhci_o2_wait_dll_detect_lock(host)) { -+ scratch_8 |= SDHCI_CLOCK_CARD_EN; -+ sdhci_writeb(host, scratch_8, -+ SDHCI_CLOCK_CONTROL); -+ ret = 1; -+ } else { -+ pr_warn("%s: DLL unlocked when dll_adjust_count is %d.\n", -+ mmc_hostname(host->mmc), -+ o2_host->dll_adjust_count); -+ } -+ } else { -+ pr_err("%s: card present detect failed.\n", -+ mmc_hostname(host->mmc)); -+ break; -+ } -+ -+ o2_host->dll_adjust_count++; -+ } -+ if (!ret && o2_host->dll_adjust_count == DMDN_SZ) -+ pr_err("%s: DLL adjust over max times\n", -+ mmc_hostname(host->mmc)); -+ /* Lock WP */ -+ pci_read_config_byte(chip->pdev, -+ O2_SD_LOCK_WP, &scratch_8); -+ scratch_8 |= 0x80; -+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8); -+ return ret; -+} -+ -+static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode) -+{ -+ struct sdhci_host *host = mmc_priv(mmc); -+ int current_bus_width = 0; -+ u32 scratch32 = 0; -+ u16 scratch = 0; -+ -+ /* -+ * This handler only implements the eMMC tuning that is specific to -+ * this controller. Fall back to the standard method for other TIMING. -+ */ -+ if ((host->timing != MMC_TIMING_MMC_HS200) && -+ (host->timing != MMC_TIMING_UHS_SDR104)) -+ return sdhci_execute_tuning(mmc, opcode); -+ -+ if (WARN_ON((opcode != MMC_SEND_TUNING_BLOCK_HS200) && -+ (opcode != MMC_SEND_TUNING_BLOCK))) -+ return -EINVAL; -+ -+ /* Force power mode enter L0 */ -+ scratch = sdhci_readw(host, O2_SD_MISC_CTRL); -+ scratch |= O2_SD_PWR_FORCE_L0; -+ sdhci_writew(host, scratch, O2_SD_MISC_CTRL); -+ -+ /* wait DLL lock, timeout value 5ms */ -+ if (readx_poll_timeout(sdhci_o2_pll_dll_wdt_control, host, -+ scratch32, (scratch32 & O2_DLL_LOCK_STATUS), 1, 5000)) -+ pr_warn("%s: DLL can't lock in 5ms after force L0 during tuning.\n", -+ mmc_hostname(host->mmc)); -+ /* -+ * Judge the tuning reason, whether caused by dll shift -+ * If cause by dll shift, should call sdhci_o2_dll_recovery -+ */ -+ if (!sdhci_o2_wait_dll_detect_lock(host)) -+ if (!sdhci_o2_dll_recovery(host)) { -+ pr_err("%s: o2 dll recovery failed\n", -+ mmc_hostname(host->mmc)); -+ return -EINVAL; -+ } -+ /* -+ * o2 sdhci host didn't support 8bit emmc tuning -+ */ -+ if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) { -+ current_bus_width = mmc->ios.bus_width; -+ mmc->ios.bus_width = MMC_BUS_WIDTH_4; -+ sdhci_set_bus_width(host, MMC_BUS_WIDTH_4); -+ } -+ -+ sdhci_o2_set_tuning_mode(host); -+ -+ sdhci_start_tuning(host); -+ -+ __sdhci_o2_execute_tuning(host, opcode); -+ -+ sdhci_end_tuning(host); -+ -+ if (current_bus_width == MMC_BUS_WIDTH_8) { -+ mmc->ios.bus_width = MMC_BUS_WIDTH_8; -+ sdhci_set_bus_width(host, current_bus_width); -+ } -+ -+ /* Cancel force power mode enter L0 */ -+ scratch = sdhci_readw(host, O2_SD_MISC_CTRL); -+ scratch &= ~(O2_SD_PWR_FORCE_L0); -+ sdhci_writew(host, scratch, O2_SD_MISC_CTRL); -+ -+ sdhci_reset(host, SDHCI_RESET_CMD); -+ sdhci_reset(host, SDHCI_RESET_DATA); -+ -+ host->flags &= ~SDHCI_HS400_TUNING; -+ return 0; -+} -+ -+static void o2_pci_led_enable(struct sdhci_pci_chip *chip) -+{ -+ int ret; -+ u32 scratch_32; -+ -+ /* Set led of SD host function enable */ -+ ret = pci_read_config_dword(chip->pdev, -+ O2_SD_FUNC_REG0, &scratch_32); -+ if (ret) -+ return; -+ -+ scratch_32 &= ~O2_SD_FREG0_LEDOFF; -+ pci_write_config_dword(chip->pdev, -+ O2_SD_FUNC_REG0, scratch_32); -+ -+ ret = pci_read_config_dword(chip->pdev, -+ O2_SD_TEST_REG, &scratch_32); -+ if (ret) -+ return; -+ -+ scratch_32 |= O2_SD_LED_ENABLE; -+ pci_write_config_dword(chip->pdev, -+ O2_SD_TEST_REG, scratch_32); -+} -+ -+static void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip) -+{ -+ u32 scratch_32; -+ int ret; -+ /* Improve write performance for SD3.0 */ -+ ret = pci_read_config_dword(chip->pdev, O2_SD_DEV_CTRL, &scratch_32); -+ if (ret) -+ return; -+ scratch_32 &= ~((1 << 12) | (1 << 13) | (1 << 14)); -+ pci_write_config_dword(chip->pdev, O2_SD_DEV_CTRL, scratch_32); -+ -+ /* Enable Link abnormal reset generating Reset */ -+ ret = pci_read_config_dword(chip->pdev, O2_SD_MISC_REG5, &scratch_32); -+ if (ret) -+ return; -+ scratch_32 &= ~((1 << 19) | (1 << 11)); -+ scratch_32 |= (1 << 10); -+ pci_write_config_dword(chip->pdev, O2_SD_MISC_REG5, scratch_32); -+ -+ /* set card power over current protection */ -+ ret = pci_read_config_dword(chip->pdev, O2_SD_TEST_REG, &scratch_32); -+ if (ret) -+ return; -+ scratch_32 |= (1 << 4); -+ pci_write_config_dword(chip->pdev, O2_SD_TEST_REG, scratch_32); -+ -+ /* adjust the output delay for SD mode */ -+ pci_write_config_dword(chip->pdev, O2_SD_DELAY_CTRL, 0x00002492); -+ -+ /* Set the output voltage setting of Aux 1.2v LDO */ -+ ret = pci_read_config_dword(chip->pdev, O2_SD_LD0_CTRL, &scratch_32); -+ if (ret) -+ return; -+ scratch_32 &= ~(3 << 12); -+ pci_write_config_dword(chip->pdev, O2_SD_LD0_CTRL, scratch_32); -+ -+ /* Set Max power supply capability of SD host */ -+ ret = pci_read_config_dword(chip->pdev, O2_SD_CAP_REG0, &scratch_32); -+ if (ret) -+ return; -+ scratch_32 &= ~(0x01FE); -+ scratch_32 |= 0x00CC; -+ pci_write_config_dword(chip->pdev, O2_SD_CAP_REG0, scratch_32); -+ /* Set DLL Tuning Window */ -+ ret = pci_read_config_dword(chip->pdev, -+ O2_SD_TUNING_CTRL, &scratch_32); -+ if (ret) -+ return; -+ scratch_32 &= ~(0x000000FF); -+ scratch_32 |= 0x00000066; -+ pci_write_config_dword(chip->pdev, O2_SD_TUNING_CTRL, scratch_32); -+ -+ /* Set UHS2 T_EIDLE */ -+ ret = pci_read_config_dword(chip->pdev, -+ O2_SD_UHS2_L1_CTRL, &scratch_32); -+ if (ret) -+ return; -+ scratch_32 &= ~(0x000000FC); -+ scratch_32 |= 0x00000084; -+ pci_write_config_dword(chip->pdev, O2_SD_UHS2_L1_CTRL, scratch_32); -+ -+ /* Set UHS2 Termination */ -+ ret = pci_read_config_dword(chip->pdev, O2_SD_FUNC_REG3, &scratch_32); -+ if (ret) -+ return; -+ scratch_32 &= ~((1 << 21) | (1 << 30)); -+ -+ pci_write_config_dword(chip->pdev, O2_SD_FUNC_REG3, scratch_32); -+ -+ /* Set L1 Entrance Timer */ -+ ret = pci_read_config_dword(chip->pdev, O2_SD_CAPS, &scratch_32); -+ if (ret) -+ return; -+ scratch_32 &= ~(0xf0000000); -+ scratch_32 |= 0x30000000; -+ pci_write_config_dword(chip->pdev, O2_SD_CAPS, scratch_32); -+ -+ ret = pci_read_config_dword(chip->pdev, -+ O2_SD_MISC_CTRL4, &scratch_32); -+ if (ret) -+ return; -+ scratch_32 &= ~(0x000f0000); -+ scratch_32 |= 0x00080000; -+ pci_write_config_dword(chip->pdev, O2_SD_MISC_CTRL4, scratch_32); -+} -+ -+static void sdhci_pci_o2_enable_msi(struct sdhci_pci_chip *chip, -+ struct sdhci_host *host) -+{ -+ int ret; -+ -+ ret = pci_find_capability(chip->pdev, PCI_CAP_ID_MSI); -+ if (!ret) { -+ pr_info("%s: unsupport msi, use INTx irq\n", -+ mmc_hostname(host->mmc)); -+ return; -+ } -+ -+ ret = pci_alloc_irq_vectors(chip->pdev, 1, 1, -+ PCI_IRQ_MSI | PCI_IRQ_MSIX); -+ if (ret < 0) { -+ pr_err("%s: enable PCI MSI failed, err=%d\n", -+ mmc_hostname(host->mmc), ret); -+ return; -+ } -+ -+ host->irq = pci_irq_vector(chip->pdev, 0); -+} -+ -+static void sdhci_o2_enable_clk(struct sdhci_host *host, u16 clk) -+{ -+ /* Enable internal clock */ -+ clk |= SDHCI_CLOCK_INT_EN; -+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); -+ -+ sdhci_o2_enable_internal_clock(host); -+ if (sdhci_o2_get_cd(host->mmc)) { -+ clk |= SDHCI_CLOCK_CARD_EN; -+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); -+ } -+} -+ -+static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock) -+{ -+ u16 clk; -+ u8 scratch; -+ u32 scratch_32; -+ struct sdhci_pci_slot *slot = sdhci_priv(host); -+ struct sdhci_pci_chip *chip = slot->chip; -+ -+ host->mmc->actual_clock = 0; -+ -+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); -+ -+ if (clock == 0) -+ return; -+ -+ if ((host->timing == MMC_TIMING_UHS_SDR104) && (clock == 200000000)) { -+ pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); -+ -+ scratch &= 0x7f; -+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); -+ -+ pci_read_config_dword(chip->pdev, O2_SD_PLL_SETTING, &scratch_32); -+ -+ if ((scratch_32 & 0xFFFF0000) != 0x2c280000) -+ o2_pci_set_baseclk(chip, 0x2c280000); -+ -+ pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); -+ -+ scratch |= 0x80; -+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); -+ } -+ -+ clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); -+ sdhci_o2_enable_clk(host, clk); -+} -+ -+static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) -+{ -+ struct sdhci_pci_chip *chip; -+ struct sdhci_host *host; -+ struct o2_host *o2_host = sdhci_pci_priv(slot); -+ u32 reg, caps; -+ int ret; -+ -+ chip = slot->chip; -+ host = slot->host; -+ -+ o2_host->dll_adjust_count = 0; -+ caps = sdhci_readl(host, SDHCI_CAPABILITIES); -+ -+ /* -+ * mmc_select_bus_width() will test the bus to determine the actual bus -+ * width. -+ */ -+ if (caps & SDHCI_CAN_DO_8BIT) -+ host->mmc->caps |= MMC_CAP_8_BIT_DATA; -+ -+ switch (chip->pdev->device) { -+ case PCI_DEVICE_ID_O2_SDS0: -+ case PCI_DEVICE_ID_O2_SEABIRD0: -+ case PCI_DEVICE_ID_O2_SEABIRD1: -+ case PCI_DEVICE_ID_O2_SDS1: -+ case PCI_DEVICE_ID_O2_FUJIN2: -+ reg = sdhci_readl(host, O2_SD_VENDOR_SETTING); -+ if (reg & 0x1) -+ host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; -+ -+ sdhci_pci_o2_enable_msi(chip, host); -+ -+ if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD0) { -+ ret = pci_read_config_dword(chip->pdev, -+ O2_SD_MISC_SETTING, ®); -+ if (ret) -+ return -EIO; -+ if (reg & (1 << 4)) { -+ pr_info("%s: emmc 1.8v flag is set, force 1.8v signaling voltage\n", -+ mmc_hostname(host->mmc)); -+ host->flags &= ~SDHCI_SIGNALING_330; -+ host->flags |= SDHCI_SIGNALING_180; -+ host->mmc->caps2 |= MMC_CAP2_NO_SD; -+ host->mmc->caps2 |= MMC_CAP2_NO_SDIO; -+ pci_write_config_dword(chip->pdev, -+ O2_SD_DETECT_SETTING, 3); -+ } -+ -+ slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd; -+ } -+ -+ if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD1) { -+ slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd; -+ host->mmc->caps2 |= MMC_CAP2_NO_SDIO; -+ host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; -+ } -+ -+ host->mmc_host_ops.execute_tuning = sdhci_o2_execute_tuning; -+ -+ if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2) -+ break; -+ /* set dll watch dog timer */ -+ reg = sdhci_readl(host, O2_SD_VENDOR_SETTING2); -+ reg |= (1 << 12); -+ sdhci_writel(host, reg, O2_SD_VENDOR_SETTING2); -+ -+ break; -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+static int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip) -+{ -+ int ret; -+ u8 scratch; -+ u32 scratch_32; -+ -+ switch (chip->pdev->device) { -+ case PCI_DEVICE_ID_O2_8220: -+ case PCI_DEVICE_ID_O2_8221: -+ case PCI_DEVICE_ID_O2_8320: -+ case PCI_DEVICE_ID_O2_8321: -+ /* This extra setup is required due to broken ADMA. */ -+ ret = pci_read_config_byte(chip->pdev, -+ O2_SD_LOCK_WP, &scratch); -+ if (ret) -+ return ret; -+ scratch &= 0x7f; -+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); -+ -+ /* Set Multi 3 to VCC3V# */ -+ pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08); -+ -+ /* Disable CLK_REQ# support after media DET */ -+ ret = pci_read_config_byte(chip->pdev, -+ O2_SD_CLKREQ, &scratch); -+ if (ret) -+ return ret; -+ scratch |= 0x20; -+ pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch); -+ -+ /* Choose capabilities, enable SDMA. We have to write 0x01 -+ * to the capabilities register first to unlock it. -+ */ -+ ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch); -+ if (ret) -+ return ret; -+ scratch |= 0x01; -+ pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch); -+ pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73); -+ -+ /* Disable ADMA1/2 */ -+ pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39); -+ pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08); -+ -+ /* Disable the infinite transfer mode */ -+ ret = pci_read_config_byte(chip->pdev, -+ O2_SD_INF_MOD, &scratch); -+ if (ret) -+ return ret; -+ scratch |= 0x08; -+ pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch); -+ -+ /* Lock WP */ -+ ret = pci_read_config_byte(chip->pdev, -+ O2_SD_LOCK_WP, &scratch); -+ if (ret) -+ return ret; -+ scratch |= 0x80; -+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); -+ break; -+ case PCI_DEVICE_ID_O2_SDS0: -+ case PCI_DEVICE_ID_O2_SDS1: -+ case PCI_DEVICE_ID_O2_FUJIN2: -+ /* UnLock WP */ -+ ret = pci_read_config_byte(chip->pdev, -+ O2_SD_LOCK_WP, &scratch); -+ if (ret) -+ return ret; -+ -+ scratch &= 0x7f; -+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); -+ -+ /* DevId=8520 subId= 0x11 or 0x12 Type Chip support */ -+ if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2) { -+ ret = pci_read_config_dword(chip->pdev, -+ O2_SD_FUNC_REG0, -+ &scratch_32); -+ scratch_32 = ((scratch_32 & 0xFF000000) >> 24); -+ -+ /* Check Whether subId is 0x11 or 0x12 */ -+ if ((scratch_32 == 0x11) || (scratch_32 == 0x12)) { -+ scratch_32 = 0x25100000; -+ -+ o2_pci_set_baseclk(chip, scratch_32); -+ ret = pci_read_config_dword(chip->pdev, -+ O2_SD_FUNC_REG4, -+ &scratch_32); -+ -+ /* Enable Base Clk setting change */ -+ scratch_32 |= O2_SD_FREG4_ENABLE_CLK_SET; -+ pci_write_config_dword(chip->pdev, -+ O2_SD_FUNC_REG4, -+ scratch_32); -+ -+ /* Set Tuning Window to 4 */ -+ pci_write_config_byte(chip->pdev, -+ O2_SD_TUNING_CTRL, 0x44); -+ -+ break; -+ } -+ } -+ -+ /* Enable 8520 led function */ -+ o2_pci_led_enable(chip); -+ -+ /* Set timeout CLK */ -+ ret = pci_read_config_dword(chip->pdev, -+ O2_SD_CLK_SETTING, &scratch_32); -+ if (ret) -+ return ret; -+ -+ scratch_32 &= ~(0xFF00); -+ scratch_32 |= 0x07E0C800; -+ pci_write_config_dword(chip->pdev, -+ O2_SD_CLK_SETTING, scratch_32); -+ -+ ret = pci_read_config_dword(chip->pdev, -+ O2_SD_CLKREQ, &scratch_32); -+ if (ret) -+ return ret; -+ scratch_32 |= 0x3; -+ pci_write_config_dword(chip->pdev, O2_SD_CLKREQ, scratch_32); -+ -+ ret = pci_read_config_dword(chip->pdev, -+ O2_SD_PLL_SETTING, &scratch_32); -+ if (ret) -+ return ret; -+ -+ scratch_32 &= ~(0x1F3F070E); -+ scratch_32 |= 0x18270106; -+ pci_write_config_dword(chip->pdev, -+ O2_SD_PLL_SETTING, scratch_32); -+ -+ /* Disable UHS1 funciton */ -+ ret = pci_read_config_dword(chip->pdev, -+ O2_SD_CAP_REG2, &scratch_32); -+ if (ret) -+ return ret; -+ scratch_32 &= ~(0xE0); -+ pci_write_config_dword(chip->pdev, -+ O2_SD_CAP_REG2, scratch_32); -+ -+ if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2) -+ sdhci_pci_o2_fujin2_pci_init(chip); -+ -+ /* Lock WP */ -+ ret = pci_read_config_byte(chip->pdev, -+ O2_SD_LOCK_WP, &scratch); -+ if (ret) -+ return ret; -+ scratch |= 0x80; -+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); -+ break; -+ case PCI_DEVICE_ID_O2_SEABIRD0: -+ case PCI_DEVICE_ID_O2_SEABIRD1: -+ /* UnLock WP */ -+ ret = pci_read_config_byte(chip->pdev, -+ O2_SD_LOCK_WP, &scratch); -+ if (ret) -+ return ret; -+ -+ scratch &= 0x7f; -+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); -+ -+ ret = pci_read_config_dword(chip->pdev, -+ O2_SD_PLL_SETTING, &scratch_32); -+ -+ if ((scratch_32 & 0xff000000) == 0x01000000) { -+ scratch_32 &= 0x0000FFFF; -+ scratch_32 |= 0x1F340000; -+ -+ pci_write_config_dword(chip->pdev, -+ O2_SD_PLL_SETTING, scratch_32); -+ } else { -+ scratch_32 &= 0x0000FFFF; -+ scratch_32 |= 0x25100000; -+ -+ pci_write_config_dword(chip->pdev, -+ O2_SD_PLL_SETTING, scratch_32); -+ -+ ret = pci_read_config_dword(chip->pdev, -+ O2_SD_FUNC_REG4, -+ &scratch_32); -+ scratch_32 |= (1 << 22); -+ pci_write_config_dword(chip->pdev, -+ O2_SD_FUNC_REG4, scratch_32); -+ } -+ -+ /* Set Tuning Windows to 5 */ -+ pci_write_config_byte(chip->pdev, -+ O2_SD_TUNING_CTRL, 0x55); -+ /* Lock WP */ -+ ret = pci_read_config_byte(chip->pdev, -+ O2_SD_LOCK_WP, &scratch); -+ if (ret) -+ return ret; -+ scratch |= 0x80; -+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); -+ break; -+ } -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip) -+{ -+ sdhci_pci_o2_probe(chip); -+ return sdhci_pci_resume_host(chip); -+} -+#endif -+ -+static const struct sdhci_ops sdhci_pci_o2_ops = { -+ .set_clock = sdhci_pci_o2_set_clock, -+ .enable_dma = sdhci_pci_enable_dma, -+ .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, -+ .set_uhs_signaling = sdhci_set_uhs_signaling, -+}; -+ -+const struct sdhci_pci_fixes sdhci_o2 = { -+ .probe = sdhci_pci_o2_probe, -+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, -+ .quirks2 = SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD, -+ .probe_slot = sdhci_pci_o2_probe_slot, -+#ifdef CONFIG_PM_SLEEP -+ .resume = sdhci_pci_o2_resume, -+#endif -+ .ops = &sdhci_pci_o2_ops, -+ .priv_size = sizeof(struct o2_host), -+}; -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci.h -new file mode 100644 -index 000000000..8f90c4163 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci-pci.h -@@ -0,0 +1,203 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef __SDHCI_PCI_H -+#define __SDHCI_PCI_H -+ -+/* -+ * PCI device IDs, sub IDs -+ */ -+ -+#define PCI_DEVICE_ID_O2_SDS0 0x8420 -+#define PCI_DEVICE_ID_O2_SDS1 0x8421 -+#define PCI_DEVICE_ID_O2_FUJIN2 0x8520 -+#define PCI_DEVICE_ID_O2_SEABIRD0 0x8620 -+#define PCI_DEVICE_ID_O2_SEABIRD1 0x8621 -+ -+#define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809 -+#define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a -+#define PCI_DEVICE_ID_INTEL_BYT_EMMC 0x0f14 -+#define PCI_DEVICE_ID_INTEL_BYT_SDIO 0x0f15 -+#define PCI_DEVICE_ID_INTEL_BYT_SD 0x0f16 -+#define PCI_DEVICE_ID_INTEL_BYT_EMMC2 0x0f50 -+#define PCI_DEVICE_ID_INTEL_BSW_EMMC 0x2294 -+#define PCI_DEVICE_ID_INTEL_BSW_SDIO 0x2295 -+#define PCI_DEVICE_ID_INTEL_BSW_SD 0x2296 -+#define PCI_DEVICE_ID_INTEL_MRFLD_MMC 0x1190 -+#define PCI_DEVICE_ID_INTEL_CLV_SDIO0 0x08f9 -+#define PCI_DEVICE_ID_INTEL_CLV_SDIO1 0x08fa -+#define PCI_DEVICE_ID_INTEL_CLV_SDIO2 0x08fb -+#define PCI_DEVICE_ID_INTEL_CLV_EMMC0 0x08e5 -+#define PCI_DEVICE_ID_INTEL_CLV_EMMC1 0x08e6 -+#define PCI_DEVICE_ID_INTEL_QRK_SD 0x08A7 -+#define PCI_DEVICE_ID_INTEL_SPT_EMMC 0x9d2b -+#define PCI_DEVICE_ID_INTEL_SPT_SDIO 0x9d2c -+#define PCI_DEVICE_ID_INTEL_SPT_SD 0x9d2d -+#define PCI_DEVICE_ID_INTEL_DNV_EMMC 0x19db -+#define PCI_DEVICE_ID_INTEL_CDF_EMMC 0x18db -+#define PCI_DEVICE_ID_INTEL_BXT_SD 0x0aca -+#define PCI_DEVICE_ID_INTEL_BXT_EMMC 0x0acc -+#define PCI_DEVICE_ID_INTEL_BXT_SDIO 0x0ad0 -+#define PCI_DEVICE_ID_INTEL_BXTM_SD 0x1aca -+#define PCI_DEVICE_ID_INTEL_BXTM_EMMC 0x1acc -+#define PCI_DEVICE_ID_INTEL_BXTM_SDIO 0x1ad0 -+#define PCI_DEVICE_ID_INTEL_APL_SD 0x5aca -+#define PCI_DEVICE_ID_INTEL_APL_EMMC 0x5acc -+#define PCI_DEVICE_ID_INTEL_APL_SDIO 0x5ad0 -+#define PCI_DEVICE_ID_INTEL_GLK_SD 0x31ca -+#define PCI_DEVICE_ID_INTEL_GLK_EMMC 0x31cc -+#define PCI_DEVICE_ID_INTEL_GLK_SDIO 0x31d0 -+#define PCI_DEVICE_ID_INTEL_CNP_EMMC 0x9dc4 -+#define PCI_DEVICE_ID_INTEL_CNP_SD 0x9df5 -+#define PCI_DEVICE_ID_INTEL_CNPH_SD 0xa375 -+#define PCI_DEVICE_ID_INTEL_ICP_EMMC 0x34c4 -+#define PCI_DEVICE_ID_INTEL_ICP_SD 0x34f8 -+#define PCI_DEVICE_ID_INTEL_EHL_EMMC 0x4b47 -+#define PCI_DEVICE_ID_INTEL_EHL_SD 0x4b48 -+#define PCI_DEVICE_ID_INTEL_CML_EMMC 0x02c4 -+#define PCI_DEVICE_ID_INTEL_CML_SD 0x02f5 -+#define PCI_DEVICE_ID_INTEL_CMLH_SD 0x06f5 -+#define PCI_DEVICE_ID_INTEL_JSL_EMMC 0x4dc4 -+#define PCI_DEVICE_ID_INTEL_JSL_SD 0x4df8 -+#define PCI_DEVICE_ID_INTEL_LKF_EMMC 0x98c4 -+#define PCI_DEVICE_ID_INTEL_LKF_SD 0x98f8 -+ -+#define PCI_DEVICE_ID_SYSKONNECT_8000 0x8000 -+#define PCI_DEVICE_ID_VIA_95D0 0x95d0 -+#define PCI_DEVICE_ID_REALTEK_5250 0x5250 -+ -+#define PCI_SUBDEVICE_ID_NI_7884 0x7884 -+#define PCI_SUBDEVICE_ID_NI_78E3 0x78e3 -+ -+#define PCI_VENDOR_ID_ARASAN 0x16e6 -+#define PCI_DEVICE_ID_ARASAN_PHY_EMMC 0x0670 -+ -+#define PCI_DEVICE_ID_SYNOPSYS_DWC_MSHC 0xc202 -+ -+#define PCI_DEVICE_ID_GLI_9755 0x9755 -+#define PCI_DEVICE_ID_GLI_9750 0x9750 -+#define PCI_DEVICE_ID_GLI_9763E 0xe763 -+ -+/* -+ * PCI device class and mask -+ */ -+ -+#define SYSTEM_SDHCI (PCI_CLASS_SYSTEM_SDHCI << 8) -+#define PCI_CLASS_MASK 0xFFFF00 -+ -+/* -+ * Macros for PCI device-description -+ */ -+ -+#define _PCI_VEND(vend) PCI_VENDOR_ID_##vend -+#define _PCI_DEV(vend, dev) PCI_DEVICE_ID_##vend##_##dev -+#define _PCI_SUBDEV(subvend, subdev) PCI_SUBDEVICE_ID_##subvend##_##subdev -+ -+#define SDHCI_PCI_DEVICE(vend, dev, cfg) { \ -+ .vendor = _PCI_VEND(vend), .device = _PCI_DEV(vend, dev), \ -+ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \ -+ .driver_data = (kernel_ulong_t)&(sdhci_##cfg) \ -+} -+ -+#define SDHCI_PCI_SUBDEVICE(vend, dev, subvend, subdev, cfg) { \ -+ .vendor = _PCI_VEND(vend), .device = _PCI_DEV(vend, dev), \ -+ .subvendor = _PCI_VEND(subvend), \ -+ .subdevice = _PCI_SUBDEV(subvend, subdev), \ -+ .driver_data = (kernel_ulong_t)&(sdhci_##cfg) \ -+} -+ -+#define SDHCI_PCI_DEVICE_CLASS(vend, cl, cl_msk, cfg) { \ -+ .vendor = _PCI_VEND(vend), .device = PCI_ANY_ID, \ -+ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \ -+ .class = (cl), .class_mask = (cl_msk), \ -+ .driver_data = (kernel_ulong_t)&(sdhci_##cfg) \ -+} -+ -+/* -+ * PCI registers -+ */ -+ -+#define PCI_SDHCI_IFPIO 0x00 -+#define PCI_SDHCI_IFDMA 0x01 -+#define PCI_SDHCI_IFVENDOR 0x02 -+ -+#define PCI_SLOT_INFO 0x40 /* 8 bits */ -+#define PCI_SLOT_INFO_SLOTS(x) ((x >> 4) & 7) -+#define PCI_SLOT_INFO_FIRST_BAR_MASK 0x07 -+ -+#define MAX_SLOTS 8 -+ -+struct sdhci_pci_chip; -+struct sdhci_pci_slot; -+ -+struct sdhci_pci_fixes { -+ unsigned int quirks; -+ unsigned int quirks2; -+ bool allow_runtime_pm; -+ bool own_cd_for_runtime_pm; -+ -+ int (*probe) (struct sdhci_pci_chip *); -+ -+ int (*probe_slot) (struct sdhci_pci_slot *); -+ int (*add_host) (struct sdhci_pci_slot *); -+ void (*remove_slot) (struct sdhci_pci_slot *, int); -+ -+#ifdef CONFIG_PM_SLEEP -+ int (*suspend) (struct sdhci_pci_chip *); -+ int (*resume) (struct sdhci_pci_chip *); -+#endif -+#ifdef CONFIG_PM -+ int (*runtime_suspend) (struct sdhci_pci_chip *); -+ int (*runtime_resume) (struct sdhci_pci_chip *); -+#endif -+ -+ const struct sdhci_ops *ops; -+ size_t priv_size; -+}; -+ -+struct sdhci_pci_slot { -+ struct sdhci_pci_chip *chip; -+ struct sdhci_host *host; -+ struct sdhci_pci_data *data; -+ -+ int rst_n_gpio; -+ int cd_gpio; -+ int cd_irq; -+ -+ int cd_idx; -+ bool cd_override_level; -+ -+ void (*hw_reset)(struct sdhci_host *host); -+ unsigned long private[] ____cacheline_aligned; -+}; -+ -+struct sdhci_pci_chip { -+ struct pci_dev *pdev; -+ -+ unsigned int quirks; -+ unsigned int quirks2; -+ bool allow_runtime_pm; -+ bool pm_retune; -+ bool rpm_retune; -+ const struct sdhci_pci_fixes *fixes; -+ -+ int num_slots; /* Slots on controller */ -+ struct sdhci_pci_slot *slots[MAX_SLOTS]; /* Pointers to host slots */ -+}; -+ -+static inline void *sdhci_pci_priv(struct sdhci_pci_slot *slot) -+{ -+ return (void *)slot->private; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+int sdhci_pci_resume_host(struct sdhci_pci_chip *chip); -+#endif -+int sdhci_pci_enable_dma(struct sdhci_host *host); -+ -+extern const struct sdhci_pci_fixes sdhci_arasan; -+extern const struct sdhci_pci_fixes sdhci_snps; -+extern const struct sdhci_pci_fixes sdhci_o2; -+extern const struct sdhci_pci_fixes sdhci_gl9750; -+extern const struct sdhci_pci_fixes sdhci_gl9755; -+extern const struct sdhci_pci_fixes sdhci_gl9763e; -+ -+#endif /* __SDHCI_PCI_H */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci.h -new file mode 100644 -index 000000000..0770c036e ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/sdhci/sdhci.h -@@ -0,0 +1,811 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver -+ * -+ * Header file for Host Controller registers and I/O accessors. -+ * -+ * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. -+ */ -+#ifndef __SDHCI_HW_H -+#define __SDHCI_HW_H -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* -+ * Controller registers -+ */ -+ -+#define SDHCI_DMA_ADDRESS 0x00 -+#define SDHCI_ARGUMENT2 SDHCI_DMA_ADDRESS -+#define SDHCI_32BIT_BLK_CNT SDHCI_DMA_ADDRESS -+ -+#define SDHCI_BLOCK_SIZE 0x04 -+#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF)) -+ -+#define SDHCI_BLOCK_COUNT 0x06 -+ -+#define SDHCI_ARGUMENT 0x08 -+ -+#define SDHCI_TRANSFER_MODE 0x0C -+#define SDHCI_TRNS_DMA 0x01 -+#define SDHCI_TRNS_BLK_CNT_EN 0x02 -+#define SDHCI_TRNS_AUTO_CMD12 0x04 -+#define SDHCI_TRNS_AUTO_CMD23 0x08 -+#define SDHCI_TRNS_AUTO_SEL 0x0C -+#define SDHCI_TRNS_READ 0x10 -+#define SDHCI_TRNS_MULTI 0x20 -+ -+#define SDHCI_COMMAND 0x0E -+#define SDHCI_CMD_RESP_MASK 0x03 -+#define SDHCI_CMD_CRC 0x08 -+#define SDHCI_CMD_INDEX 0x10 -+#define SDHCI_CMD_DATA 0x20 -+#define SDHCI_CMD_ABORTCMD 0xC0 -+ -+#define SDHCI_CMD_RESP_NONE 0x00 -+#define SDHCI_CMD_RESP_LONG 0x01 -+#define SDHCI_CMD_RESP_SHORT 0x02 -+#define SDHCI_CMD_RESP_SHORT_BUSY 0x03 -+ -+#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff)) -+#define SDHCI_GET_CMD(c) ((c>>8) & 0x3f) -+ -+#define SDHCI_RESPONSE 0x10 -+ -+#define SDHCI_BUFFER 0x20 -+ -+#define SDHCI_PRESENT_STATE 0x24 -+#define SDHCI_CMD_INHIBIT 0x00000001 -+#define SDHCI_DATA_INHIBIT 0x00000002 -+#define SDHCI_DOING_WRITE 0x00000100 -+#define SDHCI_DOING_READ 0x00000200 -+#define SDHCI_SPACE_AVAILABLE 0x00000400 -+#define SDHCI_DATA_AVAILABLE 0x00000800 -+#define SDHCI_CARD_PRESENT 0x00010000 -+#define SDHCI_CARD_PRES_SHIFT 16 -+#define SDHCI_CD_STABLE 0x00020000 -+#define SDHCI_CD_LVL 0x00040000 -+#define SDHCI_CD_LVL_SHIFT 18 -+#define SDHCI_WRITE_PROTECT 0x00080000 -+#define SDHCI_DATA_LVL_MASK 0x00F00000 -+#define SDHCI_DATA_LVL_SHIFT 20 -+#define SDHCI_DATA_0_LVL_MASK 0x00100000 -+#define SDHCI_CMD_LVL 0x01000000 -+ -+#define SDHCI_HOST_CONTROL 0x28 -+#define SDHCI_CTRL_LED 0x01 -+#define SDHCI_CTRL_4BITBUS 0x02 -+#define SDHCI_CTRL_HISPD 0x04 -+#define SDHCI_CTRL_DMA_MASK 0x18 -+#define SDHCI_CTRL_SDMA 0x00 -+#define SDHCI_CTRL_ADMA1 0x08 -+#define SDHCI_CTRL_ADMA32 0x10 -+#define SDHCI_CTRL_ADMA64 0x18 -+#define SDHCI_CTRL_ADMA3 0x18 -+#define SDHCI_CTRL_8BITBUS 0x20 -+#define SDHCI_CTRL_CDTEST_INS 0x40 -+#define SDHCI_CTRL_CDTEST_EN 0x80 -+ -+#define SDHCI_POWER_CONTROL 0x29 -+#define SDHCI_POWER_ON 0x01 -+#define SDHCI_POWER_180 0x0A -+#define SDHCI_POWER_300 0x0C -+#define SDHCI_POWER_330 0x0E -+ -+#define SDHCI_BLOCK_GAP_CONTROL 0x2A -+ -+#define SDHCI_WAKE_UP_CONTROL 0x2B -+#define SDHCI_WAKE_ON_INT 0x01 -+#define SDHCI_WAKE_ON_INSERT 0x02 -+#define SDHCI_WAKE_ON_REMOVE 0x04 -+ -+#define SDHCI_CLOCK_CONTROL 0x2C -+#define SDHCI_DIVIDER_SHIFT 8 -+#define SDHCI_DIVIDER_HI_SHIFT 6 -+#define SDHCI_DIV_MASK 0xFF -+#define SDHCI_DIV_MASK_LEN 8 -+#define SDHCI_DIV_HI_MASK 0x300 -+#define SDHCI_PROG_CLOCK_MODE 0x0020 -+#define SDHCI_CLOCK_CARD_EN 0x0004 -+#define SDHCI_CLOCK_PLL_EN 0x0008 -+#define SDHCI_CLOCK_INT_STABLE 0x0002 -+#define SDHCI_CLOCK_INT_EN 0x0001 -+ -+#define SDHCI_TIMEOUT_CONTROL 0x2E -+ -+#define SDHCI_SOFTWARE_RESET 0x2F -+#define SDHCI_RESET_ALL 0x01 -+#define SDHCI_RESET_CMD 0x02 -+#define SDHCI_RESET_DATA 0x04 -+ -+#define SDHCI_INT_STATUS 0x30 -+#define SDHCI_INT_ENABLE 0x34 -+#define SDHCI_SIGNAL_ENABLE 0x38 -+#define SDHCI_INT_RESPONSE 0x00000001 -+#define SDHCI_INT_DATA_END 0x00000002 -+#define SDHCI_INT_BLK_GAP 0x00000004 -+#define SDHCI_INT_DMA_END 0x00000008 -+#define SDHCI_INT_SPACE_AVAIL 0x00000010 -+#define SDHCI_INT_DATA_AVAIL 0x00000020 -+#define SDHCI_INT_CARD_INSERT 0x00000040 -+#define SDHCI_INT_CARD_REMOVE 0x00000080 -+#define SDHCI_INT_CARD_INT 0x00000100 -+#define SDHCI_INT_RETUNE 0x00001000 -+#define SDHCI_INT_CQE 0x00004000 -+#define SDHCI_INT_ERROR 0x00008000 -+#define SDHCI_INT_TIMEOUT 0x00010000 -+#define SDHCI_INT_CRC 0x00020000 -+#define SDHCI_INT_END_BIT 0x00040000 -+#define SDHCI_INT_INDEX 0x00080000 -+#define SDHCI_INT_DATA_TIMEOUT 0x00100000 -+#define SDHCI_INT_DATA_CRC 0x00200000 -+#define SDHCI_INT_DATA_END_BIT 0x00400000 -+#define SDHCI_INT_BUS_POWER 0x00800000 -+#define SDHCI_INT_AUTO_CMD_ERR 0x01000000 -+#define SDHCI_INT_ADMA_ERROR 0x02000000 -+ -+#define SDHCI_INT_NORMAL_MASK 0x00007FFF -+#define SDHCI_INT_ERROR_MASK 0xFFFF8000 -+ -+#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \ -+ SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX | \ -+ SDHCI_INT_AUTO_CMD_ERR) -+#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ -+ SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ -+ SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ -+ SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \ -+ SDHCI_INT_BLK_GAP) -+#define SDHCI_INT_ALL_MASK ((unsigned int)-1) -+ -+#define SDHCI_CQE_INT_ERR_MASK ( \ -+ SDHCI_INT_ADMA_ERROR | SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | \ -+ SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | \ -+ SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT) -+ -+#define SDHCI_CQE_INT_MASK (SDHCI_CQE_INT_ERR_MASK | SDHCI_INT_CQE) -+ -+#define SDHCI_AUTO_CMD_STATUS 0x3C -+#define SDHCI_AUTO_CMD_TIMEOUT 0x00000002 -+#define SDHCI_AUTO_CMD_CRC 0x00000004 -+#define SDHCI_AUTO_CMD_END_BIT 0x00000008 -+#define SDHCI_AUTO_CMD_INDEX 0x00000010 -+ -+#define SDHCI_HOST_CONTROL2 0x3E -+#define SDHCI_CTRL_UHS_MASK 0x0007 -+#define SDHCI_CTRL_UHS_SDR12 0x0000 -+#define SDHCI_CTRL_UHS_SDR25 0x0001 -+#define SDHCI_CTRL_UHS_SDR50 0x0002 -+#define SDHCI_CTRL_UHS_SDR104 0x0003 -+#define SDHCI_CTRL_UHS_DDR50 0x0004 -+#define SDHCI_CTRL_HS400 0x0005 /* Non-standard */ -+#define SDHCI_CTRL_VDD_180 0x0008 -+#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 -+#define SDHCI_CTRL_DRV_TYPE_B 0x0000 -+#define SDHCI_CTRL_DRV_TYPE_A 0x0010 -+#define SDHCI_CTRL_DRV_TYPE_C 0x0020 -+#define SDHCI_CTRL_DRV_TYPE_D 0x0030 -+#define SDHCI_CTRL_EXEC_TUNING 0x0040 -+#define SDHCI_CTRL_TUNED_CLK 0x0080 -+#define SDHCI_CMD23_ENABLE 0x0800 -+#define SDHCI_CTRL_V4_MODE 0x1000 -+#define SDHCI_CTRL_64BIT_ADDR 0x2000 -+#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000 -+ -+#define SDHCI_CAPABILITIES 0x40 -+#define SDHCI_TIMEOUT_CLK_MASK GENMASK(5, 0) -+#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080 -+#define SDHCI_CLOCK_BASE_MASK GENMASK(13, 8) -+#define SDHCI_CLOCK_V3_BASE_MASK GENMASK(15, 8) -+#define SDHCI_MAX_BLOCK_MASK 0x00030000 -+#define SDHCI_MAX_BLOCK_SHIFT 16 -+#define SDHCI_CAN_DO_8BIT 0x00040000 -+#define SDHCI_CAN_DO_ADMA2 0x00080000 -+#define SDHCI_CAN_DO_ADMA1 0x00100000 -+#define SDHCI_CAN_DO_HISPD 0x00200000 -+#define SDHCI_CAN_DO_SDMA 0x00400000 -+#define SDHCI_CAN_DO_SUSPEND 0x00800000 -+#define SDHCI_CAN_VDD_330 0x01000000 -+#define SDHCI_CAN_VDD_300 0x02000000 -+#define SDHCI_CAN_VDD_180 0x04000000 -+#define SDHCI_CAN_64BIT_V4 0x08000000 -+#define SDHCI_CAN_64BIT 0x10000000 -+ -+#define SDHCI_CAPABILITIES_1 0x44 -+#define SDHCI_SUPPORT_SDR50 0x00000001 -+#define SDHCI_SUPPORT_SDR104 0x00000002 -+#define SDHCI_SUPPORT_DDR50 0x00000004 -+#define SDHCI_DRIVER_TYPE_A 0x00000010 -+#define SDHCI_DRIVER_TYPE_C 0x00000020 -+#define SDHCI_DRIVER_TYPE_D 0x00000040 -+#define SDHCI_RETUNING_TIMER_COUNT_MASK GENMASK(11, 8) -+#define SDHCI_USE_SDR50_TUNING 0x00002000 -+#define SDHCI_RETUNING_MODE_MASK GENMASK(15, 14) -+#define SDHCI_CLOCK_MUL_MASK GENMASK(23, 16) -+#define SDHCI_CAN_DO_ADMA3 0x08000000 -+#define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */ -+ -+#define SDHCI_MAX_CURRENT 0x48 -+#define SDHCI_MAX_CURRENT_LIMIT GENMASK(7, 0) -+#define SDHCI_MAX_CURRENT_330_MASK GENMASK(7, 0) -+#define SDHCI_MAX_CURRENT_300_MASK GENMASK(15, 8) -+#define SDHCI_MAX_CURRENT_180_MASK GENMASK(23, 16) -+#define SDHCI_MAX_CURRENT_MULTIPLIER 4 -+ -+/* 4C-4F reserved for more max current */ -+ -+#define SDHCI_SET_ACMD12_ERROR 0x50 -+#define SDHCI_SET_INT_ERROR 0x52 -+ -+#define SDHCI_ADMA_ERROR 0x54 -+ -+/* 55-57 reserved */ -+ -+#define SDHCI_ADMA_ADDRESS 0x58 -+#define SDHCI_ADMA_ADDRESS_HI 0x5C -+ -+/* 60-FB reserved */ -+ -+#define SDHCI_PRESET_FOR_SDR12 0x66 -+#define SDHCI_PRESET_FOR_SDR25 0x68 -+#define SDHCI_PRESET_FOR_SDR50 0x6A -+#define SDHCI_PRESET_FOR_SDR104 0x6C -+#define SDHCI_PRESET_FOR_DDR50 0x6E -+#define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */ -+#define SDHCI_PRESET_DRV_MASK GENMASK(15, 14) -+#define SDHCI_PRESET_CLKGEN_SEL BIT(10) -+#define SDHCI_PRESET_SDCLK_FREQ_MASK GENMASK(9, 0) -+ -+#define SDHCI_SLOT_INT_STATUS 0xFC -+ -+#define SDHCI_HOST_VERSION 0xFE -+#define SDHCI_VENDOR_VER_MASK 0xFF00 -+#define SDHCI_VENDOR_VER_SHIFT 8 -+#define SDHCI_SPEC_VER_MASK 0x00FF -+#define SDHCI_SPEC_VER_SHIFT 0 -+#define SDHCI_SPEC_100 0 -+#define SDHCI_SPEC_200 1 -+#define SDHCI_SPEC_300 2 -+#define SDHCI_SPEC_400 3 -+#define SDHCI_SPEC_410 4 -+#define SDHCI_SPEC_420 5 -+ -+/* -+ * End of controller registers. -+ */ -+ -+#define SDHCI_MAX_DIV_SPEC_200 256 -+#define SDHCI_MAX_DIV_SPEC_300 2046 -+ -+/* -+ * Host SDMA buffer boundary. Valid values from 4K to 512K in powers of 2. -+ */ -+#define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024) -+#define SDHCI_DEFAULT_BOUNDARY_ARG (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12) -+ -+/* ADMA2 32-bit DMA descriptor size */ -+#define SDHCI_ADMA2_32_DESC_SZ 8 -+ -+/* ADMA2 32-bit descriptor */ -+struct sdhci_adma2_32_desc { -+ __le16 cmd; -+ __le16 len; -+ __le32 addr; -+} __packed __aligned(4); -+ -+/* ADMA2 data alignment */ -+#define SDHCI_ADMA2_ALIGN 4 -+#define SDHCI_ADMA2_MASK (SDHCI_ADMA2_ALIGN - 1) -+ -+/* -+ * ADMA2 descriptor alignment. Some controllers (e.g. Intel) require 8 byte -+ * alignment for the descriptor table even in 32-bit DMA mode. Memory -+ * allocation is at least 8 byte aligned anyway, so just stipulate 8 always. -+ */ -+#define SDHCI_ADMA2_DESC_ALIGN 8 -+ -+/* -+ * ADMA2 64-bit DMA descriptor size -+ * According to SD Host Controller spec v4.10, there are two kinds of -+ * descriptors for 64-bit addressing mode: 96-bit Descriptor and 128-bit -+ * Descriptor, if Host Version 4 Enable is set in the Host Control 2 -+ * register, 128-bit Descriptor will be selected. -+ */ -+#define SDHCI_ADMA2_64_DESC_SZ(host) ((host)->v4_mode ? 16 : 12) -+ -+/* -+ * ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte -+ * aligned. -+ */ -+struct sdhci_adma2_64_desc { -+ __le16 cmd; -+ __le16 len; -+ __le32 addr_lo; -+ __le32 addr_hi; -+} __packed __aligned(4); -+ -+#define ADMA2_TRAN_VALID 0x21 -+#define ADMA2_NOP_END_VALID 0x3 -+#define ADMA2_END 0x2 -+ -+/* -+ * Maximum segments assuming a 512KiB maximum requisition size and a minimum -+ * 4KiB page size. -+ */ -+#define SDHCI_MAX_SEGS 128 -+ -+/* Allow for a a command request and a data request at the same time */ -+#define SDHCI_MAX_MRQS 2 -+ -+/* -+ * 48bit command and 136 bit response in 100KHz clock could take upto 2.48ms. -+ * However since the start time of the command, the time between -+ * command and response, and the time between response and start of data is -+ * not known, set the command transfer time to 10ms. -+ */ -+#define MMC_CMD_TRANSFER_TIME (10 * NSEC_PER_MSEC) /* max 10 ms */ -+ -+enum sdhci_cookie { -+ COOKIE_UNMAPPED, -+ COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */ -+ COOKIE_MAPPED, /* mapped by sdhci_prepare_data() */ -+}; -+ -+struct sdhci_host { -+ /* Data set by hardware interface driver */ -+ const char *hw_name; /* Hardware bus name */ -+ -+ unsigned int quirks; /* Deviations from spec. */ -+ -+/* Controller doesn't honor resets unless we touch the clock register */ -+#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) -+/* Controller has bad caps bits, but really supports DMA */ -+#define SDHCI_QUIRK_FORCE_DMA (1<<1) -+/* Controller doesn't like to be reset when there is no card inserted. */ -+#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) -+/* Controller doesn't like clearing the power reg before a change */ -+#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) -+/* Controller has flaky internal state so reset it on each ios change */ -+#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4) -+/* Controller has an unusable DMA engine */ -+#define SDHCI_QUIRK_BROKEN_DMA (1<<5) -+/* Controller has an unusable ADMA engine */ -+#define SDHCI_QUIRK_BROKEN_ADMA (1<<6) -+/* Controller can only DMA from 32-bit aligned addresses */ -+#define SDHCI_QUIRK_32BIT_DMA_ADDR (1<<7) -+/* Controller can only DMA chunk sizes that are a multiple of 32 bits */ -+#define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<8) -+/* Controller can only ADMA chunks that are a multiple of 32 bits */ -+#define SDHCI_QUIRK_32BIT_ADMA_SIZE (1<<9) -+/* Controller needs to be reset after each request to stay stable */ -+#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<10) -+/* Controller needs voltage and power writes to happen separately */ -+#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<11) -+/* Controller provides an incorrect timeout value for transfers */ -+#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12) -+/* Controller has an issue with buffer bits for small transfers */ -+#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13) -+/* Controller does not provide transfer-complete interrupt when not busy */ -+#define SDHCI_QUIRK_NO_BUSY_IRQ (1<<14) -+/* Controller has unreliable card detection */ -+#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15) -+/* Controller reports inverted write-protect state */ -+#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16) -+/* Controller has unusable command queue engine */ -+#define SDHCI_QUIRK_BROKEN_CQE (1<<17) -+/* Controller does not like fast PIO transfers */ -+#define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18) -+/* Controller does not have a LED */ -+#define SDHCI_QUIRK_NO_LED (1<<19) -+/* Controller has to be forced to use block size of 2048 bytes */ -+#define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20) -+/* Controller cannot do multi-block transfers */ -+#define SDHCI_QUIRK_NO_MULTIBLOCK (1<<21) -+/* Controller can only handle 1-bit data transfers */ -+#define SDHCI_QUIRK_FORCE_1_BIT_DATA (1<<22) -+/* Controller needs 10ms delay between applying power and clock */ -+#define SDHCI_QUIRK_DELAY_AFTER_POWER (1<<23) -+/* Controller uses SDCLK instead of TMCLK for data timeouts */ -+#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1<<24) -+/* Controller reports wrong base clock capability */ -+#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1<<25) -+/* Controller cannot support End Attribute in NOP ADMA descriptor */ -+#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1<<26) -+/* Controller is missing device caps. Use caps provided by host */ -+#define SDHCI_QUIRK_MISSING_CAPS (1<<27) -+/* Controller uses Auto CMD12 command to stop the transfer */ -+#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1<<28) -+/* Controller doesn't have HISPD bit field in HI-SPEED SD card */ -+#define SDHCI_QUIRK_NO_HISPD_BIT (1<<29) -+/* Controller treats ADMA descriptors with length 0000h incorrectly */ -+#define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC (1<<30) -+/* The read-only detection via SDHCI_PRESENT_STATE register is unstable */ -+#define SDHCI_QUIRK_UNSTABLE_RO_DETECT (1<<31) -+ -+ unsigned int quirks2; /* More deviations from spec. */ -+ -+#define SDHCI_QUIRK2_HOST_OFF_CARD_ON (1<<0) -+#define SDHCI_QUIRK2_HOST_NO_CMD23 (1<<1) -+/* The system physically doesn't support 1.8v, even if the host does */ -+#define SDHCI_QUIRK2_NO_1_8_V (1<<2) -+#define SDHCI_QUIRK2_PRESET_VALUE_BROKEN (1<<3) -+#define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON (1<<4) -+/* Controller has a non-standard host control register */ -+#define SDHCI_QUIRK2_BROKEN_HOST_CONTROL (1<<5) -+/* Controller does not support HS200 */ -+#define SDHCI_QUIRK2_BROKEN_HS200 (1<<6) -+/* Controller does not support DDR50 */ -+#define SDHCI_QUIRK2_BROKEN_DDR50 (1<<7) -+/* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */ -+#define SDHCI_QUIRK2_STOP_WITH_TC (1<<8) -+/* Controller does not support 64-bit DMA */ -+#define SDHCI_QUIRK2_BROKEN_64_BIT_DMA (1<<9) -+/* need clear transfer mode register before send cmd */ -+#define SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD (1<<10) -+/* Capability register bit-63 indicates HS400 support */ -+#define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 (1<<11) -+/* forced tuned clock */ -+#define SDHCI_QUIRK2_TUNING_WORK_AROUND (1<<12) -+/* disable the block count for single block transactions */ -+#define SDHCI_QUIRK2_SUPPORT_SINGLE (1<<13) -+/* Controller broken with using ACMD23 */ -+#define SDHCI_QUIRK2_ACMD23_BROKEN (1<<14) -+/* Broken Clock divider zero in controller */ -+#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15) -+/* Controller has CRC in 136 bit Command Response */ -+#define SDHCI_QUIRK2_RSP_136_HAS_CRC (1<<16) -+/* -+ * Disable HW timeout if the requested timeout is more than the maximum -+ * obtainable timeout. -+ */ -+#define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT (1<<17) -+/* -+ * 32-bit block count may not support eMMC where upper bits of CMD23 are used -+ * for other purposes. Consequently we support 16-bit block count by default. -+ * Otherwise, SDHCI_QUIRK2_USE_32BIT_BLK_CNT can be selected to use 32-bit -+ * block count. -+ */ -+#define SDHCI_QUIRK2_USE_32BIT_BLK_CNT (1<<18) -+ -+ int irq; /* Device IRQ */ -+ void __iomem *ioaddr; /* Mapped address */ -+ phys_addr_t mapbase; /* physical address base */ -+ char *bounce_buffer; /* For packing SDMA reads/writes */ -+ dma_addr_t bounce_addr; -+ unsigned int bounce_buffer_size; -+ -+ const struct sdhci_ops *ops; /* Low level hw interface */ -+ -+ /* Internal data */ -+ struct mmc_host *mmc; /* MMC structure */ -+ struct mmc_host_ops mmc_host_ops; /* MMC host ops */ -+ u64 dma_mask; /* custom DMA mask */ -+ -+#if IS_ENABLED(CONFIG_LEDS_CLASS) -+ struct led_classdev led; /* LED control */ -+ char led_name[32]; -+#endif -+ -+ spinlock_t lock; /* Mutex */ -+ -+ int flags; /* Host attributes */ -+#define SDHCI_USE_SDMA (1<<0) /* Host is SDMA capable */ -+#define SDHCI_USE_ADMA (1<<1) /* Host is ADMA capable */ -+#define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */ -+#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */ -+#define SDHCI_SDR50_NEEDS_TUNING (1<<4) /* SDR50 needs tuning */ -+#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */ -+#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */ -+#define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */ -+#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */ -+#define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */ -+#define SDHCI_SIGNALING_330 (1<<14) /* Host is capable of 3.3V signaling */ -+#define SDHCI_SIGNALING_180 (1<<15) /* Host is capable of 1.8V signaling */ -+#define SDHCI_SIGNALING_120 (1<<16) /* Host is capable of 1.2V signaling */ -+ -+ unsigned int version; /* SDHCI spec. version */ -+ -+ unsigned int max_clk; /* Max possible freq (MHz) */ -+ unsigned int timeout_clk; /* Timeout freq (KHz) */ -+ unsigned int clk_mul; /* Clock Muliplier value */ -+ -+ unsigned int clock; /* Current clock (MHz) */ -+ u8 pwr; /* Current voltage */ -+ -+ bool runtime_suspended; /* Host is runtime suspended */ -+ bool bus_on; /* Bus power prevents runtime suspend */ -+ bool preset_enabled; /* Preset is enabled */ -+ bool pending_reset; /* Cmd/data reset is pending */ -+ bool irq_wake_enabled; /* IRQ wakeup is enabled */ -+ bool v4_mode; /* Host Version 4 Enable */ -+ bool use_external_dma; /* Host selects to use external DMA */ -+ bool always_defer_done; /* Always defer to complete requests */ -+ -+ struct mmc_request *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */ -+ struct mmc_command *cmd; /* Current command */ -+ struct mmc_command *data_cmd; /* Current data command */ -+ struct mmc_command *deferred_cmd; /* Deferred command */ -+ struct mmc_data *data; /* Current data request */ -+ unsigned int data_early:1; /* Data finished before cmd */ -+ -+ struct sg_mapping_iter sg_miter; /* SG state for PIO */ -+ unsigned int blocks; /* remaining PIO blocks */ -+ -+ int sg_count; /* Mapped sg entries */ -+ -+ void *adma_table; /* ADMA descriptor table */ -+ void *align_buffer; /* Bounce buffer */ -+ -+ size_t adma_table_sz; /* ADMA descriptor table size */ -+ size_t align_buffer_sz; /* Bounce buffer size */ -+ -+ dma_addr_t adma_addr; /* Mapped ADMA descr. table */ -+ dma_addr_t align_addr; /* Mapped bounce buffer */ -+ -+ unsigned int desc_sz; /* ADMA current descriptor size */ -+ unsigned int alloc_desc_sz; /* ADMA descr. max size host supports */ -+ -+ struct workqueue_struct *complete_wq; /* Request completion wq */ -+ struct work_struct complete_work; /* Request completion work */ -+ -+ struct timer_list timer; /* Timer for timeouts */ -+ struct timer_list data_timer; /* Timer for data timeouts */ -+ -+#if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA) -+ struct dma_chan *rx_chan; -+ struct dma_chan *tx_chan; -+#endif -+ -+ u32 caps; /* CAPABILITY_0 */ -+ u32 caps1; /* CAPABILITY_1 */ -+ bool read_caps; /* Capability flags have been read */ -+ -+ bool sdhci_core_to_disable_vqmmc; /* sdhci core can disable vqmmc */ -+ unsigned int ocr_avail_sdio; /* OCR bit masks */ -+ unsigned int ocr_avail_sd; -+ unsigned int ocr_avail_mmc; -+ u32 ocr_mask; /* available voltages */ -+ -+ unsigned timing; /* Current timing */ -+ -+ u32 thread_isr; -+ -+ /* cached registers */ -+ u32 ier; -+ -+ bool cqe_on; /* CQE is operating */ -+ u32 cqe_ier; /* CQE interrupt mask */ -+ u32 cqe_err_ier; /* CQE error interrupt mask */ -+ -+ wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */ -+ unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */ -+ -+ unsigned int tuning_count; /* Timer count for re-tuning */ -+ unsigned int tuning_mode; /* Re-tuning mode supported by host */ -+ unsigned int tuning_err; /* Error code for re-tuning */ -+#define SDHCI_TUNING_MODE_1 0 -+#define SDHCI_TUNING_MODE_2 1 -+#define SDHCI_TUNING_MODE_3 2 -+ /* Delay (ms) between tuning commands */ -+ int tuning_delay; -+ int tuning_loop_count; -+ -+ /* Host SDMA buffer boundary. */ -+ u32 sdma_boundary; -+ -+ /* Host ADMA table count */ -+ u32 adma_table_cnt; -+ -+ u64 data_timeout; -+ -+ unsigned long private[] ____cacheline_aligned; -+}; -+ -+struct sdhci_ops { -+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS -+ u32 (*read_l)(struct sdhci_host *host, int reg); -+ u16 (*read_w)(struct sdhci_host *host, int reg); -+ u8 (*read_b)(struct sdhci_host *host, int reg); -+ void (*write_l)(struct sdhci_host *host, u32 val, int reg); -+ void (*write_w)(struct sdhci_host *host, u16 val, int reg); -+ void (*write_b)(struct sdhci_host *host, u8 val, int reg); -+#endif -+ -+ void (*set_clock)(struct sdhci_host *host, unsigned int clock); -+ void (*set_power)(struct sdhci_host *host, unsigned char mode, -+ unsigned short vdd); -+ -+ u32 (*irq)(struct sdhci_host *host, u32 intmask); -+ -+ int (*set_dma_mask)(struct sdhci_host *host); -+ int (*enable_dma)(struct sdhci_host *host); -+ unsigned int (*get_max_clock)(struct sdhci_host *host); -+ unsigned int (*get_min_clock)(struct sdhci_host *host); -+ /* get_timeout_clock should return clk rate in unit of Hz */ -+ unsigned int (*get_timeout_clock)(struct sdhci_host *host); -+ unsigned int (*get_max_timeout_count)(struct sdhci_host *host); -+ void (*set_timeout)(struct sdhci_host *host, -+ struct mmc_command *cmd); -+ void (*set_bus_width)(struct sdhci_host *host, int width); -+ void (*platform_send_init_74_clocks)(struct sdhci_host *host, -+ u8 power_mode); -+ unsigned int (*get_ro)(struct sdhci_host *host); -+ void (*reset)(struct sdhci_host *host, u8 mask); -+ int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode); -+ void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); -+ void (*hw_reset)(struct sdhci_host *host); -+ void (*adma_workaround)(struct sdhci_host *host, u32 intmask); -+ void (*card_event)(struct sdhci_host *host); -+ void (*voltage_switch)(struct sdhci_host *host); -+ void (*adma_write_desc)(struct sdhci_host *host, void **desc, -+ dma_addr_t addr, int len, unsigned int cmd); -+ void (*copy_to_bounce_buffer)(struct sdhci_host *host, -+ struct mmc_data *data, -+ unsigned int length); -+ void (*request_done)(struct sdhci_host *host, -+ struct mmc_request *mrq); -+ void (*dump_vendor_regs)(struct sdhci_host *host); -+}; -+ -+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS -+ -+static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg) -+{ -+ if (unlikely(host->ops->write_l)) -+ host->ops->write_l(host, val, reg); -+ else -+ writel(val, host->ioaddr + reg); -+} -+ -+static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg) -+{ -+ if (unlikely(host->ops->write_w)) -+ host->ops->write_w(host, val, reg); -+ else -+ writew(val, host->ioaddr + reg); -+} -+ -+static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg) -+{ -+ if (unlikely(host->ops->write_b)) -+ host->ops->write_b(host, val, reg); -+ else -+ writeb(val, host->ioaddr + reg); -+} -+ -+static inline u32 sdhci_readl(struct sdhci_host *host, int reg) -+{ -+ if (unlikely(host->ops->read_l)) -+ return host->ops->read_l(host, reg); -+ else -+ return readl(host->ioaddr + reg); -+} -+ -+static inline u16 sdhci_readw(struct sdhci_host *host, int reg) -+{ -+ if (unlikely(host->ops->read_w)) -+ return host->ops->read_w(host, reg); -+ else -+ return readw(host->ioaddr + reg); -+} -+ -+static inline u8 sdhci_readb(struct sdhci_host *host, int reg) -+{ -+ if (unlikely(host->ops->read_b)) -+ return host->ops->read_b(host, reg); -+ else -+ return readb(host->ioaddr + reg); -+} -+ -+#else -+ -+static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg) -+{ -+ writel(val, host->ioaddr + reg); -+} -+ -+static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg) -+{ -+ writew(val, host->ioaddr + reg); -+} -+ -+static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg) -+{ -+ writeb(val, host->ioaddr + reg); -+} -+ -+static inline u32 sdhci_readl(struct sdhci_host *host, int reg) -+{ -+ return readl(host->ioaddr + reg); -+} -+ -+static inline u16 sdhci_readw(struct sdhci_host *host, int reg) -+{ -+ return readw(host->ioaddr + reg); -+} -+ -+static inline u8 sdhci_readb(struct sdhci_host *host, int reg) -+{ -+ return readb(host->ioaddr + reg); -+} -+ -+#endif /* CONFIG_MMC_SDHCI_IO_ACCESSORS */ -+ -+struct sdhci_host *sdhci_alloc_host(struct device *dev, size_t priv_size); -+void sdhci_free_host(struct sdhci_host *host); -+ -+static inline void *sdhci_priv(struct sdhci_host *host) -+{ -+ return host->private; -+} -+ -+void sdhci_card_detect(struct sdhci_host *host); -+void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver, -+ const u32 *caps, const u32 *caps1); -+int sdhci_setup_host(struct sdhci_host *host); -+void sdhci_cleanup_host(struct sdhci_host *host); -+int __sdhci_add_host(struct sdhci_host *host); -+int sdhci_add_host(struct sdhci_host *host); -+void sdhci_remove_host(struct sdhci_host *host, int dead); -+ -+static inline void sdhci_read_caps(struct sdhci_host *host) -+{ -+ __sdhci_read_caps(host, NULL, NULL, NULL); -+} -+ -+u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock, -+ unsigned int *actual_clock); -+void sdhci_set_clock(struct sdhci_host *host, unsigned int clock); -+void sdhci_enable_clk(struct sdhci_host *host, u16 clk); -+void sdhci_set_power(struct sdhci_host *host, unsigned char mode, -+ unsigned short vdd); -+void sdhci_set_power_and_bus_voltage(struct sdhci_host *host, -+ unsigned char mode, -+ unsigned short vdd); -+void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, -+ unsigned short vdd); -+void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq); -+int sdhci_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq); -+void sdhci_set_bus_width(struct sdhci_host *host, int width); -+void sdhci_reset(struct sdhci_host *host, u8 mask); -+void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); -+int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); -+void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); -+int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, -+ struct mmc_ios *ios); -+void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable); -+void sdhci_adma_write_desc(struct sdhci_host *host, void **desc, -+ dma_addr_t addr, int len, unsigned int cmd); -+ -+#ifdef CONFIG_PM -+int sdhci_suspend_host(struct sdhci_host *host); -+int sdhci_resume_host(struct sdhci_host *host); -+int sdhci_runtime_suspend_host(struct sdhci_host *host); -+int sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset); -+#endif -+ -+void sdhci_cqe_enable(struct mmc_host *mmc); -+void sdhci_cqe_disable(struct mmc_host *mmc, bool recovery); -+bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error, -+ int *data_error); -+ -+void sdhci_dumpregs(struct sdhci_host *host); -+void sdhci_enable_v4_mode(struct sdhci_host *host); -+ -+void sdhci_start_tuning(struct sdhci_host *host); -+void sdhci_end_tuning(struct sdhci_host *host); -+void sdhci_reset_tuning(struct sdhci_host *host); -+void sdhci_send_tuning(struct sdhci_host *host, u32 opcode); -+void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode); -+void sdhci_switch_external_dma(struct sdhci_host *host, bool en); -+void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable); -+void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd); -+ -+#endif /* __SDHCI_HW_H */ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/spi-bitbang-txrx.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/spi-bitbang-txrx.h -new file mode 100644 -index 000000000..47bb9b898 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/spi-bitbang-txrx.h -@@ -0,0 +1,107 @@ -+/* -+ * Mix this utility code with some glue code to get one of several types of -+ * simple SPI master driver. Two do polled word-at-a-time I/O: -+ * -+ * - GPIO/parport bitbangers. Provide chipselect() and txrx_word[](), -+ * expanding the per-word routines from the inline templates below. -+ * -+ * - Drivers for controllers resembling bare shift registers. Provide -+ * chipselect() and txrx_word[](), with custom setup()/cleanup() methods -+ * that use your controller's clock and chipselect registers. -+ * -+ * Some hardware works well with requests at spi_transfer scope: -+ * -+ * - Drivers leveraging smarter hardware, with fifos or DMA; or for half -+ * duplex (MicroWire) controllers. Provide chipselect() and txrx_bufs(), -+ * and custom setup()/cleanup() methods. -+ */ -+ -+/* -+ * The code that knows what GPIO pins do what should have declared four -+ * functions, ideally as inlines, before including this header: -+ * -+ * void setsck(struct spi_device *, int is_on); -+ * void setmosi(struct spi_device *, int is_on); -+ * int getmiso(struct spi_device *); -+ * void spidelay(unsigned); -+ * -+ * setsck()'s is_on parameter is a zero/nonzero boolean. -+ * -+ * setmosi()'s is_on parameter is a zero/nonzero boolean. -+ * -+ * getmiso() is required to return 0 or 1 only. Any other value is invalid -+ * and will result in improper operation. -+ * -+ * A non-inlined routine would call bitbang_txrx_*() routines. The -+ * main loop could easily compile down to a handful of instructions, -+ * especially if the delay is a NOP (to run at peak speed). -+ * -+ * Since this is software, the timings may not be exactly what your board's -+ * chips need ... there may be several reasons you'd need to tweak timings -+ * in these routines, not just to make it faster or slower to match a -+ * particular CPU clock rate. -+ */ -+ -+static inline u32 -+bitbang_txrx_be_cpha0(struct spi_device *spi, -+ unsigned nsecs, unsigned cpol, unsigned flags, -+ u32 word, u8 bits) -+{ -+ /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */ -+ -+ u32 oldbit = (!(word & (1<<(bits-1)))) << 31; -+ /* clock starts at inactive polarity */ -+ for (word <<= (32 - bits); likely(bits); bits--) { -+ -+ /* setup MSB (to slave) on trailing edge */ -+ if ((flags & SPI_MASTER_NO_TX) == 0) { -+ if ((word & (1 << 31)) != oldbit) { -+ setmosi(spi, word & (1 << 31)); -+ oldbit = word & (1 << 31); -+ } -+ } -+ spidelay(nsecs); /* T(setup) */ -+ -+ setsck(spi, !cpol); -+ spidelay(nsecs); -+ -+ /* sample MSB (from slave) on leading edge */ -+ word <<= 1; -+ if ((flags & SPI_MASTER_NO_RX) == 0) -+ word |= getmiso(spi); -+ setsck(spi, cpol); -+ } -+ return word; -+} -+ -+static inline u32 -+bitbang_txrx_be_cpha1(struct spi_device *spi, -+ unsigned nsecs, unsigned cpol, unsigned flags, -+ u32 word, u8 bits) -+{ -+ /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */ -+ -+ u32 oldbit = (!(word & (1<<(bits-1)))) << 31; -+ /* clock starts at inactive polarity */ -+ for (word <<= (32 - bits); likely(bits); bits--) { -+ -+ /* setup MSB (to slave) on leading edge */ -+ setsck(spi, !cpol); -+ if ((flags & SPI_MASTER_NO_TX) == 0) { -+ if ((word & (1 << 31)) != oldbit) { -+ setmosi(spi, word & (1 << 31)); -+ oldbit = word & (1 << 31); -+ } -+ } -+ spidelay(nsecs); /* T(setup) */ -+ -+ setsck(spi, cpol); -+ spidelay(nsecs); -+ -+ /* sample MSB (from slave) on trailing edge */ -+ word <<= 1; -+ if ((flags & SPI_MASTER_NO_RX) == 0) -+ word |= getmiso(spi); -+ } -+ return word; -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_eeprom_93xx46.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_eeprom_93xx46.c -new file mode 100644 -index 000000000..2ba7e7912 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_eeprom_93xx46.c -@@ -0,0 +1,558 @@ -+/* -+ * Driver for 93xx46 EEPROMs -+ * -+ * (C) 2011 DENX Software Engineering, Anatolij Gustschin -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+ -+#define OP_START 0x4 -+#define OP_WRITE (OP_START | 0x1) -+#define OP_READ (OP_START | 0x2) -+#define ADDR_EWDS 0x00 -+#define ADDR_ERAL 0x20 -+#define ADDR_EWEN 0x30 -+ -+static int g_wb_eeprom_93xx46_debug = 0; -+ -+module_param(g_wb_eeprom_93xx46_debug, int, S_IRUGO | S_IWUSR); -+ -+#define SPI_93xx46_DEBUG_VERBOSE(fmt, args...) do { \ -+ if (g_wb_eeprom_93xx46_debug) { \ -+ printk(KERN_INFO "[EEPROM-93xx46][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+struct eeprom_93xx46_devtype_data { -+ unsigned int quirks; -+}; -+ -+static const struct eeprom_93xx46_devtype_data atmel_at93c46d_data = { -+ .quirks = EEPROM_93XX46_QUIRK_SINGLE_WORD_READ | -+ EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH, -+}; -+ -+struct eeprom_93xx46_dev { -+ struct spi_device *spi; -+ struct eeprom_93xx46_platform_data *pdata; -+ struct mutex lock; -+ struct nvmem_config nvmem_config; -+ struct nvmem_device *nvmem; -+ int addrlen; -+ int size; -+}; -+ -+static inline bool has_quirk_single_word_read(struct eeprom_93xx46_dev *edev) -+{ -+ return edev->pdata->quirks & EEPROM_93XX46_QUIRK_SINGLE_WORD_READ; -+} -+ -+static inline bool has_quirk_instruction_length(struct eeprom_93xx46_dev *edev) -+{ -+ return edev->pdata->quirks & EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH; -+} -+ -+static int eeprom_93xx46_read(void *priv, unsigned int off, -+ void *val, size_t count) -+{ -+ struct eeprom_93xx46_dev *edev = priv; -+ char *buf = val; -+ int err = 0; -+ -+ if (unlikely(off >= edev->size)) -+ return 0; -+ if ((off + count) > edev->size) -+ count = edev->size - off; -+ if (unlikely(!count)) -+ return count; -+ -+ mutex_lock(&edev->lock); -+ -+ if (edev->pdata->prepare) -+ edev->pdata->prepare(edev); -+ -+ while (count) { -+ struct spi_message m; -+ struct spi_transfer t[2] = { { 0 } }; -+ u16 cmd_addr = OP_READ << edev->addrlen; -+ size_t nbytes = count; -+ int bits; -+ int data_bit; -+ -+ if (edev->addrlen == 7) { -+ cmd_addr |= off & 0x7f; -+ bits = 10; -+ data_bit = 8; -+ if (has_quirk_single_word_read(edev)) -+ nbytes = 1; -+ } else { -+ cmd_addr |= (off >> 1) & 0x3f; -+ bits = 9; -+ data_bit = 16; -+ if (has_quirk_single_word_read(edev)) -+ nbytes = 2; -+ } -+ -+ dev_dbg(&edev->spi->dev, "read cmd 0x%x, %d Hz\n", -+ cmd_addr, edev->spi->max_speed_hz); -+ -+ spi_message_init(&m); -+ -+ t[0].tx_buf = (char *)&cmd_addr; -+ t[0].len = 2; -+ t[0].bits_per_word = bits; -+ spi_message_add_tail(&t[0], &m); -+ -+ t[1].rx_buf = buf; -+ t[1].len = nbytes; -+ t[1].bits_per_word = data_bit; -+ spi_message_add_tail(&t[1], &m); -+ -+ err = spi_sync(edev->spi, &m); -+ /* have to wait at least Tcsl ns */ -+ ndelay(250); -+ -+ if (err) { -+ dev_err(&edev->spi->dev, "read %zu bytes at %d: err. %d\n", -+ nbytes, (int)off, err); -+ break; -+ } -+ -+ buf += nbytes; -+ off += nbytes; -+ count -= nbytes; -+ } -+ -+ if (edev->pdata->finish) -+ edev->pdata->finish(edev); -+ -+ mutex_unlock(&edev->lock); -+ -+ return err; -+} -+ -+static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on) -+{ -+ struct spi_message m; -+ struct spi_transfer t; -+ int bits, ret; -+ u16 cmd_addr; -+ -+ cmd_addr = OP_START << edev->addrlen; -+ if (edev->addrlen == 7) { -+ cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS) << 1; -+ bits = 10; -+ } else { -+ cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS); -+ bits = 9; -+ } -+ -+ if (has_quirk_instruction_length(edev)) { -+ cmd_addr <<= 2; -+ bits += 2; -+ } -+ -+ dev_dbg(&edev->spi->dev, "ew%s cmd 0x%04x, %d bits\n", -+ is_on ? "en" : "ds", cmd_addr, bits); -+ -+ spi_message_init(&m); -+ mem_clear(&t, sizeof(t)); -+ -+ t.tx_buf = &cmd_addr; -+ t.len = 2; -+ t.bits_per_word = bits; -+ spi_message_add_tail(&t, &m); -+ -+ mutex_lock(&edev->lock); -+ -+ if (edev->pdata->prepare) -+ edev->pdata->prepare(edev); -+ -+ ret = spi_sync(edev->spi, &m); -+ /* have to wait at least Tcsl ns */ -+ ndelay(250); -+ if (ret) -+ dev_err(&edev->spi->dev, "erase/write %sable error %d\n", -+ is_on ? "en" : "dis", ret); -+ -+ if (edev->pdata->finish) -+ edev->pdata->finish(edev); -+ -+ mutex_unlock(&edev->lock); -+ return ret; -+} -+ -+static ssize_t -+eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev, -+ char *buf, unsigned off) -+{ -+ struct spi_message m; -+ struct spi_transfer t[2]; -+ int bits, data_len, ret; -+ u16 cmd_addr; -+ int data_bit; -+ -+ cmd_addr = OP_WRITE << edev->addrlen; -+ -+ if (edev->addrlen == 7) { -+ cmd_addr |= off & 0x7f; -+ bits = 10; -+ data_len = 1; -+ data_bit = 8; -+ } else { -+ cmd_addr |= (off >> 1) & 0x3f; -+ bits = 9; -+ data_len = 2; -+ data_bit = 16; -+ } -+ -+ dev_dbg(&edev->spi->dev, "write cmd 0x%x\n", cmd_addr); -+ -+ spi_message_init(&m); -+ mem_clear(t, sizeof(t)); -+ -+ t[0].tx_buf = (char *)&cmd_addr; -+ t[0].len = 2; -+ t[0].bits_per_word = bits; -+ spi_message_add_tail(&t[0], &m); -+ -+ t[1].tx_buf = buf; -+ t[1].len = data_len; -+ t[1].bits_per_word = data_bit; -+ spi_message_add_tail(&t[1], &m); -+ -+ ret = spi_sync(edev->spi, &m); -+ /* have to wait program cycle time Twc ms */ -+ mdelay(6); -+ return ret; -+} -+ -+static int eeprom_93xx46_write(void *priv, unsigned int off, -+ void *val, size_t count) -+{ -+ struct eeprom_93xx46_dev *edev = priv; -+ char *buf = val; -+ int i, ret, step = 1; -+ -+ if (unlikely(off >= edev->size)) -+ return -EFBIG; -+ if ((off + count) > edev->size) -+ count = edev->size - off; -+ if (unlikely(!count)) -+ return count; -+ -+ /* only write even number of bytes on 16-bit devices */ -+ if (edev->addrlen == 6) { -+ step = 2; -+ count &= ~1; -+ } -+ -+ /* erase/write enable */ -+ ret = eeprom_93xx46_ew(edev, 1); -+ if (ret) -+ return ret; -+ -+ mutex_lock(&edev->lock); -+ -+ if (edev->pdata->prepare) -+ edev->pdata->prepare(edev); -+ -+ for (i = 0; i < count; i += step) { -+ ret = eeprom_93xx46_write_word(edev, &buf[i], off + i); -+ if (ret) { -+ dev_err(&edev->spi->dev, "write failed at %d: %d\n", -+ (int)off + i, ret); -+ break; -+ } -+ } -+ -+ if (edev->pdata->finish) -+ edev->pdata->finish(edev); -+ -+ mutex_unlock(&edev->lock); -+ -+ /* erase/write disable */ -+ eeprom_93xx46_ew(edev, 0); -+ return ret; -+} -+ -+static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev) -+{ -+ struct eeprom_93xx46_platform_data *pd = edev->pdata; -+ struct spi_message m; -+ struct spi_transfer t; -+ int bits, ret; -+ u16 cmd_addr; -+ -+ cmd_addr = OP_START << edev->addrlen; -+ if (edev->addrlen == 7) { -+ cmd_addr |= ADDR_ERAL << 1; -+ bits = 10; -+ } else { -+ cmd_addr |= ADDR_ERAL; -+ bits = 9; -+ } -+ -+ if (has_quirk_instruction_length(edev)) { -+ cmd_addr <<= 2; -+ bits += 2; -+ } -+ -+ dev_dbg(&edev->spi->dev, "eral cmd 0x%04x, %d bits\n", cmd_addr, bits); -+ -+ spi_message_init(&m); -+ mem_clear(&t, sizeof(t)); -+ -+ t.tx_buf = &cmd_addr; -+ t.len = 2; -+ t.bits_per_word = bits; -+ spi_message_add_tail(&t, &m); -+ -+ mutex_lock(&edev->lock); -+ -+ if (edev->pdata->prepare) -+ edev->pdata->prepare(edev); -+ -+ ret = spi_sync(edev->spi, &m); -+ if (ret) -+ dev_err(&edev->spi->dev, "erase error %d\n", ret); -+ /* have to wait erase cycle time Tec ms */ -+ mdelay(6); -+ -+ if (pd->finish) -+ pd->finish(edev); -+ -+ mutex_unlock(&edev->lock); -+ return ret; -+} -+ -+static ssize_t eeprom_93xx46_store_erase(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct eeprom_93xx46_dev *edev = dev_get_drvdata(dev); -+ int erase = 0, ret; -+ -+ sscanf(buf, "%d", &erase); -+ if (erase) { -+ ret = eeprom_93xx46_ew(edev, 1); -+ if (ret) -+ return ret; -+ ret = eeprom_93xx46_eral(edev); -+ if (ret) -+ return ret; -+ ret = eeprom_93xx46_ew(edev, 0); -+ if (ret) -+ return ret; -+ } -+ return count; -+} -+static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase); -+ -+static void select_assert(void *context) -+{ -+ struct eeprom_93xx46_dev *edev = context; -+ -+ gpiod_set_value_cansleep(edev->pdata->select, 1); -+} -+ -+static void select_deassert(void *context) -+{ -+ struct eeprom_93xx46_dev *edev = context; -+ -+ gpiod_set_value_cansleep(edev->pdata->select, 0); -+} -+ -+static const struct of_device_id eeprom_93xx46_of_table[] = { -+ { .compatible = "eeprom-93xx46", }, -+ { .compatible = "atmel,at93c46d", .data = &atmel_at93c46d_data, }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, eeprom_93xx46_of_table); -+ -+static int eeprom_93xx46_probe_dt(struct spi_device *spi) -+{ -+ const struct of_device_id *of_id = -+ of_match_device(eeprom_93xx46_of_table, &spi->dev); -+ struct device_node *np = spi->dev.of_node; -+ struct eeprom_93xx46_platform_data *pd; -+ u32 tmp; -+ int gpio; -+ enum of_gpio_flags of_flags; -+ int ret; -+ -+ pd = devm_kzalloc(&spi->dev, sizeof(*pd), GFP_KERNEL); -+ if (!pd) -+ return -ENOMEM; -+ -+ ret = of_property_read_u32(np, "data-size", &tmp); -+ if (ret < 0) { -+ dev_err(&spi->dev, "data-size property not found\n"); -+ return ret; -+ } -+ -+ if (tmp == 8) { -+ pd->flags |= EE_ADDR8; -+ } else if (tmp == 16) { -+ pd->flags |= EE_ADDR16; -+ } else { -+ dev_err(&spi->dev, "invalid data-size (%d)\n", tmp); -+ return -EINVAL; -+ } -+ -+ if (of_property_read_bool(np, "read-only")) -+ pd->flags |= EE_READONLY; -+ -+ gpio = of_get_named_gpio_flags(np, "select-gpios", 0, &of_flags); -+ if (gpio_is_valid(gpio)) { -+ unsigned long flags = -+ of_flags == OF_GPIO_ACTIVE_LOW ? GPIOF_ACTIVE_LOW : 0; -+ -+ ret = devm_gpio_request_one(&spi->dev, gpio, flags, -+ "eeprom_93xx46_select"); -+ if (ret) -+ return ret; -+ -+ pd->select = gpio_to_desc(gpio); -+ pd->prepare = select_assert; -+ pd->finish = select_deassert; -+ -+ gpiod_direction_output(pd->select, 0); -+ } -+ -+ if (of_id) { -+ if (of_id->data) { -+ const struct eeprom_93xx46_devtype_data *data = of_id->data; -+ -+ pd->quirks = data->quirks; -+ } -+ } -+ -+ spi->dev.platform_data = pd; -+ -+ return 0; -+} -+ -+static int eeprom_93xx46_probe(struct spi_device *spi) -+{ -+ struct eeprom_93xx46_platform_data *pd; -+ struct eeprom_93xx46_dev *edev; -+ int err; -+ -+ if (spi->dev.of_node) { -+ err = eeprom_93xx46_probe_dt(spi); -+ if (err < 0) -+ return err; -+ } -+ -+ pd = spi->dev.platform_data; -+ if (!pd) { -+ dev_err(&spi->dev, "missing platform data\n"); -+ return -ENODEV; -+ } -+ -+ edev = kzalloc(sizeof(*edev), GFP_KERNEL); -+ if (!edev) -+ return -ENOMEM; -+ -+ if (pd->flags & EE_ADDR8) -+ edev->addrlen = 7; -+ else if (pd->flags & EE_ADDR16) -+ edev->addrlen = 6; -+ else { -+ dev_err(&spi->dev, "unspecified address type\n"); -+ err = -EINVAL; -+ goto fail; -+ } -+ -+ mutex_init(&edev->lock); -+ -+ edev->spi = spi; -+ edev->pdata = pd; -+ -+ edev->size = 128; -+ edev->nvmem_config.name = dev_name(&spi->dev); -+ edev->nvmem_config.dev = &spi->dev; -+ edev->nvmem_config.read_only = pd->flags & EE_READONLY; -+ edev->nvmem_config.root_only = true; -+ edev->nvmem_config.owner = THIS_MODULE; -+ edev->nvmem_config.compat = true; -+ edev->nvmem_config.base_dev = &spi->dev; -+ edev->nvmem_config.reg_read = eeprom_93xx46_read; -+ edev->nvmem_config.reg_write = eeprom_93xx46_write; -+ edev->nvmem_config.priv = edev; -+ edev->nvmem_config.stride = 4; -+ edev->nvmem_config.word_size = 1; -+ edev->nvmem_config.size = edev->size; -+ -+ edev->nvmem = nvmem_register(&edev->nvmem_config); -+ if (IS_ERR(edev->nvmem)) { -+ err = PTR_ERR(edev->nvmem); -+ goto fail; -+ } -+ -+ if (g_wb_eeprom_93xx46_debug) { -+ dev_info(&spi->dev, "%d-bit eeprom %s\n", -+ (pd->flags & EE_ADDR8) ? 8 : 16, -+ (pd->flags & EE_READONLY) ? "(readonly)" : ""); -+ } -+ -+ if (!(pd->flags & EE_READONLY)) { -+ if (device_create_file(&spi->dev, &dev_attr_erase)) -+ dev_err(&spi->dev, "can't create erase interface\n"); -+ } -+ -+ spi_set_drvdata(spi, edev); -+ return 0; -+fail: -+ kfree(edev); -+ return err; -+} -+ -+static int eeprom_93xx46_remove(struct spi_device *spi) -+{ -+ struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi); -+ -+ nvmem_unregister(edev->nvmem); -+ -+ if (!(edev->pdata->flags & EE_READONLY)) -+ device_remove_file(&spi->dev, &dev_attr_erase); -+ -+ kfree(edev); -+ return 0; -+} -+ -+static struct spi_driver wb_eeprom_93xx46_driver = { -+ .driver = { -+ .name = "wb_93xx46", -+ .of_match_table = of_match_ptr(eeprom_93xx46_of_table), -+ }, -+ .probe = eeprom_93xx46_probe, -+ .remove = eeprom_93xx46_remove, -+}; -+ -+module_spi_driver(wb_eeprom_93xx46_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Driver for 93xx46 EEPROMs"); -+MODULE_AUTHOR("support"); -+MODULE_ALIAS("spi:93xx46"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_i2c_bus_drv.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_i2c_bus_drv.c -new file mode 100644 -index 000000000..3932cb26c ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_i2c_bus_drv.c -@@ -0,0 +1,1120 @@ -+/* -+ * fpga_i2c_bus_drv.c -+ * ko to create fpga i2c adapter -+ */ -+#include -+#include -+#include -+#include -+#include -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) -+#include -+#endif -+#include -+#include -+#include -+#include -+#include -+#include -+#include "fpga_i2c.h" -+ -+#include -+#include -+ -+#define DRV_NAME "wb-fpga-i2c" -+#define DRV_VERSION "1.0" -+#define DTS_NO_CFG_FLAG (0) -+ -+extern int i2c_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); -+extern int i2c_device_func_read(const char *path, uint32_t pos, uint8_t *val, size_t size); -+extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int io_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); -+extern int io_device_func_read(const char *path, uint32_t pos, uint8_t *val, size_t size); -+extern int spi_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int spi_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+ -+#define FPGA_I2C_STRETCH_TIMEOUT (0x01) -+#define FPGA_I2C_DEADLOCK_FAILED (0x02) -+#define FPGA_I2C_SLAVE_NO_RESPOND (0x03) -+#define FPGA_I2C_STA_FAIL (0x01) -+#define FPGA_I2C_STA_BUSY (0x02) -+#define FPGA_I2C_CTL_BG (0x01 << 1) -+#define FPGA_I2C_CTL_NO_REG (0x01 << 2) -+#define FPGA_I2C_CTL_RD (0x01) -+#define FPGA_I2C_CTL_WR (0x00) -+#define I2C_READ_MSG_NUM (0x02) -+#define I2C_WRITE_MSG_NUM (0x01) -+#define FPGA_REG_WIDTH (4) -+ -+#define SYMBOL_I2C_DEV_MODE (1) -+#define FILE_MODE (2) -+#define SYMBOL_PCIE_DEV_MODE (3) -+#define SYMBOL_IO_DEV_MODE (4) -+#define SYMBOL_SPI_DEV_MODE (5) -+ -+int g_wb_fpga_i2c_debug = 0; -+int g_wb_fpga_i2c_error = 0; -+ -+module_param(g_wb_fpga_i2c_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_fpga_i2c_error, int, S_IRUGO | S_IWUSR); -+ -+#define FPGA_I2C_VERBOSE(fmt, args...) do { \ -+ if (g_wb_fpga_i2c_debug) { \ -+ printk(KERN_INFO "[FPFA_I2C_BUS][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define FPGA_I2C_ERROR(fmt, args...) do { \ -+ if (g_wb_fpga_i2c_error) { \ -+ printk(KERN_ERR "[FPFA_I2C_BUS][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static int fpga_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) -+{ -+ int ret; -+ struct file *filp; -+ loff_t tmp_pos; -+ -+ filp = filp_open(path, O_RDONLY, 0); -+ if (IS_ERR(filp)) { -+ FPGA_I2C_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); -+ filp = NULL; -+ goto exit; -+ } -+ -+ tmp_pos = (loff_t)pos; -+ ret = kernel_read(filp, val, size, &tmp_pos); -+ if (ret < 0) { -+ FPGA_I2C_ERROR("kernel_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); -+ goto exit; -+ } -+ -+ filp_close(filp, NULL); -+ -+ return ret; -+ -+exit: -+ if (filp != NULL) { -+ filp_close(filp, NULL); -+ } -+ -+ return -1; -+} -+ -+static int fpga_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) -+{ -+ int ret; -+ struct file *filp; -+ loff_t tmp_pos; -+ -+ filp = filp_open(path, O_RDWR, 777); -+ if (IS_ERR(filp)) { -+ FPGA_I2C_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); -+ filp = NULL; -+ goto exit; -+ } -+ -+ tmp_pos = (loff_t)pos; -+ ret = kernel_write(filp, val, size, &tmp_pos); -+ if (ret < 0) { -+ FPGA_I2C_ERROR("kernel_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); -+ goto exit; -+ } -+ vfs_fsync(filp, 1); -+ filp_close(filp, NULL); -+ -+ return ret; -+ -+exit: -+ if (filp != NULL) { -+ filp_close(filp, NULL); -+ } -+ -+ return -1; -+} -+ -+static int fpga_device_write(fpga_i2c_dev_t *fpga_i2c, uint32_t pos, uint8_t *val, size_t size) -+{ -+ int ret; -+ -+ switch (fpga_i2c->i2c_func_mode) { -+ case SYMBOL_I2C_DEV_MODE: -+ ret = i2c_device_func_write(fpga_i2c->dev_name, pos, val, size); -+ break; -+ case FILE_MODE: -+ ret = fpga_file_write(fpga_i2c->dev_name, pos, val, size); -+ break; -+ case SYMBOL_PCIE_DEV_MODE: -+ ret = pcie_device_func_write(fpga_i2c->dev_name, pos, val, size); -+ break; -+ case SYMBOL_IO_DEV_MODE: -+ ret = io_device_func_write(fpga_i2c->dev_name, pos, val, size); -+ break; -+ case SYMBOL_SPI_DEV_MODE: -+ ret = spi_device_func_write(fpga_i2c->dev_name, pos, val, size); -+ break; -+ default: -+ FPGA_I2C_ERROR("err func_mode %d, write failed.\n", fpga_i2c->i2c_func_mode); -+ return -EINVAL; -+ } -+ return ret; -+ -+} -+ -+static int fpga_device_read(fpga_i2c_dev_t *fpga_i2c, uint32_t pos, uint8_t *val, size_t size) -+{ -+ int ret; -+ -+ switch (fpga_i2c->i2c_func_mode) { -+ case SYMBOL_I2C_DEV_MODE: -+ ret = i2c_device_func_read(fpga_i2c->dev_name, pos, val, size); -+ break; -+ case FILE_MODE: -+ ret = fpga_file_read(fpga_i2c->dev_name, pos, val, size); -+ break; -+ case SYMBOL_PCIE_DEV_MODE: -+ ret = pcie_device_func_read(fpga_i2c->dev_name, pos, val, size); -+ break; -+ case SYMBOL_IO_DEV_MODE: -+ ret = io_device_func_read(fpga_i2c->dev_name, pos, val, size); -+ break; -+ case SYMBOL_SPI_DEV_MODE: -+ ret = spi_device_func_read(fpga_i2c->dev_name, pos, val, size); -+ break; -+ default: -+ FPGA_I2C_ERROR("err func_mode %d, read failed.\n", fpga_i2c->i2c_func_mode); -+ return -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static int little_endian_dword_to_buf(uint8_t *buf, int len, uint32_t dword) -+{ -+ uint8_t tmp_buf[FPGA_REG_WIDTH]; -+ -+ if (len < 4) { -+ FPGA_I2C_ERROR("Not enough buf, dword to buf: len[%d], dword[0x%x]\n", len, dword); -+ return -1; -+ } -+ -+ mem_clear(tmp_buf, sizeof(tmp_buf)); -+ tmp_buf[0] = dword & 0xff; -+ tmp_buf[1] = (dword >> 8) & 0xff; -+ tmp_buf[2] = (dword >> 16) & 0xff; -+ tmp_buf[3] = (dword >> 24) & 0xff; -+ -+ memcpy(buf, tmp_buf, sizeof(tmp_buf)); -+ -+ return 0; -+} -+ -+static int little_endian_buf_to_dword(uint8_t *buf, int len, uint32_t *dword) -+{ -+ int i; -+ uint32_t dword_tmp; -+ -+ if (len != FPGA_REG_WIDTH) { -+ FPGA_I2C_ERROR("buf length %d error, can't convert to dowrd.\n", len); -+ return -1; -+ } -+ dword_tmp = 0; -+ for (i = 0; i < FPGA_REG_WIDTH; i++) { -+ dword_tmp |= (buf[i] << (i * 8)); -+ } -+ *dword = dword_tmp; -+ return 0; -+} -+ -+static int fpga_reg_write(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t val) -+{ -+ int ret; -+ -+ ret = fpga_device_write(fpga_i2c, addr, &val, sizeof(uint8_t)); -+ if (ret < 0) { -+ FPGA_I2C_ERROR("fpga reg write failed, dev name:%s, offset:0x%x, value:0x%x.\n", -+ fpga_i2c->dev_name, addr, val); -+ return -EIO; -+ } -+ -+ FPGA_I2C_VERBOSE("fpga reg write success, dev name:%s, offset:0x%x, value:0x%x.\n", -+ fpga_i2c->dev_name, addr, val); -+ return 0; -+} -+ -+static int fpga_reg_read(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t *val) -+{ -+ int ret; -+ -+ ret = fpga_device_read(fpga_i2c, addr, val, sizeof(uint8_t)); -+ if (ret < 0) { -+ FPGA_I2C_ERROR("fpga reg read failed, dev name:%s, offset:0x%x\n", -+ fpga_i2c->dev_name, addr); -+ return -EIO; -+ } -+ -+ FPGA_I2C_VERBOSE("fpga reg read success, dev name:%s, offset:0x%x, value:0x%x.\n", -+ fpga_i2c->dev_name, addr, *val); -+ return 0; -+} -+ -+static int fpga_data_write(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t *val, size_t size) -+{ -+ int ret; -+ -+ ret = fpga_device_write(fpga_i2c, addr, val, size); -+ if (ret < 0) { -+ FPGA_I2C_ERROR("fpga data write failed, dev name:%s, offset:0x%x, size:%lu.\n", -+ fpga_i2c->dev_name, addr, size); -+ return -EIO; -+ } -+ -+ FPGA_I2C_VERBOSE("fpga data write success, dev name:%s, offset:0x%x, size:%lu.\n", -+ fpga_i2c->dev_name, addr, size); -+ return 0; -+} -+ -+static int fpga_data_read(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t *val, size_t size) -+{ -+ int ret; -+ -+ ret = fpga_device_read(fpga_i2c, addr, val, size); -+ if (ret < 0) { -+ FPGA_I2C_ERROR("fpga data read failed, dev name:%s, offset:0x%x, size:%lu.\n", -+ fpga_i2c->dev_name, addr, size); -+ return -EIO; -+ } -+ -+ FPGA_I2C_VERBOSE("fpga data read success, dev name:%s, offset:0x%x, size:%lu.\n", -+ fpga_i2c->dev_name, addr, size); -+ return 0; -+} -+ -+static int fpga_reg_write_32(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint32_t val) -+{ -+ int ret; -+ uint8_t buf[FPGA_REG_WIDTH]; -+ -+ mem_clear(buf, sizeof(buf)); -+ little_endian_dword_to_buf(buf, sizeof(buf), val); -+ ret = fpga_device_write(fpga_i2c, addr, buf, sizeof(buf)); -+ if (ret < 0) { -+ FPGA_I2C_ERROR("fpga reg write failed, dev name: %s, offset: 0x%x, value: 0x%x.\n", -+ fpga_i2c->dev_name, addr, val); -+ return -EIO; -+ } -+ -+ FPGA_I2C_VERBOSE("fpga reg write success, dev name: %s, offset: 0x%x, value: 0x%x.\n", -+ fpga_i2c->dev_name, addr, val); -+ return 0; -+} -+ -+static int fpga_reg_read_32(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint32_t *val) -+{ -+ int ret; -+ uint8_t buf[FPGA_REG_WIDTH]; -+ -+ mem_clear(buf, sizeof(buf)); -+ ret = fpga_device_read(fpga_i2c, addr, buf, sizeof(buf)); -+ if (ret < 0) { -+ FPGA_I2C_ERROR("fpga reg read failed, dev name: %s, offset: 0x%x, ret: %d\n", -+ fpga_i2c->dev_name, addr, ret); -+ return -EIO; -+ } -+ little_endian_buf_to_dword(buf, sizeof(buf), val); -+ FPGA_I2C_VERBOSE("fpga reg read success, dev name: %s, offset: 0x%x, value: 0x%x.\n", -+ fpga_i2c->dev_name, addr, *val); -+ return 0; -+} -+ -+static int fpga_i2c_is_busy(fpga_i2c_dev_t *fpga_i2c) -+{ -+ uint8_t val; -+ int ret; -+ fpga_i2c_reg_t *reg; -+ -+ reg = &fpga_i2c->reg; -+ ret = fpga_reg_read(fpga_i2c, reg->i2c_status, &val); -+ if (ret < 0 ) { -+ FPGA_I2C_ERROR("read fpga i2c status reg failed, reg addr:0x%x, ret:%d.\n", -+ reg->i2c_status, ret); -+ return 1; -+ } -+ if (val & FPGA_I2C_STA_BUSY) { -+ FPGA_I2C_ERROR("fpga i2c status busy, reg addr:0x%x, value:0x%x.\n", -+ reg->i2c_status, val); -+ return 1; -+ } else { -+ return 0; -+ } -+} -+ -+static int fpga_i2c_wait(fpga_i2c_dev_t *fpga_i2c) -+{ -+ int retry_cnt; -+ -+ retry_cnt = FPGA_I2C_XFER_TIME_OUT/FPGA_I2C_SLEEP_TIME; -+ while (retry_cnt--) { -+ if (fpga_i2c_is_busy(fpga_i2c)) { -+ usleep_range(FPGA_I2C_SLEEP_TIME, FPGA_I2C_SLEEP_TIME + 1); -+ } else { -+ return 0; -+ } -+ } -+ -+ return -EBUSY; -+} -+ -+static int fpga_i2c_check_status(fpga_i2c_dev_t *fpga_i2c) -+{ -+ uint8_t data; -+ int ret; -+ fpga_i2c_reg_t *reg; -+ -+ reg = &fpga_i2c->reg; -+ -+ ret = fpga_reg_read(fpga_i2c, reg->i2c_status, &data); -+ if (ret) { -+ FPGA_I2C_ERROR("read fpga i2c status reg failed, reg addr:0x%x, ret:%d.\n", -+ reg->i2c_status, ret); -+ return ret; -+ } -+ -+ if (data & FPGA_I2C_STA_FAIL) { -+ FPGA_I2C_ERROR("fpga i2c status error, reg addr:0x%x, value:%d.\n", -+ reg->i2c_status, data); -+ -+ /* read i2c_err_vec to confirm err type*/ -+ if (reg->i2c_err_vec != DTS_NO_CFG_FLAG) { -+ /* read i2c_err_vec reg */ -+ ret = fpga_reg_read(fpga_i2c, reg->i2c_err_vec, &data); -+ if (ret) { -+ FPGA_I2C_ERROR("read fpga i2c err vec reg failed, reg addr:0x%x, ret:%d.\n", -+ reg->i2c_err_vec, ret); -+ return ret; -+ } -+ FPGA_I2C_VERBOSE("get i2c err vec, reg addr:0x%x, read value:0x%x\n", reg->i2c_err_vec, data); -+ -+ /* match i2c_err_vec reg value and err type*/ -+ switch (data) { -+ case FPGA_I2C_STRETCH_TIMEOUT: -+ ret = -ETIMEDOUT; -+ break; -+ case FPGA_I2C_DEADLOCK_FAILED: -+ ret = -EDEADLK; -+ break; -+ case FPGA_I2C_SLAVE_NO_RESPOND: -+ ret = -ENXIO; -+ break; -+ default: -+ FPGA_I2C_ERROR("get i2c err vec value out of range, reg addr:0x%x, read value:0x%x\n", -+ reg->i2c_err_vec, data); -+ ret = -EREMOTEIO; -+ break; -+ } -+ return ret; -+ } else { -+ FPGA_I2C_VERBOSE("i2c err vec not config, fpga i2c status check return -1\n"); -+ return -EREMOTEIO; -+ } -+ } -+ return 0; -+} -+ -+static int fpga_i2c_do_work(fpga_i2c_dev_t *fpga_i2c, int i2c_addr, -+ unsigned char *data, uint32_t length, int is_read) -+{ -+ int ret, i; -+ uint8_t op, i2c_reg_addr_len; -+ uint8_t *i2c_read_addr_buf; -+ fpga_i2c_reg_t *reg; -+ fpga_i2c_reg_addr_t *i2c_addr_desc; -+ -+ reg = &fpga_i2c->reg; -+ -+ ret = fpga_reg_write(fpga_i2c, reg->i2c_slave, i2c_addr); -+ if (ret) { -+ FPGA_I2C_ERROR("write fpga i2c slave reg failed, reg addr:0x%x, value:0x%x, ret:%d.\n", -+ reg->i2c_slave, i2c_addr, ret); -+ goto exit; -+ } -+ -+ i2c_addr_desc = &fpga_i2c->i2c_addr_desc; -+ i2c_reg_addr_len = i2c_addr_desc->reg_addr_len; -+ i2c_read_addr_buf = &i2c_addr_desc->read_reg_addr[0]; -+ -+ if (i2c_reg_addr_len > 0 && i2c_reg_addr_len <= I2C_REG_MAX_WIDTH) { -+ ret = fpga_data_write(fpga_i2c, reg->i2c_reg, i2c_read_addr_buf, i2c_reg_addr_len); -+ if (ret) { -+ FPGA_I2C_ERROR("write fpga i2c offset reg failed, fpga addr:0x%x, reg len:%d, ret:%d\n", -+ reg->i2c_reg, i2c_reg_addr_len, ret); -+ for (i = 0; i < i2c_reg_addr_len; i++) { -+ FPGA_I2C_ERROR("%02d : %02x\n", i, i2c_read_addr_buf[i]); -+ } -+ goto exit; -+ } -+ } -+ -+ ret = fpga_reg_write_32(fpga_i2c, reg->i2c_data_len, length); -+ if (ret) { -+ FPGA_I2C_ERROR("write fpga i2c date len reg failed, reg addr:0x%x, value:0x%x, ret:%d.\n", -+ reg->i2c_data_len, length, ret); -+ goto exit; -+ } -+ -+ ret = fpga_reg_write(fpga_i2c, reg->i2c_reg_len, i2c_reg_addr_len); -+ if (ret) { -+ FPGA_I2C_ERROR("write fpga i2c reg len reg failed, reg addr:0x%x, value:0x%x, ret:%d.\n", -+ reg->i2c_reg_len, i2c_reg_addr_len, ret); -+ goto exit; -+ } -+ -+ if (is_read) { -+ op = FPGA_I2C_CTL_RD | FPGA_I2C_CTL_BG; -+ } else { -+ -+ ret = fpga_data_write(fpga_i2c, reg->i2c_data_buf, data, length); -+ if (ret) { -+ FPGA_I2C_ERROR("write fpga i2c date buf failed, reg addr:0x%x, write len:%d, ret:%d.\n", -+ reg->i2c_data_buf, length, ret); -+ goto exit; -+ } -+ op = FPGA_I2C_CTL_WR | FPGA_I2C_CTL_BG ; -+ } -+ -+ ret = fpga_reg_write(fpga_i2c, reg->i2c_ctrl, op); -+ if (ret) { -+ FPGA_I2C_ERROR("write fpga i2c control reg failed, reg addr:0x%x, value:%d, ret:%d.\n", -+ reg->i2c_ctrl, op, ret); -+ goto exit; -+ } -+ -+ ret = fpga_i2c_wait(fpga_i2c); -+ if (ret) { -+ FPGA_I2C_ERROR("wait fpga i2c status timeout.\n"); -+ goto exit; -+ } -+ -+ ret = fpga_i2c_check_status(fpga_i2c); -+ if (ret) { -+ FPGA_I2C_ERROR("check fpga i2c status error.\n"); -+ goto exit; -+ } -+ -+ if (is_read) { -+ -+ ret = fpga_data_read(fpga_i2c, reg->i2c_data_buf, data, length); -+ if (ret) { -+ FPGA_I2C_ERROR("read fpga i2c data buf failed, reg addr:0x%x, read len:%d, ret:%d.\n", -+ reg->i2c_data_buf, length, ret); -+ goto exit; -+ } -+ } -+ -+exit: -+ return ret; -+} -+ -+static int fpga_i2c_write(fpga_i2c_dev_t *fpga_i2c, int target, -+ u8 *data, int length, int i2c_msg_num) -+{ -+ int ret, i; -+ fpga_i2c_reg_addr_t *i2c_addr_desc; -+ -+ if (i2c_msg_num == I2C_READ_MSG_NUM) { -+ -+ if (length > I2C_REG_MAX_WIDTH) { -+ FPGA_I2C_ERROR("read reg addr len %d, more than max length.\n", length); -+ return -EINVAL; -+ } -+ -+ i2c_addr_desc = &fpga_i2c->i2c_addr_desc; -+ for (i = 0; i < length; i++) { -+ i2c_addr_desc->read_reg_addr[i] = data[length -i -1]; -+ FPGA_I2C_VERBOSE("%02d : %02x\n", i, i2c_addr_desc->read_reg_addr[i]); -+ } -+ i2c_addr_desc->reg_addr_len = length; -+ ret = 0; -+ } else { -+ -+ ret = fpga_i2c_do_work(fpga_i2c, target, data, length, 0); -+ } -+ -+ return ret; -+} -+ -+/** -+ * fpga_i2c_read - receive data from the bus. -+ * @i2c: The struct fpga_i2c_dev_t. -+ * @target: Target address. -+ * @data: Pointer to the location to store the datae . -+ * @length: Length of the data. -+ * -+ * The address is sent over the bus, then the data is read. -+ * -+ * Returns 0 on success, otherwise a negative errno. -+ */ -+static int fpga_i2c_read(fpga_i2c_dev_t *fpga_i2c, int target, -+ u8 *data, int length) -+{ -+ int ret, offset_size; -+ int i, tmp_val; -+ fpga_i2c_reg_addr_t *i2c_addr_desc; -+ uint8_t i2c_reg_addr_len; -+ uint8_t *i2c_read_addr_buf; -+ -+ offset_size = 0; -+ i2c_addr_desc = &fpga_i2c->i2c_addr_desc; -+ i2c_reg_addr_len = i2c_addr_desc->reg_addr_len; -+ i2c_read_addr_buf = &i2c_addr_desc->read_reg_addr[0]; -+ -+ while (1) { -+ if (length <= fpga_i2c->reg.i2c_data_buf_len) { -+ return fpga_i2c_do_work(fpga_i2c, target, data + offset_size, length, 1); -+ } -+ -+ ret = fpga_i2c_do_work(fpga_i2c, target, data + offset_size, fpga_i2c->reg.i2c_data_buf_len, 1); -+ if (ret != 0) { -+ FPGA_I2C_ERROR("fpga_i2c_read failed, i2c addr:0x%x, offset:0x%x, ret:%d.\n", -+ target, offset_size, ret); -+ return ret; -+ } -+ -+ tmp_val = i2c_read_addr_buf[0]; -+ tmp_val += fpga_i2c->reg.i2c_data_buf_len; -+ if (tmp_val > 0xff) { -+ i2c_read_addr_buf[0] = tmp_val & 0xff; -+ for (i = 1; i < i2c_reg_addr_len; i++) { -+ if (i2c_read_addr_buf[i] == 0xff) { -+ i2c_read_addr_buf[i] = 0; -+ } else { -+ i2c_read_addr_buf[i]++; -+ break; -+ } -+ } -+ } else { -+ i2c_read_addr_buf[0] = tmp_val & 0xff; -+ } -+ offset_size += fpga_i2c->reg.i2c_data_buf_len; -+ length -= fpga_i2c->reg.i2c_data_buf_len; -+ } -+ -+ return ret; -+} -+ -+static void fpga_i2c_reset(fpga_i2c_dev_t *fpga_i2c) { -+ fpga_i2c_reset_cfg_t *reset_cfg; -+ uint32_t reset_addr; -+ -+ reset_cfg = &fpga_i2c->reset_cfg; -+ reset_addr = reset_cfg->reset_addr; -+ if (reset_cfg->reset_delay_b) { -+ usleep_range(reset_cfg->reset_delay_b, reset_cfg->reset_delay_b + 1); -+ } -+ -+ fpga_reg_write_32(fpga_i2c, reset_addr, reset_cfg->reset_on); -+ if (reset_cfg->reset_delay) { -+ usleep_range(reset_cfg->reset_delay, reset_cfg->reset_delay + 1); -+ } -+ -+ fpga_reg_write_32(fpga_i2c, reset_addr, reset_cfg->reset_off); -+ if (reset_cfg->reset_delay_a) { -+ usleep_range(reset_cfg->reset_delay_a, reset_cfg->reset_delay_a + 1); -+ } -+ -+ return; -+} -+ -+/** -+ * fpga_i2c_xfer - The driver's master_xfer function. -+ * @adap: Pointer to the i2c_adapter structure. -+ * @msgs: Pointer to the messages to be processed. -+ * @num: Length of the MSGS array. -+ * -+ * Returns the number of messages processed, or a negative errno on -+ * failure. -+ */ -+static int fpga_i2c_adapter_init(fpga_i2c_dev_t *fpga_i2c) -+{ -+ int ret; -+ fpga_i2c_reg_t *reg; -+ -+ reg = &fpga_i2c->reg; -+ -+ ret = 0; -+ ret += fpga_reg_write(fpga_i2c, reg->i2c_scale, fpga_i2c->i2c_scale_value); -+ ret += fpga_reg_write(fpga_i2c, reg->i2c_filter, fpga_i2c->i2c_filter_value); -+ ret += fpga_reg_write(fpga_i2c, reg->i2c_stretch, fpga_i2c->i2c_stretch_value); -+ if (ret < 0) { -+ FPGA_I2C_ERROR("fpga_i2c_init failed.\n"); -+ return ret; -+ } -+ -+ FPGA_I2C_VERBOSE("fpga_i2c_init ok.\n"); -+ return 0; -+} -+ -+static int fpga_i2c_params_check(fpga_i2c_dev_t *fpga_i2c) -+{ -+ int ret; -+ fpga_i2c_reg_t *reg; -+ uint8_t i2c_scale_value, i2c_filter_value, i2c_stretch_value; -+ -+ reg = &fpga_i2c->reg; -+ ret = 0; -+ ret += fpga_reg_read(fpga_i2c, reg->i2c_scale, &i2c_scale_value); -+ ret += fpga_reg_read(fpga_i2c, reg->i2c_filter, &i2c_filter_value); -+ ret += fpga_reg_read(fpga_i2c, reg->i2c_stretch, &i2c_stretch_value); -+ if (ret < 0) { -+ FPGA_I2C_ERROR("read fpga i2c params failed.\n"); -+ return 1; -+ } -+ -+ if ((i2c_scale_value != fpga_i2c->i2c_scale_value) -+ || (i2c_filter_value != fpga_i2c->i2c_filter_value) -+ || (i2c_stretch_value != fpga_i2c->i2c_stretch_value)) { -+ FPGA_I2C_ERROR("fpga i2c params check error, read value: i2c_scale 0x%x, i2c_filter:0x%x, i2c_stretch:0x%x.\n", -+ i2c_scale_value, i2c_filter_value, i2c_stretch_value); -+ FPGA_I2C_ERROR("fpga i2c params check error, config value: i2c_scale 0x%x, i2c_filter:0x%x, i2c_stretch:0x%x.\n", -+ fpga_i2c->i2c_scale_value, fpga_i2c->i2c_filter_value, fpga_i2c->i2c_stretch_value); -+ return 1; -+ } -+ -+ FPGA_I2C_VERBOSE("fpga i2c params check ok.\n"); -+ return 0; -+} -+ -+static int fpga_i2c_xfer(struct i2c_adapter *adap, -+ struct i2c_msg *msgs, int num) -+{ -+ struct i2c_msg *pmsg; -+ int i; -+ int ret; -+ fpga_i2c_dev_t *fpga_i2c; -+ fpga_i2c_reg_addr_t *i2c_addr_desc; -+ -+ fpga_i2c = i2c_get_adapdata(adap); -+ -+ if (num != I2C_READ_MSG_NUM && num != I2C_WRITE_MSG_NUM) { -+ FPGA_I2C_ERROR("unsupport i2c_msg len:%d.\n", num); -+ return -EINVAL; -+ } -+ -+ if ((num == I2C_WRITE_MSG_NUM) && (msgs[0].len > fpga_i2c->reg.i2c_data_buf_len)) { -+ FPGA_I2C_ERROR("unsupport i2c_msg type:msg[0].flag:0x%x, buf len:0x%x.\n", -+ msgs[0].flags, msgs[0].len); -+ return -EINVAL; -+ } -+ -+ if (num == I2C_READ_MSG_NUM ) { -+ if ((msgs[0].flags & I2C_M_RD) ||!(msgs[1].flags & I2C_M_RD)) { -+ FPGA_I2C_ERROR("unsupport i2c_msg type:msg[0].flag:0x%x, msg[1].flag:0x%x.\n", -+ msgs[0].flags, msgs[1].flags); -+ return -EINVAL; -+ } -+ } -+ -+ if (fpga_i2c_is_busy(fpga_i2c)) { -+ FPGA_I2C_ERROR("fpga i2c adapter %d is busy, do reset.\n", adap->nr); -+ if (fpga_i2c->reset_cfg.i2c_adap_reset_flag == 1) { -+ -+ fpga_i2c_reset(fpga_i2c); -+ -+ fpga_i2c_adapter_init(fpga_i2c); -+ } -+ return -EAGAIN; -+ } -+ -+ if (fpga_i2c->i2c_params_check && fpga_i2c_params_check(fpga_i2c)) { -+ FPGA_I2C_ERROR("fpga i2c params check failed, try to reinitialize.\n"); -+ fpga_i2c_adapter_init(fpga_i2c); -+ } -+ -+ ret = 0; -+ i2c_addr_desc = &fpga_i2c->i2c_addr_desc; -+ i2c_addr_desc->reg_addr_len = 0; -+ mem_clear(i2c_addr_desc->read_reg_addr, sizeof(i2c_addr_desc->read_reg_addr)); -+ -+ for (i = 0; ret == 0 && i < num; i++) { -+ pmsg = &msgs[i]; -+ FPGA_I2C_VERBOSE("Doing %s %d byte(s) to/from 0x%02x - %d of %d messages\n", -+ pmsg->flags & I2C_M_RD ? "read" : "write", pmsg->len, pmsg->addr, i + 1, num); -+ -+ if (pmsg->flags & I2C_M_RD) { -+ ret = fpga_i2c_read(fpga_i2c, pmsg->addr, pmsg->buf, pmsg->len); -+ -+ if ((pmsg->len == 1) && (pmsg->flags & I2C_M_RECV_LEN)) { -+ if ((ret != 0) || (pmsg->buf[0] > I2C_SMBUS_BLOCK_MAX)) { -+ FPGA_I2C_ERROR("smbus block data read failed, ret:%d, read len:%u.\n", -+ ret, pmsg->buf[0]); -+ return -EPROTO; -+ } -+ pmsg->len = 1 + pmsg->buf[0]; -+ FPGA_I2C_VERBOSE("smbus block data read, read len:%d.\n", pmsg->len); -+ ret = fpga_i2c_read(fpga_i2c, pmsg->addr, pmsg->buf, pmsg->len); -+ } -+ } else { -+ ret = fpga_i2c_write(fpga_i2c, pmsg->addr, pmsg->buf, pmsg->len, num); -+ } -+ } -+ -+ return (ret != 0) ? ret : num; -+} -+ -+static u32 fpga_i2c_functionality(struct i2c_adapter *adap) -+{ -+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; -+} -+ -+static const struct i2c_algorithm fpga_i2c_algo = { -+ .master_xfer = fpga_i2c_xfer, -+ .functionality = fpga_i2c_functionality, -+}; -+ -+static struct i2c_adapter fpga_i2c_ops = { -+ .owner = THIS_MODULE, -+ .name = "wb_fpga_i2c", -+ .algo = &fpga_i2c_algo, -+}; -+ -+static int fpga_i2c_config_init(fpga_i2c_dev_t *fpga_i2c) -+{ -+ int ret = 0, rv = 0; -+ fpga_i2c_reg_t *reg; -+ fpga_i2c_reset_cfg_t *reset_cfg; -+ struct device *dev; -+ uint32_t i2c_offset_reg, i2c_data_buf_len_reg; -+ int32_t i2c_offset_val; -+ -+ fpga_i2c_bus_device_t *fpga_i2c_bus_device; -+ -+ dev = fpga_i2c->dev; -+ reg = &fpga_i2c->reg; -+ reset_cfg = &fpga_i2c->reset_cfg; -+ -+ i2c_offset_val = 0; -+ -+ if (dev->of_node) { -+ ret = 0; -+ ret += of_property_read_u32(dev->of_node, "i2c_ext_9548_addr", ®->i2c_ext_9548_addr); -+ ret += of_property_read_u32(dev->of_node, "i2c_ext_9548_chan", ®->i2c_ext_9548_chan); -+ ret += of_property_read_u32(dev->of_node, "i2c_slave", ®->i2c_slave); -+ ret += of_property_read_u32(dev->of_node, "i2c_reg", ®->i2c_reg); -+ ret += of_property_read_u32(dev->of_node, "i2c_data_len", ®->i2c_data_len); -+ ret += of_property_read_u32(dev->of_node, "i2c_ctrl", ®->i2c_ctrl); -+ ret += of_property_read_u32(dev->of_node, "i2c_status", ®->i2c_status); -+ ret += of_property_read_u32(dev->of_node, "i2c_scale", ®->i2c_scale); -+ ret += of_property_read_u32(dev->of_node, "i2c_filter", ®->i2c_filter); -+ ret += of_property_read_u32(dev->of_node, "i2c_stretch", ®->i2c_stretch); -+ ret += of_property_read_u32(dev->of_node, "i2c_ext_9548_exits_flag", ®->i2c_ext_9548_exits_flag); -+ ret += of_property_read_u32(dev->of_node, "i2c_reg_len", ®->i2c_reg_len); -+ ret += of_property_read_u32(dev->of_node, "i2c_in_9548_chan", ®->i2c_in_9548_chan); -+ ret += of_property_read_u32(dev->of_node, "i2c_data_buf", ®->i2c_data_buf); -+ ret += of_property_read_string(dev->of_node, "dev_name", &fpga_i2c->dev_name); -+ ret += of_property_read_u32(dev->of_node, "i2c_scale_value", &fpga_i2c->i2c_scale_value); -+ ret += of_property_read_u32(dev->of_node, "i2c_filter_value", &fpga_i2c->i2c_filter_value); -+ ret += of_property_read_u32(dev->of_node, "i2c_stretch_value", &fpga_i2c->i2c_stretch_value); -+ ret += of_property_read_u32(dev->of_node, "i2c_timeout", &fpga_i2c->i2c_timeout); -+ ret += of_property_read_u32(dev->of_node, "i2c_func_mode", &fpga_i2c->i2c_func_mode); -+ ret += of_property_read_u32(dev->of_node, "i2c_reset_addr", &reset_cfg->reset_addr); -+ ret += of_property_read_u32(dev->of_node, "i2c_reset_on", &reset_cfg->reset_on); -+ ret += of_property_read_u32(dev->of_node, "i2c_reset_off", &reset_cfg->reset_off); -+ ret += of_property_read_u32(dev->of_node, "i2c_rst_delay_b", &reset_cfg->reset_delay_b); -+ ret += of_property_read_u32(dev->of_node, "i2c_rst_delay", &reset_cfg->reset_delay); -+ ret += of_property_read_u32(dev->of_node, "i2c_rst_delay_a", &reset_cfg->reset_delay_a); -+ ret += of_property_read_u32(dev->of_node, "i2c_adap_reset_flag", &reset_cfg->i2c_adap_reset_flag); -+ -+ if (ret != 0) { -+ FPGA_I2C_ERROR("dts config error, ret:%d.\n", ret); -+ ret = -ENXIO; -+ return ret; -+ } -+ -+ rv = of_property_read_u32(dev->of_node, "i2c_data_buf_len_reg", &i2c_data_buf_len_reg); -+ if (rv == 0) { -+ ret = fpga_reg_read_32(fpga_i2c, i2c_data_buf_len_reg, ®->i2c_data_buf_len); -+ if (ret < 0) { -+ dev_err(fpga_i2c->dev, "Failed to get fpga i2c data buf length, reg addr: 0x%x, ret: %d\n", -+ i2c_data_buf_len_reg, ret); -+ return ret; -+ } -+ FPGA_I2C_VERBOSE("fpga i2c data buf length reg addr: 0x%x, value: %d\n", -+ i2c_data_buf_len_reg, reg->i2c_data_buf_len); -+ if (reg->i2c_data_buf_len == 0) { -+ reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; -+ } -+ } else { -+ ret = of_property_read_u32(dev->of_node, "i2c_data_buf_len", ®->i2c_data_buf_len); -+ if (ret != 0) { -+ reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; -+ ret = 0; -+ } -+ } -+ -+ rv = of_property_read_u32(dev->of_node, "i2c_offset_reg", &i2c_offset_reg); -+ if (rv == 0) { -+ ret = fpga_reg_read_32(fpga_i2c, i2c_offset_reg, &i2c_offset_val); -+ if (ret < 0) { -+ dev_err(fpga_i2c->dev, "Failed to get fpga i2c adapter offset value, reg addr: 0x%x, ret: %d\n", -+ i2c_offset_reg, ret); -+ return ret; -+ } -+ FPGA_I2C_VERBOSE("fpga i2c adapter offset reg addr: 0x%x, value: %d\n", -+ i2c_offset_reg, i2c_offset_val); -+ reg->i2c_scale +=i2c_offset_val; -+ reg->i2c_filter += i2c_offset_val; -+ reg->i2c_stretch += i2c_offset_val; -+ reg->i2c_ext_9548_exits_flag += i2c_offset_val; -+ reg->i2c_ext_9548_addr += i2c_offset_val; -+ reg->i2c_ext_9548_chan += i2c_offset_val; -+ reg->i2c_in_9548_chan += i2c_offset_val; -+ reg->i2c_slave += i2c_offset_val; -+ reg->i2c_reg += i2c_offset_val; -+ reg->i2c_reg_len += i2c_offset_val; -+ reg->i2c_data_len += i2c_offset_val; -+ reg->i2c_ctrl += i2c_offset_val; -+ reg->i2c_status += i2c_offset_val; -+ reg->i2c_data_buf += i2c_offset_val; -+ } -+ -+ ret = of_property_read_u32(dev->of_node, "i2c_err_vec", ®->i2c_err_vec); -+ if (ret != 0) { -+ reg->i2c_err_vec = DTS_NO_CFG_FLAG; -+ FPGA_I2C_VERBOSE("not support i2c_err_vec cfg. ret: %d, set DTS_NO_CFG_FLAG: %d\n", -+ ret, reg->i2c_err_vec); -+ ret = 0; /* Not configuring i2c_err_vec is not an error */ -+ } else { -+ if (i2c_offset_val != 0) { -+ reg->i2c_err_vec += i2c_offset_val; -+ } -+ } -+ } else { -+ if (dev->platform_data == NULL) { -+ dev_err(fpga_i2c->dev, "Failed to get platform data config.\n"); -+ ret = -ENXIO; -+ return ret; -+ } -+ fpga_i2c_bus_device = dev->platform_data; -+ fpga_i2c->dev_name = fpga_i2c_bus_device->dev_name; -+ fpga_i2c->adap_nr = fpga_i2c_bus_device->adap_nr; -+ fpga_i2c->i2c_scale_value = fpga_i2c_bus_device->i2c_scale_value; -+ fpga_i2c->i2c_filter_value = fpga_i2c_bus_device->i2c_filter_value; -+ fpga_i2c->i2c_stretch_value = fpga_i2c_bus_device->i2c_stretch_value; -+ fpga_i2c->i2c_timeout = fpga_i2c_bus_device->i2c_timeout; -+ fpga_i2c->i2c_func_mode = fpga_i2c_bus_device->i2c_func_mode; -+ fpga_i2c->i2c_params_check = fpga_i2c_bus_device->i2c_params_check; -+ -+ reset_cfg->reset_addr = fpga_i2c_bus_device->i2c_reset_addr; -+ reset_cfg->reset_on = fpga_i2c_bus_device->i2c_reset_on; -+ reset_cfg->reset_off = fpga_i2c_bus_device->i2c_reset_off; -+ reset_cfg->reset_delay_b = fpga_i2c_bus_device->i2c_rst_delay_b; -+ reset_cfg->reset_delay = fpga_i2c_bus_device->i2c_rst_delay; -+ reset_cfg->reset_delay_a = fpga_i2c_bus_device->i2c_rst_delay_a; -+ reset_cfg->i2c_adap_reset_flag = fpga_i2c_bus_device->i2c_adap_reset_flag; -+ -+ reg->i2c_ext_9548_addr = fpga_i2c_bus_device->i2c_ext_9548_addr; -+ reg->i2c_ext_9548_chan = fpga_i2c_bus_device->i2c_ext_9548_chan; -+ reg->i2c_slave = fpga_i2c_bus_device->i2c_slave; -+ reg->i2c_reg = fpga_i2c_bus_device->i2c_reg; -+ reg->i2c_data_len = fpga_i2c_bus_device->i2c_data_len; -+ reg->i2c_ctrl = fpga_i2c_bus_device->i2c_ctrl; -+ reg->i2c_status = fpga_i2c_bus_device->i2c_status; -+ reg->i2c_scale = fpga_i2c_bus_device->i2c_scale; -+ reg->i2c_filter = fpga_i2c_bus_device->i2c_filter; -+ reg->i2c_stretch = fpga_i2c_bus_device->i2c_stretch; -+ reg->i2c_ext_9548_exits_flag = fpga_i2c_bus_device->i2c_ext_9548_exits_flag; -+ reg->i2c_reg_len = fpga_i2c_bus_device->i2c_reg_len; -+ reg->i2c_in_9548_chan = fpga_i2c_bus_device->i2c_in_9548_chan; -+ reg->i2c_data_buf = fpga_i2c_bus_device->i2c_data_buf; -+ -+ i2c_data_buf_len_reg = fpga_i2c_bus_device->i2c_data_buf_len_reg; -+ if (i2c_data_buf_len_reg > 0) { -+ ret = fpga_reg_read_32(fpga_i2c, i2c_data_buf_len_reg, ®->i2c_data_buf_len); -+ if (ret < 0) { -+ dev_err(fpga_i2c->dev, "Failed to get fpga i2c data buf length, reg addr: 0x%x, ret: %d\n", -+ i2c_data_buf_len_reg, ret); -+ return ret; -+ } -+ FPGA_I2C_VERBOSE("fpga i2c data buf length reg addr: 0x%x, value: %d\n", -+ i2c_data_buf_len_reg, reg->i2c_data_buf_len); -+ if (reg->i2c_data_buf_len == 0) { -+ reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; -+ } -+ } else { -+ if (fpga_i2c_bus_device->i2c_data_buf_len == 0) { -+ reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; -+ FPGA_I2C_VERBOSE("not support i2c_data_buf_len cfg, set default_val:%d\n", -+ reg->i2c_data_buf_len); -+ } else { -+ reg->i2c_data_buf_len = fpga_i2c_bus_device->i2c_data_buf_len; -+ } -+ } -+ -+ i2c_offset_reg = fpga_i2c_bus_device->i2c_offset_reg; -+ if (i2c_offset_reg > 0) { -+ rv = fpga_reg_read_32(fpga_i2c, i2c_offset_reg, &i2c_offset_val); -+ if (rv < 0) { -+ dev_err(fpga_i2c->dev, "Failed to get fpga i2c adapter offset value, reg addr: 0x%x, rv: %d\n", -+ i2c_offset_reg, rv); -+ return rv; -+ } -+ FPGA_I2C_VERBOSE("fpga i2c adapter offset reg addr: 0x%x, value: %d\n", -+ i2c_offset_reg, i2c_offset_val); -+ reg->i2c_scale +=i2c_offset_val; -+ reg->i2c_filter += i2c_offset_val; -+ reg->i2c_stretch += i2c_offset_val; -+ reg->i2c_ext_9548_exits_flag += i2c_offset_val; -+ reg->i2c_ext_9548_addr += i2c_offset_val; -+ reg->i2c_ext_9548_chan += i2c_offset_val; -+ reg->i2c_in_9548_chan += i2c_offset_val; -+ reg->i2c_slave += i2c_offset_val; -+ reg->i2c_reg += i2c_offset_val; -+ reg->i2c_reg_len += i2c_offset_val; -+ reg->i2c_data_len += i2c_offset_val; -+ reg->i2c_ctrl += i2c_offset_val; -+ reg->i2c_status += i2c_offset_val; -+ reg->i2c_data_buf += i2c_offset_val; -+ } -+ -+ if (fpga_i2c_bus_device->i2c_err_vec == 0) { -+ reg->i2c_err_vec = DTS_NO_CFG_FLAG; -+ FPGA_I2C_VERBOSE("not support i2c_err_vec cfg, set DTS_NO_CFG_FLAG:%d\n", -+ reg->i2c_err_vec); -+ } else { -+ reg->i2c_err_vec = fpga_i2c_bus_device->i2c_err_vec; -+ if (i2c_offset_val != 0) { -+ reg->i2c_err_vec += i2c_offset_val; -+ } -+ } -+ } -+ -+ FPGA_I2C_VERBOSE("i2c_ext_9548_addr:0x%x, i2c_ext_9548_chan:0x%x, i2c_slave:0x%x, i2c_reg:0x%x, i2c_data_len:0x%x.\n", -+ reg->i2c_ext_9548_addr, reg->i2c_ext_9548_chan, reg->i2c_slave, reg->i2c_reg, reg->i2c_data_len); -+ FPGA_I2C_VERBOSE("i2c_ctrl:0x%x, i2c_status:0x%x, i2c_scale:0x%x, i2c_filter:0x%x, i2c_stretch:0x%x.\n", -+ reg->i2c_ctrl, reg->i2c_status, reg->i2c_scale, reg->i2c_filter, reg->i2c_stretch); -+ FPGA_I2C_VERBOSE("i2c_ext_9548_exits_flag:0x%x, i2c_in_9548_chan:0x%x, i2c_data_buf:0x%x, i2c_reg_len:0x%x, i2c_data_buf_len:0x%x.\n", -+ reg->i2c_ext_9548_exits_flag, reg->i2c_in_9548_chan, reg->i2c_data_buf, reg->i2c_reg_len, reg->i2c_data_buf_len); -+ FPGA_I2C_VERBOSE("dev_name:%s, i2c_scale_value:0x%x, i2c_filter_value:0x%x, i2c_stretch_value:0x%x, i2c_timeout:0x%x.\n", -+ fpga_i2c->dev_name, fpga_i2c->i2c_scale_value, fpga_i2c->i2c_filter_value, fpga_i2c->i2c_stretch_value, fpga_i2c->i2c_timeout); -+ FPGA_I2C_VERBOSE("i2c_reset_addr:0x%x, i2c_reset_on:0x%x, i2c_reset_off:0x%x, i2c_rst_delay_b:0x%x, i2c_rst_delay:0x%x, i2c_rst_delay_a:0x%x.\n", -+ reset_cfg->reset_addr, reset_cfg->reset_on, reset_cfg->reset_off, reset_cfg->reset_delay_b, reset_cfg->reset_delay, reset_cfg->reset_delay_a); -+ FPGA_I2C_VERBOSE("i2c_adap_reset_flag:0x%x.\n", reset_cfg->i2c_adap_reset_flag); -+ FPGA_I2C_VERBOSE("i2c_err_vec:0x%x\n", reg->i2c_err_vec); -+ -+ return ret; -+} -+ -+static int fpga_i2c_probe(struct platform_device *pdev) -+{ -+ int ret; -+ fpga_i2c_dev_t *fpga_i2c; -+ struct device *dev; -+ -+ fpga_i2c = devm_kzalloc(&pdev->dev, sizeof(fpga_i2c_dev_t), GFP_KERNEL); -+ if (!fpga_i2c) { -+ dev_err(&pdev->dev, "devm_kzalloc failed.\n"); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ fpga_i2c->dev = &pdev->dev; -+ -+ ret = fpga_i2c_config_init(fpga_i2c); -+ if (ret !=0) { -+ dev_err(fpga_i2c->dev, "Failed to get fpga i2c dts config.\n"); -+ goto out; -+ } -+ -+ ret = fpga_i2c_adapter_init(fpga_i2c); -+ if (ret !=0) { -+ dev_err(fpga_i2c->dev, "Failed to init fpga i2c adapter.\n"); -+ goto out; -+ } -+ -+ if (fpga_i2c->dev->of_node) { -+ fpga_i2c->i2c_params_check = of_property_read_bool(fpga_i2c->dev->of_node, "i2c_params_check"); -+ } -+ FPGA_I2C_VERBOSE("fpga i2c params check flag:%d.\n", fpga_i2c->i2c_params_check); -+ -+ init_waitqueue_head(&fpga_i2c->queue); -+ -+ dev = fpga_i2c->dev; -+ fpga_i2c->adap = fpga_i2c_ops; -+ fpga_i2c->adap.timeout = msecs_to_jiffies(fpga_i2c->i2c_timeout); -+ fpga_i2c->adap.dev.parent = &pdev->dev; -+ fpga_i2c->adap.dev.of_node = pdev->dev.of_node; -+ i2c_set_adapdata(&fpga_i2c->adap, fpga_i2c); -+ platform_set_drvdata(pdev, fpga_i2c); -+ -+ if (fpga_i2c->dev->of_node) { -+ /* adap.nr get from dts aliases */ -+ ret = i2c_add_adapter(&fpga_i2c->adap); -+ } else { -+ fpga_i2c->adap.nr = fpga_i2c->adap_nr; -+ ret = i2c_add_numbered_adapter(&fpga_i2c->adap); -+ } -+ -+ if (ret < 0) { -+ dev_info(fpga_i2c->dev, "Failed to add adapter.\n"); -+ goto fail_add; -+ } -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) -+ of_i2c_register_devices(&fpga_i2c->adap); -+#endif -+ dev_info(fpga_i2c->dev, "registered i2c-%d for %s using mode %d with base address:0x%x, data buf len: %d success.\n", -+ fpga_i2c->adap.nr, fpga_i2c->dev_name, fpga_i2c->i2c_func_mode, fpga_i2c->reg.i2c_scale, -+ fpga_i2c->reg.i2c_data_buf_len); -+ return 0; -+ -+fail_add: -+ platform_set_drvdata(pdev, NULL); -+out: -+ return ret; -+}; -+ -+static int fpga_i2c_remove(struct platform_device *pdev) -+{ -+ fpga_i2c_dev_t *fpga_i2c; -+ -+ fpga_i2c = platform_get_drvdata(pdev); -+ i2c_del_adapter(&fpga_i2c->adap); -+ platform_set_drvdata(pdev, NULL); -+ return 0; -+}; -+ -+static struct of_device_id fpga_i2c_match[] = { -+ { -+ .compatible = "wb-fpga-i2c", -+ }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, fpga_i2c_match); -+ -+static struct platform_driver wb_fpga_i2c_driver = { -+ .probe = fpga_i2c_probe, -+ .remove = fpga_i2c_remove, -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = DRV_NAME, -+ .of_match_table = fpga_i2c_match, -+ }, -+}; -+ -+static int __init wb_fpga_i2c_init(void) -+{ -+ return platform_driver_register(&wb_fpga_i2c_driver); -+} -+ -+static void __exit wb_fpga_i2c_exit(void) -+{ -+ platform_driver_unregister(&wb_fpga_i2c_driver); -+} -+ -+module_init(wb_fpga_i2c_init); -+module_exit(wb_fpga_i2c_exit); -+MODULE_DESCRIPTION("fpga i2c adapter driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pca954x_drv.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pca954x_drv.c -new file mode 100644 -index 000000000..8fd9e4f0f ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pca954x_drv.c -@@ -0,0 +1,534 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "fpga_i2c.h" -+ -+extern int i2c_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); -+extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int io_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); -+extern int spi_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+ -+#define PCA954X_MAX_NCHANS (8) -+#define FPGA_INTERNAL_PCA9548 (1) -+#define FPGA_EXTERNAL_PCA9548 (2) -+#define FPGA_I2C_EXT_9548_EXITS (0x01 << 0) -+#define FPGA_I2C_9548_NO_RESET (0x01 << 1) -+ -+#define SYMBOL_I2C_DEV_MODE (1) -+#define FILE_MODE (2) -+#define SYMBOL_PCIE_DEV_MODE (3) -+#define SYMBOL_IO_DEV_MODE (4) -+#define SYMBOL_SPI_DEV_MODE (5) -+ -+int g_fpga_pca954x_debug = 0; -+int g_fpga_pca954x_error = 0; -+ -+module_param(g_fpga_pca954x_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_fpga_pca954x_error, int, S_IRUGO | S_IWUSR); -+ -+#define FPGA_PCA954X_VERBOSE(fmt, args...) do { \ -+ if (g_fpga_pca954x_debug) { \ -+ printk(KERN_INFO "[FPGA_PCA954X][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define FPGA_PCA954X_ERROR(fmt, args...) do { \ -+ if (g_fpga_pca954x_error) { \ -+ printk(KERN_ERR "[FPGA_PCA954X][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+enum pca_type { -+ pca_9540, -+ pca_9541, -+ pca_9542, -+ pca_9543, -+ pca_9544, -+ pca_9545, -+ pca_9546, -+ pca_9547, -+ pca_9548, -+}; -+ -+struct pca954x { -+ enum pca_type type; -+ struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS]; -+ u8 last_chan; /* last register value */ -+ uint32_t fpga_9548_flag; -+ uint32_t fpga_9548_reset_flag; -+ uint32_t pca9548_base_nr; -+ struct i2c_client *client; -+}; -+ -+struct chip_desc { -+ u8 nchans; -+ u8 enable; /* used for muxes only */ -+ enum muxtype { -+ pca954x_ismux = 0, -+ pca954x_isswi -+ } muxtype; -+}; -+ -+/* Provide specs for the PCA954x types we know about */ -+static const struct chip_desc chips[] = { -+ [pca_9540] = { -+ .nchans = 2, -+ .enable = 0x4, -+ .muxtype = pca954x_ismux, -+ }, -+ [pca_9541] = { -+ .nchans = 1, -+ .muxtype = pca954x_isswi, -+ }, -+ [pca_9543] = { -+ .nchans = 2, -+ .muxtype = pca954x_isswi, -+ }, -+ [pca_9544] = { -+ .nchans = 4, -+ .enable = 0x4, -+ .muxtype = pca954x_ismux, -+ }, -+ [pca_9545] = { -+ .nchans = 4, -+ .muxtype = pca954x_isswi, -+ }, -+ [pca_9547] = { -+ .nchans = 8, -+ .enable = 0x8, -+ .muxtype = pca954x_ismux, -+ }, -+ [pca_9548] = { -+ .nchans = 8, -+ .muxtype = pca954x_isswi, -+ }, -+}; -+ -+static const struct i2c_device_id fpga_pca954x_id[] = { -+ { "wb_fpga_pca9540", pca_9540 }, -+ { "wb_fpga_pca9541", pca_9541 }, -+ { "wb_fpga_pca9542", pca_9543 }, -+ { "wb_fpga_pca9543", pca_9543 }, -+ { "wb_fpga_pca9544", pca_9544 }, -+ { "wb_fpga_pca9545", pca_9545 }, -+ { "wb_fpga_pca9546", pca_9545 }, -+ { "wb_fpga_pca9547", pca_9547 }, -+ { "wb_fpga_pca9548", pca_9548 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, fpga_pca954x_id); -+ -+static int fpga_file_write(const char *path, int pos, unsigned char *val, size_t size) -+{ -+ int ret; -+ struct file *filp; -+ loff_t tmp_pos; -+ -+ filp = filp_open(path, O_RDWR, 777); -+ if (IS_ERR(filp)) { -+ FPGA_PCA954X_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); -+ filp = NULL; -+ goto exit; -+ } -+ -+ tmp_pos = (loff_t)pos; -+ ret = kernel_write(filp, val, size, &tmp_pos); -+ if (ret < 0) { -+ FPGA_PCA954X_ERROR("kernel_write failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); -+ goto exit; -+ } -+ -+ vfs_fsync(filp, 1); -+ filp_close(filp, NULL); -+ -+ return ret; -+ -+exit: -+ if (filp != NULL) { -+ filp_close(filp, NULL); -+ } -+ -+ return -1; -+ -+} -+ -+static int fpga_device_write(fpga_i2c_dev_t *fpga_i2c, int pos, unsigned char *val, size_t size) -+{ -+ int ret; -+ -+ switch (fpga_i2c->i2c_func_mode) { -+ case SYMBOL_I2C_DEV_MODE: -+ ret = i2c_device_func_write(fpga_i2c->dev_name, pos, val, size); -+ break; -+ case FILE_MODE: -+ ret = fpga_file_write(fpga_i2c->dev_name, pos, val, size); -+ break; -+ case SYMBOL_PCIE_DEV_MODE: -+ ret = pcie_device_func_write(fpga_i2c->dev_name, pos, val, size); -+ break; -+ case SYMBOL_IO_DEV_MODE: -+ ret = io_device_func_write(fpga_i2c->dev_name, pos, val, size); -+ break; -+ case SYMBOL_SPI_DEV_MODE: -+ ret = spi_device_func_write(fpga_i2c->dev_name, pos, val, size); -+ break; -+ default: -+ FPGA_PCA954X_ERROR("err func_mode %d, write failed.\n", fpga_i2c->i2c_func_mode); -+ return -EINVAL; -+ } -+ return ret; -+} -+ -+static int fpga_reg_write(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t val) -+{ -+ int ret; -+ -+ ret = fpga_device_write(fpga_i2c, addr, &val, sizeof(uint8_t)); -+ if (ret < 0) { -+ FPGA_PCA954X_ERROR("fpga_device_write failed. name:%s, addr:0x%x, value:0x%x.\n", -+ fpga_i2c->dev_name, addr, val); -+ return ret; -+ } -+ -+ FPGA_PCA954X_VERBOSE("fpga reg write success, dev name:%s, offset:0x%x, value:0x%x.\n", -+ fpga_i2c->dev_name, addr, val); -+ return 0; -+} -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,7) -+static int pca954x_select_chan(struct i2c_adapter *adap, void *client, u32 chan) -+{ -+ struct pca954x *data = i2c_get_clientdata(client); -+ fpga_i2c_dev_t *fpga_i2c; -+ fpga_i2c_reg_t *reg; -+ int ret; -+ u8 regval, i2c_9548_opt; -+ -+ while(i2c_parent_is_i2c_adapter(adap)){ -+ adap = to_i2c_adapter(adap->dev.parent); -+ } -+ -+ FPGA_PCA954X_VERBOSE("root bus:%d, chan:0x%x, 9548 flag:0x%x, 9548 addr:0x%x.\n", -+ adap->nr, chan, data->fpga_9548_flag, client->addr); -+ fpga_i2c = i2c_get_adapdata(adap); -+ reg = &fpga_i2c->reg; -+ -+ regval = 1 << chan; -+ if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { -+ ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, regval); -+ } else { -+ if (data->fpga_9548_reset_flag == 1) { -+ i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS & ~(FPGA_I2C_9548_NO_RESET); -+ } else { -+ i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS | FPGA_I2C_9548_NO_RESET; -+ } -+ FPGA_PCA954X_VERBOSE("fpga pca9548 reset flag:0x%x, opt:0x%x.\n", -+ data->fpga_9548_reset_flag, i2c_9548_opt); -+ ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, i2c_9548_opt); -+ ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_addr, client->addr); -+ ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, regval); -+ } -+ -+ return ret; -+} -+ -+static int pca954x_deselect_mux(struct i2c_adapter *adap, void *client, u32 chan) -+{ -+ struct pca954x *data = i2c_get_clientdata(client); -+ fpga_i2c_dev_t *fpga_i2c; -+ fpga_i2c_reg_t *reg; -+ int ret; -+ -+ while(i2c_parent_is_i2c_adapter(adap)){ -+ adap = to_i2c_adapter(adap->dev.parent); -+ } -+ -+ fpga_i2c = i2c_get_adapdata(adap); -+ reg = &fpga_i2c->reg; -+ /* Deselect active channel */ -+ data->last_chan = 0; -+ if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { -+ ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, 0); -+ } else { -+ -+ ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, FPGA_I2C_9548_NO_RESET); -+ ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, 0); -+ } -+ -+ return ret; -+} -+#else -+static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) -+{ -+ struct pca954x *data = i2c_mux_priv(muxc); -+ struct i2c_client *client = data->client; -+ struct i2c_adapter *adap; -+ fpga_i2c_dev_t *fpga_i2c; -+ fpga_i2c_reg_t *reg; -+ int ret; -+ u8 regval, i2c_9548_opt; -+ -+ adap = muxc->parent; -+ while(i2c_parent_is_i2c_adapter(adap)){ -+ adap = to_i2c_adapter(adap->dev.parent); -+ } -+ -+ FPGA_PCA954X_VERBOSE("root bus:%d, chan:0x%x, 9548 flag:0x%x, 9548 addr:0x%x.\n", -+ adap->nr, chan, data->fpga_9548_flag, client->addr); -+ fpga_i2c = i2c_get_adapdata(adap); -+ reg = &fpga_i2c->reg; -+ -+ regval = 1 << chan; -+ if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { -+ ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, regval); -+ } else { -+ if (data->fpga_9548_reset_flag == 1) { -+ i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS & ~(FPGA_I2C_9548_NO_RESET); -+ } else { -+ i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS | FPGA_I2C_9548_NO_RESET; -+ } -+ FPGA_PCA954X_VERBOSE("fpga pca9548 reset flag:0x%x, opt:0x%x.\n", -+ data->fpga_9548_reset_flag, i2c_9548_opt); -+ ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, i2c_9548_opt); -+ ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_addr, client->addr); -+ ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, regval); -+ } -+ -+ return ret; -+} -+ -+static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan) -+{ -+ struct pca954x *data = i2c_mux_priv(muxc); -+ struct i2c_adapter *adap; -+ fpga_i2c_dev_t *fpga_i2c; -+ fpga_i2c_reg_t *reg; -+ int ret; -+ -+ adap = muxc->parent; -+ while(i2c_parent_is_i2c_adapter(adap)){ -+ adap = to_i2c_adapter(adap->dev.parent); -+ } -+ -+ fpga_i2c = i2c_get_adapdata(adap); -+ reg = &fpga_i2c->reg; -+ ret = 0; -+ /* Deselect active channel */ -+ data->last_chan = 0; -+ -+ if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { -+ ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, 0); -+ } else { -+ -+ ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, FPGA_I2C_9548_NO_RESET); -+ ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, 0); -+ } -+ -+ return ret; -+} -+#endif -+/* -+ * I2C init/probing/exit functions -+ */ -+static int fpga_i2c_pca954x_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); -+ int num, force, class; -+ struct pca954x *data; -+ int ret = -ENODEV; -+ struct device *dev; -+ int dynamic_nr = 1; -+ fpga_pca954x_device_t *fpga_pca954x_device; -+ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(4,6,7) -+ struct i2c_mux_core *muxc; -+#endif -+ -+ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) { -+ dev_err(&client->dev, "i2c adapter:%d, unsupport I2C_FUNC_SMBUS_BYTE.\n", adap->nr); -+ goto err; -+ } -+ -+#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) -+ data = kzalloc(sizeof(struct pca954x), GFP_KERNEL); -+ if (!data) { -+ dev_err(&client->dev, "kzalloc failed.\n"); -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ i2c_set_clientdata(client, data); -+#else -+ muxc = i2c_mux_alloc(adap, &client->dev, -+ PCA954X_MAX_NCHANS, sizeof(*data), 0, -+ pca954x_select_chan, pca954x_deselect_mux); -+ if (!muxc) { -+ dev_err(&client->dev, "i2c_mux_alloc failed.\n"); -+ return -ENOMEM; -+ } -+ data = i2c_mux_priv(muxc); -+ i2c_set_clientdata(client, muxc); -+ data->client = client; -+#endif -+ -+ dev = &client->dev; -+ if (dev == NULL) { -+ dev_err(&client->dev, "dev is NULL.\n"); -+ ret = -ENODEV; -+ goto exit_free; -+ } -+ -+ if (dev->of_node == NULL) { -+ if (client->dev.platform_data == NULL) { -+ dev_err(&client->dev, "Failed to get 954x platform data config.\n"); -+ ret = -EINVAL; -+ goto exit_free; -+ } -+ fpga_pca954x_device = client->dev.platform_data; -+ data->fpga_9548_flag = fpga_pca954x_device->fpga_9548_flag; -+ data->fpga_9548_reset_flag = fpga_pca954x_device->fpga_9548_reset_flag; -+ data->pca9548_base_nr = fpga_pca954x_device->pca9548_base_nr; -+ if (data->pca9548_base_nr == 0) { -+ -+ dynamic_nr = 1; -+ } else { -+ dynamic_nr = 0; -+ FPGA_PCA954X_VERBOSE("pca9548_base_nr:%u.\n", data->pca9548_base_nr); -+ } -+ } else { -+ data->type = id->driver_data; -+ /* BUS ID */ -+ ret = of_property_read_u32(dev->of_node, "fpga_9548_flag", &data->fpga_9548_flag); -+ ret += of_property_read_u32(dev->of_node, "fpga_9548_reset_flag", &data->fpga_9548_reset_flag); -+ if (ret != 0) { -+ dev_err(&client->dev, "Failed to get 954x dts config, ret:%d.\n", ret); -+ ret = -EINVAL; -+ goto exit_free; -+ } -+ if (of_property_read_u32(dev->of_node, "pca9548_base_nr", &data->pca9548_base_nr)) { -+ -+ dynamic_nr = 1; -+ FPGA_PCA954X_VERBOSE("pca9548_base_nr not found, use dynamic adap number"); -+ } else { -+ dynamic_nr = 0; -+ FPGA_PCA954X_VERBOSE("pca9548_base_nr:%u.\n", data->pca9548_base_nr); -+ } -+ } -+ -+ if (data->fpga_9548_flag != FPGA_EXTERNAL_PCA9548 && data->fpga_9548_flag != FPGA_INTERNAL_PCA9548) { -+ dev_err(&client->dev, "Error: fpga 954x flag config error, value:0x%x.\n", data->fpga_9548_flag); -+ ret = -EINVAL; -+ goto exit_free; -+ } -+ -+ data->type = id->driver_data; -+ data->last_chan = 0; /* force the first selection */ -+ -+ /* Now create an adapter for each channel */ -+ for (num = 0; num < chips[data->type].nchans; num++) { -+ if (dynamic_nr == 1) { -+ force = 0; /* dynamic adap number */ -+ } else { -+ force = data->pca9548_base_nr + num; -+ } -+ class = 0; /* no class by default */ -+#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) -+ data->virt_adaps[num] = -+ i2c_add_mux_adapter(adap, &client->dev, client, -+ force, num, class, pca954x_select_chan, pca954x_deselect_mux); -+ -+ if (data->virt_adaps[num] == NULL) { -+ ret = -ENODEV; -+ dev_err(&client->dev, "Failed to register multiplexed adapter %d as bus %d\n", -+ num, force); -+ goto virt_reg_failed; -+ } -+#else -+ ret = i2c_mux_add_adapter(muxc, force, num, class); -+ if (ret) { -+ dev_err(&client->dev, "Failed to register multiplexed adapter %d as bus %d\n", -+ num, force); -+ goto virt_reg_failed; -+ } -+#endif -+ } /* end for num = 0; num < chips[data->type].nchans... */ -+ -+ dev_info(&client->dev, "registered %d multiplexed busses for I2C %s %s\n", -+ num, chips[data->type].muxtype == pca954x_ismux ? "mux" : "switch", client->name); -+ -+ return 0; -+ -+virt_reg_failed: -+#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) -+ for (num--; num >= 0; num--) -+ i2c_del_mux_adapter(data->virt_adaps[num]); -+exit_free: -+ kfree(data); -+#else -+exit_free: -+ i2c_mux_del_adapters(muxc); -+#endif -+err: -+ return ret; -+} -+ -+static int fpga_i2c_pca954x_remove(struct i2c_client *client) -+{ -+#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) -+ struct pca954x *data = i2c_get_clientdata(client); -+ const struct chip_desc *chip = &chips[data->type]; -+ int i; -+ -+ for (i = 0; i < chip->nchans; ++i) -+ if (data->virt_adaps[i]) { -+ i2c_del_mux_adapter(data->virt_adaps[i]); -+ data->virt_adaps[i] = NULL; -+ } -+ -+ kfree(data); -+#else -+ struct i2c_mux_core *muxc = i2c_get_clientdata(client); -+ -+ i2c_mux_del_adapters(muxc); -+#endif -+ -+ return 0; -+} -+ -+static struct i2c_driver fpga_i2c_pca954x_driver = { -+ .driver = { -+ .name = "wb_fpga_pca954x", -+ .owner = THIS_MODULE, -+ }, -+ .probe = fpga_i2c_pca954x_probe, -+ .remove = fpga_i2c_pca954x_remove, -+ .id_table = fpga_pca954x_id, -+}; -+ -+static int __init fpga_i2c_pca954x_init(void) -+{ -+ int ret; -+ -+ ret = i2c_add_driver(&fpga_i2c_pca954x_driver); -+ return ret; -+} -+ -+static void __exit fpga_i2c_pca954x_exit(void) -+{ -+ i2c_del_driver(&fpga_i2c_pca954x_driver); -+} -+ -+module_init(fpga_i2c_pca954x_init); -+module_exit(fpga_i2c_pca954x_exit); -+MODULE_DESCRIPTION("fpga pca954x driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pcie.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pcie.c -new file mode 100644 -index 000000000..aedcc78da ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pcie.c -@@ -0,0 +1,164 @@ -+/* -+ * wb_fpga_pcie.c -+ * ko to enable fpga pcie -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#define FPGA_MSI_IRQ_NUM (14) -+#define FPGA_MSI_IRQ_BEGIN (0) -+#define XILINX_FPGA_USE_MSI (0) -+#define XILINX_FPGA_NUSE_MSI (1) -+ -+int g_fpga_pcie_dev_debug = 0; -+int g_fpga_pcie_dev_error = 0; -+module_param(g_fpga_pcie_dev_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_fpga_pcie_dev_error, int, S_IRUGO | S_IWUSR); -+ -+#define FPGA_PCIE_DEV_VERBOSE(fmt, args...) do { \ -+ if (g_fpga_pcie_dev_debug) { \ -+ printk(KERN_INFO "[FPGA_PCIE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define FPGA_PCIE_DEV_ERROR(fmt, args...) do { \ -+ if (g_fpga_pcie_dev_error) { \ -+ printk(KERN_ERR "[FPGA_PCIE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+typedef struct wb_fpga_pcie_s { -+ struct pci_dev *pci_dev; -+ int driver_data; -+} wb_fpga_pcie_t; -+ -+static void fpga_pcie_recover(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ struct resource *mem_base; -+ u32 bar0_val; -+ int ret; -+ -+ mem_base = &pdev->resource[0]; -+ ret = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0_val); -+ if (ret) { -+ FPGA_PCIE_DEV_ERROR("pci_read_config_dword failed ret %d.\n", ret); -+ return; -+ } -+ FPGA_PCIE_DEV_VERBOSE("mem_base->start[0x%llx], bar0_val[0x%x], ret %d.\n", -+ mem_base->start, bar0_val, ret); -+ -+ if (bar0_val != mem_base->start) { -+ ret = pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, mem_base->start); -+ if (ret) { -+ FPGA_PCIE_DEV_ERROR("pci_write_config_dword mem_base->start[0x%llx], failed ret %d.\n", mem_base->start, ret); -+ return; -+ } -+ FPGA_PCIE_DEV_VERBOSE("pci_write_config_dword mem_base->start[0x%llx] success.\n", mem_base->start); -+ } else { -+ FPGA_PCIE_DEV_VERBOSE("mem_base->start[0x%llx], bar0_val[0x%x], do nothing.\n", -+ mem_base->start, bar0_val); -+ } -+} -+ -+static int fpga_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ int err; -+ wb_fpga_pcie_t *wb_fpga_pcie; -+ -+ FPGA_PCIE_DEV_VERBOSE("Enter vendor 0x%x, subsystem_vendor 0x%x.\n", pdev->vendor, pdev->subsystem_vendor); -+ -+ wb_fpga_pcie = devm_kzalloc(&pdev->dev, sizeof(wb_fpga_pcie_t), GFP_KERNEL); -+ if (!wb_fpga_pcie) { -+ dev_err(&pdev->dev, "devm_kzalloc failed.\n"); -+ return -ENOMEM; -+ } -+ -+ fpga_pcie_recover(pdev, id); -+ -+ /* enable device: ask low-level code to enable I/O and memory */ -+ FPGA_PCIE_DEV_VERBOSE("start pci_enable_device!\n"); -+ err = pci_enable_device(pdev); -+ if (err) { -+ dev_err(&pdev->dev, "Failed to enable pci device, ret:%d.\n", err); -+ return err; -+ } -+ -+ FPGA_PCIE_DEV_VERBOSE("start pci_set_master!\n"); -+ pci_set_master(pdev); -+ -+ wb_fpga_pcie->driver_data = id->driver_data; -+ wb_fpga_pcie->pci_dev = pdev; -+ pci_set_drvdata(pdev, wb_fpga_pcie); -+ -+ if (wb_fpga_pcie->driver_data == XILINX_FPGA_USE_MSI) { -+ FPGA_PCIE_DEV_VERBOSE("start pci_enable_msi_range!\n"); -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,152) -+ err = pci_enable_msi_range(pdev, FPGA_MSI_IRQ_BEGIN + 1, FPGA_MSI_IRQ_NUM); -+#else -+ err = pci_alloc_irq_vectors_affinity(pdev, FPGA_MSI_IRQ_BEGIN + 1, -+ FPGA_MSI_IRQ_NUM, PCI_IRQ_MSI, NULL); -+#endif -+ if (err != FPGA_MSI_IRQ_NUM) { -+ FPGA_PCIE_DEV_ERROR("pci_enable_msi_block err %d FPGA_MSI_IRQ_NUM %d.\n", err, -+ FPGA_MSI_IRQ_NUM); -+ dev_err(&pdev->dev, "Failed to enable pci msi, ret:%d.\n", err); -+ return -EINVAL; -+ } -+ } -+ -+ dev_info(&pdev->dev, "fpga pci device init success.\n"); -+ return 0; -+} -+ -+static void fpga_pcie_remove(struct pci_dev *pdev) -+{ -+ wb_fpga_pcie_t *wb_fpga_pcie; -+ -+ FPGA_PCIE_DEV_VERBOSE("fpga_pcie_remove.\n"); -+ -+ wb_fpga_pcie = pci_get_drvdata(pdev); -+ if (wb_fpga_pcie->driver_data == XILINX_FPGA_USE_MSI) { -+ FPGA_PCIE_DEV_VERBOSE("start pci_disable_msi!\n"); -+ pci_disable_msi(pdev); -+ } -+ -+ pci_disable_device(pdev); -+ return; -+} -+ -+static const struct pci_device_id fpga_pci_ids[] = { -+ { PCI_DEVICE(0x10ee, 0x7022), .driver_data = XILINX_FPGA_USE_MSI}, -+ { PCI_DEVICE(0x10ee, 0x7011), .driver_data = XILINX_FPGA_NUSE_MSI}, -+ {0} -+}; -+MODULE_DEVICE_TABLE(pci, fpga_pci_ids); -+ -+static struct pci_driver wb_fpga_pcie_driver = { -+ .name = "wb_fpga_pcie", -+ .id_table = fpga_pci_ids,/* only dynamic id's */ -+ .probe = fpga_pcie_probe, -+ .remove = fpga_pcie_remove, -+}; -+ -+static int __init wb_fpga_pcie_init(void) -+{ -+ -+ FPGA_PCIE_DEV_VERBOSE("wb_fpga_pcie_init enter!\n"); -+ return pci_register_driver(&wb_fpga_pcie_driver); -+} -+ -+static void __exit wb_fpga_pcie_exit(void) -+{ -+ FPGA_PCIE_DEV_VERBOSE("wb_fpga_pcie_exit enter!\n"); -+ pci_unregister_driver(&wb_fpga_pcie_driver); -+ return; -+} -+ -+module_init(wb_fpga_pcie_init); -+module_exit(wb_fpga_pcie_exit); -+MODULE_DESCRIPTION("fpga pcie driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_d1500.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_d1500.c -new file mode 100644 -index 000000000..7d5d5da87 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_d1500.c -@@ -0,0 +1,367 @@ -+/* -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ * -+ * Copyright (C) 2011, 2012 Cavium Inc. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define GPIO_NAME "wb_gpio_d1500" -+ -+#define GPIO_BASE (0x500) -+#define GP_IO_SEL (GPIO_BASE + 0x4) -+#define GP_LVL (GPIO_BASE + 0xC) -+#define GPI_NMI_EN (GPIO_BASE + 0x28) -+#define GPI_NMI_STS (GPIO_BASE + 0x2a) -+#define GPI_INV (GPIO_BASE + 0x2c) -+#define GPIO_USE_SEL2 (GPIO_BASE + 0x30) -+#define GP_IO_SEL2 (GPIO_BASE + 0x34) -+#define GP_LVL2 (GPIO_BASE + 0x38) -+#define GPI_NMI_EN_2 (GPIO_BASE + 0x3c) -+#define GPI_NMI_STS_2 (GPIO_BASE + 0x3e) -+#define GPIO_USE_SEL3 (GPIO_BASE + 0x40) -+#define GP_IO_SEL3 (GPIO_BASE + 0x44) -+#define GP_LVL3 (GPIO_BASE + 0x48) -+#define GPI_NMI_EN_3 (GPIO_BASE + 0x50) -+#define GPI_NMI_STS_3 (GPIO_BASE + 0x54) -+ -+#define GPIO_BASE_ID (0) -+#define BANKSIZE (32) -+#define D1500_GPIO_PIN_NUM (96) -+#define CELL_NUM (2) -+ -+int g_gpio_d1500_debug = 0; -+int g_gpio_d1500_error = 0; -+module_param(g_gpio_d1500_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_gpio_d1500_error, int, S_IRUGO | S_IWUSR); -+ -+#define GPIO_DEBUG_VERBOSE(fmt, args...) do { \ -+ if (g_gpio_d1500_debug) { \ -+ printk(KERN_ERR "[GPIO-D1500][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define GPIO_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_gpio_d1500_error) { \ -+ printk(KERN_ERR "[GPIO-D1500][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static DEFINE_SPINLOCK(sio_lock); -+ -+struct gpio_d1500_t { -+ struct gpio_chip chip; -+ u64 register_base; -+}; -+ -+static int wb_gpio_get(struct gpio_chip *gc, unsigned gpio_num) -+{ -+ u32 data = 0; -+ unsigned int bank, offset; -+ unsigned long flags; -+ -+ bank = gpio_num / BANKSIZE; -+ offset = gpio_num % BANKSIZE; -+ -+ spin_lock_irqsave(&sio_lock, flags); -+ if (bank == 0) { -+ data = inl(GP_LVL) & (1 << offset); -+ if (data) { -+ data = 1; -+ } -+ } else if (bank == 1) { -+ data = inl(GP_LVL2) & (1 << offset); -+ if (data) { -+ data = 1; -+ } -+ } else if (bank == 2) { -+ data = inl(GP_LVL3) & (1 << offset); -+ if (data) { -+ data = 1; -+ } -+ } -+ spin_unlock_irqrestore(&sio_lock, flags); -+ -+ return data; -+} -+ -+static int wb_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num) -+{ -+ u32 data; -+ unsigned int bank, offset; -+ unsigned long flags; -+ -+ bank = gpio_num / BANKSIZE; -+ offset = gpio_num % BANKSIZE; -+ -+ spin_lock_irqsave(&sio_lock, flags); -+ if (bank == 0) { -+ data = inl(GP_IO_SEL); -+ data = data | (1 << offset); -+ outl(data, GP_IO_SEL); -+ } else if (bank == 1) { -+ data = inl(GP_IO_SEL2); -+ data = data | (1 << offset); -+ outl(data, GP_IO_SEL2); -+ } else if (bank == 2) { -+ data = inl(GP_IO_SEL3); -+ data = data | (1 << offset); -+ outl(data, GP_IO_SEL3); -+ } -+ spin_unlock_irqrestore(&sio_lock, flags); -+ -+ return 0; -+} -+ -+static void wb_gpio_set(struct gpio_chip *gc, -+ unsigned gpio_num, int val) -+{ -+ u32 data; -+ unsigned int bank, offset; -+ unsigned long flags; -+ -+ bank = gpio_num / BANKSIZE; -+ offset = gpio_num % BANKSIZE; -+ -+ spin_lock_irqsave(&sio_lock, flags); -+ if (bank == 0) { -+ data = inl(GP_LVL); -+ if (val) { -+ data = data | (1 << offset); -+ } else { -+ data = data & ~(1 << offset); -+ } -+ outl(data, GP_LVL); -+ } else if (bank == 1) { -+ data = inl(GP_LVL2); -+ if (val) { -+ data = data | (1 << offset); -+ } else { -+ data = data & ~(1 << offset); -+ } -+ outl(data, GP_LVL2); -+ } else if (bank == 2) { -+ data = inl(GP_LVL3); -+ if (val) { -+ data = data | (1 << offset); -+ } else { -+ data = data & ~(1 << offset); -+ } -+ outl(data, GP_LVL3); -+ } -+ spin_unlock_irqrestore(&sio_lock, flags); -+ -+ return; -+} -+ -+static int wb_gpio_direction_out(struct gpio_chip *gc, -+ unsigned gpio_num, int val) -+{ -+ u32 data; -+ unsigned int bank, offset; -+ unsigned long flags; -+ -+ bank = gpio_num / BANKSIZE; -+ offset = gpio_num % BANKSIZE; -+ -+ spin_lock_irqsave(&sio_lock, flags); -+ if (bank == 0) { -+ data = inl(GP_IO_SEL); -+ data = data & ~(1 << offset); -+ outl(data, GP_IO_SEL); -+ -+ data = inl(GP_LVL); -+ if (val) { -+ data = data | (1 << offset); -+ } else { -+ data = data & ~(1 << offset); -+ } -+ outl(data, GP_LVL); -+ } else if (bank == 1) { -+ data = inl(GP_IO_SEL2); -+ data = data & ~(1 << offset); -+ outl(data, GP_IO_SEL2); -+ -+ data = inl(GP_LVL2); -+ if (val) { -+ data = data | (1 << offset); -+ } else { -+ data = data & ~(1 << offset); -+ } -+ outl(data, GP_LVL2); -+ } else if (bank == 2) { -+ data = inl(GP_IO_SEL3); -+ data = data & ~(1 << offset); -+ outl(data, GP_IO_SEL3); -+ -+ data = inl(GP_LVL3); -+ if (val) { -+ data = data | (1 << offset); -+ } else { -+ data = data & ~(1 << offset); -+ } -+ outl(data, GP_LVL3); -+ } -+ spin_unlock_irqrestore(&sio_lock, flags); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_OF -+static int wb_gpio_of_xlate(struct gpio_chip *chip, -+ const struct of_phandle_args *gpio_desc, -+ u32 *flags) -+{ -+ if (chip->of_gpio_n_cells < 2) { -+ return -EINVAL; -+ } -+ -+ if (flags) { -+ *flags = gpio_desc->args[1]; -+ } -+ -+ return gpio_desc->args[0]; -+} -+#endif -+ -+static int wb_gpio_request(struct gpio_chip *chip, unsigned int offset) -+{ -+ u32 data; -+ unsigned int bank, tmp_offset; -+ unsigned long flags; -+ -+ bank = offset / BANKSIZE; -+ tmp_offset = offset % BANKSIZE; -+ -+ spin_lock_irqsave(&sio_lock, flags); -+ if (bank == 0) { -+ data = inl(GPIO_BASE); -+ data = data | (1 << tmp_offset); -+ outl(data, GPIO_BASE); -+ } else if (bank == 1) { -+ data = inl(GPIO_USE_SEL2); -+ data = data | (1 << tmp_offset); -+ outl(data, GPIO_USE_SEL2); -+ } else if (bank == 2) { -+ data = inl(GPIO_USE_SEL3); -+ data = data | (1 << tmp_offset); -+ outl(data, GPIO_USE_SEL3); -+ } -+ spin_unlock_irqrestore(&sio_lock, flags); -+ -+ return 0; -+} -+ -+#if 0 -+static void wb_gpio_free(struct gpio_chip *chip, unsigned int offset) -+{ -+ u32 data; -+ unsigned int bank, tmp_offset; -+ unsigned long flags; -+ -+ bank = offset / BANKSIZE; -+ tmp_offset = offset % BANKSIZE; -+ -+ spin_lock_irqsave(&sio_lock, flags); -+ if (bank == 0) { -+ data = inl(GPIO_BASE); -+ data = data & ~(1 << tmp_offset); -+ outl(data, GPIO_BASE); -+ } else if (bank == 1) { -+ data = inl(GPIO_USE_SEL2); -+ data = data & ~(1 << tmp_offset); -+ outl(data, GPIO_USE_SEL2); -+ } else if (bank == 2) { -+ data = inl(GPIO_USE_SEL3); -+ data = data & ~(1 << tmp_offset); -+ outl(data, GPIO_USE_SEL3); -+ } -+ -+ spin_unlock_irqrestore(&sio_lock, flags); -+ -+ return; -+} -+#endif -+ -+static struct gpio_chip wb_gpio_chip = { -+ .label = GPIO_NAME, -+ .owner = THIS_MODULE, -+ .base = GPIO_BASE_ID, -+ .get = wb_gpio_get, -+ .direction_input = wb_gpio_direction_in, -+ .set = wb_gpio_set, -+ .direction_output = wb_gpio_direction_out, -+#ifdef CONFIG_OF -+ .of_xlate = wb_gpio_of_xlate, -+#endif -+ .request = wb_gpio_request, -+ .ngpio = D1500_GPIO_PIN_NUM, -+#ifdef CONFIG_OF -+ .of_gpio_n_cells = CELL_NUM, -+#endif -+ .can_sleep = false, -+}; -+ -+static int wb_gpio_probe(struct platform_device *pdev) -+{ -+ struct gpio_d1500_t *gpio; -+ int err; -+ -+ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); -+ if (!gpio) { -+ dev_err(&pdev->dev, "gpio kzalloc failed\n"); -+ return -ENOMEM; -+ } -+ -+ wb_gpio_chip.parent = &pdev->dev; -+ gpio->register_base = GPIO_BASE; -+ gpio->chip = wb_gpio_chip; -+ pdev->dev.platform_data = &wb_gpio_chip; -+ err = devm_gpiochip_add_data(&pdev->dev, &wb_gpio_chip, gpio); -+ if (err) { -+ dev_err(&pdev->dev, "gpiochip add failed\n"); -+ return err; -+ } -+ -+ dev_info(&pdev->dev, "register %llu gpio success.\n", gpio->register_base); -+ -+ return 0; -+} -+ -+static int wb_gpio_remove(struct platform_device *pdev) -+{ -+ dev_info(&pdev->dev, "unregister d1500 gpio success\n"); -+ return 0; -+} -+ -+static const struct of_device_id gpio_d1500_match[] = { -+ { -+ .compatible = "wb_gpio_d1500", -+ }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, gpio_d1500_match); -+ -+static struct platform_driver wb_gpio_driver = { -+ .driver = { -+ .name = GPIO_NAME, -+ .of_match_table = gpio_d1500_match, -+ }, -+ .probe = wb_gpio_probe, -+ .remove = wb_gpio_remove, -+}; -+ -+module_platform_driver(wb_gpio_driver); -+ -+MODULE_DESCRIPTION("d1500 gpio driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_device.c -new file mode 100644 -index 000000000..75f883b59 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_device.c -@@ -0,0 +1,54 @@ -+#include -+#include -+#include -+#include -+#include -+ -+static int g_wb_gpio_device_debug = 0; -+static int g_wb_gpio_device_error = 0; -+ -+module_param(g_wb_gpio_device_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_gpio_device_error, int, S_IRUGO | S_IWUSR); -+ -+#define WB_GPIO_DEVICE_VERBOSE(fmt, args...) do { \ -+ if (g_wb_gpio_device_debug) { \ -+ printk(KERN_INFO "[WB_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_GPIO_DEVICE_ERROR(fmt, args...) do { \ -+ if (g_wb_gpio_device_error) { \ -+ printk(KERN_ERR "[WB_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static void wb_gpio_device_release(struct device *dev) -+{ -+ return; -+} -+ -+static struct platform_device wb_gpio_d1500_device = { -+ .name = "wb_gpio_d1500", -+ .id = -1, -+ .dev = { -+ .release = wb_gpio_device_release, -+ }, -+}; -+ -+static int __init wb_gpio_device_init(void) -+{ -+ WB_GPIO_DEVICE_VERBOSE("wb_gpio_device_init enter!\n"); -+ return platform_device_register(&wb_gpio_d1500_device); -+} -+ -+static void __exit wb_gpio_device_exit(void) -+{ -+ WB_GPIO_DEVICE_VERBOSE("wb_gpio_device_exit enter!\n"); -+ return platform_device_unregister(&wb_gpio_d1500_device); -+} -+ -+module_init(wb_gpio_device_init); -+module_exit(wb_gpio_device_exit); -+MODULE_DESCRIPTION("GPIO Devices"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.c -new file mode 100644 -index 000000000..4abdccabe ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.c -@@ -0,0 +1,815 @@ -+/* -+ * wb_io_dev.c -+ * ko to read/write i2c client through /dev/XXX device -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "wb_i2c_dev.h" -+ -+#define MAX_I2C_DEV_NUM (256) -+#define FPGA_MAX_LEN (256) -+#define MAX_NAME_SIZE (20) -+#define MAX_BUS_WIDTH (16) -+#define TRANSFER_WRITE_BUFF (FPGA_MAX_LEN + MAX_BUS_WIDTH) -+ -+#define WIDTH_1Byte (1) -+#define WIDTH_2Byte (2) -+#define WIDTH_4Byte (4) -+ -+static int g_i2c_dev_debug = 0; -+static int g_i2c_dev_error = 0; -+ -+module_param(g_i2c_dev_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_i2c_dev_error, int, S_IRUGO | S_IWUSR); -+ -+#define I2C_DEV_DEBUG_DMESG(fmt, args...) do { \ -+ if (g_i2c_dev_debug) { \ -+ printk(KERN_ERR "[I2C_DEV][DEBUG][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define I2C_DEV_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_i2c_dev_error) { \ -+ printk(KERN_ERR "[I2C_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static struct i2c_dev_info* i2c_dev_arry[MAX_I2C_DEV_NUM]; -+ -+struct i2c_dev_info { -+ const char *name; -+ uint32_t data_bus_width; -+ uint32_t addr_bus_width; -+ uint32_t per_rd_len; -+ uint32_t per_wr_len; -+ uint32_t i2c_len; -+ struct miscdevice misc; -+ struct i2c_client *client; -+}; -+ -+static int transfer_read(struct i2c_client *client, u8 *buf, loff_t regaddr, size_t count) -+{ -+ struct i2c_adapter *adap; -+ union i2c_smbus_data data; -+ int i, j; -+ u8 offset_buf[MAX_BUS_WIDTH]; -+ struct i2c_msg msgs[2]; -+ int msgs_num, ret; -+ struct i2c_dev_info *i2c_dev; -+ u8 offset; -+ u8 length; -+ -+ if (!client) { -+ I2C_DEV_DEBUG_ERROR("can't get read client\n"); -+ return -ENODEV; -+ } -+ -+ adap = client->adapter; -+ if (!adap) { -+ I2C_DEV_DEBUG_ERROR("can't get read adap\n"); -+ return -ENODEV; -+ } -+ -+ i2c_dev = i2c_get_clientdata(client); -+ if (!i2c_dev) { -+ I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\n"); -+ return -ENODEV; -+ } -+ -+ i = 0; -+ -+ mem_clear(offset_buf, sizeof(offset_buf)); -+ -+ switch (i2c_dev->addr_bus_width) { -+ case WIDTH_4Byte: -+ offset_buf[i++] = (regaddr >> 24) & 0xFF; -+ offset_buf[i++] = (regaddr >> 16) & 0xFF; -+ offset_buf[i++] = (regaddr >> 8) & 0xFF; -+ offset_buf[i++] = regaddr & 0xFF; -+ break; -+ case WIDTH_2Byte: -+ offset_buf[i++] = (regaddr >> 8) & 0xFF; -+ offset_buf[i++] = regaddr & 0xFF; -+ break; -+ case WIDTH_1Byte: -+ offset_buf[i++] = regaddr & 0xFF; -+ break; -+ default: -+ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\n", -+ i2c_dev->addr_bus_width); -+ return -EINVAL; -+ } -+ -+ if (adap->algo->master_xfer) { -+ mem_clear(msgs, sizeof(msgs)); -+ msgs[0].addr = client->addr; -+ msgs[0].flags = 0; -+ msgs[0].len = i2c_dev->addr_bus_width; -+ msgs[0].buf = offset_buf; -+ -+ msgs[1].addr = client->addr; -+ msgs[1].flags = I2C_M_RD; -+ msgs[1].len = count; -+ msgs[1].buf = buf; -+ -+ msgs_num = 2; -+ ret = i2c_transfer(client->adapter, msgs, msgs_num); -+ if (ret != msgs_num) { -+ I2C_DEV_DEBUG_ERROR("i2c_transfer read error\n"); -+ return -EINVAL; -+ } -+ } else { -+ if (i2c_dev->addr_bus_width == WIDTH_1Byte) { -+ offset = regaddr & 0xFF; -+ if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { -+ for (j = 0; j < count; j += I2C_SMBUS_BLOCK_MAX) { -+ if (count - j > I2C_SMBUS_BLOCK_MAX) { -+ length = I2C_SMBUS_BLOCK_MAX; -+ } else { -+ length = count - j; -+ } -+ data.block[0] = length; -+ ret = adap->algo->smbus_xfer(adap, client->addr, -+ 0, -+ I2C_SMBUS_READ, -+ offset, I2C_SMBUS_I2C_BLOCK_DATA, &data); -+ if (ret) { -+ I2C_DEV_DEBUG_ERROR("smbus_xfer read block error, ret = %d\n", ret); -+ return -EFAULT; -+ } -+ memcpy(buf + j, data.block + 1, length); -+ offset += length; -+ } -+ } else { -+ for (j = 0; j < count; j++) { -+ ret = adap->algo->smbus_xfer(adap, client->addr, -+ 0, -+ I2C_SMBUS_READ, -+ offset, I2C_SMBUS_BYTE_DATA, &data); -+ -+ if (!ret) { -+ buf[j] = data.byte; -+ } else { -+ I2C_DEV_DEBUG_ERROR("smbus_xfer read byte error, ret = %d\n", ret); -+ return -EFAULT; -+ } -+ offset++; -+ } -+ } -+ } else { -+ I2C_DEV_DEBUG_ERROR("smbus_xfer not support addr_bus_width = %d\n", i2c_dev->addr_bus_width); -+ return -EINVAL; -+ } -+ } -+ return 0; -+} -+ -+static int transfer_write(struct i2c_client *client, u8 *buf, loff_t regaddr, size_t count) -+{ -+ struct i2c_adapter *adap; -+ int i; -+ u8 offset_buf[TRANSFER_WRITE_BUFF]; -+ struct i2c_msg msgs[1]; -+ int msgs_num, ret; -+ struct i2c_dev_info *i2c_dev; -+ -+ if (!client) { -+ I2C_DEV_DEBUG_ERROR("can't get write client\n"); -+ return -ENODEV; -+ } -+ -+ adap = client->adapter; -+ if (!adap) { -+ I2C_DEV_DEBUG_ERROR("can't get write adap\n"); -+ return -ENODEV; -+ } -+ -+ i2c_dev = i2c_get_clientdata(client); -+ if (!i2c_dev) { -+ I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\n"); -+ return -ENODEV; -+ } -+ -+ i = 0; -+ -+ mem_clear(offset_buf, sizeof(offset_buf)); -+ -+ switch (i2c_dev->addr_bus_width) { -+ case WIDTH_4Byte: -+ offset_buf[i++] = (regaddr >> 24) & 0xFF; -+ offset_buf[i++] = (regaddr >> 16) & 0xFF; -+ offset_buf[i++] = (regaddr >> 8) & 0xFF; -+ offset_buf[i++] = regaddr & 0xFF; -+ break; -+ case WIDTH_2Byte: -+ offset_buf[i++] = (regaddr >> 8) & 0xFF; -+ offset_buf[i++] = regaddr & 0xFF; -+ break; -+ case WIDTH_1Byte: -+ offset_buf[i++] = regaddr & 0xFF; -+ break; -+ default: -+ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\n", -+ i2c_dev->addr_bus_width); -+ return -EINVAL; -+ } -+ -+ memcpy(offset_buf + i2c_dev->addr_bus_width, buf, count); -+ -+ if (adap->algo->master_xfer) { -+ mem_clear(msgs, sizeof(msgs)); -+ -+ msgs[0].addr = client->addr; -+ msgs[0].flags = 0; -+ msgs[0].len = i2c_dev->addr_bus_width + count; -+ msgs[0].buf = offset_buf; -+ -+ msgs_num = 1; -+ ret = i2c_transfer(adap, msgs, msgs_num); -+ if (ret != msgs_num) { -+ I2C_DEV_DEBUG_ERROR("i2c_transfer write error\n"); -+ return -EINVAL; -+ } -+ } else { -+ I2C_DEV_DEBUG_ERROR("don't find write master_xfer\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static long i2c_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ return 0; -+} -+ -+static int i2c_dev_open(struct inode *inode, struct file *file) -+{ -+ unsigned int minor = iminor(inode); -+ struct i2c_dev_info *i2c_dev; -+ -+ i2c_dev = i2c_dev_arry[minor]; -+ if (i2c_dev == NULL) { -+ return -ENODEV; -+ } -+ -+ file->private_data = i2c_dev; -+ -+ return 0; -+} -+ -+static int i2c_dev_release(struct inode *inode, struct file *file) -+{ -+ file->private_data = NULL; -+ -+ return 0; -+} -+ -+static int device_read(struct i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ int i, j, ret; -+ u8 tmp_offset; -+ u8 val[FPGA_MAX_LEN]; -+ u32 width, rd_len, per_len, tmp; -+ u32 max_per_len; -+ -+ if (offset > i2c_dev->i2c_len) { -+ I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, count: %lu, EOF.\n", -+ offset, i2c_dev->i2c_len, count); -+ return 0; -+ } -+ -+ if (count > (i2c_dev->i2c_len - offset)) { -+ I2C_DEV_DEBUG_DMESG("read count out of range. input len:%lu, read len:%u.\n", -+ count, i2c_dev->i2c_len - offset); -+ count = i2c_dev->i2c_len - offset; -+ } -+ -+ if (count == 0) { -+ I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, read len: %lu, EOF.\n", -+ offset, i2c_dev->i2c_len, count); -+ return 0; -+ } -+ -+ width = i2c_dev->data_bus_width; -+ switch (width) { -+ case WIDTH_4Byte: -+ tmp_offset = offset & 0x3; -+ if (tmp_offset) { -+ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", -+ width, offset, count); -+ return -EINVAL; -+ } -+ break; -+ case WIDTH_2Byte: -+ tmp_offset = offset & 0x1; -+ if (tmp_offset) { -+ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", -+ width, offset, count); -+ return -EINVAL; -+ } -+ break; -+ case WIDTH_1Byte: -+ break; -+ default: -+ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\n", width); -+ return -EINVAL; -+ } -+ -+ max_per_len = i2c_dev->per_rd_len; -+ tmp = (width - 1) & count; -+ rd_len = (tmp == 0) ? count : count + width - tmp; -+ per_len = (rd_len > max_per_len) ? (max_per_len) : (rd_len); -+ -+ mem_clear(val, sizeof(val)); -+ for (i = 0; i < rd_len; i += per_len) { -+ ret = transfer_read(i2c_dev->client, val + i, offset + i, per_len); -+ if (ret < 0) { -+ I2C_DEV_DEBUG_ERROR("read error.read offset = %u\n", (offset + i)); -+ return -EFAULT; -+ } -+ } -+ -+ if (width == WIDTH_1Byte) { -+ memcpy(buf, val, count); -+ } else { -+ for (i = 0; i < count; i += width) { -+ for (j = 0; (j < width) && (i + j < count); j++) { -+ buf[i + j] = val[i + width - j - 1]; -+ } -+ } -+ } -+ -+ return count; -+} -+ -+static int device_write(struct i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ int i, j, ret; -+ u8 tmp_offset; -+ u32 width; -+ u8 val[FPGA_MAX_LEN]; -+ u32 wr_len, per_len, tmp; -+ u32 max_per_len; -+ -+ if (offset > i2c_dev->i2c_len) { -+ I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, count: %lu, EOF.\n", -+ offset, i2c_dev->i2c_len, count); -+ return 0; -+ } -+ -+ if (count > (i2c_dev->i2c_len - offset)) { -+ I2C_DEV_DEBUG_DMESG("read count out of range. input len:%lu, read len:%u.\n", -+ count, i2c_dev->i2c_len - offset); -+ count = i2c_dev->i2c_len - offset; -+ } -+ -+ if (count == 0) { -+ I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, read len: %lu, EOF.\n", -+ offset, i2c_dev->i2c_len, count); -+ return 0; -+ } -+ -+ width = i2c_dev->data_bus_width; -+ switch (width) { -+ case WIDTH_4Byte: -+ tmp_offset = offset & 0x3; -+ if (tmp_offset) { -+ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", -+ width, offset, count); -+ return -EINVAL; -+ } -+ break; -+ case WIDTH_2Byte: -+ tmp_offset = offset & 0x1; -+ if (tmp_offset) { -+ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", -+ width, offset, count); -+ return -EINVAL; -+ } -+ break; -+ case WIDTH_1Byte: -+ break; -+ default: -+ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\n", width); -+ return -EINVAL; -+ } -+ -+ mem_clear(val, sizeof(val)); -+ -+ if (width == WIDTH_1Byte) { -+ memcpy(val, buf, count); -+ } else { -+ for (i = 0; i < count; i += width) { -+ for (j = 0; (j < width) && (i + j < count); j++) { -+ val[i + width - j - 1] = buf[i + j]; -+ } -+ } -+ } -+ -+ max_per_len = i2c_dev->per_wr_len; -+ tmp = (width - 1) & count; -+ wr_len = (tmp == 0) ? count : count + width - tmp; -+ per_len = (wr_len > max_per_len) ? (max_per_len) : (wr_len); -+ -+ for (i = 0; i < wr_len; i += per_len) { -+ ret = transfer_write(i2c_dev->client, val + i, offset + i, per_len); -+ if (ret < 0) { -+ I2C_DEV_DEBUG_ERROR("write error.offset = %u\n", (offset + i)); -+ return -EFAULT; -+ } -+ } -+ return count; -+} -+ -+static ssize_t i2c_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) -+{ -+ u8 val[FPGA_MAX_LEN]; -+ int ret, read_len; -+ struct i2c_dev_info *i2c_dev; -+ -+ i2c_dev = file->private_data; -+ if (i2c_dev == NULL) { -+ I2C_DEV_DEBUG_ERROR("can't get read private_data.\n"); -+ return -EINVAL; -+ } -+ -+ if (count == 0) { -+ I2C_DEV_DEBUG_ERROR("Invalid params, read count is 0.\n"); -+ return -EINVAL; -+ } -+ -+ if (count > sizeof(val)) { -+ I2C_DEV_DEBUG_DMESG("read count %lu exceed max %lu.\n", count, sizeof(val)); -+ count = sizeof(val); -+ } -+ -+ mem_clear(val, sizeof(val)); -+ read_len = device_read(i2c_dev, (uint32_t)*offset, val, count); -+ if (read_len < 0) { -+ I2C_DEV_DEBUG_ERROR("i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", -+ i2c_dev->name, (uint32_t)*offset, count); -+ return read_len; -+ } -+ -+ if (access_ok(buf, read_len)) { -+ I2C_DEV_DEBUG_DMESG("user space read, buf: %p, offset: %lld, read count %lu.\n", -+ buf, *offset, count); -+ if (copy_to_user(buf, val, read_len)) { -+ I2C_DEV_DEBUG_ERROR("copy_to_user failed.\n"); -+ return -EFAULT; -+ } -+ } else { -+ I2C_DEV_DEBUG_DMESG("kernel space read, buf: %p, offset: %lld, read count %lu.\n", -+ buf, *offset, count); -+ memcpy(buf, val, read_len); -+ } -+ -+ *offset += read_len; -+ ret = read_len; -+ return ret; -+} -+ -+static ssize_t i2c_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) -+{ -+ int ret; -+ -+ I2C_DEV_DEBUG_DMESG("i2c_dev_read_iter, file: %p, count: %lu, offset: %lld\n", -+ iocb->ki_filp, to->count, iocb->ki_pos); -+ ret = i2c_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos); -+ return ret; -+} -+ -+static ssize_t i2c_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) -+{ -+ u8 val[FPGA_MAX_LEN]; -+ int write_len; -+ struct i2c_dev_info *i2c_dev; -+ -+ i2c_dev = file->private_data; -+ if (i2c_dev == NULL) { -+ I2C_DEV_DEBUG_ERROR("get write private_data error.\n"); -+ return -EINVAL; -+ } -+ -+ if (count == 0) { -+ I2C_DEV_DEBUG_ERROR("Invalid params, write count is 0.\n"); -+ return -EINVAL; -+ } -+ -+ if (count > sizeof(val)) { -+ I2C_DEV_DEBUG_DMESG("write count %lu exceed max %lu.\n", count, sizeof(val)); -+ count = sizeof(val); -+ } -+ -+ mem_clear(val, sizeof(val)); -+ if (access_ok(buf, count)) { -+ I2C_DEV_DEBUG_DMESG("user space write, buf: %p, offset: %lld, write count %lu.\n", -+ buf, *offset, count); -+ if (copy_from_user(val, buf, count)) { -+ I2C_DEV_DEBUG_ERROR("copy_from_user failed.\n"); -+ return -EFAULT; -+ } -+ } else { -+ I2C_DEV_DEBUG_DMESG("kernel space write, buf: %p, offset: %lld, write count %lu.\n", -+ buf, *offset, count); -+ memcpy(val, buf, count); -+ } -+ -+ write_len = device_write(i2c_dev, (uint32_t)*offset, val, count); -+ if (write_len < 0) { -+ I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%llx, len:%lu.\n", -+ i2c_dev->name, *offset, count); -+ return write_len; -+ } -+ -+ *offset += write_len; -+ return write_len; -+} -+ -+static ssize_t i2c_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) -+{ -+ int ret; -+ -+ I2C_DEV_DEBUG_DMESG("i2c_dev_write_iter, file: %p, count: %lu, offset: %lld\n", -+ iocb->ki_filp, from->count, iocb->ki_pos); -+ ret = i2c_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos); -+ return ret; -+} -+ -+static loff_t i2c_dev_llseek(struct file *file, loff_t offset, int origin) -+{ -+ loff_t ret = 0; -+ struct i2c_dev_info *i2c_dev; -+ -+ i2c_dev = file->private_data; -+ if (i2c_dev == NULL) { -+ I2C_DEV_DEBUG_ERROR("i2c_dev is NULL, llseek failed.\n"); -+ return -EINVAL; -+ } -+ -+ switch (origin) { -+ case SEEK_SET: -+ if (offset < 0) { -+ I2C_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); -+ ret = -EINVAL; -+ break; -+ } -+ if (offset > i2c_dev->i2c_len) { -+ I2C_DEV_DEBUG_ERROR("SEEK_SET out of range, offset:%lld, i2c_len:0x%x.\n", -+ offset, i2c_dev->i2c_len); -+ ret = - EINVAL; -+ break; -+ } -+ file->f_pos = offset; -+ ret = file->f_pos; -+ break; -+ case SEEK_CUR: -+ if (((file->f_pos + offset) > i2c_dev->i2c_len) || ((file->f_pos + offset) < 0)) { -+ I2C_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld, i2c_len:0x%x.\n", -+ file->f_pos, offset, i2c_dev->i2c_len); -+ ret = - EINVAL; -+ break; -+ } -+ file->f_pos += offset; -+ ret = file->f_pos; -+ break; -+ default: -+ I2C_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+ -+static const struct file_operations i2c_dev_fops = { -+ .owner = THIS_MODULE, -+ .llseek = i2c_dev_llseek, -+ .read_iter = i2c_dev_read_iter, -+ .write_iter = i2c_dev_write_iter, -+ .unlocked_ioctl = i2c_dev_ioctl, -+ .open = i2c_dev_open, -+ .release = i2c_dev_release, -+}; -+ -+static struct i2c_dev_info * dev_match(const char *path) -+{ -+ struct i2c_dev_info * i2c_dev; -+ char dev_name[MAX_NAME_SIZE]; -+ int i; -+ for (i = 0; i < MAX_I2C_DEV_NUM; i++) { -+ if (i2c_dev_arry[ i ] == NULL) { -+ continue; -+ } -+ i2c_dev = i2c_dev_arry[ i ]; -+ snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", i2c_dev->name); -+ if (!strcmp(path, dev_name)) { -+ I2C_DEV_DEBUG_DMESG("get dev_name = %s, minor = %d\n", dev_name, i); -+ return i2c_dev; -+ } -+ } -+ -+ return NULL; -+} -+ -+int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ struct i2c_dev_info *i2c_dev = NULL; -+ int ret; -+ -+ if(path == NULL){ -+ I2C_DEV_DEBUG_ERROR("path NULL"); -+ return -EINVAL; -+ } -+ -+ if(buf == NULL){ -+ I2C_DEV_DEBUG_ERROR("buf NULL"); -+ return -EINVAL; -+ } -+ -+ if (count > FPGA_MAX_LEN) { -+ I2C_DEV_DEBUG_ERROR("read count %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); -+ return -EINVAL; -+ } -+ -+ i2c_dev = dev_match(path); -+ if (i2c_dev == NULL) { -+ I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); -+ return -EINVAL; -+ } -+ -+ ret = device_read(i2c_dev, offset, buf, count); -+ if (ret < 0) { -+ I2C_DEV_DEBUG_ERROR("fpga i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", -+ i2c_dev->name, offset, count); -+ return -EINVAL; -+ } -+ -+ return count; -+} -+EXPORT_SYMBOL(i2c_device_func_read); -+ -+int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ struct i2c_dev_info *i2c_dev = NULL; -+ int ret; -+ -+ if(path == NULL){ -+ I2C_DEV_DEBUG_ERROR("path NULL"); -+ return -EINVAL; -+ } -+ -+ if(buf == NULL){ -+ I2C_DEV_DEBUG_ERROR("buf NULL"); -+ return -EINVAL; -+ } -+ -+ if (count > FPGA_MAX_LEN) { -+ I2C_DEV_DEBUG_ERROR("write count %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); -+ return -EINVAL; -+ } -+ -+ i2c_dev = dev_match(path); -+ if (i2c_dev == NULL) { -+ I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); -+ return -EINVAL; -+ } -+ -+ ret = device_write (i2c_dev, offset, buf, count); -+ if (ret < 0) { -+ I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%x, len:%lu.\n", -+ i2c_dev->name, offset, count); -+ return -EINVAL; -+ } -+ -+ return count; -+} -+EXPORT_SYMBOL(i2c_device_func_write); -+ -+static int i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ int ret = 0; -+ struct i2c_dev_info *i2c_dev; -+ struct miscdevice *misc; -+ i2c_dev_device_t *i2c_dev_device; -+ -+ i2c_dev = devm_kzalloc(&client->dev, sizeof(struct i2c_dev_info), GFP_KERNEL); -+ if (!i2c_dev) { -+ dev_err(&client->dev, "devm_kzalloc error. \n"); -+ return -ENOMEM; -+ } -+ -+ i2c_set_clientdata(client, i2c_dev); -+ i2c_dev->client = client; -+ -+ if (client->dev.of_node) { -+ -+ ret += of_property_read_string(client->dev.of_node, "i2c_name", &i2c_dev->name); -+ ret += of_property_read_u32(client->dev.of_node, "data_bus_width", &i2c_dev->data_bus_width); -+ ret += of_property_read_u32(client->dev.of_node, "addr_bus_width", &i2c_dev->addr_bus_width); -+ ret += of_property_read_u32(client->dev.of_node, "per_rd_len", &i2c_dev->per_rd_len); -+ ret += of_property_read_u32(client->dev.of_node, "per_wr_len", &i2c_dev->per_wr_len); -+ ret += of_property_read_u32(client->dev.of_node, "i2c_len", &i2c_dev->i2c_len); -+ if (ret != 0) { -+ dev_err(&client->dev, "dts config error.ret:%d.\n", ret); -+ return -ENXIO; -+ } -+ } else { -+ if (client->dev.platform_data == NULL) { -+ dev_err(&client->dev, "Failed to get platform data config.\n"); -+ return -ENXIO; -+ } -+ i2c_dev_device = client->dev.platform_data; -+ i2c_dev->name = i2c_dev_device->i2c_name; -+ i2c_dev->data_bus_width = i2c_dev_device->data_bus_width; -+ i2c_dev->addr_bus_width = i2c_dev_device->addr_bus_width; -+ i2c_dev->per_rd_len = i2c_dev_device->per_rd_len; -+ i2c_dev->per_wr_len = i2c_dev_device->per_wr_len; -+ i2c_dev->i2c_len = i2c_dev_device->i2c_len; -+ } -+ -+ if ((i2c_dev->per_rd_len & (i2c_dev->data_bus_width - 1)) || -+ (i2c_dev->per_wr_len & (i2c_dev->data_bus_width - 1))) { -+ dev_err(&client->dev, "Invalid config per_rd_len %d per_wr_len %d data bus_width %d.\n", -+ i2c_dev->per_rd_len, i2c_dev->per_wr_len, i2c_dev->data_bus_width); -+ return -ENXIO; -+ } -+ -+ if ((i2c_dev->i2c_len == 0) || (i2c_dev->i2c_len & (i2c_dev->data_bus_width - 1))) { -+ dev_err(&client->dev, "Invalid config i2c_len %d, data bus_width %d.\n", -+ i2c_dev->i2c_len, i2c_dev->data_bus_width); -+ return -ENXIO; -+ } -+ -+ misc = &i2c_dev->misc; -+ misc->minor = MISC_DYNAMIC_MINOR; -+ misc->name = i2c_dev->name; -+ misc->fops = &i2c_dev_fops; -+ misc->mode = 0666; -+ if (misc_register(misc) != 0) { -+ dev_err(&client->dev, "register %s faild.\n", misc->name); -+ return -ENXIO; -+ } -+ -+ if (misc->minor >= MAX_I2C_DEV_NUM) { -+ dev_err(&client->dev, "minor number beyond the limit! is %d.\n", misc->minor); -+ misc_deregister(misc); -+ return -ENXIO; -+ } -+ i2c_dev_arry[misc->minor] = i2c_dev; -+ -+ dev_info(&client->dev, "register %u addr_bus_width %u data_bus_width 0x%x i2c_len device %s with %u per_rd_len %u per_wr_len success.\n", -+ i2c_dev->addr_bus_width, i2c_dev->data_bus_width, i2c_dev->i2c_len, i2c_dev->name, i2c_dev->per_rd_len, i2c_dev->per_wr_len); -+ -+ return 0; -+} -+ -+static int i2c_dev_remove(struct i2c_client *client) -+{ -+ int i; -+ for (i = 0; i < MAX_I2C_DEV_NUM; i++) { -+ if (i2c_dev_arry[i] != NULL) { -+ misc_deregister(&i2c_dev_arry[i]->misc); -+ i2c_dev_arry[i] = NULL; -+ } -+ } -+ return 0; -+} -+ -+static const struct i2c_device_id i2c_dev_id[] = { -+ { "wb-i2c-dev", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, i2c_dev_id); -+ -+static const struct of_device_id i2c_dev_of_match[] = { -+ { .compatible = "wb-i2c-dev" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, i2c_dev_of_match); -+ -+static struct i2c_driver i2c_dev_driver = { -+ .driver = { -+ .name = "wb-i2c-dev", -+ .of_match_table = i2c_dev_of_match, -+ }, -+ .probe = i2c_dev_probe, -+ .remove = i2c_dev_remove, -+ .id_table = i2c_dev_id, -+}; -+module_i2c_driver(i2c_dev_driver); -+ -+MODULE_DESCRIPTION("i2c dev driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.h -new file mode 100644 -index 000000000..9cc95d88e ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.h -@@ -0,0 +1,20 @@ -+#ifndef __WB_I2C_DEV_H__ -+#define __WB_I2C_DEV_H__ -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+#define I2C_DEV_NAME_MAX_LEN (64) -+ -+typedef struct i2c_dev_device_s { -+ struct i2c_client *client; -+ uint32_t i2c_bus; -+ uint32_t i2c_addr; -+ char i2c_name[I2C_DEV_NAME_MAX_LEN]; -+ uint32_t data_bus_width; -+ uint32_t addr_bus_width; -+ uint32_t per_rd_len; -+ uint32_t per_wr_len; -+ uint32_t i2c_len; -+} i2c_dev_device_t; -+ -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.c -new file mode 100644 -index 000000000..1f69d96ba ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.c -@@ -0,0 +1,1143 @@ -+// 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 -+#include -+#include -+ -+#include "wb_i2c_ocores.h" -+ -+#define OCORES_FLAG_POLL BIT(0) -+ -+/* 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 OCORE_WAIT_SCH (40) -+#define REG_IO_WIDTH_1 (1) -+#define REG_IO_WIDTH_2 (2) -+#define REG_IO_WIDTH_4 (4) -+ -+#define SYMBOL_I2C_DEV_MODE (1) -+#define FILE_MODE (2) -+#define SYMBOL_PCIE_DEV_MODE (3) -+#define SYMBOL_IO_DEV_MODE (4) -+ -+typedef struct wb_pci_dev_s { -+ uint32_t domain; -+ uint32_t bus; -+ uint32_t slot; -+ uint32_t fn; -+} wb_pci_dev_t; -+ -+/* -+ * 'process_lock' exists because ocores_process() and ocores_process_timeout() -+ * can't run in parallel. -+ */ -+struct ocores_i2c { -+ uint32_t base_addr; -+ uint32_t reg_shift; -+ uint32_t reg_io_width; -+ unsigned long flags; -+ wait_queue_head_t wait; -+ struct i2c_adapter adap; -+ int adap_nr; -+ struct i2c_msg *msg; -+ int pos; -+ int nmsgs; -+ int state; -+ spinlock_t process_lock; -+ uint32_t ip_clock_khz; -+ uint32_t bus_clock_khz; -+ void (*setreg)(struct ocores_i2c *i2c, int reg, u32 value); -+ u32 (*getreg)(struct ocores_i2c *i2c, int reg); -+ const char *dev_name; -+ uint32_t reg_access_mode; -+ uint32_t big_endian; -+ uint32_t irq_offset; -+ wb_pci_dev_t wb_pci_dev; -+ struct device *dev; -+}; -+ -+int g_wb_ocores_i2c_debug = 0; -+int g_wb_ocores_i2c_error = 0; -+int g_wb_ocores_i2c_xfer = 0; -+ -+module_param(g_wb_ocores_i2c_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_ocores_i2c_error, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_ocores_i2c_xfer, int, S_IRUGO | S_IWUSR); -+ -+#define OCORES_I2C_VERBOSE(fmt, args...) do { \ -+ if (g_wb_ocores_i2c_debug) { \ -+ printk(KERN_INFO "[OCORES_I2C][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define OCORES_I2C_ERROR(fmt, args...) do { \ -+ if (g_wb_ocores_i2c_error) { \ -+ printk(KERN_ERR "[OCORES_I2C][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define OCORES_I2C_XFER(fmt, args...) do { \ -+ if (g_wb_ocores_i2c_xfer) { \ -+ printk(KERN_INFO "[OCORES_I2C][XFER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+extern int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+#if 0 -+int __attribute__((weak)) i2c_device_func_read(const char *path, uint32_t offset, -+ uint8_t *buf, size_t count) -+{ -+ OCORES_I2C_ERROR("enter __weak i2c func read\r\n"); -+ return -EINVAL; -+} -+ -+int __attribute__((weak)) i2c_device_func_write(const char *path, uint32_t offset, -+ uint8_t *buf, size_t count) -+{ -+ OCORES_I2C_ERROR("enter __weak i2c func write\r\n"); -+ return -EINVAL; -+} -+ -+int __attribute__((weak)) pcie_device_func_read(const char *path, uint32_t offset, -+ uint8_t *buf, size_t count) -+{ -+ OCORES_I2C_ERROR("enter __weak pcie func read\r\n"); -+ return -EINVAL; -+} -+ -+int __attribute__((weak)) pcie_device_func_write(const char *path, uint32_t offset, -+ uint8_t *buf, size_t count) -+{ -+ OCORES_I2C_ERROR("enter __weak pcie func write\r\n"); -+ return -EINVAL; -+} -+ -+int __attribute__((weak)) io_device_func_read(const char *path, uint32_t offset, -+ uint8_t *buf, size_t count) -+{ -+ OCORES_I2C_ERROR("enter __weak io func read\r\n"); -+ return -EINVAL; -+} -+ -+int __attribute__((weak)) io_device_func_write(const char *path, uint32_t offset, -+ uint8_t *buf, size_t count) -+{ -+ OCORES_I2C_ERROR("enter __weak io func write\r\n"); -+ return -EINVAL; -+} -+#endif -+static int ocores_i2c_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) -+{ -+ int ret; -+ struct file *filp; -+ loff_t tmp_pos; -+ -+ filp = filp_open(path, O_RDONLY, 0); -+ if (IS_ERR(filp)) { -+ OCORES_I2C_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); -+ filp = NULL; -+ goto exit; -+ } -+ -+ tmp_pos = (loff_t)pos; -+ ret = kernel_read(filp, val, size, &tmp_pos); -+ if (ret < 0) { -+ OCORES_I2C_ERROR("kernel_read failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); -+ goto exit; -+ } -+ -+ filp_close(filp, NULL); -+ -+ return ret; -+ -+exit: -+ if (filp != NULL) { -+ filp_close(filp, NULL); -+ } -+ -+ return -1; -+} -+ -+static int ocores_i2c_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) -+{ -+ -+ int ret; -+ struct file *filp; -+ loff_t tmp_pos; -+ -+ filp = filp_open(path, O_RDWR, 777); -+ if (IS_ERR(filp)) { -+ OCORES_I2C_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); -+ filp = NULL; -+ goto exit; -+ } -+ -+ tmp_pos = (loff_t)pos; -+ ret = kernel_write(filp, val, size, &tmp_pos); -+ if (ret < 0) { -+ OCORES_I2C_ERROR("kernel_write failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); -+ goto exit; -+ } -+ -+ vfs_fsync(filp, 1); -+ filp_close(filp, NULL); -+ -+ return ret; -+ -+exit: -+ if (filp != NULL) { -+ filp_close(filp, NULL); -+ } -+ -+ return -1; -+} -+ -+static int ocores_i2c_reg_write(struct ocores_i2c *i2c, uint32_t pos, uint8_t *val, size_t size) -+{ -+ int ret; -+ -+ switch (i2c->reg_access_mode) { -+ case SYMBOL_I2C_DEV_MODE: -+ ret = i2c_device_func_write(i2c->dev_name, pos, val, size); -+ break; -+ case FILE_MODE: -+ ret = ocores_i2c_file_write(i2c->dev_name, pos, val, size); -+ break; -+ case SYMBOL_PCIE_DEV_MODE: -+ ret = pcie_device_func_write(i2c->dev_name, pos, val, size); -+ break; -+ case SYMBOL_IO_DEV_MODE: -+ ret = io_device_func_write(i2c->dev_name, pos, val, size); -+ break; -+ default: -+ OCORES_I2C_ERROR("err func_mode, write failed.\n"); -+ return -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static int ocores_i2c_reg_read(struct ocores_i2c *i2c, uint32_t pos, uint8_t *val, size_t size) -+{ -+ int ret; -+ -+ switch (i2c->reg_access_mode) { -+ case SYMBOL_I2C_DEV_MODE: -+ ret = i2c_device_func_read(i2c->dev_name, pos, val, size); -+ break; -+ case FILE_MODE: -+ ret = ocores_i2c_file_read(i2c->dev_name, pos, val, size); -+ break; -+ case SYMBOL_PCIE_DEV_MODE: -+ ret = pcie_device_func_read(i2c->dev_name, pos, val, size); -+ break; -+ case SYMBOL_IO_DEV_MODE: -+ ret = io_device_func_read(i2c->dev_name, pos, val, size); -+ break; -+ default: -+ OCORES_I2C_ERROR("err func_mode, read failed.\n"); -+ return -EINVAL; -+ } -+ -+ return ret; -+} -+static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u32 value) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_1]; -+ u32 pos; -+ -+ pos = i2c->base_addr + (reg << i2c->reg_shift); -+ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ i2c->dev_name, i2c->reg_access_mode, pos, value); -+ -+ buf_tmp[0] = (value & 0Xff); -+ ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_1); -+ return; -+} -+ -+static void oc_setreg_16(struct ocores_i2c *i2c, int reg, u32 value) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_2]; -+ u32 pos; -+ -+ pos = i2c->base_addr + (reg << i2c->reg_shift); -+ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ i2c->dev_name, i2c->reg_access_mode, pos, value); -+ -+ buf_tmp[0] = (value & 0Xff); -+ buf_tmp[1] = (value >> 8) & 0xff; -+ ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_2); -+ return; -+} -+ -+static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u32 value) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_4]; -+ u32 pos; -+ -+ pos = i2c->base_addr + (reg << i2c->reg_shift); -+ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ i2c->dev_name, i2c->reg_access_mode, pos, value); -+ -+ buf_tmp[0] = (value & 0xff); -+ buf_tmp[1] = (value >> 8) & 0xff; -+ buf_tmp[2] = (value >> 16) & 0xff; -+ buf_tmp[3] = (value >> 24) & 0xff; -+ -+ ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_4); -+ return; -+} -+ -+static void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u32 value) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_2]; -+ u32 pos; -+ -+ pos = i2c->base_addr + (reg << i2c->reg_shift); -+ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ i2c->dev_name, i2c->reg_access_mode, pos, value); -+ -+ buf_tmp[0] = (value >> 8) & 0xff; -+ buf_tmp[1] = (value & 0Xff); -+ ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_2); -+ return; -+} -+ -+static void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u32 value) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_4]; -+ u32 pos; -+ -+ pos = i2c->base_addr + (reg << i2c->reg_shift); -+ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ i2c->dev_name, i2c->reg_access_mode, pos, value); -+ -+ buf_tmp[0] = (value >> 24) & 0xff; -+ buf_tmp[1] = (value >> 16) & 0xff; -+ buf_tmp[2] = (value >> 8) & 0xff; -+ buf_tmp[3] = (value & 0xff); -+ ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_4); -+ return; -+} -+ -+static inline u32 oc_getreg_8(struct ocores_i2c *i2c, int reg) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_1]; -+ u32 value, pos; -+ -+ pos = i2c->base_addr + (reg << i2c->reg_shift); -+ ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_1); -+ value = buf_tmp[0]; -+ -+ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ i2c->dev_name, i2c->reg_access_mode, pos, value); -+ -+ return value; -+} -+ -+static inline u32 oc_getreg_16(struct ocores_i2c *i2c, int reg) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_2]; -+ u32 value, pos; -+ int i; -+ -+ pos = i2c->base_addr + (reg << i2c->reg_shift); -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_2); -+ -+ value = 0; -+ for (i = 0; i < REG_IO_WIDTH_2 ; i++) { -+ value |= buf_tmp[i] << (8 * i); -+ } -+ -+ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ i2c->dev_name, i2c->reg_access_mode, pos, value); -+ return value; -+} -+ -+static inline u32 oc_getreg_32(struct ocores_i2c *i2c, int reg) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_4]; -+ u32 value, pos; -+ int i; -+ -+ pos = i2c->base_addr + (reg << i2c->reg_shift); -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_4); -+ -+ value = 0; -+ for (i = 0; i < REG_IO_WIDTH_4 ; i++) { -+ value |= buf_tmp[i] << (8 * i); -+ } -+ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ i2c->dev_name, i2c->reg_access_mode, pos, value); -+ return value; -+} -+ -+static inline u32 oc_getreg_16be(struct ocores_i2c *i2c, int reg) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_2]; -+ u32 value, pos; -+ int i; -+ -+ pos = i2c->base_addr + (reg << i2c->reg_shift); -+ -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_2); -+ -+ value = 0; -+ for (i = 0; i < REG_IO_WIDTH_2 ; i++) { -+ value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_2 -i - 1)); -+ } -+ -+ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ i2c->dev_name, i2c->reg_access_mode, pos, value); -+ return value; -+} -+ -+static inline u32 oc_getreg_32be(struct ocores_i2c *i2c, int reg) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_4]; -+ u32 value, pos; -+ int i; -+ -+ pos = i2c->base_addr + (reg << i2c->reg_shift); -+ -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_4); -+ -+ value = 0; -+ for (i = 0; i < REG_IO_WIDTH_4 ; i++) { -+ value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_4 -i - 1)); -+ } -+ -+ OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ i2c->dev_name, i2c->reg_access_mode, pos, value); -+ return value; -+ -+} -+ -+static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u32 value) -+{ -+ i2c->setreg(i2c, reg, value); -+ return; -+} -+ -+static inline u32 oc_getreg(struct ocores_i2c *i2c, int reg) -+{ -+ return i2c->getreg(i2c, reg); -+} -+ -+static int ocores_msg_check(struct i2c_msg *msgs, int num) -+{ -+ int i, ret = 0; -+ -+ if (!msgs) { -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ for (i = 0; i < num; ++i) { -+ if (!msgs[i].buf) { -+ ret = -EFAULT; -+ goto out; -+ } -+ } -+ -+out: -+ return ret; -+} -+ -+static void ocores_process(struct ocores_i2c *i2c, u8 stat) -+{ -+ struct i2c_msg *msg = i2c->msg; -+ -+ OCORES_I2C_XFER("Enter nr %d.\n", i2c->adap.nr); -+ 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); -+ OCORES_I2C_XFER("stop has been sent, exit.\n"); -+ goto out; -+ } -+ -+ /* error? */ -+ if (stat & OCI2C_STAT_ARBLOST) { -+ i2c->state = STATE_ERROR; -+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); -+ OCORES_I2C_XFER("error exit, lose arbitration.\n"); -+ goto out; -+ } -+ -+ if (ocores_msg_check(i2c->msg, i2c->nmsgs) != 0) { -+ OCORES_I2C_XFER("msg buf is NULL\n"); -+ i2c->state = STATE_ERROR; -+ 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; -+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); -+ OCORES_I2C_XFER("OCI2C_STAT_NACK, exit.\n"); -+ goto out; -+ } -+ } else { -+ msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA); -+ } -+ -+ /* end of msg? */ -+ if (i2c->pos == msg->len) { -+ OCORES_I2C_XFER("Enter end of msg.\n"); -+ 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); -+ OCORES_I2C_XFER("send start, exit.\n"); -+ 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); -+ OCORES_I2C_XFER("send OCI2C_CMD_STOP, exit.\n"); -+ 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: -+ OCORES_I2C_XFER("normal, exit nr %d.\n", i2c->adap.nr); -+ return; -+} -+ -+static irqreturn_t ocores_isr(int irq, void *dev_id) -+{ -+ struct ocores_i2c *i2c = dev_id; -+ u8 stat; -+ unsigned long flags; -+ -+ if (!i2c) { -+ return IRQ_NONE; -+ } -+ -+ spin_lock_irqsave(&i2c->process_lock, flags); -+ stat = oc_getreg(i2c, OCI2C_STATUS); -+ if (!(stat & OCI2C_STAT_IF)) { -+ spin_unlock_irqrestore(&i2c->process_lock, flags); -+ return IRQ_NONE; -+ } -+ OCORES_I2C_XFER("Enter, irq %d nr %d addr 0x%x.\n", irq, i2c->adap.nr, (!i2c->msg)? 0 : i2c->msg->addr); -+ ocores_process(i2c, stat); -+ OCORES_I2C_XFER("Leave, irq %d nr %d addr 0x%x.\n", irq, i2c->adap.nr, (!i2c->msg)? 0 : i2c->msg->addr); -+ spin_unlock_irqrestore(&i2c->process_lock, flags); -+ -+ 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); -+ mdelay(1); -+ spin_unlock_irqrestore(&i2c->process_lock, flags); -+ return; -+} -+ -+/** -+ * 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) -+{ -+ u8 status; -+ unsigned long j, jiffies_tmp; -+ unsigned int usleep; -+ -+ usleep = OCORE_WAIT_SCH; -+ j = jiffies + timeout; -+ while (1) { -+ jiffies_tmp = jiffies; -+ status = oc_getreg(i2c, reg); -+ -+ if ((status & mask) == val) { -+ break; -+ } -+ -+ if (time_after(jiffies_tmp, j)) { -+ OCORES_I2C_XFER("STATUS timeout, mask[0x%x] val[0x%x] status[0x%x]\n", mask, val, status); -+ return -ETIMEDOUT; -+ } -+ usleep_range(usleep,usleep + 1); -+ } -+ 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 100ms we timeout then something is broken. -+ */ -+ err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, msecs_to_jiffies(100)); -+ if (err) { -+ OCORES_I2C_XFER("STATUS timeout, bit 0x%x did not clear in 100ms, err %d\n", mask, err); -+ } -+ 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 int ocores_process_polling(struct ocores_i2c *i2c) -+{ -+ irqreturn_t ret; -+ int err; -+ -+ while (1) { -+ 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 */ -+ } -+ } -+ -+ return err; -+} -+ -+static int ocores_xfer_core(struct ocores_i2c *i2c, -+ struct i2c_msg *msgs, int num, -+ bool polling) -+{ -+ int ret; -+ u8 ctrl; -+ unsigned long flags; -+ -+ OCORES_I2C_VERBOSE("Enter ocores_xfer_core. polling mode:%d.\n", polling); -+ spin_lock_irqsave(&i2c->process_lock, flags); -+ -+ 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); -+ -+ spin_unlock_irqrestore(&i2c->process_lock, flags); -+ -+ if (polling) { -+ ret = ocores_process_polling(i2c); -+ if (ret) { -+ ocores_process_timeout(i2c); -+ return -ETIMEDOUT; -+ } -+ } 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(struct i2c_adapter *adap, -+ struct i2c_msg *msgs, int num) -+{ -+ struct ocores_i2c *i2c; -+ int ret; -+ -+ OCORES_I2C_VERBOSE("Enter ocores_xfer.\n"); -+ if (!adap || ocores_msg_check(msgs, num)) { -+ OCORES_I2C_ERROR("[MAY BE USER SPACE ERROR]:msg buf is NULL\n"); -+ return -EFAULT; -+ } -+ OCORES_I2C_VERBOSE("i2c bus:%d, msgs num:%d.\n", adap->nr, num); -+ -+ i2c = i2c_get_adapdata(adap); -+ -+ if (i2c->flags & OCORES_FLAG_POLL) { -+ ret = ocores_xfer_core(i2c, msgs, num, true); -+ } else { -+ ret = ocores_xfer_core(i2c, msgs, num, false); -+ } -+ -+ return ret; -+} -+ -+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 const struct i2c_algorithm ocores_algorithm = { -+ .master_xfer = ocores_xfer, -+ .functionality = ocores_func, -+}; -+ -+static const struct i2c_adapter ocores_adapter = { -+ .owner = THIS_MODULE, -+ .name = "wb-i2c-ocores", -+ .class = I2C_CLASS_DEPRECATED, -+ .algo = &ocores_algorithm, -+}; -+ -+static const struct of_device_id ocores_i2c_match[] = { -+ { -+ .compatible = "opencores,wb-i2c-ocores", -+ .data = (void *)TYPE_OCORES, -+ }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, ocores_i2c_match); -+ -+static int fpga_ocores_i2c_get_irq(struct ocores_i2c *i2c) -+{ -+ int devfn, irq; -+ struct device *dev; -+ wb_pci_dev_t *wb_pci_dev; -+ struct pci_dev *pci_dev; -+ i2c_ocores_device_t *i2c_ocores_device; -+ int ret; -+ -+ dev = i2c->dev; -+ wb_pci_dev = &i2c->wb_pci_dev; -+ -+ if (dev->of_node) { -+ ret = 0; -+ ret += of_property_read_u32(dev->of_node, "pci_domain", &wb_pci_dev->domain); -+ ret += of_property_read_u32(dev->of_node, "pci_bus", &wb_pci_dev->bus); -+ ret += of_property_read_u32(dev->of_node, "pci_slot", &wb_pci_dev->slot); -+ ret += of_property_read_u32(dev->of_node, "pci_fn", &wb_pci_dev->fn); -+ -+ if (ret != 0) { -+ OCORES_I2C_ERROR("dts config error, ret:%d.\n", ret); -+ ret = -EINVAL; -+ return ret; -+ } -+ } else { -+ if (i2c->dev->platform_data == NULL) { -+ OCORES_I2C_ERROR("Failed to get platform data config.\n"); -+ ret = -EINVAL; -+ return ret; -+ } -+ i2c_ocores_device = i2c->dev->platform_data; -+ wb_pci_dev->domain = i2c_ocores_device->pci_domain; -+ wb_pci_dev->bus = i2c_ocores_device->pci_bus; -+ wb_pci_dev->slot = i2c_ocores_device->pci_slot; -+ wb_pci_dev->fn = i2c_ocores_device->pci_fn; -+ } -+ -+ OCORES_I2C_VERBOSE("pci_domain:0x%x, pci_bus:0x%x, pci_slot:0x%x, pci_fn:0x%x.\n", -+ wb_pci_dev->domain, wb_pci_dev->bus, wb_pci_dev->slot, wb_pci_dev->fn); -+ -+ devfn = PCI_DEVFN(wb_pci_dev->slot, wb_pci_dev->fn); -+ pci_dev = pci_get_domain_bus_and_slot(wb_pci_dev->domain, wb_pci_dev->bus, devfn); -+ if (pci_dev == NULL) { -+ OCORES_I2C_ERROR("Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", -+ wb_pci_dev->domain, wb_pci_dev->bus, devfn); -+ return -ENODEV; -+ } -+ irq = pci_dev->irq + i2c->irq_offset; -+ OCORES_I2C_VERBOSE("get irq no:%d.\n", irq); -+ return irq; -+} -+ -+static int ocores_i2c_config_init(struct ocores_i2c *i2c) -+{ -+ int ret; -+ struct device *dev; -+ i2c_ocores_device_t *i2c_ocores_device; -+ -+ dev = i2c->dev; -+ ret = 0; -+ -+ if (dev->of_node) { -+ ret += of_property_read_string(dev->of_node, "dev_name", &i2c->dev_name); -+ ret += of_property_read_u32(dev->of_node, "dev_base", &i2c->base_addr); -+ ret += of_property_read_u32(dev->of_node, "reg_shift", &i2c->reg_shift); -+ ret += of_property_read_u32(dev->of_node, "reg_io_width", &i2c->reg_io_width); -+ ret += of_property_read_u32(dev->of_node, "ip_clock_khz", &i2c->ip_clock_khz); -+ ret += of_property_read_u32(dev->of_node, "bus_clock_khz", &i2c->bus_clock_khz); -+ ret += of_property_read_u32(dev->of_node, "reg_access_mode", &i2c->reg_access_mode); -+ -+ if (ret != 0) { -+ OCORES_I2C_ERROR("dts config error, ret:%d.\n", ret); -+ ret = -ENXIO; -+ return ret; -+ } -+ } else { -+ if (i2c->dev->platform_data == NULL) { -+ OCORES_I2C_ERROR("Failed to get platform data config.\n"); -+ ret = -ENXIO; -+ return ret; -+ } -+ i2c_ocores_device = i2c->dev->platform_data; -+ i2c->dev_name = i2c_ocores_device->dev_name; -+ i2c->adap_nr = i2c_ocores_device->adap_nr; -+ i2c->big_endian = i2c_ocores_device->big_endian; -+ i2c->base_addr = i2c_ocores_device->dev_base; -+ i2c->reg_shift = i2c_ocores_device->reg_shift; -+ i2c->reg_io_width = i2c_ocores_device->reg_io_width; -+ i2c->ip_clock_khz = i2c_ocores_device->ip_clock_khz; -+ i2c->bus_clock_khz = i2c_ocores_device->bus_clock_khz; -+ i2c->reg_access_mode = i2c_ocores_device->reg_access_mode; -+ } -+ -+ OCORES_I2C_VERBOSE("name:%s, base:0x%x, reg_shift:0x%x, io_width:0x%x, ip_clock_khz:0x%x, bus_clock_khz:0x%x.\n", -+ i2c->dev_name, i2c->base_addr, i2c->reg_shift, i2c->reg_io_width, i2c->ip_clock_khz, i2c->bus_clock_khz); -+ OCORES_I2C_VERBOSE("reg access mode:%d.\n", i2c->reg_access_mode); -+ return ret; -+} -+ -+static int ocores_i2c_probe(struct platform_device *pdev) -+{ -+ struct ocores_i2c *i2c; -+ int irq, ret; -+ bool be; -+ i2c_ocores_device_t *i2c_ocores_device; -+ -+ OCORES_I2C_VERBOSE("Enter main probe\n"); -+ -+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); -+ if (!i2c) { -+ dev_err(&pdev->dev, "devm_kzalloc failed.\n"); -+ return -ENOMEM; -+ } -+ -+ spin_lock_init(&i2c->process_lock); -+ -+ i2c->dev = &pdev->dev; -+ ret = ocores_i2c_config_init(i2c); -+ if (ret !=0) { -+ dev_err(i2c->dev, "Failed to get ocores i2c dts config.\n"); -+ goto out; -+ } -+ -+ if (i2c->dev->of_node) { -+ if (of_property_read_u32(i2c->dev->of_node, "big_endian", &i2c->big_endian)) { -+ -+ be = 0; -+ } else { -+ be = i2c->big_endian; -+ } -+ } else { -+ be = i2c->big_endian; -+ } -+ -+ if (i2c->reg_io_width == 0) { -+ i2c->reg_io_width = 1; /* Set to default value */ -+ } -+ -+ if (!i2c->setreg || !i2c->getreg) { -+ switch (i2c->reg_io_width) { -+ case REG_IO_WIDTH_1: -+ i2c->setreg = oc_setreg_8; -+ i2c->getreg = oc_getreg_8; -+ break; -+ -+ case REG_IO_WIDTH_2: -+ i2c->setreg = be ? oc_setreg_16be : oc_setreg_16; -+ i2c->getreg = be ? oc_getreg_16be : oc_getreg_16; -+ break; -+ -+ case REG_IO_WIDTH_4: -+ i2c->setreg = be ? oc_setreg_32be : oc_setreg_32; -+ i2c->getreg = be ? oc_getreg_32be : oc_getreg_32; -+ break; -+ -+ default: -+ dev_err(i2c->dev, "Unsupported I/O width (%d)\n", -+ i2c->reg_io_width); -+ ret = -EINVAL; -+ goto out; -+ } -+ } -+ -+ init_waitqueue_head(&i2c->wait); -+ irq = -1; -+ -+ if (i2c->dev->of_node) { -+ if (of_property_read_u32(i2c->dev->of_node, "irq_offset", &i2c->irq_offset)) { -+ -+ i2c->flags |= OCORES_FLAG_POLL; -+ } else { -+ -+ irq = fpga_ocores_i2c_get_irq(i2c); -+ if (irq < 0 ) { -+ dev_err(i2c->dev, "Failed to get ocores i2c irq number, ret: %d.\n", irq); -+ ret = irq; -+ goto out; -+ } -+ } -+ } else { -+ if (i2c->dev->platform_data == NULL) { -+ -+ i2c->flags |= OCORES_FLAG_POLL; -+ OCORES_I2C_VERBOSE("Failed to get platform data config, set OCORES_FLAG_POLL.\n"); -+ } else { -+ i2c_ocores_device = i2c->dev->platform_data; -+ if (i2c_ocores_device->irq_type == 0) { -+ -+ i2c->flags |= OCORES_FLAG_POLL; -+ } else { -+ -+ irq = fpga_ocores_i2c_get_irq(i2c); -+ if (irq < 0 ) { -+ dev_err(i2c->dev, "Failed to get ocores i2c irq number, ret: %d.\n", irq); -+ ret = irq; -+ goto out; -+ } -+ } -+ } -+ } -+ -+ if (!(i2c->flags & OCORES_FLAG_POLL)) { -+ ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, -+ pdev->name, i2c); -+ if (ret) { -+ dev_err(i2c->dev, "Cannot claim IRQ\n"); -+ goto out; -+ } -+ } -+ -+ ret = ocores_init(i2c->dev, i2c); -+ if (ret) { -+ goto out; -+ } -+ -+ /* 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; -+ i2c->adap.dev.of_node = pdev->dev.of_node; -+ -+ if (i2c->dev->of_node) { -+ /* adap.nr get from dts aliases */ -+ ret = i2c_add_adapter(&i2c->adap); -+ } else { -+ i2c->adap.nr = i2c->adap_nr; -+ ret = i2c_add_numbered_adapter(&i2c->adap); -+ } -+ if (ret) { -+ goto fail_add; -+ } -+ OCORES_I2C_VERBOSE("Main probe out\n"); -+ dev_info(i2c->dev, "registered i2c-%d for %s with base address:0x%x success.\n", -+ i2c->adap.nr, i2c->dev_name, i2c->base_addr); -+ return 0; -+fail_add: -+ platform_set_drvdata(pdev, NULL); -+out: -+ return ret; -+} -+ -+static int 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); -+ return 0; -+} -+ -+static struct platform_driver ocores_i2c_driver = { -+ .probe = ocores_i2c_probe, -+ .remove = ocores_i2c_remove, -+ .driver = { -+ .name = "wb-ocores-i2c", -+ .of_match_table = ocores_i2c_match, -+ }, -+}; -+ -+module_platform_driver(ocores_i2c_driver); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("OpenCores I2C bus driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:ocores-i2c"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.h -new file mode 100644 -index 000000000..acd2710a9 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.h -@@ -0,0 +1,28 @@ -+#ifndef __WB_I2C_OCORES_H__ -+#define __WB_I2C_OCORES_H__ -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+#define I2C_OCORES_DEV_NAME_MAX_LEN (64) -+ -+typedef struct i2c_ocores_device_s { -+ uint32_t big_endian; -+ char dev_name[I2C_OCORES_DEV_NAME_MAX_LEN]; -+ int adap_nr; -+ uint32_t dev_base; -+ uint32_t reg_shift; -+ uint32_t reg_io_width; -+ uint32_t ip_clock_khz; -+ uint32_t bus_clock_khz; -+ uint32_t reg_access_mode; -+ -+ uint32_t irq_type; -+ uint32_t irq_offset; -+ uint32_t pci_domain; -+ uint32_t pci_bus; -+ uint32_t pci_slot; -+ uint32_t pci_fn; -+ int device_flag; -+} i2c_ocores_device_t; -+ -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.c -new file mode 100644 -index 000000000..b1f5294b8 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.c -@@ -0,0 +1,571 @@ -+/* -+ * wb_io_dev.c -+ * ko to read/write ioports through /dev/XXX device -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "wb_io_dev.h" -+ -+#define PROXY_NAME "wb-io-dev" -+#define MAX_IO_DEV_NUM (256) -+#define IO_RDWR_MAX_LEN (256) -+#define MAX_NAME_SIZE (20) -+#define IO_INDIRECT_ADDR_H(addr) ((addr >> 8) & 0xff) -+#define IO_INDIRECT_ADDR_L(addr) ((addr) & 0xff) -+#define IO_INDIRECT_OP_WRITE (0x2) -+#define IO_INDIRECT_OP_READ (0X3) -+ -+static int g_io_dev_debug = 0; -+static int g_io_dev_error = 0; -+ -+module_param(g_io_dev_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_io_dev_error, int, S_IRUGO | S_IWUSR); -+ -+#define IO_DEV_DEBUG_VERBOSE(fmt, args...) do { \ -+ if (g_io_dev_debug) { \ -+ printk(KERN_INFO "[IO_DEV][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define IO_DEV_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_io_dev_error) { \ -+ printk(KERN_ERR "[IO_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+typedef struct wb_io_dev_s { -+ const char *name; -+ uint32_t io_base; -+ uint32_t io_len; -+ uint32_t indirect_addr; -+ uint32_t wr_data; -+ uint32_t addr_low; -+ uint32_t addr_high; -+ uint32_t rd_data; -+ uint32_t opt_ctl; -+ spinlock_t io_dev_lock; -+ struct miscdevice misc; -+} wb_io_dev_t; -+ -+static wb_io_dev_t* io_dev_arry[MAX_IO_DEV_NUM]; -+ -+static int io_dev_open(struct inode *inode, struct file *file) -+{ -+ unsigned int minor = iminor(inode); -+ wb_io_dev_t *wb_io_dev; -+ -+ if (minor >= MAX_IO_DEV_NUM) { -+ IO_DEV_DEBUG_ERROR("minor out of range, minor = %d.\n", minor); -+ return -ENODEV; -+ } -+ -+ wb_io_dev = io_dev_arry[minor]; -+ if (wb_io_dev == NULL) { -+ IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, open failed, minor = %d\n", minor); -+ return -ENODEV; -+ } -+ -+ file->private_data = wb_io_dev; -+ return 0; -+} -+ -+static int io_dev_release(struct inode *inode, struct file *file) -+{ -+ file->private_data = NULL; -+ return 0; -+} -+ -+uint8_t io_indirect_addressing_read(wb_io_dev_t *wb_io_dev, uint32_t address) -+{ -+ uint8_t addr_l, addr_h, value; -+ unsigned long flags; -+ -+ addr_h = IO_INDIRECT_ADDR_H(address); -+ addr_l = IO_INDIRECT_ADDR_L(address); -+ IO_DEV_DEBUG_VERBOSE("read one count, addr = 0x%x\n", address); -+ -+ spin_lock_irqsave(&wb_io_dev->io_dev_lock, flags); -+ -+ outb(addr_l, wb_io_dev->io_base + wb_io_dev->addr_low); -+ -+ outb(addr_h, wb_io_dev->io_base + wb_io_dev->addr_high); -+ -+ outb(IO_INDIRECT_OP_READ, wb_io_dev->io_base + wb_io_dev->opt_ctl); -+ -+ value = inb(wb_io_dev->io_base + wb_io_dev->rd_data); -+ -+ spin_unlock_irqrestore(&wb_io_dev->io_dev_lock, flags); -+ -+ return value; -+} -+ -+static int io_dev_read_tmp(wb_io_dev_t *wb_io_dev, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ int i; -+ -+ if (offset > wb_io_dev->io_len) { -+ IO_DEV_DEBUG_VERBOSE("offset:0x%x, io len:0x%x, EOF.\n", offset, wb_io_dev->io_len); -+ return 0; -+ } -+ -+ if (count > wb_io_dev->io_len - offset) { -+ IO_DEV_DEBUG_VERBOSE("read count out of range. input len:%lu, read len:%u.\n", -+ count, wb_io_dev->io_len - offset); -+ count = wb_io_dev->io_len - offset; -+ } -+ if (wb_io_dev->indirect_addr) { -+ for (i = 0; i < count; i++) { -+ buf[i] = io_indirect_addressing_read(wb_io_dev, offset + i); -+ } -+ } else { -+ for (i = 0; i < count; i++) { -+ buf[i] = inb(wb_io_dev->io_base + offset + i); -+ } -+ } -+ -+ return count; -+} -+ -+static ssize_t io_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) -+{ -+ wb_io_dev_t *wb_io_dev; -+ int ret, read_len; -+ u8 buf_tmp[IO_RDWR_MAX_LEN]; -+ -+ wb_io_dev = file->private_data; -+ if (wb_io_dev == NULL) { -+ IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, read failed.\n"); -+ return -EINVAL; -+ } -+ -+ if (count == 0) { -+ IO_DEV_DEBUG_ERROR("Invalid params, read count is 0.\n"); -+ return -EINVAL; -+ } -+ -+ if (count > sizeof(buf_tmp)) { -+ IO_DEV_DEBUG_VERBOSE("read count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); -+ count = sizeof(buf_tmp); -+ } -+ -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ read_len = io_dev_read_tmp(wb_io_dev, *offset, buf_tmp, count); -+ if (read_len < 0) { -+ IO_DEV_DEBUG_ERROR("io_dev_read_tmp failed, ret:%d.\n", read_len); -+ return read_len; -+ } -+ -+ if (access_ok(buf, read_len)) { -+ IO_DEV_DEBUG_VERBOSE("user space read, buf: %p, offset: %lld, read count %lu.\n", -+ buf, *offset, count); -+ if (copy_to_user(buf, buf_tmp, read_len)) { -+ IO_DEV_DEBUG_ERROR("copy_to_user failed.\n"); -+ return -EFAULT; -+ } -+ } else { -+ IO_DEV_DEBUG_VERBOSE("kernel space read, buf: %p, offset: %lld, read count %lu.\n", -+ buf, *offset, count); -+ memcpy(buf, buf_tmp, read_len); -+ } -+ *offset += read_len; -+ ret = read_len; -+ return ret; -+} -+ -+static ssize_t io_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) -+{ -+ int ret; -+ -+ IO_DEV_DEBUG_VERBOSE("io_dev_read_iter, file: %p, count: %lu, offset: %lld\n", -+ iocb->ki_filp, to->count, iocb->ki_pos); -+ ret = io_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos); -+ return ret; -+} -+ -+void io_indirect_addressing_write(wb_io_dev_t *wb_io_dev, uint32_t address, uint8_t reg_val) -+{ -+ uint8_t addr_l, addr_h; -+ unsigned long flags; -+ -+ addr_h = IO_INDIRECT_ADDR_H(address); -+ addr_l = IO_INDIRECT_ADDR_L(address); -+ IO_DEV_DEBUG_VERBOSE("write one count, addr = 0x%x\n", address); -+ -+ spin_lock_irqsave(&wb_io_dev->io_dev_lock, flags); -+ -+ outb(reg_val, wb_io_dev->io_base + wb_io_dev->wr_data); -+ -+ outb(addr_l, wb_io_dev->io_base + wb_io_dev->addr_low); -+ -+ outb(addr_h, wb_io_dev->io_base + wb_io_dev->addr_high); -+ -+ outb(IO_INDIRECT_OP_WRITE, wb_io_dev->io_base + wb_io_dev->opt_ctl); -+ -+ spin_unlock_irqrestore(&wb_io_dev->io_dev_lock, flags); -+ -+ return; -+} -+ -+static int io_dev_write_tmp(wb_io_dev_t *wb_io_dev, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ int i; -+ -+ if (offset > wb_io_dev->io_len) { -+ IO_DEV_DEBUG_VERBOSE("offset:0x%x, io len:0x%x, EOF.\n", offset, wb_io_dev->io_len); -+ return 0; -+ } -+ -+ if (count > wb_io_dev->io_len - offset) { -+ IO_DEV_DEBUG_VERBOSE("write count out of range. input len:%lu, write len:%u.\n", -+ count, wb_io_dev->io_len - offset); -+ count = wb_io_dev->io_len - offset; -+ } -+ if (wb_io_dev->indirect_addr) { -+ for (i = 0; i < count; i++) { -+ io_indirect_addressing_write(wb_io_dev, offset + i, buf[i]); -+ } -+ } else { -+ for (i = 0; i < count; i++) { -+ outb(buf[i], wb_io_dev->io_base + offset + i); -+ } -+ } -+ -+ return count; -+} -+ -+static ssize_t io_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) -+{ -+ wb_io_dev_t *wb_io_dev; -+ int write_len; -+ u8 buf_tmp[IO_RDWR_MAX_LEN]; -+ -+ wb_io_dev = file->private_data; -+ if (wb_io_dev == NULL) { -+ IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, write failed.\n"); -+ return -EINVAL; -+ } -+ -+ if (count == 0) { -+ IO_DEV_DEBUG_ERROR("Invalid params, write count is 0.\n"); -+ return -EINVAL; -+ } -+ -+ if (count > sizeof(buf_tmp)) { -+ IO_DEV_DEBUG_VERBOSE("write count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); -+ count = sizeof(buf_tmp); -+ } -+ -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ if (access_ok(buf, count)) { -+ IO_DEV_DEBUG_VERBOSE("user space write, buf: %p, offset: %lld, write count %lu.\n", -+ buf, *offset, count); -+ if (copy_from_user(buf_tmp, buf, count)) { -+ IO_DEV_DEBUG_ERROR("copy_from_user failed.\n"); -+ return -EFAULT; -+ } -+ } else { -+ IO_DEV_DEBUG_VERBOSE("kernel space write, buf: %p, offset: %lld, write count %lu.\n", -+ buf, *offset, count); -+ memcpy(buf_tmp, buf, count); -+ } -+ -+ write_len = io_dev_write_tmp(wb_io_dev, *offset, buf_tmp, count); -+ if (write_len < 0) { -+ IO_DEV_DEBUG_ERROR("io_dev_write_tmp failed, ret:%d.\n", write_len); -+ return write_len; -+ } -+ -+ *offset += write_len; -+ return write_len; -+} -+ -+static ssize_t io_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) -+{ -+ int ret; -+ -+ IO_DEV_DEBUG_VERBOSE("io_dev_write_iter, file: %p, count: %lu, offset: %lld\n", -+ iocb->ki_filp, from->count, iocb->ki_pos); -+ ret = io_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos); -+ return ret; -+} -+ -+static loff_t io_dev_llseek(struct file *file, loff_t offset, int origin) -+{ -+ loff_t ret = 0; -+ wb_io_dev_t *wb_io_dev; -+ -+ wb_io_dev = file->private_data; -+ if (wb_io_dev == NULL) { -+ IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, llseek failed.\n"); -+ return -EINVAL; -+ } -+ -+ switch (origin) { -+ case SEEK_SET: -+ if (offset < 0) { -+ IO_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); -+ ret = -EINVAL; -+ break; -+ } -+ if (offset > wb_io_dev->io_len) { -+ IO_DEV_DEBUG_ERROR("SEEK_SET out of range, offset:%lld, io_len:0x%x.\n", -+ offset, wb_io_dev->io_len); -+ ret = - EINVAL; -+ break; -+ } -+ file->f_pos = offset; -+ ret = file->f_pos; -+ break; -+ case SEEK_CUR: -+ if (((file->f_pos + offset) > wb_io_dev->io_len) || ((file->f_pos + offset) < 0)) { -+ IO_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld, io_len:0x%x.\n", -+ file->f_pos, offset, wb_io_dev->io_len); -+ ret = - EINVAL; -+ break; -+ } -+ file->f_pos += offset; -+ ret = file->f_pos; -+ break; -+ default: -+ IO_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+ -+static long io_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ return 0; -+} -+ -+static const struct file_operations io_dev_fops = { -+ .owner = THIS_MODULE, -+ .llseek = io_dev_llseek, -+ .read_iter = io_dev_read_iter, -+ .write_iter = io_dev_write_iter, -+ .unlocked_ioctl = io_dev_ioctl, -+ .open = io_dev_open, -+ .release = io_dev_release, -+}; -+ -+static wb_io_dev_t *dev_match(const char *path) -+{ -+ wb_io_dev_t *wb_io_dev; -+ char dev_name[MAX_NAME_SIZE]; -+ int i; -+ -+ for (i = 0; i < MAX_IO_DEV_NUM; i++) { -+ if (io_dev_arry[i] == NULL) { -+ continue; -+ } -+ wb_io_dev = io_dev_arry[i]; -+ snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", wb_io_dev->name); -+ if (!strcmp(path, dev_name)) { -+ IO_DEV_DEBUG_VERBOSE("get dev_name = %s, minor = %d\n", dev_name, i); -+ return wb_io_dev; -+ } -+ } -+ -+ return NULL; -+} -+ -+int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ wb_io_dev_t *wb_io_dev; -+ int read_len; -+ -+ if (path == NULL) { -+ IO_DEV_DEBUG_ERROR("path NULL"); -+ return -EINVAL; -+ } -+ -+ if (buf == NULL) { -+ IO_DEV_DEBUG_ERROR("buf NULL"); -+ return -EINVAL; -+ } -+ -+ wb_io_dev = dev_match(path); -+ if (wb_io_dev == NULL) { -+ IO_DEV_DEBUG_ERROR("io_dev match failed. dev path = %s", path); -+ return -EINVAL; -+ } -+ -+ read_len = io_dev_read_tmp(wb_io_dev, offset, buf, count); -+ if (read_len < 0) { -+ IO_DEV_DEBUG_ERROR("io_dev_read_tmp failed, ret:%d.\n", read_len); -+ } -+ return read_len; -+} -+EXPORT_SYMBOL(io_device_func_read); -+ -+int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ wb_io_dev_t *wb_io_dev; -+ int write_len; -+ -+ if (path == NULL) { -+ IO_DEV_DEBUG_ERROR("path NULL"); -+ return -EINVAL; -+ } -+ -+ if (buf == NULL) { -+ IO_DEV_DEBUG_ERROR("buf NULL"); -+ return -EINVAL; -+ } -+ -+ wb_io_dev = dev_match(path); -+ if (wb_io_dev == NULL) { -+ IO_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); -+ return -EINVAL; -+ } -+ -+ write_len = io_dev_write_tmp(wb_io_dev, offset, buf, count); -+ if (write_len < 0) { -+ IO_DEV_DEBUG_ERROR("io_dev_write_tmp failed, ret:%d.\n", write_len); -+ } -+ return write_len; -+} -+EXPORT_SYMBOL(io_device_func_write); -+ -+static int io_dev_probe(struct platform_device *pdev) -+{ -+ int ret; -+ wb_io_dev_t *wb_io_dev; -+ struct miscdevice *misc; -+ io_dev_device_t *io_dev_device; -+ -+ wb_io_dev = devm_kzalloc(&pdev->dev, sizeof(wb_io_dev_t), GFP_KERNEL); -+ if (!wb_io_dev) { -+ dev_err(&pdev->dev, "devm_kzalloc failed.\n"); -+ ret = -ENOMEM; -+ return ret; -+ } -+ spin_lock_init(&wb_io_dev->io_dev_lock); -+ -+ if (pdev->dev.of_node) { -+ ret = 0; -+ ret += of_property_read_string(pdev->dev.of_node, "io_dev_name", &wb_io_dev->name); -+ ret += of_property_read_u32(pdev->dev.of_node, "io_base", &wb_io_dev->io_base); -+ ret += of_property_read_u32(pdev->dev.of_node, "io_len", &wb_io_dev->io_len); -+ if (of_property_read_bool(pdev->dev.of_node, "indirect_addr")) { -+ -+ wb_io_dev->indirect_addr = 1; -+ ret += of_property_read_u32(pdev->dev.of_node, "wr_data", &wb_io_dev->wr_data); -+ ret += of_property_read_u32(pdev->dev.of_node, "addr_low", &wb_io_dev->addr_low); -+ ret += of_property_read_u32(pdev->dev.of_node, "addr_high", &wb_io_dev->addr_high); -+ ret += of_property_read_u32(pdev->dev.of_node, "rd_data", &wb_io_dev->rd_data); -+ ret += of_property_read_u32(pdev->dev.of_node, "opt_ctl", &wb_io_dev->opt_ctl); -+ } else { -+ -+ wb_io_dev->indirect_addr = 0; -+ } -+ if (ret != 0) { -+ dev_err(&pdev->dev, "Failed to get dts config, ret:%d.\n", ret); -+ return -ENXIO; -+ } -+ } else { -+ if (pdev->dev.platform_data == NULL) { -+ dev_err(&pdev->dev, "Failed to get platform data config.\n"); -+ return -ENXIO; -+ } -+ io_dev_device = pdev->dev.platform_data; -+ wb_io_dev->name = io_dev_device->io_dev_name; -+ wb_io_dev->io_base = io_dev_device->io_base; -+ wb_io_dev->io_len = io_dev_device->io_len; -+ wb_io_dev->indirect_addr = io_dev_device->indirect_addr; -+ if (wb_io_dev->indirect_addr == 1) { -+ wb_io_dev->wr_data = io_dev_device->wr_data; -+ wb_io_dev->addr_low = io_dev_device->addr_low; -+ wb_io_dev->addr_high = io_dev_device->addr_high; -+ wb_io_dev->rd_data = io_dev_device->rd_data; -+ wb_io_dev->opt_ctl = io_dev_device->opt_ctl; -+ } -+ } -+ -+ IO_DEV_DEBUG_VERBOSE("name:%s, io base:0x%x, io len:0x%x, addressing type:%s.\n", -+ wb_io_dev->name, wb_io_dev->io_base, wb_io_dev->io_len, -+ wb_io_dev->indirect_addr ? "indirect" : "direct"); -+ -+ misc = &wb_io_dev->misc; -+ misc->minor = MISC_DYNAMIC_MINOR; -+ misc->name = wb_io_dev->name; -+ misc->fops = &io_dev_fops; -+ misc->mode = 0666; -+ if (misc_register(misc) != 0) { -+ dev_err(&pdev->dev, "Failed to register %s device.\n", misc->name); -+ return -ENXIO; -+ } -+ if (misc->minor >= MAX_IO_DEV_NUM) { -+ dev_err(&pdev->dev, "Error: device minor[%d] more than max io device num[%d].\n", -+ misc->minor, MAX_IO_DEV_NUM); -+ misc_deregister(misc); -+ return -EINVAL; -+ } -+ io_dev_arry[misc->minor] = wb_io_dev; -+ dev_info(&pdev->dev, "register %s device [0x%x][0x%x] with minor %d using %s addressing success.\n", -+ misc->name, wb_io_dev->io_base, wb_io_dev->io_len, misc->minor, -+ wb_io_dev->indirect_addr ? "indirect" : "direct"); -+ -+ return 0; -+} -+ -+static int io_dev_remove(struct platform_device *pdev) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_IO_DEV_NUM ; i++) { -+ if (io_dev_arry[i] != NULL) { -+ misc_deregister(&io_dev_arry[i]->misc); -+ io_dev_arry[i] = NULL; -+ } -+ } -+ -+ return 0; -+} -+ -+static struct of_device_id io_dev_match[] = { -+ { -+ .compatible = "wb-io-dev", -+ }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, io_dev_match); -+ -+static struct platform_driver wb_io_dev_driver = { -+ .probe = io_dev_probe, -+ .remove = io_dev_remove, -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = PROXY_NAME, -+ .of_match_table = io_dev_match, -+ }, -+}; -+ -+static int __init wb_io_dev_init(void) -+{ -+ return platform_driver_register(&wb_io_dev_driver); -+} -+ -+static void __exit wb_io_dev_exit(void) -+{ -+ platform_driver_unregister(&wb_io_dev_driver); -+} -+ -+module_init(wb_io_dev_init); -+module_exit(wb_io_dev_exit); -+MODULE_DESCRIPTION("IO device driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.h -new file mode 100644 -index 000000000..3a1a10f0f ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.h -@@ -0,0 +1,21 @@ -+#ifndef __WB_IO_DEV_H__ -+#define __WB_IO_DEV_H__ -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+#define IO_DEV_NAME_MAX_LEN (64) -+ -+typedef struct io_dev_device_s { -+ char io_dev_name[IO_DEV_NAME_MAX_LEN]; -+ uint32_t io_base; -+ uint32_t io_len; -+ uint32_t indirect_addr; -+ uint32_t wr_data; -+ uint32_t addr_low; -+ uint32_t addr_high; -+ uint32_t rd_data; -+ uint32_t opt_ctl; -+ int device_flag; -+} io_dev_device_t; -+ -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.c -new file mode 100644 -index 000000000..c079dc409 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.c -@@ -0,0 +1,166 @@ -+/* -+ * wb_lpc_drv.c -+ * ko to set lpc pcie config io addr and enable lpc -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "wb_lpc_drv.h" -+ -+#define LPC_DRIVER_NAME "wb-lpc" -+#define LPC_MAKE_PCI_IO_RANGE(__base) ((0xfc0001) | ((__base) & (0xFFFC))) -+ -+int g_lpc_dev_debug = 0; -+int g_lpc_dev_error = 0; -+ -+module_param(g_lpc_dev_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_lpc_dev_error, int, S_IRUGO | S_IWUSR); -+ -+#define LPC_DEV_DEBUG_VERBOSE(fmt, args...) do { \ -+ if (g_lpc_dev_debug) { \ -+ printk(KERN_INFO "[LPC_DEV][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define LPC_DEV_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_lpc_dev_error) { \ -+ printk(KERN_ERR "[LPC_DEV][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+typedef struct wb_lpc_dev_s { -+ const char *lpc_io_name; -+ uint32_t domain; -+ uint32_t bus; -+ uint32_t slot; -+ uint32_t fn; -+ uint32_t lpc_io_base; -+ uint32_t lpc_io_size; -+ uint32_t lpc_gen_dec; -+} wb_lpc_dev_t; -+ -+static int wb_lpc_probe(struct platform_device *pdev) -+{ -+ int ret, devfn; -+ wb_lpc_dev_t *wb_lpc_dev; -+ struct pci_dev *pci_dev; -+ lpc_drv_device_t *lpc_drv_device; -+ -+ wb_lpc_dev = devm_kzalloc(&pdev->dev, sizeof(wb_lpc_dev_t), GFP_KERNEL); -+ if (!wb_lpc_dev) { -+ dev_err(&pdev->dev, "devm_kzalloc failed.\n"); -+ ret = -ENOMEM; -+ return ret; -+ } -+ -+ if (pdev->dev.of_node) { -+ ret = 0; -+ ret += of_property_read_string(pdev->dev.of_node, "lpc_io_name", &wb_lpc_dev->lpc_io_name); -+ ret += of_property_read_u32(pdev->dev.of_node, "pci_domain", &wb_lpc_dev->domain); -+ ret += of_property_read_u32(pdev->dev.of_node, "pci_bus", &wb_lpc_dev->bus); -+ ret += of_property_read_u32(pdev->dev.of_node, "pci_slot", &wb_lpc_dev->slot); -+ ret += of_property_read_u32(pdev->dev.of_node, "pci_fn", &wb_lpc_dev->fn); -+ ret += of_property_read_u32(pdev->dev.of_node, "lpc_io_base", &wb_lpc_dev->lpc_io_base); -+ ret += of_property_read_u32(pdev->dev.of_node, "lpc_io_size", &wb_lpc_dev->lpc_io_size); -+ ret += of_property_read_u32(pdev->dev.of_node, "lpc_gen_dec", &wb_lpc_dev->lpc_gen_dec); -+ if (ret != 0) { -+ dev_err(&pdev->dev, "Failed to get dts config, ret:%d.\n", ret); -+ return -ENXIO; -+ } -+ } else { -+ if (pdev->dev.platform_data == NULL) { -+ dev_err(&pdev->dev, "Failed to get platform data config.\n"); -+ return -ENXIO; -+ } -+ lpc_drv_device = pdev->dev.platform_data; -+ wb_lpc_dev->lpc_io_name = lpc_drv_device->lpc_io_name; -+ wb_lpc_dev->domain = lpc_drv_device->pci_domain; -+ wb_lpc_dev->bus = lpc_drv_device->pci_bus; -+ wb_lpc_dev->slot = lpc_drv_device->pci_slot; -+ wb_lpc_dev->fn = lpc_drv_device->pci_fn; -+ wb_lpc_dev->lpc_io_base = lpc_drv_device->lpc_io_base; -+ wb_lpc_dev->lpc_io_size = lpc_drv_device->lpc_io_size; -+ wb_lpc_dev->lpc_gen_dec = lpc_drv_device->lpc_gen_dec; -+ } -+ -+ LPC_DEV_DEBUG_VERBOSE("domain:0x%04x, bus:0x%02x, slot:0x%02x, fn:%u\n", -+ wb_lpc_dev->domain,wb_lpc_dev->bus, wb_lpc_dev->slot, wb_lpc_dev->fn); -+ LPC_DEV_DEBUG_VERBOSE("lpc_io_name:%s, lpc_io_base:0x%x, lpc_io_size:%u, lpc_gen_dec:0x%x.\n", -+ wb_lpc_dev->lpc_io_name, wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size, wb_lpc_dev->lpc_gen_dec); -+ -+ devfn = PCI_DEVFN(wb_lpc_dev->slot, wb_lpc_dev->fn); -+ pci_dev = pci_get_domain_bus_and_slot(wb_lpc_dev->domain, wb_lpc_dev->bus, devfn); -+ if (pci_dev == NULL) { -+ dev_err(&pdev->dev, "Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", -+ wb_lpc_dev->domain, wb_lpc_dev->bus, devfn); -+ return -ENXIO; -+ } -+ -+ pci_write_config_dword(pci_dev, wb_lpc_dev->lpc_gen_dec, LPC_MAKE_PCI_IO_RANGE(wb_lpc_dev->lpc_io_base)); -+ if (!request_region(wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size, wb_lpc_dev->lpc_io_name)) { -+ dev_err(&pdev->dev, "Failed to request_region [0x%x][0x%x].\n", wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size); -+ return -EBUSY; -+ } -+ -+ platform_set_drvdata(pdev, wb_lpc_dev); -+ -+ dev_info(&pdev->dev, "lpc request_region [0x%x][0x%x] success.\n", wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size); -+ -+ return 0; -+} -+ -+static int wb_lpc_remove(struct platform_device *pdev) -+{ -+ wb_lpc_dev_t *wb_lpc_dev; -+ -+ wb_lpc_dev = platform_get_drvdata(pdev); -+ if (wb_lpc_dev) { -+ release_region(wb_lpc_dev->lpc_io_base , wb_lpc_dev->lpc_io_size); -+ LPC_DEV_DEBUG_VERBOSE("lpc base:0x%x, len:0x%x.\n", wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size); -+ } -+ LPC_DEV_DEBUG_VERBOSE("lpc remove.\n"); -+ -+ return 0; -+} -+ -+static struct of_device_id lpc_dev_match[] = { -+ { -+ .compatible = "wb-lpc", -+ }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, lpc_dev_match); -+ -+static struct platform_driver wb_lpc_driver = { -+ .probe = wb_lpc_probe, -+ .remove = wb_lpc_remove, -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = LPC_DRIVER_NAME, -+ .of_match_table = lpc_dev_match, -+ }, -+}; -+ -+static int __init wb_lpc_init(void) -+{ -+ return platform_driver_register(&wb_lpc_driver); -+} -+ -+static void __exit wb_lpc_exit(void) -+{ -+ platform_driver_unregister(&wb_lpc_driver); -+} -+ -+module_init(wb_lpc_init); -+module_exit(wb_lpc_exit); -+MODULE_DESCRIPTION("lpc driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.h -new file mode 100644 -index 000000000..76e8c32c1 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.h -@@ -0,0 +1,18 @@ -+#ifndef __WB_LPC_DRV_H__ -+#define __WB_LPC_DRV_H__ -+ -+#define LPC_IO_NAME_MAX_LEN (64) -+ -+typedef struct lpc_drv_device_s { -+ char lpc_io_name[LPC_IO_NAME_MAX_LEN]; -+ int pci_domain; -+ int pci_bus; -+ int pci_slot; -+ int pci_fn; -+ int lpc_io_base; -+ int lpc_io_size; -+ int lpc_gen_dec; -+ int device_flag; -+} lpc_drv_device_t; -+ -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mac_bsc.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mac_bsc.c -new file mode 100644 -index 000000000..d72e91ace ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mac_bsc.c -@@ -0,0 +1,845 @@ -+/* -+ * -+ * Copyright (c) 1998, 1999 Frodo Looijaard -+ * -+ * 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 -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+ -+#define MAC_TEMP_INVALID (99999999) -+#define MAC_ID_REG (0x02000000) -+ -+#define MAC_REG_ADDR_WIDTH (4) -+#define MAC_REG_DATA_WIDTH (4) -+#define MAC_BSC_MAX_TEMP_NUM (16) -+#define MAC_BSC_MAX_READ_REG_STEP (6) -+#define MAC_BSC_MAX_SETUP_NUM (1) -+ -+static int g_wb_mac_bsc_debug = 0; -+static int g_wb_mac_bsc_error = 0; -+ -+module_param(g_wb_mac_bsc_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_mac_bsc_error, int, S_IRUGO | S_IWUSR); -+ -+#define WB_MAC_BSC_DEBUG(fmt, args...) do { \ -+ if (g_wb_mac_bsc_debug) { \ -+ printk(KERN_INFO "[MAC_BSC][VER][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_MAC_BSC_ERROR(fmt, args...) do { \ -+ if (g_wb_mac_bsc_error) { \ -+ printk(KERN_ERR "[MAC_BSC][ERR][func:%s line:%d]"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+typedef enum{ -+ MAC_TYPE_START, -+ TD4_X9 = 0xb780, -+ TD4_X9_8 = 0xb788, -+ TH3 = 0xb980, -+ TD3 = 0xb870, -+ TD3_X2 = 0xb274, -+ TD4 = 0xb880, -+ TH4 = 0xb990, -+ MAC_TYPE_END, -+} mac_id; -+ -+typedef enum { -+ MAC_TEMP_START, -+ MAC_TEMP_INDEX1, -+ MAC_TEMP_INDEX2, -+ MAC_TEMP_INDEX3, -+ MAC_TEMP_INDEX4, -+ MAC_TEMP_INDEX5, -+ MAC_TEMP_INDEX6, -+ MAC_TEMP_INDEX7, -+ MAC_TEMP_INDEX8, -+ MAC_TEMP_INDEX9, -+ MAC_TEMP_INDEX10, -+ MAC_TEMP_INDEX11, -+ MAC_TEMP_INDEX12, -+ MAC_TEMP_INDEX13, -+ MAC_TEMP_INDEX14, -+ MAC_TEMP_INDEX15, -+ MAC_TEMP_END, -+} mac_hwmon_index; -+ -+typedef enum action_e { -+ I2C_WRITE, -+ I2C_READ -+} action_t; -+ -+typedef struct i2c_op_s { -+ action_t op; -+ uint32_t reg_addr; -+ uint32_t reg_val; -+ int read_back; -+} i2c_op_t; -+ -+typedef struct dev_params_s { -+ int mac_id; -+ i2c_op_t sbus_setup[MAC_BSC_MAX_SETUP_NUM]; -+ i2c_op_t vtmon_read[MAC_BSC_MAX_READ_REG_STEP]; -+ uint32_t vtmon_reg_addrs[MAC_BSC_MAX_TEMP_NUM]; -+ uint8_t vtmon_instances; -+ uint32_t vtmon_data_width; -+ int vtmon_scalar; -+ int vtmon_offset; -+ uint8_t sbus_setup_ops; -+ int vtmon_read_ops; -+ int sbus_addr_op; -+ int sbus_error_op; -+ uint32_t sbus_error_mask; -+} dev_params_t; -+ -+static dev_params_t mac_temp_conf[] = { -+ { -+ .mac_id = TD3_X2, -+ /* CMIC_TOP_SBUS_RING_MAP_0_7 = 0x52222100 */ -+ .sbus_setup = {{I2C_WRITE, 0x1010000c, 0x52222100, 0}}, -+ .vtmon_read = { -+ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000000 */ -+ {I2C_WRITE, 0x10110400, 0x00000000, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[0] = 0x2c380200 */ -+ {I2C_WRITE, 0x1011040c, 0x2c380200, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] = TOP_PVTMON_RESULT_0 */ -+ {I2C_WRITE, 0x10110410, 0x02005300, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000001 */ -+ {I2C_WRITE, 0x10110400, 0x00000001, 0}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_ERR */ -+ {I2C_READ, 0x10110408}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] */ -+ {I2C_READ, 0x10110410} -+ }, -+ .vtmon_reg_addrs = { -+ 0x02005300, 0x02005400, 0x02005500, 0x02005600, 0x02005700, 0x02005800 -+ }, -+ .vtmon_instances = 6, -+ .vtmon_data_width = 10, -+ .vtmon_scalar = -5570, -+ .vtmon_offset = 4578289, -+ .sbus_setup_ops = 1, -+ .vtmon_read_ops = 6, -+ .sbus_addr_op = 2, -+ .sbus_error_op = 4, -+ .sbus_error_mask = 0x00000041, -+ }, -+ { -+ .mac_id = TD3, /* TD3_X7*/ -+ /* CMIC_TOP_SBUS_RING_MAP_0_7 = 0x52222100 */ -+ .sbus_setup = {{I2C_WRITE, 0x0320000c, 0x52222100, 0}}, -+ .vtmon_read = { -+ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000000 */ -+ {I2C_WRITE, 0x03210400, 0x00000000, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[0] = 0x2c380200 */ -+ {I2C_WRITE, 0x0321040c, 0x2c380200, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] = TOP_PVTMON_RESULT_0 */ -+ {I2C_WRITE, 0x03210410, 0x02004700, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000001 */ -+ {I2C_WRITE, 0x03210400, 0x00000001, 0}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_ERR */ -+ {I2C_READ, 0x03210408}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] */ -+ {I2C_READ, 0x03210410} -+ }, -+ .vtmon_reg_addrs = { -+ 0x02004700, 0x02004800, 0x02004900, 0x02004a00, 0x02004b00, 0x02004c00, -+ 0x02004d00, 0x02004e00, 0x02005200, 0x02005100, 0x02005000, 0x02004f00 -+ }, -+ .vtmon_instances = 12, -+ .vtmon_data_width = 10, -+ .vtmon_scalar = -5350, -+ .vtmon_offset = 4341000, -+ .sbus_setup_ops = 0, -+ .vtmon_read_ops = 6, -+ .sbus_addr_op = 2, -+ .sbus_error_op = 4, -+ .sbus_error_mask = 0x00000041, -+ }, -+ { -+ .mac_id = TH3, -+ .vtmon_read = { -+ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000000 */ -+ {I2C_WRITE, 0x03210400, 0x00000000, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[0] = 0x2c400200 */ -+ {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] = TOP_PVTMON_RESULT_0 */ -+ {I2C_WRITE, 0x03210410, 0x02004a00, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000001 */ -+ {I2C_WRITE, 0x03210400, 0x00000001, 0}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_ERR */ -+ {I2C_READ, 0x03210408}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] */ -+ {I2C_READ, 0x03210410} -+ }, -+ .vtmon_reg_addrs = { -+ 0x02004a00, 0x02004b00, 0x02004c00, 0x02004d00, 0x02004e00, 0x02004f00, -+ 0x02005000, 0x02005100, 0x02005200, 0x02005300, 0x02005400, 0x02005500, -+ 0x02005600, 0x02005700, 0x02005800 -+ }, -+ .vtmon_instances = 15, -+ .vtmon_data_width = 10, -+ .vtmon_scalar = -5350, -+ .vtmon_offset = 4341000, -+ .sbus_setup_ops = 0, -+ .vtmon_read_ops = 6, -+ .sbus_addr_op = 2, -+ .sbus_error_op = -1, -+ }, -+ { -+ .mac_id = TD4_X9, -+ /* CMIC_TOP_SBUS_RING_MAP_8_15r = 0x00000000 */ -+ .sbus_setup = {{I2C_WRITE, 0x03200010, 0x00000000, 0}}, -+ .vtmon_read = { -+ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ -+ {I2C_WRITE, 0x03210400, 0x00000000, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ -+ {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ -+ {I2C_WRITE, 0x03210410, 0x02005a00, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ -+ {I2C_WRITE, 0x03210400, 0x00000001, 0}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ -+ {I2C_READ, 0x03210408}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ -+ {I2C_READ, 0x03210410} -+ }, -+ .vtmon_reg_addrs = { -+ 0x02005a00, 0x02005c00, 0x02005e00, 0x02006000, 0x02006200, 0x02006400, -+ 0x02006600, 0x02006800, 0x02006a00 -+ }, -+ .vtmon_instances = 9, -+ .vtmon_data_width = 11, -+ .vtmon_scalar = -2454, -+ .vtmon_offset = 3668120, -+ .sbus_setup_ops = 0, -+ .vtmon_read_ops = 6, -+ .sbus_addr_op = 2, -+ .sbus_error_op = 4, -+ .sbus_error_mask = 0x00000041, -+ }, -+ { -+ .mac_id = TD4_X9_8, -+ /* CMIC_TOP_SBUS_RING_MAP_8_15r = 0x00000000 */ -+ .sbus_setup = {{I2C_WRITE, 0x03200010, 0x00000000, 0}}, -+ .vtmon_read = { -+ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ -+ {I2C_WRITE, 0x03210400, 0x00000000, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ -+ {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ -+ {I2C_WRITE, 0x03210410, 0x02005a00, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ -+ {I2C_WRITE, 0x03210400, 0x00000001, 0}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ -+ {I2C_READ, 0x03210408}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ -+ {I2C_READ, 0x03210410} -+ }, -+ .vtmon_reg_addrs = { -+ 0x02005a00, 0x02005c00, 0x02005e00, 0x02006000, 0x02006200, 0x02006400, -+ 0x02006600, 0x02006800, 0x02006a00 -+ }, -+ .vtmon_instances = 9, -+ .vtmon_data_width = 11, -+ .vtmon_scalar = -2454, -+ .vtmon_offset = 3668120, -+ .sbus_setup_ops = 0, -+ .vtmon_read_ops = 6, -+ .sbus_addr_op = 2, -+ .sbus_error_op = 4, -+ .sbus_error_mask = 0x00000041, -+ }, -+ { -+ .mac_id = TD4, /* TD4-X11 */ -+ /* CMIC_TOP_SBUS_RING_MAP_8_15r = 0x00000000 */ -+ .sbus_setup = {{I2C_WRITE, 0x03200010, 0x00000000, 0}}, -+ .vtmon_read = { -+ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ -+ {I2C_WRITE, 0x03210400, 0x00000000, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ -+ {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ -+ {I2C_WRITE, 0x03210410, 0x02004900, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ -+ {I2C_WRITE, 0x03210400, 0x00000001, 0}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ -+ {I2C_READ, 0x03210408}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ -+ {I2C_READ, 0x03210410} -+ }, -+ .vtmon_reg_addrs = { -+ 0x02004900, 0x02004b00, 0x02004d00, 0x02004f00, 0x02005100, 0x02005300, -+ 0x02005500, 0x02005700, 0x02005900, 0x02005b00, 0x02005d00, 0x02005f00, -+ 0x02006100, 0x02006300, 0x02006500 -+ }, -+ .vtmon_instances = 15, -+ .vtmon_data_width = 11, -+ .vtmon_scalar = -2454, -+ .vtmon_offset = 3668120, -+ .sbus_setup_ops = 0, -+ .vtmon_read_ops = 6, -+ .sbus_addr_op = 2, -+ .sbus_error_op = 4, -+ .sbus_error_mask = 0x00000041, -+ }, -+ { -+ .mac_id = TH4, -+ .vtmon_read = { -+ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ -+ {I2C_WRITE, 0x03210400, 0x00000000, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ -+ {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ -+ {I2C_WRITE, 0x03210410, 0x0201d800, 1}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ -+ {I2C_WRITE, 0x03210400, 0x00000001, 0}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ -+ {I2C_READ, 0x03210408}, -+ /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ -+ {I2C_READ, 0x03210410} -+ }, -+ .vtmon_reg_addrs = { -+ 0x0201d800, 0x0201e000, 0x0201e800, 0x0201f000, 0x0201f800, 0x02020000, -+ 0x02020800, 0x02021000, 0x02021800, 0x02022000, 0x02022800, 0x02023000, -+ 0x02023800, 0x02024000, 0x02024800, -+ }, -+ .vtmon_instances = 15, -+ .vtmon_data_width = 11, -+ .vtmon_scalar = -2454, -+ .vtmon_offset = 3668120, -+ .sbus_setup_ops = 0, -+ .vtmon_read_ops = 6, -+ .sbus_addr_op = 2, -+ .sbus_error_op = -1, -+ }, -+}; -+ -+struct mac_data { -+ struct i2c_client *client; -+ struct device *hwmon_dev; -+ struct mutex update_lock; -+ dev_params_t dev_param; -+}; -+ -+static int bsc_i2c_read(struct i2c_client *client, uint32_t reg_addr, uint32_t *reg_val) -+{ -+ int msgs_num, ret, i; -+ uint8_t addr_buf[MAC_REG_ADDR_WIDTH]; -+ uint8_t data_buf[MAC_REG_DATA_WIDTH]; -+ uint32_t val; -+ struct i2c_msg msgs[2]; -+ -+ for (i = 0; i < MAC_REG_ADDR_WIDTH; i++) { -+ addr_buf[i] = (reg_addr >> ((MAC_REG_ADDR_WIDTH -i -1) * 8)) & 0xff; -+ } -+ -+ mem_clear(msgs, sizeof(msgs)); -+ msgs[0].addr = client->addr; -+ msgs[0].flags = 0; -+ msgs[0].len = MAC_REG_ADDR_WIDTH; -+ msgs[0].buf = addr_buf; -+ -+ msgs[1].addr = client->addr; -+ msgs[1].flags = I2C_M_RD; -+ msgs[1].len = MAC_REG_DATA_WIDTH; -+ msgs[1].buf = data_buf; -+ -+ msgs_num = 2; -+ ret = i2c_transfer(client->adapter, msgs, msgs_num); -+ if (ret != msgs_num) { -+ WB_MAC_BSC_ERROR("i2c_transfer read failed, reg_addr: 0x%x, ret: %d\n", reg_addr, ret); -+ return -EIO; -+ } -+ val = 0; -+ for (i = 0; i < MAC_REG_DATA_WIDTH; i++) { -+ val |= data_buf[i] << ((MAC_REG_DATA_WIDTH - i -1) * 8); -+ } -+ WB_MAC_BSC_DEBUG("bsc_i2c_read success, reg_addr: 0x%x, reg_val: 0x%x\n", reg_addr, val); -+ *reg_val = val; -+ return 0; -+} -+ -+static int bsc_i2c_write(struct i2c_client *client, uint32_t reg_addr, uint32_t reg_val) -+{ -+ int ret, i; -+ uint8_t write_buf[MAC_REG_ADDR_WIDTH + MAC_REG_DATA_WIDTH]; -+ struct i2c_msg msgs[1]; -+ -+ /* fill reg_addr first*/ -+ for (i = 0; i < MAC_REG_ADDR_WIDTH; i++) { -+ write_buf[i] = (reg_addr >> ((MAC_REG_ADDR_WIDTH -i -1) * 8)) & 0xff; -+ } -+ for (i = 0; i < MAC_REG_DATA_WIDTH; i++) { -+ write_buf[i + MAC_REG_ADDR_WIDTH] = (reg_val >> ((MAC_REG_DATA_WIDTH -i -1) * 8)) & 0xff; -+ } -+ -+ mem_clear(msgs, sizeof(msgs)); -+ msgs[0].len = MAC_REG_ADDR_WIDTH + MAC_REG_DATA_WIDTH; -+ msgs[0].buf = write_buf; -+ msgs[0].addr = client->addr; -+ msgs[0].flags = I2C_M_IGNORE_NAK; -+ -+ ret = i2c_transfer(client->adapter, msgs, 1); -+ if (ret < 0) { -+ WB_MAC_BSC_DEBUG("i2c_transfer write failed, reg_addr: 0x%x, reg_val: 0x%x, ret: %d\n", -+ reg_addr, reg_val, ret); -+ return ret; -+ } -+ WB_MAC_BSC_DEBUG("i2c_transfer write reg_addr: 0x%x, reg_val: 0x%x success\n", -+ reg_addr, reg_val); -+ return 0; -+} -+ -+static int handle_operation(struct i2c_client *client, i2c_op_t *operation) -+{ -+ int ret; -+ uint32_t rd_back_val; -+ -+ if (operation->op == I2C_WRITE) { -+ ret = bsc_i2c_write(client, operation->reg_addr, operation->reg_val); -+ WB_MAC_BSC_DEBUG("bsc_i2c_write reg_addr: 0x%x, set val: 0x%x, ret: %d\n", -+ operation->reg_addr, operation->reg_val, ret); -+ if (operation->read_back) { -+ ret = bsc_i2c_read(client, operation->reg_addr, &rd_back_val); -+ if (rd_back_val != operation->reg_val) { -+ WB_MAC_BSC_ERROR("bsc_i2c_write failed, reg_addr: 0x%x, set val: 0x%x, read back valu: 0x%x\n", -+ operation->reg_addr, operation->reg_val, rd_back_val); -+ return -1; -+ } -+ WB_MAC_BSC_DEBUG("bsc_i2c_write success, reg_addr: 0x%x, set val: 0x%x, read_back val: 0x%x\n", -+ operation->reg_addr, operation->reg_val, rd_back_val); -+ } -+ return 0; -+ } -+ -+ if (operation->op == I2C_READ) { -+ ret = bsc_i2c_read(client, operation->reg_addr, &operation->reg_val); -+ WB_MAC_BSC_DEBUG("bsc_i2c_read reg_addr: 0x%x, get val: 0x%x, ret: %d\n", -+ operation->reg_addr, operation->reg_val, ret); -+ return ret; -+ } -+ -+ WB_MAC_BSC_ERROR("Unsupport operation type: %d\n", operation->op); -+ return -EINVAL; -+} -+ -+static int get_mac_reg(struct i2c_client *client, uint32_t reg_addr, uint32_t *reg_value) -+{ -+ int i, ret; -+ i2c_op_t *op; -+ struct mac_data *data; -+ dev_params_t *dev_params; -+ uint32_t val_tmp; -+ -+ data = i2c_get_clientdata(client); -+ dev_params = &data->dev_param; -+ val_tmp = 0; -+ for (i = 0; i < dev_params->vtmon_read_ops; i++) { -+ op = &dev_params->vtmon_read[i]; -+ if (i == dev_params->sbus_addr_op) { -+ op->reg_val = reg_addr; -+ } -+ WB_MAC_BSC_DEBUG("Start to handle %s operation, step: %d, reg_addr: 0x%x, reg_value: 0x%x, read back flag: %d\n", -+ op->op == I2C_READ ? "I2C_READ" : "I2C_WRITE", i, op->reg_addr, op->reg_val, op->read_back); -+ ret = handle_operation(client, op); -+ if (ret < 0) { -+ WB_MAC_BSC_ERROR("handle operation %d failed, ret: %d\n", i, ret); -+ return ret; -+ } -+ if (op->op == I2C_READ) { -+ val_tmp = op->reg_val; -+ } -+ -+ if (i == dev_params->sbus_error_op) { -+ if (val_tmp & dev_params->sbus_error_mask) { -+ WB_MAC_BSC_ERROR("SBUS error seen, status value: 0x%x\n", op->reg_val); -+ return -EIO; -+ } -+ WB_MAC_BSC_DEBUG("Error status check ok, status: 0x%x, error_mask: 0x%x \n", -+ val_tmp, dev_params->sbus_error_mask); -+ } -+ } -+ -+ if (val_tmp == reg_addr) { -+ WB_MAC_BSC_ERROR("get mac register error, register value: 0x%x equal to reg_addr: 0x%x\n", -+ val_tmp, reg_addr); -+ return -EIO; -+ } -+ -+ *reg_value = val_tmp; -+ WB_MAC_BSC_DEBUG("get_mac_reg success, reg_addr: 0x%x, reg_value: 0x%x", reg_addr, *reg_value); -+ return 0; -+} -+ -+static int read_vtmon(struct i2c_client *client, uint8_t vtmon, int *temp) -+{ -+ struct mac_data *data; -+ dev_params_t *dev_params; -+ uint32_t reg_addr, reg_val; -+ uint32_t vtmon_val; -+ int ret; -+ -+ data = i2c_get_clientdata(client); -+ dev_params = &data->dev_param; -+ -+ if (vtmon >= dev_params->vtmon_instances) { -+ WB_MAC_BSC_ERROR("VTMON index [%d] greater or equal to VTMON instance number: %d\n", -+ vtmon, dev_params->vtmon_instances); -+ return -1; -+ } -+ reg_addr = dev_params->vtmon_reg_addrs[vtmon]; -+ ret = get_mac_reg(client, reg_addr, ®_val); -+ if (ret < 0) { -+ WB_MAC_BSC_ERROR("Read VTMON[%d] failed, reg_addr: 0x%x, ret: %d\n", -+ vtmon, reg_addr, ret); -+ return ret; -+ } -+ -+ vtmon_val = reg_val & ((1 << dev_params->vtmon_data_width) - 1); -+ *temp = ((dev_params->vtmon_scalar * vtmon_val) + dev_params->vtmon_offset) / 10; -+ -+ if ((*temp / 1000 < -40) || (*temp / 1000 > 120)) { -+ WB_MAC_BSC_ERROR("MAC temp invalid, vtmon: %d, temp: %d\n", vtmon, *temp); -+ return -EINVAL; -+ } -+ WB_MAC_BSC_DEBUG("Read mac temp success, index: %d, value: %d\n", vtmon + 1, *temp); -+ return 0; -+} -+ -+static ssize_t show_mac_temp(struct device *dev, struct device_attribute *da, char *buf) -+{ -+ struct mac_data *data = dev_get_drvdata(dev); -+ struct i2c_client *client = data->client; -+ u32 temp_index = to_sensor_dev_attr(da)->index; -+ int ret, temp; -+ -+ mutex_lock(&data->update_lock); -+ ret = read_vtmon(client, temp_index - 1, &temp); -+ if (ret < 0) { -+ temp = -MAC_TEMP_INVALID; -+ WB_MAC_BSC_ERROR("get_mactemp index: %d failed, ret = %d\n", temp_index, ret); -+ } -+ mutex_unlock(&data->update_lock); -+ return snprintf(buf, PAGE_SIZE, "%d\n", temp); -+} -+ -+static ssize_t show_mac_max_temp(struct device *dev, struct device_attribute *da, char *buf) -+{ -+ struct mac_data *data = dev_get_drvdata(dev); -+ struct i2c_client *client = data->client; -+ dev_params_t *dev_params; -+ int i, ret; -+ int tmp, temp; -+ -+ mutex_lock(&data->update_lock); -+ -+ dev_params = &data->dev_param; -+ temp = -MAC_TEMP_INVALID; -+ for (i = 0; i < dev_params->vtmon_instances ; i++) { -+ ret = read_vtmon(client, i, &tmp); -+ if (ret < 0) { -+ WB_MAC_BSC_ERROR("Get mactemp failed, temp index: %d, ret = %d\n", -+ i, ret); -+ tmp = -MAC_TEMP_INVALID; -+ } -+ -+ temp = (temp > tmp) ? temp : tmp; -+ } -+ -+ mutex_unlock(&data->update_lock); -+ return snprintf(buf, PAGE_SIZE, "%d\n", temp); -+} -+ -+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX1); -+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX2); -+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX3); -+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX4); -+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX5); -+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX6); -+static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX7); -+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX8); -+static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX9); -+static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX10); -+static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX11); -+static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX12); -+static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX13); -+static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX14); -+static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX15); -+static SENSOR_DEVICE_ATTR(temp99_input, S_IRUGO, show_mac_max_temp, NULL, 0); -+ -+static struct attribute *mac_hwmon_attrs[] = { -+ &sensor_dev_attr_temp1_input.dev_attr.attr, -+ &sensor_dev_attr_temp2_input.dev_attr.attr, -+ &sensor_dev_attr_temp3_input.dev_attr.attr, -+ &sensor_dev_attr_temp4_input.dev_attr.attr, -+ &sensor_dev_attr_temp5_input.dev_attr.attr, -+ &sensor_dev_attr_temp6_input.dev_attr.attr, -+ &sensor_dev_attr_temp7_input.dev_attr.attr, -+ &sensor_dev_attr_temp8_input.dev_attr.attr, -+ &sensor_dev_attr_temp9_input.dev_attr.attr, -+ &sensor_dev_attr_temp10_input.dev_attr.attr, -+ &sensor_dev_attr_temp11_input.dev_attr.attr, -+ &sensor_dev_attr_temp12_input.dev_attr.attr, -+ &sensor_dev_attr_temp13_input.dev_attr.attr, -+ &sensor_dev_attr_temp14_input.dev_attr.attr, -+ &sensor_dev_attr_temp15_input.dev_attr.attr, -+ &sensor_dev_attr_temp99_input.dev_attr.attr, -+ NULL -+}; -+ATTRIBUTE_GROUPS(mac_hwmon); -+ -+static void mac_bsc_setup(struct i2c_client *client) -+{ -+ int i, ret; -+ struct mac_data *data; -+ dev_params_t *dev_params; -+ uint32_t reg_value; -+ -+ data = i2c_get_clientdata(client); -+ dev_params = &data->dev_param; -+ -+ for (i = 0; i < dev_params->sbus_setup_ops; i++) { -+ ret = bsc_i2c_read(client, dev_params->sbus_setup[i].reg_addr, ®_value); -+ if ((ret < 0) || (reg_value != dev_params->sbus_setup[i].reg_val)) { -+ WB_MAC_BSC_DEBUG("bsc setup op%d, ret: %d, reg_addr: 0x%x, read value: 0x%x not equal to set value: 0x%x\n", -+ i, ret, dev_params->sbus_setup[i].reg_addr, reg_value, dev_params->sbus_setup[i].reg_val); -+ bsc_i2c_write(client, dev_params->sbus_setup[i].reg_addr, dev_params->sbus_setup[i].reg_val); -+ } else { -+ WB_MAC_BSC_DEBUG("bsc setup op%d, reg_addr: 0x%x, read value: 0x%x equal to set value: 0x%x\n", -+ i, dev_params->sbus_setup[i].reg_addr, reg_value, dev_params->sbus_setup[i].reg_val); -+ } -+ } -+ return; -+} -+ -+static int mac_bsc_init(struct i2c_client *client) -+{ -+ int ret, mac_id; -+ uint32_t reg_value; -+ -+ ret = get_mac_reg(client, MAC_ID_REG, ®_value); -+ if (ret < 0) { -+ WB_MAC_BSC_ERROR("Get MAC ID failed, reg_addr: 0x%x, ret = %d\n", -+ MAC_ID_REG, ret); -+ return ret; -+ } -+ -+ WB_MAC_BSC_DEBUG("Get MAC ID success, reg_addr: 0x%x, value: 0x%x \n", -+ MAC_ID_REG, reg_value); -+ mac_id = reg_value & 0xffff; -+ return mac_id; -+} -+ -+static int find_mac_config(int type, int *index) -+{ -+ int i, size; -+ -+ size = ARRAY_SIZE(mac_temp_conf); -+ for (i = 0; i < size; i++) { -+ if (mac_temp_conf[i].mac_id == type) { -+ *index = i; -+ return 0; -+ } -+ } -+ return -1; -+} -+ -+static int mac_bsc_config_check(dev_params_t *dev_params) -+{ -+ i2c_op_t *last_op; -+ i2c_op_t *err_op; -+ i2c_op_t *addr_op; -+ -+ /* vtmon_instances should not more than the MAC_BSC_MAX_TEMP_NUM */ -+ if ((dev_params->vtmon_instances > MAC_BSC_MAX_TEMP_NUM) || -+ (dev_params->vtmon_instances <= 0)) { -+ WB_MAC_BSC_ERROR("VTMON instance number %d more than the max number: %d\n", -+ dev_params->vtmon_instances, MAC_BSC_MAX_TEMP_NUM); -+ return -1; -+ } -+ -+ /* vtmon read operation steps should not more than the MAC_BSC_MAX_READ_REG_STEP */ -+ if ((dev_params->vtmon_read_ops > MAC_BSC_MAX_READ_REG_STEP) || -+ (dev_params->vtmon_read_ops <=0)) { -+ WB_MAC_BSC_ERROR("VTMON read ops number %d more than the max step: %d\n", -+ dev_params->vtmon_read_ops, MAC_BSC_MAX_READ_REG_STEP); -+ return -1; -+ } -+ -+ /* the last operation must be I2C_READ to get temperature register value */ -+ last_op = &dev_params->vtmon_read[dev_params->vtmon_read_ops - 1]; -+ if (last_op->op != I2C_READ) { -+ WB_MAC_BSC_ERROR("VTMON read ops config error, last operation not I2C_READ, last step: %d, op_code: %d\n", -+ dev_params->vtmon_read_ops - 1, last_op->op); -+ return -1; -+ } -+ -+ /* the address operation steps should not more than the vtmon_read_ops and not the last step */ -+ if ((dev_params->sbus_addr_op >= (dev_params->vtmon_read_ops - 1)) || -+ (dev_params->sbus_addr_op < 0)) { -+ WB_MAC_BSC_ERROR("VTMON addr op step invalid, index %d, read ops: %d\n", -+ dev_params->sbus_addr_op, dev_params->vtmon_read_ops); -+ return -1; -+ } -+ -+ /* the address operation must be I2C_WRITE to set temperature register address */ -+ addr_op = &dev_params->vtmon_read[dev_params->sbus_addr_op]; -+ if (addr_op->op != I2C_WRITE) { -+ WB_MAC_BSC_ERROR("VTMON addr op config error, addr operation not I2C_WRITE, addr op step: %d, op_code: %d\n", -+ dev_params->sbus_addr_op, addr_op->op); -+ return -1; -+ } -+ -+ /* the error status operation steps should not more than the vtmon_read_ops and not the last step */ -+ if (dev_params->sbus_error_op >= (dev_params->vtmon_read_ops - 1)) { -+ WB_MAC_BSC_ERROR("VTMON error op step invalid, index %d, read ops: %d\n", -+ dev_params->sbus_error_op, dev_params->vtmon_read_ops); -+ return -1; -+ } -+ -+ /* if error status operation exist, it must be I2C_READ to get error status register */ -+ if (dev_params->sbus_error_op >=0) { -+ err_op = &dev_params->vtmon_read[dev_params->sbus_error_op]; -+ if (err_op->op != I2C_READ) { -+ WB_MAC_BSC_ERROR("VTMON error op config error, error operation not I2C_READ, error op step: %d, op_code: %d\n", -+ dev_params->sbus_error_op, err_op->op); -+ return -1; -+ } -+ } -+ WB_MAC_BSC_DEBUG("dev_params check ok, instance number: %d, read_ops: %d, addr_op: %d, error_op: %d\n", -+ dev_params->vtmon_instances, dev_params->vtmon_read_ops, -+ dev_params->sbus_addr_op, dev_params->sbus_error_op); -+ return 0; -+} -+ -+static int mac_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct mac_data *data; -+ int ret, mac_id, index; -+ -+ WB_MAC_BSC_DEBUG("=========mac_probe(%d-%04x)===========\n", -+ client->adapter->nr, client->addr); -+ -+ if (!client->adapter->algo->master_xfer) { -+ dev_err(&client->adapter->dev, "I2C level transfers not supported\n"); -+ return -EOPNOTSUPP; -+ } -+ -+ data = devm_kzalloc(&client->dev, sizeof(struct mac_data), GFP_KERNEL); -+ if (!data) { -+ dev_err(&client->dev, "Failed to devm_kzalloc.\n"); -+ return -ENOMEM; -+ } -+ -+ data->client = client; -+ i2c_set_clientdata(client, data); -+ -+ mac_id = id->driver_data; -+ ret = find_mac_config(mac_id, &index); -+ if (ret < 0) { -+ dev_err(&client->dev, "Failed to find mac config, mac id from driver_data: 0x%x\n", mac_id); -+ return -EINVAL; -+ } -+ data->dev_param = mac_temp_conf[index]; -+ ret = mac_bsc_config_check(&data->dev_param); -+ if (ret < 0) { -+ dev_err(&client->dev, "Invalid config parameter, mac id: 0x%x, config index: %d\n", -+ mac_id, index); -+ return -EINVAL; -+ } -+ -+ mac_bsc_setup(client); -+ -+ if (mac_id == TD4) { -+ ret = mac_bsc_init(client); -+ if (ret < 0) { -+ dev_err(&client->dev, "Failed to get mac id, ret: %d\n", ret); -+ return -EIO; -+ } -+ mac_id = ret; -+ ret = find_mac_config(mac_id, &index); -+ if (ret < 0) { -+ dev_err(&client->dev, "Failed to find mac config, mac id from chip: 0x%x\n", mac_id); -+ return -EINVAL; -+ } -+ data->dev_param = mac_temp_conf[index]; -+ ret = mac_bsc_config_check(&data->dev_param); -+ if (ret < 0) { -+ dev_err(&client->dev, "Invalid config parameter, mac id: 0x%x, config index: %d\n", -+ mac_id, index); -+ return -EINVAL; -+ } -+ } -+ -+ WB_MAC_BSC_DEBUG("mac_id: 0x%x, config index: %d\n", mac_id, index); -+ -+ mutex_init(&data->update_lock); -+ data->hwmon_dev = hwmon_device_register_with_groups(&client->dev, client->name, data, mac_hwmon_groups); -+ if (IS_ERR(data->hwmon_dev)) { -+ dev_err(&client->dev, "Failed to register mac bsc hwmon\n"); -+ return PTR_ERR(data->hwmon_dev); -+ } -+ -+ dev_info(&client->dev, "Register mac bsc %x with %d vtmon instance number success\n", -+ mac_id, data->dev_param.vtmon_instances); -+ return 0; -+} -+ -+static int mac_remove(struct i2c_client *client) -+{ -+ struct mac_data *data = i2c_get_clientdata(client); -+ -+ hwmon_device_unregister(data->hwmon_dev); -+ return 0; -+} -+ -+static const struct i2c_device_id mac_id_table[] = { -+ { "wb_mac_bsc_td3", TD3 }, -+ { "wb_mac_bsc_td3_x2", TD3_X2 }, -+ { "wb_mac_bsc_td4", TD4 }, -+ { "wb_mac_bsc_th3", TH3 }, -+ { "wb_mac_bsc_th4", TH4 }, -+ {} -+}; -+MODULE_DEVICE_TABLE(i2c, mac_id_table); -+ -+static struct i2c_driver wb_mac_bsc_driver = { -+ .driver = { -+ .name = "wb_mac_bsc", -+ }, -+ .probe = mac_probe, -+ .remove = mac_remove, -+ .id_table = mac_id_table, -+}; -+ -+module_i2c_driver(wb_mac_bsc_driver); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("mac bsc driver"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_optoe.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_optoe.c -new file mode 100644 -index 000000000..c09162368 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_optoe.c -@@ -0,0 +1,1192 @@ -+/* -+ * optoe.c - A driver to read and write the EEPROM on optical transceivers -+ * (SFP, QSFP and similar I2C based devices) -+ * -+ * Copyright (C) 2014 Cumulus networks Inc. -+ * Copyright (C) 2017 Finisar Corp. -+ * -+ * 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 Freeoftware Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+/* -+ * Description: -+ * a) Optical transceiver EEPROM read/write transactions are just like -+ * the at24 eeproms managed by the at24.c i2c driver -+ * b) The register/memory layout is up to 256 128 byte pages defined by -+ * a "pages valid" register and switched via a "page select" -+ * register as explained in below diagram. -+ * c) 256 bytes are mapped at a time. 'Lower page 00h' is the first 128 -+ * bytes of address space, and always references the same -+ * location, independent of the page select register. -+ * All mapped pages are mapped into the upper 128 bytes -+ * (offset 128-255) of the i2c address. -+ * d) Devices with one I2C address (eg QSFP) use I2C address 0x50 -+ * (A0h in the spec), and map all pages in the upper 128 bytes -+ * of that address. -+ * e) Devices with two I2C addresses (eg SFP) have 256 bytes of data -+ * at I2C address 0x50, and 256 bytes of data at I2C address -+ * 0x51 (A2h in the spec). Page selection and paged access -+ * only apply to this second I2C address (0x51). -+ * e) The address space is presented, by the driver, as a linear -+ * address space. For devices with one I2C client at address -+ * 0x50 (eg QSFP), offset 0-127 are in the lower -+ * half of address 50/A0h/client[0]. Offset 128-255 are in -+ * page 0, 256-383 are page 1, etc. More generally, offset -+ * 'n' resides in page (n/128)-1. ('page -1' is the lower -+ * half, offset 0-127). -+ * f) For devices with two I2C clients at address 0x50 and 0x51 (eg SFP), -+ * the address space places offset 0-127 in the lower -+ * half of 50/A0/client[0], offset 128-255 in the upper -+ * half. Offset 256-383 is in the lower half of 51/A2/client[1]. -+ * Offset 384-511 is in page 0, in the upper half of 51/A2/... -+ * Offset 512-639 is in page 1, in the upper half of 51/A2/... -+ * Offset 'n' is in page (n/128)-3 (for n > 383) -+ * -+ * One I2c addressed (eg QSFP) Memory Map -+ * -+ * 2-Wire Serial Address: 1010000x -+ * -+ * Lower Page 00h (128 bytes) -+ * ===================== -+ * | | -+ * | | -+ * | | -+ * | | -+ * | | -+ * | | -+ * | | -+ * | | -+ * | | -+ * | | -+ * |Page Select Byte(127)| -+ * ===================== -+ * | -+ * | -+ * | -+ * | -+ * V -+ * ------------------------------------------------------------ -+ * | | | | -+ * | | | | -+ * | | | | -+ * | | | | -+ * | | | | -+ * | | | | -+ * | | | | -+ * | | | | -+ * | | | | -+ * V V V V -+ * ------------ -------------- --------------- -------------- -+ * | | | | | | | | -+ * | Upper | | Upper | | Upper | | Upper | -+ * | Page 00h | | Page 01h | | Page 02h | | Page 03h | -+ * | | | (Optional) | | (Optional) | | (Optional | -+ * | | | | | | | for Cable | -+ * | | | | | | | Assemblies) | -+ * | ID | | AST | | User | | | -+ * | Fields | | Table | | EEPROM Data | | | -+ * | | | | | | | | -+ * | | | | | | | | -+ * | | | | | | | | -+ * ------------ -------------- --------------- -------------- -+ * -+ * The SFF 8436 (QSFP) spec only defines the 4 pages described above. -+ * In anticipation of future applications and devices, this driver -+ * supports access to the full architected range, 256 pages. -+ * -+ * The CMIS (Common Management Interface Specification) defines use of -+ * considerably more pages (at least to page 0xAF), which this driver -+ * supports. -+ * -+ * NOTE: This version of the driver ONLY SUPPORTS BANK 0 PAGES on CMIS -+ * devices. -+ * -+ **/ -+ -+/* #define DEBUG 1 */ -+ -+#undef EEPROM_CLASS -+#ifdef CONFIG_EEPROM_CLASS -+#define EEPROM_CLASS -+#endif -+#ifdef CONFIG_EEPROM_CLASS_MODULE -+#define EEPROM_CLASS -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+#ifdef EEPROM_CLASS -+#include -+#endif -+ -+#include -+ -+/* The maximum length of a port name */ -+#define MAX_PORT_NAME_LEN 20 -+ -+struct optoe_platform_data { -+ u32 byte_len; /* size (sum of all addr) */ -+ u16 page_size; /* for writes */ -+ u8 flags; -+ void *dummy1; /* backward compatibility */ -+ void *dummy2; /* backward compatibility */ -+ -+#ifdef EEPROM_CLASS -+ struct eeprom_platform_data *eeprom_data; -+#endif -+ char port_name[MAX_PORT_NAME_LEN]; -+}; -+ -+/* fundamental unit of addressing for EEPROM */ -+#define OPTOE_PAGE_SIZE 128 -+/* -+ * Single address devices (eg QSFP) have 256 pages, plus the unpaged -+ * low 128 bytes. If the device does not support paging, it is -+ * only 2 'pages' long. -+ */ -+#define OPTOE_ARCH_PAGES 256 -+#define ONE_ADDR_EEPROM_SIZE ((1 + OPTOE_ARCH_PAGES) * OPTOE_PAGE_SIZE) -+#define ONE_ADDR_EEPROM_UNPAGED_SIZE (2 * OPTOE_PAGE_SIZE) -+/* -+ * Dual address devices (eg SFP) have 256 pages, plus the unpaged -+ * low 128 bytes, plus 256 bytes at 0x50. If the device does not -+ * support paging, it is 4 'pages' long. -+ */ -+#define TWO_ADDR_EEPROM_SIZE ((3 + OPTOE_ARCH_PAGES) * OPTOE_PAGE_SIZE) -+#define TWO_ADDR_EEPROM_UNPAGED_SIZE (4 * OPTOE_PAGE_SIZE) -+#define TWO_ADDR_NO_0X51_SIZE (2 * OPTOE_PAGE_SIZE) -+ -+/* a few constants to find our way around the EEPROM */ -+#define OPTOE_PAGE_SELECT_REG 0x7F -+#define ONE_ADDR_PAGEABLE_REG 0x02 -+#define QSFP_NOT_PAGEABLE (1<<2) -+#define CMIS_NOT_PAGEABLE (1<<7) -+#define TWO_ADDR_PAGEABLE_REG 0x40 -+#define TWO_ADDR_PAGEABLE (1<<4) -+#define TWO_ADDR_0X51_REG 92 -+#define TWO_ADDR_0X51_SUPP (1<<6) -+#define OPTOE_ID_REG 0 -+#define OPTOE_READ_OP 0 -+#define OPTOE_WRITE_OP 1 -+#define OPTOE_EOF 0 /* used for access beyond end of device */ -+ -+struct optoe_data { -+ struct optoe_platform_data chip; -+ int use_smbus; -+ char port_name[MAX_PORT_NAME_LEN]; -+ -+ /* -+ * Lock protects against activities from other Linux tasks, -+ * but not from changes by other I2C masters. -+ */ -+ struct mutex lock; -+ struct bin_attribute bin; -+ struct attribute_group attr_group; -+ -+ u8 *writebuf; -+ unsigned int write_max; -+ -+ unsigned int num_addresses; -+ -+#ifdef EEPROM_CLASS -+ struct eeprom_device *eeprom_dev; -+#endif -+ -+ /* dev_class: ONE_ADDR (QSFP) or TWO_ADDR (SFP) */ -+ int dev_class; -+ -+ struct i2c_client *client[]; -+}; -+ -+/* -+ * This parameter is to help this driver avoid blocking other drivers out -+ * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C -+ * clock, one 256 byte read takes about 1/43 second which is excessive; -+ * but the 1/170 second it takes at 400 kHz may be quite reasonable; and -+ * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible. -+ * -+ * This value is forced to be a power of two so that writes align on pages. -+ */ -+static unsigned int io_limit = OPTOE_PAGE_SIZE; -+ -+/* -+ * specs often allow 5 msec for a page write, sometimes 20 msec; -+ * it's important to recover from write timeouts. -+ */ -+static unsigned int write_timeout = 50; -+ -+/* -+ * flags to distinguish one-address (QSFP family) from two-address (SFP family) -+ * If the family is not known, figure it out when the device is accessed -+ */ -+#define ONE_ADDR 1 -+#define TWO_ADDR 2 -+#define CMIS_ADDR 3 -+ -+static const struct i2c_device_id optoe_ids[] = { -+ { "wb_optoe1", ONE_ADDR }, -+ { "wb_optoe2", TWO_ADDR }, -+ { "wb_optoe3", CMIS_ADDR }, -+ { "wb_sff8436", ONE_ADDR }, -+ { "wb_24c04", TWO_ADDR }, -+ { /* END OF LIST */ } -+}; -+MODULE_DEVICE_TABLE(i2c, optoe_ids); -+ -+/*-------------------------------------------------------------------------*/ -+/* -+ * This routine computes the addressing information to be used for -+ * a given r/w request. -+ * -+ * Task is to calculate the client (0 = i2c addr 50, 1 = i2c addr 51), -+ * the page, and the offset. -+ * -+ * Handles both single address (eg QSFP) and two address (eg SFP). -+ * For SFP, offset 0-255 are on client[0], >255 is on client[1] -+ * Offset 256-383 are on the lower half of client[1] -+ * Pages are accessible on the upper half of client[1]. -+ * Offset >383 are in 128 byte pages mapped into the upper half -+ * -+ * For QSFP, all offsets are on client[0] -+ * offset 0-127 are on the lower half of client[0] (no paging) -+ * Pages are accessible on the upper half of client[1]. -+ * Offset >127 are in 128 byte pages mapped into the upper half -+ * -+ * Callers must not read/write beyond the end of a client or a page -+ * without recomputing the client/page. Hence offset (within page) -+ * plus length must be less than or equal to 128. (Note that this -+ * routine does not have access to the length of the call, hence -+ * cannot do the validity check.) -+ * -+ * Offset within Lower Page 00h and Upper Page 00h are not recomputed -+ */ -+ -+static uint8_t optoe_translate_offset(struct optoe_data *optoe, -+ loff_t *offset, struct i2c_client **client) -+{ -+ unsigned int page = 0; -+ -+ *client = optoe->client[0]; -+ -+ /* if SFP style, offset > 255, shift to i2c addr 0x51 */ -+ if (optoe->dev_class == TWO_ADDR) { -+ if (*offset > 255) { -+ /* like QSFP, but shifted to client[1] */ -+ *client = optoe->client[1]; -+ *offset -= 256; -+ } -+ } -+ -+ /* -+ * if offset is in the range 0-128... -+ * page doesn't matter (using lower half), return 0. -+ * offset is already correct (don't add 128 to get to paged area) -+ */ -+ if (*offset < OPTOE_PAGE_SIZE) -+ return page; -+ -+ /* note, page will always be positive since *offset >= 128 */ -+ page = (*offset >> 7)-1; -+ /* 0x80 places the offset in the top half, offset is last 7 bits */ -+ *offset = OPTOE_PAGE_SIZE + (*offset & 0x7f); -+ -+ return page; /* note also returning client and offset */ -+} -+ -+static ssize_t optoe_eeprom_read(struct optoe_data *optoe, -+ struct i2c_client *client, -+ char *buf, unsigned int offset, size_t count) -+{ -+ struct i2c_msg msg[2]; -+ u8 msgbuf[2]; -+ unsigned long timeout, read_time; -+ int status, i; -+ -+ mem_clear(msg, sizeof(msg)); -+ -+ switch (optoe->use_smbus) { -+ case I2C_SMBUS_I2C_BLOCK_DATA: -+ /*smaller eeproms can work given some SMBus extension calls */ -+ if (count > I2C_SMBUS_BLOCK_MAX) -+ count = I2C_SMBUS_BLOCK_MAX; -+ break; -+ case I2C_SMBUS_WORD_DATA: -+ /* Check for odd length transaction */ -+ count = (count == 1) ? 1 : 2; -+ break; -+ case I2C_SMBUS_BYTE_DATA: -+ count = 1; -+ break; -+ default: -+ /* -+ * When we have a better choice than SMBus calls, use a -+ * combined I2C message. Write address; then read up to -+ * io_limit data bytes. msgbuf is u8 and will cast to our -+ * needs. -+ */ -+ i = 0; -+ msgbuf[i++] = offset; -+ -+ msg[0].addr = client->addr; -+ msg[0].buf = msgbuf; -+ msg[0].len = i; -+ -+ msg[1].addr = client->addr; -+ msg[1].flags = I2C_M_RD; -+ msg[1].buf = buf; -+ msg[1].len = count; -+ } -+ -+ /* -+ * Reads fail if the previous write didn't complete yet. We may -+ * loop a few times until this one succeeds, waiting at least -+ * long enough for one entire page write to work. -+ */ -+ timeout = jiffies + msecs_to_jiffies(write_timeout); -+ do { -+ read_time = jiffies; -+ -+ switch (optoe->use_smbus) { -+ case I2C_SMBUS_I2C_BLOCK_DATA: -+ status = i2c_smbus_read_i2c_block_data(client, offset, -+ count, buf); -+ break; -+ case I2C_SMBUS_WORD_DATA: -+ status = i2c_smbus_read_word_data(client, offset); -+ if (status >= 0) { -+ buf[0] = status & 0xff; -+ if (count == 2) -+ buf[1] = status >> 8; -+ status = count; -+ } -+ break; -+ case I2C_SMBUS_BYTE_DATA: -+ status = i2c_smbus_read_byte_data(client, offset); -+ if (status >= 0) { -+ buf[0] = status; -+ status = count; -+ } -+ break; -+ default: -+ status = i2c_transfer(client->adapter, msg, 2); -+ if (status == 2) -+ status = count; -+ } -+ -+ dev_dbg(&client->dev, "eeprom read %zu@%d --> %d (%ld)\n", -+ count, offset, status, jiffies); -+ -+ if (status == count) /* happy path */ -+ return count; -+ -+ /* REVISIT: at HZ=100, this is sloooow */ -+ usleep_range(1000, 2000); -+ } while (time_before(read_time, timeout)); -+ -+ return -ETIMEDOUT; -+} -+ -+static ssize_t optoe_eeprom_write(struct optoe_data *optoe, -+ struct i2c_client *client, -+ const char *buf, -+ unsigned int offset, size_t count) -+{ -+ struct i2c_msg msg; -+ ssize_t status; -+ unsigned long timeout, write_time; -+ unsigned int next_page_start; -+ int i = 0; -+ -+ /* write max is at most a page -+ * (In this driver, write_max is actually one byte!) -+ */ -+ if (count > optoe->write_max) -+ count = optoe->write_max; -+ -+ /* shorten count if necessary to avoid crossing page boundary */ -+ next_page_start = roundup(offset + 1, OPTOE_PAGE_SIZE); -+ if (offset + count > next_page_start) -+ count = next_page_start - offset; -+ -+ switch (optoe->use_smbus) { -+ case I2C_SMBUS_I2C_BLOCK_DATA: -+ /*smaller eeproms can work given some SMBus extension calls */ -+ if (count > I2C_SMBUS_BLOCK_MAX) -+ count = I2C_SMBUS_BLOCK_MAX; -+ break; -+ case I2C_SMBUS_WORD_DATA: -+ /* Check for odd length transaction */ -+ count = (count == 1) ? 1 : 2; -+ break; -+ case I2C_SMBUS_BYTE_DATA: -+ count = 1; -+ break; -+ default: -+ /* If we'll use I2C calls for I/O, set up the message */ -+ msg.addr = client->addr; -+ msg.flags = 0; -+ -+ /* msg.buf is u8 and casts will mask the values */ -+ msg.buf = optoe->writebuf; -+ -+ msg.buf[i++] = offset; -+ memcpy(&msg.buf[i], buf, count); -+ msg.len = i + count; -+ break; -+ } -+ -+ /* -+ * Reads fail if the previous write didn't complete yet. We may -+ * loop a few times until this one succeeds, waiting at least -+ * long enough for one entire page write to work. -+ */ -+ timeout = jiffies + msecs_to_jiffies(write_timeout); -+ do { -+ write_time = jiffies; -+ -+ switch (optoe->use_smbus) { -+ case I2C_SMBUS_I2C_BLOCK_DATA: -+ status = i2c_smbus_write_i2c_block_data(client, -+ offset, count, buf); -+ if (status == 0) -+ status = count; -+ break; -+ case I2C_SMBUS_WORD_DATA: -+ if (count == 2) { -+ status = i2c_smbus_write_word_data(client, -+ offset, (u16)((buf[0])|(buf[1] << 8))); -+ } else { -+ /* count = 1 */ -+ status = i2c_smbus_write_byte_data(client, -+ offset, buf[0]); -+ } -+ if (status == 0) -+ status = count; -+ break; -+ case I2C_SMBUS_BYTE_DATA: -+ status = i2c_smbus_write_byte_data(client, offset, -+ buf[0]); -+ if (status == 0) -+ status = count; -+ break; -+ default: -+ status = i2c_transfer(client->adapter, &msg, 1); -+ if (status == 1) -+ status = count; -+ break; -+ } -+ -+ dev_dbg(&client->dev, "eeprom write %zu@%d --> %ld (%lu)\n", -+ count, offset, (long int) status, jiffies); -+ -+ if (status == count) -+ return count; -+ -+ /* REVISIT: at HZ=100, this is sloooow */ -+ usleep_range(1000, 2000); -+ } while (time_before(write_time, timeout)); -+ -+ return -ETIMEDOUT; -+} -+ -+static ssize_t optoe_eeprom_update_client(struct optoe_data *optoe, -+ char *buf, loff_t off, -+ size_t count, int opcode) -+{ -+ struct i2c_client *client; -+ ssize_t retval = 0; -+ uint8_t page = 0; -+ uint8_t loc; -+ loff_t phy_offset = off; -+ int ret = 0; -+ -+ page = optoe_translate_offset(optoe, &phy_offset, &client); -+ dev_dbg(&client->dev, -+ "%s off %lld page:%d phy_offset:%lld, count:%ld, opcode:%d\n", -+ __func__, off, page, phy_offset, (long int) count, opcode); -+ -+ ret = optoe_eeprom_read(optoe, client, &loc, OPTOE_PAGE_SELECT_REG, 1); -+ if (ret < 0) { -+ dev_dbg(&client->dev, "Read page register for get now location page failed. ret:%d\n", ret); -+ return ret; -+ } -+ -+ /* Only when read and now location page is inconsistent, will doing switch page */ -+ if (loc != page) { -+ ret = optoe_eeprom_write(optoe, client, &page, -+ OPTOE_PAGE_SELECT_REG, 1); -+ if (ret < 0) { -+ dev_dbg(&client->dev, -+ "Write page register for page %d failed ret:%d!\n", -+ page, ret); -+ return ret; -+ } -+ } -+ -+ while (count) { -+ ssize_t status; -+ -+ if (opcode == OPTOE_READ_OP) { -+ status = optoe_eeprom_read(optoe, client, -+ buf, phy_offset, count); -+ } else { -+ status = optoe_eeprom_write(optoe, client, -+ buf, phy_offset, count); -+ } -+ if (status <= 0) { -+ if (retval == 0) -+ retval = status; -+ break; -+ } -+ buf += status; -+ phy_offset += status; -+ count -= status; -+ retval += status; -+ } -+ -+ return retval; -+} -+ -+/* -+ * Figure out if this access is within the range of supported pages. -+ * Note this is called on every access because we don't know if the -+ * module has been replaced since the last call. -+ * If/when modules support more pages, this is the routine to update -+ * to validate and allow access to additional pages. -+ * -+ * Returns updated len for this access: -+ * - entire access is legal, original len is returned. -+ * - access begins legal but is too long, len is truncated to fit. -+ * - initial offset exceeds supported pages, return OPTOE_EOF (zero) -+ */ -+static ssize_t optoe_page_legal(struct optoe_data *optoe, -+ loff_t off, size_t len) -+{ -+ struct i2c_client *client = optoe->client[0]; -+ u8 regval; -+ int not_pageable; -+ int status; -+ size_t maxlen; -+ -+ if (off < 0) -+ return -EINVAL; -+ if (optoe->dev_class == TWO_ADDR) { -+ /* SFP case */ -+ /* if only using addr 0x50 (first 256 bytes) we're good */ -+ if ((off + len) <= TWO_ADDR_NO_0X51_SIZE) -+ return len; -+ /* if offset exceeds possible pages, we're not good */ -+ if (off >= TWO_ADDR_EEPROM_SIZE) -+ return OPTOE_EOF; -+ /* in between, are pages supported? */ -+ status = optoe_eeprom_read(optoe, client, ®val, -+ TWO_ADDR_PAGEABLE_REG, 1); -+ if (status < 0) -+ return status; /* error out (no module?) */ -+ if (regval & TWO_ADDR_PAGEABLE) { -+ /* Pages supported, trim len to the end of pages */ -+ maxlen = TWO_ADDR_EEPROM_SIZE - off; -+ } else { -+ /* pages not supported, trim len to unpaged size */ -+ if (off >= TWO_ADDR_EEPROM_UNPAGED_SIZE) -+ return OPTOE_EOF; -+ -+ /* will be accessing addr 0x51, is that supported? */ -+ /* byte 92, bit 6 implies DDM support, 0x51 support */ -+ status = optoe_eeprom_read(optoe, client, ®val, -+ TWO_ADDR_0X51_REG, 1); -+ if (status < 0) -+ return status; -+ if (regval & TWO_ADDR_0X51_SUPP) { -+ /* addr 0x51 is OK */ -+ maxlen = TWO_ADDR_EEPROM_UNPAGED_SIZE - off; -+ } else { -+ /* addr 0x51 NOT supported, trim to 256 max */ -+ if (off >= TWO_ADDR_NO_0X51_SIZE) -+ return OPTOE_EOF; -+ maxlen = TWO_ADDR_NO_0X51_SIZE - off; -+ } -+ } -+ len = (len > maxlen) ? maxlen : len; -+ dev_dbg(&client->dev, -+ "page_legal, SFP, off %lld len %ld\n", -+ off, (long int) len); -+ } else { -+ /* QSFP case, CMIS case */ -+ /* if no pages needed, we're good */ -+ if ((off + len) <= ONE_ADDR_EEPROM_UNPAGED_SIZE) -+ return len; -+ /* if offset exceeds possible pages, we're not good */ -+ if (off >= ONE_ADDR_EEPROM_SIZE) -+ return OPTOE_EOF; -+ /* in between, are pages supported? */ -+ status = optoe_eeprom_read(optoe, client, ®val, -+ ONE_ADDR_PAGEABLE_REG, 1); -+ if (status < 0) -+ return status; /* error out (no module?) */ -+ -+ if (optoe->dev_class == ONE_ADDR) { -+ not_pageable = QSFP_NOT_PAGEABLE; -+ } else { -+ not_pageable = CMIS_NOT_PAGEABLE; -+ } -+ dev_dbg(&client->dev, -+ "Paging Register: 0x%x; not_pageable mask: 0x%x\n", -+ regval, not_pageable); -+ -+ if (regval & not_pageable) { -+ /* pages not supported, trim len to unpaged size */ -+ if (off >= ONE_ADDR_EEPROM_UNPAGED_SIZE) -+ return OPTOE_EOF; -+ maxlen = ONE_ADDR_EEPROM_UNPAGED_SIZE - off; -+ } else { -+ /* Pages supported, trim len to the end of pages */ -+ maxlen = ONE_ADDR_EEPROM_SIZE - off; -+ } -+ len = (len > maxlen) ? maxlen : len; -+ dev_dbg(&client->dev, -+ "page_legal, QSFP, off %lld len %ld\n", -+ off, (long int) len); -+ } -+ return len; -+} -+ -+static ssize_t optoe_read_write(struct optoe_data *optoe, -+ char *buf, loff_t off, size_t len, int opcode) -+{ -+ struct i2c_client *client = optoe->client[0]; -+ int chunk; -+ int status = 0; -+ ssize_t retval; -+ size_t pending_len = 0, chunk_len = 0; -+ loff_t chunk_offset = 0, chunk_start_offset = 0; -+ loff_t chunk_end_offset = 0; -+ -+ dev_dbg(&client->dev, -+ "%s: off %lld len:%ld, opcode:%s\n", -+ __func__, off, (long int) len, -+ (opcode == OPTOE_READ_OP) ? "r" : "w"); -+ if (unlikely(!len)) -+ return len; -+ -+ /* -+ * Read data from chip, protecting against concurrent updates -+ * from this host, but not from other I2C masters. -+ */ -+ mutex_lock(&optoe->lock); -+ -+ /* -+ * Confirm this access fits within the device suppored addr range -+ */ -+ status = optoe_page_legal(optoe, off, len); -+ if ((status == OPTOE_EOF) || (status < 0)) { -+ mutex_unlock(&optoe->lock); -+ return status; -+ } -+ len = status; -+ -+ /* -+ * For each (128 byte) chunk involved in this request, issue a -+ * separate call to sff_eeprom_update_client(), to -+ * ensure that each access recalculates the client/page -+ * and writes the page register as needed. -+ * Note that chunk to page mapping is confusing, is different for -+ * QSFP and SFP, and never needs to be done. Don't try! -+ */ -+ pending_len = len; /* amount remaining to transfer */ -+ retval = 0; /* amount transferred */ -+ for (chunk = off >> 7; chunk <= (off + len - 1) >> 7; chunk++) { -+ -+ /* -+ * Compute the offset and number of bytes to be read/write -+ * -+ * 1. start at an offset not equal to 0 (within the chunk) -+ * and read/write less than the rest of the chunk -+ * 2. start at an offset not equal to 0 and read/write the rest -+ * of the chunk -+ * 3. start at offset 0 (within the chunk) and read/write less -+ * than entire chunk -+ * 4. start at offset 0 (within the chunk), and read/write -+ * the entire chunk -+ */ -+ chunk_start_offset = chunk * OPTOE_PAGE_SIZE; -+ chunk_end_offset = chunk_start_offset + OPTOE_PAGE_SIZE; -+ -+ if (chunk_start_offset < off) { -+ chunk_offset = off; -+ if ((off + pending_len) < chunk_end_offset) -+ chunk_len = pending_len; -+ else -+ chunk_len = chunk_end_offset - off; -+ } else { -+ chunk_offset = chunk_start_offset; -+ if (pending_len < OPTOE_PAGE_SIZE) -+ chunk_len = pending_len; -+ else -+ chunk_len = OPTOE_PAGE_SIZE; -+ } -+ -+ dev_dbg(&client->dev, -+ "sff_r/w: off %lld, len %ld, chunk_start_offset %lld, chunk_offset %lld, chunk_len %ld, pending_len %ld\n", -+ off, (long int) len, chunk_start_offset, chunk_offset, -+ (long int) chunk_len, (long int) pending_len); -+ -+ /* -+ * note: chunk_offset is from the start of the EEPROM, -+ * not the start of the chunk -+ */ -+ status = optoe_eeprom_update_client(optoe, buf, -+ chunk_offset, chunk_len, opcode); -+ if (status != chunk_len) { -+ /* This is another 'no device present' path */ -+ dev_dbg(&client->dev, -+ "o_u_c: chunk %d c_offset %lld c_len %ld failed %d!\n", -+ chunk, chunk_offset, (long int) chunk_len, status); -+ if (status > 0) -+ retval += status; -+ if (retval == 0) -+ retval = status; -+ break; -+ } -+ buf += status; -+ pending_len -= status; -+ retval += status; -+ } -+ mutex_unlock(&optoe->lock); -+ -+ return retval; -+} -+ -+static ssize_t optoe_bin_read(struct file *filp, struct kobject *kobj, -+ struct bin_attribute *attr, -+ char *buf, loff_t off, size_t count) -+{ -+ struct i2c_client *client = to_i2c_client(container_of(kobj, -+ struct device, kobj)); -+ struct optoe_data *optoe = i2c_get_clientdata(client); -+ -+ return optoe_read_write(optoe, buf, off, count, OPTOE_READ_OP); -+} -+ -+static ssize_t optoe_bin_write(struct file *filp, struct kobject *kobj, -+ struct bin_attribute *attr, -+ char *buf, loff_t off, size_t count) -+{ -+ struct i2c_client *client = to_i2c_client(container_of(kobj, -+ struct device, kobj)); -+ struct optoe_data *optoe = i2c_get_clientdata(client); -+ -+ return optoe_read_write(optoe, buf, off, count, OPTOE_WRITE_OP); -+} -+ -+static int optoe_remove(struct i2c_client *client) -+{ -+ struct optoe_data *optoe; -+ int i; -+ -+ optoe = i2c_get_clientdata(client); -+ sysfs_remove_group(&client->dev.kobj, &optoe->attr_group); -+ sysfs_remove_bin_file(&client->dev.kobj, &optoe->bin); -+ -+ for (i = 1; i < optoe->num_addresses; i++) -+ i2c_unregister_device(optoe->client[i]); -+ -+#ifdef EEPROM_CLASS -+ eeprom_device_unregister(optoe->eeprom_dev); -+#endif -+ -+ kfree(optoe->writebuf); -+ kfree(optoe); -+ return 0; -+} -+ -+static ssize_t show_dev_class(struct device *dev, -+ struct device_attribute *dattr, char *buf) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct optoe_data *optoe = i2c_get_clientdata(client); -+ ssize_t count; -+ -+ mutex_lock(&optoe->lock); -+ count = sprintf(buf, "%d\n", optoe->dev_class); -+ mutex_unlock(&optoe->lock); -+ -+ return count; -+} -+ -+static ssize_t set_dev_class(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct optoe_data *optoe = i2c_get_clientdata(client); -+ int dev_class; -+ -+ /* -+ * dev_class is actually the number of i2c addresses used, thus -+ * legal values are "1" (QSFP class) and "2" (SFP class) -+ * And... CMIS spec is 1 i2c address, but puts the pageable -+ * bit in a different location, so CMIS devices are "3" -+ */ -+ -+ if (kstrtoint(buf, 0, &dev_class) != 0 || -+ dev_class < 1 || dev_class > 3) -+ return -EINVAL; -+ -+ mutex_lock(&optoe->lock); -+ if (dev_class == TWO_ADDR) { -+ /* SFP family */ -+ /* if it doesn't exist, create 0x51 i2c address */ -+ if (!optoe->client[1]) { -+ optoe->client[1] = i2c_new_dummy_device(client->adapter, 0x51); -+ if (!optoe->client[1]) { -+ dev_err(&client->dev, -+ "address 0x51 unavailable\n"); -+ mutex_unlock(&optoe->lock); -+ return -EADDRINUSE; -+ } -+ } -+ optoe->bin.size = TWO_ADDR_EEPROM_SIZE; -+ optoe->num_addresses = 2; -+ } else { -+ /* one-address (eg QSFP) and CMIS family */ -+ /* if it exists, remove 0x51 i2c address */ -+ if (optoe->client[1]) { -+ i2c_unregister_device(optoe->client[1]); -+ optoe->client[1] = NULL; -+ } -+ optoe->bin.size = ONE_ADDR_EEPROM_SIZE; -+ optoe->num_addresses = 1; -+ } -+ optoe->dev_class = dev_class; -+ mutex_unlock(&optoe->lock); -+ -+ return count; -+} -+ -+/* -+ * if using the EEPROM CLASS driver, we don't report a port_name, -+ * the EEPROM CLASS drive handles that. Hence all this code is -+ * only compiled if we are NOT using the EEPROM CLASS driver. -+ */ -+#ifndef EEPROM_CLASS -+ -+static ssize_t show_port_name(struct device *dev, -+ struct device_attribute *dattr, char *buf) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct optoe_data *optoe = i2c_get_clientdata(client); -+ ssize_t count; -+ -+ mutex_lock(&optoe->lock); -+ count = sprintf(buf, "%s\n", optoe->port_name); -+ mutex_unlock(&optoe->lock); -+ -+ return count; -+} -+ -+static ssize_t set_port_name(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct optoe_data *optoe = i2c_get_clientdata(client); -+ char port_name[MAX_PORT_NAME_LEN]; -+ -+ /* no checking, this value is not used except by show_port_name */ -+ -+ if (sscanf(buf, "%19s", port_name) != 1) -+ return -EINVAL; -+ -+ mutex_lock(&optoe->lock); -+ strcpy(optoe->port_name, port_name); -+ mutex_unlock(&optoe->lock); -+ -+ return count; -+} -+ -+static DEVICE_ATTR(port_name, 0644, show_port_name, set_port_name); -+#endif /* if NOT defined EEPROM_CLASS, the common case */ -+ -+static DEVICE_ATTR(dev_class, 0644, show_dev_class, set_dev_class); -+ -+static struct attribute *optoe_attrs[] = { -+#ifndef EEPROM_CLASS -+ &dev_attr_port_name.attr, -+#endif -+ &dev_attr_dev_class.attr, -+ NULL, -+}; -+ -+static struct attribute_group optoe_attr_group = { -+ .attrs = optoe_attrs, -+}; -+ -+static int optoe_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ int err; -+ int use_smbus = 0; -+ struct optoe_platform_data chip; -+ struct optoe_data *optoe; -+ int num_addresses = 0; -+ char port_name[MAX_PORT_NAME_LEN]; -+ -+ if (client->addr != 0x50) { -+ dev_dbg(&client->dev, "probe, bad i2c addr: 0x%x\n", -+ client->addr); -+ err = -EINVAL; -+ goto exit; -+ } -+ -+ if (client->dev.platform_data) { -+ chip = *(struct optoe_platform_data *)client->dev.platform_data; -+ /* take the port name from the supplied platform data */ -+#ifdef EEPROM_CLASS -+ strncpy(port_name, chip.eeprom_data->label, MAX_PORT_NAME_LEN); -+#else -+ memcpy(port_name, chip.port_name, MAX_PORT_NAME_LEN); -+#endif -+ dev_dbg(&client->dev, -+ "probe, chip provided, flags:0x%x; name: %s\n", -+ chip.flags, client->name); -+ } else { -+ if (!id->driver_data) { -+ err = -ENODEV; -+ goto exit; -+ } -+ dev_dbg(&client->dev, "probe, building chip\n"); -+ strcpy(port_name, "unitialized"); -+ chip.flags = 0; -+#ifdef EEPROM_CLASS -+ chip.eeprom_data = NULL; -+#endif -+ } -+ -+ /* Use I2C operations unless we're stuck with SMBus extensions. */ -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { -+ if (i2c_check_functionality(client->adapter, -+ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { -+ use_smbus = I2C_SMBUS_I2C_BLOCK_DATA; -+ } else if (i2c_check_functionality(client->adapter, -+ I2C_FUNC_SMBUS_READ_WORD_DATA)) { -+ use_smbus = I2C_SMBUS_WORD_DATA; -+ } else if (i2c_check_functionality(client->adapter, -+ I2C_FUNC_SMBUS_READ_BYTE_DATA)) { -+ use_smbus = I2C_SMBUS_BYTE_DATA; -+ } else { -+ err = -EPFNOSUPPORT; -+ goto exit; -+ } -+ } -+ -+ /* -+ * Make room for two i2c clients -+ */ -+ num_addresses = 2; -+ -+ optoe = kzalloc(sizeof(struct optoe_data) + -+ num_addresses * sizeof(struct i2c_client *), -+ GFP_KERNEL); -+ if (!optoe) { -+ err = -ENOMEM; -+ goto exit; -+ } -+ -+ mutex_init(&optoe->lock); -+ -+ /* determine whether this is a one-address or two-address module */ -+ if ((strcmp(client->name, "wb_optoe1") == 0) || -+ (strcmp(client->name, "wb_sff8436") == 0)) { -+ /* one-address (eg QSFP) family */ -+ optoe->dev_class = ONE_ADDR; -+ chip.byte_len = ONE_ADDR_EEPROM_SIZE; -+ num_addresses = 1; -+ } else if ((strcmp(client->name, "wb_optoe2") == 0) || -+ (strcmp(client->name, "wb_24c04") == 0)) { -+ /* SFP family */ -+ optoe->dev_class = TWO_ADDR; -+ chip.byte_len = TWO_ADDR_EEPROM_SIZE; -+ num_addresses = 2; -+ } else if (strcmp(client->name, "wb_optoe3") == 0) { -+ /* CMIS spec */ -+ optoe->dev_class = CMIS_ADDR; -+ chip.byte_len = ONE_ADDR_EEPROM_SIZE; -+ num_addresses = 1; -+ } else { /* those were the only choices */ -+ err = -EINVAL; -+ goto exit; -+ } -+ -+ dev_dbg(&client->dev, "dev_class: %d\n", optoe->dev_class); -+ optoe->use_smbus = use_smbus; -+ optoe->chip = chip; -+ optoe->num_addresses = num_addresses; -+ memcpy(optoe->port_name, port_name, MAX_PORT_NAME_LEN); -+ -+ /* -+ * Export the EEPROM bytes through sysfs, since that's convenient. -+ * By default, only root should see the data (maybe passwords etc) -+ */ -+ sysfs_bin_attr_init(&optoe->bin); -+ optoe->bin.attr.name = "eeprom"; -+ optoe->bin.attr.mode = 0444; -+ optoe->bin.read = optoe_bin_read; -+ optoe->bin.size = chip.byte_len; -+ -+ if (!use_smbus || -+ (i2c_check_functionality(client->adapter, -+ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) || -+ i2c_check_functionality(client->adapter, -+ I2C_FUNC_SMBUS_WRITE_WORD_DATA) || -+ i2c_check_functionality(client->adapter, -+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { -+ /* -+ * NOTE: AN-2079 -+ * Finisar recommends that the host implement 1 byte writes -+ * only since this module only supports 32 byte page boundaries. -+ * 2 byte writes are acceptable for PE and Vout changes per -+ * Application Note AN-2071. -+ */ -+ unsigned int write_max = 1; -+ -+ optoe->bin.write = optoe_bin_write; -+ optoe->bin.attr.mode |= 0200; -+ -+ if (write_max > io_limit) -+ write_max = io_limit; -+ if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX) -+ write_max = I2C_SMBUS_BLOCK_MAX; -+ optoe->write_max = write_max; -+ -+ /* buffer (data + address at the beginning) */ -+ optoe->writebuf = kmalloc(write_max + 2, GFP_KERNEL); -+ if (!optoe->writebuf) { -+ err = -ENOMEM; -+ goto exit_kfree; -+ } -+ } else { -+ dev_warn(&client->dev, -+ "cannot write due to controller restrictions."); -+ } -+ -+ optoe->client[0] = client; -+ -+ /* SFF-8472 spec requires that the second I2C address be 0x51 */ -+ if (num_addresses == 2) { -+ optoe->client[1] = i2c_new_dummy_device(client->adapter, 0x51); -+ if (!optoe->client[1]) { -+ dev_err(&client->dev, "address 0x51 unavailable\n"); -+ err = -EADDRINUSE; -+ goto err_struct; -+ } -+ } -+ -+ /* create the sysfs eeprom file */ -+ err = sysfs_create_bin_file(&client->dev.kobj, &optoe->bin); -+ if (err) -+ goto err_struct; -+ -+ optoe->attr_group = optoe_attr_group; -+ -+ err = sysfs_create_group(&client->dev.kobj, &optoe->attr_group); -+ if (err) { -+ dev_err(&client->dev, "failed to create sysfs attribute group.\n"); -+ goto err_struct; -+ } -+ -+#ifdef EEPROM_CLASS -+ optoe->eeprom_dev = eeprom_device_register(&client->dev, -+ chip.eeprom_data); -+ if (IS_ERR(optoe->eeprom_dev)) { -+ dev_err(&client->dev, "error registering eeprom device.\n"); -+ err = PTR_ERR(optoe->eeprom_dev); -+ goto err_sysfs_cleanup; -+ } -+#endif -+ -+ i2c_set_clientdata(client, optoe); -+ -+ dev_info(&client->dev, "%zu byte %s EEPROM, %s\n", -+ optoe->bin.size, client->name, -+ optoe->bin.write ? "read/write" : "read-only"); -+ -+ if (use_smbus == I2C_SMBUS_WORD_DATA || -+ use_smbus == I2C_SMBUS_BYTE_DATA) { -+ dev_notice(&client->dev, -+ "Falling back to %s reads, performance will suffer\n", -+ use_smbus == I2C_SMBUS_WORD_DATA ? "word" : "byte"); -+ } -+ -+ return 0; -+ -+#ifdef EEPROM_CLASS -+err_sysfs_cleanup: -+ sysfs_remove_group(&client->dev.kobj, &optoe->attr_group); -+ sysfs_remove_bin_file(&client->dev.kobj, &optoe->bin); -+#endif -+ -+err_struct: -+ if (num_addresses == 2) { -+ if (optoe->client[1]) { -+ i2c_unregister_device(optoe->client[1]); -+ optoe->client[1] = NULL; -+ } -+ } -+ -+ kfree(optoe->writebuf); -+exit_kfree: -+ kfree(optoe); -+exit: -+ dev_dbg(&client->dev, "probe error %d\n", err); -+ -+ return err; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static struct i2c_driver optoe_driver = { -+ .driver = { -+ .name = "wb_optoe", -+ .owner = THIS_MODULE, -+ }, -+ .probe = optoe_probe, -+ .remove = optoe_remove, -+ .id_table = optoe_ids, -+}; -+ -+static int __init optoe_init(void) -+{ -+ -+ if (!io_limit) { -+ pr_err("optoe: io_limit must not be 0!\n"); -+ return -EINVAL; -+ } -+ -+ io_limit = rounddown_pow_of_two(io_limit); -+ return i2c_add_driver(&optoe_driver); -+} -+module_init(optoe_init); -+ -+static void __exit optoe_exit(void) -+{ -+ i2c_del_driver(&optoe_driver); -+} -+module_exit(optoe_exit); -+ -+MODULE_DESCRIPTION("Driver for optical transceiver (SFP, QSFP, ...) EEPROMs"); -+MODULE_AUTHOR("support"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.c -new file mode 100644 -index 000000000..757c100e4 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.c -@@ -0,0 +1,770 @@ -+/* -+ * wb_pcie_dev.c -+ * ko to read/write pcie iomem and ioports through /dev/XXX device -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "wb_pcie_dev.h" -+ -+#define PROXY_NAME "wb-pci-dev" -+#define MAX_NAME_SIZE (20) -+#define MAX_PCIE_NUM (256) -+#define PCI_RDWR_MAX_LEN (256) -+#define PCIE_BUS_WIDTH_1 (1) -+#define PCIE_BUS_WIDTH_2 (2) -+#define PCIE_BUS_WIDTH_4 (4) -+ -+static int g_pcie_dev_debug = 0; -+static int g_pcie_dev_error = 0; -+ -+module_param(g_pcie_dev_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_pcie_dev_error, int, S_IRUGO | S_IWUSR); -+ -+#define PCIE_DEV_DEBUG_VERBOSE(fmt, args...) do { \ -+ if (g_pcie_dev_debug) { \ -+ printk(KERN_INFO "[PCIE_DEV][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define PCIE_DEV_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_pcie_dev_error) { \ -+ printk(KERN_ERR "[PCIE_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+typedef struct firmware_upg_s { -+ int upg_ctrl_base; -+ int upg_flash_base; -+} firmware_upg_t; -+ -+typedef struct wb_pci_dev_s { -+ const char *name; -+ uint32_t domain; -+ uint32_t bus; -+ uint32_t slot; -+ uint32_t fn; -+ uint32_t bar; -+ void __iomem *pci_mem_base; -+ uint32_t pci_io_base; -+ uint32_t bar_len; -+ uint32_t bar_flag; -+ uint32_t bus_width; -+ struct miscdevice misc; -+ void (*setreg)(struct wb_pci_dev_s *wb_pci_dev, int reg, u32 value); -+ u32 (*getreg)(struct wb_pci_dev_s *wb_pci_dev, int reg); -+ firmware_upg_t firmware_upg; -+} wb_pci_dev_t; -+ -+static wb_pci_dev_t* pcie_dev_arry[MAX_PCIE_NUM]; -+ -+static void pci_dev_setreg_8(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) -+{ -+ u8 w_value; -+ -+ w_value = (u8)(value & 0xff); -+ if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { -+ writeb(w_value, wb_pci_dev->pci_mem_base + reg); -+ } else { -+ outb(w_value, wb_pci_dev->pci_io_base + reg); -+ } -+ return; -+} -+ -+static void pci_dev_setreg_16(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) -+{ -+ u16 w_value; -+ -+ w_value = (u16)(value & 0xffff); -+ if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { -+ writew(w_value, wb_pci_dev->pci_mem_base + reg); -+ } else { -+ outw(w_value, wb_pci_dev->pci_io_base + reg); -+ } -+ -+ return; -+} -+ -+static void pci_dev_setreg_32(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) -+{ -+ -+ if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { -+ writel(value, wb_pci_dev->pci_mem_base + reg); -+ } else { -+ outl(value, wb_pci_dev->pci_io_base + reg); -+ } -+ return; -+} -+ -+static inline u32 pci_dev_getreg_8(wb_pci_dev_t *wb_pci_dev, int reg) -+{ -+ u32 value; -+ -+ if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { -+ value = readb(wb_pci_dev->pci_mem_base + reg); -+ } else { -+ value = inb(wb_pci_dev->pci_io_base + reg); -+ } -+ -+ return value; -+} -+ -+static inline u32 pci_dev_getreg_16(wb_pci_dev_t *wb_pci_dev, int reg) -+{ -+ u32 value; -+ -+ if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { -+ value = readw(wb_pci_dev->pci_mem_base + reg); -+ } else { -+ value = inw(wb_pci_dev->pci_io_base + reg); -+ } -+ -+ return value; -+} -+ -+static inline u32 pci_dev_getreg_32(wb_pci_dev_t *wb_pci_dev, int reg) -+{ -+ u32 value; -+ -+ if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { -+ value = readl(wb_pci_dev->pci_mem_base + reg); -+ } else { -+ value = inl(wb_pci_dev->pci_io_base + reg); -+ } -+ -+ return value; -+} -+ -+static inline void pci_dev_setreg(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) -+{ -+ wb_pci_dev->setreg(wb_pci_dev, reg, value); -+} -+ -+static inline u32 pci_dev_getreg(wb_pci_dev_t *wb_pci_dev, int reg) -+{ -+ return wb_pci_dev->getreg(wb_pci_dev, reg); -+} -+ -+static int pci_dev_open(struct inode *inode, struct file *file) -+{ -+ unsigned int minor = iminor(inode); -+ wb_pci_dev_t *wb_pci_dev; -+ -+ PCIE_DEV_DEBUG_VERBOSE("inode: %p, file: %p, minor: %u", inode, file, minor); -+ -+ if (minor >= MAX_PCIE_NUM) { -+ PCIE_DEV_DEBUG_ERROR("minor out of range, minor = %d.\n", minor); -+ return -ENODEV; -+ } -+ -+ wb_pci_dev = pcie_dev_arry[minor]; -+ if (wb_pci_dev == NULL) { -+ PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, open failed, minor = %d\n", minor); -+ return -ENODEV; -+ } -+ -+ file->private_data = wb_pci_dev; -+ return 0; -+} -+ -+static int pci_dev_release(struct inode *inode, struct file *file) -+{ -+ file->private_data = NULL; -+ return 0; -+} -+ -+static int pci_dev_read_tmp(wb_pci_dev_t *wb_pci_dev, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ int width, i, j; -+ u32 val; -+ -+ if (offset > wb_pci_dev->bar_len) { -+ PCIE_DEV_DEBUG_VERBOSE("offset:0x%x, bar len:0x%x, EOF.\n", offset, wb_pci_dev->bar_len); -+ return 0; -+ } -+ -+ width = wb_pci_dev->bus_width; -+ -+ if (offset % width) { -+ PCIE_DEV_DEBUG_ERROR("pci bus width:%d, offset:0x%x, read size %lu invalid.\n", -+ width, offset, count); -+ return -EINVAL; -+ } -+ -+ if (count > wb_pci_dev->bar_len - offset) { -+ PCIE_DEV_DEBUG_VERBOSE("read count out of range. input len:%lu, read len:%u.\n", -+ count, wb_pci_dev->bar_len - offset); -+ count = wb_pci_dev->bar_len - offset; -+ } -+ -+ for (i = 0; i < count; i += width) { -+ val = pci_dev_getreg(wb_pci_dev, offset + i); -+ for (j = 0; (j < width) && (i + j < count); j++) { -+ buf[i + j] = (val >> (8 * j)) & 0xff; -+ } -+ } -+ return count; -+} -+ -+static ssize_t pci_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) -+{ -+ wb_pci_dev_t *wb_pci_dev; -+ int ret, read_len; -+ u8 buf_tmp[PCI_RDWR_MAX_LEN]; -+ -+ wb_pci_dev = file->private_data; -+ if (wb_pci_dev == NULL) { -+ PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, read failed.\n"); -+ return -EINVAL; -+ } -+ -+ if (count == 0) { -+ PCIE_DEV_DEBUG_ERROR("Invalid params, read count is 0.\n"); -+ return -EINVAL; -+ } -+ -+ if (count > sizeof(buf_tmp)) { -+ PCIE_DEV_DEBUG_VERBOSE("read count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); -+ count = sizeof(buf_tmp); -+ } -+ -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ read_len = pci_dev_read_tmp(wb_pci_dev, *offset, buf_tmp, count); -+ if (read_len < 0) { -+ PCIE_DEV_DEBUG_ERROR("pci_dev_read_tmp failed, ret:%d.\n", read_len); -+ return read_len; -+ } -+ if (access_ok(buf, read_len)) { -+ PCIE_DEV_DEBUG_VERBOSE("user space read, buf: %p, offset: %lld, read count %lu.\n", -+ buf, *offset, count); -+ if (copy_to_user(buf, buf_tmp, read_len)) { -+ PCIE_DEV_DEBUG_ERROR("copy_to_user failed.\n"); -+ return -EFAULT; -+ } -+ } else { -+ PCIE_DEV_DEBUG_VERBOSE("kernel space read, buf: %p, offset: %lld, read count %lu.\n", -+ buf, *offset, count); -+ memcpy(buf, buf_tmp, read_len); -+ } -+ *offset += read_len; -+ ret = read_len; -+ return ret; -+} -+ -+static ssize_t pci_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) -+{ -+ int ret; -+ -+ PCIE_DEV_DEBUG_VERBOSE("pci_dev_read_iter, file: %p, count: %lu, offset: %lld\n", -+ iocb->ki_filp, to->count, iocb->ki_pos); -+ ret = pci_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos); -+ return ret; -+} -+ -+static int pci_dev_write_tmp(wb_pci_dev_t *wb_pci_dev, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ int width, i, j; -+ u32 val; -+ -+ if (offset > wb_pci_dev->bar_len) { -+ PCIE_DEV_DEBUG_VERBOSE("offset:0x%x, bar len:0x%x, EOF.\n", offset, wb_pci_dev->bar_len); -+ return 0; -+ } -+ -+ width = wb_pci_dev->bus_width; -+ -+ if (offset % width) { -+ PCIE_DEV_DEBUG_ERROR("pci bus width:%d, offset:0x%x, read size %lu invalid.\n", -+ width, offset, count); -+ return -EINVAL; -+ } -+ -+ if (count > wb_pci_dev->bar_len - offset) { -+ PCIE_DEV_DEBUG_VERBOSE("write count out of range. input len:%lu, write len:%u.\n", -+ count, wb_pci_dev->bar_len - offset); -+ count = wb_pci_dev->bar_len - offset; -+ } -+ -+ for (i = 0; i < count; i += width) { -+ val = 0; -+ for (j = 0; (j < width) && (i + j < count); j++) { -+ val |= buf[i + j] << (8 * j); -+ } -+ pci_dev_setreg(wb_pci_dev, i + offset, val); -+ } -+ -+ return count; -+} -+ -+static ssize_t pci_dev_write(struct file *file, const char __user *buf, size_t count, -+ loff_t *offset) -+{ -+ wb_pci_dev_t *wb_pci_dev; -+ u8 buf_tmp[PCI_RDWR_MAX_LEN]; -+ int write_len; -+ -+ wb_pci_dev = file->private_data; -+ if (wb_pci_dev == NULL) { -+ PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, write failed.\n"); -+ return -EINVAL; -+ } -+ -+ if (count == 0) { -+ PCIE_DEV_DEBUG_ERROR("Invalid params, write count is 0.\n"); -+ return -EINVAL; -+ } -+ -+ if (count > sizeof(buf_tmp)) { -+ PCIE_DEV_DEBUG_VERBOSE("write count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); -+ count = sizeof(buf_tmp); -+ } -+ -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ if (access_ok(buf, count)) { -+ PCIE_DEV_DEBUG_VERBOSE("user space write, buf: %p, offset: %lld, write count %lu.\n", -+ buf, *offset, count); -+ if (copy_from_user(buf_tmp, buf, count)) { -+ PCIE_DEV_DEBUG_ERROR("copy_from_user failed.\n"); -+ return -EFAULT; -+ } -+ } else { -+ PCIE_DEV_DEBUG_VERBOSE("kernel space write, buf: %p, offset: %lld, write count %lu.\n", -+ buf, *offset, count); -+ memcpy(buf_tmp, buf, count); -+ } -+ -+ write_len = pci_dev_write_tmp(wb_pci_dev, *offset, buf_tmp, count); -+ if (write_len < 0) { -+ PCIE_DEV_DEBUG_ERROR("pci_dev_write_tmp failed, ret:%d.\n", write_len); -+ return write_len; -+ } -+ -+ *offset += write_len; -+ return write_len; -+} -+ -+static ssize_t pci_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) -+{ -+ int ret; -+ -+ PCIE_DEV_DEBUG_VERBOSE("pci_dev_write_iter, file: %p, count: %lu, offset: %lld\n", -+ iocb->ki_filp, from->count, iocb->ki_pos); -+ ret = pci_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos); -+ return ret; -+} -+ -+static loff_t pci_dev_llseek(struct file *file, loff_t offset, int origin) -+{ -+ loff_t ret = 0; -+ wb_pci_dev_t *wb_pci_dev; -+ -+ wb_pci_dev = file->private_data; -+ if (wb_pci_dev == NULL) { -+ PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, llseek failed.\n"); -+ return -EINVAL; -+ } -+ -+ switch (origin) { -+ case SEEK_SET: -+ if (offset < 0) { -+ PCIE_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); -+ ret = -EINVAL; -+ break; -+ } -+ if (offset > wb_pci_dev->bar_len) { -+ PCIE_DEV_DEBUG_ERROR("SEEK_SET out of range, offset:%lld, bar len:0x%x.\n", -+ offset, wb_pci_dev->bar_len); -+ ret = - EINVAL; -+ break; -+ } -+ file->f_pos = offset; -+ ret = file->f_pos; -+ break; -+ case SEEK_CUR: -+ if (((file->f_pos + offset) > wb_pci_dev->bar_len) || ((file->f_pos + offset) < 0)) { -+ PCIE_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld, bar len:0x%x.\n", -+ file->f_pos, offset, wb_pci_dev->bar_len); -+ ret = - EINVAL; -+ break; -+ } -+ file->f_pos += offset; -+ ret = file->f_pos; -+ break; -+ default: -+ PCIE_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+ -+static long pci_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ wb_pci_dev_t *wb_pci_dev; -+ void __user *argp; -+ firmware_upg_t *firmware_upg; -+ int upg_ctrl_base; -+ int upg_flash_base; -+ -+ PCIE_DEV_DEBUG_VERBOSE("ioctl, cmd=0x%02x, arg=0x%02lx\n",cmd, arg); -+ -+ wb_pci_dev = file->private_data; -+ if (wb_pci_dev == NULL) { -+ PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, ioctl failed.\n"); -+ return -EINVAL; -+ } -+ -+ firmware_upg = &wb_pci_dev->firmware_upg; -+ -+ argp = (void __user *)arg; -+ -+ switch (cmd) { -+ case GET_FPGA_UPG_CTL_BASE: -+ if (firmware_upg->upg_ctrl_base < 0) { -+ PCIE_DEV_DEBUG_ERROR("dts not adaptive upg_ctrl_base\n"); -+ return -EFAULT; -+ } else { -+ upg_ctrl_base = firmware_upg->upg_ctrl_base; -+ if (copy_to_user(argp, &upg_ctrl_base, sizeof(upg_ctrl_base))) { -+ PCIE_DEV_DEBUG_ERROR("upg_ctrl_base copy_from_user failed\n"); -+ return -EFAULT; -+ } -+ } -+ break; -+ case GET_FPGA_UPG_FLASH_BASE: -+ if (firmware_upg->upg_flash_base < 0) { -+ PCIE_DEV_DEBUG_ERROR("dts not adaptive upg_flash_base\n"); -+ return -EFAULT; -+ } else { -+ upg_flash_base = firmware_upg->upg_flash_base; -+ if (copy_to_user(argp, &upg_flash_base, sizeof(upg_flash_base))) { -+ PCIE_DEV_DEBUG_ERROR("upg_flash_base copy_from_user failed\n"); -+ return -EFAULT; -+ } -+ } -+ break; -+ default: -+ PCIE_DEV_DEBUG_ERROR("command unsupported \n"); -+ return -ENOTTY; -+ } -+ -+ return 0; -+} -+ -+static const struct file_operations pcie_dev_fops = { -+ .owner = THIS_MODULE, -+ .llseek = pci_dev_llseek, -+ .read_iter = pci_dev_read_iter, -+ .write_iter = pci_dev_write_iter, -+ .unlocked_ioctl = pci_dev_ioctl, -+ .open = pci_dev_open, -+ .release = pci_dev_release, -+}; -+ -+static wb_pci_dev_t *dev_match(const char *path) -+{ -+ wb_pci_dev_t *wb_pci_dev; -+ char dev_name[MAX_NAME_SIZE]; -+ int i; -+ -+ for (i = 0; i < MAX_PCIE_NUM; i++) { -+ if (pcie_dev_arry[i] == NULL) { -+ continue; -+ } -+ wb_pci_dev = pcie_dev_arry[i]; -+ snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", wb_pci_dev->name); -+ if (!strcmp(path, dev_name)) { -+ PCIE_DEV_DEBUG_VERBOSE("get dev_name = %s, minor = %d\n", dev_name, i); -+ return wb_pci_dev; -+ } -+ } -+ -+ return NULL; -+} -+ -+int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ wb_pci_dev_t *wb_pci_dev; -+ int read_len; -+ -+ if (path == NULL) { -+ PCIE_DEV_DEBUG_ERROR("path NULL"); -+ return -EINVAL; -+ } -+ -+ if (buf == NULL) { -+ PCIE_DEV_DEBUG_ERROR("buf NULL"); -+ return -EINVAL; -+ } -+ -+ wb_pci_dev = dev_match(path); -+ if (wb_pci_dev == NULL) { -+ PCIE_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); -+ return -EINVAL; -+ } -+ -+ read_len = pci_dev_read_tmp(wb_pci_dev, offset, buf, count); -+ if (read_len < 0) { -+ PCIE_DEV_DEBUG_ERROR("pci_dev_read_tmp failed, ret:%d.\n", read_len); -+ } -+ return read_len; -+} -+EXPORT_SYMBOL(pcie_device_func_read); -+ -+int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ wb_pci_dev_t *wb_pci_dev; -+ int write_len; -+ -+ if (path == NULL) { -+ PCIE_DEV_DEBUG_ERROR("path NULL"); -+ return -EINVAL; -+ } -+ -+ if (buf == NULL) { -+ PCIE_DEV_DEBUG_ERROR("buf NULL"); -+ return -EINVAL; -+ } -+ -+ wb_pci_dev = dev_match(path); -+ if (wb_pci_dev == NULL) { -+ PCIE_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); -+ return -EINVAL; -+ } -+ -+ write_len = pci_dev_write_tmp(wb_pci_dev, offset, buf, count); -+ if (write_len < 0) { -+ PCIE_DEV_DEBUG_ERROR("pci_dev_write_tmp failed, ret:%d.\n", write_len); -+ } -+ return write_len; -+} -+EXPORT_SYMBOL(pcie_device_func_write); -+ -+static int pci_setup_bars(wb_pci_dev_t *wb_pci_dev, struct pci_dev *dev) -+{ -+ int ret; -+ uint32_t addr, len, flags; -+ -+ ret = 0; -+ addr = pci_resource_start(dev, wb_pci_dev->bar); -+ len = pci_resource_len(dev, wb_pci_dev->bar); -+ if (addr == 0 || len == 0) { -+ PCIE_DEV_DEBUG_ERROR("get bar addr failed. bar:%d, addr:0x%x, len:0x%x.\n", -+ wb_pci_dev->bar, addr, len); -+ return -EFAULT; -+ } -+ wb_pci_dev->bar_len = len; -+ -+ flags = pci_resource_flags(dev, wb_pci_dev->bar); -+ PCIE_DEV_DEBUG_VERBOSE("bar:%d, flag:0x%08x, phys addr:0x%x, len:0x%x\n", -+ wb_pci_dev->bar, flags, addr, len); -+ if (flags & IORESOURCE_MEM) { -+ wb_pci_dev->bar_flag = IORESOURCE_MEM; -+ wb_pci_dev->pci_mem_base = ioremap(addr, len); -+ PCIE_DEV_DEBUG_VERBOSE("pci mem base:%p.\n", wb_pci_dev->pci_mem_base); -+ } else if (flags & IORESOURCE_IO) { -+ wb_pci_dev->bar_flag = IORESOURCE_IO; -+ wb_pci_dev->pci_io_base = addr; -+ PCIE_DEV_DEBUG_VERBOSE("pci io base:0x%x.\n", wb_pci_dev->pci_io_base); -+ } else { -+ PCIE_DEV_DEBUG_ERROR("unknow pci bar flag:0x%08x.\n", flags); -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static int pci_dev_probe(struct platform_device *pdev) -+{ -+ int ret, devfn; -+ wb_pci_dev_t *wb_pci_dev; -+ struct pci_dev *pci_dev; -+ struct miscdevice *misc; -+ firmware_upg_t *firmware_upg; -+ pci_dev_device_t *pci_dev_device; -+ -+ wb_pci_dev = devm_kzalloc(&pdev->dev, sizeof(wb_pci_dev_t), GFP_KERNEL); -+ if (!wb_pci_dev) { -+ dev_err(&pdev->dev, "devm_kzalloc failed.\n"); -+ ret = -ENOMEM; -+ return ret; -+ } -+ -+ firmware_upg = &wb_pci_dev->firmware_upg; -+ -+ if (pdev->dev.of_node) { -+ ret = 0; -+ ret += of_property_read_string(pdev->dev.of_node, "pci_dev_name", &wb_pci_dev->name); -+ ret += of_property_read_u32(pdev->dev.of_node, "pci_domain", &wb_pci_dev->domain); -+ ret += of_property_read_u32(pdev->dev.of_node, "pci_bus", &wb_pci_dev->bus); -+ ret += of_property_read_u32(pdev->dev.of_node, "pci_slot", &wb_pci_dev->slot); -+ ret += of_property_read_u32(pdev->dev.of_node, "pci_fn", &wb_pci_dev->fn); -+ ret += of_property_read_u32(pdev->dev.of_node, "pci_bar", &wb_pci_dev->bar); -+ ret += of_property_read_u32(pdev->dev.of_node, "bus_width", &wb_pci_dev->bus_width); -+ -+ if (ret != 0) { -+ dev_err(&pdev->dev, "Failed to get dts config, ret:%d.\n", ret); -+ return -ENXIO; -+ } -+ -+ ret = 0; -+ ret += of_property_read_u32(pdev->dev.of_node, "upg_ctrl_base", &firmware_upg->upg_ctrl_base); -+ ret += of_property_read_u32(pdev->dev.of_node, "upg_flash_base", &firmware_upg->upg_flash_base); -+ if (ret != 0) { -+ PCIE_DEV_DEBUG_VERBOSE("dts don't adaptive fpga upg related, ret:%d.\n", ret); -+ firmware_upg->upg_ctrl_base = -1; -+ firmware_upg->upg_flash_base = -1; -+ } else { -+ PCIE_DEV_DEBUG_VERBOSE("upg_ctrl_base:0x%04x, upg_flash_base:0x%02x.\n", -+ firmware_upg->upg_ctrl_base, firmware_upg->upg_flash_base); -+ } -+ } else { -+ if (pdev->dev.platform_data == NULL) { -+ dev_err(&pdev->dev, "Failed to get platform data config.\n"); -+ return -ENXIO; -+ } -+ pci_dev_device = pdev->dev.platform_data; -+ wb_pci_dev->name = pci_dev_device->pci_dev_name; -+ wb_pci_dev->domain = pci_dev_device->pci_domain; -+ wb_pci_dev->bus = pci_dev_device->pci_bus; -+ wb_pci_dev->slot = pci_dev_device->pci_slot; -+ wb_pci_dev->fn = pci_dev_device->pci_fn; -+ wb_pci_dev->bar = pci_dev_device->pci_bar; -+ wb_pci_dev->bus_width = pci_dev_device->bus_width; -+ firmware_upg->upg_ctrl_base = pci_dev_device->upg_ctrl_base; -+ firmware_upg->upg_flash_base = pci_dev_device->upg_flash_base; -+ PCIE_DEV_DEBUG_VERBOSE("upg_ctrl_base:0x%04x, upg_flash_base:0x%02x.\n", -+ firmware_upg->upg_ctrl_base, firmware_upg->upg_flash_base); -+ } -+ -+ PCIE_DEV_DEBUG_VERBOSE("name:%s, domain:0x%04x, bus:0x%02x, slot:0x%02x, fn:%u, bar:%u, bus_width:%d.\n", -+ wb_pci_dev->name, wb_pci_dev->domain, wb_pci_dev->bus, wb_pci_dev->slot, wb_pci_dev->fn, -+ wb_pci_dev->bar, wb_pci_dev->bus_width); -+ -+ devfn = PCI_DEVFN(wb_pci_dev->slot, wb_pci_dev->fn); -+ pci_dev = pci_get_domain_bus_and_slot(wb_pci_dev->domain, wb_pci_dev->bus, devfn); -+ if (pci_dev == NULL) { -+ dev_err(&pdev->dev, "Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", -+ wb_pci_dev->domain, wb_pci_dev->bus, devfn); -+ return -ENXIO; -+ } -+ ret = pci_setup_bars(wb_pci_dev, pci_dev); -+ if (ret != 0) { -+ dev_err(&pdev->dev, "Failed to get pci bar address.\n"); -+ return ret; -+ } -+ -+ if (!wb_pci_dev->setreg || !wb_pci_dev->getreg) { -+ switch (wb_pci_dev->bus_width) { -+ case 1: -+ wb_pci_dev->setreg = pci_dev_setreg_8; -+ wb_pci_dev->getreg = pci_dev_getreg_8; -+ break; -+ -+ case 2: -+ wb_pci_dev->setreg = pci_dev_setreg_16; -+ wb_pci_dev->getreg = pci_dev_getreg_16; -+ break; -+ -+ case 4: -+ wb_pci_dev->setreg = pci_dev_setreg_32; -+ wb_pci_dev->getreg = pci_dev_getreg_32; -+ break; -+ default: -+ dev_err(&pdev->dev, "Error: unsupported I/O width (%d).\n", wb_pci_dev->bus_width); -+ ret = -EINVAL; -+ goto io_unmap; -+ } -+ } -+ -+ misc = &wb_pci_dev->misc; -+ misc->minor = MISC_DYNAMIC_MINOR; -+ misc->name = wb_pci_dev->name; -+ misc->fops = &pcie_dev_fops; -+ misc->mode = 0666; -+ if (misc_register(misc) != 0) { -+ dev_err(&pdev->dev, "Failed to register %s device.\n", misc->name); -+ ret = -ENXIO; -+ goto io_unmap; -+ } -+ if (misc->minor >= MAX_PCIE_NUM) { -+ dev_err(&pdev->dev, "Error: device minor[%d] more than max pcie num[%d].\n", -+ misc->minor, MAX_PCIE_NUM); -+ misc_deregister(misc); -+ ret = -EINVAL; -+ goto io_unmap; -+ } -+ pcie_dev_arry[misc->minor] = wb_pci_dev; -+ dev_info(&pdev->dev, "%04x:%02x:%02x.%d[bar%d: %s]: register %s device with minor:%d success.\n", -+ wb_pci_dev->domain, wb_pci_dev->bus, wb_pci_dev->slot, wb_pci_dev->fn, wb_pci_dev->bar, -+ wb_pci_dev->bar_flag == IORESOURCE_MEM ? "IORESOURCE_MEM" : "IORESOURCE_IO", -+ misc->name, misc->minor ); -+ return 0; -+ -+io_unmap: -+ if (wb_pci_dev->pci_mem_base) { -+ iounmap(wb_pci_dev->pci_mem_base); -+ } -+ return ret; -+} -+ -+static int pci_dev_remove(struct platform_device *pdev) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_PCIE_NUM ; i++) { -+ if (pcie_dev_arry[i] != NULL) { -+ if (pcie_dev_arry[i]->pci_mem_base) { -+ iounmap(pcie_dev_arry[i]->pci_mem_base); -+ } -+ misc_deregister(&pcie_dev_arry[i]->misc); -+ pcie_dev_arry[i] = NULL; -+ } -+ } -+ -+ return 0; -+} -+ -+static struct of_device_id pci_dev_match[] = { -+ { -+ .compatible = "wb-pci-dev", -+ }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, pci_dev_match); -+ -+static struct platform_driver wb_pci_dev_driver = { -+ .probe = pci_dev_probe, -+ .remove = pci_dev_remove, -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = PROXY_NAME, -+ .of_match_table = pci_dev_match, -+ }, -+}; -+ -+static int __init wb_pci_dev_init(void) -+{ -+ return platform_driver_register(&wb_pci_dev_driver); -+} -+ -+static void __exit wb_pci_dev_exit(void) -+{ -+ platform_driver_unregister(&wb_pci_dev_driver); -+} -+ -+module_init(wb_pci_dev_init); -+module_exit(wb_pci_dev_exit); -+MODULE_DESCRIPTION("pcie device driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.h -new file mode 100644 -index 000000000..9ba0f3b45 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.h -@@ -0,0 +1,26 @@ -+#ifndef __WB_PCIE_DEV_H__ -+#define __WB_PCIE_DEV_H__ -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+ -+#define UPG_TYPE 'U' -+#define GET_FPGA_UPG_CTL_BASE _IOR(UPG_TYPE, 0, int) -+#define GET_FPGA_UPG_FLASH_BASE _IOR(UPG_TYPE, 1, int) -+ -+#define PCI_DEV_NAME_MAX_LEN (64) -+ -+typedef struct pci_dev_device_s { -+ char pci_dev_name[PCI_DEV_NAME_MAX_LEN]; -+ int pci_domain; -+ int pci_bus; -+ int pci_slot; -+ int pci_fn; -+ int pci_bar; -+ int bus_width; -+ int upg_ctrl_base; -+ int upg_flash_base; -+ int device_flag; -+} pci_dev_device_t; -+ -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.c -new file mode 100644 -index 000000000..092c99da2 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.c -@@ -0,0 +1,749 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "wb_platform_i2c_dev.h" -+ -+#define PROXY_NAME "wb-platform-i2c-dev" -+#define MAX_I2C_DEV_NUM (256) -+#define FPGA_MAX_LEN (256) -+#define MAX_NAME_SIZE (20) -+#define MAX_BUS_WIDTH (16) -+#define TRANSFER_WRITE_BUFF (FPGA_MAX_LEN + MAX_BUS_WIDTH) -+ -+#define WIDTH_1Byte (1) -+#define WIDTH_2Byte (2) -+#define WIDTH_4Byte (4) -+ -+int g_i2c_dev_debug = 0; -+int g_i2c_dev_error = 0; -+ -+module_param(g_i2c_dev_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_i2c_dev_error, int, S_IRUGO | S_IWUSR); -+ -+#define I2C_DEV_DEBUG_DMESG(fmt, args...) do { \ -+ if (g_i2c_dev_debug) { \ -+ printk(KERN_ERR "[I2C_DEV][DEBUG][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define I2C_DEV_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_i2c_dev_error) { \ -+ printk(KERN_ERR "[I2C_DEV][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static struct platform_i2c_dev_info* i2c_dev_arry[MAX_I2C_DEV_NUM]; -+ -+struct platform_i2c_dev_info { -+ uint32_t i2c_bus; -+ uint32_t i2c_addr; -+ const char *name; -+ uint32_t data_bus_width; -+ uint32_t addr_bus_width; -+ uint32_t per_rd_len; -+ uint32_t per_wr_len; -+ struct miscdevice misc; -+}; -+ -+static int transfer_read(struct platform_i2c_dev_info *i2c_dev, u8 *buf, loff_t regaddr, size_t count) -+{ -+ int i, j; -+ struct i2c_adapter *adap; -+ union i2c_smbus_data data; -+ u8 offset_buf[MAX_BUS_WIDTH]; -+ struct i2c_msg msgs[2]; -+ int msgs_num, ret; -+ u8 offset; -+ u8 length; -+ -+ if (!i2c_dev) { -+ I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\r\n"); -+ return -ENODEV; -+ } -+ -+ i = 0; -+ -+ mem_clear(offset_buf, sizeof(offset_buf)); -+ -+ switch (i2c_dev->addr_bus_width) { -+ case WIDTH_4Byte: -+ offset_buf[i++] = (regaddr >> 24) & 0xFF; -+ offset_buf[i++] = (regaddr >> 16) & 0xFF; -+ offset_buf[i++] = (regaddr >> 8) & 0xFF; -+ offset_buf[i++] = regaddr & 0xFF; -+ break; -+ case WIDTH_2Byte: -+ offset_buf[i++] = (regaddr >> 8) & 0xFF; -+ offset_buf[i++] = regaddr & 0xFF; -+ break; -+ case WIDTH_1Byte: -+ offset_buf[i++] = regaddr & 0xFF; -+ break; -+ default: -+ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\r\n", i2c_dev->addr_bus_width); -+ return -EINVAL; -+ } -+ -+ adap = i2c_get_adapter(i2c_dev->i2c_bus); -+ if (adap == NULL) { -+ I2C_DEV_DEBUG_ERROR("get i2c adapter %d faild.\n", i2c_dev->i2c_bus); -+ return -ENXIO; -+ } -+ -+ if (adap->algo->master_xfer) { -+ mem_clear(msgs, sizeof(msgs)); -+ msgs[0].addr = i2c_dev->i2c_addr; -+ msgs[0].flags = 0; -+ msgs[0].len = i2c_dev->addr_bus_width; -+ msgs[0].buf = offset_buf; -+ -+ msgs[1].addr = i2c_dev->i2c_addr; -+ msgs[1].flags = I2C_M_RD; -+ msgs[1].len = count; -+ msgs[1].buf = buf; -+ -+ msgs_num = 2; -+ ret = i2c_transfer(adap, msgs, msgs_num); -+ if (ret != msgs_num) { -+ I2C_DEV_DEBUG_ERROR("i2c_transfer read error\r\n"); -+ ret = -EFAULT; -+ goto error_exit; -+ } -+ } else { -+ if (i2c_dev->addr_bus_width == WIDTH_1Byte) { -+ offset = regaddr & 0xFF; -+ if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { -+ for (j = 0; j < count; j += I2C_SMBUS_BLOCK_MAX) { -+ if (count - j > I2C_SMBUS_BLOCK_MAX) { -+ length = I2C_SMBUS_BLOCK_MAX; -+ } else { -+ length = count - j; -+ } -+ data.block[0] = length; -+ ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, -+ 0, -+ I2C_SMBUS_READ, -+ offset, I2C_SMBUS_I2C_BLOCK_DATA, &data); -+ if (ret) { -+ I2C_DEV_DEBUG_ERROR("smbus_xfer read block error, ret = %d\n", ret); -+ ret = -EFAULT; -+ goto error_exit; -+ } -+ memcpy(buf + j, data.block + 1, length); -+ offset += length; -+ } -+ } else { -+ for (j = 0; j < count; j++) { -+ ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, -+ 0, -+ I2C_SMBUS_READ, -+ offset, I2C_SMBUS_BYTE_DATA, &data); -+ -+ if (!ret) { -+ buf[j] = data.byte; -+ } else { -+ I2C_DEV_DEBUG_ERROR("smbus_xfer read byte error, ret = %d\n", ret); -+ ret = -EFAULT; -+ goto error_exit; -+ } -+ offset++; -+ } -+ } -+ } else { -+ I2C_DEV_DEBUG_ERROR("smbus_xfer not support addr_bus_width = %d\n", i2c_dev->addr_bus_width); -+ ret = -EINVAL; -+ goto error_exit; -+ } -+ } -+ -+ i2c_put_adapter(adap); -+ return 0; -+error_exit: -+ i2c_put_adapter(adap); -+ return ret; -+} -+ -+static int transfer_write(struct platform_i2c_dev_info *i2c_dev, u8 *buf, loff_t regaddr, size_t count) -+{ -+ int i, j; -+ struct i2c_adapter *adap; -+ union i2c_smbus_data data; -+ u8 offset_buf[TRANSFER_WRITE_BUFF]; -+ struct i2c_msg msgs[1]; -+ int msgs_num, ret; -+ u8 offset; -+ u8 length; -+ -+ if (!i2c_dev) { -+ I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\r\n"); -+ return -ENODEV; -+ } -+ -+ i = 0; -+ -+ mem_clear(offset_buf, sizeof(offset_buf)); -+ -+ switch (i2c_dev->addr_bus_width) { -+ case WIDTH_4Byte: -+ offset_buf[i++] = (regaddr >> 24) & 0xFF; -+ offset_buf[i++] = (regaddr >> 16) & 0xFF; -+ offset_buf[i++] = (regaddr >> 8) & 0xFF; -+ offset_buf[i++] = regaddr & 0xFF; -+ break; -+ case WIDTH_2Byte: -+ offset_buf[i++] = (regaddr >> 8) & 0xFF; -+ offset_buf[i++] = regaddr & 0xFF; -+ break; -+ case WIDTH_1Byte: -+ offset_buf[i++] = regaddr & 0xFF; -+ break; -+ default: -+ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\r\n", i2c_dev->addr_bus_width); -+ return -EINVAL; -+ } -+ -+ memcpy(offset_buf + i2c_dev->addr_bus_width, buf, count); -+ -+ adap = i2c_get_adapter(i2c_dev->i2c_bus); -+ if (adap == NULL) { -+ I2C_DEV_DEBUG_ERROR("get i2c adapter %d faild.\n", i2c_dev->i2c_bus); -+ return -ENXIO; -+ } -+ -+ if (adap->algo->master_xfer) { -+ mem_clear(msgs, sizeof(msgs)); -+ -+ msgs[0].addr = i2c_dev->i2c_addr; -+ msgs[0].flags = 0; -+ msgs[0].len = i2c_dev->addr_bus_width + count; -+ msgs[0].buf = offset_buf; -+ -+ msgs_num = 1; -+ ret = i2c_transfer(adap, msgs, msgs_num); -+ if (ret != msgs_num) { -+ I2C_DEV_DEBUG_ERROR("i2c_transfer write error\r\n"); -+ ret = -EFAULT; -+ goto error_exit; -+ } -+ } else { -+ if (i2c_dev->addr_bus_width == WIDTH_1Byte) { -+ offset = regaddr & 0xFF; -+ if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { -+ for (j = 0; j < count; j += I2C_SMBUS_BLOCK_MAX) { -+ if (count - j > I2C_SMBUS_BLOCK_MAX) { -+ length = I2C_SMBUS_BLOCK_MAX; -+ } else { -+ length = count - j; -+ } -+ data.block[0] = length; -+ memcpy(data.block + 1, buf + j, length); -+ ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, -+ 0, -+ I2C_SMBUS_WRITE, -+ offset, I2C_SMBUS_I2C_BLOCK_DATA, &data); -+ if (ret) { -+ I2C_DEV_DEBUG_ERROR("smbus_xfer write block error, ret = %d\r\n", ret); -+ ret = -EFAULT; -+ goto error_exit; -+ } -+ offset += length; -+ } -+ } else { -+ for (j = 0; j < count; j++) { -+ data.byte = buf[j]; -+ ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, -+ 0, -+ I2C_SMBUS_WRITE, -+ offset, I2C_SMBUS_BYTE_DATA, &data); -+ if (ret) { -+ I2C_DEV_DEBUG_ERROR("smbus_xfer write byte error, ret = %d\r\n", ret); -+ ret = -EFAULT; -+ goto error_exit; -+ } -+ offset += 1; -+ } -+ } -+ } else { -+ I2C_DEV_DEBUG_ERROR("smbus_xfer not support addr_bus_width = %d\r\n", i2c_dev->addr_bus_width); -+ ret = -EINVAL; -+ goto error_exit; -+ } -+ } -+ -+ i2c_put_adapter(adap); -+ return 0; -+error_exit: -+ i2c_put_adapter(adap); -+ return ret; -+} -+ -+static long i2c_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ return 0; -+} -+ -+static int i2c_dev_open(struct inode *inode, struct file *file) -+{ -+ unsigned int minor = iminor(inode); -+ struct platform_i2c_dev_info *i2c_dev; -+ -+ i2c_dev = i2c_dev_arry[minor]; -+ if (i2c_dev == NULL) { -+ return -ENODEV; -+ } -+ -+ file->private_data = i2c_dev; -+ -+ return 0; -+} -+ -+static int i2c_dev_release(struct inode *inode, struct file *file) -+{ -+ file->private_data = NULL; -+ -+ return 0; -+} -+ -+static int device_read(struct platform_i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, int count) -+{ -+ int i, j, ret; -+ u8 tmp_offset; -+ u8 val[FPGA_MAX_LEN]; -+ u32 width, rd_len, per_len, tmp; -+ u32 max_per_len; -+ -+ width = i2c_dev->data_bus_width; -+ switch (width) { -+ case WIDTH_4Byte: -+ tmp_offset = offset & 0x3; -+ if (tmp_offset) { -+ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %d invalid.\r\n", width, offset, count); -+ return -EINVAL; -+ } -+ break; -+ case WIDTH_2Byte: -+ tmp_offset = offset & 0x1; -+ if (tmp_offset) { -+ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %d invalid.\r\n", width, offset, count); -+ return -EINVAL; -+ } -+ break; -+ case WIDTH_1Byte: -+ break; -+ default: -+ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\r\n", width); -+ return -EINVAL; -+ } -+ -+ max_per_len = i2c_dev->per_rd_len; -+ tmp = (width - 1) & count; -+ rd_len = (tmp == 0) ? count : count + width - tmp; -+ per_len = (rd_len > max_per_len) ? (max_per_len) : (rd_len); -+ -+ mem_clear(val, sizeof(val)); -+ for (i = 0; i < rd_len; i += per_len) { -+ ret = transfer_read(i2c_dev, val + i, offset + i, per_len); -+ if (ret < 0) { -+ I2C_DEV_DEBUG_ERROR("read error.read offset = %u\r\n", (offset + i)); -+ return -EFAULT; -+ } -+ } -+ -+ if (width == WIDTH_1Byte) { -+ memcpy(buf, val, count); -+ } else { -+ for (i = 0; i < count; i += width) { -+ for (j = 0; (j < width) && (i + j < count); j++) { -+ buf[i + j] = val[i + width - j - 1]; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int device_write(struct platform_i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ int i, j, ret; -+ u8 tmp_offset; -+ u32 width; -+ u8 val[FPGA_MAX_LEN]; -+ u32 wr_len, per_len, tmp; -+ u32 max_per_len; -+ -+ width = i2c_dev->data_bus_width; -+ switch (width) { -+ case WIDTH_4Byte: -+ tmp_offset = offset & 0x3; -+ if (tmp_offset) { -+ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\r\n", width, offset, count); -+ return -EINVAL; -+ } -+ break; -+ case WIDTH_2Byte: -+ tmp_offset = offset & 0x1; -+ if (tmp_offset) { -+ I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\r\n", width, offset, count); -+ return -EINVAL; -+ } -+ break; -+ case WIDTH_1Byte: -+ break; -+ default: -+ I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\r\n", width); -+ return -EINVAL; -+ } -+ -+ mem_clear(val, sizeof(val)); -+ -+ if (width == WIDTH_1Byte) { -+ memcpy(val, buf, count); -+ } else { -+ for (i = 0; i < count; i += width) { -+ for (j = 0; (j < width) && (i + j < count); j++) { -+ val[i + width - j - 1] = buf[i + j]; -+ } -+ } -+ } -+ -+ max_per_len = i2c_dev->per_wr_len; -+ tmp = (width - 1) & count; -+ wr_len = (tmp == 0) ? count : count + width - tmp; -+ per_len = (wr_len > max_per_len) ? (max_per_len) : (wr_len); -+ -+ for (i = 0; i < wr_len; i += per_len) { -+ ret = transfer_write(i2c_dev, val + i, offset + i, per_len); -+ if (ret < 0) { -+ I2C_DEV_DEBUG_ERROR("write error.offset = %u\r\n", (offset + i)); -+ return -EFAULT; -+ } -+ } -+ return 0; -+} -+ -+static ssize_t i2c_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) -+{ -+ u8 val[FPGA_MAX_LEN]; -+ int ret; -+ struct platform_i2c_dev_info *i2c_dev; -+ -+ if (count <= 0 || count > sizeof(val)) { -+ I2C_DEV_DEBUG_ERROR("read conut %lu , beyond max:%lu.\n", count, sizeof(val)); -+ return -EINVAL; -+ } -+ -+ i2c_dev = file->private_data; -+ if (i2c_dev == NULL) { -+ I2C_DEV_DEBUG_ERROR("can't get read private_data .\r\n"); -+ return -EINVAL; -+ } -+ -+ ret = device_read(i2c_dev, (uint32_t)*offset, val, count); -+ if (ret < 0) { -+ I2C_DEV_DEBUG_ERROR("i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", -+ i2c_dev->name, (uint32_t)*offset, count); -+ return -EINVAL; -+ } -+ -+ if (copy_to_user(buf, val, count)) { -+ I2C_DEV_DEBUG_ERROR("copy_to_user error \r\n"); -+ return -EFAULT; -+ } else{ -+ *offset += count; -+ } -+ -+ return count; -+} -+ -+static ssize_t i2c_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) -+{ -+ u8 val[FPGA_MAX_LEN]; -+ int ret; -+ struct platform_i2c_dev_info *i2c_dev; -+ -+ if (count <= 0 || count > sizeof(val)) { -+ I2C_DEV_DEBUG_ERROR("write conut %lu, beyond max val:%lu.\n", count, sizeof(val)); -+ return -EINVAL; -+ } -+ -+ i2c_dev = file->private_data; -+ if (i2c_dev == NULL) { -+ I2C_DEV_DEBUG_ERROR("get write private_data error.\r\n"); -+ return -EINVAL; -+ } -+ -+ mem_clear(val, sizeof(val)); -+ if (copy_from_user(val, buf, count)) { -+ I2C_DEV_DEBUG_ERROR("copy_from_user error.\r\n"); -+ return -EFAULT; -+ } -+ -+ ret = device_write (i2c_dev, (uint32_t)*offset, val, count); -+ if (ret < 0) { -+ I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%llx, len:%lu.\n", -+ i2c_dev->name, *offset, count); -+ return -EINVAL; -+ } -+ -+ *offset += count; -+ return count; -+} -+ -+static loff_t i2c_dev_llseek(struct file *file, loff_t offset, int origin) -+{ -+ loff_t ret = 0; -+ -+ switch (origin) { -+ case SEEK_SET: -+ if (offset < 0) { -+ I2C_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\r\n", offset); -+ ret = -EINVAL; -+ break; -+ } -+ file->f_pos = offset; -+ ret = file->f_pos; -+ break; -+ case SEEK_CUR: -+ if (file->f_pos + offset < 0) { -+ I2C_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld.\n", -+ file->f_pos, offset); -+ } -+ file->f_pos += offset; -+ ret = file->f_pos; -+ break; -+ default: -+ I2C_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+ -+static const struct file_operations i2c_dev_fops = { -+ .owner = THIS_MODULE, -+ .llseek = i2c_dev_llseek, -+ .read = i2c_dev_read, -+ .write = i2c_dev_write, -+ .unlocked_ioctl = i2c_dev_ioctl, -+ .open = i2c_dev_open, -+ .release = i2c_dev_release, -+}; -+ -+static struct platform_i2c_dev_info * dev_match(const char *path) -+{ -+ struct platform_i2c_dev_info *i2c_dev; -+ char dev_name[MAX_NAME_SIZE]; -+ int i; -+ for (i = 0; i < MAX_I2C_DEV_NUM; i++) { -+ if (i2c_dev_arry[ i ] == NULL) { -+ continue; -+ } -+ i2c_dev = i2c_dev_arry[ i ]; -+ snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", i2c_dev->name); -+ if (!strcmp(path, dev_name)) { -+ I2C_DEV_DEBUG_DMESG("get dev_name = %s, minor = %d\n", dev_name, i); -+ return i2c_dev; -+ } -+ } -+ -+ return NULL; -+} -+ -+int platform_i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ struct platform_i2c_dev_info *i2c_dev = NULL; -+ int ret; -+ -+ if(path == NULL){ -+ I2C_DEV_DEBUG_ERROR("path NULL"); -+ return -EINVAL; -+ } -+ -+ if(buf == NULL){ -+ I2C_DEV_DEBUG_ERROR("buf NULL"); -+ return -EINVAL; -+ } -+ -+ if (count > FPGA_MAX_LEN) { -+ I2C_DEV_DEBUG_ERROR("read conut %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); -+ return -EINVAL; -+ } -+ -+ i2c_dev = dev_match(path); -+ if (i2c_dev == NULL) { -+ I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); -+ return -EINVAL; -+ } -+ -+ ret = device_read(i2c_dev, offset, buf, count); -+ if (ret < 0) { -+ I2C_DEV_DEBUG_ERROR("fpga i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", -+ i2c_dev->name, offset, count); -+ return -EINVAL; -+ } -+ -+ return count; -+} -+EXPORT_SYMBOL(platform_i2c_device_func_read); -+ -+int platform_i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ struct platform_i2c_dev_info *i2c_dev = NULL; -+ int ret; -+ -+ if(path == NULL){ -+ I2C_DEV_DEBUG_ERROR("path NULL"); -+ return -EINVAL; -+ } -+ -+ if(buf == NULL){ -+ I2C_DEV_DEBUG_ERROR("buf NULL"); -+ return -EINVAL; -+ } -+ -+ if (count > FPGA_MAX_LEN) { -+ I2C_DEV_DEBUG_ERROR("write conut %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); -+ return -EINVAL; -+ } -+ -+ i2c_dev = dev_match(path); -+ if (i2c_dev == NULL) { -+ I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); -+ return -EINVAL; -+ } -+ -+ ret = device_write (i2c_dev, offset, buf, count); -+ if (ret < 0) { -+ I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%x, len:%lu.\n", -+ i2c_dev->name, offset, count); -+ return -EINVAL; -+ } -+ -+ return count; -+} -+EXPORT_SYMBOL(platform_i2c_device_func_write); -+ -+static int platform_i2c_dev_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ struct platform_i2c_dev_info *i2c_dev; -+ struct miscdevice *misc; -+ platform_i2c_dev_device_t *platform_i2c_dev_device; -+ -+ i2c_dev = devm_kzalloc(&pdev->dev, sizeof(struct platform_i2c_dev_info), GFP_KERNEL); -+ if (!i2c_dev) { -+ dev_err(&pdev->dev, "devm_kzalloc error. \r\n"); -+ return -ENOMEM; -+ } -+ -+ if (pdev->dev.of_node) { -+ -+ ret += of_property_read_u32(pdev->dev.of_node, "i2c_bus", &i2c_dev->i2c_bus); -+ ret += of_property_read_u32(pdev->dev.of_node, "i2c_addr", &i2c_dev->i2c_addr); -+ ret += of_property_read_string(pdev->dev.of_node, "i2c_name", &i2c_dev->name); -+ ret += of_property_read_u32(pdev->dev.of_node, "data_bus_width", &i2c_dev->data_bus_width); -+ ret += of_property_read_u32(pdev->dev.of_node, "addr_bus_width", &i2c_dev->addr_bus_width); -+ ret += of_property_read_u32(pdev->dev.of_node, "per_rd_len", &i2c_dev->per_rd_len); -+ ret += of_property_read_u32(pdev->dev.of_node, "per_wr_len", &i2c_dev->per_wr_len); -+ if (ret != 0) { -+ dev_err(&pdev->dev, "dts config error.ret:%d.\r\n", ret); -+ return -ENXIO; -+ } -+ } else { -+ if (pdev->dev.platform_data == NULL) { -+ dev_err(&pdev->dev, "Failed to get platform data config.\n"); -+ return -ENXIO; -+ } -+ platform_i2c_dev_device = pdev->dev.platform_data; -+ i2c_dev->i2c_bus = platform_i2c_dev_device->i2c_bus; -+ i2c_dev->i2c_addr = platform_i2c_dev_device->i2c_addr; -+ i2c_dev->name = platform_i2c_dev_device->i2c_name; -+ i2c_dev->data_bus_width = platform_i2c_dev_device->data_bus_width; -+ i2c_dev->addr_bus_width = platform_i2c_dev_device->addr_bus_width; -+ i2c_dev->per_rd_len = platform_i2c_dev_device->per_rd_len; -+ i2c_dev->per_wr_len = platform_i2c_dev_device->per_wr_len; -+ } -+ -+ if ((i2c_dev->per_rd_len & (i2c_dev->data_bus_width - 1)) || (i2c_dev->per_wr_len & (i2c_dev->data_bus_width - 1))) { -+ dev_err(&pdev->dev, "Invalid config per_rd_len %d per_wr_len %d data bus_width %d.\r\n", i2c_dev->per_rd_len, -+ i2c_dev->per_wr_len, i2c_dev->data_bus_width); -+ return -ENXIO; -+ } -+ -+ misc = &i2c_dev->misc; -+ misc->minor = MISC_DYNAMIC_MINOR; -+ misc->name = i2c_dev->name; -+ misc->fops = &i2c_dev_fops; -+ if (misc_register(misc) != 0) { -+ dev_err(&pdev->dev, "register %s faild.\r\n", misc->name); -+ return -ENXIO; -+ } -+ -+ if (misc->minor >= MAX_I2C_DEV_NUM) { -+ dev_err(&pdev->dev, "minor number beyond the limit! is %d.\r\n", misc->minor); -+ misc_deregister(misc); -+ return -ENXIO; -+ } -+ i2c_dev_arry[misc->minor] = i2c_dev; -+ -+ dev_info(&pdev->dev, "register %u addr_bus_width %u data_bus_width device %s with %u per_rd_len %u per_wr_len success.\r\n", -+ i2c_dev->addr_bus_width, i2c_dev->data_bus_width, i2c_dev->name, i2c_dev->per_rd_len, i2c_dev->per_wr_len); -+ -+ return 0; -+} -+ -+static int platform_i2c_dev_remove(struct platform_device *pdev) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_I2C_DEV_NUM ; i++) { -+ if (i2c_dev_arry[i] != NULL) { -+ misc_deregister(&i2c_dev_arry[i]->misc); -+ i2c_dev_arry[i] = NULL; -+ } -+ } -+ -+ return 0; -+} -+ -+static const struct of_device_id platform_i2c_dev_of_match[] = { -+ { .compatible = "wb-platform-i2c-dev" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, platform_i2c_dev_of_match); -+ -+static struct platform_driver wb_platform_i2c_dev_driver = { -+ .probe = platform_i2c_dev_probe, -+ .remove = platform_i2c_dev_remove, -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = PROXY_NAME, -+ .of_match_table = platform_i2c_dev_of_match, -+ }, -+}; -+ -+static int __init wb_platform_i2c_dev_init(void) -+{ -+ return platform_driver_register(&wb_platform_i2c_dev_driver); -+} -+ -+static void __exit wb_platform_i2c_dev_exit(void) -+{ -+ platform_driver_unregister(&wb_platform_i2c_dev_driver); -+} -+ -+module_init(wb_platform_i2c_dev_init); -+module_exit(wb_platform_i2c_dev_exit); -+ -+MODULE_DESCRIPTION("platform i2c dev driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.h -new file mode 100644 -index 000000000..b5158c9fe ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.h -@@ -0,0 +1,19 @@ -+#ifndef __WB_PLATFORM_I2C_DEV_H__ -+#define __WB_PLATFORM_I2C_DEV_H__ -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+#define I2C_DEV_NAME_MAX_LEN (64) -+ -+typedef struct platform_i2c_dev_device_s { -+ uint32_t i2c_bus; -+ uint32_t i2c_addr; -+ char i2c_name[I2C_DEV_NAME_MAX_LEN]; -+ uint32_t data_bus_width; -+ uint32_t addr_bus_width; -+ uint32_t per_rd_len; -+ uint32_t per_wr_len; -+ int device_flag; -+} platform_i2c_dev_device_t; -+ -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_93xx46.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_93xx46.c -new file mode 100644 -index 000000000..abc4f1567 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_93xx46.c -@@ -0,0 +1,111 @@ -+/* -+ * EEPROMs access control driver for display configuration EEPROMs -+ * on DigsyMTC board. -+ * -+ * (C) 2011 DENX Software Engineering, Anatolij Gustschin -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DEFAULT_SPI_BUS_NUM (0) -+#define DEFAULT_SPI_CS_NUM (0) -+#define DEFAULT_SPI_HZ (100000) -+ -+#define GPIO_EEPROM_CS (-1) -+ -+int g_wb_spi_93xx46_debug = 0; -+int g_wb_spi_93xx46_error = 0; -+int spi_bus_num = DEFAULT_SPI_BUS_NUM; -+int spi_cs_gpio = GPIO_EEPROM_CS; -+ -+module_param(g_wb_spi_93xx46_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_spi_93xx46_error, int, S_IRUGO | S_IWUSR); -+module_param(spi_bus_num, int, S_IRUGO | S_IWUSR); -+module_param(spi_cs_gpio, int, S_IRUGO | S_IWUSR); -+ -+#define SPI_93xx46_DEBUG_VERBOSE(fmt, args...) do { \ -+ if (g_wb_spi_93xx46_debug) { \ -+ printk(KERN_INFO "[SPI-93xx46][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define SPI_93xx46_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_wb_spi_93xx46_error) { \ -+ printk(KERN_ERR "[SPI-93xx46][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+struct eeprom_93xx46_platform_data eeprom_data = { -+ .flags = EE_ADDR16, -+ .quirks = EEPROM_93XX46_QUIRK_SINGLE_WORD_READ, -+}; -+ -+struct spi_board_info eeprom_93xx46_info __initdata = { -+ .modalias = "wb_93xx46", -+ .max_speed_hz = DEFAULT_SPI_HZ, -+ .bus_num = DEFAULT_SPI_BUS_NUM, -+ .chip_select = DEFAULT_SPI_CS_NUM, -+ .mode = SPI_MODE_0 | SPI_CS_HIGH, -+ .controller_data = (void *)GPIO_EEPROM_CS, -+ .platform_data = &eeprom_data, -+}; -+ -+static struct spi_device *g_spi_device; -+ -+static int __init wb_spi_93xx46_init(void) -+{ -+ struct spi_master *master; -+ -+ SPI_93xx46_DEBUG_VERBOSE("Enter.\n"); -+ -+ eeprom_93xx46_info.bus_num = spi_bus_num; -+ eeprom_93xx46_info.controller_data = (void *)(long)spi_cs_gpio; -+ master = spi_busnum_to_master(eeprom_93xx46_info.bus_num); -+ if (!master) { -+ SPI_93xx46_DEBUG_ERROR("get bus_num %u spi master failed.\n", -+ eeprom_93xx46_info.bus_num); -+ return -EINVAL; -+ } -+ -+ g_spi_device = spi_new_device(master, &eeprom_93xx46_info); -+ put_device(&master->dev); -+ if (!g_spi_device) { -+ SPI_93xx46_DEBUG_ERROR("register spi new device failed.\n"); -+ return -EPERM; -+ } -+ -+ if (g_wb_spi_93xx46_debug) { -+ dev_info(&g_spi_device->dev, "register %u bus_num spi 93xx46 eeprom success\n", -+ eeprom_93xx46_info.bus_num); -+ } -+ -+ return 0; -+} -+ -+static void __exit wb_spi_93xx46_exit(void) -+{ -+ spi_unregister_device(g_spi_device); -+ -+ if (g_wb_spi_93xx46_debug) { -+ dev_info(&g_spi_device->dev, "unregister spi 93xx46 eeprom success\n"); -+ } -+ -+ return; -+} -+ -+module_init(wb_spi_93xx46_init); -+module_exit(wb_spi_93xx46_exit); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("create 93xx46 eeprom device"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.c -new file mode 100644 -index 000000000..b569ace32 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.c -@@ -0,0 +1,684 @@ -+/* -+ * wb_spi_dev.c -+ * ko to read/write spi device through /dev/XXX device -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "wb_spi_dev.h" -+ -+#define MAX_SPI_DEV_NUM (256) -+#define MAX_RW_LEN (256) -+#define MAX_NAME_SIZE (20) -+#define MAX_ADDR_BUS_WIDTH (4) -+ -+#define TRANSFER_WRITE_BUFF (1 + MAX_ADDR_BUS_WIDTH + MAX_RW_LEN) -+ -+#define WIDTH_1Byte (1) -+#define WIDTH_2Byte (2) -+#define WIDTH_4Byte (4) -+ -+#define OP_READ (0x3) -+#define OP_WRITE (0x2) -+ -+static int g_spi_dev_debug = 0; -+static int g_spi_dev_error = 0; -+ -+module_param(g_spi_dev_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_spi_dev_error, int, S_IRUGO | S_IWUSR); -+ -+#define SPI_DEV_DEBUG(fmt, args...) do { \ -+ if (g_spi_dev_debug) { \ -+ printk(KERN_ERR "[SPI_DEV][DEBUG][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define SPI_DEV_ERROR(fmt, args...) do { \ -+ if (g_spi_dev_error) { \ -+ printk(KERN_ERR "[SPI_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static struct spi_dev_info* spi_dev_arry[MAX_SPI_DEV_NUM]; -+ -+struct spi_dev_info { -+ const char *name; -+ uint32_t data_bus_width; -+ uint32_t addr_bus_width; -+ uint32_t per_rd_len; -+ uint32_t per_wr_len; -+ uint32_t spi_len; -+ struct miscdevice misc; -+ struct spi_device *spi_device; -+}; -+ -+static int transfer_read(struct spi_dev_info *spi_dev, u8 *buf, uint32_t regaddr, size_t count) -+{ -+ int i, ret; -+ u8 tx_buf[MAX_ADDR_BUS_WIDTH + 1]; -+ struct spi_message m; -+ struct spi_transfer xfer[2]; -+ -+ i = 0; -+ mem_clear(tx_buf, sizeof(tx_buf)); -+ tx_buf[i++] = OP_READ; -+ -+ switch (spi_dev->addr_bus_width) { -+ case WIDTH_4Byte: -+ tx_buf[i++] = (regaddr >> 24) & 0xFF; -+ tx_buf[i++] = (regaddr >> 16) & 0xFF; -+ tx_buf[i++] = (regaddr >> 8) & 0xFF; -+ tx_buf[i++] = regaddr & 0xFF; -+ break; -+ case WIDTH_2Byte: -+ tx_buf[i++] = (regaddr >> 8) & 0xFF; -+ tx_buf[i++] = regaddr & 0xFF; -+ break; -+ case WIDTH_1Byte: -+ tx_buf[i++] = regaddr & 0xFF; -+ break; -+ default: -+ SPI_DEV_ERROR("Only support 1,2,4 Byte Width,but set width = %u\n", -+ spi_dev->addr_bus_width); -+ return -EINVAL; -+ } -+ -+ mem_clear(xfer, sizeof(xfer)); -+ spi_message_init(&m); -+ xfer[0].tx_buf = tx_buf; -+ xfer[0].len = spi_dev->addr_bus_width + 1; -+ spi_message_add_tail(&xfer[0], &m); -+ -+ xfer[1].rx_buf = buf; -+ xfer[1].len = count; -+ spi_message_add_tail(&xfer[1], &m); -+ -+ ret = spi_sync(spi_dev->spi_device, &m); -+ if (ret) { -+ SPI_DEV_ERROR("transfer_read failed, reg addr:0x%x, len:%lu, ret:%d.\n", -+ regaddr, count, ret); -+ return -EIO; -+ } -+ return 0; -+} -+ -+static int transfer_write(struct spi_dev_info *spi_dev, u8 *buf, uint32_t regaddr, size_t count) -+{ -+ int i, ret; -+ u8 tx_buf[TRANSFER_WRITE_BUFF]; -+ struct spi_message m; -+ struct spi_transfer xfer ; -+ -+ i = 0; -+ mem_clear(tx_buf, sizeof(tx_buf)); -+ tx_buf[i++] = OP_WRITE; -+ switch (spi_dev->addr_bus_width) { -+ case WIDTH_4Byte: -+ tx_buf[i++] = (regaddr >> 24) & 0xFF; -+ tx_buf[i++] = (regaddr >> 16) & 0xFF; -+ tx_buf[i++] = (regaddr >> 8) & 0xFF; -+ tx_buf[i++] = regaddr & 0xFF; -+ break; -+ case WIDTH_2Byte: -+ tx_buf[i++] = (regaddr >> 8) & 0xFF; -+ tx_buf[i++] = regaddr & 0xFF; -+ break; -+ case WIDTH_1Byte: -+ tx_buf[i++] = regaddr & 0xFF; -+ break; -+ default: -+ SPI_DEV_ERROR("Only support 1,2,4 Byte Width, but set width = %u\n", -+ spi_dev->addr_bus_width); -+ return -EINVAL; -+ } -+ -+ memcpy(tx_buf + i, buf, count); -+ -+ mem_clear(&xfer, sizeof(xfer)); -+ spi_message_init(&m); -+ xfer.tx_buf = tx_buf; -+ xfer.len = count + i; -+ spi_message_add_tail(&xfer, &m); -+ -+ ret = spi_sync(spi_dev->spi_device, &m); -+ if (ret) { -+ SPI_DEV_ERROR("transfer_write failed, reg addr:0x%x, len:%lu, ret:%d.\n", -+ regaddr, count, ret); -+ return -EIO; -+ } -+ return 0; -+} -+ -+static long spi_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ return 0; -+} -+ -+static int spi_dev_open(struct inode *inode, struct file *file) -+{ -+ unsigned int minor = iminor(inode); -+ struct spi_dev_info *spi_dev; -+ -+ if (minor >= MAX_SPI_DEV_NUM) { -+ SPI_DEV_ERROR("minor out of range, minor = %d.\n", minor); -+ return -ENODEV; -+ } -+ -+ spi_dev = spi_dev_arry[minor]; -+ if (spi_dev == NULL) { -+ SPI_DEV_ERROR("spi_dev is NULL, open failed, minor = %d\n", minor); -+ return -ENODEV; -+ } -+ -+ file->private_data = spi_dev; -+ -+ return 0; -+} -+ -+static int spi_dev_release(struct inode *inode, struct file *file) -+{ -+ file->private_data = NULL; -+ -+ return 0; -+} -+ -+static int device_read(struct spi_dev_info *spi_dev, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ int i, j, ret; -+ u8 val[MAX_RW_LEN]; -+ u32 data_width, rd_len, per_len, tmp; -+ u32 max_per_len; -+ -+ if (offset > spi_dev->spi_len) { -+ SPI_DEV_DEBUG("offset: 0x%x, spi len: 0x%x, count: %lu, EOF.\n", -+ offset, spi_dev->spi_len, count); -+ return 0; -+ } -+ -+ data_width = spi_dev->data_bus_width; -+ if (offset % data_width) { -+ SPI_DEV_ERROR("data bus width:%d, offset:0x%x, read size %lu invalid.\n", -+ data_width, offset, count); -+ return -EINVAL; -+ } -+ -+ if (count > (spi_dev->spi_len - offset)) { -+ SPI_DEV_DEBUG("read count out of range. input len:%lu, read len:%u.\n", -+ count, spi_dev->spi_len - offset); -+ count = spi_dev->spi_len - offset; -+ } -+ -+ if (count == 0) { -+ SPI_DEV_DEBUG("offset: 0x%x, spi len: 0x%x, read len: %lu, EOF.\n", -+ offset, spi_dev->spi_len, count); -+ return 0; -+ } -+ -+ max_per_len = spi_dev->per_rd_len; -+ tmp = (data_width - 1) & count; -+ rd_len = (tmp == 0) ? count : count + data_width - tmp; -+ per_len = (rd_len > max_per_len) ? (max_per_len) : (rd_len); -+ -+ mem_clear(val, sizeof(val)); -+ for (i = 0; i < rd_len; i += per_len) { -+ ret = transfer_read(spi_dev, val + i, offset + i, per_len); -+ if (ret < 0) { -+ SPI_DEV_ERROR("read error.read offset = %u\n", (offset + i)); -+ return -EFAULT; -+ } -+ } -+ -+ if (data_width == WIDTH_1Byte) { -+ memcpy(buf, val, count); -+ } else { -+ for (i = 0; i < count; i += data_width) { -+ for (j = 0; (j < data_width) && (i + j < count); j++) { -+ buf[i + j] = val[i + data_width - j - 1]; -+ } -+ } -+ } -+ -+ return count; -+} -+ -+static int device_write(struct spi_dev_info *spi_dev, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ int i, j, ret; -+ u32 data_width; -+ u8 val[MAX_RW_LEN]; -+ u32 wr_len, per_len, tmp; -+ u32 max_per_len; -+ -+ if (offset > spi_dev->spi_len) { -+ SPI_DEV_DEBUG("offset: 0x%x, spi len: 0x%x, count: %lu, EOF.\n", -+ offset, spi_dev->spi_len, count); -+ return 0; -+ } -+ -+ data_width = spi_dev->data_bus_width; -+ if (offset % data_width) { -+ SPI_DEV_ERROR("data bus width:%d, offset:0x%x, read size %lu invalid.\n", -+ data_width, offset, count); -+ return -EINVAL; -+ } -+ -+ if (count > (spi_dev->spi_len - offset)) { -+ SPI_DEV_DEBUG("read count out of range. input len:%lu, read len:%u.\n", -+ count, spi_dev->spi_len - offset); -+ count = spi_dev->spi_len - offset; -+ } -+ -+ if (count == 0) { -+ SPI_DEV_DEBUG("offset: 0x%x, i2c len: 0x%x, read len: %lu, EOF.\n", -+ offset, spi_dev->spi_len, count); -+ return 0; -+ } -+ -+ mem_clear(val, sizeof(val)); -+ -+ if (data_width == WIDTH_1Byte) { -+ memcpy(val, buf, count); -+ } else { -+ for (i = 0; i < count; i += data_width) { -+ for (j = 0; (j < data_width) && (i + j < count); j++) { -+ val[i + data_width - j - 1] = buf[i + j]; -+ } -+ } -+ } -+ -+ max_per_len = spi_dev->per_wr_len; -+ tmp = (data_width - 1) & count; -+ wr_len = (tmp == 0) ? count : count + data_width - tmp; -+ per_len = (wr_len > max_per_len) ? (max_per_len) : (wr_len); -+ -+ for (i = 0; i < wr_len; i += per_len) { -+ ret = transfer_write(spi_dev, val + i, offset + i, per_len); -+ if (ret < 0) { -+ SPI_DEV_ERROR("write error.offset = %u\n", (offset + i)); -+ return -EFAULT; -+ } -+ } -+ return count; -+} -+ -+static ssize_t spi_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) -+{ -+ u8 val[MAX_RW_LEN]; -+ int ret, read_len; -+ struct spi_dev_info *spi_dev; -+ -+ spi_dev = file->private_data; -+ if (spi_dev == NULL) { -+ SPI_DEV_ERROR("can't get read private_data.\n"); -+ return -EINVAL; -+ } -+ -+ if (count == 0) { -+ SPI_DEV_ERROR("Invalid params, read count is 0.\n"); -+ return -EINVAL; -+ } -+ -+ if (count > sizeof(val)) { -+ SPI_DEV_DEBUG("read count %lu exceed max %lu.\n", count, sizeof(val)); -+ count = sizeof(val); -+ } -+ -+ mem_clear(val, sizeof(val)); -+ read_len = device_read(spi_dev, (uint32_t)*offset, val, count); -+ if (read_len < 0) { -+ SPI_DEV_ERROR("spi dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", -+ spi_dev->name, (uint32_t)*offset, count); -+ return read_len; -+ } -+ -+ if (access_ok(buf, read_len)) { -+ SPI_DEV_DEBUG("user space read, buf: %p, offset: %lld, read count %lu.\n", -+ buf, *offset, count); -+ if (copy_to_user(buf, val, read_len)) { -+ SPI_DEV_ERROR("copy_to_user failed.\n"); -+ return -EFAULT; -+ } -+ } else { -+ SPI_DEV_DEBUG("kernel space read, buf: %p, offset: %lld, read count %lu.\n", -+ buf, *offset, count); -+ memcpy(buf, val, read_len); -+ } -+ -+ *offset += read_len; -+ ret = read_len; -+ return ret; -+} -+ -+static ssize_t spi_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) -+{ -+ int ret; -+ -+ SPI_DEV_DEBUG("spi_dev_read_iter, file: %p, count: %lu, offset: %lld\n", -+ iocb->ki_filp, to->count, iocb->ki_pos); -+ ret = spi_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos); -+ return ret; -+} -+ -+static ssize_t spi_dev_write(struct file *file, const char __user *buf, -+ size_t count, loff_t *offset) -+{ -+ u8 val[MAX_RW_LEN]; -+ int write_len; -+ struct spi_dev_info *spi_dev; -+ -+ spi_dev = file->private_data; -+ if (spi_dev == NULL) { -+ SPI_DEV_ERROR("get write private_data error.\n"); -+ return -EINVAL; -+ } -+ -+ if (count == 0) { -+ SPI_DEV_ERROR("Invalid params, write count is 0.\n"); -+ return -EINVAL; -+ } -+ -+ if (count > sizeof(val)) { -+ SPI_DEV_DEBUG("write count %lu exceed max %lu.\n", count, sizeof(val)); -+ count = sizeof(val); -+ } -+ -+ mem_clear(val, sizeof(val)); -+ if (access_ok(buf, count)) { -+ SPI_DEV_DEBUG("user space write, buf: %p, offset: %lld, write count %lu.\n", -+ buf, *offset, count); -+ if (copy_from_user(val, buf, count)) { -+ SPI_DEV_ERROR("copy_from_user failed.\n"); -+ return -EFAULT; -+ } -+ } else { -+ SPI_DEV_DEBUG("kernel space write, buf: %p, offset: %lld, write count %lu.\n", -+ buf, *offset, count); -+ memcpy(val, buf, count); -+ } -+ -+ write_len = device_write(spi_dev, (uint32_t)*offset, val, count); -+ if (write_len < 0) { -+ SPI_DEV_ERROR("spi dev write failed, dev name:%s, offset:0x%llx, len:%lu.\n", -+ spi_dev->name, *offset, count); -+ return write_len; -+ } -+ -+ *offset += write_len; -+ return write_len; -+} -+ -+static ssize_t spi_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) -+{ -+ int ret; -+ -+ SPI_DEV_DEBUG("spi_dev_write_iter, file: %p, count: %lu, offset: %lld\n", -+ iocb->ki_filp, from->count, iocb->ki_pos); -+ ret = spi_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos); -+ return ret; -+} -+ -+static loff_t spi_dev_llseek(struct file *file, loff_t offset, int origin) -+{ -+ loff_t ret = 0; -+ struct spi_dev_info *spi_dev; -+ -+ spi_dev = file->private_data; -+ if (spi_dev == NULL) { -+ SPI_DEV_ERROR("spi_dev is NULL, llseek failed.\n"); -+ return -EINVAL; -+ } -+ -+ switch (origin) { -+ case SEEK_SET: -+ if (offset < 0) { -+ SPI_DEV_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); -+ ret = -EINVAL; -+ break; -+ } -+ if (offset > spi_dev->spi_len) { -+ SPI_DEV_ERROR("SEEK_SET out of range, offset:%lld, i2c_len:0x%x.\n", -+ offset, spi_dev->spi_len); -+ ret = - EINVAL; -+ break; -+ } -+ file->f_pos = offset; -+ ret = file->f_pos; -+ break; -+ case SEEK_CUR: -+ if (((file->f_pos + offset) > spi_dev->spi_len) || ((file->f_pos + offset) < 0)) { -+ SPI_DEV_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld.\n", -+ file->f_pos, offset); -+ } -+ file->f_pos += offset; -+ ret = file->f_pos; -+ break; -+ default: -+ SPI_DEV_ERROR("unsupport llseek type:%d.\n", origin); -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+ -+static const struct file_operations spi_dev_fops = { -+ .owner = THIS_MODULE, -+ .llseek = spi_dev_llseek, -+ .read_iter = spi_dev_read_iter, -+ .write_iter = spi_dev_write_iter, -+ .unlocked_ioctl = spi_dev_ioctl, -+ .open = spi_dev_open, -+ .release = spi_dev_release, -+}; -+ -+static struct spi_dev_info * dev_match(const char *path) -+{ -+ struct spi_dev_info * spi_dev; -+ char dev_name[MAX_NAME_SIZE]; -+ int i; -+ for (i = 0; i < MAX_SPI_DEV_NUM; i++) { -+ if (spi_dev_arry[ i ] == NULL) { -+ continue; -+ } -+ spi_dev = spi_dev_arry[ i ]; -+ snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", spi_dev->name); -+ if (!strcmp(path, dev_name)) { -+ SPI_DEV_DEBUG("get dev_name = %s, minor = %d\n", dev_name, i); -+ return spi_dev; -+ } -+ } -+ -+ return NULL; -+} -+ -+int spi_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ struct spi_dev_info *spi_dev = NULL; -+ int ret; -+ -+ if(path == NULL){ -+ SPI_DEV_ERROR("path NULL"); -+ return -EINVAL; -+ } -+ -+ if(buf == NULL){ -+ SPI_DEV_ERROR("buf NULL"); -+ return -EINVAL; -+ } -+ -+ if (count > MAX_RW_LEN) { -+ SPI_DEV_ERROR("read count %lu, beyond max:%d.\n", count, MAX_RW_LEN); -+ return -EINVAL; -+ } -+ -+ spi_dev = dev_match(path); -+ if (spi_dev == NULL) { -+ SPI_DEV_ERROR("spi_dev match failed. dev path = %s", path); -+ return -EINVAL; -+ } -+ -+ ret = device_read(spi_dev, offset, buf, count); -+ if (ret < 0) { -+ SPI_DEV_ERROR("spi dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", -+ spi_dev->name, offset, count); -+ return -EINVAL; -+ } -+ -+ return count; -+} -+EXPORT_SYMBOL(spi_device_func_read); -+ -+int spi_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) -+{ -+ struct spi_dev_info *spi_dev = NULL; -+ int ret; -+ -+ if(path == NULL){ -+ SPI_DEV_ERROR("path NULL"); -+ return -EINVAL; -+ } -+ -+ if(buf == NULL){ -+ SPI_DEV_ERROR("buf NULL"); -+ return -EINVAL; -+ } -+ -+ if (count > MAX_RW_LEN) { -+ SPI_DEV_ERROR("write count %lu, beyond max:%d.\n", count, MAX_RW_LEN); -+ return -EINVAL; -+ } -+ -+ spi_dev = dev_match(path); -+ if (spi_dev == NULL) { -+ SPI_DEV_ERROR("i2c_dev match failed. dev path = %s", path); -+ return -EINVAL; -+ } -+ -+ ret = device_write (spi_dev, offset, buf, count); -+ if (ret < 0) { -+ SPI_DEV_ERROR("i2c dev write failed, dev name:%s, offset:0x%x, len:%lu.\n", -+ spi_dev->name, offset, count); -+ return -EINVAL; -+ } -+ -+ return count; -+} -+EXPORT_SYMBOL(spi_device_func_write); -+ -+static int spi_dev_probe(struct spi_device *spi) -+{ -+ int ret; -+ struct spi_dev_info *spi_dev; -+ struct miscdevice *misc; -+ spi_dev_device_t *spi_dev_device; -+ -+ spi_dev = devm_kzalloc(&spi->dev, sizeof(struct spi_dev_info), GFP_KERNEL); -+ if (!spi_dev) { -+ dev_err(&spi->dev, "devm_kzalloc error. \n"); -+ return -ENOMEM; -+ } -+ -+ spi_set_drvdata(spi, spi_dev); -+ spi_dev->spi_device = spi; -+ -+ if (spi->dev.of_node) { -+ -+ ret = 0; -+ ret += of_property_read_string(spi->dev.of_node, "spi_dev_name", &spi_dev->name); -+ ret += of_property_read_u32(spi->dev.of_node, "data_bus_width", &spi_dev->data_bus_width); -+ ret += of_property_read_u32(spi->dev.of_node, "addr_bus_width", &spi_dev->addr_bus_width); -+ ret += of_property_read_u32(spi->dev.of_node, "per_rd_len", &spi_dev->per_rd_len); -+ ret += of_property_read_u32(spi->dev.of_node, "per_wr_len", &spi_dev->per_wr_len); -+ ret += of_property_read_u32(spi->dev.of_node, "spi_len", &spi_dev->spi_len); -+ if (ret != 0) { -+ dev_err(&spi->dev, "dts config error.ret:%d.\n", ret); -+ return -ENXIO; -+ } -+ } else { -+ if (spi->dev.platform_data == NULL) { -+ dev_err(&spi->dev, "Failed to get platform data config.\n"); -+ return -ENXIO; -+ } -+ spi_dev_device = spi->dev.platform_data; -+ spi_dev->name = spi_dev_device->spi_dev_name; -+ spi_dev->data_bus_width = spi_dev_device->data_bus_width; -+ spi_dev->addr_bus_width = spi_dev_device->addr_bus_width; -+ spi_dev->per_rd_len = spi_dev_device->per_rd_len; -+ spi_dev->per_wr_len = spi_dev_device->per_wr_len; -+ spi_dev->spi_len = spi_dev_device->spi_len; -+ } -+ -+ if ((spi_dev->per_rd_len & (spi_dev->data_bus_width - 1)) -+ || (spi_dev->per_wr_len & (spi_dev->data_bus_width - 1))) { -+ dev_err(&spi->dev, "Invalid config per_rd_len [%u] per_wr_len [%u] data bus_width [%u], addr bus width [%u].\n", -+ spi_dev->per_rd_len, spi_dev->per_wr_len, spi_dev->data_bus_width, spi_dev->addr_bus_width); -+ return -ENXIO; -+ } -+ -+ misc = &spi_dev->misc; -+ misc->minor = MISC_DYNAMIC_MINOR; -+ misc->name = spi_dev->name; -+ misc->fops = &spi_dev_fops; -+ misc->mode = 0666; -+ if (misc_register(misc) != 0) { -+ dev_err(&spi->dev, "register %s faild.\n", misc->name); -+ return -ENXIO; -+ } -+ -+ if (misc->minor >= MAX_SPI_DEV_NUM) { -+ dev_err(&spi->dev, "minor number beyond the limit! is %d.\n", misc->minor); -+ misc_deregister(misc); -+ return -ENXIO; -+ } -+ spi_dev_arry[misc->minor] = spi_dev; -+ -+ dev_info(&spi->dev, "register %u data_bus_width %u addr_bus_witdh 0x%x spi_len device %s with %u per_rd_len %u per_wr_len success.\n", -+ spi_dev->data_bus_width, spi_dev->addr_bus_width, spi_dev->spi_len, spi_dev->name, spi_dev->per_rd_len, spi_dev->per_wr_len); -+ -+ return 0; -+} -+ -+static int spi_dev_remove(struct spi_device *spi) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_SPI_DEV_NUM; i++) { -+ if (spi_dev_arry[i] != NULL) { -+ misc_deregister(&spi_dev_arry[i]->misc); -+ spi_dev_arry[i] = NULL; -+ } -+ } -+ return 0; -+} -+ -+static const struct of_device_id spi_dev_of_match[] = { -+ { .compatible = "wb-spi-dev" }, -+ { }, -+}; -+ -+MODULE_DEVICE_TABLE(of, spi_dev_of_match); -+ -+static struct spi_driver spi_dev_driver = { -+ .driver = { -+ .name = "wb-spi-dev", -+ .of_match_table = of_match_ptr(spi_dev_of_match), -+ }, -+ .probe = spi_dev_probe, -+ .remove = spi_dev_remove, -+}; -+ -+module_spi_driver(spi_dev_driver); -+ -+MODULE_DESCRIPTION("spi dev driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.h -new file mode 100644 -index 000000000..fed5237e3 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.h -@@ -0,0 +1,17 @@ -+#ifndef __WB_SPI_DEV_H__ -+#define __WB_SPI_DEV_H__ -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+#define SPI_DEV_NAME_MAX_LEN (64) -+ -+typedef struct spi_dev_device_s { -+ char spi_dev_name[SPI_DEV_NAME_MAX_LEN]; -+ uint32_t data_bus_width; -+ uint32_t addr_bus_width; -+ uint32_t per_rd_len; -+ uint32_t per_wr_len; -+ uint32_t spi_len; -+} spi_dev_device_t; -+ -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio.c -new file mode 100644 -index 000000000..16408f067 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio.c -@@ -0,0 +1,477 @@ -+/* -+ * SPI master driver using generic bitbanged GPIO -+ * -+ * Copyright (C) 2006,2008 David Brownell -+ * Copyright (C) 2017 Linus Walleij -+ * -+ * 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. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+/* -+ * This bitbanging SPI master driver should help make systems usable -+ * when a native hardware SPI engine is not available, perhaps because -+ * its driver isn't yet working or because the I/O pins it requires -+ * are used for other purposes. -+ * -+ * platform_device->driver_data ... points to spi_gpio -+ * -+ * spi->controller_state ... reserved for bitbang framework code -+ * spi->controller_data ... holds chipselect GPIO -+ * -+ * spi->master->dev.driver_data ... points to spi_gpio->bitbang -+ */ -+ -+struct spi_gpio { -+ struct spi_bitbang bitbang; -+ struct spi_gpio_platform_data pdata; -+ struct platform_device *pdev; -+ struct gpio_desc *sck; -+ struct gpio_desc *miso; -+ struct gpio_desc *mosi; -+ struct gpio_desc **cs_gpios; -+ bool has_cs; -+}; -+ -+/*----------------------------------------------------------------------*/ -+ -+/* -+ * Because the overhead of going through four GPIO procedure calls -+ * per transferred bit can make performance a problem, this code -+ * is set up so that you can use it in either of two ways: -+ * -+ * - The slow generic way: set up platform_data to hold the GPIO -+ * numbers used for MISO/MOSI/SCK, and issue procedure calls for -+ * each of them. This driver can handle several such busses. -+ * -+ * - The quicker inlined way: only helps with platform GPIO code -+ * that inlines operations for constant GPIOs. This can give -+ * you tight (fast!) inner loops, but each such bus needs a -+ * new driver. You'll define a new C file, with Makefile and -+ * Kconfig support; the C code can be a total of six lines: -+ * -+ * #define DRIVER_NAME "myboard_spi2" -+ * #define SPI_MISO_GPIO 119 -+ * #define SPI_MOSI_GPIO 120 -+ * #define SPI_SCK_GPIO 121 -+ * #define SPI_N_CHIPSEL 4 -+ * #include "spi-gpio.c" -+ */ -+ -+#ifndef DRIVER_NAME -+#define DRIVER_NAME "wb_spi_gpio" -+ -+#define GENERIC_BITBANG /* vs tight inlines */ -+ -+#endif -+ -+/*----------------------------------------------------------------------*/ -+ -+static inline struct spi_gpio *__pure -+spi_to_spi_gpio(const struct spi_device *spi) -+{ -+ const struct spi_bitbang *bang; -+ struct spi_gpio *spi_gpio; -+ -+ bang = spi_master_get_devdata(spi->master); -+ spi_gpio = container_of(bang, struct spi_gpio, bitbang); -+ return spi_gpio; -+} -+ -+static inline struct spi_gpio_platform_data *__pure -+spi_to_pdata(const struct spi_device *spi) -+{ -+ return &spi_to_spi_gpio(spi)->pdata; -+} -+ -+/* These helpers are in turn called by the bitbang inlines */ -+static inline void setsck(const struct spi_device *spi, int is_on) -+{ -+ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); -+ -+ gpiod_set_value_cansleep(spi_gpio->sck, is_on); -+} -+ -+static inline void setmosi(const struct spi_device *spi, int is_on) -+{ -+ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); -+ -+ gpiod_set_value_cansleep(spi_gpio->mosi, is_on); -+} -+ -+static inline int getmiso(const struct spi_device *spi) -+{ -+ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); -+ -+ if (spi->mode & SPI_3WIRE) -+ return !!gpiod_get_value_cansleep(spi_gpio->mosi); -+ else -+ return !!gpiod_get_value_cansleep(spi_gpio->miso); -+} -+ -+/* -+ * NOTE: this clocks "as fast as we can". It "should" be a function of the -+ * requested device clock. Software overhead means we usually have trouble -+ * reaching even one Mbit/sec (except when we can inline bitops), so for now -+ * we'll just assume we never need additional per-bit slowdowns. -+ */ -+#define spidelay(nsecs) do {} while (0) -+ -+#include "spi-bitbang-txrx.h" -+ -+/* -+ * These functions can leverage inline expansion of GPIO calls to shrink -+ * costs for a txrx bit, often by factors of around ten (by instruction -+ * count). That is particularly visible for larger word sizes, but helps -+ * even with default 8-bit words. -+ * -+ * REVISIT overheads calling these functions for each word also have -+ * significant performance costs. Having txrx_bufs() calls that inline -+ * the txrx_word() logic would help performance, e.g. on larger blocks -+ * used with flash storage or MMC/SD. There should also be ways to make -+ * GCC be less stupid about reloading registers inside the I/O loops, -+ * even without inlined GPIO calls; __attribute__((hot)) on GCC 4.3? -+ */ -+ -+static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi, -+ unsigned nsecs, u32 word, u8 bits, unsigned flags) -+{ -+ return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits); -+} -+ -+static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi, -+ unsigned nsecs, u32 word, u8 bits, unsigned flags) -+{ -+ return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits); -+} -+ -+static u32 spi_gpio_txrx_word_mode2(struct spi_device *spi, -+ unsigned nsecs, u32 word, u8 bits, unsigned flags) -+{ -+ return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits); -+} -+ -+static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi, -+ unsigned nsecs, u32 word, u8 bits, unsigned flags) -+{ -+ return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits); -+} -+ -+/* -+ * These functions do not call setmosi or getmiso if respective flag -+ * (SPI_MASTER_NO_RX or SPI_MASTER_NO_TX) is set, so they are safe to -+ * call when such pin is not present or defined in the controller. -+ * A separate set of callbacks is defined to get highest possible -+ * speed in the generic case (when both MISO and MOSI lines are -+ * available), as optimiser will remove the checks when argument is -+ * constant. -+ */ -+ -+static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi, -+ unsigned nsecs, u32 word, u8 bits, unsigned flags) -+{ -+ flags = spi->master->flags; -+ return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits); -+} -+ -+static u32 spi_gpio_spec_txrx_word_mode1(struct spi_device *spi, -+ unsigned nsecs, u32 word, u8 bits, unsigned flags) -+{ -+ flags = spi->master->flags; -+ return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits); -+} -+ -+static u32 spi_gpio_spec_txrx_word_mode2(struct spi_device *spi, -+ unsigned nsecs, u32 word, u8 bits, unsigned flags) -+{ -+ flags = spi->master->flags; -+ return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits); -+} -+ -+static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi, -+ unsigned nsecs, u32 word, u8 bits, unsigned flags) -+{ -+ flags = spi->master->flags; -+ return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits); -+} -+ -+/*----------------------------------------------------------------------*/ -+ -+static void spi_gpio_chipselect(struct spi_device *spi, int is_active) -+{ -+ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); -+ -+ /* set initial clock line level */ -+ if (is_active) -+ gpiod_set_value_cansleep(spi_gpio->sck, spi->mode & SPI_CPOL); -+ -+ /* Drive chip select line, if we have one */ -+ if (spi_gpio->has_cs) { -+ struct gpio_desc *cs = spi_gpio->cs_gpios[spi->chip_select]; -+ -+ /* SPI chip selects are normally active-low */ -+ gpiod_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active); -+ } -+} -+ -+static int spi_gpio_setup(struct spi_device *spi) -+{ -+ struct gpio_desc *cs; -+ int status = 0; -+ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); -+ -+ /* -+ * The CS GPIOs have already been -+ * initialized from the descriptor lookup. -+ */ -+ cs = spi_gpio->cs_gpios[spi->chip_select]; -+ if (!spi->controller_state && cs) -+ status = gpiod_direction_output(cs, -+ !(spi->mode & SPI_CS_HIGH)); -+ -+ if (!status) -+ status = spi_bitbang_setup(spi); -+ -+ return status; -+} -+ -+static int spi_gpio_set_direction(struct spi_device *spi, bool output) -+{ -+ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); -+ -+ if (output) -+ return gpiod_direction_output(spi_gpio->mosi, 1); -+ else -+ return gpiod_direction_input(spi_gpio->mosi); -+} -+ -+static void spi_gpio_cleanup(struct spi_device *spi) -+{ -+ spi_bitbang_cleanup(spi); -+} -+ -+/* -+ * It can be convenient to use this driver with pins that have alternate -+ * functions associated with a "native" SPI controller if a driver for that -+ * controller is not available, or is missing important functionality. -+ * -+ * On platforms which can do so, configure MISO with a weak pullup unless -+ * there's an external pullup on that signal. That saves power by avoiding -+ * floating signals. (A weak pulldown would save power too, but many -+ * drivers expect to see all-ones data as the no slave "response".) -+ */ -+static int spi_gpio_request(struct device *dev, -+ struct spi_gpio *spi_gpio, -+ unsigned int num_chipselects, -+ u16 *mflags) -+{ -+ int i; -+ -+ spi_gpio->mosi = devm_gpiod_get_optional(dev, "mosi", GPIOD_OUT_LOW); -+ if (IS_ERR(spi_gpio->mosi)) -+ return PTR_ERR(spi_gpio->mosi); -+ if (!spi_gpio->mosi) -+ /* HW configuration without MOSI pin */ -+ *mflags |= SPI_MASTER_NO_TX; -+ -+ spi_gpio->miso = devm_gpiod_get_optional(dev, "miso", GPIOD_IN); -+ if (IS_ERR(spi_gpio->miso)) -+ return PTR_ERR(spi_gpio->miso); -+ /* -+ * No setting SPI_MASTER_NO_RX here - if there is only a MOSI -+ * pin connected the host can still do RX by changing the -+ * direction of the line. -+ */ -+ -+ spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW); -+ if (IS_ERR(spi_gpio->sck)) -+ return PTR_ERR(spi_gpio->sck); -+ -+ for (i = 0; i < num_chipselects; i++) { -+ spi_gpio->cs_gpios[i] = devm_gpiod_get_index(dev, "cs", -+ i, GPIOD_OUT_HIGH); -+ if (IS_ERR(spi_gpio->cs_gpios[i])) -+ return PTR_ERR(spi_gpio->cs_gpios[i]); -+ } -+ -+ return 0; -+} -+ -+#ifdef CONFIG_OF -+static const struct of_device_id spi_gpio_dt_ids[] = { -+ { .compatible = "wb-spi-gpio" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids); -+ -+static int spi_gpio_probe_dt(struct platform_device *pdev) -+{ -+ int ret; -+ u32 tmp; -+ struct spi_gpio_platform_data *pdata; -+ struct device_node *np = pdev->dev.of_node; -+ const struct of_device_id *of_id = -+ of_match_device(spi_gpio_dt_ids, &pdev->dev); -+ -+ if (!of_id) -+ return 0; -+ -+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); -+ if (!pdata) -+ return -ENOMEM; -+ -+ ret = of_property_read_u32(np, "num-chipselects", &tmp); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "num-chipselects property not found\n"); -+ goto error_free; -+ } -+ -+ pdata->num_chipselect = tmp; -+ pdev->dev.platform_data = pdata; -+ -+ return 1; -+ -+error_free: -+ devm_kfree(&pdev->dev, pdata); -+ return ret; -+} -+#else -+static inline int spi_gpio_probe_dt(struct platform_device *pdev) -+{ -+ return 0; -+} -+#endif -+ -+static int spi_gpio_probe(struct platform_device *pdev) -+{ -+ int status; -+ struct spi_master *master; -+ struct spi_gpio *spi_gpio; -+ struct spi_gpio_platform_data *pdata; -+ u16 master_flags = 0; -+ bool use_of = 0; -+ -+ status = spi_gpio_probe_dt(pdev); -+ if (status < 0) -+ return status; -+ if (status > 0) -+ use_of = 1; -+ -+ pdata = dev_get_platdata(&pdev->dev); -+#ifdef GENERIC_BITBANG -+ if (!pdata || (!use_of && !pdata->num_chipselect)) -+ return -ENODEV; -+#endif -+ -+ master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio)); -+ if (!master) -+ return -ENOMEM; -+ -+ spi_gpio = spi_master_get_devdata(master); -+ -+ spi_gpio->cs_gpios = devm_kcalloc(&pdev->dev, -+ pdata->num_chipselect, -+ sizeof(*spi_gpio->cs_gpios), -+ GFP_KERNEL); -+ if (!spi_gpio->cs_gpios) -+ return -ENOMEM; -+ -+ platform_set_drvdata(pdev, spi_gpio); -+ -+ /* Determine if we have chip selects connected */ -+ spi_gpio->has_cs = !!pdata->num_chipselect; -+ -+ spi_gpio->pdev = pdev; -+ if (pdata) -+ spi_gpio->pdata = *pdata; -+ -+ status = spi_gpio_request(&pdev->dev, spi_gpio, -+ pdata->num_chipselect, &master_flags); -+ if (status) -+ return status; -+ -+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); -+ master->mode_bits = SPI_3WIRE | SPI_CPHA | SPI_CPOL | SPI_CS_HIGH; -+ master->flags = master_flags; -+ master->bus_num = pdev->id; -+ /* The master needs to think there is a chipselect even if not connected */ -+ master->num_chipselect = spi_gpio->has_cs ? pdata->num_chipselect : 1; -+ master->setup = spi_gpio_setup; -+ master->cleanup = spi_gpio_cleanup; -+ -+ if (pdev->dev.of_node) { -+ master->dev.of_node = pdev->dev.of_node; -+ } -+ -+ spi_gpio->bitbang.master = master; -+ spi_gpio->bitbang.chipselect = spi_gpio_chipselect; -+ spi_gpio->bitbang.set_line_direction = spi_gpio_set_direction; -+ -+ if ((master_flags & SPI_MASTER_NO_TX) == 0) { -+ spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0; -+ spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1; -+ spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2; -+ spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_word_mode3; -+ } else { -+ spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0; -+ spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_spec_txrx_word_mode1; -+ spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_spec_txrx_word_mode2; -+ spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_spec_txrx_word_mode3; -+ } -+ spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer; -+ -+ status = spi_bitbang_start(&spi_gpio->bitbang); -+ if (status) -+ spi_master_put(master); -+ -+ return status; -+} -+ -+static int spi_gpio_remove(struct platform_device *pdev) -+{ -+ struct spi_gpio *spi_gpio; -+ struct spi_gpio_platform_data *pdata; -+ -+ spi_gpio = platform_get_drvdata(pdev); -+ pdata = dev_get_platdata(&pdev->dev); -+ -+ /* stop() unregisters child devices too */ -+ spi_bitbang_stop(&spi_gpio->bitbang); -+ -+ spi_master_put(spi_gpio->bitbang.master); -+ -+ return 0; -+} -+ -+MODULE_ALIAS("platform:" DRIVER_NAME); -+ -+static struct platform_driver spi_gpio_driver = { -+ .driver = { -+ .name = DRIVER_NAME, -+ .of_match_table = of_match_ptr(spi_gpio_dt_ids), -+ }, -+ .probe = spi_gpio_probe, -+ .remove = spi_gpio_remove, -+}; -+module_platform_driver(spi_gpio_driver); -+ -+MODULE_DESCRIPTION("SPI master driver using generic bitbanged GPIO "); -+MODULE_AUTHOR("support"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio_device.c -new file mode 100644 -index 000000000..b073dac08 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio_device.c -@@ -0,0 +1,163 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+ -+#define DEFAULT_GPIO_SCK (67) -+#define DEFAULT_GPIO_MISO (32) -+#define DEFAULT_GPIO_MOSI (65) -+#define DEFAULT_GPIO_CS (6) -+#define DEFAULT_SPI_BUS (0) -+ -+static int sck = DEFAULT_GPIO_SCK; -+module_param(sck, int, S_IRUGO | S_IWUSR); -+ -+static int miso = DEFAULT_GPIO_MISO; -+module_param(miso, int, S_IRUGO | S_IWUSR); -+ -+static int mosi = DEFAULT_GPIO_MOSI; -+module_param(mosi, int, S_IRUGO | S_IWUSR); -+ -+static int cs = DEFAULT_GPIO_CS; -+module_param(cs, int, S_IRUGO | S_IWUSR); -+ -+static int bus = DEFAULT_SPI_BUS; -+module_param(bus, int, S_IRUGO | S_IWUSR); -+ -+static int g_wb_spi_gpio_device_debug = 0; -+static int g_wb_spi_gpio_device_error = 0; -+ -+module_param(g_wb_spi_gpio_device_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_spi_gpio_device_error, int, S_IRUGO | S_IWUSR); -+ -+static char gpiod_lookup_table_devid[64]; -+ -+static char *gpio_chip_name = NULL; -+module_param(gpio_chip_name, charp, 0644); -+MODULE_PARM_DESC(str_var, "A string variable for GPIO controller"); -+ -+#define WB_SPI_GPIO_DEVICE_VERBOSE(fmt, args...) do { \ -+ if (g_wb_spi_gpio_device_debug) { \ -+ printk(KERN_INFO "[WB_SPI_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_SPI_GPIO_DEVICE_ERROR(fmt, args...) do { \ -+ if (g_wb_spi_gpio_device_error) { \ -+ printk(KERN_ERR "[WB_SPI_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static struct gpiod_lookup_table wb_spi_gpio_table = { -+ .table = { -+ GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_SCK, -+ "sck", GPIO_ACTIVE_HIGH), -+ GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_MOSI, -+ "mosi", GPIO_ACTIVE_HIGH), -+ GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_MISO, -+ "miso", GPIO_ACTIVE_HIGH), -+ GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_CS, -+ "cs", GPIO_ACTIVE_HIGH), -+ { }, -+ }, -+}; -+ -+static struct spi_gpio_platform_data spi_pdata = { -+ .num_chipselect = 1, -+}; -+ -+static void spi_gpio_release(struct device *dev) -+{ -+ return; -+} -+ -+static struct platform_device wb_spi_gpio_device = { -+ .name = "wb_spi_gpio", -+ .num_resources = 0, -+ .id = -1, -+ -+ .dev = { -+ .platform_data = &spi_pdata, -+ .release = spi_gpio_release, -+ } -+}; -+ -+static void wb_spi_gpio_table_devid_name_set(void) { -+ int size; -+ -+ size = sizeof(gpiod_lookup_table_devid); -+ wb_spi_gpio_device.id = bus; -+ -+ mem_clear(gpiod_lookup_table_devid, size); -+ switch (bus) { -+ case PLATFORM_DEVID_NONE: -+ snprintf(gpiod_lookup_table_devid, size, "%s", wb_spi_gpio_device.name); -+ break; -+ case PLATFORM_DEVID_AUTO: -+ snprintf(gpiod_lookup_table_devid, size, "%s.%d.auto", wb_spi_gpio_device.name, bus); -+ break; -+ default: -+ snprintf(gpiod_lookup_table_devid, size, "%s.%d", wb_spi_gpio_device.name, bus); -+ break; -+ } -+ -+ wb_spi_gpio_table.dev_id = gpiod_lookup_table_devid; -+ return ; -+} -+static int __init wb_spi_gpio_device_init(void) -+{ -+ int err; -+ struct gpiod_lookup *p; -+ -+ WB_SPI_GPIO_DEVICE_VERBOSE("enter!\n"); -+ wb_spi_gpio_table.table[0].chip_hwnum = sck; -+ wb_spi_gpio_table.table[1].chip_hwnum = mosi; -+ wb_spi_gpio_table.table[2].chip_hwnum = miso; -+ wb_spi_gpio_table.table[3].chip_hwnum = cs; -+ if (gpio_chip_name) { -+ wb_spi_gpio_table.table[0].key = gpio_chip_name; -+ wb_spi_gpio_table.table[1].key = gpio_chip_name; -+ wb_spi_gpio_table.table[2].key = gpio_chip_name; -+ wb_spi_gpio_table.table[3].key = gpio_chip_name; -+ } -+ wb_spi_gpio_table_devid_name_set(); -+ WB_SPI_GPIO_DEVICE_VERBOSE("spi gpi device table bus[%d] dev id[%s]\n", bus, wb_spi_gpio_table.dev_id); -+ for (p = &wb_spi_gpio_table.table[0]; p->key; p++) { -+ WB_SPI_GPIO_DEVICE_VERBOSE("con_id:%s gpio:%d\n", p->con_id, p->chip_hwnum); -+ } -+ -+ gpiod_add_lookup_table(&wb_spi_gpio_table); -+ err = platform_device_register(&wb_spi_gpio_device); -+ if (err < 0) { -+ printk(KERN_ERR "register spi gpio device fail(%d). \n", err); -+ gpiod_remove_lookup_table(&wb_spi_gpio_table); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static void __exit wb_spi_gpio_device_exit(void) -+{ -+ WB_SPI_GPIO_DEVICE_VERBOSE("enter!\n"); -+ platform_device_unregister(&wb_spi_gpio_device); -+ gpiod_remove_lookup_table(&wb_spi_gpio_table); -+} -+ -+module_init(wb_spi_gpio_device_init); -+module_exit(wb_spi_gpio_device_exit); -+MODULE_DESCRIPTION("SPI GPIO Devices"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_nor_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_nor_device.c -new file mode 100644 -index 000000000..4196601f7 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_nor_device.c -@@ -0,0 +1,87 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* The SPI Bus number that the device is mounted on can be specified manually when this module is loaded */ -+#define DEFAULT_SPI_BUS_NUM (0) -+#define DEFAULT_SPI_CS_NUM (0) -+#define DEFAULT_SPI_HZ (100000) -+ -+int g_wb_spi_nor_dev_debug = 0; -+int g_wb_spi_nor_dev_error = 0; -+int spi_bus_num = DEFAULT_SPI_BUS_NUM; -+ -+module_param(g_wb_spi_nor_dev_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_spi_nor_dev_error, int, S_IRUGO | S_IWUSR); -+module_param(spi_bus_num, int, S_IRUGO | S_IWUSR); -+ -+#define SPI_NOR_DEV_DEBUG_VERBOSE(fmt, args...) do { \ -+ if (g_wb_spi_nor_dev_debug) { \ -+ printk(KERN_INFO "[SPI_NOR_DEV][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define SPI_NOR_DEV_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_wb_spi_nor_dev_error) { \ -+ printk(KERN_ERR "[SPI_NOR_DEV][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+struct spi_board_info spi_nor_device_info __initdata= { -+ .modalias = "mx25l6405d", -+ .bus_num = DEFAULT_SPI_BUS_NUM, -+ .chip_select = DEFAULT_SPI_CS_NUM, -+ .max_speed_hz = 10 * 1000 * 1000, -+}; -+ -+static struct spi_device *g_spi_device; -+ -+static int __init wb_spi_nor_dev_init(void) -+{ -+ struct spi_master *master; -+ -+ SPI_NOR_DEV_DEBUG_VERBOSE("Enter.\n"); -+ -+ spi_nor_device_info.bus_num = spi_bus_num; -+ master = spi_busnum_to_master(spi_nor_device_info.bus_num); /* Get the controller according to the SPI Bus number */ -+ if (!master) { -+ SPI_NOR_DEV_DEBUG_ERROR("get bus_num %u spi master failed.\n", -+ spi_nor_device_info.bus_num); -+ return -EINVAL; -+ } -+ -+ g_spi_device = spi_new_device(master, &spi_nor_device_info); -+ put_device(&master->dev); -+ if (!g_spi_device) { -+ SPI_NOR_DEV_DEBUG_ERROR("register spi new device failed.\n"); -+ return -EPERM; -+ } -+ -+ if (g_wb_spi_nor_dev_debug) { -+ dev_info(&g_spi_device->dev, "register %u bus_num spi nor device success\n", -+ spi_nor_device_info.bus_num); -+ } -+ -+ return 0; -+} -+ -+static void __exit wb_spi_nor_dev_exit(void) -+{ -+ spi_unregister_device(g_spi_device); -+ -+ if (g_wb_spi_nor_dev_debug) { -+ dev_info(&g_spi_device->dev, "unregister spi nor device success\n"); -+ } -+ -+ return; -+} -+ -+module_init(wb_spi_nor_dev_init); -+module_exit(wb_spi_nor_dev_exit); -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("create spi nor device"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.c -new file mode 100644 -index 000000000..a709427c5 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.c -@@ -0,0 +1,1025 @@ -+/* -+ * wb_spi_ocores.c -+ * ko to create ocores spi adapter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "wb_spi_ocores.h" -+ -+#define SPIOC_WAIT_SCH (5) -+#define SPIOC_CONF (0x00) -+#define SPIOC_LSBF BIT(0) /* 0:MSB 1:LSB */ -+#define SPIOC_IDLE_LOW BIT(1) -+#define SPIOC_INTREN BIT(2) /* 0:enable 1:disabel */ -+#define SPIOC_DIV_MASK (0xf0) -+#define SPIOC_MAX_DIV (0x0E) -+#define SPIOC_DIV(div) (((div) & 0x0f) << 4) -+ -+#define SPIOC_STS (0x01) -+#define SPIOC_INTR_STS BIT(0) -+#define SPIOC_BUSY_STS BIT(1) -+#define SPIOC_RXNUM_SHIFT (4) -+#define SPIOC_RXNUM_MASK (0xf << SPIOC_RXNUM_SHIFT) -+/* Just for read */ -+#define SPIOC_RXNUM(reg) (((reg) & SPIOC_RXNUM_MASK) >> SPIOC_RXNUM_SHIFT ) -+ -+#define SPIOC_TXTOT_NUM (0x02) -+#define SPIOC_TXNUM(reg) ((reg) & 0x0f) -+#define SPIOC_TOTNUM(reg) (((reg) & 0x0f) << 4) -+ -+#define SPIOC_TXCTL (0x03) -+#define SPIOC_CSLV BIT(0) /* 0:Deassert SPICS 1:Laeve SPICS */ -+#define SPIOC_TRSTART BIT(1) -+#define SPIOC_CSID_SHIFT (5) -+#define SPIOC_CSID_MASK (0x7 << SPIOC_CSID_SHIFT) -+/* Just for write */ -+#define SPIOC_CSID(id) (((id) << SPIOC_CSID_SHIFT) & SPIOC_CSID_MASK) -+ -+/* Just single byte */ -+#define SPIOC_RX(i) ((0x4) + i) -+#define SPIOC_TX(i) ((0x4) + i) -+ -+#define SPIOC_MAX_LEN ((unsigned int)8) -+#define SPIOC_TXRX_MAX_LEN ((unsigned int)7) -+ -+#define MODEBITS (SPI_CPHA |SPI_CPOL | SPI_LSB_FIRST |SPI_CS_HIGH) -+ -+#define REG_IO_WIDTH_1 (1) -+#define REG_IO_WIDTH_2 (2) -+#define REG_IO_WIDTH_4 (4) -+ -+#define SYMBOL_I2C_DEV_MODE (1) -+#define FILE_MODE (2) -+#define SYMBOL_PCIE_DEV_MODE (3) -+#define SYMBOL_IO_DEV_MODE (4) -+ -+int g_spi_oc_debug = 0; -+int g_spi_oc_error = 0; -+ -+module_param(g_spi_oc_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_spi_oc_error, int, S_IRUGO | S_IWUSR); -+ -+#define SPI_OC_VERBOSE(fmt, args...) do { \ -+ if (g_spi_oc_debug) { \ -+ printk(KERN_INFO "[OC_SPI_BUS][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define SPI_OC_ERROR(fmt, args...) do { \ -+ if (g_spi_oc_error) { \ -+ printk(KERN_ERR "[OC_SPI_BUS][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+struct spioc { -+ /* bitbang has to be first */ -+ struct spi_bitbang bitbang; -+ int irq; -+ struct completion done; -+ unsigned int reamin_len; -+ unsigned int cur_pos; -+ unsigned int cur_len; -+ const u8 *txp; -+ u8 *rxp; -+ u8 chip_select; -+ void (*setreg)(struct spioc *spioc, int reg, u32 value); -+ u32 (*getreg)(struct spioc *spioc, int reg); -+ uint32_t bus_num; -+ const char *dev_name; -+ uint32_t reg_access_mode; -+ uint32_t base_addr; -+ uint32_t reg_shift; -+ uint32_t reg_io_width; -+ uint32_t num_chipselect; -+ uint32_t freq; -+ uint32_t big_endian; -+ struct device *dev; -+ int transfer_busy_flag; -+}; -+ -+extern int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+ -+static int oc_spi_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) -+{ -+ int ret; -+ struct file *filp; -+ loff_t tmp_pos; -+ -+ filp = filp_open(path, O_RDONLY, 0); -+ if (IS_ERR(filp)) { -+ SPI_OC_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); -+ filp = NULL; -+ goto exit; -+ } -+ -+ tmp_pos = (loff_t)pos; -+ ret = kernel_read(filp, val, size, &tmp_pos); -+ if (ret < 0) { -+ SPI_OC_ERROR("kernel_read failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); -+ goto exit; -+ } -+ -+ filp_close(filp, NULL); -+ -+ return ret; -+ -+exit: -+ if (filp != NULL) { -+ filp_close(filp, NULL); -+ } -+ -+ return -1; -+} -+ -+static int oc_spi_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) -+{ -+ -+ int ret; -+ struct file *filp; -+ loff_t tmp_pos; -+ -+ filp = filp_open(path, O_RDWR, 777); -+ if (IS_ERR(filp)) { -+ SPI_OC_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); -+ filp = NULL; -+ goto exit; -+ } -+ -+ tmp_pos = (loff_t)pos; -+ ret = kernel_write(filp, val, size, &tmp_pos); -+ if (ret < 0) { -+ SPI_OC_ERROR("kernel_write failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); -+ goto exit; -+ } -+ -+ vfs_fsync(filp, 1); -+ filp_close(filp, NULL); -+ -+ return ret; -+ -+exit: -+ if (filp != NULL) { -+ filp_close(filp, NULL); -+ } -+ -+ return -1; -+} -+ -+static int oc_spi_reg_write(struct spioc *spioc, uint32_t pos, uint8_t *val, size_t size) -+{ -+ int ret; -+ -+ switch (spioc->reg_access_mode) { -+ case SYMBOL_I2C_DEV_MODE: -+ ret = i2c_device_func_write(spioc->dev_name, pos, val, size); -+ break; -+ case FILE_MODE: -+ ret = oc_spi_file_write(spioc->dev_name, pos, val, size); -+ break; -+ case SYMBOL_PCIE_DEV_MODE: -+ ret = pcie_device_func_write(spioc->dev_name, pos, val, size); -+ break; -+ case SYMBOL_IO_DEV_MODE: -+ ret = io_device_func_write(spioc->dev_name, pos, val, size); -+ break; -+ default: -+ SPI_OC_ERROR("err func_mode, write failed.\n"); -+ return -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static int oc_spi_reg_read(struct spioc *spioc, uint32_t pos, uint8_t *val, size_t size) -+{ -+ int ret; -+ -+ switch (spioc->reg_access_mode) { -+ case SYMBOL_I2C_DEV_MODE: -+ ret = i2c_device_func_read(spioc->dev_name, pos, val, size); -+ break; -+ case FILE_MODE: -+ ret = oc_spi_file_read(spioc->dev_name, pos, val, size); -+ break; -+ case SYMBOL_PCIE_DEV_MODE: -+ ret = pcie_device_func_read(spioc->dev_name, pos, val, size); -+ break; -+ case SYMBOL_IO_DEV_MODE: -+ ret = io_device_func_read(spioc->dev_name, pos, val, size); -+ break; -+ default: -+ SPI_OC_ERROR("err func_mode, read failed.\n"); -+ return -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static void oc_spi_setreg_8(struct spioc *spioc, int reg, u32 value) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_1]; -+ u32 pos; -+ -+ pos = spioc->base_addr + (reg << spioc->reg_shift); -+ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ spioc->dev_name, spioc->reg_access_mode, pos, value); -+ -+ buf_tmp[0] = (value & 0Xff); -+ oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_1); -+ return; -+} -+ -+static void oc_spi_setreg_16(struct spioc *spioc, int reg, u32 value) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_2]; -+ u32 pos; -+ -+ pos = spioc->base_addr + (reg << spioc->reg_shift); -+ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ spioc->dev_name, spioc->reg_access_mode, pos, value); -+ -+ buf_tmp[0] = (value & 0Xff); -+ buf_tmp[1] = (value >> 8) & 0xff; -+ oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_2); -+ return; -+} -+ -+static void oc_spi_setreg_32(struct spioc *spioc, int reg, u32 value) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_4]; -+ u32 pos; -+ -+ pos = spioc->base_addr + (reg << spioc->reg_shift); -+ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ spioc->dev_name, spioc->reg_access_mode, pos, value); -+ -+ buf_tmp[0] = (value & 0xff); -+ buf_tmp[1] = (value >> 8) & 0xff; -+ buf_tmp[2] = (value >> 16) & 0xff; -+ buf_tmp[3] = (value >> 24) & 0xff; -+ -+ oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_4); -+ return; -+} -+ -+static void oc_spi_setreg_16be(struct spioc *spioc, int reg, u32 value) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_2]; -+ u32 pos; -+ -+ pos = spioc->base_addr + (reg << spioc->reg_shift); -+ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ spioc->dev_name, spioc->reg_access_mode, pos, value); -+ -+ buf_tmp[0] = (value >> 8) & 0xff; -+ buf_tmp[1] = (value & 0Xff); -+ oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_2); -+ return; -+} -+ -+static void oc_spi_setreg_32be(struct spioc *spioc, int reg, u32 value) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_4]; -+ u32 pos; -+ -+ pos = spioc->base_addr + (reg << spioc->reg_shift); -+ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ spioc->dev_name, spioc->reg_access_mode, pos, value); -+ -+ buf_tmp[0] = (value >> 24) & 0xff; -+ buf_tmp[1] = (value >> 16) & 0xff; -+ buf_tmp[2] = (value >> 8) & 0xff; -+ buf_tmp[3] = (value & 0xff); -+ oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_4); -+ return; -+} -+ -+static inline u32 oc_spi_getreg_8(struct spioc *spioc, int reg) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_1]; -+ u32 value, pos; -+ -+ pos = spioc->base_addr + (reg << spioc->reg_shift); -+ oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_1); -+ value = buf_tmp[0]; -+ -+ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ spioc->dev_name, spioc->reg_access_mode, pos, value); -+ -+ return value; -+} -+ -+static inline u32 oc_spi_getreg_16(struct spioc *spioc, int reg) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_2]; -+ u32 value, pos; -+ int i; -+ -+ pos = spioc->base_addr + (reg << spioc->reg_shift); -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_2); -+ -+ value = 0; -+ for (i = 0; i < REG_IO_WIDTH_2 ; i++) { -+ value |= buf_tmp[i] << (8 * i); -+ } -+ -+ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ spioc->dev_name, spioc->reg_access_mode, pos, value); -+ return value; -+} -+ -+static inline u32 oc_spi_getreg_32(struct spioc *spioc, int reg) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_4]; -+ u32 value, pos; -+ int i; -+ -+ pos = spioc->base_addr + (reg << spioc->reg_shift); -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_4); -+ -+ value = 0; -+ for (i = 0; i < REG_IO_WIDTH_4 ; i++) { -+ value |= buf_tmp[i] << (8 * i); -+ } -+ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ spioc->dev_name, spioc->reg_access_mode, pos, value); -+ return value; -+} -+ -+static inline u32 oc_spi_getreg_16be(struct spioc *spioc, int reg) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_2]; -+ u32 value, pos; -+ int i; -+ -+ pos = spioc->base_addr + (reg << spioc->reg_shift); -+ -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_2); -+ -+ value = 0; -+ for (i = 0; i < REG_IO_WIDTH_2 ; i++) { -+ value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_2 -i - 1)); -+ } -+ -+ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ spioc->dev_name, spioc->reg_access_mode, pos, value); -+ return value; -+} -+ -+static inline u32 oc_spi_getreg_32be(struct spioc *spioc, int reg) -+{ -+ u8 buf_tmp[REG_IO_WIDTH_4]; -+ u32 value, pos; -+ int i; -+ -+ pos = spioc->base_addr + (reg << spioc->reg_shift); -+ -+ mem_clear(buf_tmp, sizeof(buf_tmp)); -+ oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_4); -+ -+ value = 0; -+ for (i = 0; i < REG_IO_WIDTH_4 ; i++) { -+ value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_4 -i - 1)); -+ } -+ -+ SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", -+ spioc->dev_name, spioc->reg_access_mode, pos, value); -+ return value; -+ -+} -+ -+static inline void oc_spi_setreg(struct spioc *spioc, int reg, u32 value) -+{ -+ spioc->setreg(spioc, reg, value); -+ return; -+} -+ -+static inline u32 oc_spi_getreg(struct spioc *spioc, int reg) -+{ -+ return spioc->getreg(spioc, reg); -+} -+ -+static int spioc_get_clkdiv(struct spioc *spioc, u32 speed) -+{ -+ u32 rate, div; -+ -+ rate = spioc->freq; -+ SPI_OC_VERBOSE("clk get rate:%u, speed:%u\n", rate, speed); -+ /* fs = fw/((DIV+2)*2) */ -+ -+ if (speed > (rate / 4)) { -+ div = 0; -+ SPI_OC_VERBOSE("spi device speed[%u] more than a quarter of clk rate[%u].\n", -+ speed, rate); -+ return div; -+ } -+ div = (rate/(2 * speed)) - 2; -+ if (div > SPIOC_MAX_DIV) { -+ SPI_OC_ERROR("Unsupport spi device speed, div:%u.\n", div); -+ return -1; -+ } -+ SPI_OC_VERBOSE("DIV is:0x%x\n", div); -+ return div; -+} -+ -+static inline int spioc_wait_trans(struct spioc *spioc, const unsigned long timeout) -+{ -+ unsigned long j; -+ unsigned int sch_time; -+ u8 reg; -+ -+ j = jiffies + timeout; -+ sch_time = SPIOC_WAIT_SCH; -+ while (1) { -+ reg = oc_spi_getreg(spioc, SPIOC_STS); -+ if (!(reg & SPIOC_BUSY_STS)) { -+ SPI_OC_VERBOSE("wait ok!\n"); -+ break; -+ } -+ -+ if (time_after(jiffies, j)) { -+ return -ETIMEDOUT; -+ } -+ -+ usleep_range(sch_time, sch_time + 1); -+ } -+ -+ return 0; -+} -+ -+static void spioc_chipselect(struct spi_device *spi, int is_active) -+{ -+ struct spioc *spioc; -+ u8 tx_conf; -+ int ret; -+ -+ spioc = spi_master_get_devdata(spi->master); -+ spioc->transfer_busy_flag = 0; -+ ret = spioc_wait_trans(spioc, msecs_to_jiffies(100)); -+ if (ret < 0) { -+ SPI_OC_ERROR("spi transfer is busy, ret=%d.\n", ret); -+ spioc->transfer_busy_flag = 1; -+ return; -+ } -+ spioc->chip_select = spi->chip_select; -+ SPI_OC_VERBOSE("spioc_chipselect:%u, value:%d.\n", spioc->chip_select, is_active); -+ tx_conf = 0; -+ tx_conf |= SPIOC_CSID(spioc->chip_select); -+ if (is_active) { -+ tx_conf |= SPIOC_CSLV; -+ } -+ -+ SPI_OC_VERBOSE("tx_config:[0x%x]\n", tx_conf); -+ oc_spi_setreg(spioc, SPIOC_TXCTL, tx_conf); -+ return; -+} -+ -+static void spioc_copy_tx(struct spioc *spioc) -+{ -+ const u8 *src; -+ int i; -+ -+ if (!spioc->txp) { -+ SPI_OC_ERROR("spioc->txp is NULL.\n"); -+ return; -+ } -+ -+ src = (u8 *)spioc->txp + spioc->cur_pos; -+ SPI_OC_VERBOSE("current tx len:0x%x, tx pos:[0x%x]\n", spioc->cur_len, spioc->cur_pos); -+ -+ for (i = 0; i < spioc->cur_len; i++) { -+ SPI_OC_VERBOSE("write %d, val:[0x%x]\n", i, src[i]); -+ oc_spi_setreg(spioc, SPIOC_TX(i), src[i]); -+ } -+} -+ -+static void spioc_copy_rx(struct spioc *spioc) -+{ -+ u8 *dest; -+ int i; -+ -+ if (!spioc->rxp) { -+ SPI_OC_ERROR("spioc->rxp is NULL.\n"); -+ return; -+ } -+ -+ dest = (u8 *)spioc->rxp + spioc->cur_pos; -+ SPI_OC_VERBOSE("current rx len:0x%x, rx pos:[0x%x]\n", spioc->cur_len, spioc->cur_pos); -+ -+ for (i = 0; i < spioc->cur_len; i++) { -+ dest[i] = oc_spi_getreg(spioc, SPIOC_RX(i)); -+ SPI_OC_VERBOSE("read %d, val:[0x%x]\n", i, dest[i]); -+ } -+} -+ -+static int spioc_setup_transfer(struct spi_device *spi, struct spi_transfer *transfer) -+{ -+ struct spioc *spioc; -+ u8 ctrl; -+ u32 hz; -+ int div; -+ -+ spioc = spi_master_get_devdata(spi->master); -+ ctrl = 0; -+ -+ if (spi->mode & SPI_LSB_FIRST) { -+ ctrl |= SPIOC_LSBF; -+ } -+ -+ if (!(spi->mode & SPI_CPOL)) { -+ ctrl |= SPIOC_IDLE_LOW; -+ } -+ -+ if (spioc->irq < 0) { -+ -+ ctrl |= SPIOC_INTREN; -+ } -+ -+ if (transfer != NULL) { -+ hz = transfer->speed_hz; -+ -+ if (hz == 0) { -+ hz = spi->max_speed_hz; -+ } -+ } else { -+ hz = spi->max_speed_hz; -+ } -+ -+ if (hz == 0) { -+ SPI_OC_ERROR("Unsupport zero speed.\n"); -+ return -EINVAL; -+ } -+ -+ div = spioc_get_clkdiv(spioc, hz); -+ if (div < 0) { -+ SPI_OC_ERROR("get div error, div:%d.\n", div); -+ return -EINVAL; -+ } -+ ctrl |= SPIOC_DIV(div); -+ -+ SPI_OC_VERBOSE("ctrl:[0x%x].\n", ctrl); -+ -+ oc_spi_setreg(spioc, SPIOC_CONF, ctrl); -+ return 0; -+} -+ -+static int spioc_spi_setup(struct spi_device *spi) -+{ -+ struct spioc *spioc; -+ -+ if (!(spi->mode & SPI_CPHA)) { -+ SPI_OC_ERROR("Unsupport spi device mde:0x%x, SPI_CPHA must be 1.\n", spi->mode); -+ return -EINVAL; -+ } -+ -+ spioc = spi_master_get_devdata(spi->master); -+ if (spi->chip_select >= spioc->num_chipselect) { -+ SPI_OC_ERROR("Spi device chipselect:%u, more than max chipselect:%u.\n", -+ spi->chip_select, spioc->num_chipselect); -+ return -EINVAL; -+ } -+ SPI_OC_VERBOSE("Support spi device mode:0x%x, chip_select:%u.\n", -+ spi->mode, spi->chip_select); -+ return 0; -+} -+ -+static int spioc_transfer_start(struct spioc *spioc) -+{ -+ u8 tx_conf; -+ int ret; -+ -+ tx_conf = oc_spi_getreg(spioc, SPIOC_TXCTL); -+ tx_conf |= SPIOC_TRSTART; -+ -+ SPI_OC_VERBOSE("tx_config:[0x%x]\n", tx_conf); -+ oc_spi_setreg(spioc, SPIOC_TXCTL, tx_conf); -+ -+ ret = spioc_wait_trans(spioc, msecs_to_jiffies(100)); -+ return ret; -+} -+ -+static int spioc_tx_start_one(struct spioc *spioc) -+{ -+ unsigned int txlen; -+ u8 txreg; -+ int ret; -+ -+ if (!spioc->reamin_len) { -+ SPI_OC_VERBOSE("spioc txlen:[0x0]\n"); -+ return 0; -+ } -+ -+ spioc->cur_len = spioc->reamin_len > SPIOC_MAX_LEN ? SPIOC_MAX_LEN : spioc->reamin_len; -+ -+ txlen = spioc->cur_len; -+ spioc->reamin_len -= txlen; -+ SPI_OC_VERBOSE("txlen:[0x%x], tx len remain:[0x%x]\n", txlen, spioc->reamin_len); -+ -+ spioc_copy_tx(spioc); -+ -+ /* when we only send, txlen == totlen */ -+ txreg = SPIOC_TXNUM(txlen) | SPIOC_TOTNUM(txlen); -+ SPI_OC_VERBOSE("txreg:[0x%x]\n", txreg); -+ oc_spi_setreg(spioc, SPIOC_TXTOT_NUM, txreg); -+ -+ ret = spioc_transfer_start(spioc); -+ if (ret) { -+ SPI_OC_ERROR("spioc tx rx poll wait for transfer timeout.\n"); -+ return ret; -+ } -+ -+ if (spioc->reamin_len) { -+ spioc->cur_pos += txlen; -+ SPI_OC_VERBOSE("cur_txpos:[0x%x]\n", spioc->cur_pos); -+ } -+ -+ return 0; -+} -+ -+static int spioc_rx_start_one(struct spioc *spioc) -+{ -+ unsigned int rxlen; -+ u8 txtnum; -+ int ret; -+ -+ if (!spioc->reamin_len) { -+ SPI_OC_VERBOSE("spioc reamin_len:[0x0]\n"); -+ return 0; -+ } -+ -+ spioc->cur_len = spioc->reamin_len > SPIOC_MAX_LEN ? SPIOC_MAX_LEN : spioc->reamin_len; -+ -+ rxlen = spioc->cur_len; -+ spioc->reamin_len -= rxlen; -+ SPI_OC_VERBOSE("rxlen:[0x%x], rx len remain:[0x%x]\n", rxlen, spioc->reamin_len); -+ -+ /* when we only receive, rxnum=totnum. txnum=0 */ -+ txtnum = SPIOC_TOTNUM(rxlen); -+ SPI_OC_VERBOSE("tx total reg:0x%x\n", txtnum); -+ oc_spi_setreg(spioc, SPIOC_TXTOT_NUM, txtnum); -+ -+ ret = spioc_transfer_start(spioc); -+ if (ret) { -+ SPI_OC_ERROR("spioc tx rx poll wait for transfer timeout.\n"); -+ return ret; -+ } -+ -+ spioc_copy_rx(spioc); -+ -+ if (spioc->reamin_len) { -+ spioc->cur_pos += rxlen; -+ SPI_OC_VERBOSE("cur_rxpos:[0x%x]\n", spioc->cur_pos); -+ } -+ -+ return 0; -+} -+ -+static int spioc_tx_rx_start_one(struct spioc *spioc) -+{ -+ unsigned int txlen, total_len; -+ u8 txreg; -+ int ret; -+ -+ if (!spioc->reamin_len) { -+ SPI_OC_VERBOSE("spioc reamin_len:[0x0]\n"); -+ return 0; -+ } -+ -+ spioc->cur_len = spioc->reamin_len > SPIOC_TXRX_MAX_LEN ? SPIOC_TXRX_MAX_LEN : spioc->reamin_len; -+ -+ txlen = spioc->cur_len; -+ spioc->reamin_len -= txlen; -+ SPI_OC_VERBOSE("tx len:[0x%x], tx len remain:[0x%x]\n", txlen, spioc->reamin_len); -+ -+ spioc_copy_tx(spioc); -+ -+ total_len = 2 * txlen; /* total_len=txlen + rxlen; rxlen=txlen */ -+ txreg = SPIOC_TXNUM(txlen) | SPIOC_TOTNUM(total_len); -+ SPI_OC_VERBOSE("txreg:[0x%x]\n", txreg); -+ oc_spi_setreg(spioc, SPIOC_TXTOT_NUM, txreg); -+ -+ ret = spioc_transfer_start(spioc); -+ if (ret) { -+ SPI_OC_ERROR("spioc tx rx poll wait for transfer timeout.\n"); -+ return ret; -+ } -+ -+ spioc_copy_rx(spioc); -+ if (spioc->reamin_len) { -+ spioc->cur_pos += txlen; -+ SPI_OC_VERBOSE("cur_txrx pos:[0x%x]\n", spioc->cur_pos); -+ } -+ return 0; -+} -+ -+static int spioc_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) -+{ -+ struct spioc *spioc; -+ int ret , len; -+ -+ if(!t->len || (!t->tx_buf && !t->rx_buf)) { -+ SPI_OC_ERROR("params error, tx_buf and rx_buf may both NULL, transfer len:0x%x.\n", -+ t->len); -+ return 0; -+ } -+ -+ spioc = spi_master_get_devdata(spi->master); -+ if (spioc->transfer_busy_flag) { -+ ret = -EBUSY; -+ goto err; -+ } -+ -+ spioc->txp = t->tx_buf; -+ spioc->rxp = t->rx_buf; -+ spioc->reamin_len = t->len; -+ spioc->cur_len = 0; -+ spioc->cur_pos = 0; -+ len = t->len; -+ ret = 0; -+ if (spioc->irq >= 0) { -+ /* use interrupt driven data transfer */ -+ if (t->tx_buf && t->rx_buf) { -+ spioc_tx_rx_start_one(spioc); -+ wait_for_completion(&spioc->done); -+ } else if (t->tx_buf) { -+ spioc_tx_start_one(spioc); -+ wait_for_completion(&spioc->done); -+ -+ } else { -+ spioc_rx_start_one(spioc); -+ wait_for_completion(&spioc->done); -+ } -+ } else { -+ if (t->tx_buf && t->rx_buf) { -+ SPI_OC_VERBOSE("start tx rx, len:0x%x\n", t->len); -+ while (spioc->reamin_len) { -+ ret = spioc_tx_rx_start_one(spioc); -+ if (ret) { -+ goto err; -+ } -+ } -+ } else if (t->tx_buf) { -+ SPI_OC_VERBOSE("start tx, txlen:0x%x\n", t->len); -+ while (spioc->reamin_len) { -+ ret = spioc_tx_start_one(spioc); -+ if (ret) { -+ goto err; -+ } -+ } -+ } else { -+ SPI_OC_VERBOSE("start rx, rxlen:0x%x\n", t->len); -+ while (spioc->reamin_len) { -+ ret = spioc_rx_start_one(spioc); -+ if (ret) { -+ goto err; -+ } -+ } -+ } -+ } -+ SPI_OC_VERBOSE("return num: 0x%x\n", len); -+ return len; -+err: -+ return ret; -+} -+ -+static irqreturn_t spioc_spi_irq(int irq, void *dev) -+{ -+ struct spioc *spioc; -+ -+ spioc = dev; -+ /* gooooohi, interrupt status bit judgment is not done */ -+ -+ if (spioc->txp && spioc->rxp) { -+ if (!spioc->reamin_len) { -+ complete(&spioc->done); -+ } else { -+ spioc_tx_rx_start_one(spioc); -+ } -+ } else if (spioc->txp) { -+ if (!spioc->reamin_len) { -+ complete(&spioc->done); -+ } else { -+ spioc_tx_start_one(spioc); -+ } -+ } else if (spioc->rxp){ -+ if (!spioc->reamin_len) { -+ complete(&spioc->done); -+ } else { -+ spioc_rx_start_one(spioc); -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static int ocores_spi_config_init(struct spioc *spioc) -+{ -+ int ret = 0; -+ struct device *dev; -+ spi_ocores_device_t *spi_ocores_device; -+ -+ dev = spioc->dev; -+ if (dev->of_node) { -+ ret += of_property_read_string(dev->of_node, "dev_name", &spioc->dev_name); -+ ret += of_property_read_u32(dev->of_node, "dev_base", &spioc->base_addr); -+ ret += of_property_read_u32(dev->of_node, "reg_shift", &spioc->reg_shift); -+ ret += of_property_read_u32(dev->of_node, "reg_io_width", &spioc->reg_io_width); -+ ret += of_property_read_u32(dev->of_node, "clock-frequency", &spioc->freq); -+ ret += of_property_read_u32(dev->of_node, "reg_access_mode", &spioc->reg_access_mode); -+ ret += of_property_read_u32(dev->of_node, "num_chipselect", &spioc->num_chipselect); -+ -+ if (ret != 0) { -+ SPI_OC_ERROR("dts config error, ret:%d.\n", ret); -+ ret = -ENXIO; -+ return ret; -+ } -+ } else { -+ if (spioc->dev->platform_data == NULL) { -+ SPI_OC_ERROR("platform data config error.\n"); -+ ret = -ENXIO; -+ return ret; -+ } -+ spi_ocores_device = spioc->dev->platform_data; -+ spioc->bus_num = spi_ocores_device->bus_num; -+ spioc->dev_name = spi_ocores_device->dev_name; -+ spioc->big_endian = spi_ocores_device->big_endian; -+ spioc->base_addr = spi_ocores_device->dev_base; -+ spioc->reg_shift = spi_ocores_device->reg_shift; -+ spioc->reg_io_width = spi_ocores_device->reg_io_width; -+ spioc->freq = spi_ocores_device->clock_frequency; -+ spioc->reg_access_mode = spi_ocores_device->reg_access_mode; -+ spioc->num_chipselect = spi_ocores_device->num_chipselect; -+ } -+ -+ SPI_OC_VERBOSE("name:%s, base:0x%x, reg_shift:0x%x, io_width:0x%x, clock-frequency:0x%x.\n", -+ spioc->dev_name, spioc->base_addr, spioc->reg_shift, spioc->reg_io_width, spioc->freq); -+ SPI_OC_VERBOSE("reg access mode:%u, num_chipselect:%u.\n", -+ spioc->reg_access_mode, spioc->num_chipselect); -+ return ret; -+} -+ -+static int spioc_probe(struct platform_device *pdev) -+{ -+ struct spi_master *master; -+ struct spioc *spioc; -+ int ret; -+ bool be; -+ -+ ret = -1; -+ master = spi_alloc_master(&pdev->dev, sizeof(struct spioc)); -+ if (!master) { -+ dev_err(&pdev->dev, "Failed to alloc spi master.\n"); -+ goto out; -+ } -+ -+ spioc = spi_master_get_devdata(master); -+ platform_set_drvdata(pdev, spioc); -+ -+ spioc->dev = &pdev->dev; -+ ret = ocores_spi_config_init(spioc); -+ if (ret != 0) { -+ dev_err(spioc->dev, "Failed to get ocores spi dts config.\n"); -+ goto free; -+ } -+ -+ if (spioc->dev->of_node) { -+ if (of_property_read_u32(spioc->dev->of_node, "big_endian", &spioc->big_endian)) { -+ -+ be = 0; -+ } else { -+ be = spioc->big_endian; -+ } -+ } else { -+ be = spioc->big_endian; -+ } -+ -+ if (spioc->reg_io_width == 0) { -+ spioc->reg_io_width = 1; /* Set to default value */ -+ } -+ -+ if (!spioc->setreg || !spioc->getreg) { -+ switch (spioc->reg_io_width) { -+ case REG_IO_WIDTH_1: -+ spioc->setreg = oc_spi_setreg_8; -+ spioc->getreg = oc_spi_getreg_8; -+ break; -+ -+ case REG_IO_WIDTH_2: -+ spioc->setreg = be ? oc_spi_setreg_16be : oc_spi_setreg_16; -+ spioc->getreg = be ? oc_spi_getreg_16be : oc_spi_getreg_16; -+ break; -+ -+ case REG_IO_WIDTH_4: -+ spioc->setreg = be ? oc_spi_setreg_32be : oc_spi_setreg_32; -+ spioc->getreg = be ? oc_spi_getreg_32be : oc_spi_getreg_32; -+ break; -+ -+ default: -+ dev_err(spioc->dev, "Unsupported I/O width (%d)\n", spioc->reg_io_width); -+ ret = -EINVAL; -+ goto free; -+ } -+ } -+ -+ /* master state */ -+ master->num_chipselect = spioc->num_chipselect; -+ master->mode_bits = MODEBITS; -+ master->setup = spioc_spi_setup; -+ if (spioc->dev->of_node) { -+ master->dev.of_node = pdev->dev.of_node; -+ } else { -+ master->bus_num = spioc->bus_num; -+ } -+ -+ /* setup the state for the bitbang driver */ -+ spioc->bitbang.master = master; -+ spioc->bitbang.setup_transfer = spioc_setup_transfer; -+ spioc->bitbang.chipselect = spioc_chipselect; -+ spioc->bitbang.txrx_bufs = spioc_spi_txrx_bufs; -+ -+ /* gooooohi need revision */ -+ spioc->irq = platform_get_irq(pdev, 0); -+ if (spioc->irq >= 0) { -+ SPI_OC_VERBOSE("spi oc use irq, irq number:%d.\n", spioc->irq); -+ init_completion(&spioc->done); -+ ret = devm_request_irq(&pdev->dev, spioc->irq, spioc_spi_irq, 0, -+ pdev->name, spioc); -+ if (ret) { -+ dev_err(spioc->dev, "Failed to request irq:%d.\n", spioc->irq); -+ goto free; -+ } -+ } -+ -+ ret = spi_bitbang_start(&spioc->bitbang); -+ if (ret) { -+ dev_err(spioc->dev, "Failed to start spi bitbang, ret:%d.\n", ret); -+ goto free; -+ } -+ dev_info(spioc->dev, "registered spi-%d for %s with base address:0x%x success.\n", -+ master->bus_num, spioc->dev_name, spioc->base_addr); -+ -+ return ret; -+free: -+ spi_master_put(master); -+out: -+ return ret; -+} -+ -+static int spioc_remove(struct platform_device *pdev) -+{ -+ struct spioc *spioc; -+ struct spi_master *master; -+ -+ spioc = platform_get_drvdata(pdev); -+ master = spioc->bitbang.master; -+ spi_bitbang_stop(&spioc->bitbang); -+ platform_set_drvdata(pdev, NULL); -+ spi_master_put(master); -+ -+ return 0; -+} -+ -+static const struct of_device_id spioc_match[] = { -+ { .compatible = "wb-spi-oc", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, spioc_match); -+ -+static struct platform_driver spioc_driver = { -+ .probe = spioc_probe, -+ .remove = spioc_remove, -+ .driver = { -+ .name = "wb-spioc", -+ .owner = THIS_MODULE, -+ .of_match_table = spioc_match, -+ }, -+}; -+ -+module_platform_driver(spioc_driver); -+ -+MODULE_DESCRIPTION("spi open core adapter driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.h -new file mode 100644 -index 000000000..647ff0c5f ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.h -@@ -0,0 +1,21 @@ -+#ifndef __WB_SPI_OCORES_H__ -+#define __WB_SPI_OCORES_H__ -+#include -+ -+#define mem_clear(data, size) memset((data), 0, (size)) -+#define SPI_OCORES_DEV_NAME_MAX_LEN (64) -+ -+typedef struct spi_ocores_device_s { -+ uint32_t bus_num; -+ uint32_t big_endian; -+ char dev_name[SPI_OCORES_DEV_NAME_MAX_LEN]; -+ uint32_t reg_access_mode; -+ uint32_t dev_base; -+ uint32_t reg_shift; -+ uint32_t reg_io_width; -+ uint32_t clock_frequency; -+ uint32_t num_chipselect; -+ int device_flag; -+} spi_ocores_device_t; -+ -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_uio_irq.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_uio_irq.c -new file mode 100644 -index 000000000..da2b58244 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_uio_irq.c -@@ -0,0 +1,282 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+typedef struct dfd_irq_s { -+ int gpio; -+ int irq_type; -+ struct uio_info dfd_irq_info; -+ spinlock_t lock; -+ struct attribute_group attr_group; -+} dfd_irq_t; -+ -+#define DRV_NAME "uio-irq" -+#define DRV_VERSION "1.0" -+#define ENABLE_VAL (1) -+#define DISABLE_VAL (0) -+ -+#define DEBUG_ERR_LEVEL (0x1) -+#define DEBUG_WARN_LEVEL (0x2) -+#define DEBUG_INFO_LEVEL (0x4) -+#define DEBUG_VER_LEVEL (0x8) -+ -+static int debug = 0; -+module_param(debug, int, S_IRUGO | S_IWUSR); -+#define DEBUG_ERROR(fmt, args...) \ -+ do { \ -+ if (debug & DEBUG_ERR_LEVEL) { \ -+ printk(KERN_ERR "[ERR][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ -+ } else { \ -+ pr_debug(fmt, ## args); \ -+ } \ -+ } while(0) -+ -+#define DEBUG_WARN(fmt, args...) \ -+ do { \ -+ if (debug & DEBUG_WARN_LEVEL) { \ -+ printk(KERN_WARNING "[WARN][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ -+ } else { \ -+ pr_debug(fmt, ## args); \ -+ } \ -+ } while(0) -+ -+#define DEBUG_INFO(fmt, args...) \ -+ do { \ -+ if (debug & DEBUG_INFO_LEVEL) { \ -+ printk(KERN_INFO "[INFO][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ -+ } else { \ -+ pr_debug(fmt, ## args); \ -+ } \ -+ } while(0) -+ -+#define DEBUG_VERBOSE(fmt, args...) \ -+ do { \ -+ if (debug & DEBUG_VER_LEVEL) { \ -+ printk(KERN_DEBUG "[VER][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ -+ } else { \ -+ pr_debug(fmt, ## args); \ -+ } \ -+ } while(0) -+ -+static irqreturn_t dfd_genirq_handler(int irq, struct uio_info *dev_info) -+{ -+ disable_irq_nosync(irq); -+ DEBUG_VERBOSE("handler disable irq"); -+ return IRQ_HANDLED; -+} -+ -+static int dfd_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on) -+{ -+ struct irq_data *irqdata; -+ -+ irqdata = irq_get_irq_data(dev_info->irq); -+ -+ if (irqd_irq_disabled(irqdata) == !irq_on) { -+ DEBUG_VERBOSE("irq already disable"); -+ return 0; -+ } -+ if (irq_on) { -+ DEBUG_VERBOSE("irqcontrol enable irq"); -+ enable_irq(dev_info->irq); -+ } else { -+ DEBUG_VERBOSE("irqcontrol disable irq"); -+ disable_irq(dev_info->irq); -+ } -+ -+ return 0; -+} -+ -+static ssize_t set_irq_enable(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ dfd_irq_t *dfd_irq; -+ struct uio_info *dev_info; -+ unsigned long flags; -+ int ret, val; -+ -+ dfd_irq = dev_get_drvdata(dev); -+ dev_info = &dfd_irq->dfd_irq_info; -+ -+ spin_lock_irqsave(&dfd_irq->lock, flags); -+ -+ sscanf(buf, "%d", &val); -+ DEBUG_VERBOSE("set val:%d.\n", val); -+ -+ if ((val != ENABLE_VAL) && (val != DISABLE_VAL)) { -+ DEBUG_ERROR("unsupport val:%d ", val); -+ ret = -EINVAL; -+ goto fail; -+ } -+ -+ if (val) { -+ DEBUG_VERBOSE("sysfs enable irq"); -+ enable_irq(dev_info->irq); -+ } else { -+ DEBUG_VERBOSE("sysfs disable irq"); -+ disable_irq(dev_info->irq); -+ } -+ -+ spin_unlock_irqrestore(&dfd_irq->lock, flags); -+ return count; -+ -+fail: -+ spin_unlock_irqrestore(&dfd_irq->lock, flags); -+ return ret; -+} -+ -+static DEVICE_ATTR(irq_enable, S_IWUSR, NULL, set_irq_enable); -+ -+static struct attribute *irq_attrs[] = { -+ &dev_attr_irq_enable.attr, -+ NULL, -+}; -+ -+static struct attribute_group irq_attr_group = { -+ .attrs = irq_attrs, -+}; -+ -+static int dfd_irq_probe(struct platform_device *pdev) -+{ -+ u32 gpio, irq_type, pirq_line; -+ int ret, ret1, ret2; -+ struct uio_info *dfd_irq_info; -+ dfd_irq_t *dfd_irq; -+ -+ dfd_irq = kzalloc(sizeof(dfd_irq_t), GFP_KERNEL); -+ if (!dfd_irq) { -+ dev_err(&pdev->dev, "dfd_irq_t kzalloc failed.\n"); -+ return -ENOMEM; -+ } -+ -+ dfd_irq_info = &dfd_irq->dfd_irq_info; -+ dfd_irq_info->version = "1.0"; -+ dfd_irq_info->name = "uio-irq"; -+ -+ /* get pirq line for x86 */ -+ ret1 = of_property_read_u32(pdev->dev.of_node, "pirq-line", &pirq_line); -+ if (!ret1) { -+ DEBUG_VERBOSE("use pirq-line method, pirq-line:%u", pirq_line); -+ dfd_irq_info->irq = pirq_line; -+ } -+ -+ ret2 = of_property_read_u32(pdev->dev.of_node, "gpio", &gpio); -+ if (!ret2 && ret1) { -+ dfd_irq->gpio = gpio; -+ gpio_request(dfd_irq->gpio, "GPIOA"); -+ dfd_irq_info->irq = gpio_to_irq(dfd_irq->gpio); -+ DEBUG_VERBOSE("use gpio:%u, irq num:%ld", gpio, dfd_irq_info->irq); -+ } else if (ret2 && ret1){ -+ ret = -ENXIO; -+ dev_err(&pdev->dev, "no define irq num. ret2:%d, ret1:%d.\n", ret2, ret1); -+ goto free_mem; -+ } -+ -+ ret = of_property_read_u32(pdev->dev.of_node, "irq_type", &irq_type); -+ if (!ret && ret1) { -+ DEBUG_VERBOSE("use irq_type:%u", irq_type); -+ dfd_irq->irq_type = irq_type; -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) -+ irq_set_irq_type(dfd_irq_info->irq, dfd_irq->irq_type); -+#else -+ set_irq_type(dfd_irq_info->irq, dfd_irq->irq_type); -+#endif -+ } else if (ret && ret1){ -+ ret = -ENXIO; -+ dev_err(&pdev->dev, "no define irq type. ret:%d, ret1:%d.\n", ret, ret1); -+ goto free_mem; -+ } -+ -+ dfd_irq_info->irq_flags = IRQF_SHARED; -+ dfd_irq_info->handler = dfd_genirq_handler; -+ dfd_irq_info->irqcontrol = dfd_genirq_irqcontrol; -+ -+ if(uio_register_device(&pdev->dev, dfd_irq_info)){ -+ ret = -ENODEV; -+ dev_err(&pdev->dev, "uio register failed.\n"); -+ goto free_mem; -+ } -+ -+ spin_lock_init(&dfd_irq->lock); -+ -+ dfd_irq->attr_group = irq_attr_group; -+ ret = sysfs_create_group(&pdev->dev.kobj, &dfd_irq->attr_group); -+ if (ret != 0) { -+ dev_err(&pdev->dev, "sysfs_create_group failed. ret:%d.\n", ret); -+ goto free_mem; -+ } -+ DEBUG_VERBOSE("sysfs create group success\n"); -+ -+ platform_set_drvdata(pdev, dfd_irq); -+ -+ return 0; -+ -+free_mem: -+ kfree(dfd_irq); -+ -+ return ret; -+} -+ -+static int dfd_irq_remove(struct platform_device *pdev) -+{ -+ dfd_irq_t *dfd_irq; -+ struct uio_info *dfd_irq_info; -+ -+ dfd_irq = platform_get_drvdata(pdev); -+ dfd_irq_info = &dfd_irq->dfd_irq_info; -+ -+ uio_unregister_device(dfd_irq_info); -+ kfree(dfd_irq); -+ -+ sysfs_remove_group(&pdev->dev.kobj, &dfd_irq->attr_group); -+ -+ return 0; -+} -+ -+static struct of_device_id dfd_irq_match[] = { -+ { -+ .compatible = "uio-irq", -+ }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, dfd_irq_match); -+ -+static struct platform_driver dfd_irq_driver = { -+ .probe = dfd_irq_probe, -+ .remove = dfd_irq_remove, -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = DRV_NAME, -+ .of_match_table = dfd_irq_match, -+ }, -+}; -+ -+static int __init dfd_irq_init(void) -+{ -+ int ret; -+ -+ ret = platform_driver_register(&dfd_irq_driver); -+ if (ret != 0 ) { -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void __exit dfd_irq_exit(void) -+{ -+ platform_driver_unregister(&dfd_irq_driver); -+} -+ -+module_init(dfd_irq_init); -+module_exit(dfd_irq_exit); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.c -new file mode 100644 -index 000000000..c97288944 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.c -@@ -0,0 +1,1187 @@ -+/* -+ * wb_wdt.c -+ * ko for watchdog function -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "wb_wdt.h" -+ -+#define GPIO_FEED_WDT_MODE (1) -+#define LOGIC_FEED_WDT_MODE (2) -+ -+#define SYMBOL_I2C_DEV_MODE (1) -+#define SYMBOL_PCIE_DEV_MODE (2) -+#define SYMBOL_IO_DEV_MODE (3) -+#define FILE_MODE (4) -+ -+#define ONE_BYTE (1) -+ -+#define WDT_OFF (0) -+#define WDT_ON (1) -+ -+#define MS_TO_S (1000) -+#define MS_TO_NS (1000 * 1000) -+ -+#define MAX_REG_VAL (255) -+ -+extern int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+extern int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); -+ -+int g_wb_wdt_debug = 0; -+int g_wb_wdt_error = 0; -+ -+module_param(g_wb_wdt_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_wdt_error, int, S_IRUGO | S_IWUSR); -+ -+#define WDT_VERBOSE(fmt, args...) do { \ -+ if (g_wb_wdt_debug) { \ -+ printk(KERN_INFO "[WDT][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WDT_ERROR(fmt, args...) do { \ -+ if (g_wb_wdt_error) { \ -+ printk(KERN_ERR "[WDT][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+enum { -+ HW_ALGO_TOGGLE, -+ HW_ALGO_LEVEL, -+ HW_ALGO_EIGENVALUES, -+}; -+ -+enum { -+ WATCHDOG_DEVICE_TYPE = 0, -+ HRTIMER_TYPE, -+ THREAD_TYPE, -+}; -+ -+typedef struct wb_wdt_priv_s { -+ struct task_struct *thread; -+ struct hrtimer hrtimer; -+ ktime_t m_kt; -+ const char *config_dev_name; -+ uint8_t config_mode; -+ uint8_t hw_algo; -+ uint8_t enable_val; -+ uint8_t disable_val; -+ uint8_t enable_mask; -+ uint8_t priv_func_mode; -+ uint8_t feed_wdt_type; -+ uint32_t enable_reg; -+ uint32_t timeout_cfg_reg; -+ uint32_t timeleft_cfg_reg; -+ uint32_t hw_margin; -+ uint32_t feed_time; -+ uint8_t timer_accuracy_reg_flag; -+ uint32_t timer_accuracy_reg; -+ uint8_t timer_accuracy_reg_val; -+ uint32_t timer_accuracy; -+ uint8_t timer_update_reg_flag; -+ uint32_t timer_update_reg; -+ uint8_t timer_update_reg_val; -+ gpio_wdt_info_t gpio_wdt; -+ logic_wdt_info_t logic_wdt; -+ struct device *dev; -+ const struct attribute_group *sysfs_group; -+ uint8_t sysfs_index; -+ struct mutex update_lock; -+ struct watchdog_device wdd; -+}wb_wdt_priv_t; -+ -+static int wdt_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) -+{ -+ int ret; -+ struct file *filp; -+ loff_t tmp_pos; -+ -+ filp = filp_open(path, O_RDONLY, 0); -+ if (IS_ERR(filp)) { -+ WDT_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); -+ filp = NULL; -+ goto exit; -+ } -+ -+ tmp_pos = (loff_t)pos; -+ ret = kernel_read(filp, val, size, &tmp_pos); -+ if (ret < 0) { -+ WDT_ERROR("kernel_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); -+ goto exit; -+ } -+ -+ filp_close(filp, NULL); -+ -+ return ret; -+ -+exit: -+ if (filp != NULL) { -+ filp_close(filp, NULL); -+ } -+ -+ return -1; -+} -+ -+static int wdt_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) -+{ -+ int ret; -+ struct file *filp; -+ loff_t tmp_pos; -+ -+ filp = filp_open(path, O_RDWR, 777); -+ if (IS_ERR(filp)) { -+ WDT_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); -+ filp = NULL; -+ goto exit; -+ } -+ -+ tmp_pos = (loff_t)pos; -+ ret = kernel_write(filp, val, size, &tmp_pos); -+ if (ret < 0) { -+ WDT_ERROR("kernel_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); -+ goto exit; -+ } -+ -+ vfs_fsync(filp, 1); -+ filp_close(filp, NULL); -+ -+ return ret; -+ -+exit: -+ if (filp != NULL) { -+ filp_close(filp, NULL); -+ } -+ -+ return -1; -+} -+ -+static int wb_wdt_read(uint8_t mode, const char *path, -+ uint32_t offset, uint8_t *buf, size_t count) -+{ -+ int ret; -+ -+ switch (mode) { -+ case SYMBOL_I2C_DEV_MODE: -+ ret = i2c_device_func_read(path, offset, buf, count); -+ break; -+ case SYMBOL_PCIE_DEV_MODE: -+ ret = pcie_device_func_read(path, offset, buf, count); -+ break; -+ case SYMBOL_IO_DEV_MODE: -+ ret = io_device_func_read(path, offset, buf, count); -+ break; -+ case FILE_MODE: -+ ret = wdt_file_read(path, offset, buf, count); -+ break; -+ default: -+ WDT_ERROR("mode %u error, wdt func read failed.\n", mode); -+ return -EINVAL; -+ } -+ -+ WDT_VERBOSE("wdt func read mode:%u,dev_nam:%s, offset:0x%x, read_val:0x%x, size:%lu.\n", -+ mode, path, offset, *buf, count); -+ -+ return ret; -+} -+ -+static int wb_wdt_write(uint8_t mode, const char *path, -+ uint32_t offset, uint8_t *buf, size_t count) -+{ -+ int ret; -+ -+ switch (mode) { -+ case SYMBOL_I2C_DEV_MODE: -+ ret = i2c_device_func_write(path, offset, buf, count); -+ break; -+ case SYMBOL_PCIE_DEV_MODE: -+ ret = pcie_device_func_write(path, offset, buf, count); -+ break; -+ case SYMBOL_IO_DEV_MODE: -+ ret = io_device_func_write(path, offset, buf, count); -+ break; -+ case FILE_MODE: -+ ret = wdt_file_write(path, offset, buf, count); -+ break; -+ default: -+ WDT_ERROR("mode %u error, wdt func write failed.\n", mode); -+ return -EINVAL; -+ } -+ -+ WDT_VERBOSE("wdt func write mode:%u, dev_nam:%s, offset:0x%x, write_val:0x%x, size:%lu.\n", -+ mode, path, offset, *buf, count); -+ -+ return ret; -+} -+ -+static int wb_wdt_enable_ctrl(wb_wdt_priv_t *priv, uint8_t flag) -+{ -+ int ret; -+ uint8_t val; -+ uint8_t ctrl_val; -+ -+ switch (flag) { -+ case WDT_ON: -+ ctrl_val = priv->enable_val; -+ break; -+ case WDT_OFF: -+ ctrl_val = priv->disable_val; -+ break; -+ default: -+ WDT_ERROR("unsupport wdt enable ctrl:%u.\n", flag); -+ return -EINVAL; -+ } -+ -+ ret = wb_wdt_read(priv->priv_func_mode, priv->config_dev_name, -+ priv->enable_reg, &val, ONE_BYTE); -+ if (ret < 0) { -+ dev_err(priv->dev, "read wdt control reg error.\n"); -+ return ret; -+ } -+ -+ val &= ~priv->enable_mask; -+ -+ val |= ctrl_val & priv->enable_mask; -+ -+ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, -+ priv->enable_reg, &val, ONE_BYTE); -+ if (ret < 0) { -+ dev_err(priv->dev, "write wdt control reg error.\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void wdt_hwping(wb_wdt_priv_t *priv) -+{ -+ gpio_wdt_info_t *gpio_wdt; -+ logic_wdt_info_t *logic_wdt; -+ uint8_t tmp_val; -+ int ret; -+ -+ if (priv->config_mode == GPIO_FEED_WDT_MODE) { -+ gpio_wdt = &priv->gpio_wdt; -+ switch (priv->hw_algo) { -+ case HW_ALGO_TOGGLE: -+ gpio_wdt = &priv->gpio_wdt; -+ gpio_wdt->state = !gpio_wdt->state; -+ gpio_set_value_cansleep(gpio_wdt->gpio, gpio_wdt->state); -+ WDT_VERBOSE("gpio toggle wdt work. val:%u\n", gpio_wdt->state); -+ break; -+ case HW_ALGO_LEVEL: -+ gpio_wdt = &priv->gpio_wdt; -+ /* Pulse */ -+ gpio_set_value_cansleep(gpio_wdt->gpio, !gpio_wdt->active_low); -+ udelay(1); -+ gpio_set_value_cansleep(gpio_wdt->gpio, gpio_wdt->active_low); -+ WDT_VERBOSE("gpio level wdt work.\n"); -+ break; -+ } -+ } else { -+ logic_wdt = &priv->logic_wdt; -+ switch (priv->hw_algo) { -+ case HW_ALGO_TOGGLE: -+ logic_wdt->active_val = !logic_wdt->active_val; -+ ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, -+ logic_wdt->feed_reg, &logic_wdt->active_val, ONE_BYTE); -+ if (ret < 0) { -+ WDT_ERROR("logic toggle wdt write failed.ret = %d\n", ret); -+ } -+ WDT_VERBOSE("logic toggle wdt work.\n"); -+ break; -+ case HW_ALGO_LEVEL: -+ tmp_val = !logic_wdt->active_val; -+ ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, -+ logic_wdt->feed_reg, &tmp_val, ONE_BYTE); -+ if (ret < 0) { -+ WDT_ERROR("logic level wdt write first failed.ret = %d\n", ret); -+ } -+ udelay(1); -+ ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, -+ logic_wdt->feed_reg, &logic_wdt->active_val, ONE_BYTE); -+ if (ret < 0) { -+ WDT_ERROR("logic level wdt write second failed.ret = %d\n", ret); -+ } -+ WDT_VERBOSE("logic level wdt work.\n"); -+ break; -+ case HW_ALGO_EIGENVALUES: -+ ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, -+ logic_wdt->feed_reg, &logic_wdt->active_val, ONE_BYTE); -+ if (ret < 0) { -+ WDT_ERROR("logic eigenvalues wdt write failed, path: %s, mode: %d, reg: 0x%x, val: 0x%x, ret: %d\n", -+ logic_wdt->feed_dev_name, logic_wdt->logic_func_mode, logic_wdt->feed_reg, -+ logic_wdt->active_val, ret); -+ } -+ WDT_VERBOSE("logic eigenvalues wdt work, path: %s, mode: %d, reg: 0x%x, val: 0x%x\n", -+ logic_wdt->feed_dev_name, logic_wdt->logic_func_mode, logic_wdt->feed_reg, logic_wdt->active_val); -+ break; -+ } -+ } -+ return; -+} -+ -+static enum hrtimer_restart hrtimer_hwping(struct hrtimer *timer) -+{ -+ wb_wdt_priv_t *priv = container_of(timer, wb_wdt_priv_t, hrtimer); -+ -+ wdt_hwping(priv); -+ hrtimer_forward(timer, timer->base->get_time(), priv->m_kt); -+ return HRTIMER_RESTART; -+} -+ -+static int thread_timer_cfg(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) -+{ -+ struct device *dev; -+ uint32_t hw_margin; -+ uint32_t feed_time; -+ uint32_t accuracy; -+ uint8_t set_time_val; -+ int ret; -+ -+ dev = priv->dev; -+ -+ ret = 0; -+ if (dev->of_node) { -+ ret += of_property_read_u32(dev->of_node, "feed_time", &priv->feed_time); -+ if (ret != 0) { -+ dev_err(dev, "thread Failed to priv dts.\n"); -+ return -ENXIO; -+ } -+ } else { -+ priv->feed_time = wb_wdt_device->feed_time; -+ } -+ WDT_VERBOSE("thread priv->feed_time: %u.\n", priv->feed_time); -+ -+ hw_margin = priv->hw_margin; -+ feed_time = priv->feed_time; -+ accuracy = priv->timer_accuracy; -+ -+ if ((feed_time > (hw_margin / 2)) || (feed_time == 0)) { -+ dev_err(dev, "thread timer feed_time[%d] should be less than half hw_margin or zero.\n", feed_time); -+ return -EINVAL; -+ } -+ -+ if (priv->timer_accuracy_reg_flag != 0) { -+ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, -+ priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); -+ if (ret < 0) { -+ dev_err(priv->dev, "set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", -+ priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); -+ return ret; -+ } -+ } -+ -+ set_time_val = hw_margin / accuracy; -+ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, -+ priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); -+ if (ret < 0) { -+ dev_err(dev, "set wdt thread timer reg error.\n"); -+ return ret; -+ } -+ -+ if (priv->timer_update_reg_flag != 0) { -+ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, -+ priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); -+ if (ret < 0) { -+ dev_err(priv->dev, "set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", -+ priv->timer_update_reg, priv->timer_update_reg_val, ret); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static int wdt_thread_timer(void *data) -+{ -+ wb_wdt_priv_t *priv = data; -+ -+ while (!kthread_should_stop()) { -+ schedule_timeout_uninterruptible(msecs_to_jiffies(priv->feed_time)); -+ wdt_hwping(priv); -+ } -+ return 0; -+} -+ -+static int thread_timer_create(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) -+{ -+ struct task_struct *p; -+ int ret; -+ -+ ret = thread_timer_cfg(priv, wb_wdt_device); -+ if (ret < 0) { -+ dev_err(priv->dev, "set wdt thread timer failed.\n"); -+ return ret; -+ } -+ -+ p = kthread_create(wdt_thread_timer, (void *)priv, "%s", "wb_wdt"); -+ if (!IS_ERR(p)) { -+ WDT_VERBOSE("timer thread create success.\n"); -+ priv->thread = p; -+ wake_up_process(p); -+ } else { -+ dev_err(priv->dev, "timer thread create failed.\n"); -+ return -ENXIO; -+ } -+ -+ ret = wb_wdt_enable_ctrl(priv, WDT_ON); -+ if (ret < 0) { -+ dev_err(priv->dev, "thread enable wdt failed.\n"); -+ return -ENXIO; -+ } -+ -+ return 0; -+} -+ -+static int hrtimer_cfg(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) -+{ -+ struct device *dev; -+ struct hrtimer *hrtimer; -+ uint8_t set_time_val; -+ uint8_t hrtimer_s; -+ uint32_t hrtimer_ns; -+ int ret; -+ uint32_t hw_margin; -+ uint32_t feed_time; -+ uint32_t accuracy; -+ uint32_t max_timeout; -+ -+ dev = priv->dev; -+ -+ ret = 0; -+ if (dev->of_node) { -+ ret += of_property_read_u32(dev->of_node, "feed_time", &priv->feed_time); -+ if (ret != 0) { -+ dev_err(dev, "hrtimer Failed to priv dts.\n"); -+ return -ENXIO; -+ } -+ } else { -+ priv->feed_time = wb_wdt_device->feed_time; -+ } -+ WDT_VERBOSE("hrtimer priv->feed_time: %u.\n", priv->feed_time); -+ -+ hrtimer = &priv->hrtimer; -+ hw_margin = priv->hw_margin; -+ feed_time = priv->feed_time; -+ accuracy = priv->timer_accuracy; -+ max_timeout = accuracy * 255; -+ -+ if (hw_margin < accuracy || hw_margin > max_timeout) { -+ dev_err(dev, "hrtimer_hw_margin should be between %u and %u.\n", -+ accuracy, max_timeout); -+ return -EINVAL; -+ } -+ if ((feed_time > (hw_margin / 2)) || (feed_time == 0)) { -+ dev_err(dev, "feed_time[%d] should be less than half hw_margin or zeor.\n", feed_time); -+ return -EINVAL; -+ } -+ -+ hrtimer_s = feed_time / MS_TO_S; -+ hrtimer_ns = (feed_time % MS_TO_S) * MS_TO_NS; -+ set_time_val = hw_margin / accuracy; -+ -+ if (priv->timer_accuracy_reg_flag != 0) { -+ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, -+ priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); -+ if (ret < 0) { -+ dev_err(priv->dev, "set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", -+ priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); -+ return ret; -+ } -+ } -+ -+ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, -+ priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); -+ if (ret < 0) { -+ dev_err(dev, "set wdt time reg error.\n"); -+ return ret; -+ } -+ -+ if (priv->timer_update_reg_flag != 0) { -+ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, -+ priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); -+ if (ret < 0) { -+ dev_err(priv->dev, "set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", -+ priv->timer_update_reg, priv->timer_update_reg_val, ret); -+ return ret; -+ } -+ } -+ -+ priv->m_kt = ktime_set(hrtimer_s, hrtimer_ns); -+ hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ hrtimer->function = hrtimer_hwping; -+ hrtimer_start(hrtimer, priv->m_kt, HRTIMER_MODE_REL); -+ -+ ret = wb_wdt_enable_ctrl(priv, WDT_ON); -+ if (ret < 0) { -+ dev_err(dev, "hrtimer enable wdt failed.\n"); -+ return -ENXIO; -+ } -+ -+ return 0; -+} -+ -+static int wb_wdt_ping(struct watchdog_device *wdd) -+{ -+ wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); -+ -+ wdt_hwping(priv); -+ return 0; -+} -+ -+static int wb_wdt_start(struct watchdog_device *wdd) -+{ -+ wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); -+ int ret; -+ -+ ret = wb_wdt_enable_ctrl(priv, WDT_ON); -+ if (ret < 0) { -+ WDT_ERROR("start wdt enable failed.\n"); -+ return -ENXIO; -+ } -+ set_bit(WDOG_HW_RUNNING, &wdd->status); -+ return 0; -+} -+ -+static int wb_wdt_stop(struct watchdog_device *wdd) -+{ -+ wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); -+ int ret; -+ -+ ret = wb_wdt_enable_ctrl(priv, WDT_OFF); -+ if (ret < 0) { -+ WDT_ERROR("stop wdt enable failed.\n"); -+ return -ENXIO; -+ } -+ clear_bit(WDOG_HW_RUNNING, &wdd->status); -+ return 0; -+} -+ -+static int wb_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) -+{ -+ wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); -+ uint32_t timeout_ms; -+ uint32_t accuracy; -+ uint8_t set_time_val; -+ int ret; -+ -+ accuracy = priv->timer_accuracy; -+ timeout_ms = t * 1000; -+ if (timeout_ms > accuracy * 255) { -+ WDT_ERROR("set wdt timeout too larger error.timeout_ms:%u\n", timeout_ms); -+ return -EINVAL; -+ } -+ -+ if (priv->timer_accuracy_reg_flag != 0) { -+ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, -+ priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); -+ if (ret < 0) { -+ WDT_ERROR("set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", -+ priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); -+ return ret; -+ } -+ } -+ -+ set_time_val = timeout_ms / accuracy; -+ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, -+ priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); -+ if (ret < 0) { -+ WDT_ERROR("set wdt timeout reg error, set_time_val:%u ret:%d\n", set_time_val, ret); -+ return ret; -+ } -+ -+ if (priv->timer_update_reg_flag != 0) { -+ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, -+ priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); -+ if (ret < 0) { -+ WDT_ERROR("set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", -+ priv->timer_update_reg, priv->timer_update_reg_val, ret); -+ return ret; -+ } -+ } -+ -+ wdd->timeout = t; -+ -+ return 0; -+} -+ -+static unsigned int wb_wdt_get_timeleft(struct watchdog_device *wdd) -+{ -+ wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); -+ unsigned int time_left; -+ uint32_t accuracy; -+ uint8_t get_time_val; -+ int ret; -+ -+ accuracy = priv->timer_accuracy; -+ -+ ret = wb_wdt_read(priv->priv_func_mode, priv->config_dev_name, -+ priv->timeleft_cfg_reg, &get_time_val, ONE_BYTE); -+ if (ret < 0) { -+ WDT_ERROR("get wdt timeout reg error.ret:%d\n", ret); -+ return ret; -+ } -+ time_left = get_time_val * accuracy / MS_TO_S; -+ -+ WDT_VERBOSE("get wdt timeleft %d get_time_val %d accuracy=%d\n", -+ time_left, get_time_val, accuracy); -+ return time_left; -+} -+ -+static const struct watchdog_info wb_wdt_ident = { -+ .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, -+ .firmware_version = 0, -+ .identity = "CPLD Watchdog", -+}; -+ -+static const struct watchdog_ops wb_wdt_ops = { -+ .owner = THIS_MODULE, -+ .start = wb_wdt_start, -+ .stop = wb_wdt_stop, -+ .ping = wb_wdt_ping, -+ .set_timeout = wb_wdt_set_timeout, -+ .get_timeleft = wb_wdt_get_timeleft, -+}; -+ -+static int watchdog_device_cfg(wb_wdt_priv_t *priv) -+{ -+ int ret; -+ uint8_t set_time_val; -+ -+ ret = wb_wdt_enable_ctrl(priv, WDT_OFF); -+ if (ret < 0) { -+ dev_err(priv->dev, "probe disable wdt failed.\n"); -+ return -ENXIO; -+ } -+ -+ if (priv->timer_accuracy_reg_flag != 0) { -+ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, -+ priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); -+ if (ret < 0) { -+ dev_err(priv->dev, "set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", -+ priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); -+ return ret; -+ } -+ } -+ -+ set_time_val = priv->hw_margin / priv->timer_accuracy; -+ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, -+ priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); -+ if (ret < 0) { -+ dev_err(priv->dev, "set wdt time reg error.\n"); -+ return ret; -+ } -+ -+ if (priv->timer_update_reg_flag != 0) { -+ ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, -+ priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); -+ if (ret < 0) { -+ dev_err(priv->dev, "set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", -+ priv->timer_update_reg, priv->timer_update_reg_val, ret); -+ return ret; -+ } -+ } -+ -+ watchdog_set_drvdata(&priv->wdd, priv); -+ -+ priv->wdd.info = &wb_wdt_ident; -+ priv->wdd.ops = &wb_wdt_ops; -+ priv->wdd.bootstatus = 0; -+ priv->wdd.timeout = priv->hw_margin / MS_TO_S; -+ priv->wdd.min_timeout = priv->timer_accuracy / MS_TO_S; -+ priv->wdd.max_timeout = priv->timer_accuracy * MAX_REG_VAL / MS_TO_S; -+ priv->wdd.parent = priv->dev; -+ -+ watchdog_stop_on_reboot(&priv->wdd); -+ -+ ret = devm_watchdog_register_device(priv->dev, &priv->wdd); -+ if (ret != 0) { -+ dev_err(priv->dev, "cannot register watchdog device (err=%d)\n", ret); -+ return -ENXIO; -+ } -+ -+ return 0; -+} -+ -+static int logic_wdt_init(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) -+{ -+ struct device *dev; -+ logic_wdt_info_t *logic_wdt; -+ int ret; -+ -+ dev = priv->dev; -+ logic_wdt = &priv->logic_wdt; -+ -+ ret = 0; -+ if (dev->of_node) { -+ ret += of_property_read_string(dev->of_node, "feed_dev_name", &logic_wdt->feed_dev_name); -+ ret += of_property_read_u32(dev->of_node, "feed_reg", &logic_wdt->feed_reg); -+ ret += of_property_read_u8(dev->of_node, "active_val", &logic_wdt->active_val); -+ ret += of_property_read_u8(dev->of_node, "logic_func_mode", &logic_wdt->logic_func_mode); -+ if (ret != 0) { -+ dev_err(dev, "Failed to logic_wdt dts.\n"); -+ return -ENXIO; -+ } -+ } else { -+ logic_wdt->feed_dev_name = wb_wdt_device->wdt_config_mode.logic_wdt.feed_dev_name; -+ logic_wdt->feed_reg = wb_wdt_device->wdt_config_mode.logic_wdt.feed_reg; -+ logic_wdt->active_val = wb_wdt_device->wdt_config_mode.logic_wdt.active_val; -+ logic_wdt->logic_func_mode = wb_wdt_device->wdt_config_mode.logic_wdt.logic_func_mode; -+ } -+ -+ logic_wdt->state_val = logic_wdt->active_val; -+ -+ WDT_VERBOSE("feed_dev_name:%s, feed_reg:0x%x, active_val:%u, logic_func_mode:%u\n", -+ logic_wdt->feed_dev_name, logic_wdt->feed_reg, -+ logic_wdt->active_val, logic_wdt->logic_func_mode); -+ -+ return 0; -+} -+ -+static int gpio_wdt_init(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) -+{ -+ struct device *dev; -+ gpio_wdt_info_t *gpio_wdt; -+ enum of_gpio_flags flags; -+ uint32_t f = 0; -+ int ret; -+ -+ dev = priv->dev; -+ gpio_wdt = &priv->gpio_wdt; -+ -+ if (dev->of_node) { -+ gpio_wdt->gpio = of_get_gpio_flags(dev->of_node, 0, &flags); -+ } else { -+ gpio_wdt->gpio = wb_wdt_device->wdt_config_mode.gpio_wdt.gpio; -+ flags = wb_wdt_device->wdt_config_mode.gpio_wdt.flags; -+ } -+ if (!gpio_is_valid(gpio_wdt->gpio)) { -+ dev_err(dev, "gpio is invalid.\n"); -+ return gpio_wdt->gpio; -+ } -+ -+ gpio_wdt->active_low = flags & OF_GPIO_ACTIVE_LOW; -+ -+ if(priv->hw_algo == HW_ALGO_TOGGLE) { -+ f = GPIOF_IN; -+ } else { -+ f = gpio_wdt->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; -+ } -+ -+ ret = devm_gpio_request_one(dev, gpio_wdt->gpio, f, -+ dev_name(dev)); -+ if (ret) { -+ dev_err(dev, "devm_gpio_request_one failed.\n"); -+ return ret; -+ } -+ -+ gpio_wdt->state = gpio_wdt->active_low; -+ gpio_direction_output(gpio_wdt->gpio, gpio_wdt->state); -+ -+ WDT_VERBOSE("active_low:%d\n", gpio_wdt->active_low); -+ return 0; -+} -+ -+static ssize_t set_wdt_sysfs_value(struct device *dev, struct device_attribute *da, -+ const char *buf, size_t count) -+{ -+ wb_wdt_priv_t *priv = dev_get_drvdata(dev); -+ int ret, val; -+ -+ val = 0; -+ sscanf(buf, "%d", &val); -+ WDT_VERBOSE("set wdt, val:%d.\n", val); -+ -+ if (val < 0 || val > 255) { -+ WDT_ERROR("set wdt val %d failed.\n", val); -+ return -EINVAL; -+ } -+ -+ mutex_lock(&priv->update_lock); -+ -+ ret = wb_wdt_enable_ctrl(priv, val); -+ if (ret < 0) { -+ WDT_ERROR("set wdt sysfs value:%u failed.\n", val); -+ goto fail; -+ } -+ -+ WDT_VERBOSE("set wdt sysfs value:%u successed.\n", val); -+ mutex_unlock(&priv->update_lock); -+ return count; -+ -+fail: -+ mutex_unlock(&priv->update_lock); -+ return ret; -+} -+ -+static ssize_t show_wdt_sysfs_value(struct device *dev, -+ struct device_attribute *da, char *buf) -+{ -+ wb_wdt_priv_t *priv = dev_get_drvdata(dev); -+ uint8_t val, status; -+ int ret; -+ -+ mutex_lock(&priv->update_lock); -+ -+ ret = wb_wdt_read(priv->priv_func_mode, priv->config_dev_name, -+ priv->enable_reg, &val, ONE_BYTE); -+ if (ret < 0) { -+ dev_err(priv->dev, "read wdt enable reg val error.\n"); -+ goto fail; -+ } -+ -+ val &= priv->enable_mask; -+ if (val == priv->enable_val) { -+ status = WDT_ON; -+ } else if(val == priv->disable_val) { -+ status = WDT_OFF; -+ } else { -+ WDT_ERROR("enable reg read val not match set val, read val:%u, mask:%u, enable_val:%u, disable_val:%u", -+ val, priv->enable_mask, priv->enable_val, priv->disable_val); -+ ret = -EIO; -+ goto fail; -+ } -+ -+ WDT_VERBOSE("read_val:%u, mask:%u, enable_val:%u, disable_val:%u, status:%u", -+ val, priv->enable_mask, priv->enable_val, priv->disable_val, status); -+ -+ mutex_unlock(&priv->update_lock); -+ return sprintf(buf, "%u\n", status); -+ -+fail: -+ mutex_unlock(&priv->update_lock); -+ return ret; -+} -+ -+static SENSOR_DEVICE_ATTR(wdt_status, S_IRUGO | S_IWUSR, show_wdt_sysfs_value, set_wdt_sysfs_value, 0); -+ -+static struct attribute *wdt_sysfs_attrs[] = { -+ &sensor_dev_attr_wdt_status.dev_attr.attr, -+ NULL -+}; -+ -+static const struct attribute_group wdt_sysfs_group = { -+ .attrs = wdt_sysfs_attrs, -+}; -+ -+struct wdt_attr_match_group { -+ uint8_t index; -+ const struct attribute_group *attr_group_ptr; -+}; -+ -+static struct wdt_attr_match_group g_wdt_attr_match[] = { -+ {0, &wdt_sysfs_group}, -+}; -+ -+static const struct attribute_group *wdt_get_attr_group(uint32_t index) -+{ -+ int i; -+ struct wdt_attr_match_group *group; -+ -+ for (i = 0; i < ARRAY_SIZE(g_wdt_attr_match); i++) { -+ group = &g_wdt_attr_match[i]; -+ if (index == group->index) { -+ WDT_VERBOSE("get wdt attr, index:%u.\n", index); -+ return group->attr_group_ptr; -+ } -+ } -+ -+ return NULL; -+} -+ -+static int wb_wdt_probe(struct platform_device *pdev) -+{ -+ wb_wdt_priv_t *priv; -+ int ret; -+ const char *algo; -+ wb_wdt_device_t *wb_wdt_device; -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) { -+ dev_err(&pdev->dev, "devm_kzalloc failed.\n"); -+ return -ENOMEM; -+ } -+ -+ platform_set_drvdata(pdev, priv); -+ -+ if (pdev->dev.of_node) { -+ ret = 0; -+ ret += of_property_read_string(pdev->dev.of_node, "config_dev_name", &priv->config_dev_name); -+ ret += of_property_read_string(pdev->dev.of_node, "hw_algo", &algo); -+ ret += of_property_read_u8(pdev->dev.of_node, "config_mode", &priv->config_mode); -+ ret += of_property_read_u8(pdev->dev.of_node, "priv_func_mode", &priv->priv_func_mode); -+ ret += of_property_read_u8(pdev->dev.of_node, "enable_val", &priv->enable_val); -+ ret += of_property_read_u8(pdev->dev.of_node, "disable_val", &priv->disable_val); -+ ret += of_property_read_u8(pdev->dev.of_node, "enable_mask", &priv->enable_mask); -+ ret += of_property_read_u32(pdev->dev.of_node, "enable_reg", &priv->enable_reg); -+ ret += of_property_read_u32(pdev->dev.of_node, "timeout_cfg_reg", &priv->timeout_cfg_reg); -+ ret += of_property_read_u32(pdev->dev.of_node,"hw_margin_ms", &priv->hw_margin); -+ ret += of_property_read_u8(pdev->dev.of_node,"feed_wdt_type", &priv->feed_wdt_type); -+ ret += of_property_read_u32(pdev->dev.of_node,"timer_accuracy", &priv->timer_accuracy); -+ if (ret != 0) { -+ dev_err(&pdev->dev, "Failed to priv dts.\n"); -+ return -ENXIO; -+ } -+ -+ priv->sysfs_index = SYSFS_NO_CFG; -+ of_property_read_u8(pdev->dev.of_node,"sysfs_index", &priv->sysfs_index); -+ -+ priv->timeleft_cfg_reg = priv->timeout_cfg_reg; -+ of_property_read_u32(pdev->dev.of_node,"timeleft_cfg_reg", &priv->timeleft_cfg_reg); -+ -+ /* timer accuracy register is optional */ -+ ret = of_property_read_u8(pdev->dev.of_node,"timer_accuracy_reg_flag", &priv->timer_accuracy_reg_flag); -+ if (ret < 0) { -+ /* case: don't has timer_accuracy_reg */ -+ dev_dbg(&pdev->dev, "Failed to get property in dts: timer_accuracy_reg_flag.\n"); -+ priv->timer_accuracy_reg_flag = 0; -+ } else { -+ ret = of_property_read_u32(pdev->dev.of_node, "timer_accuracy_reg", &priv->timer_accuracy_reg); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "Failed to get timer accuracy register address.\n"); -+ return -ENXIO; -+ } -+ ret = of_property_read_u8(pdev->dev.of_node, "timer_accuracy_reg_val", &priv->timer_accuracy_reg_val); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "Failed to get timer accuracy register value.\n"); -+ return -ENXIO; -+ } -+ } -+ -+ /* timer update register is optional */ -+ ret = of_property_read_u8(pdev->dev.of_node,"timer_update_reg_flag", &priv->timer_update_reg_flag); -+ if (ret < 0) { -+ /* case: don't has timer_update_reg */ -+ dev_dbg(&pdev->dev, "Failed to get property in dts: timer_update_reg_flag.\n"); -+ priv->timer_update_reg_flag = 0; /* no timer update register */ -+ } else { -+ ret = of_property_read_u32(pdev->dev.of_node, "timer_update_reg", &priv->timer_update_reg); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "Failed to get timer update register address.\n"); -+ return -ENXIO; -+ } -+ ret = of_property_read_u8(pdev->dev.of_node, "timer_update_reg_val", &priv->timer_update_reg_val); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "Failed to get timer update register value.\n"); -+ return -ENXIO; -+ } -+ } -+ } else { -+ if (pdev->dev.platform_data == NULL) { -+ dev_err(&pdev->dev, "Failed to get platform data config.\n"); -+ return -ENXIO; -+ } -+ wb_wdt_device = pdev->dev.platform_data; -+ priv->config_dev_name = wb_wdt_device->config_dev_name; -+ algo = wb_wdt_device->hw_algo; -+ priv->config_mode = wb_wdt_device->config_mode; -+ priv->priv_func_mode = wb_wdt_device->priv_func_mode; -+ priv->enable_val = wb_wdt_device->enable_val; -+ priv->disable_val = wb_wdt_device->disable_val; -+ priv->enable_mask = wb_wdt_device->enable_mask; -+ priv->enable_reg = wb_wdt_device->enable_reg; -+ priv->timeout_cfg_reg = wb_wdt_device->timeout_cfg_reg; -+ priv->hw_margin = wb_wdt_device->hw_margin; -+ priv->timer_accuracy = wb_wdt_device->timer_accuracy; -+ priv->feed_wdt_type = wb_wdt_device->feed_wdt_type; -+ priv->sysfs_index = wb_wdt_device->sysfs_index; -+ priv->timeleft_cfg_reg = wb_wdt_device->timeleft_cfg_reg; -+ priv->timer_accuracy_reg_flag = wb_wdt_device->timer_accuracy_reg_flag; -+ priv->timer_accuracy_reg = wb_wdt_device->timer_accuracy_reg; -+ priv->timer_accuracy_reg_val = wb_wdt_device->timer_accuracy_reg_val; -+ priv->timer_update_reg_flag = wb_wdt_device->timer_update_reg_flag; -+ priv->timer_update_reg = wb_wdt_device->timer_update_reg; -+ priv->timer_update_reg_val = wb_wdt_device->timer_update_reg_val; -+ } -+ -+ if (!strcmp(algo, "toggle")) { -+ priv->hw_algo = HW_ALGO_TOGGLE; -+ } else if (!strcmp(algo, "level")) { -+ priv->hw_algo = HW_ALGO_LEVEL; -+ } else if (!strcmp(algo, "eigenvalues")) { -+ priv->hw_algo = HW_ALGO_EIGENVALUES; -+ } else { -+ dev_err(&pdev->dev, "hw_algo config error.must be toggle or level.\n"); -+ return -EINVAL; -+ } -+ -+ WDT_VERBOSE("config_dev_name:%s, config_mode:%u, priv_func_mode:%u, enable_reg:0x%x, timeout_cfg_reg:0x%x\n", -+ priv->config_dev_name, priv->config_mode, priv->priv_func_mode, priv->enable_reg, priv->timeout_cfg_reg); -+ WDT_VERBOSE("timeout_cfg_reg:0x%x, enable_val:0x%x, disable_val:0x%x, enable_mask:0x%x, hw_margin:%u, feed_wdt_type:%u\n", -+ priv->timeleft_cfg_reg, priv->enable_val, priv->disable_val, priv->enable_mask, priv->hw_margin, priv->feed_wdt_type); -+ WDT_VERBOSE("timer_accuracy_reg_flag: %d, timer_accuracy_reg: 0x%x, timer_accuracy_reg_val: 0x%x, timer_accuracy: %d\n", -+ priv->timer_accuracy_reg_flag, priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, priv->timer_accuracy); -+ WDT_VERBOSE("timer_update_reg_flag: %d, timer_update_reg: 0x%x, timer_update_reg_val: 0x%x\n", priv->timer_update_reg_flag, -+ priv->timer_update_reg, priv->timer_update_reg_val); -+ -+ priv->dev = &pdev->dev; -+ if (priv->config_mode == GPIO_FEED_WDT_MODE) { -+ ret = gpio_wdt_init(priv, wb_wdt_device); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "init gpio mode wdt failed.\n"); -+ return -ENXIO; -+ } -+ } else if (priv->config_mode == LOGIC_FEED_WDT_MODE) { -+ ret = logic_wdt_init(priv, wb_wdt_device); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "init func mode wdt failed.\n"); -+ return -ENXIO; -+ } -+ } else { -+ dev_err(&pdev->dev, "unsupport %u config_mode, dts configure error.\n", -+ priv->config_mode); -+ return -ENXIO; -+ } -+ -+ switch (priv->feed_wdt_type) { -+ case WATCHDOG_DEVICE_TYPE: -+ ret = watchdog_device_cfg(priv); -+ break; -+ case HRTIMER_TYPE: -+ ret = hrtimer_cfg(priv, wb_wdt_device); -+ break; -+ case THREAD_TYPE: -+ ret = thread_timer_create(priv, wb_wdt_device); -+ break; -+ default: -+ dev_err(&pdev->dev, "timer type %u unsupport.\n", priv->feed_wdt_type); -+ return -EINVAL; -+ } -+ if (ret < 0) { -+ dev_err(&pdev->dev, "init timer feed_wdt_type %u failed.\n", priv->feed_wdt_type); -+ return -ENXIO; -+ } -+ -+ dev_info(&pdev->dev, "register %s mode, config_mode %u, func_mode %u, %u ms overtime wdt success\n", -+ algo, priv->config_mode, priv->priv_func_mode, priv->hw_margin); -+ -+ if (priv->sysfs_index != SYSFS_NO_CFG) { -+ -+ priv->sysfs_group = wdt_get_attr_group(priv->sysfs_index); -+ if (priv->sysfs_group) { -+ ret = sysfs_create_group(&pdev->dev.kobj, priv->sysfs_group); -+ if (ret != 0) { -+ dev_err(&pdev->dev, "sysfs_create_group failed. ret:%d.\n", ret); -+ return -ENOMEM; -+ } -+ dev_info(&pdev->dev, "sysfs create group success\n"); -+ } else { -+ dev_err(&pdev->dev, "failed to find %u index wdt, return NULL.\n", priv->sysfs_index); -+ return -ENOMEM; -+ } -+ -+ mutex_init(&priv->update_lock); -+ -+ dev_info(&pdev->dev, "register %u index wdt sysfs success." ,priv->sysfs_index); -+ } -+ -+ return 0; -+} -+ -+static void unregister_action(struct platform_device *pdev) -+{ -+ wb_wdt_priv_t *priv = platform_get_drvdata(pdev); -+ gpio_wdt_info_t *gpio_wdt; -+ logic_wdt_info_t *logic_wdt; -+ int ret; -+ -+ ret = wb_wdt_enable_ctrl(priv, WDT_OFF); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "remove disable wdt failed.\n"); -+ } -+ -+ if (priv->sysfs_index != SYSFS_NO_CFG) { -+ sysfs_remove_group(&pdev->dev.kobj, priv->sysfs_group); -+ } -+ -+ if (priv->feed_wdt_type == HRTIMER_TYPE) { -+ hrtimer_cancel(&priv->hrtimer); -+ } else if (priv->feed_wdt_type == THREAD_TYPE) { -+ kthread_stop(priv->thread); -+ priv->thread = NULL; -+ } else { -+ WDT_VERBOSE("wdd type, do nothing.\n"); -+ } -+ -+ if (priv->config_mode == GPIO_FEED_WDT_MODE) { -+ gpio_wdt = &priv->gpio_wdt; -+ gpio_set_value_cansleep(gpio_wdt->gpio, !gpio_wdt->active_low); -+ -+ if (priv->hw_algo == HW_ALGO_TOGGLE) { -+ gpio_direction_input(gpio_wdt->gpio); -+ } -+ } else { -+ logic_wdt = &priv->logic_wdt; -+ logic_wdt->state_val = !logic_wdt->state_val; -+ ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, -+ logic_wdt->feed_reg, &logic_wdt->state_val, ONE_BYTE); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "set wdt control reg error.\n"); -+ } -+ } -+ -+ return; -+} -+ -+static int wb_wdt_remove(struct platform_device *pdev) -+{ -+ WDT_VERBOSE("enter remove wdt.\n"); -+ unregister_action(pdev); -+ dev_info(&pdev->dev, "remove wdt finish.\n"); -+ -+ return 0; -+} -+ -+static void wb_wdt_shutdown(struct platform_device *pdev) -+{ -+ WDT_VERBOSE("enter shutdown wdt.\n"); -+ unregister_action(pdev); -+ dev_info(&pdev->dev, "shutdown wdt finish.\n"); -+ -+ return; -+} -+ -+static const struct of_device_id wb_wdt_dt_ids[] = { -+ { .compatible = "wb_wdt", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, wb_wdt_dt_ids); -+ -+static struct platform_driver wb_wdt_driver = { -+ .driver = { -+ .name = "wb_wdt", -+ .of_match_table = wb_wdt_dt_ids, -+ }, -+ .probe = wb_wdt_probe, -+ .remove = wb_wdt_remove, -+ .shutdown = wb_wdt_shutdown, -+}; -+ -+#ifdef CONFIG_GPIO_WATCHDOG_ARCH_INITCALL -+static int __init wb_wdt_init(void) -+{ -+ return platform_driver_register(&wb_wdt_driver); -+} -+arch_initcall(wb_wdt_init); -+#else -+module_platform_driver(wb_wdt_driver); -+#endif -+ -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("watchdog driver"); -+MODULE_LICENSE("GPL"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.h -new file mode 100644 -index 000000000..d45904ba3 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.h -@@ -0,0 +1,53 @@ -+#ifndef __WB_WDT_H__ -+#define __WB_WDT_H__ -+ -+#include -+ -+#define SYSFS_NO_CFG (0xff) -+#define INVALID_REG_ADDR (0xffffffff) -+ -+typedef struct gpio_wdt_info_s { -+ int gpio; -+ enum of_gpio_flags flags; -+ bool active_low; -+ bool state; -+}gpio_wdt_info_t; -+ -+typedef struct logic_wdt_info_s { -+ const char *feed_dev_name; -+ uint8_t logic_func_mode; -+ uint32_t feed_reg; -+ uint8_t active_val; -+ uint8_t state_val; -+}logic_wdt_info_t; -+ -+typedef struct wb_wdt_device_s { -+ int device_flag; -+ const char *config_dev_name; -+ uint8_t config_mode; -+ const char *hw_algo; -+ uint8_t enable_val; -+ uint8_t disable_val; -+ uint8_t enable_mask; -+ uint8_t priv_func_mode; -+ uint8_t feed_wdt_type; -+ uint32_t enable_reg; -+ uint32_t timeout_cfg_reg; -+ uint32_t timeleft_cfg_reg; -+ uint32_t hw_margin; -+ uint32_t feed_time; -+ uint8_t timer_accuracy_reg_flag; -+ uint32_t timer_accuracy_reg; -+ uint8_t timer_accuracy_reg_val; -+ uint32_t timer_accuracy; -+ uint8_t timer_update_reg_flag; -+ uint32_t timer_update_reg; -+ uint8_t timer_update_reg_val; -+ union { -+ gpio_wdt_info_t gpio_wdt; -+ logic_wdt_info_t logic_wdt; -+ } wdt_config_mode; -+ uint8_t sysfs_index; -+} wb_wdt_device_t; -+ -+#endif -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_xdpe132g5c.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_xdpe132g5c.c -new file mode 100644 -index 000000000..edc12d34b ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_xdpe132g5c.c -@@ -0,0 +1,574 @@ -+/* -+ * xdpe132g5c_i2c_drv.c -+ * -+ * This module create sysfs to set AVS and create hwmon to get out power -+ * through xdpe132g5c I2C address. -+ * -+ * History -+ * [Version] [Date] [Description] -+ * * v1.0 2021-09-17 Initial version -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define WB_I2C_RETRY_SLEEP_TIME (10000) /* 10ms */ -+#define WB_I2C_RETRY_TIME (10) -+#define WB_XDPE_I2C_PAGE_ADDR (0xff) -+#define WB_XDPE_I2C_VOUT_MODE (0x40) -+#define WB_XDPE_I2C_VOUT_COMMAND (0x42) -+#define WB_XDPE_I2C_VOUT_PAGE (0x06) -+#define WB_XDPE_VOUT_MAX_THRESHOLD ((0xFFFF * 1000L * 1000L) / (256)) -+#define WB_XDPE_VOUT_MIN_THRESHOLD (0) -+ -+static int g_wb_xdpe_debug = 0; -+static int g_wb_xdpe_error = 0; -+ -+module_param(g_wb_xdpe_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_xdpe_error, int, S_IRUGO | S_IWUSR); -+ -+#define WB_XDPE_VERBOSE(fmt, args...) do { \ -+ if (g_wb_xdpe_debug) { \ -+ printk(KERN_INFO "[WB_XDPE][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_XDPE_ERROR(fmt, args...) do { \ -+ if (g_wb_xdpe_error) { \ -+ printk(KERN_ERR "[WB_XDPE][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+struct xdpe_data { -+ struct i2c_client *client; -+ struct device *hwmon_dev; -+ struct mutex update_lock; -+ long vout_max; -+ long vout_min; -+}; -+ -+typedef struct xdpe_vout_data_s { -+ u8 vout_mode; -+ int vout_precision; -+} xdpe_vout_data_t; -+ -+static xdpe_vout_data_t g_xdpe_vout_group[] = { -+ {.vout_mode = 0x18, .vout_precision = 256}, -+ {.vout_mode = 0x17, .vout_precision = 512}, -+ {.vout_mode = 0x16, .vout_precision = 1024}, -+ {.vout_mode = 0x15, .vout_precision = 2048}, -+ {.vout_mode = 0x14, .vout_precision = 4096}, -+}; -+ -+static s32 wb_i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command) -+{ -+ int i; -+ s32 ret; -+ -+ for (i = 0; i < WB_I2C_RETRY_TIME; i++) { -+ ret = i2c_smbus_read_byte_data(client, command); -+ if (ret >= 0) { -+ return ret; -+ } -+ usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); -+ } -+ return ret; -+} -+ -+static s32 wb_i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command, u8 value) -+{ -+ int i; -+ s32 ret; -+ -+ for (i = 0; i < WB_I2C_RETRY_TIME; i++) { -+ ret = i2c_smbus_write_byte_data(client, command, value); -+ if (ret >= 0) { -+ return ret; -+ } -+ usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); -+ } -+ return ret; -+} -+ -+static s32 wb_i2c_smbus_read_word_data(const struct i2c_client *client, u8 command) -+{ -+ int i; -+ s32 ret; -+ -+ for (i = 0; i < WB_I2C_RETRY_TIME; i++) { -+ ret = i2c_smbus_read_word_data(client, command); -+ if (ret >= 0) { -+ return ret; -+ } -+ usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); -+ } -+ return ret; -+} -+ -+static s32 wb_i2c_smbus_write_word_data(const struct i2c_client *client, u8 command, -+ u16 value) -+{ -+ int i; -+ s32 ret; -+ -+ for (i = 0; i < WB_I2C_RETRY_TIME; i++) { -+ ret = i2c_smbus_write_word_data(client, command, value); -+ if (ret >= 0) { -+ return ret; -+ } -+ usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); -+ } -+ return ret; -+} -+ -+static long calc_power_linear11_data(int data) -+{ -+ s16 exponent; -+ s32 mantissa; -+ long val; -+ -+ exponent = ((s16)data) >> 11; -+ mantissa = ((s16)((data & 0x7ff) << 5)) >> 5; -+ val = mantissa; -+ val = val * 1000L * 1000L; -+ -+ if (exponent >= 0) { -+ val <<= exponent; -+ } else { -+ val >>= -exponent; -+ } -+ return val; -+} -+ -+static int read_xdpe_power_value(const struct i2c_client *client, u8 page, u8 reg, long *value) -+{ -+ int ret, data; -+ -+ ret = wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, page); -+ if (ret < 0) { -+ WB_XDPE_ERROR("%d-%04x: set xdpe page%u failed, ret: %d\n", client->adapter->nr, -+ client->addr, page, ret); -+ return ret; -+ } -+ data = wb_i2c_smbus_read_word_data(client, reg); -+ if (data < 0) { -+ WB_XDPE_ERROR("%d-%04x: read xdpe page%u reg: 0x%x failed, ret: %d\n", -+ client->adapter->nr, client->addr, page, reg, data); -+ return data; -+ } -+ *value = calc_power_linear11_data(data); -+ WB_XDPE_VERBOSE("%d-%04x: page%u reg: 0x%x rd_data: 0x%x, decode linear11 value: %ld\n", -+ client->adapter->nr, client->addr, page, reg, data, *value); -+ return 0; -+} -+ -+static ssize_t xdpe_power_value_show(struct device *dev, struct device_attribute *da, -+ char *buf) -+{ -+ int ret, ori_page; -+ u16 sensor_h, sensor_l; -+ u8 page, reg; -+ struct sensor_device_attribute *attr; -+ struct i2c_client *client; -+ struct xdpe_data *data; -+ long value1, value2; -+ -+ data = dev_get_drvdata(dev); -+ client = data->client; -+ attr = to_sensor_dev_attr(da); -+ sensor_h = ((attr->index) >> 16) & 0xffff; -+ sensor_l = (attr->index) & 0xffff; -+ -+ mutex_lock(&data->update_lock); -+ -+ ori_page = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_PAGE_ADDR); -+ if (ori_page < 0) { -+ WB_XDPE_ERROR("%d-%04x: read xdpe origin page failed, ret: %d\n", client->adapter->nr, -+ client->addr, ori_page); -+ mutex_unlock(&data->update_lock); -+ return ori_page; -+ } -+ value1 = 0; -+ value2 = 0; -+ -+ if (sensor_h) { -+ page = (sensor_h >> 8) & 0xff; -+ reg = sensor_h & 0xff; -+ ret = read_xdpe_power_value(client, page, reg, &value1); -+ if (ret < 0) { -+ WB_XDPE_ERROR("%d-%04x: read xdpe sensor high sensor page%u reg: 0x%x failed, ret: %d\n", -+ client->adapter->nr, client->addr, page, reg, ret); -+ goto error; -+ } -+ WB_XDPE_VERBOSE("%d-%04x: read xdpe sensor high sensor page%u reg: 0x%x success, value: %ld\n", -+ client->adapter->nr, client->addr, page, reg, value1); -+ } -+ -+ page = (sensor_l >> 8) & 0xff; -+ reg = sensor_l & 0xff; -+ ret = read_xdpe_power_value(client, page, reg, &value2); -+ if (ret < 0) { -+ WB_XDPE_ERROR("%d-%04x: read xdpe sensor low sensor page%u reg: 0x%x failed, ret: %d\n", -+ client->adapter->nr, client->addr, page, reg, ret); -+ goto error; -+ } -+ WB_XDPE_VERBOSE("%d-%04x: read xdpe sensor low sensor page%u reg: 0x%x success, value: %ld\n", -+ client->adapter->nr, client->addr, page, reg, value2); -+ -+ wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); -+ mutex_unlock(&data->update_lock); -+ return snprintf(buf, PAGE_SIZE, "%ld\n", value1 + value2); -+error: -+ wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); -+ mutex_unlock(&data->update_lock); -+ return ret; -+} -+ -+static int xdpe_get_vout_precision(const struct i2c_client *client, int *vout_precision) -+{ -+ int i, vout_mode, a_size; -+ -+ vout_mode = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_VOUT_MODE); -+ if (vout_mode < 0) { -+ WB_XDPE_ERROR("%d-%04x: read xdpe vout mode reg: 0x%x failed, ret: %d\n", -+ client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_MODE, vout_mode); -+ return vout_mode; -+ } -+ -+ a_size = ARRAY_SIZE(g_xdpe_vout_group); -+ for (i = 0; i < a_size; i++) { -+ if (g_xdpe_vout_group[i].vout_mode == vout_mode) { -+ *vout_precision = g_xdpe_vout_group[i].vout_precision; -+ WB_XDPE_VERBOSE("%d-%04x: match, vout mode: 0x%x, precision: %d\n", -+ client->adapter->nr, client->addr, vout_mode, *vout_precision); -+ break; -+ } -+ } -+ if (i == a_size) { -+ WB_XDPE_ERROR("%d-%04x: invalid vout mode: 0x%x\n",client->adapter->nr, client->addr, -+ vout_mode); -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static ssize_t xdpe_avs_vout_show(struct device *dev, struct device_attribute *da, char *buf) -+{ -+ int ret, ori_page, vout_cmd, vout_precision; -+ struct i2c_client *client; -+ struct xdpe_data *data; -+ long vout; -+ -+ client = to_i2c_client(dev); -+ data = i2c_get_clientdata(client); -+ -+ mutex_lock(&data->update_lock); -+ -+ ori_page = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_PAGE_ADDR); -+ if (ori_page < 0) { -+ WB_XDPE_ERROR("%d-%04x: read xdpe origin page failed, ret: %d\n", client->adapter->nr, -+ client->addr, ori_page); -+ mutex_unlock(&data->update_lock); -+ return ori_page; -+ } -+ -+ ret = wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, WB_XDPE_I2C_VOUT_PAGE); -+ if (ret < 0) { -+ WB_XDPE_ERROR("%d-%04x: set xdpe avs vout page%u failed, ret: %d\n", client->adapter->nr, -+ client->addr, WB_XDPE_I2C_VOUT_PAGE, ret); -+ goto error; -+ } -+ -+ ret = xdpe_get_vout_precision(client, &vout_precision); -+ if (ret < 0) { -+ WB_XDPE_ERROR("%d-%04x: get xdpe avs vout precision failed, ret: %d\n", -+ client->adapter->nr, client->addr, ret); -+ goto error; -+ } -+ -+ vout_cmd = wb_i2c_smbus_read_word_data(client, WB_XDPE_I2C_VOUT_COMMAND); -+ if (vout_cmd < 0) { -+ ret = vout_cmd; -+ WB_XDPE_ERROR("%d-%04x: read xdpe vout command reg: 0x%x failed, ret: %d\n", -+ client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_COMMAND, ret); -+ goto error; -+ } -+ -+ wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); -+ mutex_unlock(&data->update_lock); -+ -+ vout = vout_cmd * 1000L * 1000L / vout_precision; -+ WB_XDPE_VERBOSE("%d-%04x: vout: %ld, vout_cmd: 0x%x, precision: %d\n", client->adapter->nr, -+ client->addr, vout, vout_cmd, vout_precision); -+ return snprintf(buf, PAGE_SIZE, "%ld\n", vout); -+error: -+ wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); -+ mutex_unlock(&data->update_lock); -+ return ret; -+} -+ -+static ssize_t xdpe_avs_vout_store(struct device *dev, struct device_attribute *da, -+ const char *buf, size_t count) -+{ -+ int ret, ori_page, vout_cmd, vout_cmd_set, vout_precision; -+ struct i2c_client *client; -+ struct xdpe_data *data; -+ long vout, vout_max, vout_min; -+ -+ client = to_i2c_client(dev); -+ ret = kstrtol(buf, 10, &vout); -+ if (ret) { -+ WB_XDPE_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); -+ return -EINVAL; -+ } -+ -+ data = i2c_get_clientdata(client); -+ vout_max = data->vout_max; -+ vout_min = data->vout_min; -+ if ((vout > vout_max) || (vout < vout_min)) { -+ WB_XDPE_ERROR("%d-%04x: vout value: %ld, out of range [%ld, %ld] \n", client->adapter->nr, -+ client->addr, vout, vout_min, vout_max); -+ return -EINVAL; -+ } -+ -+ mutex_lock(&data->update_lock); -+ -+ ori_page = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_PAGE_ADDR); -+ if (ori_page < 0) { -+ WB_XDPE_ERROR("%d-%04x: read xdpe origin page failed, ret: %d\n", client->adapter->nr, -+ client->addr, ori_page); -+ mutex_unlock(&data->update_lock); -+ return ori_page; -+ } -+ -+ ret = wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, WB_XDPE_I2C_VOUT_PAGE); -+ if (ret < 0) { -+ WB_XDPE_ERROR("%d-%04x: set xdpe avs vout page%u failed, ret: %d\n", client->adapter->nr, -+ client->addr, WB_XDPE_I2C_VOUT_PAGE, ret); -+ goto error; -+ } -+ -+ ret = xdpe_get_vout_precision(client, &vout_precision); -+ if (ret < 0) { -+ WB_XDPE_ERROR("%d-%04x: get xdpe avs vout precision failed, ret: %d\n", -+ client->adapter->nr, client->addr, ret); -+ goto error; -+ } -+ -+ vout_cmd_set = (vout * vout_precision) / (1000L * 1000L); -+ if (vout_cmd_set > 0xffff) { -+ WB_XDPE_ERROR("%d-%04x: invalid value, vout %ld, vout_precision: %d, vout_cmd_set: 0x%x\n", -+ client->adapter->nr, client->addr, vout, vout_precision, vout_cmd_set); -+ ret = -EINVAL; -+ goto error; -+ } -+ ret = wb_i2c_smbus_write_word_data(client, WB_XDPE_I2C_VOUT_COMMAND, vout_cmd_set); -+ if (ret < 0) { -+ WB_XDPE_ERROR("%d-%04x: set xdpe vout cmd reg: 0x%x, value: 0x%x failed, ret: %d\n", -+ client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_COMMAND, vout_cmd_set, ret); -+ goto error; -+ } -+ -+ vout_cmd = wb_i2c_smbus_read_word_data(client, WB_XDPE_I2C_VOUT_COMMAND); -+ if (vout_cmd < 0) { -+ ret = vout_cmd; -+ WB_XDPE_ERROR("%d-%04x: read xdpe vout command reg: 0x%x failed, ret: %d\n", -+ client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_COMMAND, ret); -+ goto error; -+ } -+ if (vout_cmd != vout_cmd_set) { -+ ret = -EIO; -+ WB_XDPE_ERROR("%d-%04x: vout cmd value check error, vout cmd read: 0x%x, vout cmd set: 0x%x\n", -+ client->adapter->nr, client->addr, vout_cmd, vout_cmd_set); -+ goto error; -+ -+ } -+ -+ wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); -+ mutex_unlock(&data->update_lock); -+ WB_XDPE_VERBOSE("%d-%04x: set vout cmd success, vout %ld, vout_precision: %d, vout_cmd_set: 0x%x\n", -+ client->adapter->nr, client->addr, vout, vout_precision, vout_cmd_set); -+ return count; -+error: -+ wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); -+ mutex_unlock(&data->update_lock); -+ return ret; -+} -+ -+static ssize_t xdpe_avs_vout_max_show(struct device *dev, struct device_attribute *da, char *buf) -+{ -+ struct i2c_client *client; -+ struct xdpe_data *data; -+ long vout_max; -+ -+ client = to_i2c_client(dev); -+ data = i2c_get_clientdata(client); -+ vout_max = data->vout_max; -+ return snprintf(buf, PAGE_SIZE, "%ld\n", vout_max); -+} -+ -+static ssize_t xdpe_avs_vout_max_store(struct device *dev, struct device_attribute *da, -+ const char *buf, size_t count) -+{ -+ int ret; -+ struct i2c_client *client; -+ struct xdpe_data *data; -+ long vout_max; -+ -+ client = to_i2c_client(dev); -+ ret = kstrtol(buf, 10, &vout_max); -+ if (ret) { -+ WB_XDPE_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); -+ return -EINVAL; -+ } -+ WB_XDPE_VERBOSE("%d-%04x: vout max threshold: %ld", client->adapter->nr, client->addr, -+ vout_max); -+ data = i2c_get_clientdata(client); -+ data->vout_max = vout_max; -+ return count; -+} -+ -+static ssize_t xdpe_avs_vout_min_show(struct device *dev, struct device_attribute *da, char *buf) -+{ -+ struct i2c_client *client; -+ struct xdpe_data *data; -+ long vout_min; -+ -+ client = to_i2c_client(dev); -+ data = i2c_get_clientdata(client); -+ vout_min = data->vout_min; -+ return snprintf(buf, PAGE_SIZE, "%ld\n", vout_min); -+} -+ -+static ssize_t xdpe_avs_vout_min_store(struct device *dev, struct device_attribute *da, -+ const char *buf, size_t count) -+{ -+ int ret; -+ struct i2c_client *client; -+ struct xdpe_data *data; -+ long vout_min; -+ -+ client = to_i2c_client(dev); -+ ret = kstrtol(buf, 10, &vout_min); -+ if (ret) { -+ WB_XDPE_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); -+ return -EINVAL; -+ } -+ WB_XDPE_VERBOSE("%d-%04x: vout min threshold: %ld", client->adapter->nr, client->addr, -+ vout_min); -+ data = i2c_get_clientdata(client); -+ data->vout_min = vout_min; -+ return count; -+} -+ -+/* xdpe hwmon */ -+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO ,xdpe_power_value_show, NULL, 0x072c); -+static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO ,xdpe_power_value_show, NULL, 0x0b2c); -+static SENSOR_DEVICE_ATTR(power3_input, S_IRUGO ,xdpe_power_value_show, NULL, 0x072c0b2c); -+ -+static struct attribute *xdpe_hwmon_attrs[] = { -+ &sensor_dev_attr_power1_input.dev_attr.attr, -+ &sensor_dev_attr_power2_input.dev_attr.attr, -+ &sensor_dev_attr_power3_input.dev_attr.attr, -+ NULL -+}; -+ATTRIBUTE_GROUPS(xdpe_hwmon); -+ -+/* xdpe sysfs */ -+static SENSOR_DEVICE_ATTR(avs_vout, S_IRUGO | S_IWUSR, xdpe_avs_vout_show, xdpe_avs_vout_store, 0); -+static SENSOR_DEVICE_ATTR(avs_vout_max, S_IRUGO | S_IWUSR, xdpe_avs_vout_max_show, xdpe_avs_vout_max_store, 0); -+static SENSOR_DEVICE_ATTR(avs_vout_min, S_IRUGO | S_IWUSR, xdpe_avs_vout_min_show, xdpe_avs_vout_min_store, 0); -+ -+static struct attribute *xdpe132g5c_sysfs_attrs[] = { -+ &sensor_dev_attr_avs_vout.dev_attr.attr, -+ &sensor_dev_attr_avs_vout_max.dev_attr.attr, -+ &sensor_dev_attr_avs_vout_min.dev_attr.attr, -+ NULL, -+}; -+ -+static const struct attribute_group xdpe132g5c_sysfs_attrs_group = { -+ .attrs = xdpe132g5c_sysfs_attrs, -+}; -+ -+static int xdpe132g5c_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct xdpe_data *data; -+ int ret; -+ -+ WB_XDPE_VERBOSE("bus: %d, addr: 0x%02x do probe.\n", client->adapter->nr, client->addr); -+ data = devm_kzalloc(&client->dev, sizeof(struct xdpe_data), GFP_KERNEL); -+ if (!data) { -+ dev_err(&client->dev, "devm_kzalloc failed.\n"); -+ return -ENOMEM; -+ } -+ -+ data->client = client; -+ i2c_set_clientdata(client, data); -+ mutex_init(&data->update_lock); -+ -+ ret = sysfs_create_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); -+ if (ret != 0) { -+ dev_err(&client->dev, "Create xdpe132g5c sysfs failed, ret: %d\n", ret); -+ return ret; -+ } -+ data->hwmon_dev = hwmon_device_register_with_groups(&client->dev, client->name, data, -+ xdpe_hwmon_groups); -+ if (IS_ERR(data->hwmon_dev)) { -+ ret = PTR_ERR(data->hwmon_dev); -+ sysfs_remove_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); -+ dev_err(&client->dev, "Failed to register xdpe hwmon device, ret: %d\n", ret); -+ return ret; -+ } -+ data->vout_max = WB_XDPE_VOUT_MAX_THRESHOLD; -+ data->vout_min = WB_XDPE_VOUT_MIN_THRESHOLD; -+ dev_info(&client->dev, "xdpe132g5c probe success\n"); -+ return 0; -+} -+ -+static int xdpe132g5c_remove(struct i2c_client *client) -+{ -+ struct xdpe_data *data; -+ -+ WB_XDPE_VERBOSE("bus: %d, addr: 0x%02x do remove\n", client->adapter->nr, client->addr); -+ data = i2c_get_clientdata(client); -+ hwmon_device_unregister(data->hwmon_dev); -+ sysfs_remove_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); -+ return 0; -+} -+ -+static const struct i2c_device_id xdpe132g5c_id[] = { -+ {"wb_xdpe132g5c", 0}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(i2c, xdpe132g5c_id); -+ -+static const struct of_device_id __maybe_unused xdpe132g5c_of_match[] = { -+ {.compatible = "infineon,wb_xdpe132g5c"}, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, xdpe132g5c_of_match); -+ -+static struct i2c_driver wb_xdpe132g5c_driver = { -+ .driver = { -+ .name = "wb_xdpe132g5c", -+ .of_match_table = of_match_ptr(xdpe132g5c_of_match), -+ }, -+ .probe = xdpe132g5c_probe, -+ .remove = xdpe132g5c_remove, -+ .id_table = xdpe132g5c_id, -+}; -+ -+module_i2c_driver(wb_xdpe132g5c_driver); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -+MODULE_DESCRIPTION("I2C driver for Infineon XDPE132 family"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/auto_update.py b/platform/broadcom/sonic-platform-modules-micas/common/script/auto_update.py -new file mode 100755 -index 000000000..838e64f6b ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/auto_update.py -@@ -0,0 +1,196 @@ -+#!/usr/bin/env python3 -+ -+try: -+ import os -+ import json -+ import logging -+ import sys -+ from sonic_py_common import device_info -+ from sonic_platform.platform import Platform -+except ImportError as e: -+ raise ImportError(str(e) + "- required module not found") from e -+ -+PLATFORM_COMPONENTS_FILE = "platform_components.json" -+CHASSIS_KEY = "chassis" -+COMPONENT_KEY = "component" -+FIRMWARE_KEY = "firmware" -+VERSION_KEY = "version" -+chassis_component_map = {} -+current_chassis_component_map = {} -+current_chassis = Platform().get_chassis() -+ -+ -+def parse_component_section(section, component): -+ if not isinstance(component, dict): -+ logging.error("dictionary is expected: key=%s", COMPONENT_KEY) -+ return False -+ -+ if not component: -+ return False -+ -+ missing_key = None -+ chassis_component_map[section] = {} -+ -+ for key1, value1 in component.items(): -+ if not isinstance(value1, dict): -+ logging.error("dictionary is expected: key=%s", key1) -+ return False -+ -+ if value1: -+ if len(value1) < 1 or len(value1) > 3: -+ logging.error("unexpected number of records: key=%s", key1) -+ return False -+ -+ if FIRMWARE_KEY not in value1: -+ missing_key = FIRMWARE_KEY -+ break -+ -+ for key2, value2 in value1.items(): -+ if not isinstance(value2, str): -+ logging.error("string is expected: key=%s", key2) -+ return False -+ -+ chassis_component_map[section][key1] = value1 -+ -+ if missing_key is not None: -+ logging.error("\"%s\" key hasn't been found", missing_key) -+ return False -+ -+ return True -+ -+ -+def parse_chassis_section(chassis): -+ if not isinstance(chassis, dict): -+ logging.error("dictionary is expected: key=%s", CHASSIS_KEY) -+ return False -+ -+ if not chassis: -+ logging.error("dictionary is empty: key=%s", CHASSIS_KEY) -+ return False -+ -+ if len(chassis) != 1: -+ logging.error("unexpected number of records: key=%s", CHASSIS_KEY) -+ return False -+ -+ for key, value in chassis.items(): -+ if not isinstance(value, dict): -+ logging.error("dictionary is expected: key=%s", key) -+ return False -+ -+ if not value: -+ logging.error("dictionary is empty: key=%s", key) -+ return False -+ -+ if COMPONENT_KEY not in value: -+ logging.error("\"%s\" key hasn't been found", COMPONENT_KEY) -+ return False -+ -+ if len(value) != 1: -+ logging.error("unexpected number of records: key=%s", key) -+ return False -+ -+ return parse_component_section(key, value[COMPONENT_KEY]) -+ -+ return False -+ -+ -+def get_platform_components_path(): -+ PLATFORM_COMPONENTS_PATH_TEMPLATE = "/usr/share/sonic/device/{}/{}" -+ PLATFORM_COMPONENTS_FILE_PATH = PLATFORM_COMPONENTS_PATH_TEMPLATE.format( -+ device_info.get_platform(), PLATFORM_COMPONENTS_FILE) -+ return PLATFORM_COMPONENTS_FILE_PATH -+ -+ -+def parse_platform_components(): -+ platform_components_path = get_platform_components_path() -+ with open(platform_components_path) as platform_components: -+ data = json.load(platform_components) -+ -+ if not isinstance(data, dict): -+ logging.error("dictionary is expected: key=root") -+ return False -+ -+ if not data: -+ logging.error("dictionary is empty: key=root") -+ return False -+ -+ if CHASSIS_KEY not in data: -+ logging.error("\"%s\" key hasn't been found", CHASSIS_KEY) -+ return False -+ -+ return parse_chassis_section(data[CHASSIS_KEY]) -+ -+ -+def get_current_chassis_component_map(): -+ chassis_name = current_chassis.get_name() -+ current_chassis_component_map[chassis_name] = {} -+ -+ component_list = current_chassis.get_all_components() -+ for component in component_list: -+ component_name = component.get_name() -+ current_chassis_component_map[chassis_name][component_name] = component -+ -+ return current_chassis_component_map -+ -+ -+def get_upgrade_dict(): -+ upgrade_dict = {} -+ firmware_version_current = "" -+ firmware_version_available = "" -+ -+ if not parse_platform_components(): -+ logging.error("Reading platform_components.json i, ion exception") -+ sys.exit(1) -+ -+ if not get_current_chassis_component_map(): -+ logging.error("Reading firmware i, ion from the driver is abnormal") -+ sys.exit(1) -+ -+ chassis_name = current_chassis.get_name() -+ diff_keys = set(chassis_component_map.keys()) ^ set(current_chassis_component_map.keys()) -+ if diff_keys: -+ logging.error("%s names mismatch: keys=%s", chassis_name, str(list(diff_keys))) -+ return None -+ -+ for chassis_name, component_map in current_chassis_component_map.items(): -+ for component_name, component in component_map.items(): -+ firmware_version_current = component.get_firmware_version() -+ if component_name in chassis_component_map[chassis_name]: -+ firmware_version_available = chassis_component_map[chassis_name][component_name][VERSION_KEY] -+ else: -+ logging.warning("can't find %s in %s", component_name, PLATFORM_COMPONENTS_FILE) -+ break -+ -+ if not os.path.exists(chassis_component_map[chassis_name][component_name][FIRMWARE_KEY]): -+ logging.error("%s does not exist", chassis_component_map[chassis_name][component_name][FIRMWARE_KEY]) -+ break -+ -+ if firmware_version_available != firmware_version_current: -+ upgrade_dict[component_name] = chassis_component_map[chassis_name][component_name][FIRMWARE_KEY] -+ -+ return upgrade_dict -+ -+ -+def auto_upgrade(): -+ upgrade_result_dict = {} -+ chassis_name = current_chassis.get_name() -+ -+ upgrade_dict = get_upgrade_dict() -+ if not upgrade_dict: -+ logging.info("No firmware found for automatic upgrade") -+ return None -+ -+ component_map = current_chassis_component_map[chassis_name] -+ for value, path in upgrade_dict.items(): -+ status = component_map[value].install_firmware(path) -+ if status: -+ upgrade_result_dict[value] = "success" -+ logging.info("%s Upgrade Success", value) -+ else: -+ upgrade_result_dict[value] = "failed" -+ logging.error("%s Upgrade Failed", value) -+ return upgrade_result_dict -+ -+ -+if __name__ == '__main__': -+ auto_upgrade() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/avscontrol.py b/platform/broadcom/sonic-platform-modules-micas/common/script/avscontrol.py -new file mode 100755 -index 000000000..a0a2ccaac ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/avscontrol.py -@@ -0,0 +1,203 @@ -+#!/usr/bin/env python3 -+import sys -+import os -+import time -+import syslog -+import glob -+import click -+from platform_config import MAC_DEFAULT_PARAM -+from platform_util import getSdkReg, write_sysfs, get_value, get_format_value -+ -+ -+AVSCTROL_DEBUG_FILE = "/etc/.avscontrol_debug_flag" -+ -+AVSCTROLERROR = 1 -+AVSCTROLDEBUG = 2 -+ -+debuglevel = 0 -+ -+CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} -+ -+ -+class AliasedGroup(click.Group): -+ def get_command(self, ctx, cmd_name): -+ rv = click.Group.get_command(self, ctx, cmd_name) -+ if rv is not None: -+ return rv -+ matches = [x for x in self.list_commands(ctx) -+ if x.startswith(cmd_name)] -+ if not matches: -+ return None -+ if len(matches) == 1: -+ return click.Group.get_command(self, ctx, matches[0]) -+ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) -+ return None -+ -+ -+def avscontrol_debug(s): -+ if AVSCTROLDEBUG & debuglevel: -+ syslog.openlog("AVSCONTROL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def avscontrol_error(s): -+ if AVSCTROLERROR & debuglevel: -+ syslog.openlog("AVSCONTROL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+def avserror(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("AVSCONTROL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+def avsinfo(s): -+ syslog.openlog("AVSCONTROL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_INFO, s) -+ -+ -+def debug_init(): -+ global debuglevel -+ if os.path.exists(AVSCTROL_DEBUG_FILE): -+ debuglevel = debuglevel | AVSCTROLDEBUG | AVSCTROLERROR -+ else: -+ debuglevel = debuglevel & ~(AVSCTROLDEBUG | AVSCTROLERROR) -+ -+ -+def set_avs_value_sysfs(conf, dcdc_value): -+ msg = "" -+ formula = conf.get("formula", None) -+ loc = conf.get("loc") -+ locations = glob.glob(loc) -+ if len(locations) == 0: -+ msg = "avs sysfs loc: %s not found" % loc -+ avscontrol_error(msg) -+ return False, msg -+ sysfs_loc = locations[0] -+ avscontrol_debug("set_avs_value_sysfs, loc: %s, origin dcdc value: %s, formula: %s" % -+ (sysfs_loc, dcdc_value, formula)) -+ if formula is not None: -+ dcdc_value = get_format_value(formula % (dcdc_value)) -+ wr_val = str(dcdc_value) -+ avscontrol_debug("set_avs_value_sysfs, write val: %s" % wr_val) -+ ret, log = write_sysfs(sysfs_loc, wr_val) -+ if ret is False: -+ msg = "set_avs_value_sysfs failed, msg: %s" % log -+ avscontrol_error(msg) -+ return ret, msg -+ -+ -+def set_avs_value(avs_conf, dcdc_value): -+ set_avs_way = avs_conf.get("set_avs", {}).get("gettype") -+ if set_avs_way != "sysfs": -+ msg = "unsupport set avs value type: %s" % set_avs_way -+ avscontrol_error(msg) -+ return False, msg -+ ret, msg = set_avs_value_sysfs(avs_conf["set_avs"], dcdc_value) -+ return ret, msg -+ -+ -+def get_dcdc_value(avs_conf, rov_value): -+ msg = "" -+ mac_avs_param = avs_conf.get("mac_avs_param", {}) -+ if rov_value not in mac_avs_param.keys(): -+ if avs_conf["type"] == 0: -+ msg = "VID:0x%x out of range, voltage regulate stop" % rov_value -+ avsinfo(msg) -+ return False, msg -+ dcdc_value = mac_avs_param[avs_conf["default"]] -+ avsinfo("VID:0x%x out of range, use default VID:0x%x" % (rov_value, dcdc_value)) -+ else: -+ dcdc_value = mac_avs_param[rov_value] -+ return True, dcdc_value -+ -+ -+def get_rov_value_cpld(avs_conf): -+ cpld_avs_config = avs_conf["cpld_avs"] -+ return get_value(cpld_avs_config) -+ -+ -+def get_rov_value_sdk(avs_conf): -+ name = avs_conf["sdkreg"] -+ ret, status = getSdkReg(name) -+ if ret is False: -+ return False, status -+ status = int(status, 16) -+ # shift operation -+ if avs_conf["sdktype"] != 0: -+ status = (status >> avs_conf["macregloc"]) & avs_conf["mask"] -+ macavs = status -+ return True, macavs -+ -+ -+def doAvsCtrol_single(avs_conf): -+ try: -+ avs_name = avs_conf.get("name") -+ rov_source = avs_conf["rov_source"] -+ if rov_source == 0: -+ ret, rov_value = get_rov_value_cpld(avs_conf) # get rov from cpld reg -+ else: -+ ret, rov_value = get_rov_value_sdk(avs_conf) # get rov from sdk reg -+ if ret is False: -+ msg = "%s get rov_value failed, msg: %s" % (avs_name, rov_value) -+ avscontrol_error(msg) -+ return False, msg -+ avscontrol_debug("%s rov_value: 0x%x" % (avs_name, rov_value)) -+ ret, dcdc_value = get_dcdc_value(avs_conf, rov_value) -+ if ret is False: -+ msg = "%s get output voltage value failed, msg: %s" % (avs_name, dcdc_value) -+ avscontrol_error(msg) -+ return False, msg -+ ret, msg = set_avs_value(avs_conf, dcdc_value) -+ return ret, msg -+ except Exception as e: -+ msg = "%s avscontrol raise exception, msg: %s" % (avs_name, str(e)) -+ avscontrol_error(msg) -+ return False, msg -+ -+ -+def doAvsCtrol(avs_conf): -+ retry_time = avs_conf.get("retry", 10) -+ for i in range(retry_time): -+ debug_init() -+ ret, log = doAvsCtrol_single(avs_conf) -+ if ret is True: -+ return True, log -+ time.sleep(1) -+ return False, log -+ -+ -+def run(): -+ # wait 30s for device steady -+ time.sleep(30) -+ errcnt = 0 -+ msg = "" -+ for item in MAC_DEFAULT_PARAM: -+ status, log = doAvsCtrol(item) -+ if status is False: -+ errcnt += 1 -+ msg += log -+ -+ if errcnt == 0: -+ avsinfo("%%AVSCONTROL success") -+ sys.exit(0) -+ avserror("%%DEV_MONITOR-AVS: MAC Voltage adjust failed.") -+ avserror("%%DEV_MONITOR-AVS: errmsg: %s" % msg) -+ sys.exit(1) -+ -+ -+@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) -+def main(): -+ '''device operator''' -+ -+ -+@main.command() -+def start(): -+ '''start AVS control''' -+ avsinfo("%%AVSCONTROL start") -+ run() -+ -+ -+if __name__ == '__main__': -+ main() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/dev_monitor.py b/platform/broadcom/sonic-platform-modules-micas/common/script/dev_monitor.py -new file mode 100755 -index 000000000..e13377b80 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/dev_monitor.py -@@ -0,0 +1,303 @@ -+#!/usr/bin/env python3 -+import sys -+import os -+import time -+import syslog -+import traceback -+import click -+from platform_config import DEV_MONITOR_PARAM -+from platform_util import io_rd, wbi2cget -+ -+ -+CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} -+ -+ -+class AliasedGroup(click.Group): -+ def get_command(self, ctx, cmd_name): -+ rv = click.Group.get_command(self, ctx, cmd_name) -+ if rv is not None: -+ return rv -+ matches = [x for x in self.list_commands(ctx) -+ if x.startswith(cmd_name)] -+ if not matches: -+ return None -+ if len(matches) == 1: -+ return click.Group.get_command(self, ctx, matches[0]) -+ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) -+ return None -+ -+ -+DEVMONITOR_DEBUG_FILE = "/etc/.devmonitor_debug_flag" -+ -+debuglevel = 0 -+ -+ -+def debug_init(): -+ global debuglevel -+ if os.path.exists(DEVMONITOR_DEBUG_FILE): -+ debuglevel = 1 -+ else: -+ debuglevel = 0 -+ -+ -+def devwarninglog(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("DEVMONITOR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_WARNING, s) -+ -+ -+def devcriticallog(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("DEVMONITOR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_CRIT, s) -+ -+ -+def deverror(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("DEVMONITOR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+def devinfo(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("DEVMONITOR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_INFO, s) -+ -+ -+def devdebuglog(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ if debuglevel == 1: -+ syslog.openlog("DEVMONITOR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+class DevMonitor(): -+ -+ def getpresentstatus(self, param): -+ try: -+ ret = {} -+ ret["status"] = '' -+ gettype = param.get('gettype') -+ presentbit = param.get('presentbit') -+ okval = param.get('okval') -+ if gettype == "io": -+ io_addr = param.get('io_addr') -+ val = io_rd(io_addr) -+ if val is None: -+ ret["status"] = "NOT OK" -+ return ret -+ retval = val -+ else: -+ bus = param.get('bus') -+ loc = param.get('loc') -+ offset = param.get('offset') -+ ind, val = wbi2cget(bus, loc, offset) -+ if ind is not True: -+ ret["status"] = "NOT OK" -+ return ret -+ retval = val -+ val_t = (int(retval, 16) & (1 << presentbit)) >> presentbit -+ if val_t != okval: -+ ret["status"] = "ABSENT" -+ else: -+ ret["status"] = "PRESENT" -+ except Exception as e: -+ ret["status"] = "NOT OK" -+ deverror("getpresentstatus error") -+ deverror(str(e)) -+ return ret -+ -+ def removeDev(self, bus, loc): -+ cmd = "echo 0x%02x > /sys/bus/i2c/devices/i2c-%d/delete_device" % (loc, bus) -+ devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) -+ if os.path.exists(devpath): -+ os.system(cmd) -+ -+ def addDev(self, name, bus, loc): -+ if name == "lm75": -+ time.sleep(0.1) -+ cmd = "echo %s 0x%02x > /sys/bus/i2c/devices/i2c-%d/new_device" % (name, loc, bus) -+ devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) -+ if os.path.exists(devpath) is False: -+ os.system(cmd) -+ -+ def checkattr(self, bus, loc, attr): -+ try: -+ attrpath = "/sys/bus/i2c/devices/%d-%04x/%s" % (bus, loc, attr) -+ if os.path.exists(attrpath): -+ return True -+ except Exception as e: -+ deverror("checkattr error") -+ deverror(str(e)) -+ return False -+ -+ def monitor(self, ret): -+ totalerr = 0 -+ for item in ret: -+ try: -+ name = item.get('name') -+ itemattr = '%sattr' % name -+ val_t = getattr(DevMonitor, itemattr, None) -+ if val_t == 'OK': -+ continue -+ present = item.get('present', None) -+ devices = item.get('device') -+ err_t = 0 -+ for item_dev in devices: -+ item_devattr = '%s' % (item_dev['id']) -+ val_t = getattr(DevMonitor, item_devattr, None) -+ if val_t == 'OK': -+ continue -+ devname = item_dev.get('name') -+ bus = item_dev.get('bus') -+ loc = item_dev.get('loc') -+ attr = item_dev.get('attr') -+ if self.checkattr(bus, loc, attr) is False: -+ err_t -= 1 -+ setattr(DevMonitor, item_devattr, 'NOT OK') -+ if present is not None: -+ presentstatus = self.getpresentstatus(present) -+ devdebuglog("%s present status:%s" % (name, presentstatus.get('status'))) -+ if presentstatus.get('status') == 'PRESENT': -+ self.removeDev(bus, loc) -+ time.sleep(0.1) -+ self.addDev(devname, bus, loc) -+ else: -+ self.removeDev(bus, loc) -+ time.sleep(0.1) -+ self.addDev(devname, bus, loc) -+ else: -+ setattr(DevMonitor, item_devattr, 'OK') -+ val_t = getattr(DevMonitor, item_devattr, None) -+ devdebuglog("%s status %s" % (item_devattr, val_t)) -+ if err_t == 0: -+ setattr(DevMonitor, itemattr, 'OK') -+ else: -+ totalerr -= 1 -+ setattr(DevMonitor, itemattr, 'NOT OK') -+ val_t = getattr(DevMonitor, itemattr, None) -+ devdebuglog("%s status %s" % (itemattr, val_t)) -+ except Exception as e: -+ totalerr -= 1 -+ deverror("monitor error") -+ deverror(str(e)) -+ return totalerr -+ -+ def psusmonitor(self): -+ psus_conf = DEV_MONITOR_PARAM.get('psus') -+ if psus_conf is None: -+ return 0 -+ psusattr = 'psusattr' -+ val_t = getattr(DevMonitor, psusattr, None) -+ if val_t == 'OK': -+ return 0 -+ ret = self.monitor(psus_conf) -+ if ret == 0: -+ setattr(DevMonitor, psusattr, 'OK') -+ else: -+ setattr(DevMonitor, psusattr, 'NOT OK') -+ val_t = getattr(DevMonitor, psusattr, None) -+ devdebuglog("psusattr:value:%s" % (val_t)) -+ return ret -+ -+ def fansmonitor(self): -+ fans_conf = DEV_MONITOR_PARAM.get('fans') -+ if fans_conf is None: -+ return 0 -+ fansattr = 'fansattr' -+ val_t = getattr(DevMonitor, fansattr, None) -+ if val_t == 'OK': -+ return 0 -+ ret = self.monitor(fans_conf) -+ if ret == 0: -+ setattr(DevMonitor, fansattr, 'OK') -+ else: -+ setattr(DevMonitor, fansattr, 'NOT OK') -+ val_t = getattr(DevMonitor, fansattr, None) -+ devdebuglog("fansattr:value:%s" % (val_t)) -+ return ret -+ -+ def slotsmonitor(self): -+ slots_conf = DEV_MONITOR_PARAM.get('slots') -+ if slots_conf is None: -+ return 0 -+ slotsattr = 'slotsattr' -+ val_t = getattr(DevMonitor, slotsattr, None) -+ if val_t == 'OK': -+ return 0 -+ ret = self.monitor(slots_conf) -+ if ret == 0: -+ setattr(DevMonitor, slotsattr, 'OK') -+ else: -+ setattr(DevMonitor, slotsattr, 'NOT OK') -+ val_t = getattr(DevMonitor, slotsattr, None) -+ devdebuglog("slotsattr:value:%s" % (val_t)) -+ return ret -+ -+ def othersmonitor(self): -+ others_conf = DEV_MONITOR_PARAM.get('others') -+ if others_conf is None: -+ return 0 -+ othersattr = 'othersattr' -+ val_t = getattr(DevMonitor, othersattr, None) -+ if val_t == 'OK': -+ return 0 -+ ret = self.monitor(others_conf) -+ if ret == 0: -+ setattr(DevMonitor, othersattr, 'OK') -+ else: -+ setattr(DevMonitor, othersattr, 'NOT OK') -+ val_t = getattr(DevMonitor, othersattr, None) -+ devdebuglog("othersattr:value:%s" % (val_t)) -+ return ret -+ -+ -+def doDevMonitor(devMonitor): -+ ret_t = 0 -+ ret_t += devMonitor.psusmonitor() -+ ret_t += devMonitor.fansmonitor() -+ ret_t += devMonitor.slotsmonitor() -+ ret_t += devMonitor.othersmonitor() -+ return ret_t -+ -+ -+def run(interval, devMonitor): -+ # devMonitor.devattrinit() -+ while True: -+ try: -+ debug_init() -+ ret = doDevMonitor(devMonitor) -+ except Exception as e: -+ traceback.print_exc() -+ deverror(str(e)) -+ ret = -1 -+ if ret == 0: -+ time.sleep(5) -+ devinfo("dev_monitor finished!") -+ sys.exit(0) -+ time.sleep(interval) -+ -+ -+@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) -+def main(): -+ '''device operator''' -+ -+ -+@main.command() -+def start(): -+ '''start device monitor''' -+ devinfo("dev_monitor start") -+ devMonitor = DevMonitor() -+ interval = DEV_MONITOR_PARAM.get('polling_time', 10) -+ run(interval, devMonitor) -+ -+ -+@main.command() -+def stop(): -+ '''stop device monitor ''' -+ devinfo("stop") -+ -+ -+# device_i2c operation -+if __name__ == '__main__': -+ main() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/drv_update.py b/platform/broadcom/sonic-platform-modules-micas/common/script/drv_update.py -new file mode 100755 -index 000000000..9de4911e8 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/drv_update.py -@@ -0,0 +1,152 @@ -+#!/usr/bin/env python -+# -*- coding: UTF-8 -*- -+import syslog -+import os -+import shutil -+from platform_config import DRVIER_UPDATE_CONF -+from platform_util import exec_os_cmd -+ -+ -+DRV_UPDATE_DEBUG_FILE = "/etc/.drv_update_debug_flag" -+ -+DRVUPDATEERROR = 1 -+DRVUPDATEDEBUG = 2 -+debuglevel = 0 -+ -+ -+def drv_update_debug(s): -+ if DRVUPDATEDEBUG & debuglevel: -+ syslog.openlog("DRV_UPDATE", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_INFO, s) -+ -+ -+def drv_update_error(s): -+ if DRVUPDATEERROR & debuglevel: -+ syslog.openlog("DRV_UPDATE", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+def drv_update_info(s): -+ syslog.openlog("DRV_UPDATE", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_NOTICE, s) -+ -+def debug_init(): -+ global debuglevel -+ try: -+ with open(DRV_UPDATE_DEBUG_FILE, "r") as fd: -+ value = fd.read() -+ debuglevel = int(value) -+ except Exception: -+ debuglevel = 0 -+ -+ -+def get_driver_md5sum(drv_path): -+ status, output = exec_os_cmd("md5sum %s" % drv_path) -+ if status or len(output) == 0: -+ return False, output -+ drv_md5 = output.strip().split(" ")[0] -+ return True, drv_md5 -+ -+ -+def do_driver_replace(src_file, target_file): -+ # Backup target file -+ src_file_dir = os.path.dirname(src_file) -+ target_file_name = os.path.basename(target_file) -+ drv_update_debug("src_file: %s, src_file_dir: %s" % (src_file, src_file_dir)) -+ drv_update_debug("target_file: %s, target_file_name: %s" % (target_file, target_file_name)) -+ try: -+ shutil.copyfile(target_file, "%s/%s.bak" % (src_file_dir, target_file_name)) -+ shutil.copyfile(src_file, target_file) -+ return True -+ except Exception as e: -+ drv_update_error("do_driver_replace error, msg: %s" % str(e)) -+ return False -+ -+ -+def doDrvUpdate(): -+ reboot_flag = DRVIER_UPDATE_CONF.get("reboot_flag", 0) -+ drv_list = DRVIER_UPDATE_CONF.get("drv_list", []) -+ err_cnt = 0 -+ update_initramfs_flag = 0 -+ # get kernel version -+ status, output = exec_os_cmd("uname -r") -+ if status or len(output) == 0: -+ drv_update_error("Failed to get kernel version, status: %s, log: %s" % (status, output)) -+ return -+ kversion = output.strip() -+ drv_update_debug("kernel version: %s" % kversion) -+ for item in drv_list: -+ try: -+ source_drv = item.get("source") -+ target_drv = item.get("target") -+ judge_flag = item.get("judge_flag") -+ if source_drv is None or target_drv is None or judge_flag is None: -+ drv_update_error("driver update config error, source_drv: %s, target_drv: %s, judge_file: %s" % (source_drv, target_drv, judge_flag)) -+ err_cnt += 1 -+ continue -+ drv_update_debug("source_drv: %s, target_drv: %s, judge_flag: %s" % (source_drv, target_drv, judge_flag)) -+ -+ # Check if the current driver is expected -+ if os.path.exists(judge_flag): -+ drv_update_debug("The current driver is expected, do nothing") -+ continue -+ -+ # get source driver file path -+ source_drv_path = "/lib/modules/%s/%s" % (kversion, source_drv) -+ drv_update_debug("source driver: %s, file path: %s" % (source_drv, source_drv_path)) -+ -+ # get target driver file path -+ target_drv_path = "/lib/modules/%s/%s" % (kversion, target_drv) -+ drv_update_debug("target driver: %s, file path: %s" % (target_drv, target_drv_path)) -+ -+ # get source driver md5sum -+ status, source_drv_md5 = get_driver_md5sum(source_drv_path) -+ if status is False: -+ msg = "get %s md5sum failed msg: %s" % (source_drv_path, source_drv_md5) -+ drv_update_error(msg) -+ err_cnt += 1 -+ continue -+ drv_update_debug("source driver file path: %s, md5sum: %s" % (source_drv_path, source_drv_md5)) -+ -+ # get target driver md5sum -+ status, target_drv_md5 = get_driver_md5sum(target_drv_path) -+ if status is False: -+ msg = "get %s md5sum failed msg: %s" % (target_drv_path, target_drv_md5) -+ drv_update_error(msg) -+ err_cnt += 1 -+ continue -+ drv_update_debug("target driver file path: %s, md5sum: %s" % (target_drv_path, target_drv_md5)) -+ -+ if source_drv_md5 != target_drv_md5: -+ drv_update_debug("source_drv_md5 not equal to target_drv_md5, try to use source driver replace target driver") -+ status = do_driver_replace(source_drv_path, target_drv_path) -+ if status is False: -+ err_cnt += 1 -+ continue -+ else: -+ drv_update_debug("source_drv_md5 equal to target_drv_md5, do nothing") -+ -+ drv_update_debug("Driver replacement completed, set update_initramfs_flag") -+ update_initramfs_flag = 1 -+ -+ except Exception as e: -+ err_cnt += 1 -+ drv_update_error(str(e)) -+ -+ if update_initramfs_flag == 1: -+ drv_update_debug("starting to update initramfs") -+ os.system("update-initramfs -u") -+ drv_update_debug("update initramfs finish") -+ -+ os.system("sync") -+ if update_initramfs_flag == 1 and err_cnt == 0 and reboot_flag == 1: -+ reboot_log = "%DRV_UPDATE-5-REBOOT: Update initramfs is completed, restarting the system to take effect." -+ reboot_log_cmd = "echo '%s' > /dev/ttyS0" % reboot_log -+ exec_os_cmd(reboot_log_cmd) -+ drv_update_info(reboot_log) -+ os.system("/sbin/reboot") -+ return -+ -+if __name__ == '__main__': -+ debug_init() -+ doDrvUpdate() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/generate_airflow.py b/platform/broadcom/sonic-platform-modules-micas/common/script/generate_airflow.py -new file mode 100755 -index 000000000..89d3e7233 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/generate_airflow.py -@@ -0,0 +1,254 @@ -+#!/usr/bin/env python -+# -*- coding: UTF-8 -*- -+''' -+generate board air flow according to fan and psu air flow -+write resulet to AIRFLOW_RESULT_FILE, file format: -+{ -+ "FAN1": { -+ "model":"M1HFAN I-F", -+ "airflow":"intake", -+ }, -+ "PSU1": { -+ "model":"CSU550AP-3-500", -+ "airflow":"intake", -+ }, -+ "board":"intake" -+} -+''' -+import os -+import syslog -+import json -+from platform_config import AIR_FLOW_CONF, AIRFLOW_RESULT_FILE -+from platform_util import dev_file_read, byteTostr -+from eepromutil.fru import ipmifru -+from eepromutil.cust_fru import CustFru -+from eepromutil.fantlv import fan_tlv -+ -+ -+AIRFLOW_DEBUG_FILE = "/etc/.airflow_debug_flag" -+ -+AIRFLOWERROR = 1 -+AIRFLOWDEBUG = 2 -+ -+debuglevel = 0 -+ -+ -+def airflow_info(s): -+ syslog.openlog("AIRFLOW", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_INFO, s) -+ -+ -+def airflow_error(s): -+ syslog.openlog("AIRFLOW", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+def airflow_debug(s): -+ if AIRFLOWDEBUG & debuglevel: -+ syslog.openlog("AIRFLOW", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def airflow_debug_error(s): -+ if AIRFLOWERROR & debuglevel: -+ syslog.openlog("AIRFLOW", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+def debug_init(): -+ global debuglevel -+ try: -+ with open(AIRFLOW_DEBUG_FILE, "r") as fd: -+ value = fd.read() -+ debuglevel = int(value) -+ except Exception: -+ debuglevel = 0 -+ -+ -+def get_model_fru(device, eeprom): -+ try: -+ fru = ipmifru() -+ fru.decodeBin(eeprom) -+ dev_name = device.get("name") -+ area = device.get("area") -+ field = device.get("field") -+ tmp_area = getattr(fru, area, None) -+ if tmp_area is None: -+ msg = "%s fru %s area config error" % (dev_name, area) -+ return False, msg -+ model = getattr(tmp_area, field, None) -+ if model is None: -+ msg = "%s get model error, area: %s, field: %s" % (dev_name, area, field) -+ return False, msg -+ airflow_debug("%s get model success, model: %s" % (dev_name, model)) -+ return True, model -+ except Exception as e: -+ return False, str(e) -+ -+def get_model_custfru(device, eeprom): -+ try: -+ custfru = CustFru() -+ custfru.decode(eeprom) -+ dev_name = device.get("name") -+ field = device.get("field") -+ model = getattr(custfru, field, None) -+ if model is None: -+ msg = "%s get model error, field: %s" % (dev_name, field) -+ return False, msg -+ airflow_debug("%s get model success, model: %s" % (dev_name, model)) -+ return True, model -+ except Exception as e: -+ return False, str(e) -+ -+ -+def get_model_fantlv(device, eeprom): -+ try: -+ dev_name = device.get("name") -+ tlv = fan_tlv() -+ rets = tlv.decode(eeprom) -+ if len(rets) == 0: -+ msg = "%s decode fantlv eeprom info error" % dev_name -+ return False, msg -+ -+ field = device.get("field") -+ for fantlv_item in rets: -+ if fantlv_item.get("name") == field: -+ return True, fantlv_item["value"] -+ msg = "%s get model error, field: %s not found" % (dev_name, field) -+ return False, msg -+ except Exception as e: -+ return False, str(e) -+ -+ -+def get_device_modele(device): -+ e2_type = device.get("e2_type") -+ dev_name = device.get("name") -+ support_e2_type = ("fru", "fantlv", "custfru") -+ if e2_type not in support_e2_type: -+ msg = "%s unsupport e2_type: %s" % (dev_name, e2_type) -+ return False, msg -+ -+ e2_path = device.get("e2_path") -+ e2_size = device.get("e2_size", 256) -+ ret, binval_bytes = dev_file_read(e2_path, 0, e2_size) -+ if ret is False: -+ msg = "%s eeprom read error, eeprom path: %s, msg: %s" % (dev_name, e2_path, binval_bytes) -+ return False, msg -+ -+ binval = byteTostr(binval_bytes) -+ if e2_type == "fru": -+ return get_model_fru(device, binval) -+ if e2_type == "custfru": -+ return get_model_custfru(device, binval) -+ return get_model_fantlv(device, binval) -+ -+ -+def get_board_air_flow(fan_intake_num, fan_exhaust_num, psu_intake_num, psu_exhaust_num): -+ airflow_debug("fan_intake_num: %d, fan_exhaust_num: %d, psu_intake_num: %d, psu_exhaust_num: %d" % -+ (fan_intake_num, fan_exhaust_num, psu_intake_num, psu_exhaust_num)) -+ -+ if fan_intake_num == 0 and fan_exhaust_num == 0 and psu_intake_num == 0 and psu_exhaust_num == 0: -+ airflow_error("get all fans and psus air flow failed") -+ return "N/A" -+ -+ if fan_intake_num > fan_exhaust_num: -+ airflow_debug("fan intake number more than fan exhaust number, set board air flow: intake") -+ return "intake" -+ -+ if fan_intake_num < fan_exhaust_num: -+ airflow_debug("fan intake number less than fan exhaust number, set board air flow: exhaust") -+ return "exhaust" -+ -+ airflow_debug("fan intake number equal to exhaust number, check psu air flow") -+ -+ if psu_intake_num > psu_exhaust_num: -+ airflow_debug("psu intake number more than psu exhaust number, set board air flow: intake") -+ return "intake" -+ -+ if psu_intake_num < psu_exhaust_num: -+ airflow_debug("psu intake number less than psu exhaust number, set board air flow: exhaust") -+ return "exhaust" -+ -+ airflow_debug("fan and psu intake and exhaust number equal, return intake") -+ return "intake" -+ -+ -+def generate_airflow(): -+ fan_intake_list = [] -+ fan_exhaust_list = [] -+ psu_intake_list = [] -+ psu_exhaust_list = [] -+ ret = {} -+ fans = AIR_FLOW_CONF.get("fans", []) -+ psus = AIR_FLOW_CONF.get("psus", []) -+ -+ for fan in fans: -+ dev_name = fan.get("name") -+ air_flow = "N/A" -+ status, model = get_device_modele(fan) -+ if status is False: -+ ret[dev_name] = {"model": "N/A", "airflow": "N/A"} -+ airflow_error(model) -+ continue -+ model = model.strip() -+ airflowconifg = AIR_FLOW_CONF[fan["decode"]] -+ for key, value in airflowconifg.items(): -+ if model in value: -+ air_flow = key -+ ret[dev_name] = {"model": model, "airflow": air_flow} -+ airflow_debug("%s model: %s, airflow: %s" % (dev_name, model, air_flow)) -+ if air_flow == "intake": -+ fan_intake_list.append(fan.get("name")) -+ elif air_flow == "exhaust": -+ fan_exhaust_list.append(fan.get("name")) -+ -+ airflow_debug("fan_intake_list: %s" % fan_intake_list) -+ airflow_debug("fan_exhaust_list: %s" % fan_exhaust_list) -+ -+ for psu in psus: -+ dev_name = psu.get("name") -+ air_flow = "N/A" -+ status, model = get_device_modele(psu) -+ if status is False: -+ ret[dev_name] = {"model": "N/A", "airflow": "N/A"} -+ airflow_error(model) -+ continue -+ model = model.strip() -+ airflowconifg = AIR_FLOW_CONF[psu["decode"]] -+ for key, value in airflowconifg.items(): -+ if model in value: -+ air_flow = key -+ ret[dev_name] = {"model": model, "airflow": air_flow} -+ airflow_debug("%s model: %s, airflow: %s" % (dev_name, model, air_flow)) -+ if air_flow == "intake": -+ psu_intake_list.append(psu.get("name")) -+ elif air_flow == "exhaust": -+ psu_exhaust_list.append(psu.get("name")) -+ -+ airflow_debug("psu_intake_list: %s" % psu_intake_list) -+ airflow_debug("psu_exhaust_list: %s" % psu_exhaust_list) -+ -+ fan_intake_num = len(fan_intake_list) -+ fan_exhaust_num = len(fan_exhaust_list) -+ psu_intake_num = len(psu_intake_list) -+ psu_exhaust_num = len(psu_exhaust_list) -+ -+ board_airflow = get_board_air_flow(fan_intake_num, fan_exhaust_num, psu_intake_num, psu_exhaust_num) -+ airflow_debug("board_airflow: %s" % board_airflow) -+ ret["board"] = board_airflow -+ ret_json = json.dumps(ret, ensure_ascii=False, indent=4) -+ -+ out_file_dir = os.path.dirname(AIRFLOW_RESULT_FILE) -+ if len(out_file_dir) != 0: -+ cmd = "mkdir -p %s" % out_file_dir -+ os.system(cmd) -+ os.system("sync") -+ with open(AIRFLOW_RESULT_FILE, "w") as fd: -+ fd.write(ret_json) -+ os.system("sync") -+ -+ -+if __name__ == '__main__': -+ debug_init() -+ airflow_debug("enter main") -+ generate_airflow() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/hal_fanctrl.py b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_fanctrl.py -new file mode 100755 -index 000000000..7722b111f ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_fanctrl.py -@@ -0,0 +1,1135 @@ -+#!/usr/bin/env python3 -+import os -+import subprocess -+import time -+import syslog -+import traceback -+from plat_hal.interface import interface -+from plat_hal.baseutil import baseutil -+from algorithm.pid import pid -+from algorithm.openloop import openloop -+from algorithm.hysteresis import hysteresis -+ -+ -+SWITCH_TEMP = "SWITCH_TEMP" -+INLET_TEMP = "INLET_TEMP" -+BOARD_TEMP = "BOARD_TEMP" -+OUTLET_TEMP = "OUTLET_TEMP" -+CPU_TEMP = "CPU_TEMP" -+ -+FANCTROL_DEBUG_FILE = "/etc/.fancontrol_debug_flag" -+# coordination with REBOOT_CAUSE_PARA -+OTP_SWITCH_REBOOT_JUDGE_FILE = "/etc/.otp_reboot_flag" -+OTP_OTHER_REBOOT_JUDGE_FILE = OTP_SWITCH_REBOOT_JUDGE_FILE -+ -+FANCTROLERROR = 1 -+FANCTROLDEBUG = 2 -+FANAIRFLOWDEBUG = 4 -+ -+debuglevel = 0 -+ -+F2B_AIR_FLOW = "intake" -+B2F_AIR_FLOW = "exhaust" -+ONIE_E2_NAME = "ONIE_E2" -+ -+TEMP_REBOOT_CRIT_SWITCH_FLAG = 1 -+TEMP_REBOOT_CRIT_OTHER_FLAG = 2 -+ -+ -+def fancontrol_debug(s): -+ if FANCTROLDEBUG & debuglevel: -+ syslog.openlog("FANCONTROL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def fancontrol_error(s): -+ if FANCTROLERROR & debuglevel: -+ syslog.openlog("FANCONTROL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+def fanairflow_debug(s): -+ if FANAIRFLOWDEBUG & debuglevel: -+ syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def fancontrol_warn(s): -+ syslog.openlog("FANCONTROL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_WARNING, s) -+ -+ -+def fancontrol_crit(s): -+ syslog.openlog("FANCONTROL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_CRIT, s) -+ -+ -+def fancontrol_alert(s): -+ syslog.openlog("FANCONTROL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_ALERT, s) -+ -+ -+def fancontrol_emerg(s): -+ syslog.openlog("FANCONTROL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_EMERG, s) -+ -+ -+def exec_os_cmd(cmd): -+ status, output = subprocess.getstatusoutput(cmd) -+ if status: -+ print(output) -+ return status, output -+ -+ -+def debug_init(): -+ global debuglevel -+ try: -+ with open(FANCTROL_DEBUG_FILE, "r") as fd: -+ value = fd.read() -+ debuglevel = int(value) -+ except Exception: -+ debuglevel = 0 -+ -+ -+error_temp = -9999 # get temp error -+invalid_temp = -10000 # get temp invalid -+PRE_FAN_NOK_UNKNOWN = "UNKNOWN" -+ -+ -+class DevFan(object): -+ -+ def __init__(self, name, hal_interface): -+ self.__name = name -+ self.origin_name = None -+ self.display_name = None -+ self.air_flow = None -+ self.air_flow_inconsistent = False -+ self.int_case = hal_interface -+ -+ @property -+ def name(self): -+ return self.__name -+ -+ def get_fan_rotor_number(self): -+ return self.int_case.get_fan_rotor_number(self.name) -+ -+ def get_fan_presence(self): -+ return self.int_case.get_fan_presence(self.name) -+ -+ def get_fan_rotor_status(self, rotor_name): -+ return self.int_case.get_fan_rotor_status(self.name, rotor_name) -+ -+ def get_fan_fru_info(self): -+ return self.int_case.get_fan_fru_info(self.name) -+ -+ @property -+ def na_ret(self): -+ return self.int_case.na_ret -+ -+ def update_fru_info(self): -+ try: -+ dic = self.get_fan_fru_info() -+ self.origin_name = dic["PN"] -+ self.air_flow = dic["AirFlow"] -+ self.display_name = dic["DisplayName"] -+ except Exception as e: -+ fanairflow_debug("update %s fru info error, msg: %s" % (self.name, str(e))) -+ self.origin_name = self.na_ret -+ self.air_flow = self.na_ret -+ self.display_name = self.na_ret -+ -+ -+class DevPsu(object): -+ -+ def __init__(self, name, hal_interface): -+ self.__name = name -+ self.origin_name = None -+ self.display_name = None -+ self.air_flow = None -+ self.air_flow_inconsistent = False -+ self.int_case = hal_interface -+ -+ @property -+ def name(self): -+ return self.__name -+ -+ def get_psu_fru_info(self): -+ return self.int_case.get_psu_fru_info(self.name) -+ -+ @property -+ def na_ret(self): -+ return self.int_case.na_ret -+ -+ def update_fru_info(self): -+ try: -+ dic = self.get_psu_fru_info() -+ self.origin_name = dic["PN"] -+ self.air_flow = dic["AirFlow"] -+ self.display_name = dic["DisplayName"] -+ except Exception as e: -+ fanairflow_debug("update %s fru info error, msg: %s" % (self.name, str(e))) -+ self.origin_name = self.na_ret -+ self.air_flow = self.na_ret -+ self.display_name = self.na_ret -+ -+ -+class fancontrol(object): -+ __int_case = None -+ -+ __pwm = 0x80 -+ -+ def __init__(self): -+ self.int_case = interface() -+ self.__config = baseutil.get_monitor_config() -+ self.__pid_config = self.__config["pid"] -+ self.__hyst_config = self.__config.get("hyst", {}) -+ self.__temps_threshold_config = self.__config["temps_threshold"] -+ for temp_threshold in self.__temps_threshold_config.values(): -+ temp_threshold['temp'] = 0 -+ temp_threshold['fail_num'] = 0 -+ temp_threshold['warning_num'] = 0 # temp warning times -+ temp_threshold['critical_num'] = 0 # temp critical times -+ temp_threshold['emergency_num'] = 0 # temp emergency times -+ temp_threshold.setdefault('ignore_threshold', 0) # default temp threshold on -+ temp_threshold.setdefault('invalid', invalid_temp) -+ temp_threshold.setdefault('error', error_temp) -+ -+ self.__otp_reboot_judge_file_config = self.__config.get("otp_reboot_judge_file", None) -+ if self.__otp_reboot_judge_file_config is None: -+ self.__otp_switch_reboot_judge_file = OTP_SWITCH_REBOOT_JUDGE_FILE -+ self.__otp_other_reboot_judge_file = OTP_OTHER_REBOOT_JUDGE_FILE -+ else: -+ self.__otp_switch_reboot_judge_file = self.__otp_reboot_judge_file_config.get( -+ "otp_switch_reboot_judge_file", OTP_SWITCH_REBOOT_JUDGE_FILE) -+ self.__otp_other_reboot_judge_file = self.__otp_reboot_judge_file_config.get( -+ "otp_other_reboot_judge_file", OTP_OTHER_REBOOT_JUDGE_FILE) -+ -+ self.__fan_rotor_error_num = {} -+ self.__fan_present_status = {} # {"FAN1":0, "FAN2":1...} 1:present, 0:absent -+ self.__fan_rotate_status = {} # {"FAN1":0, "FAN2":1...} 1:OK, 0:NOT OK -+ self.__fan_repair_flag = {} # {"FAN1":0, "FAN2":1...} 1:repair, 0:give up -+ fan_num = self.get_fan_total_number() -+ for i in range(fan_num): -+ fan_name = "FAN" + str(i + 1) -+ self.__fan_present_status[fan_name] = 1 # present -+ self.__fan_rotate_status[fan_name] = 1 # OK -+ self.__fan_repair_flag[fan_name] = 1 # repair -+ rotor_num = self.get_rotor_number(fan_name) -+ tmp_fan = {} -+ for j in range(rotor_num): -+ rotor_name = "Rotor" + str(j + 1) -+ tmp_fan[rotor_name] = 0 # not error -+ self.__fan_rotor_error_num[fan_name] = tmp_fan -+ -+ self.__fancontrol_para = self.__config["fancontrol_para"] -+ self.__interval = self.__fancontrol_para.get("interval", 5) -+ self.__fan_status_interval = self.__fancontrol_para.get("fan_status_interval", 0) -+ self.__max_pwm = self.__fancontrol_para.get("max_pwm", 0xff) -+ self.__min_pwm = self.__fancontrol_para.get("min_pwm", 0x80) -+ self.__abnormal_pwm = self.__fancontrol_para.get("abnormal_pwm", 0xbb) -+ self.__warning_pwm = self.__fancontrol_para.get("warning_pwm", 0xff) -+ self.__temp_invalid_pid_pwm = self.__fancontrol_para.get("temp_invalid_pid_pwm", 0x80) -+ self.__temp_error_pid_pwm = self.__fancontrol_para.get("temp_error_pid_pwm", 0x80) -+ self.__temp_fail_num = self.__fancontrol_para.get("temp_fail_num", 3) -+ self.__check_temp_fail = self.__fancontrol_para.get("check_temp_fail", []) -+ self.__temp_warning_num = self.__fancontrol_para.get("temp_warning_num", 3) -+ self.__temp_critical_num = self.__fancontrol_para.get("temp_critical_num", 3) -+ self.__temp_emergency_num = self.__fancontrol_para.get("temp_emergency_num", 3) -+ self.__temp_warning_countdown = self.__fancontrol_para.get("temp_warning_countdown", 60) -+ self.__temp_critical_countdown = self.__fancontrol_para.get("temp_critical_countdown", 60) -+ self.__temp_emergency_countdown = self.__fancontrol_para.get("temp_emergency_countdown", 60) -+ self.__rotor_error_count = self.__fancontrol_para.get("rotor_error_count", 6) -+ self.__inlet_mac_diff = self.__fancontrol_para.get("inlet_mac_diff", 50) -+ self.__check_crit_reboot_flag = self.__fancontrol_para.get("check_crit_reboot_flag", 1) -+ self.__check_emerg_reboot_flag = self.__fancontrol_para.get("check_emerg_reboot_flag", 1) -+ self.__check_crit_reboot_num = self.__fancontrol_para.get("check_crit_reboot_num", 3) -+ self.__check_crit_sleep_time = self.__fancontrol_para.get("check_crit_sleep_time", 20) -+ self.__check_emerg_reboot_num = self.__fancontrol_para.get("check_emerg_reboot_num", 3) -+ self.__check_emerg_sleep_time = self.__fancontrol_para.get("check_emerg_sleep_time", 20) -+ self.__check_temp_emergency = self.__fancontrol_para.get("check_temp_emergency", 0) -+ self.__check_temp_critical = self.__fancontrol_para.get("check_temp_critical", 1) -+ self.__check_temp_warning = self.__fancontrol_para.get("check_temp_warning", 1) -+ self.__check_temp_emergency_reboot = self.__fancontrol_para.get("check_temp_emergency_reboot", []) -+ self.__psu_absent_fullspeed_num = self.__fancontrol_para.get("psu_absent_fullspeed_num", 1) -+ self.__fan_absent_fullspeed_num = self.__fancontrol_para.get("fan_absent_fullspeed_num", 1) -+ self.__rotor_error_fullspeed_num = self.__fancontrol_para.get("rotor_error_fullspeed_num", 1) -+ self.__psu_fan_control = self.__fancontrol_para.get("psu_fan_control", 1) # default control psu fan -+ self.__fan_plug_in_pwm = self.__fancontrol_para.get("fan_plug_in_pwm", 0x80) -+ self.__fan_plug_in_default_countdown = self.__fancontrol_para.get("fan_plug_in_default_countdown", 0) -+ self.__deal_fan_error_policy = self.__fancontrol_para.get("deal_fan_error", 0) -+ self.__deal_fan_error_conf = self.__fancontrol_para.get("deal_fan_error_conf", {}) -+ self.__deal_fan_error_default_countdown = self.__deal_fan_error_conf.get("countdown", 0) -+ -+ self.__warning_countdown = 0 # temp warning flag for normal fancontrol -+ self.__critical_countdown = 0 # temp critical flag for normal fancontrol -+ self.__emergency_countdown = 0 # temp emergency flag for normal fancontrol -+ self.__fan_plug_in_countdown = 0 # fan plug in flag for normal fancontrol -+ self.__deal_fan_error_countdown = 0 -+ self.__fan_absent_num = 0 -+ self.__fan_nok_num = 0 -+ self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN -+ self.openloop = openloop() -+ self.pid = pid() -+ self.hyst = hysteresis() -+ self.__pwm = self.__min_pwm -+ -+ self.__board_air_flow = "" -+ self.__fan_air_flow_monitor = self.__fancontrol_para.get("fan_air_flow_monitor", 0) -+ self.__psu_air_flow_monitor = self.__fancontrol_para.get("psu_air_flow_monitor", 0) -+ self.__air_flow_correct_fan_pwm = self.__fancontrol_para.get("air_flow_correct_fan_pwm", 0xff) -+ self.__air_flow_correct_psu_pwm = self.__fancontrol_para.get("air_flow_correct_psu_pwm", 0xff) -+ self.__air_flow_error_fan_pwm = self.__fancontrol_para.get("air_flow_error_fan_pwm", 0) -+ self.__air_flow_error_psu_pwm = self.__fancontrol_para.get("air_flow_error_psu_pwm", 0) -+ self.fan_air_flow_inconsistent_flag = False -+ self.psu_air_flow_inconsistent_flag = False -+ self.air_flow_inconsistent_flag = False -+ self.fan_obj_list = [] -+ self.psu_obj_list = [] -+ -+ @property -+ def na_ret(self): -+ return self.int_case.na_ret -+ -+ def get_onie_e2_obj(self, name): -+ return self.int_case.get_onie_e2_obj(name) -+ -+ @property -+ def board_air_flow(self): -+ air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) -+ if self.__board_air_flow not in air_flow_tuple: -+ self.__board_air_flow = self.int_case.get_device_airflow(ONIE_E2_NAME) -+ fanairflow_debug("board_air_flow: %s" % self.__board_air_flow) -+ return self.__board_air_flow -+ -+ @property -+ def fan_air_flow_monitor(self): -+ return self.__fan_air_flow_monitor -+ -+ @property -+ def psu_air_flow_monitor(self): -+ return self.__psu_air_flow_monitor -+ -+ @property -+ def air_flow_correct_fan_pwm(self): -+ return self.__air_flow_correct_fan_pwm -+ -+ @property -+ def air_flow_correct_psu_pwm(self): -+ return self.__air_flow_correct_psu_pwm -+ -+ @property -+ def air_flow_error_fan_pwm(self): -+ return self.__air_flow_error_fan_pwm -+ -+ @property -+ def air_flow_error_psu_pwm(self): -+ return self.__air_flow_error_psu_pwm -+ -+ def get_para(self, t): -+ para = self.__pid_config.get(t) -+ return para -+ -+ def update_over_temp_threshold_num(self): -+ for temp_threshold in self.__temps_threshold_config.values(): -+ if temp_threshold['ignore_threshold']: -+ continue -+ emergency_threshold = temp_threshold.get('emergency', None) -+ critical_threshold = temp_threshold.get('critical', None) -+ warning_threshold = temp_threshold.get('warning', None) -+ fancontrol_debug("%s warning = %s, critical = %s, emergency = %s" % -+ (temp_threshold['name'], warning_threshold, critical_threshold, emergency_threshold)) -+ -+ if emergency_threshold is not None and temp_threshold['temp'] >= emergency_threshold: -+ temp_threshold['emergency_num'] += 1 -+ else: -+ temp_threshold['emergency_num'] = 0 -+ -+ if critical_threshold is not None and temp_threshold['temp'] >= critical_threshold: -+ temp_threshold['critical_num'] += 1 -+ else: -+ temp_threshold['critical_num'] = 0 -+ -+ if warning_threshold is not None and temp_threshold['temp'] >= warning_threshold: -+ temp_threshold['warning_num'] += 1 -+ else: -+ temp_threshold['warning_num'] = 0 -+ -+ fancontrol_debug("%s warning_num = %d, critical_num = %d, emergency_num = %d" % -+ (temp_threshold['name'], temp_threshold['warning_num'], temp_threshold['critical_num'], temp_threshold.get("emergency_num"))) -+ -+ def get_monitor_temp(self): -+ sensorlist = self.int_case.get_temp_info() -+ -+ for temp_threshold in self.__temps_threshold_config.values(): -+ sensor = sensorlist.get(temp_threshold['name']) -+ if sensor["Value"] is None or int(sensor["Value"]) == self.int_case.error_ret: -+ temp_threshold['fail_num'] += 1 -+ fancontrol_error("get %s failed, fail_num = %d" % (temp_threshold['name'], temp_threshold['fail_num'])) -+ else: -+ temp_threshold['fail_num'] = 0 -+ temp_threshold.setdefault('fix', 0) -+ temp_threshold['temp'] = sensor["Value"] + temp_threshold['fix'] -+ fancontrol_debug("%s = %d" % (temp_threshold['name'], temp_threshold['temp'])) -+ self.update_over_temp_threshold_num() -+ -+ def is_temp_warning(self): -+ warning_flag = False -+ for temp_threshold in self.__temps_threshold_config.values(): -+ if temp_threshold['ignore_threshold']: -+ continue -+ if temp_threshold['warning_num'] >= self.__temp_warning_num: -+ warning_flag = True -+ fancontrol_warn("%%FANCONTROL-4-TEMP_HIGH: %s temperature %sC is larger than warning threshold %sC." % -+ (temp_threshold['name'], temp_threshold['temp'], temp_threshold.get('warning'))) -+ return warning_flag -+ -+ def checkTempWarning(self): -+ try: -+ if self.is_temp_warning(): -+ self.__warning_countdown = self.__temp_warning_countdown -+ fancontrol_debug("temp is over warning") -+ return True -+ if self.__warning_countdown > 0: -+ self.__warning_countdown -= 1 -+ return False -+ except Exception as e: -+ fancontrol_error("%%policy: checkTempWarning failed") -+ fancontrol_error(str(e)) -+ return False -+ -+ def checkTempWarningCountdown(self): -+ if self.__warning_countdown > 0: -+ return True -+ return False -+ -+ def is_temp_critical(self): -+ critical_flag = False -+ for temp_threshold in self.__temps_threshold_config.values(): -+ temp_threshold['critical_flag'] = False -+ if temp_threshold['ignore_threshold']: -+ continue -+ if temp_threshold['critical_num'] >= self.__temp_critical_num: -+ critical_flag = True -+ temp_threshold['critical_flag'] = True -+ fancontrol_crit("%%FANCONTROL-2-TEMP_HIGH: %s temperature %sC is larger than critical threshold %sC." % -+ (temp_threshold['name'], temp_threshold['temp'], temp_threshold.get('critical'))) -+ return critical_flag -+ -+ def checkTempCritical(self): -+ try: -+ if self.is_temp_critical(): -+ self.__critical_countdown = self.__temp_critical_countdown -+ fancontrol_debug("temp is over critical") -+ return True -+ if self.__critical_countdown > 0: -+ self.__critical_countdown -= 1 -+ return False -+ except Exception as e: -+ fancontrol_error("%%policy: checkTempCrit failed") -+ fancontrol_error(str(e)) -+ return False -+ -+ def is_temp_emergency(self): -+ emergency_flag = False -+ for temp_threshold in self.__temps_threshold_config.values(): -+ temp_threshold['emergency_flag'] = False -+ if temp_threshold['ignore_threshold']: -+ continue -+ if temp_threshold['emergency_num'] >= self.__temp_emergency_num: -+ emergency_flag = True -+ temp_threshold['emergency_flag'] = True -+ fancontrol_alert("%%FANCONTROL-1-TEMP_HIGH: %s temperature %sC is larger than emergency threshold %sC." % -+ (temp_threshold['name'], temp_threshold['temp'], temp_threshold.get('emergency'))) -+ return emergency_flag -+ -+ def checkTempEmergency(self): -+ try: -+ if self.is_temp_emergency(): -+ self.__emergency_countdown = self.__temp_emergency_countdown -+ fancontrol_debug("temp is over emergency") -+ return True -+ if self.__emergency_countdown > 0: -+ self.__emergency_countdown -= 1 -+ return False -+ except Exception as e: -+ fancontrol_error("%%policy: checkTempEmergency failed") -+ fancontrol_error(str(e)) -+ return False -+ -+ def checkTempCriticalCountdown(self): -+ if self.__critical_countdown > 0: -+ return True -+ return False -+ -+ def checkTempEmergencyCountdown(self): -+ if self.__emergency_countdown > 0: -+ return True -+ return False -+ -+ def checkTempRebootCrit(self): -+ try: -+ if self.is_temp_critical(): -+ temp_dict = dict(self.__temps_threshold_config) -+ tmp = temp_dict.get(SWITCH_TEMP) -+ if tmp['critical_flag'] is True: -+ fancontrol_debug("switch temp is over reboot critical") -+ return TEMP_REBOOT_CRIT_SWITCH_FLAG -+ del temp_dict[SWITCH_TEMP] -+ for temp_items in temp_dict.values(): -+ if temp_items['ignore_threshold']: -+ continue -+ if temp_items['critical_flag'] is False: -+ return 0 -+ -+ fancontrol_debug("other temp is over reboot critical") -+ return TEMP_REBOOT_CRIT_OTHER_FLAG -+ except Exception as e: -+ fancontrol_error("%%policy: checkTempRebootCrit failed") -+ fancontrol_error(str(e)) -+ return 0 -+ -+ def checkCritReboot(self): -+ try: -+ reboot_flag = self.checkTempRebootCrit() -+ if reboot_flag > 0: -+ self.set_all_fan_speed_pwm(self.__max_pwm) -+ for i in range(self.__check_crit_reboot_num): -+ time.sleep(self.__check_crit_sleep_time) -+ self.get_monitor_temp() -+ reboot_flag = self.checkTempRebootCrit() -+ if reboot_flag > 0: -+ fancontrol_emerg("%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot critical value lasts for %d seconds." % -+ (self.__check_crit_sleep_time * (i + 1))) -+ continue -+ fancontrol_debug("The temperature of device is not over reboot critical value.") -+ break -+ if reboot_flag > 0: -+ fancontrol_emerg( -+ "%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot critical value, system is going to reboot now.") -+ for temp_threshold in self.__temps_threshold_config.values(): -+ fancontrol_emerg( -+ "%%FANCONTROL-TEMP_EMERG: %s temperature: %sC." % -+ (temp_threshold['name'], temp_threshold['temp'])) -+ if reboot_flag == TEMP_REBOOT_CRIT_SWITCH_FLAG: -+ create_judge_file = "touch %s" % self.__otp_switch_reboot_judge_file -+ else: -+ create_judge_file = "touch %s" % self.__otp_other_reboot_judge_file -+ exec_os_cmd(create_judge_file) -+ exec_os_cmd("sync") -+ time.sleep(3) -+ os.system("/sbin/reboot") -+ except Exception as e: -+ fancontrol_error("%%policy: checkCritReboot failed") -+ fancontrol_error(str(e)) -+ -+ def checkTempRebootEmerg(self): -+ try: -+ if self.is_temp_emergency(): -+ temp_emerg_reboot_flag = False -+ for temp_list in self.__check_temp_emergency_reboot: -+ for temp in temp_list: -+ tmp = self.__temps_threshold_config.get(temp) -+ if tmp['emergency_flag'] is False: -+ fancontrol_debug("temp_list %s, temp: %s not emergency" % (temp_list, temp)) -+ temp_emerg_reboot_flag = False -+ break -+ temp_emerg_reboot_flag = True -+ if temp_emerg_reboot_flag is True: -+ fancontrol_debug("temp_list %s, all temp is over emergency reboot" % temp_list) -+ return True -+ except Exception as e: -+ fancontrol_error("%%policy: checkTempRebootEmerg failed") -+ fancontrol_error(str(e)) -+ return False -+ -+ def checkEmergReboot(self): -+ try: -+ reboot_flag = False -+ if self.checkTempRebootEmerg() is True: -+ self.set_all_fan_speed_pwm(self.__max_pwm) -+ for i in range(self.__check_emerg_reboot_num): -+ time.sleep(self.__check_emerg_sleep_time) -+ self.get_monitor_temp() -+ if self.checkTempRebootEmerg() is True: -+ fancontrol_emerg("%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot emergency value lasts for %d seconds." % -+ (self.__check_emerg_sleep_time * (i + 1))) -+ reboot_flag = True -+ continue -+ fancontrol_debug("The temperature of device is not over reboot emergency value.") -+ reboot_flag = False -+ break -+ if reboot_flag is True: -+ fancontrol_emerg( -+ "%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot emergency value, system is going to reboot now.") -+ for temp_threshold in self.__temps_threshold_config.values(): -+ fancontrol_emerg( -+ "%%FANCONTROL-0-TEMP_EMERG: %s temperature: %sC." % -+ (temp_threshold['name'], temp_threshold['temp'])) -+ create_judge_file = "touch %s" % OTP_SWITCH_REBOOT_JUDGE_FILE -+ exec_os_cmd(create_judge_file) -+ exec_os_cmd("sync") -+ time.sleep(3) -+ os.system("/sbin/reboot") -+ except Exception as e: -+ fancontrol_error("%%policy: checkEmergReboot failed") -+ fancontrol_error(str(e)) -+ -+ def get_fan_total_number(self): -+ return self.int_case.get_fan_total_number() -+ -+ def get_rotor_number(self, fan_name): -+ return self.int_case.get_fan_rotor_number(fan_name) -+ -+ def get_fan_presence(self, fan_name): -+ return self.int_case.get_fan_presence(fan_name) -+ -+ def get_fan_rotor_status(self, fan_name, rotor_name): -+ return self.int_case.get_fan_rotor_status(fan_name, rotor_name) -+ -+ def get_psu_total_number(self): -+ return self.int_case.get_psu_total_number() -+ -+ def get_psu_presence(self, psu_name): -+ return self.int_case.get_psu_presence(psu_name) -+ -+ def get_psu_input_output_status(self, psu_name): -+ return self.int_case.get_psu_input_output_status(psu_name) -+ -+ def checkFanPresence(self): -+ absent_num = 0 -+ -+ fan_num = self.get_fan_total_number() -+ for i in range(fan_num): -+ fan_name = "FAN" + str(i + 1) -+ rotor_num = self.get_rotor_number(fan_name) -+ tmp_fan = self.__fan_rotor_error_num.get(fan_name) -+ status = self.get_fan_presence(fan_name) -+ if status is False: -+ absent_num = absent_num + 1 -+ self.__fan_present_status[fan_name] = 0 -+ fancontrol_debug("%s absent" % fan_name) -+ else: -+ if self.__fan_present_status[fan_name] == 0: # absent -> present -+ self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN -+ self.__fan_plug_in_countdown = self.__fan_plug_in_default_countdown -+ self.__fan_repair_flag[fan_name] = 1 -+ for j in range(rotor_num): -+ rotor_name = "Rotor" + str(j + 1) -+ tmp_fan[rotor_name] = 0 -+ self.__fan_present_status[fan_name] = 1 -+ fancontrol_debug("%s presence" % fan_name) -+ return absent_num -+ -+ def checkFanRotorStatus(self): -+ err_num = 0 -+ self.__fan_nok_num = 0 -+ fan_num = self.get_fan_total_number() -+ for i in range(fan_num): -+ fan_name = "FAN" + str(i + 1) -+ rotor_num = self.get_rotor_number(fan_name) -+ tmp_fan = self.__fan_rotor_error_num.get(fan_name) -+ fan_rotor_err_cnt = 0 -+ for j in range(rotor_num): -+ rotor_name = "Rotor" + str(j + 1) -+ status = self.get_fan_rotor_status(fan_name, rotor_name) -+ if status is True: -+ tmp_fan[rotor_name] = 0 -+ fancontrol_debug("%s %s ok" % (fan_name, rotor_name)) -+ else: -+ tmp_fan[rotor_name] += 1 -+ if tmp_fan[rotor_name] >= self.__rotor_error_count: -+ err_num = err_num + 1 -+ fan_rotor_err_cnt += 1 -+ fancontrol_debug("%s %s error" % (fan_name, rotor_name)) -+ fancontrol_debug("%s %s error %d times" % (fan_name, rotor_name, tmp_fan[rotor_name])) -+ if fan_rotor_err_cnt == 0: -+ self.__fan_rotate_status[fan_name] = 1 # FAN is ok -+ else: -+ self.__fan_rotate_status[fan_name] = 0 # FAN is not ok -+ self.__fan_nok_num += 1 -+ fancontrol_debug("fan not ok number:%d." % self.__fan_nok_num) -+ return err_num -+ -+ def checkPsuPresence(self): -+ absent_num = 0 -+ psu_num = self.get_psu_total_number() -+ for i in range(psu_num): -+ psu_name = "PSU" + str(i + 1) -+ status = self.get_psu_presence(psu_name) -+ if status is False: -+ absent_num = absent_num + 1 -+ fancontrol_debug("%s absent" % psu_name) -+ else: -+ fancontrol_debug("%s presence" % psu_name) -+ return absent_num -+ -+ def checkPsuStatus(self): -+ err_num = 0 -+ psu_num = self.get_psu_total_number() -+ for i in range(psu_num): -+ psu_name = "PSU" + str(i + 1) -+ status = self.get_psu_input_output_status(psu_name) -+ if status is False: -+ err_num = err_num + 1 -+ fancontrol_debug("%s error" % psu_name) -+ else: -+ fancontrol_debug("%s ok" % psu_name) -+ return err_num -+ -+ def checkDevError(self): -+ pwm = self.__min_pwm -+ switchtemp = self.__temps_threshold_config.get(SWITCH_TEMP)['temp'] -+ inlettemp = self.__temps_threshold_config.get(INLET_TEMP)['temp'] -+ temp_diff = abs(switchtemp - inlettemp) -+ fancontrol_debug("|switchtemp - inlettemp| = %d" % temp_diff) -+ if temp_diff >= self.__inlet_mac_diff: -+ fancontrol_debug("temp_diff is over than inlet_mac_diff(%d)" % self.__inlet_mac_diff) -+ if self.__pwm > self.__abnormal_pwm: -+ pwm = self.__max_pwm -+ else: -+ pwm = self.__abnormal_pwm -+ return pwm -+ -+ def checktempfail(self): -+ pwm = self.__min_pwm -+ for temp in self.__check_temp_fail: -+ temp_name = temp.get("temp_name") -+ temp_fail_num = self.__temps_threshold_config.get(temp_name)['fail_num'] -+ if temp_fail_num >= self.__temp_fail_num: -+ pwm = self.__abnormal_pwm -+ fancontrol_debug("%s temp_fail_num = %d" % (temp_name, temp_fail_num)) -+ fancontrol_debug("self.__temp_fail_num = %d" % self.__temp_fail_num) -+ return pwm -+ -+ def abnormal_check(self): -+ pwm_list = [] -+ pwm_min = self.__min_pwm -+ pwm_list.append(pwm_min) -+ -+ if self.__check_temp_emergency == 1: -+ status = self.checkTempEmergency() -+ if status is True: -+ over_emerg_pwm = self.__max_pwm -+ pwm_list.append(over_emerg_pwm) -+ fancontrol_debug("over_emerg_pwm = 0x%x" % over_emerg_pwm) -+ # do reset check -+ if self.__check_emerg_reboot_flag == 1: -+ self.checkEmergReboot() -+ else: -+ if self.checkTempEmergencyCountdown() is True: # temp lower than emergency in 5 min -+ over_emerg_countdown_pwm = self.__max_pwm -+ pwm_list.append(over_emerg_countdown_pwm) -+ fancontrol_debug("TempEmergencyCountdown: %d, over_emerg_countdown_pwm = 0x%x" % -+ (self.__emergency_countdown, over_emerg_countdown_pwm)) -+ -+ if self.__check_temp_critical == 1: -+ status = self.checkTempCritical() -+ if status is True: -+ over_crit_pwm = self.__max_pwm -+ pwm_list.append(over_crit_pwm) -+ fancontrol_debug("over_crit_pwm = 0x%x" % over_crit_pwm) -+ # do reset check -+ if self.__check_crit_reboot_flag == 1: -+ self.checkCritReboot() -+ else: -+ if self.checkTempCriticalCountdown() is True: # temp lower than critical in 5 min -+ over_crit_countdown_pwm = self.__max_pwm -+ pwm_list.append(over_crit_countdown_pwm) -+ fancontrol_debug("TempCriticalCountdown: %d, over_crit_countdown_pwm = 0x%x" % -+ (self.__critical_countdown, over_crit_countdown_pwm)) -+ -+ if self.__check_temp_warning == 1: -+ status = self.checkTempWarning() -+ if status is True: -+ over_warn_pwm = self.__warning_pwm -+ pwm_list.append(over_warn_pwm) -+ fancontrol_debug("over_warn_pwm = 0x%x" % over_warn_pwm) -+ else: -+ if self.checkTempWarningCountdown() is True: # temp lower than warning in 5 min -+ over_warn_countdown_pwm = self.__warning_pwm -+ pwm_list.append(over_warn_countdown_pwm) -+ fancontrol_debug("TempWarningCountdown: %d, over_warn_countdown_pwm = 0x%x" % -+ (self.__warning_countdown, over_warn_countdown_pwm)) -+ -+ self.__fan_absent_num = self.checkFanPresence() -+ if self.__fan_absent_num >= self.__fan_absent_fullspeed_num: -+ fan_absent_pwm = self.__max_pwm -+ pwm_list.append(fan_absent_pwm) -+ fancontrol_debug("fan_absent_pwm = 0x%x" % fan_absent_pwm) -+ -+ rotor_err_num = self.checkFanRotorStatus() -+ if rotor_err_num >= self.__rotor_error_fullspeed_num: -+ rotor_err_pwm = self.__max_pwm -+ pwm_list.append(rotor_err_pwm) -+ fancontrol_debug("rotor_err_pwm = 0x%x" % rotor_err_pwm) -+ -+ psu_absent_num = self.checkPsuPresence() -+ if psu_absent_num >= self.__psu_absent_fullspeed_num: -+ psu_absent_pwm = self.__max_pwm -+ pwm_list.append(psu_absent_pwm) -+ fancontrol_debug("psu_absent_pwm = 0x%x" % psu_absent_pwm) -+ -+ dev_err_pwm = self.checkDevError() -+ pwm_list.append(dev_err_pwm) -+ fancontrol_debug("dev_err_pwm = 0x%x" % dev_err_pwm) -+ -+ temp_fail_pwm = self.checktempfail() -+ pwm_list.append(temp_fail_pwm) -+ fancontrol_debug("temp_fail_pwm = 0x%x" % temp_fail_pwm) -+ -+ pwm = max(pwm_list) -+ return pwm -+ -+ def get_error_fan(self): -+ fan_num = self.get_fan_total_number() -+ for i in range(fan_num): -+ fan_name = "FAN" + str(i + 1) -+ if self.__fan_rotate_status[fan_name] == 0: -+ return fan_name -+ return None -+ -+ def fan_error_update_pwm(self, fan_pwm_dict): -+ try: -+ fancontrol_debug("enter deal fan error policy") -+ ori_fan_pwm_dict = fan_pwm_dict.copy() -+ -+ err_fan_name = self.get_error_fan() -+ if err_fan_name is None: -+ fancontrol_debug("fan name is None, do nothing.") -+ return ori_fan_pwm_dict -+ -+ if self.__fan_repair_flag[err_fan_name] == 0: -+ fancontrol_debug("%s already repaired, do nothing." % err_fan_name) -+ return ori_fan_pwm_dict -+ -+ if self.__pre_fan_nok != err_fan_name: -+ fancontrol_debug( -+ "not ok fan change from %s to %s, update countdown." % -+ (self.__pre_fan_nok, err_fan_name)) -+ self.__deal_fan_error_countdown = self.__deal_fan_error_default_countdown -+ if self.__pre_fan_nok != PRE_FAN_NOK_UNKNOWN: -+ fancontrol_debug( -+ "%s repaire success, %s NOT OK, try to repaire." % -+ (self.__pre_fan_nok, err_fan_name)) -+ self.__fan_repair_flag[self.__pre_fan_nok] = 0 -+ self.__pre_fan_nok = err_fan_name -+ -+ if self.__deal_fan_error_countdown > 0: -+ self.__deal_fan_error_countdown -= 1 -+ fancontrol_debug("%s repaire, countdown %d." % (err_fan_name, self.__deal_fan_error_countdown)) -+ -+ if self.__deal_fan_error_countdown == 0: -+ self.__fan_repair_flag[err_fan_name] = 0 -+ fancontrol_debug("%s set repaire fail flag, use origin pwm." % err_fan_name) -+ return ori_fan_pwm_dict -+ -+ fan_err_pwm_conf_list = self.__deal_fan_error_conf[err_fan_name] -+ for item in fan_err_pwm_conf_list: -+ fan_pwm_dict[item["name"]] = item["pwm"] -+ fancontrol_debug("fan pwm update, fan pwm dict:%s" % fan_pwm_dict) -+ -+ return fan_pwm_dict -+ except Exception as e: -+ fancontrol_error("%%policy: deal_fan_error raise Exception:%s" % str(e)) -+ self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN -+ return ori_fan_pwm_dict -+ -+ def get_fan_pwm_dict(self, default_pwm): -+ fan_pwm_dict = {} -+ fan_num = self.get_fan_total_number() -+ for i in range(fan_num): -+ fan_name = "FAN" + str(i + 1) -+ fan_pwm_dict[fan_name] = default_pwm -+ if self.__deal_fan_error_policy: -+ if self.__fan_absent_num == 0 and self.__fan_nok_num == 1: -+ fan_pwm_dict = self.fan_error_update_pwm(fan_pwm_dict) -+ else: -+ if self.__pre_fan_nok != PRE_FAN_NOK_UNKNOWN and self.__fan_rotate_status[self.__pre_fan_nok] == 1: -+ fancontrol_debug("%s repaire success." % (self.__pre_fan_nok)) -+ self.__fan_repair_flag[self.__pre_fan_nok] = 0 -+ self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN -+ return fan_pwm_dict -+ -+ def get_psu_pwm_dict(self, default_pwm): -+ psu_pwm_dict = {} -+ psu_num = self.get_psu_total_number() -+ for i in range(psu_num): -+ psu_name = "PSU" + str(i + 1) -+ psu_pwm_dict[psu_name] = default_pwm -+ return psu_pwm_dict -+ -+ def check_board_air_flow(self): -+ board_air_flow = self.board_air_flow -+ air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) -+ if board_air_flow not in air_flow_tuple: -+ fanairflow_debug("get board air flow error, value [%s]" % board_air_flow) -+ return False -+ fanairflow_debug("board air flow check ok: %s" % board_air_flow) -+ return True -+ -+ def check_fan_air_flow(self): -+ if self.fan_air_flow_monitor: -+ fanairflow_debug("open air flow monitor, check fan air flow") -+ ret = self.check_board_air_flow() -+ if ret is False: -+ fanairflow_debug("get board air flow error, set fan_air_flow_inconsistent_flag False") -+ self.fan_air_flow_inconsistent_flag = False -+ return -+ air_flow_inconsistent_flag_tmp = False -+ for fan_obj in self.fan_obj_list: -+ fan_obj.update_fru_info() -+ fanairflow_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % -+ (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow)) -+ if fan_obj.air_flow == self.na_ret: -+ fanairflow_debug("%s get air flow failed, set air_flow_inconsistent flag False" % fan_obj.name) -+ fan_obj.air_flow_inconsistent = False -+ continue -+ if fan_obj.air_flow != self.board_air_flow: -+ fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], fan air flow [%s], board air flow [%s]" % -+ (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) -+ air_flow_inconsistent_flag_tmp = True -+ fan_obj.air_flow_inconsistent = True -+ else: -+ fanairflow_debug("%s air flow check ok, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s]" % -+ (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) -+ fan_obj.air_flow_inconsistent = False -+ self.fan_air_flow_inconsistent_flag = air_flow_inconsistent_flag_tmp -+ else: -+ fanairflow_debug("air flow monitor not open, set fan_air_flow_inconsistent_flag False") -+ self.fan_air_flow_inconsistent_flag = False -+ return -+ -+ def check_psu_air_flow(self): -+ if self.psu_air_flow_monitor: -+ fanairflow_debug("open air flow monitor, check psu air flow") -+ ret = self.check_board_air_flow() -+ if ret is False: -+ fanairflow_debug("get board air flow error, set psu_air_flow_inconsistent_flag False") -+ self.psu_air_flow_inconsistent_flag = False -+ return -+ air_flow_inconsistent_flag_tmp = False -+ for psu_obj in self.psu_obj_list: -+ psu_obj.update_fru_info() -+ fanairflow_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % -+ (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow)) -+ if psu_obj.air_flow == self.na_ret: -+ fanairflow_debug("%s get air flow failed, set air_flow_inconsistent flag False" % psu_obj.name) -+ psu_obj.air_flow_inconsistent = False -+ continue -+ if psu_obj.air_flow != self.board_air_flow: -+ fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], psu air flow [%s], board air flow [%s]" % -+ (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) -+ air_flow_inconsistent_flag_tmp = True -+ psu_obj.air_flow_inconsistent = True -+ else: -+ fanairflow_debug("%s air flow check ok, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s]" % -+ (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) -+ psu_obj.air_flow_inconsistent = False -+ self.psu_air_flow_inconsistent_flag = air_flow_inconsistent_flag_tmp -+ else: -+ fanairflow_debug("air flow monitor not open, set psu_air_flow_inconsistent_flag False") -+ self.psu_air_flow_inconsistent_flag = False -+ return -+ -+ def do_fancontrol(self): -+ pwm_list = [] -+ pwm_min = self.__min_pwm -+ pwm_list.append(pwm_min) -+ -+ # first check air flow -+ self.check_fan_air_flow() -+ self.check_psu_air_flow() -+ if self.fan_air_flow_inconsistent_flag is True or self.psu_air_flow_inconsistent_flag is True: -+ self.air_flow_inconsistent_flag = True -+ else: -+ self.air_flow_inconsistent_flag = False -+ fanairflow_debug("check_air_flow, air_flow_inconsistent_flag: %s" % self.air_flow_inconsistent_flag) -+ # get_monitor_temp -+ self.get_monitor_temp() -+ fancontrol_debug("last_pwm = 0x%x" % self.__pwm) -+ # openloop -+ inlettemp = self.__temps_threshold_config.get(INLET_TEMP)['temp'] -+ linear_value = self.openloop.linear_cacl(inlettemp) -+ if linear_value is None: -+ linear_value = self.__min_pwm -+ pwm_list.append(linear_value) -+ fancontrol_debug("linear_value = 0x%x" % linear_value) -+ -+ curve_value = self.openloop.curve_cacl(inlettemp) -+ if curve_value is None: -+ curve_value = self.__min_pwm -+ pwm_list.append(curve_value) -+ fancontrol_debug("curve_value = 0x%x" % curve_value) -+ -+ # hyst -+ for hyst_index in self.__hyst_config.values(): -+ temp_name = hyst_index.get("name") -+ hyst_flag = hyst_index.get("flag", 0) -+ if hyst_flag == 0: -+ fancontrol_debug("%s hyst flag is 0, do nothing" % temp_name) -+ continue -+ tmp_temp = int(self.__temps_threshold_config.get(temp_name)['temp']) # make sure temp is int -+ hyst_value = self.hyst.cacl(temp_name, tmp_temp) -+ if hyst_value is None: -+ hyst_value = self.__min_pwm -+ pwm_list.append(hyst_value) -+ fancontrol_debug("%s hyst_value = 0x%x" % (temp_name, hyst_value)) -+ -+ # pid -+ for pid_index in self.__pid_config.values(): -+ temp_name = pid_index.get("name") -+ pid_flag = pid_index.get("flag", 0) -+ if pid_flag == 0: -+ fancontrol_debug("%s pid flag is 0, do nothing" % temp_name) -+ continue -+ tmp_temp = self.__temps_threshold_config.get(temp_name)['temp'] -+ if tmp_temp is not None: -+ tmp_temp = int(tmp_temp) # make sure temp is int -+ invalid_temp_val = self.__temps_threshold_config.get(temp_name)['invalid'] -+ error_temp_val = self.__temps_threshold_config.get(temp_name)['error'] -+ if tmp_temp == invalid_temp_val: # temp is invalid -+ temp = None -+ self.pid.cacl(self.__pwm, temp_name, temp) # temp invalid, PID need to record None -+ pid_value = self.__temp_invalid_pid_pwm -+ fancontrol_debug("%s is invalid, pid_value = 0x%x" % (temp_name, pid_value)) -+ fancontrol_debug("temp = %d, invalid_temp = %d" % (tmp_temp, invalid_temp_val)) -+ elif tmp_temp == error_temp_val: # temp is error -+ temp = None -+ self.pid.cacl(self.__pwm, temp_name, temp) # temp error, PID need to record None -+ pid_value = self.__temp_error_pid_pwm -+ fancontrol_debug("%s is error, pid_value = 0x%x" % (temp_name, pid_value)) -+ fancontrol_debug("temp = %d, error_temp = %d" % (tmp_temp, error_temp_val)) -+ else: -+ pid_value = self.pid.cacl(self.__pwm, temp_name, tmp_temp) -+ else: # temp get failed -+ pid_value = self.pid.cacl(self.__pwm, temp_name, tmp_temp) -+ if pid_value is None: -+ pid_value = self.__min_pwm -+ pwm_list.append(pid_value) -+ fancontrol_debug("%s pid_value = 0x%x" % (temp_name, pid_value)) -+ -+ # abnormal -+ abnormal_value = self.abnormal_check() -+ pwm_list.append(abnormal_value) -+ fancontrol_debug("abnormal_value = 0x%x" % abnormal_value) -+ -+ if self.__fan_plug_in_countdown > 0 and self.__fan_absent_num == 0: -+ fancontrol_debug("fan plug in countdown %d, set plug in pwm: 0x%x" % -+ (self.__fan_plug_in_countdown, self.__fan_plug_in_pwm)) -+ self.__pwm = self.__fan_plug_in_pwm -+ self.__fan_plug_in_countdown -= 1 -+ else: -+ self.__pwm = max(pwm_list) -+ fancontrol_debug("__pwm = 0x%x\n" % self.__pwm) -+ if self.air_flow_inconsistent_flag is True: -+ fanairflow_debug("air flow inconsistent, set all fan speed pwm") -+ self.set_all_fan_speed_pwm(self.__pwm) -+ else: -+ fanairflow_debug("air flow consistent, deal fan error policy") -+ fan_pwm_dict = self.get_fan_pwm_dict(self.__pwm) -+ psu_pwm_dict = self.get_psu_pwm_dict(self.__pwm) -+ self.set_fan_pwm_independent(fan_pwm_dict, psu_pwm_dict) -+ -+ def run(self): -+ start_time = time.time() -+ while True: -+ try: -+ debug_init() -+ if self.__fan_status_interval > 0 and self.__fan_status_interval < self.__interval: -+ delta_time = time.time() - start_time -+ if delta_time >= self.__interval or delta_time < 0: -+ self.do_fancontrol() -+ start_time = time.time() -+ else: -+ self.checkFanPresence() -+ time.sleep(self.__fan_status_interval) -+ else: -+ self.do_fancontrol() -+ time.sleep(self.__interval) -+ except Exception as e: -+ traceback.print_exc() -+ fancontrol_error(str(e)) -+ -+ def set_all_fan_speed_pwm(self, pwm): -+ fan_pwm_dict = {} -+ psu_pwm_dict = {} -+ fan_num = self.get_fan_total_number() -+ for i in range(fan_num): -+ fan_name = "FAN" + str(i + 1) -+ fan_pwm_dict[fan_name] = pwm -+ -+ psu_num = self.get_psu_total_number() -+ for i in range(psu_num): -+ psu_name = "PSU" + str(i + 1) -+ psu_pwm_dict[psu_name] = pwm -+ self.set_fan_pwm_independent(fan_pwm_dict, psu_pwm_dict) -+ -+ def set_fan_pwm_independent(self, fan_pwm_dict, psu_pwm_dict): -+ if self.air_flow_inconsistent_flag is True: -+ for psu_obj in self.psu_obj_list: -+ if psu_obj.air_flow_inconsistent is True: -+ psu_pwm_dict[psu_obj.name] = self.air_flow_error_psu_pwm -+ fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s], set psu pwm: 0x%x" % -+ (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow, self.air_flow_error_psu_pwm)) -+ else: -+ psu_pwm_dict[psu_obj.name] = self.air_flow_correct_psu_pwm -+ fanairflow_debug("%s air flow correct, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s], set psu pwm: 0x%x" % -+ (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow, self.air_flow_correct_psu_pwm)) -+ -+ for fan_obj in self.fan_obj_list: -+ if fan_obj.air_flow_inconsistent is True: -+ fan_pwm_dict[fan_obj.name] = self.air_flow_error_fan_pwm -+ fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s], set fan pwm: 0x%x" % -+ (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow, self.air_flow_error_fan_pwm)) -+ else: -+ fan_pwm_dict[fan_obj.name] = self.air_flow_correct_fan_pwm -+ fanairflow_debug("%s air flow correct, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s], set fan pwm: 0x%x" % -+ (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow, self.air_flow_correct_fan_pwm)) -+ fan_num = self.get_fan_total_number() -+ for i in range(fan_num): -+ fan_name = "FAN" + str(i + 1) -+ self.fan_set_speed_pwm_by_name(fan_name, fan_pwm_dict[fan_name]) -+ if self.__psu_fan_control == 1: -+ psu_num = self.get_psu_total_number() -+ for i in range(psu_num): -+ psu_name = "PSU" + str(i + 1) -+ self.psu_set_speed_pwm_by_name(psu_name, psu_pwm_dict[psu_name]) -+ -+ def fan_set_speed_pwm_by_name(self, fan_name, pwm): -+ duty = round(pwm * 100 / 255) -+ rotor_len = self.get_rotor_number(fan_name) -+ for i in range(rotor_len): -+ val = self.int_case.set_fan_speed_pwm(fan_name, i + 1, duty) -+ if val != 0: -+ fancontrol_error("%s rotor%d: %d" % (fan_name, i + 1, val)) -+ -+ def psu_set_speed_pwm_by_name(self, psu_name, pwm): -+ duty = round(pwm * 100 / 255) -+ status = self.int_case.set_psu_fan_speed_pwm(psu_name, int(duty)) -+ if status is not True: -+ fancontrol_error("set %s speed fail" % psu_name) -+ -+ def fan_obj_init(self): -+ fan_num = self.get_fan_total_number() -+ for i in range(fan_num): -+ fan_name = "FAN" + str(i + 1) -+ fan_obj = DevFan(fan_name, self.int_case) -+ self.fan_obj_list.append(fan_obj) -+ fanairflow_debug("fan object initialize success") -+ -+ def psu_obj_init(self): -+ psu_num = self.get_psu_total_number() -+ for i in range(psu_num): -+ psu_name = "PSU" + str(i + 1) -+ psu_obj = DevPsu(psu_name, self.int_case) -+ self.psu_obj_list.append(psu_obj) -+ fanairflow_debug("psu object initialize success") -+ -+ -+if __name__ == '__main__': -+ debug_init() -+ fancontrol_debug("enter main") -+ fan_control = fancontrol() -+ fan_control.fan_obj_init() -+ fan_control.psu_obj_init() -+ fan_control.run() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/hal_ledctrl.py b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_ledctrl.py -new file mode 100755 -index 000000000..c21fd3c1f ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_ledctrl.py -@@ -0,0 +1,830 @@ -+#!/usr/bin/env python3 -+import time -+import syslog -+import traceback -+from plat_hal.interface import interface -+from plat_hal.baseutil import baseutil -+try: -+ import abc -+except ImportError as error: -+ raise ImportError(str(error) + " - required module not found") from error -+ -+SWITCH_TEMP = "SWITCH_TEMP" -+F2B_AIR_FLOW = "intake" -+B2F_AIR_FLOW = "exhaust" -+ONIE_E2_NAME = "ONIE_E2" -+ -+# status -+STATUS_PRESENT = "PRESENT" -+STATUS_ABSENT = "ABSENT" -+STATUS_OK = "OK" -+STATUS_NOT_OK = "NOT OK" -+STATUS_FAILED = "FAILED" -+STATUS_UNKNOWN = "UNKNOWN" -+ -+LEDCTROL_DEBUG_FILE = "/etc/.ledcontrol_debug_flag" -+ -+LEDCTROLERROR = 1 -+LEDCTROLDEBUG = 2 -+ -+debuglevel = 0 -+# led status defined -+COLOR_GREEN = 1 -+COLOR_AMBER = 2 -+COLOR_RED = 3 -+LED_STATUS_DICT = {COLOR_GREEN: "green", COLOR_AMBER: "amber", COLOR_RED: "red"} -+ -+ -+def ledcontrol_debug(s): -+ if LEDCTROLDEBUG & debuglevel: -+ syslog.openlog("LEDCONTROL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def ledcontrol_error(s): -+ if LEDCTROLERROR & debuglevel: -+ syslog.openlog("LEDCONTROL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+def air_flow_warn(s): -+ syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_WARNING, s) -+ -+ -+def air_flow_error(s): -+ syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_ERR, s) -+ -+ -+def air_flow_emerg(s): -+ syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_EMERG, s) -+ -+ -+def debug_init(): -+ global debuglevel -+ try: -+ with open(LEDCTROL_DEBUG_FILE, "r") as fd: -+ value = fd.read() -+ debuglevel = int(value) -+ except Exception: -+ debuglevel = 0 -+ -+ -+class DevBase(object): -+ __metaclass__ = abc.ABCMeta -+ -+ def __init__(self, name, air_flow_monitor): -+ self.__name = name -+ self.__air_flow_monitor = air_flow_monitor -+ self.present = STATUS_UNKNOWN -+ self.status = STATUS_UNKNOWN -+ self.status_summary = STATUS_UNKNOWN -+ self.origin_name = STATUS_UNKNOWN -+ self.display_name = STATUS_UNKNOWN -+ self.air_flow = STATUS_UNKNOWN -+ self.led_status = COLOR_GREEN -+ -+ @property -+ def name(self): -+ return self.__name -+ -+ @property -+ def air_flow_monitor(self): -+ return self.__air_flow_monitor -+ -+ @abc.abstractmethod -+ def get_present(self): -+ """ -+ Gets the present status of PSU/FAN -+ -+ Returns: -+ A string, e.g. 'PRESENT, ABSENT, FAILED' -+ """ -+ raise NotImplementedError -+ -+ @abc.abstractmethod -+ def get_status(self): -+ """ -+ Gets the status of PSU/FAN -+ -+ Returns: -+ A string, e.g. 'OK, NOT OK, FAILED' -+ """ -+ raise NotImplementedError -+ -+ @abc.abstractmethod -+ def update_dev_info(self): -+ """ -+ update status and fru info of PSU/FAN -+ -+ include present, status, status_summary, part_model_name, product_name, air_flow -+ """ -+ raise NotImplementedError -+ -+ @abc.abstractmethod -+ def set_module_led(self, color): -+ """ -+ set PSU/FAN module LED status -+ -+ Args: -+ color: A string representing the color with which to set the -+ PSU/FAN module LED status -+ -+ Returns: -+ bool: True if status LED state is set successfully, False if not -+ """ -+ raise NotImplementedError -+ -+ -+class DevPsu(DevBase): -+ -+ def __init__(self, name, air_flow_monitor, hal_interface): -+ super(DevPsu, self).__init__(name, air_flow_monitor) -+ self.int_case = hal_interface -+ -+ def get_psu_presence(self): -+ return self.int_case.get_psu_presence(self.name) -+ -+ def get_psu_input_output_status(self): -+ return self.int_case.get_psu_input_output_status(self.name) -+ -+ def get_psu_fru_info(self): -+ return self.int_case.get_psu_fru_info(self.name) -+ -+ @property -+ def na_ret(self): -+ return self.int_case.na_ret -+ -+ def get_present(self): -+ try: -+ status = self.get_psu_presence() -+ if status is True: -+ return STATUS_PRESENT -+ if status is False: -+ return STATUS_ABSENT -+ except Exception as e: -+ ledcontrol_error("get %s present status error, msg: %s" % (self.name, str(e))) -+ return STATUS_FAILED -+ -+ def get_status(self): -+ try: -+ status = self.get_psu_input_output_status() -+ if status is True: -+ return STATUS_OK -+ if status is False: -+ return STATUS_NOT_OK -+ except Exception as e: -+ ledcontrol_error("get %s status error, msg: %s" % (self.name, str(e))) -+ return STATUS_FAILED -+ -+ def update_dev_info(self): -+ try: -+ # update status -+ self.present = self.get_present() -+ if self.present != STATUS_PRESENT: -+ self.status = STATUS_UNKNOWN -+ self.status_summary = self.present -+ else: -+ self.status = self.get_status() -+ self.status_summary = self.status -+ # update fru info if need air flow monitor -+ if self.air_flow_monitor: -+ dic = self.get_psu_fru_info() -+ self.origin_name = dic["PN"] -+ self.air_flow = dic["AirFlow"] -+ self.display_name = dic["DisplayName"] -+ except Exception as e: -+ ledcontrol_error("update %s info error, msg: %s" % (self.name, str(e))) -+ self.present = STATUS_FAILED -+ self.status = STATUS_FAILED -+ self.status_summary = STATUS_FAILED -+ self.origin_name = self.na_ret -+ self.air_flow = self.na_ret -+ self.display_name = self.na_ret -+ -+ def set_module_led(self, color): -+ """ -+ set PSU module LED is not support, always return True -+ """ -+ return True -+ -+ -+class DevFan(DevBase): -+ -+ def __init__(self, name, air_flow_monitor, hal_interface): -+ super(DevFan, self).__init__(name, air_flow_monitor) -+ self.int_case = hal_interface -+ -+ def get_fan_rotor_number(self): -+ return self.int_case.get_fan_rotor_number(self.name) -+ -+ def get_fan_presence(self): -+ return self.int_case.get_fan_presence(self.name) -+ -+ def get_fan_rotor_status(self, rotor_name): -+ return self.int_case.get_fan_rotor_status(self.name, rotor_name) -+ -+ def get_fan_fru_info(self): -+ return self.int_case.get_fan_fru_info(self.name) -+ -+ @property -+ def na_ret(self): -+ return self.int_case.na_ret -+ -+ def get_present(self): -+ try: -+ status = self.get_fan_presence() -+ if status is True: -+ return STATUS_PRESENT -+ if status is False: -+ return STATUS_ABSENT -+ except Exception as e: -+ ledcontrol_error("get %s present status error, msg: %s" % (self.name, str(e))) -+ return STATUS_FAILED -+ -+ def get_status(self): -+ try: -+ rotor_num = self.get_fan_rotor_number() -+ err_motor_num = 0 -+ for j in range(rotor_num): -+ rotor_name = "Rotor" + str(j + 1) -+ roll_status = self.get_fan_rotor_status(rotor_name) -+ if roll_status is not True: -+ err_motor_num += 1 -+ ledcontrol_debug("%s %s error, status %s" % (self.name, rotor_name, roll_status)) -+ else: -+ ledcontrol_debug("%s %s ok" % (self.name, rotor_name)) -+ if err_motor_num > 0: -+ return STATUS_NOT_OK -+ return STATUS_OK -+ except Exception as e: -+ ledcontrol_error("get %s status error, msg: %s" % (self.name, str(e))) -+ return STATUS_FAILED -+ -+ def update_dev_info(self): -+ try: -+ # update status -+ self.present = self.get_present() -+ if self.present != STATUS_PRESENT: -+ self.status = STATUS_UNKNOWN -+ self.status_summary = self.present -+ else: -+ self.status = self.get_status() -+ self.status_summary = self.status -+ # update fru info if need air flow monitor -+ if self.air_flow_monitor: -+ dic = self.get_fan_fru_info() -+ self.origin_name = dic["PN"] -+ self.air_flow = dic["AirFlow"] -+ self.display_name = dic["DisplayName"] -+ except Exception as e: -+ ledcontrol_error("update %s fru info error, msg: %s" % (self.name, str(e))) -+ self.present = STATUS_FAILED -+ self.status = STATUS_FAILED -+ self.status_summary = STATUS_FAILED -+ self.origin_name = self.na_ret -+ self.air_flow = self.na_ret -+ self.display_name = self.na_ret -+ -+ def set_module_led(self, color): -+ ret = self.int_case.set_fan_led(self.name, color) -+ if ret == 0: -+ return True -+ return False -+ -+ -+class ledcontrol(object): -+ -+ def __init__(self): -+ self.fan_obj_list = [] -+ self.psu_obj_list = [] -+ self.board_psu_led_status = COLOR_GREEN -+ self.board_fan_led_status = COLOR_GREEN -+ self.__board_air_flow = "" -+ self.int_case = interface() -+ self.__config = baseutil.get_monitor_config() -+ self.__temps_threshold_config = self.__config["temps_threshold"] -+ for temp_threshold in self.__temps_threshold_config.values(): -+ temp_threshold['temp'] = 0 -+ temp_threshold['fail_num'] = 0 -+ self.__ledcontrol_para = self.__config["ledcontrol_para"] -+ self.__interval = self.__ledcontrol_para.get("interval", 5) -+ self.__checkpsu = self.__ledcontrol_para.get("checkpsu", 0) -+ self.__checkfan = self.__ledcontrol_para.get("checkfan", 0) -+ self.__psu_amber_num = self.__ledcontrol_para.get("psu_amber_num") -+ self.__fan_amber_num = self.__ledcontrol_para.get("fan_amber_num") -+ self.__psu_air_flow_amber_num = self.__ledcontrol_para.get("psu_air_flow_amber_num", 0) -+ self.__fan_air_flow_amber_num = self.__ledcontrol_para.get("fan_air_flow_amber_num", 0) -+ self.__board_sys_led = self.__ledcontrol_para.get("board_sys_led", []) -+ self.__board_psu_led = self.__ledcontrol_para.get("board_psu_led", []) -+ self.__board_fan_led = self.__ledcontrol_para.get("board_fan_led", []) -+ self.__psu_air_flow_monitor = self.__ledcontrol_para.get("psu_air_flow_monitor", 0) -+ self.__fan_air_flow_monitor = self.__ledcontrol_para.get("fan_air_flow_monitor", 0) -+ self.__fan_mix_list = self.__ledcontrol_para.get("fan_mix_list", []) -+ -+ @property -+ def na_ret(self): -+ return self.int_case.na_ret -+ -+ @property -+ def checkpsu(self): -+ return self.__checkpsu -+ -+ @property -+ def checkfan(self): -+ return self.__checkfan -+ -+ @property -+ def psu_amber_num(self): -+ return self.__psu_amber_num -+ -+ @property -+ def fan_amber_num(self): -+ return self.__fan_amber_num -+ -+ @property -+ def psu_air_flow_amber_num(self): -+ return self.__psu_air_flow_amber_num -+ -+ @property -+ def fan_air_flow_amber_num(self): -+ return self.__fan_air_flow_amber_num -+ -+ @property -+ def psu_air_flow_monitor(self): -+ return self.__psu_air_flow_monitor -+ -+ @property -+ def fan_air_flow_monitor(self): -+ return self.__fan_air_flow_monitor -+ -+ @property -+ def board_sys_led(self): -+ return self.__board_sys_led -+ -+ @property -+ def board_psu_led(self): -+ return self.__board_psu_led -+ -+ @property -+ def board_fan_led(self): -+ return self.__board_fan_led -+ -+ @property -+ def fan_mix_list(self): -+ return self.__fan_mix_list -+ -+ @property -+ def interval(self): -+ return self.__interval -+ -+ def get_fan_total_number(self): -+ return self.int_case.get_fan_total_number() -+ -+ def get_psu_total_number(self): -+ return self.int_case.get_psu_total_number() -+ -+ def get_onie_e2_obj(self, name): -+ return self.int_case.get_onie_e2_obj(name) -+ -+ def set_led_color(self, led_name, color): -+ try: -+ ret = self.int_case.set_led_color(led_name, color) -+ except Exception as e: -+ ledcontrol_error("set %s led %s error, msg: %s" % (led_name, color, str(e))) -+ ret = False -+ return ret -+ -+ def set_sys_led(self, color): -+ for led in self.board_sys_led: -+ led_name = led.get("led_name") -+ ret = self.set_led_color(led_name, color) -+ if ret is True: -+ ledcontrol_debug("set %s success, color:%s," % (led_name, color)) -+ else: -+ ledcontrol_debug("set %s failed, color:%s," % (led_name, color)) -+ -+ def set_psu_led(self, color): -+ for led in self.board_psu_led: -+ led_name = led.get("led_name") -+ ret = self.set_led_color(led_name, color) -+ if ret is True: -+ ledcontrol_debug("set %s success, color:%s," % (led_name, color)) -+ else: -+ ledcontrol_debug("set %s failed, color:%s," % (led_name, color)) -+ -+ def set_fan_led(self, color): -+ for led in self.board_fan_led: -+ led_name = led.get("led_name") -+ ret = self.set_led_color(led_name, color) -+ if ret is True: -+ ledcontrol_debug("set %s success, color:%s," % (led_name, color)) -+ else: -+ ledcontrol_debug("set %s failed, color:%s," % (led_name, color)) -+ -+ def set_fan_module_led(self): -+ for fan_obj in self.fan_obj_list: -+ color = LED_STATUS_DICT.get(fan_obj.led_status) -+ ret = fan_obj.set_module_led(color) -+ if ret is True: -+ ledcontrol_debug("set %s module led success, color: %s," % (fan_obj.name, color)) -+ else: -+ ledcontrol_debug("set %s module led failed, color: %s," % (fan_obj.name, color)) -+ -+ @property -+ def board_air_flow(self): -+ air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) -+ if self.__board_air_flow not in air_flow_tuple: -+ self.__board_air_flow = self.int_case.get_device_airflow(ONIE_E2_NAME) -+ ledcontrol_debug("board_air_flow: %s" % self.__board_air_flow) -+ return self.__board_air_flow -+ -+ def update_psu_info(self): -+ for psu_obj in self.psu_obj_list: -+ psu_obj.update_dev_info() -+ ledcontrol_debug("%s present: [%s], status: [%s] status_summary [%s]" % -+ (psu_obj.name, psu_obj.present, psu_obj.status, psu_obj.status_summary)) -+ if psu_obj.air_flow_monitor: -+ ledcontrol_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % -+ (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow)) -+ -+ def update_fan_info(self): -+ for fan_obj in self.fan_obj_list: -+ fan_obj.update_dev_info() -+ ledcontrol_debug("%s present: [%s], status: [%s] status_summary [%s]" % -+ (fan_obj.name, fan_obj.present, fan_obj.status, fan_obj.status_summary)) -+ if fan_obj.air_flow_monitor: -+ ledcontrol_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % -+ (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow)) -+ -+ def get_monitor_temp(self): -+ sensorlist = self.int_case.get_temp_info() -+ -+ for temp_threshold in self.__temps_threshold_config.values(): -+ sensor = sensorlist.get(temp_threshold['name']) -+ if sensor["Value"] is None: -+ temp_threshold['fail_num'] += 1 -+ ledcontrol_error("get %s failed, fail_num = %d" % (temp_threshold['name'], temp_threshold['fail_num'])) -+ else: -+ temp_threshold['fail_num'] = 0 -+ temp_threshold.setdefault('fix', 0) -+ temp_threshold['temp'] = sensor["Value"] + temp_threshold['fix'] -+ ledcontrol_debug("%s = %d" % (temp_threshold['name'], temp_threshold['temp'])) -+ ledcontrol_debug("warning = %d, critical = %d" % (temp_threshold['warning'], temp_threshold['critical'])) -+ -+ def is_temp_warning(self): -+ warning_flag = False -+ for temp_threshold in self.__temps_threshold_config.values(): -+ if temp_threshold['temp'] >= temp_threshold['warning']: -+ warning_flag = True -+ ledcontrol_debug("%s is over warning" % temp_threshold['name']) -+ ledcontrol_debug( -+ "%s = %d, warning = %d" % -+ (temp_threshold['name'], -+ temp_threshold['temp'], -+ temp_threshold['warning'])) -+ return warning_flag -+ -+ def checkTempWarning(self): -+ try: -+ if self.is_temp_warning(): -+ ledcontrol_debug("temp is over warning") -+ return True -+ except Exception as e: -+ ledcontrol_error("%%policy: checkTempWarning failed") -+ ledcontrol_error(str(e)) -+ return False -+ -+ def is_temp_critical(self): -+ critical_flag = False -+ for temp_threshold in self.__temps_threshold_config.values(): -+ temp_threshold['critical_flag'] = False -+ if temp_threshold['temp'] >= temp_threshold['critical']: -+ critical_flag = True -+ temp_threshold['critical_flag'] = True -+ ledcontrol_debug("%s is over critical" % temp_threshold['name']) -+ ledcontrol_debug( -+ "%s = %d, critical = %d" % -+ (temp_threshold['name'], -+ temp_threshold['temp'], -+ temp_threshold['critical'])) -+ return critical_flag -+ -+ def checkTempCrit(self): -+ try: -+ if self.is_temp_critical(): -+ temp_dict = dict(self.__temps_threshold_config) -+ tmp = temp_dict.get(SWITCH_TEMP) -+ if tmp['critical_flag'] is True: -+ ledcontrol_debug("temp is over critical") -+ return True -+ -+ del temp_dict[SWITCH_TEMP] -+ for temp_items in temp_dict.values(): -+ if temp_items['critical_flag'] is False: -+ return False -+ -+ ledcontrol_debug("temp is over critical") -+ return True -+ except Exception as e: -+ ledcontrol_error("%%policy: checkTempCrit failed") -+ ledcontrol_error(str(e)) -+ return False -+ -+ def check_board_air_flow(self): -+ board_air_flow = self.board_air_flow -+ air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) -+ if board_air_flow not in air_flow_tuple: -+ air_flow_error("%%AIR_FLOW_MONITOR-3-BOARD: Get board air flow failed, value: %s." % board_air_flow) -+ return False -+ ledcontrol_debug("board air flow check ok: %s" % board_air_flow) -+ return True -+ -+ def get_monitor_fan_status(self): -+ fanerrnum = 0 -+ for fan_obj in self.fan_obj_list: -+ status = fan_obj.status_summary -+ ledcontrol_debug("%s status: %s" % (fan_obj.name, status)) -+ if status != STATUS_OK: -+ fan_obj.led_status = COLOR_RED -+ fanerrnum += 1 -+ else: -+ fan_obj.led_status = COLOR_GREEN -+ ledcontrol_debug("fan error number: %d" % fanerrnum) -+ -+ if fanerrnum == 0: -+ fan_led_status = COLOR_GREEN -+ elif fanerrnum <= self.fan_amber_num: -+ fan_led_status = COLOR_AMBER -+ else: -+ fan_led_status = COLOR_RED -+ ledcontrol_debug("monitor fan status, set fan led: %s" % LED_STATUS_DICT.get(fan_led_status)) -+ return fan_led_status -+ -+ def get_monitor_psu_status(self): -+ psuerrnum = 0 -+ for psu_obj in self.psu_obj_list: -+ status = psu_obj.status_summary -+ ledcontrol_debug("%s status: %s" % (psu_obj.name, status)) -+ if status != STATUS_OK: -+ psu_obj.led_status = COLOR_RED -+ psuerrnum += 1 -+ else: -+ psu_obj.led_status = COLOR_GREEN -+ ledcontrol_debug("psu error number: %d" % psuerrnum) -+ -+ if psuerrnum == 0: -+ psu_led_status = COLOR_GREEN -+ elif psuerrnum <= self.psu_amber_num: -+ psu_led_status = COLOR_AMBER -+ else: -+ psu_led_status = COLOR_RED -+ ledcontrol_debug("monitor psu status, set psu led: %s" % LED_STATUS_DICT.get(psu_led_status)) -+ return psu_led_status -+ -+ def get_monitor_fan_air_flow(self): -+ if self.fan_air_flow_monitor == 0: -+ ledcontrol_debug("fan air flow monitor not open, default green") -+ return COLOR_GREEN -+ -+ ret = self.check_board_air_flow() -+ if ret is False: -+ ledcontrol_debug("check board air flow error, skip fan air flow monitor.") -+ return COLOR_GREEN -+ -+ fan_led_status_list = [] -+ fan_air_flow_ok_obj_list = [] -+ fan_air_flow_ok_set = set() -+ fan_module_led_list = [] -+ fan_air_flow_err_num = 0 -+ for fan_obj in self.fan_obj_list: -+ if fan_obj.present != STATUS_PRESENT: -+ fan_module_led_list.append(COLOR_GREEN) -+ continue -+ if fan_obj.air_flow == self.na_ret: -+ air_flow_warn("%%AIR_FLOW_MONITOR-4-FAN: %s get air flow failed, fan model: %s, air flow: %s." % -+ (fan_obj.name, fan_obj.display_name, fan_obj.air_flow)) -+ led_status = COLOR_AMBER -+ fan_module_led_list.append(led_status) -+ elif fan_obj.air_flow != self.board_air_flow: -+ air_flow_emerg("%%AIR_FLOW_MONITOR-0-FAN: %s air flow error, fan model: %s, fan air flow: %s, board air flow: %s." % -+ (fan_obj.name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) -+ led_status = COLOR_RED -+ fan_air_flow_err_num += 1 -+ else: -+ fan_air_flow_ok_obj_list.append(fan_obj) -+ fan_air_flow_ok_set.add(fan_obj.origin_name) -+ ledcontrol_debug("%s air flow check ok, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s]" % -+ (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) -+ led_status = COLOR_GREEN -+ fan_module_led_list.append(led_status) -+ if led_status > fan_obj.led_status: -+ fan_obj.led_status = led_status -+ if len(fan_module_led_list) != 0: -+ fan_led_status = max(fan_module_led_list) -+ fan_led_status_list.append(fan_led_status) -+ # check fan mixing -+ if len(fan_air_flow_ok_set) > 1 and fan_air_flow_ok_set not in self.fan_mix_list: -+ for fan_obj in fan_air_flow_ok_obj_list: -+ air_flow_warn("%%AIR_FLOW_MONITOR-4-FAN: %s mixing, fan model: %s, air flow: %s." % -+ (fan_obj.name, fan_obj.origin_name, fan_obj.air_flow)) -+ fan_led_status = COLOR_AMBER -+ fan_led_status_list.append(fan_led_status) -+ # check fan air flow error number -+ if fan_air_flow_err_num == 0: -+ fan_led_status = COLOR_GREEN -+ elif fan_air_flow_err_num <= self.fan_air_flow_amber_num: -+ fan_led_status = COLOR_AMBER -+ else: -+ fan_led_status = COLOR_RED -+ fan_led_status_list.append(fan_led_status) -+ -+ fan_led_status = max(fan_led_status_list) -+ ledcontrol_debug("monitor fan air flow, set fan led: %s" % LED_STATUS_DICT.get(fan_led_status)) -+ return fan_led_status -+ -+ def get_monitor_psu_air_flow(self): -+ if self.psu_air_flow_monitor == 0: -+ ledcontrol_debug("psu air flow monitor not open, default green") -+ return COLOR_GREEN -+ -+ ret = self.check_board_air_flow() -+ if ret is False: -+ ledcontrol_debug("check board air flow error, skip psu air flow monitor.") -+ return COLOR_GREEN -+ -+ psu_led_status_list = [] -+ psu_module_led_list = [] -+ psu_air_flow_err_num = 0 -+ for psu_obj in self.psu_obj_list: -+ if psu_obj.present != STATUS_PRESENT: -+ psu_module_led_list.append(COLOR_GREEN) -+ continue -+ if psu_obj.air_flow == self.na_ret: -+ air_flow_warn("%%AIR_FLOW_MONITOR-4-PSU: %s get air flow failed, psu model: %s, air flow: %s." % -+ (psu_obj.name, psu_obj.display_name, psu_obj.air_flow)) -+ led_status = COLOR_AMBER -+ psu_module_led_list.append(led_status) -+ elif psu_obj.air_flow != self.board_air_flow: -+ air_flow_emerg("%%AIR_FLOW_MONITOR-0-PSU: %s air flow error, psu model: %s, psu air flow: %s, board air flow: %s." % -+ (psu_obj.name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) -+ led_status = COLOR_RED -+ psu_air_flow_err_num += 1 -+ else: -+ ledcontrol_debug("%s psu air flow check ok, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s]" % -+ (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) -+ led_status = COLOR_GREEN -+ psu_module_led_list.append(led_status) -+ if led_status > psu_obj.led_status: -+ psu_obj.led_status = led_status -+ -+ if len(psu_module_led_list) != 0: -+ psu_led_status = max(psu_module_led_list) -+ psu_led_status_list.append(psu_led_status) -+ -+ # check fan air flow error number -+ if psu_air_flow_err_num == 0: -+ psu_led_status = COLOR_GREEN -+ elif psu_air_flow_err_num <= self.psu_air_flow_amber_num: -+ psu_led_status = COLOR_AMBER -+ else: -+ psu_led_status = COLOR_RED -+ psu_led_status_list.append(psu_led_status) -+ -+ psu_led_status = max(psu_led_status_list) -+ ledcontrol_debug("monitor psu air flow, set psu led: %s" % LED_STATUS_DICT.get(psu_led_status)) -+ return psu_led_status -+ -+ def get_temp_sys_led_status(self): -+ if self.checkTempCrit() is True: -+ sys_led_status = COLOR_RED -+ elif self.checkTempWarning() is True: -+ sys_led_status = COLOR_AMBER -+ else: -+ sys_led_status = COLOR_GREEN -+ ledcontrol_debug("monitor temperature, set sys led: %s" % LED_STATUS_DICT.get(sys_led_status)) -+ return sys_led_status -+ -+ def get_sys_led_follow_fan_status(self): -+ -+ if self.checkfan: -+ sys_led_status = self.board_fan_led_status -+ ledcontrol_debug("sys led follow fan led, set sys led: %s" % LED_STATUS_DICT.get(sys_led_status)) -+ else: -+ sys_led_status = COLOR_GREEN -+ ledcontrol_debug("sys led don't follow fan led, set default green") -+ return sys_led_status -+ -+ def get_sys_led_follow_psu_status(self): -+ if self.checkpsu: -+ sys_led_status = self.board_psu_led_status -+ ledcontrol_debug("sys led follow psu led, set sys led: %s" % LED_STATUS_DICT.get(sys_led_status)) -+ else: -+ sys_led_status = COLOR_GREEN -+ ledcontrol_debug("sys led don't follow psu led, set default green") -+ return sys_led_status -+ -+ def dealSysLedStatus(self): -+ sys_led_status_list = [] -+ # get_monitor_temp -+ self.get_monitor_temp() -+ -+ # monitor temp get sys led status -+ sys_led_status = self.get_temp_sys_led_status() -+ sys_led_status_list.append(sys_led_status) -+ -+ # check sys led follow fan led status -+ sys_led_status = self.get_sys_led_follow_fan_status() -+ sys_led_status_list.append(sys_led_status) -+ -+ # check sys led follow psu led status -+ sys_led_status = self.get_sys_led_follow_psu_status() -+ sys_led_status_list.append(sys_led_status) -+ -+ sys_led_status = max(sys_led_status_list) -+ sys_led_color = LED_STATUS_DICT.get(sys_led_status) -+ -+ # set sys led -+ self.set_sys_led(sys_led_color) -+ -+ def dealFanLedStatus(self): -+ fan_led_status_list = [] -+ # update fan info -+ self.update_fan_info() -+ -+ # monitor fan status first -+ fan_led_status = self.get_monitor_fan_status() -+ fan_led_status_list.append(fan_led_status) -+ -+ # monitor fan air flow -+ fan_led_status = self.get_monitor_fan_air_flow() -+ fan_led_status_list.append(fan_led_status) -+ -+ self.board_fan_led_status = max(fan_led_status_list) -+ fan_led_color = LED_STATUS_DICT.get(self.board_fan_led_status) -+ -+ # set fan led -+ self.set_fan_led(fan_led_color) -+ # set fan module led -+ self.set_fan_module_led() -+ -+ def dealPsuLedStatus(self): -+ psu_led_status_list = [] -+ # update psu info -+ self.update_psu_info() -+ -+ # monitor psu status first -+ psu_led_status = self.get_monitor_psu_status() -+ psu_led_status_list.append(psu_led_status) -+ -+ # monitor psu air flow -+ psu_led_status = self.get_monitor_psu_air_flow() -+ psu_led_status_list.append(psu_led_status) -+ -+ self.board_psu_led_status = max(psu_led_status_list) -+ psu_led_color = LED_STATUS_DICT.get(self.board_psu_led_status) -+ -+ # set psu led -+ self.set_psu_led(psu_led_color) -+ -+ def do_ledcontrol(self): -+ self.dealPsuLedStatus() -+ self.dealFanLedStatus() -+ self.dealSysLedStatus() -+ -+ def fan_obj_init(self): -+ fan_num = self.get_fan_total_number() -+ for i in range(fan_num): -+ fan_name = "FAN" + str(i + 1) -+ fan_obj = DevFan(fan_name, self.fan_air_flow_monitor, self.int_case) -+ self.fan_obj_list.append(fan_obj) -+ ledcontrol_debug("fan object initialize success") -+ -+ def psu_obj_init(self): -+ psu_num = self.get_psu_total_number() -+ for i in range(psu_num): -+ psu_name = "PSU" + str(i + 1) -+ psu_obj = DevPsu(psu_name, self.psu_air_flow_monitor, self.int_case) -+ self.psu_obj_list.append(psu_obj) -+ ledcontrol_debug("psu object initialize success") -+ -+ def run(self): -+ while True: -+ try: -+ debug_init() -+ self.do_ledcontrol() -+ time.sleep(self.interval) -+ except Exception as e: -+ traceback.print_exc() -+ ledcontrol_error(str(e)) -+ -+ -+if __name__ == '__main__': -+ debug_init() -+ ledcontrol_debug("enter main") -+ led_control = ledcontrol() -+ led_control.fan_obj_init() -+ led_control.psu_obj_init() -+ led_control.run() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/hal_pltfm.py b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_pltfm.py -new file mode 100755 -index 000000000..11196f507 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_pltfm.py -@@ -0,0 +1,492 @@ -+#!/usr/bin/env python3 -+# -*- coding: UTF-8 -*- -+import inspect -+import sys -+import json -+import time -+from plat_hal.interface import interface -+ -+ -+class Command(): -+ def __init__(self, name, f): -+ self.name = name -+ self.f = f -+ self.paramcount = self.f.__code__.co_argcount -+ -+ def dofun(self, args): -+ fn = self.f.__call__ -+ fn(*args) -+ -+ -+class Group(): -+ def __init__(self, name, f): -+ self.groups = [] -+ self.commands = [] -+ self.name = name -+ self.f = f -+ -+ def add_groups(self, command): -+ self.groups.append(command) -+ -+ def add_commands(self, commnad): -+ x = Command(commnad.__name__, commnad) -+ self.commands.append(x) -+ -+ def find_valuebyname(self, name): -+ for item in self.groups: -+ if name == item.name: -+ return item -+ for item in self.commands: -+ if name == item.name: -+ return item -+ return None -+ -+ def deal(self, args): -+ if len(args) <= 0: -+ return self.print_help() -+ funclevel = args[0] -+ val = self.find_valuebyname(funclevel) -+ if val is None: -+ return self.print_help() -+ if isinstance(val, Command): -+ if len(args) < (val.paramcount + 1): -+ return self.print_help() -+ inputargs = args[1: (1 + val.paramcount)] -+ return val.dofun(inputargs) -+ if isinstance(val, Group): -+ args = args[1:] -+ return val.deal(args) -+ return self.print_help() -+ -+ def get_max(self, arr): -+ lentmp = 0 -+ for ar in arr: -+ lentmp = len(ar) if (len(ar) > lentmp) else lentmp -+ return lentmp -+ -+ def print_help(self): -+ -+ namesize = [] -+ for item in self.groups: -+ namesize.append(item.name) -+ for item in self.commands: -+ namesize.append(item.name) -+ maxvalue = self.get_max(namesize) -+ -+ if len(self.groups) > 0: -+ print("Groups:") -+ for item in self.groups: -+ print(" %-*s %s" % (maxvalue, item.name, item.f.__doc__ or '')) -+ if len(self.commands) > 0: -+ print("Commands:") -+ for item in self.commands: -+ print(" %-*s %s" % (maxvalue, item.name, item.f.__doc__ or '')) -+ -+ -+class clival(): -+ @staticmethod -+ def Fire(val=None): -+ group = Group("top", 'mainlevel') -+ clival.iterGroup(val, group) -+ # context = {} -+ # caller = inspect.stack()[1] -+ # caller_frame = caller[0] -+ # caller_globals = caller_frame.f_globals -+ # caller_locals = caller_frame.f_locals -+ # context.update(caller_globals) -+ # context.update(caller_locals) -+ args = sys.argv[1:] -+ group.deal(args) -+ -+ @staticmethod -+ def iterGroup(val, group): -+ for key, item in val.items(): -+ if item is None: # first level -+ if inspect.isfunction(key): -+ group.add_commands(key) -+ else: -+ group1 = Group(key.__name__, key) -+ clival.iterGroup(item, group1) -+ group.add_groups(group1) -+ -+ -+def psu(): -+ r'''test psu ''' -+ -+ -+def fan(): -+ r'''test fan ''' -+ -+ -+def sensor(): -+ r'''test sensor ''' -+ -+ -+def dcdc(): -+ r'''test dcdc ''' -+ -+ -+def led(): -+ r'''test led ''' -+ -+ -+def e2(): -+ r'''test onie eeprom ''' -+ -+ -+def temps(): -+ r'''test temps sensor''' -+ -+def cpu(): -+ r'''test cpu''' -+ -+ -+int_case = interface() -+ -+ -+def get_total_number(): -+ r'''psu get_total_number ''' -+ print("=================get_total_number======================") -+ print(int_case.get_psu_total_number()) -+ -+ -+def get_presence(): -+ r'''psu get_presence ''' -+ print("=================get_presence======================") -+ psus = int_case.get_psus() -+ for psu_item in psus: -+ print(psu_item.name, end=' ') -+ print(int_case.get_psu_presence(psu_item.name)) -+ -+ -+def get_fru_info(): -+ r'''psu get_fru_info ''' -+ print("=================get_fru_info======================") -+ psus = int_case.get_psus() -+ for psu_item in psus: -+ print(psu_item.name, end=' ') -+ print(json.dumps(int_case.get_psu_fru_info(psu_item.name), ensure_ascii=False, indent=4)) -+ -+ -+def get_status(): -+ r'''psu get_status ''' -+ print("=================get_status======================") -+ psus = int_case.get_psus() -+ for psu_item in psus: -+ print(psu_item.name, end=' ') -+ print(json.dumps(int_case.get_psu_status(psu_item.name), ensure_ascii=False, indent=4)) -+ -+ -+def set_psu_fan_speed_pwm(realspeed): -+ r'''set_psu_fan_speed_pwm''' -+ print("=================set_psu_fan_speed_pwm======================") -+ psus = int_case.get_psus() -+ for psu_item in psus: -+ print(psu_item.name, end=' ') -+ print(int_case.set_psu_fan_speed_pwm(psu_item.name, int(realspeed))) -+ -+ -+def get_psu_fan_speed_pwm(): -+ r'''get_psu_fan_speed_pwm''' -+ print("=================get_psu_fan_speed_pwm======================") -+ psus = int_case.get_psus() -+ for psu_item in psus: -+ print(psu_item.name, end=' ') -+ print(json.dumps(int_case.get_psu_fan_speed_pwm(psu_item.name))) -+ -+ -+def get_psu_power_status(): -+ r'''psu get_psu_power_status ''' -+ print("=================get_psu_power_status======================") -+ psus = int_case.get_psus() -+ for psu_item in psus: -+ print(psu_item.name, end=' ') -+ print(json.dumps(int_case.get_psu_power_status(psu_item.name), ensure_ascii=False, indent=4)) -+ -+ -+def get_info_all(): -+ r'''psu get_info_all ''' -+ print("=================get_info_all======================") -+ print(json.dumps(int_case.get_psu_info_all(), ensure_ascii=False, indent=4)) -+ -+ -+def fan_get_total_number(): -+ print("=================get_info_all======================") -+ print(json.dumps(int_case.get_fan_total_number(), ensure_ascii=False, indent=4)) -+ -+ -+def fan_get_rotor_number(): -+ r'''fan_get_rotor_number''' -+ print("=================fan_get_rotor_number======================") -+ fans = int_case.get_fans() -+ for fan_item in fans: -+ print(fan_item.name, end=' ') -+ print(int_case.get_fan_rotor_number(fan_item.name)) -+ -+ -+def fan_get_speed(): -+ r'''fan_get_speed''' -+ print("=================fan_get_speed======================") -+ fans = int_case.get_fans() -+ for fan_item in fans: -+ rotors = fan_item.rotor_list -+ for rotor in rotors: -+ index = rotors.index(rotor) -+ print("%s rotor%d" % (fan_item.name, index + 1), end=' ') -+ print(int_case.get_fan_speed(fan_item.name, index + 1)) -+ -+ -+def fan_get_speed_pwm(): -+ r'''fan_get_speed_pwm''' -+ print("=================fan_get_speed_pwm======================") -+ fans = int_case.get_fans() -+ for fan_item in fans: -+ rotors = fan_item.rotor_list -+ for rotor in rotors: -+ index = rotors.index(rotor) -+ print("%s rotor%d" % (fan_item.name, index + 1), end=' ') -+ print(int_case.get_fan_speed_pwm(fan_item.name, index + 1)) -+ -+ -+def fan_set_speed_pwm(pwm): -+ r'''fan_set_speed_pwm''' -+ print("=================fan_set_speed_pwm======================") -+ fans = int_case.get_fans() -+ for fan_item in fans: -+ rotors = fan_item.rotor_list -+ for rotor in rotors: -+ index = rotors.index(rotor) -+ print("%s %s" % (fan_item.name, rotor.name), end=' ') -+ val = int_case.set_fan_speed_pwm(fan_item.name, index + 1, pwm) -+ print(val) -+ -+ -+def fan_get_watchdog_status(): -+ r'''fan_get_watchdog_status''' -+ print("=================fan_get_watchdog_status======================") -+ print(int_case.get_fan_watchdog_status()) -+ -+ -+def fan_enable_watchdog(): -+ r'''fan_enable_watchdog''' -+ print("=================fan_enable_watchdog======================") -+ print('enable', int_case.enable_fan_watchdog()) -+ -+ -+def fan_disable_watchdog(): -+ r'''fan_disable_watchdog''' -+ print("=================fan_disable_watchdog======================") -+ print('disable', int_case.enable_fan_watchdog(enable=False)) -+ -+ -+def fan_get_speed1(): -+ r'''fan_get_speed''' -+ print("=================fan_get_speed======================") -+ fans = int_case.get_fans() -+ for fan_item in fans: -+ rotors = fan_item.rotor_list -+ for rotor in rotors: -+ print("%s %s" % (fan_item.name, rotor.name), end=' ') -+ print(int_case.get_fan_speed(fan_item.name, rotor.name)) -+ -+ -+def fan_feed_watchdog(): -+ r'''fan_feed_watchdog''' -+ print("=================fan_feed_watchdog======================") -+ fan_get_speed() -+ print(int_case.feed_fan_watchdog()) -+ time.sleep(2) -+ fan_get_speed() -+ -+ -+def fan_set_led(color): -+ r'''fan_set_led''' -+ print("=================fan_set_led======================") -+ fans = int_case.get_fans() -+ for fan_item in fans: -+ print("%s" % fan_item.name) -+ print(color, int_case.set_fan_led(fan_item.name, color)) -+ -+def fan_get_led(): -+ r'''fan_get_led''' -+ print("=================fan_get_led======================") -+ fans = int_case.get_fans() -+ for fan_item in fans: -+ print("%s" % fan_item.name) -+ print(int_case.get_fan_led(fan_item.name)) -+ -+ -+def fan_get_presence(): -+ r'''fan_get_presence''' -+ print("=================fan_get_presence======================") -+ fans = int_case.get_fans() -+ for fan_item in fans: -+ print("%s" % fan_item.name) -+ print(int_case.get_fan_presence(fan_item.name)) -+ -+ -+def fan_get_info(): -+ r'''fan_get_info''' -+ print("=================fan_get_info======================") -+ fans = int_case.get_fans() -+ for fan_item in fans: -+ print("%s" % fan_item.name) -+ print(json.dumps(int_case.get_fan_info(fan_item.name), ensure_ascii=False, indent=4)) -+ -+ -+def fan_get_status(): -+ r'''fan_get_status''' -+ print("=================fan_get_status======================") -+ fans = int_case.get_fans() -+ for fan_item in fans: -+ print("%s" % fan_item.name) -+ print(json.dumps(int_case.get_fan_status(fan_item.name), ensure_ascii=False, indent=4)) -+ -+ -+def fan_get_info_all(): -+ r'''fan_get_info_all''' -+ print("=================fan_get_info_all======================") -+ print(json.dumps(int_case.get_fan_info_all(), ensure_ascii=False, indent=4)) -+ -+ -+def get_sensor_info(): -+ r'''get_sensor_info''' -+ print("=================get_sensor_info======================") -+ print(json.dumps(int_case.get_sensor_info(), ensure_ascii=False, indent=4)) -+ -+ -+def get_dcdc_all_info(): -+ r'''get_dcdc_all_info''' -+ print("=================get_dcdc_all_info======================") -+ print(json.dumps(int_case.get_dcdc_all_info(), ensure_ascii=False, indent=4)) -+ -+ -+def set_all_led_color(color): -+ r'''set_all_led_color color''' -+ print("=================set_all_led_color======================") -+ leds = int_case.get_leds() -+ for led_item in leds: -+ print("%s" % led_item.name) -+ print(color, int_case.set_led_color(led_item.name, color)) -+ -+ -+def get_all_led_color(): -+ r'''get_all_led_color''' -+ print("=================get_all_led_color======================") -+ leds = int_case.get_leds() -+ for led_item in leds: -+ print("%s" % led_item.name) -+ print(int_case.get_led_color(led_item.name)) -+ -+ -+def set_single_led_color(led_name, color): -+ r'''set_single_led_color led_name color''' -+ print("=================set_single_led_color======================") -+ leds = int_case.get_leds() -+ for led_item in leds: -+ if led_name == led_item.name: -+ print("%s" % led_item.name) -+ print(color, int_case.set_led_color(led_item.name, color)) -+ -+ -+def get_single_led_color(led_name): -+ r'''get_single_led_color''' -+ print("=================get_single_led_color======================") -+ leds = int_case.get_leds() -+ for led_item in leds: -+ if led_name == led_item.name: -+ print("%s" % led_item.name) -+ print(int_case.get_led_color(led_item.name)) -+ -+ -+def get_onie_e2_path(): -+ r'''get_onie_e2_path''' -+ print("=================get_onie_e2_path======================") -+ path = int_case.get_onie_e2_path("ONIE_E2") -+ print("%s" % path) -+ -+ -+def get_device_airflow(): -+ r'''get_device_airflow''' -+ print("=================get_device_airflow======================") -+ airflow = int_case.get_device_airflow("ONIE_E2") -+ print("%s" % airflow) -+ -+ -+def get_temps_sensor(): -+ r'''get_temps_sensor''' -+ print("=================get_temps_sensor======================") -+ temp_list = int_case.get_temps() -+ for temp in temp_list: -+ print("id: %s, name: %s, API name: %s, value: %s" % (temp.temp_id, temp.name, temp.api_name, temp.Value)) -+ -+def get_cpu_reset_num(): -+ r'''get_cpu_reset_num''' -+ print("=================get_cpu_reset_num======================") -+ print(int_case.get_cpu_reset_num()) -+ -+def get_cpu_reboot_cause(): -+ r'''get_cpu_reboot_cause''' -+ print("=================get_cpu_reboot_cause======================") -+ print(int_case.get_cpu_reboot_cause()) -+ -+ -+def run_cli_man(): -+ clival.Fire( -+ { -+ psu: { -+ get_total_number: None, -+ get_presence: None, -+ get_fru_info: None, -+ set_psu_fan_speed_pwm: None, -+ get_psu_fan_speed_pwm: None, -+ get_status: None, -+ get_psu_power_status: None, -+ get_info_all: None -+ }, -+ fan: { -+ fan_get_total_number: None, -+ fan_get_rotor_number: None, -+ fan_get_speed: None, -+ fan_get_speed_pwm: None, -+ fan_set_speed_pwm: None, -+ fan_get_watchdog_status: None, -+ fan_enable_watchdog: None, -+ fan_disable_watchdog: None, -+ fan_feed_watchdog: None, -+ fan_set_led: None, -+ fan_get_led: None, -+ fan_get_presence: None, -+ fan_get_info: None, -+ fan_get_status: None, -+ fan_get_info_all: None -+ }, -+ sensor: { -+ get_sensor_info: None -+ }, -+ dcdc: { -+ get_dcdc_all_info: None -+ }, -+ led: { -+ set_all_led_color: None, -+ set_single_led_color: None, -+ get_all_led_color: None, -+ get_single_led_color: None, -+ }, -+ e2: { -+ get_onie_e2_path: None, -+ get_device_airflow: None, -+ }, -+ temps: { -+ get_temps_sensor: None, -+ }, -+ cpu: { -+ get_cpu_reset_num: None, -+ get_cpu_reboot_cause: None, -+ } -+ } -+ ) -+ -+ -+if __name__ == '__main__': -+ run_cli_man() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor.py b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor.py -new file mode 100755 -index 000000000..33d5bfba6 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor.py -@@ -0,0 +1,144 @@ -+#!/usr/bin/python3 -+# -*- coding: UTF-8 -*- -+ -+import os -+import time -+import syslog -+from plat_hal.interface import interface -+from plat_hal.baseutil import baseutil -+from platform_util import io_rd, wbi2cget -+ -+INTELLIGENT_MONITOR_DEBUG_FILE = "/etc/.intelligent_monitor_debug" -+ -+debuglevel = 0 -+ -+ -+def monitor_syslog_debug(s): -+ if debuglevel: -+ syslog.openlog("INTELLIGENT_MONITOR_DEBUG", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def monitor_syslog(s): -+ syslog.openlog("INTELLIGENT_MONITOR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_WARNING, s) -+ -+ -+def pmon_syslog_notice(s): -+ syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_NOTICE, s) -+ -+ -+class IntelligentMonitor(): -+ def __init__(self): -+ self.dcdc_dict = {} -+ self.int_case = interface() -+ self.__config = baseutil.get_monitor_config() -+ self.__intelligent_monitor_para = self.__config.get('intelligent_monitor_para', {}) -+ self.__interval = self.__intelligent_monitor_para.get('interval', 60) -+ self.__dcdc_whitelist = self.__config.get('dcdc_monitor_whitelist', {}) -+ self.__error_ret = self.int_case.error_ret -+ -+ @property -+ def error_ret(self): -+ return self.__error_ret -+ -+ @property -+ def interval(self): -+ return self.__interval -+ -+ def debug_init(self): -+ global debuglevel -+ if os.path.exists(INTELLIGENT_MONITOR_DEBUG_FILE): -+ debuglevel = 1 -+ else: -+ debuglevel = 0 -+ -+ def dcdc_whitelist_check(self, dcdc_name): -+ try: -+ check_item = self.__dcdc_whitelist.get(dcdc_name, {}) -+ if len(check_item) == 0: -+ return False -+ gettype = check_item.get("gettype", None) -+ checkbit = check_item.get("checkbit", None) -+ okval = check_item.get("okval", None) -+ if gettype is None or checkbit is None or okval is None: -+ monitor_syslog('%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s config error. gettype:%s, checkbit:%s, okval:%s' % -+ (dcdc_name, gettype, checkbit, okval)) -+ return False -+ if gettype == "io": -+ io_addr = check_item.get('io_addr', None) -+ val = io_rd(io_addr) -+ if val is not None: -+ retval = val -+ else: -+ monitor_syslog( -+ '%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s io_rd error. io_addr:%s' % -+ (dcdc_name, io_addr)) -+ return False -+ elif gettype == "i2c": -+ bus = check_item.get('bus', None) -+ addr = check_item.get('addr', None) -+ offset = check_item.get('offset', None) -+ ind, val = wbi2cget(bus, addr, offset) -+ if ind is True: -+ retval = val -+ else: -+ monitor_syslog('%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s i2cget error. bus:%s, addr:%s, offset:%s' % -+ (dcdc_name, bus, addr, offset)) -+ return False -+ else: -+ monitor_syslog('%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s gettype not support' % dcdc_name) -+ return False -+ -+ val_t = (int(retval, 16) & (1 << checkbit)) >> checkbit -+ if val_t != okval: -+ return False -+ return True -+ except Exception as e: -+ monitor_syslog('%%WHITELIST_CHECK: %s check error, msg: %s.' % (dcdc_name, str(e))) -+ return False -+ -+ def update_dcdc_status(self): -+ try: -+ self.dcdc_dict = self.int_case.get_dcdc_all_info() -+ for dcdc_name, item in self.dcdc_dict.items(): -+ ret = self.dcdc_whitelist_check(dcdc_name) -+ if ret is False: -+ if item['Value'] == self.error_ret: -+ monitor_syslog( -+ '%%INTELLIGENT_MONITOR-3-DCDC_SENSOR_FAILED: The value of %s read failed.' % -+ (dcdc_name)) -+ elif float(item['Value']) > float(item['Max']): -+ pmon_syslog_notice('%%PMON-5-VOLTAGE_HIGH: %s voltage %.3f%s is larger than max threshold %.3f%s.' % -+ (dcdc_name, float(item['Value']), item['Unit'], float(item['Max']), item['Unit'])) -+ elif float(item['Value']) < float(item['Min']): -+ pmon_syslog_notice('%%PMON-5-VOLTAGE_LOW: %s voltage %.3f%s is lower than min threshold %.3f%s.' % -+ (dcdc_name, float(item['Value']), item['Unit'], float(item['Min']), item['Unit'])) -+ else: -+ monitor_syslog_debug('%%INTELLIGENT_MONITOR-6-DCDC_SENSOR_OK: %s normal, value is %.3f%s.' % -+ (dcdc_name, item['Value'], item['Unit'])) -+ else: -+ monitor_syslog_debug( -+ '%%INTELLIGENT_MONITOR-6-DCDC_WHITELIST_CHECK: %s is in dcdc whitelist, not monitor voltage' % -+ dcdc_name) -+ continue -+ except Exception as e: -+ monitor_syslog('%%INTELLIGENT_MONITOR-3-EXCEPTION: update dcdc sensors status error, msg: %s.' % (str(e))) -+ -+ def doWork(self): -+ self.update_dcdc_status() -+ -+ def run(self): -+ while True: -+ try: -+ self.debug_init() -+ self.doWork() -+ time.sleep(self.interval) -+ except Exception as e: -+ monitor_syslog('%%INTELLIGENT_MONITOR-3-EXCEPTION: %s.' % (str(e))) -+ -+ -+if __name__ == '__main__': -+ intelligent_monitor = IntelligentMonitor() -+ intelligent_monitor.run() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor/monitor_fan.py b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor/monitor_fan.py -new file mode 100755 -index 000000000..c84319f3b ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor/monitor_fan.py -@@ -0,0 +1,284 @@ -+#!/usr/bin/python3 -+# -*- coding: UTF-8 -*- -+ -+import os -+import time -+import logging -+from logging.handlers import RotatingFileHandler -+ -+from plat_hal.interface import interface -+from plat_hal.baseutil import baseutil -+ -+ -+DEBUG_FILE = "/etc/.monitor_fan_debug_flag" -+ -+LOG_FILE = "/var/log/intelligent_monitor/monitor_fan_log" -+ -+E2_NAME = "ONIE_E2" -+ -+ -+def _init_logger(): -+ if not os.path.exists(LOG_FILE): -+ os.system("mkdir -p %s" % os.path.dirname(LOG_FILE)) -+ os.system("sync") -+ handler = RotatingFileHandler(filename=LOG_FILE, maxBytes=5 * 1024 * 1024, backupCount=1) -+ formatter = logging.Formatter("%(asctime)s %(levelname)s %(filename)s[%(funcName)s][%(lineno)s]: %(message)s") -+ handler.setFormatter(formatter) -+ logger = logging.getLogger(__name__) -+ logger.setLevel(logging.INFO) -+ logger.addHandler(handler) -+ return logger -+ -+ -+class Fan(object): -+ -+ def __init__(self, name, hal_interface): -+ self.name = name -+ self.fan_dict = {} -+ self.int_case = hal_interface -+ self.update_time = 0 -+ self.pre_present = False -+ self.pre_status = True -+ self.plugin_cnt = 0 -+ self.plugout_cnt = 0 -+ self.status_normal_cnt = 0 -+ self.status_error_cnt = 0 -+ -+ def fan_dict_update(self): -+ local_time = time.time() -+ if not self.fan_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds -+ self.update_time = local_time -+ self.fan_dict = self.int_case.get_fan_info(self.name) -+ -+ def get_model(self): -+ self.fan_dict_update() -+ return self.fan_dict["NAME"] -+ -+ def get_serial(self): -+ self.fan_dict_update() -+ return self.fan_dict["SN"] -+ -+ def get_presence(self): -+ return self.int_case.get_fan_presence(self.name) -+ -+ def get_rotor_speed(self, rotor_name): -+ """ -+ Retrieves the speed of fan as a percentage of full speed -+ -+ Returns: -+ An integer, the percentage of full fan speed, in the range 0 (off) -+ to 100 (full speed) -+ """ -+ fan_dir = {} -+ fan_dir = self.int_case.get_fan_info_rotor(self.name) -+ # get fan rotor pwm -+ value = fan_dir[rotor_name]["Speed"] -+ max_speed = fan_dir[rotor_name]["SpeedMax"] -+ -+ if isinstance(value, str) or value is None: -+ return 0 -+ pwm = value * 100 / max_speed -+ if pwm > 100: -+ pwm = 100 -+ elif pwm < 0: -+ pwm = 0 -+ return int(pwm) -+ -+ def get_rotor_speed_tolerance(self, rotor_name): -+ """ -+ Retrieves the speed tolerance of the fan -+ Returns: -+ An integer, the percentage of variance from target speed which is -+ considered tolerable -+ """ -+ # The default tolerance value is fixed as 30% -+ fan_dir = {} -+ fan_dir = self.int_case.get_fan_info_rotor(self.name) -+ # get fan rotor tolerance -+ tolerance = fan_dir[rotor_name]["Tolerance"] -+ -+ if isinstance(tolerance, str) or tolerance is None: -+ return 30 -+ return tolerance -+ -+ 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) -+ """ -+ pwm = self.int_case.get_fan_speed_pwm(self.name, 0) -+ return int(pwm) -+ -+ def get_status(self): -+ """ -+ Retrieves the operational status of the FAN -+ Returns: -+ bool: True if FAN is operating properly, False if not -+ """ -+ if not self.get_presence(): -+ return False -+ -+ rotor_num = self.int_case.get_fan_rotor_number(self.name) -+ for i in range(rotor_num): -+ rotor_name = "Rotor" + str(i + 1) -+ speed = self.get_rotor_speed(rotor_name) -+ tolerance = self.get_rotor_speed_tolerance(rotor_name) -+ target = self.get_target_speed() -+ if (speed - target) > target * tolerance / 100: -+ return False -+ if (target - speed) > target * tolerance / 100: -+ return False -+ -+ return True -+ -+ def get_direction(self): -+ """ -+ Retrieves the fan airflow direction -+ Returns: -+ A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST -+ depending on fan direction -+ -+ Notes: -+ - Forward/Exhaust : Air flows from Port side to Fan side. -+ - Reverse/Intake : Air flows from Fan side to Port side. -+ """ -+ self.fan_dict_update() -+ return self.fan_dict["AirFlow"] -+ -+ -+class MonitorFan(object): -+ -+ def __init__(self): -+ self.int_case = interface() -+ self.logger = _init_logger() -+ self.fan_obj_list = [] -+ self.__config = baseutil.get_monitor_config() -+ self.__monitor_fan_config = self.__config.get("monitor_fan_para", {}) -+ self.__present_interval = self.__monitor_fan_config.get("present_interval", 0.5) -+ self.__status_interval = self.__monitor_fan_config.get("status_interval", 5) -+ self.__present_check_cnt = self.__monitor_fan_config.get("present_check_cnt", 3) -+ self.__status_check_cnt = self.__monitor_fan_config.get("status_check_cnt", 3) -+ -+ def debug_init(self): -+ if os.path.exists(DEBUG_FILE): -+ self.logger.setLevel(logging.DEBUG) -+ else: -+ self.logger.setLevel(logging.INFO) -+ -+ def get_fan_total_number(self): -+ return self.int_case.get_fan_total_number() -+ -+ def get_device_airflow(self): -+ return self.int_case.get_device_airflow(E2_NAME) -+ -+ def fan_obj_init(self): -+ fan_num = self.get_fan_total_number() -+ for i in range(fan_num): -+ fan_name = "FAN" + str(i + 1) -+ fan_obj = Fan(fan_name, self.int_case) -+ self.fan_obj_list.append(fan_obj) -+ self.logger.info("fan object initialize success") -+ -+ def fan_airflow_check(self, fan_obj): -+ fan_airflow = fan_obj.get_direction() -+ device_airflow = self.get_device_airflow() -+ if fan_airflow != device_airflow: -+ self.logger.error("%s airflow[%s] not match device airflow[%s]", fan_obj.name, fan_airflow, device_airflow) -+ else: -+ self.logger.debug("%s airflow[%s] match device airflow[%s]", fan_obj.name, fan_airflow, device_airflow) -+ -+ def fan_plug_in_out_check(self, fan_obj): -+ present = fan_obj.get_presence() -+ if present is True: -+ self.logger.debug("%s is present", fan_obj.name) -+ else: -+ self.logger.debug("%s is absent", fan_obj.name) -+ -+ if present != fan_obj.pre_present: -+ if present is True: -+ fan_obj.plugin_cnt += 1 -+ fan_obj.plugout_cnt = 0 -+ if fan_obj.plugin_cnt >= self.__present_check_cnt: -+ fan_obj.pre_present = True -+ self.logger.info("%s [serial:%s] is plugin", fan_obj.name, fan_obj.get_serial()) -+ self.fan_airflow_check(fan_obj) -+ else: -+ fan_obj.plugin_cnt = 0 -+ fan_obj.plugout_cnt += 1 -+ if fan_obj.plugout_cnt >= self.__present_check_cnt: -+ fan_obj.pre_present = False -+ self.logger.info("%s is plugout", fan_obj.name) -+ else: -+ fan_obj.plugin_cnt = 0 -+ fan_obj.plugout_cnt = 0 -+ self.logger.debug("%s present status is not change", fan_obj.name) -+ -+ def fan_status_check(self, fan_obj): -+ status = fan_obj.get_status() -+ if status is True: -+ self.logger.debug("%s is normal", fan_obj.name) -+ else: -+ self.logger.debug("%s is error", fan_obj.name) -+ -+ if status != fan_obj.pre_status: -+ if status is True: -+ fan_obj.status_normal_cnt += 1 -+ fan_obj.status_error_cnt = 0 -+ if fan_obj.status_normal_cnt >= self.__status_check_cnt: -+ fan_obj.pre_status = True -+ self.logger.info( -+ "%s [serial:%s] is form error change to normal", -+ fan_obj.name, -+ fan_obj.get_serial()) -+ else: -+ fan_obj.status_normal_cnt = 0 -+ fan_obj.status_error_cnt += 1 -+ if fan_obj.status_error_cnt >= self.__status_check_cnt: -+ fan_obj.pre_status = False -+ self.logger.info( -+ "%s [serial:%s] is form normal change to error", -+ fan_obj.name, -+ fan_obj.get_serial()) -+ else: -+ fan_obj.status_normal_cnt = 0 -+ fan_obj.status_error_cnt = 0 -+ self.logger.debug("%s status is not change", fan_obj.name) -+ -+ def checkFanPresence(self): -+ for fan_obj in self.fan_obj_list: -+ self.fan_plug_in_out_check(fan_obj) -+ -+ def checkFanStatus(self): -+ for fan_obj in self.fan_obj_list: -+ self.fan_status_check(fan_obj) -+ -+ def run(self): -+ start_time = time.time() -+ while True: -+ try: -+ self.debug_init() -+ delta_time = time.time() - start_time -+ if self.__present_interval <= self.__status_interval: -+ if delta_time >= self.__status_interval or delta_time < 0: -+ self.checkFanStatus() -+ start_time = time.time() -+ else: -+ self.checkFanPresence() -+ time.sleep(self.__present_interval) -+ else: -+ if delta_time >= self.__present_interval or delta_time < 0: -+ self.checkFanPresence() -+ start_time = time.time() -+ else: -+ self.checkFanStatus() -+ time.sleep(self.__status_interval) -+ except Exception as e: -+ self.logger.error('EXCEPTION: %s.', str(e)) -+ -+ -+if __name__ == '__main__': -+ monitor_fan = MonitorFan() -+ monitor_fan.fan_obj_init() -+ monitor_fan.run() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_common.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_common.py -new file mode 100755 -index 000000000..35c16728f ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_common.py -@@ -0,0 +1,186 @@ -+#!/usr/bin/python3 -+ -+__all__ = [ -+ "BLACKLIST_DRIVERS", -+ "DRIVERLISTS", -+ "DEVICE", -+ "STARTMODULE", -+ "MAC_LED_RESET", -+ "MAC_DEFAULT_PARAM", -+ "DEV_MONITOR_PARAM", -+ "SLOT_MONITOR_PARAM", -+ "MANUINFO_CONF", -+ "REBOOT_CTRL_PARAM", -+ "PMON_SYSLOG_STATUS", -+ "OPTOE", -+ "REBOOT_CAUSE_PARA", -+ "UPGRADE_SUMMARY", -+ "WARM_UPGRADE_PARAM", -+ "WARM_UPG_FLAG", -+ "WARM_UPGRADE_STARTED_FLAG", -+ "PLATFORM_E2_CONF", -+ "AIR_FLOW_CONF", -+ "AIRFLOW_RESULT_FILE", -+ "INIT_PARAM_PRE", -+ "INIT_COMMAND_PRE", -+ "INIT_PARAM", -+ "INIT_COMMAND", -+ "SET_MAC_CONF", -+ "DRVIER_UPDATE_CONF", -+ "MONITOR_TEMP_MIN", -+ "MONITOR_K", -+ "MONITOR_MAC_IN", -+ "MONITOR_DEFAULT_SPEED", -+ "MONITOR_MAX_SPEED", -+ "MONITOR_MIN_SPEED", -+ "MONITOR_MAC_ERROR_SPEED", -+ "MONITOR_FAN_TOTAL_NUM", -+ "MONITOR_MAC_UP_TEMP", -+ "MONITOR_MAC_LOWER_TEMP", -+ "MONITOR_MAC_MAX_TEMP", -+ "MONITOR_FALL_TEMP", -+ "MONITOR_MAC_WARNING_THRESHOLD", -+ "MONITOR_OUTTEMP_WARNING_THRESHOLD", -+ "MONITOR_BOARDTEMP_WARNING_THRESHOLD", -+ "MONITOR_CPUTEMP_WARNING_THRESHOLD", -+ "MONITOR_INTEMP_WARNING_THRESHOLD", -+ "MONITOR_MAC_CRITICAL_THRESHOLD", -+ "MONITOR_OUTTEMP_CRITICAL_THRESHOLD", -+ "MONITOR_BOARDTEMP_CRITICAL_THRESHOLD", -+ "MONITOR_CPUTEMP_CRITICAL_THRESHOLD", -+ "MONITOR_INTEMP_CRITICAL_THRESHOLD", -+ "MONITOR_CRITICAL_NUM", -+ "MONITOR_SHAKE_TIME", -+ "MONITOR_INTERVAL", -+ "MONITOR_LED_INTERVAL", -+ "MONITOR_PID_FLAG", -+ "MONITOR_MAC_SOURCE_SYSFS", -+ "MONITOR_MAC_SOURCE_PATH", -+ "MONITOR_PID_MODULE", -+ "PSU_FAN_FOLLOW", -+ "MONITOR_SYS_LED", -+ "MONITOR_SYS_FAN_LED", -+ "MONITOR_FANS_LED", -+ "MONITOR_SYS_PSU_LED", -+ "MONITOR_FAN_STATUS", -+ "MONITOR_PSU_STATUS", -+ "MONITOR_DEV_STATUS", -+ "MONITOR_DEV_STATUS_DECODE", -+ "DEV_LEDS", -+ "fanloc" -+] -+ -+# driver blacklist parameter -+BLACKLIST_DRIVERS = [] -+ -+# driver list parameter -+DRIVERLISTS = [] -+ -+# device list parameter -+DEVICE = [] -+ -+# start module parameters -+STARTMODULE = {} -+ -+# mac led reset parameter -+MAC_LED_RESET = {} -+ -+# avscontrol parameter -+MAC_DEFAULT_PARAM = [] -+ -+# dev_monitor parameter -+DEV_MONITOR_PARAM = {} -+ -+# slot_monitor parameter -+SLOT_MONITOR_PARAM = {} -+ -+# platform_manufacturer parameter -+MANUINFO_CONF = {} -+ -+# reboot_ctrl parameter -+REBOOT_CTRL_PARAM = {} -+ -+# pmon_syslog parameter -+PMON_SYSLOG_STATUS = {} -+ -+# sfp optoe device parameter -+OPTOE = [] -+ -+# reboot_cause parameter -+REBOOT_CAUSE_PARA = [] -+ -+# upgrade parameter -+UPGRADE_SUMMARY = {} -+ -+# warm_uprade parameter -+WARM_UPGRADE_PARAM = {} -+WARM_UPG_FLAG = "/etc/sonic/.warm_upg_flag" -+WARM_UPGRADE_STARTED_FLAG = "/etc/sonic/.doing_warm_upg" -+ -+# platform_e2 parameter -+PLATFORM_E2_CONF = {} -+ -+# generate_airflow parameter -+AIR_FLOW_CONF = {} -+AIRFLOW_RESULT_FILE = "/etc/sonic/.airflow" -+ -+# Initialization parameters -+INIT_PARAM_PRE = [] -+INIT_COMMAND_PRE = [] -+INIT_PARAM = [] -+INIT_COMMAND = [] -+ -+# Set eth mac address parameters -+SET_MAC_CONF = [] -+ -+# driver update config -+DRVIER_UPDATE_CONF = {} -+ -+################################ fancontrol parameter################################### -+MONITOR_TEMP_MIN = 38 -+MONITOR_K = 11 -+MONITOR_MAC_IN = 35 -+MONITOR_DEFAULT_SPEED = 0x60 -+MONITOR_MAX_SPEED = 0xFF -+MONITOR_MIN_SPEED = 0x60 -+MONITOR_MAC_ERROR_SPEED = 0XBB -+MONITOR_FAN_TOTAL_NUM = 4 -+MONITOR_MAC_UP_TEMP = 50 -+MONITOR_MAC_LOWER_TEMP = -50 -+MONITOR_MAC_MAX_TEMP = 100 # -+ -+MONITOR_FALL_TEMP = 4 -+MONITOR_MAC_WARNING_THRESHOLD = 100 -+MONITOR_OUTTEMP_WARNING_THRESHOLD = 85 -+MONITOR_BOARDTEMP_WARNING_THRESHOLD = 85 -+MONITOR_CPUTEMP_WARNING_THRESHOLD = 85 -+MONITOR_INTEMP_WARNING_THRESHOLD = 70 -+ -+MONITOR_MAC_CRITICAL_THRESHOLD = 105 -+MONITOR_OUTTEMP_CRITICAL_THRESHOLD = 90 -+MONITOR_BOARDTEMP_CRITICAL_THRESHOLD = 90 -+MONITOR_CPUTEMP_CRITICAL_THRESHOLD = 100 -+MONITOR_INTEMP_CRITICAL_THRESHOLD = 80 -+MONITOR_CRITICAL_NUM = 3 -+MONITOR_SHAKE_TIME = 20 -+MONITOR_INTERVAL = 60 -+MONITOR_LED_INTERVAL = 2 -+MONITOR_PID_FLAG = 0 -+ -+MONITOR_MAC_SOURCE_SYSFS = 0 -+MONITOR_MAC_SOURCE_PATH = None -+ -+MONITOR_PID_MODULE = {} -+ -+PSU_FAN_FOLLOW = {} -+ -+MONITOR_SYS_LED = [] -+MONITOR_SYS_FAN_LED = [] -+MONITOR_FANS_LED = [] -+MONITOR_SYS_PSU_LED = [] -+MONITOR_FAN_STATUS = [] -+MONITOR_PSU_STATUS = [] -+MONITOR_DEV_STATUS = {} -+MONITOR_DEV_STATUS_DECODE = {} -+DEV_LEDS = {} -+fanloc = [] -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_config.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_config.py -new file mode 100755 -index 000000000..d6b3151e4 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_config.py -@@ -0,0 +1,192 @@ -+#!/usr/bin/python3 -+ -+import sys -+import os -+from wbutil.baseutil import get_machine_info -+from wbutil.baseutil import get_platform_info -+from wbutil.baseutil import get_board_id -+ -+__all__ = [ -+ "MAILBOX_DIR", -+ "PLATFORM_GLOBALCONFIG", -+ "GLOBALCONFIG", -+ "STARTMODULE", -+ "MAC_LED_RESET", -+ "MAC_DEFAULT_PARAM", -+ "DEV_MONITOR_PARAM", -+ "SLOT_MONITOR_PARAM", -+ "MANUINFO_CONF", -+ "REBOOT_CTRL_PARAM", -+ "PMON_SYSLOG_STATUS", -+ "REBOOT_CAUSE_PARA", -+ "UPGRADE_SUMMARY", -+ "WARM_UPGRADE_PARAM", -+ "WARM_UPG_FLAG", -+ "WARM_UPGRADE_STARTED_FLAG", -+ "PLATFORM_E2_CONF", -+ "AIR_FLOW_CONF", -+ "AIRFLOW_RESULT_FILE", -+ "GLOBALINITPARAM", -+ "GLOBALINITCOMMAND", -+ "GLOBALINITPARAM_PRE", -+ "GLOBALINITCOMMAND_PRE", -+ "SET_MAC_CONF", -+ "DRVIER_UPDATE_CONF", -+ "MONITOR_CONST", -+ "PSU_FAN_FOLLOW", -+ "MONITOR_SYS_LED", -+ "MONITOR_FANS_LED", -+ "MONITOR_SYS_FAN_LED", -+ "MONITOR_SYS_PSU_LED", -+ "MONITOR_FAN_STATUS", -+ "MONITOR_PSU_STATUS", -+ "MONITOR_DEV_STATUS", -+ "MONITOR_DEV_STATUS_DECODE", -+ "DEV_LEDS", -+ "fanloc" -+] -+ -+ -+def getdeviceplatform(): -+ x = get_platform_info(get_machine_info()) -+ if x is not None: -+ filepath = "/usr/share/sonic/device/" + x -+ return filepath -+ return None -+ -+ -+platform = get_platform_info(get_machine_info()) -+board_id = get_board_id(get_machine_info()) -+platformpath = getdeviceplatform() -+MAILBOX_DIR = "/sys/bus/i2c/devices/" -+grtd_productfile = (platform + "_config").replace("-", "_") -+common_productfile = "platform_common" -+platform_configfile = (platform + "_" + board_id + "_config").replace("-", "_") # platfrom + board_id -+configfile_pre = "/usr/local/bin/" -+sys.path.append(platformpath) -+sys.path.append(configfile_pre) -+ -+############################################################################################ -+if os.path.exists(configfile_pre + platform_configfile + ".py"): -+ module_product = __import__(platform_configfile, globals(), locals(), [], 0) -+elif os.path.exists(configfile_pre + grtd_productfile + ".py"): -+ module_product = __import__(grtd_productfile, globals(), locals(), [], 0) -+elif os.path.exists(configfile_pre + common_productfile + ".py"): -+ module_product = __import__(common_productfile, globals(), locals(), [], 0) -+else: -+ print("config file not exist") -+ sys.exit(-1) -+############################################################################################ -+ -+PLATFORM_GLOBALCONFIG = { -+ "DRIVERLISTS": module_product.DRIVERLISTS, -+ "OPTOE": module_product.OPTOE, -+ "DEVS": module_product.DEVICE, -+ "BLACKLIST_DRIVERS": module_product.BLACKLIST_DRIVERS -+} -+GLOBALCONFIG = PLATFORM_GLOBALCONFIG -+ -+# start module parameters -+STARTMODULE = module_product.STARTMODULE -+ -+# mac led reset parameter -+MAC_LED_RESET = module_product.MAC_LED_RESET -+ -+# avscontrol parameter -+MAC_DEFAULT_PARAM = module_product.MAC_DEFAULT_PARAM -+ -+# dev_monitor parameter -+DEV_MONITOR_PARAM = module_product.DEV_MONITOR_PARAM -+ -+# slot_monitor parameter -+SLOT_MONITOR_PARAM = module_product.SLOT_MONITOR_PARAM -+ -+# platform_manufacturer parameter -+MANUINFO_CONF = module_product.MANUINFO_CONF -+ -+# reboot_ctrl parameter -+REBOOT_CTRL_PARAM = module_product.REBOOT_CTRL_PARAM -+ -+# pmon_syslog parameter -+PMON_SYSLOG_STATUS = module_product.PMON_SYSLOG_STATUS -+ -+# reboot_cause parameter -+REBOOT_CAUSE_PARA = module_product.REBOOT_CAUSE_PARA -+ -+# upgrade parameter -+UPGRADE_SUMMARY = module_product.UPGRADE_SUMMARY -+ -+# warm_uprade parameter -+WARM_UPGRADE_PARAM = module_product.WARM_UPGRADE_PARAM -+WARM_UPG_FLAG = module_product.WARM_UPG_FLAG -+WARM_UPGRADE_STARTED_FLAG = module_product.WARM_UPGRADE_STARTED_FLAG -+ -+# platform_e2 parameter -+PLATFORM_E2_CONF = module_product.PLATFORM_E2_CONF -+ -+# generate_airflow parameter -+AIR_FLOW_CONF = module_product.AIR_FLOW_CONF -+AIRFLOW_RESULT_FILE = module_product.AIRFLOW_RESULT_FILE -+ -+# Initialization parameters -+GLOBALINITPARAM = module_product.INIT_PARAM -+GLOBALINITCOMMAND = module_product.INIT_COMMAND -+GLOBALINITPARAM_PRE = module_product.INIT_PARAM_PRE -+GLOBALINITCOMMAND_PRE = module_product.INIT_COMMAND_PRE -+ -+# Set eth mac address parameters -+SET_MAC_CONF = module_product.SET_MAC_CONF -+ -+# driver update config -+DRVIER_UPDATE_CONF = module_product.DRVIER_UPDATE_CONF -+ -+################################ fancontrol parameter################################### -+ -+ -+class MONITOR_CONST: -+ TEMP_MIN = module_product.MONITOR_TEMP_MIN -+ K = module_product.MONITOR_K -+ MAC_IN = module_product.MONITOR_MAC_IN -+ DEFAULT_SPEED = module_product.MONITOR_DEFAULT_SPEED -+ MAX_SPEED = module_product.MONITOR_MAX_SPEED -+ MIN_SPEED = module_product.MONITOR_MIN_SPEED -+ MAC_ERROR_SPEED = module_product.MONITOR_MAC_ERROR_SPEED -+ FAN_TOTAL_NUM = module_product.MONITOR_FAN_TOTAL_NUM -+ MAC_UP_TEMP = module_product.MONITOR_MAC_UP_TEMP -+ MAC_LOWER_TEMP = module_product.MONITOR_MAC_LOWER_TEMP -+ MAC_MAX_TEMP = module_product.MONITOR_MAC_MAX_TEMP -+ -+ MAC_WARNING_THRESHOLD = module_product.MONITOR_MAC_WARNING_THRESHOLD -+ OUTTEMP_WARNING_THRESHOLD = module_product.MONITOR_OUTTEMP_WARNING_THRESHOLD -+ BOARDTEMP_WARNING_THRESHOLD = module_product.MONITOR_BOARDTEMP_WARNING_THRESHOLD -+ CPUTEMP_WARNING_THRESHOLD = module_product.MONITOR_CPUTEMP_WARNING_THRESHOLD -+ INTEMP_WARNING_THRESHOLD = module_product.MONITOR_INTEMP_WARNING_THRESHOLD -+ -+ MAC_CRITICAL_THRESHOLD = module_product.MONITOR_MAC_CRITICAL_THRESHOLD -+ OUTTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_OUTTEMP_CRITICAL_THRESHOLD -+ BOARDTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_BOARDTEMP_CRITICAL_THRESHOLD -+ CPUTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_CPUTEMP_CRITICAL_THRESHOLD -+ INTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_INTEMP_CRITICAL_THRESHOLD -+ CRITICAL_NUM = module_product.MONITOR_CRITICAL_NUM -+ SHAKE_TIME = module_product.MONITOR_SHAKE_TIME -+ MONITOR_INTERVAL = module_product.MONITOR_INTERVAL -+ MONITOR_LED_INTERVAL = module_product.MONITOR_LED_INTERVAL -+ MONITOR_FALL_TEMP = module_product.MONITOR_FALL_TEMP -+ MONITOR_PID_FLAG = module_product.MONITOR_PID_FLAG -+ MONITOR_PID_MODULE = module_product.MONITOR_PID_MODULE -+ -+ MONITOR_MAC_SOURCE_SYSFS = module_product.MONITOR_MAC_SOURCE_SYSFS -+ MONITOR_MAC_SOURCE_PATH = module_product.MONITOR_MAC_SOURCE_PATH -+ -+ -+PSU_FAN_FOLLOW = module_product.PSU_FAN_FOLLOW -+MONITOR_SYS_LED = module_product.MONITOR_SYS_LED -+MONITOR_FANS_LED = module_product.MONITOR_FANS_LED -+MONITOR_SYS_FAN_LED = module_product.MONITOR_SYS_FAN_LED -+MONITOR_SYS_PSU_LED = module_product.MONITOR_SYS_PSU_LED -+MONITOR_FAN_STATUS = module_product.MONITOR_FAN_STATUS -+MONITOR_PSU_STATUS = module_product.MONITOR_PSU_STATUS -+MONITOR_DEV_STATUS = module_product.MONITOR_DEV_STATUS -+MONITOR_DEV_STATUS_DECODE = module_product.MONITOR_DEV_STATUS_DECODE -+DEV_LEDS = module_product.DEV_LEDS -+fanloc = module_product.fanloc -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_driver.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_driver.py -new file mode 100755 -index 000000000..6d2c6de65 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_driver.py -@@ -0,0 +1,258 @@ -+#!/usr/bin/env python3 -+import os -+import subprocess -+import time -+import click -+from platform_config import GLOBALCONFIG, WARM_UPGRADE_STARTED_FLAG, WARM_UPG_FLAG -+ -+ -+CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} -+ -+ -+class AliasedGroup(click.Group): -+ def get_command(self, ctx, cmd_name): -+ rv = click.Group.get_command(self, ctx, cmd_name) -+ if rv is not None: -+ return rv -+ matches = [x for x in self.list_commands(ctx) -+ if x.startswith(cmd_name)] -+ if not matches: -+ return None -+ if len(matches) == 1: -+ return click.Group.get_command(self, ctx, matches[0]) -+ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) -+ return None -+ -+ -+def log_os_system(cmd): -+ status, output = subprocess.getstatusoutput(cmd) -+ if status: -+ print(output) -+ return status, output -+ -+ -+def platform_process_file_check(): -+ # WARM_UPGRADE_STARTED_FLAG is used as warm_upgrade.py process start flag -+ if os.path.exists(WARM_UPGRADE_STARTED_FLAG): -+ os.remove(WARM_UPGRADE_STARTED_FLAG) -+ -+ # WARM_UPG_FLAG is used as port related service judgment flag -+ if os.path.exists(WARM_UPG_FLAG): -+ os.remove(WARM_UPG_FLAG) -+ -+ -+def startCommon_operation(): -+ platform_process_file_check() -+ -+ -+def check_driver(): -+ status, output = log_os_system("lsmod | grep wb | wc -l") -+ if status: -+ return False -+ if output.isdigit() and int(output) > 0: -+ return True -+ return False -+ -+ -+def removeDev(bus, loc): -+ cmd = "echo 0x%02x > /sys/bus/i2c/devices/i2c-%d/delete_device" % (loc, bus) -+ devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) -+ if os.path.exists(devpath): -+ log_os_system(cmd) -+ -+ -+def addDev(name, bus, loc): -+ if name == "lm75": -+ time.sleep(0.1) -+ pdevpath = "/sys/bus/i2c/devices/i2c-%d/" % (bus) -+ for i in range(1, 100): -+ if os.path.exists(pdevpath) is True: -+ break -+ time.sleep(0.1) -+ if i % 10 == 0: -+ click.echo("%%WB_PLATFORM_DRIVER-INIT: %s not found, wait 0.1 second ! i %d " % (pdevpath, i)) -+ -+ cmd = "echo %s 0x%02x > /sys/bus/i2c/devices/i2c-%d/new_device" % (name, loc, bus) -+ devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) -+ if os.path.exists(devpath) is False: -+ os.system(cmd) -+ -+ -+def removeOPTOE(startbus, endbus): -+ for bus in range(endbus, startbus - 1, -1): -+ removeDev(bus, 0x50) -+ -+ -+def addOPTOE(name, startbus, endbus): -+ for bus in range(startbus, endbus + 1): -+ addDev(name, bus, 0x50) -+ -+ -+def removeoptoes(): -+ optoes = GLOBALCONFIG["OPTOE"] -+ for index in range(len(optoes) - 1, -1, -1): -+ removeOPTOE(optoes[index]["startbus"], optoes[index]["endbus"]) -+ -+ -+def addoptoes(): -+ optoes = GLOBALCONFIG["OPTOE"] -+ for optoe in optoes: -+ addOPTOE(optoe["name"], optoe["startbus"], optoe["endbus"]) -+ -+ -+def removedevs(): -+ devs = GLOBALCONFIG["DEVS"] -+ for index in range(len(devs) - 1, -1, -1): -+ removeDev(devs[index]["bus"], devs[index]["loc"]) -+ -+ -+def adddevs(): -+ devs = GLOBALCONFIG["DEVS"] -+ for dev in devs: -+ addDev(dev["name"], dev["bus"], dev["loc"]) -+ -+ -+def checksignaldriver(name): -+ modisexistcmd = "lsmod | grep -w %s | wc -l" % name -+ status, output = log_os_system(modisexistcmd) -+ if status: -+ return False -+ if output.isdigit() and int(output) > 0: -+ return True -+ return False -+ -+ -+def adddriver(name, delay): -+ cmd = "modprobe %s" % name -+ if delay != 0: -+ time.sleep(delay) -+ if checksignaldriver(name) is not True: -+ log_os_system(cmd) -+ -+ -+def removedriver(name, delay, removeable=1): -+ realname = name.lstrip().split(" ")[0] -+ cmd = "rmmod -f %s" % realname -+ if checksignaldriver(realname) and removeable: -+ log_os_system(cmd) -+ if delay > 0: -+ time.sleep(delay) -+ -+ -+def removedrivers(): -+ if GLOBALCONFIG is None: -+ click.echo("%%WB_PLATFORM_DRIVER-INIT: load global config failed.") -+ return -+ drivers = GLOBALCONFIG.get("DRIVERLISTS", None) -+ if drivers is None: -+ click.echo("%%WB_PLATFORM_DRIVER-INIT: load driver list failed.") -+ return -+ for index in range(len(drivers) - 1, -1, -1): -+ delay = 0 -+ name = "" -+ removeable = drivers[index].get("removable", 1) -+ if isinstance(drivers[index], dict) and "delay" in drivers[index]: -+ name = drivers[index].get("name") -+ delay = drivers[index]["delay"] -+ else: -+ name = drivers[index] -+ removedriver(name, delay, removeable) -+ -+ -+def adddrivers(): -+ if GLOBALCONFIG is None: -+ click.echo("%%WB_PLATFORM_DRIVER-INIT: load global config failed.") -+ return -+ drivers = GLOBALCONFIG.get("DRIVERLISTS", None) -+ if drivers is None: -+ click.echo("%%WB_PLATFORM_DRIVER-INIT: load driver list failed.") -+ return -+ for driver in drivers: -+ delay = 0 -+ name = "" -+ if isinstance(driver, dict) and "delay" in driver: -+ name = driver.get("name") -+ delay = driver["delay"] -+ else: -+ name = driver -+ adddriver(name, delay) -+ -+ -+def blacklist_driver_remove(): -+ if GLOBALCONFIG is None: -+ click.echo("%%WB_PLATFORM_DRIVER-INIT: load global config failed.") -+ return -+ blacklist_drivers = GLOBALCONFIG.get("BLACKLIST_DRIVERS", []) -+ for driver in blacklist_drivers: -+ delay = 0 -+ name = "" -+ if isinstance(driver, dict) and "delay" in driver: -+ name = driver.get("name") -+ delay = driver["delay"] -+ else: -+ name = driver -+ removedriver(name, delay) -+ -+ -+def unload_driver(): -+ removeoptoes() -+ removedevs() -+ removedrivers() -+ -+ -+def reload_driver(): -+ removedevs() -+ removedrivers() -+ time.sleep(1) -+ adddrivers() -+ adddevs() -+ -+ -+def i2c_check(bus, retrytime=6): -+ try: -+ i2cpath = "/sys/bus/i2c/devices/" + bus -+ while retrytime and not os.path.exists(i2cpath): -+ click.echo("%%WB_PLATFORM_DRIVER-HA: i2c bus abnormal, last bus %s is not exist." % i2cpath) -+ reload_driver() -+ retrytime -= 1 -+ time.sleep(1) -+ except Exception as e: -+ click.echo("%%WB_PLATFORM_DRIVER-HA: %s" % str(e)) -+ -+ -+def load_driver(): -+ startCommon_operation() -+ adddrivers() -+ adddevs() -+ addoptoes() -+ -+ -+@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) -+def main(): -+ '''device operator''' -+ -+ -+@main.command() -+def start(): -+ '''load drivers and device ''' -+ blacklist_driver_remove() -+ if check_driver(): -+ unload_driver() -+ load_driver() -+ -+ -+@main.command() -+def stop(): -+ '''stop drivers device ''' -+ unload_driver() -+ -+ -+@main.command() -+def restart(): -+ '''restart drivers and device''' -+ unload_driver() -+ load_driver() -+ -+ -+if __name__ == '__main__': -+ main() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_e2.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_e2.py -new file mode 100755 -index 000000000..152dd16a2 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_e2.py -@@ -0,0 +1,439 @@ -+#!/usr/bin/env python3 -+# -*- coding: UTF-8 -*- -+import click -+ -+from eepromutil.fru import ipmifru -+from eepromutil.cust_fru import CustFru -+from eepromutil.fantlv import fan_tlv -+import eepromutil.onietlv as ot -+from platform_config import PLATFORM_E2_CONF -+from platform_util import byteTostr, dev_file_read -+ -+CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} -+ -+ -+class AliasedGroup(click.Group): -+ def get_command(self, ctx, cmd_name): -+ rv = click.Group.get_command(self, ctx, cmd_name) -+ if rv is not None: -+ return rv -+ matches = [x for x in self.list_commands(ctx) -+ if x.startswith(cmd_name)] -+ if not matches: -+ return None -+ if len(matches) == 1: -+ return click.Group.get_command(self, ctx, matches[0]) -+ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) -+ return None -+ -+ -+class ExtraFunc(object): -+ @staticmethod -+ def decode_mac(encodedata): -+ if encodedata is None: -+ return None -+ ret = ":".join("%02x" % ord(data) for data in encodedata) -+ return ret.upper() -+ -+ @staticmethod -+ def decode_mac_number(encodedata): -+ if encodedata is None: -+ return None -+ return (ord(encodedata[0]) << 8) | (ord(encodedata[1]) & 0x00ff) -+ -+ @staticmethod -+ @staticmethod -+ def fru_decode_mac_number(params): -+ ipmi_fru = params.get("fru") -+ area = params.get("area") -+ field = params.get("field") -+ area_info = getattr(ipmi_fru, area, None) -+ if area_info is not None: -+ raw_mac_number = getattr(area_info, field, None) -+ mac_number = decode_mac_number(raw_mac_number) -+ ipmi_fru.setValue(area, field, mac_number) -+ -+ @staticmethod -+ def fru_decode_mac(params): -+ ipmi_fru = params.get("fru") -+ area = params.get("area") -+ field = params.get("field") -+ area_info = getattr(ipmi_fru, area, None) -+ if area_info is not None: -+ raw_mac = getattr(area_info, field, None) -+ decoded_mac = decode_mac(raw_mac) -+ ipmi_fru.setValue(area, field, decoded_mac) -+ -+ @staticmethod -+ def fru_decode_hw(params): -+ ipmi_fru = params.get("fru") -+ area = params.get("area") -+ field = params.get("field") -+ area_info = getattr(ipmi_fru, area, None) -+ if area_info is not None: -+ raw_hw = getattr(area_info, field, None) -+ decode_hw = str(int(raw_hw, 16)) -+ ipmi_fru.setValue(area, field, decode_hw) -+ -+ -+def set_onie_value(params): -+ onie = params.get("onie") -+ field = params.get("field") -+ config_value = params.get("config_value") -+ for index, onie_item in enumerate(onie): -+ if onie_item.get("name") == field: -+ if "value" in onie_item.keys(): -+ onie[index]["value"] = config_value -+ -+ -+def onie_eeprom_decode(onie, e2_decode): -+ for e2_decode_item in e2_decode: -+ field = e2_decode_item.get("field") -+ decode_type = e2_decode_item.get("decode_type") -+ if decode_type == 'func': -+ params = { -+ "onie": onie, -+ "field": field -+ } -+ func_name = e2_decode_item.get("func_name") -+ if func_name is not None: -+ run_func(func_name, params) -+ elif decode_type == 'config': -+ config_value = e2_decode_item.get("config_value") -+ if config_value is not None: -+ params = { -+ "onie": onie, -+ "field": field, -+ "config_value": config_value -+ } -+ set_onie_value(params) -+ else: -+ print("unsupport decode type") -+ continue -+ -+ -+def onie_eeprom_show(eeprom, e2_decode=None): -+ try: -+ onietlv = ot.onie_tlv() -+ rets = onietlv.decode(eeprom) -+ if e2_decode is not None: -+ onie_eeprom_decode(rets, e2_decode) -+ print("%-20s %-5s %-5s %-20s" % ("TLV name", "Code", "lens", "Value")) -+ for item in rets: -+ if item["code"] == 0xfd: -+ print("%-20s 0x%-02X %-5s" % (item["name"], item["code"], item["lens"])) -+ else: -+ print("%-20s 0x%-02X %-5s %-20s" % (item["name"], item["code"], item["lens"], item["value"])) -+ except Exception as e: -+ print(str(e)) -+ -+ -+def set_fantlv_value(params): -+ fantlv_dict = params.get("fantlv") -+ field = params.get("field") -+ config_value = params.get("config_value") -+ for index, fantlv_item in enumerate(fantlv_dict): -+ if fantlv_item.get("name") == field: -+ if "value" in fantlv_item.keys(): -+ fantlv_dict[index]["value"] = config_value -+ -+ -+def fantlv_eeprom_decode(fantlv_dict, e2_decode): -+ for e2_decode_item in e2_decode: -+ field = e2_decode_item.get("field") -+ decode_type = e2_decode_item.get("decode_type") -+ if decode_type == 'func': -+ params = { -+ "fantlv": fantlv_dict, -+ "field": field -+ } -+ func_name = e2_decode_item.get("func_name") -+ if func_name is not None: -+ run_func(func_name, params) -+ elif decode_type == 'config': -+ config_value = e2_decode_item.get("config_value") -+ if config_value is not None: -+ params = { -+ "fantlv": fantlv_dict, -+ "field": field, -+ "config_value": config_value -+ } -+ set_fantlv_value(params) -+ else: -+ print("unsupport decode type") -+ continue -+ -+ -+def fantlv_eeprom_show(eeprom, e2_decode=None): -+ try: -+ tlv = fan_tlv() -+ rets = tlv.decode(eeprom) -+ if len(rets) == 0: -+ print("fan tlv eeprom info error.!") -+ return -+ if e2_decode is not None: -+ fantlv_eeprom_decode(rets, e2_decode) -+ print("%-15s %-5s %-5s %-20s" % ("TLV name", "Code", "lens", "Value")) -+ for item in rets: -+ print("%-15s 0x%-02X %-5s %-20s" % (item["name"], item["code"], item["lens"], item["value"])) -+ except Exception as e: -+ print(str(e)) -+ return -+ -+ -+def run_func(funcname, params): -+ try: -+ func = getattr(ExtraFunc, funcname) -+ func(params) -+ except Exception as e: -+ print(str(e)) -+ -+def set_fru_value(params): -+ ipmi_fru = params.get("fru") -+ area = params.get("area") -+ field = params.get("field") -+ config_value = params.get("config_value") -+ ipmi_fru.setValue(area, field, config_value) -+ -+ -+def fru_eeprom_decode(ipmi_fru, e2_decode): -+ for e2_decode_item in e2_decode: -+ area = e2_decode_item.get("area") -+ field = e2_decode_item.get("field") -+ decode_type = e2_decode_item.get("decode_type") -+ if decode_type == 'func': -+ params = { -+ "fru": ipmi_fru, -+ "area": area, -+ "field": field -+ } -+ func_name = e2_decode_item.get("func_name") -+ if func_name is not None: -+ run_func(func_name, params) -+ elif decode_type == 'config': -+ config_value = e2_decode_item.get("config_value") -+ if config_value is not None: -+ params = { -+ "fru": ipmi_fru, -+ "area": area, -+ "field": field, -+ "config_value": config_value -+ } -+ set_fru_value(params) -+ else: -+ print("unsupport decode type") -+ continue -+ -+ -+def fru_eeprom_show(eeprom, e2_decode=None): -+ try: -+ ipmi_fru = ipmifru() -+ ipmi_fru.decodeBin(eeprom) -+ if e2_decode is not None: -+ fru_eeprom_decode(ipmi_fru, e2_decode) -+ print("=================board=================") -+ print(ipmi_fru.boardInfoArea) -+ print("=================product=================") -+ print(ipmi_fru.productInfoArea) -+ except Exception as e: -+ print(str(e)) -+ -+ -+def custfru_eeprom_show(eeprom, e2_decode=None): -+ try: -+ custfru = CustFru() -+ custfru.decode(eeprom) -+ print(custfru) -+ except Exception as e: -+ print(str(e)) -+ -+ -+def eeprom_parase(eeprom_conf): -+ name = eeprom_conf.get("name") -+ e2_type = eeprom_conf.get("e2_type") -+ e2_path = eeprom_conf.get("e2_path") -+ e2_size = eeprom_conf.get("e2_size", 256) -+ e2_decode = eeprom_conf.get("e2_decode") -+ print("===================%s===================" % name) -+ ret, binval_bytes = dev_file_read(e2_path, 0, e2_size) -+ if ret is False: -+ print("eeprom read error, eeprom path: %s, msg: %s" % (e2_path, binval_bytes)) -+ return -+ binval = byteTostr(binval_bytes) -+ if e2_type == "onie_tlv": -+ onie_eeprom_show(binval, e2_decode) -+ elif e2_type == "fru": -+ fru_eeprom_show(binval, e2_decode) -+ elif e2_type == "fantlv": -+ fantlv_eeprom_show(binval, e2_decode) -+ elif e2_type == "custfru": -+ custfru_eeprom_show(binval, e2_decode) -+ else: -+ print("Unknow eeprom type: %s" % e2_type) -+ return -+ -+ -+def get_fans_eeprom_info(param): -+ fan_eeprom_conf = PLATFORM_E2_CONF.get("fan", []) -+ fan_num = len(fan_eeprom_conf) -+ if fan_num == 0: -+ print("fan number is 0, can't get fan eeprom info") -+ return -+ if param == 'all': -+ for conf in fan_eeprom_conf: -+ eeprom_parase(conf) -+ return -+ if not param.isdigit(): -+ print("param error, %s is not digital or 'all'" % param) -+ return -+ fan_index = int(param, 10) - 1 -+ if fan_index < 0 or fan_index >= fan_num: -+ print("param error, total fan number: %d, fan index: %d" % (fan_num, fan_index + 1)) -+ return -+ eeprom_parase(fan_eeprom_conf[fan_index]) -+ return -+ -+ -+def get_psus_eeprom_info(param): -+ psu_eeprom_conf = PLATFORM_E2_CONF.get("psu", []) -+ psu_num = len(psu_eeprom_conf) -+ if psu_num == 0: -+ print("psu number is 0, can't get psu eeprom info") -+ return -+ if param == 'all': -+ for conf in psu_eeprom_conf: -+ eeprom_parase(conf) -+ return -+ if not param.isdigit(): -+ print("param error, %s is not digital or 'all'" % param) -+ return -+ psu_index = int(param, 10) - 1 -+ if psu_index < 0 or psu_index >= psu_num: -+ print("param error, total psu number: %d, psu index: %d" % (psu_num, psu_index + 1)) -+ return -+ eeprom_parase(psu_eeprom_conf[psu_index]) -+ return -+ -+ -+def get_slots_eeprom_info(param): -+ slot_eeprom_conf = PLATFORM_E2_CONF.get("slot", []) -+ slot_num = len(slot_eeprom_conf) -+ if slot_num == 0: -+ print("slot number is 0, can't get slot eeprom info") -+ return -+ if param == 'all': -+ for conf in slot_eeprom_conf: -+ eeprom_parase(conf) -+ return -+ if not param.isdigit(): -+ print("param error, %s is not digital or 'all'" % param) -+ return -+ slot_index = int(param, 10) - 1 -+ if slot_index < 0 or slot_index >= slot_num: -+ print("param error, total slot number: %d, slot index: %d" % (slot_num, slot_index + 1)) -+ return -+ eeprom_parase(slot_eeprom_conf[slot_index]) -+ return -+ -+ -+def get_syseeprom_info(param): -+ syseeprom_conf = PLATFORM_E2_CONF.get("syseeprom", []) -+ syseeprom_num = len(syseeprom_conf) -+ if syseeprom_num == 0: -+ print("syseeprom number is 0, can't get syseeprom info") -+ return -+ if param == 'all': -+ for conf in syseeprom_conf: -+ eeprom_parase(conf) -+ return -+ if not param.isdigit(): -+ print("param error, %s is not digital or 'all'" % param) -+ return -+ syseeprom_index = int(param, 10) - 1 -+ if syseeprom_index < 0 or syseeprom_index >= syseeprom_num: -+ print("param error, total syseeprom number: %d, syseeprom index: %d" % (syseeprom_num, syseeprom_index + 1)) -+ return -+ eeprom_parase(syseeprom_conf[syseeprom_index]) -+ return -+ -+ -+def decode_eeprom_info(e2_type, e2_path, e2_size): -+ if not e2_size.isdigit(): -+ print("param error, e2_size %s is not digital" % e2_size) -+ return -+ e2_size = int(e2_size, 10) -+ eeprom_conf = {} -+ eeprom_conf["name"] = e2_type -+ eeprom_conf["e2_type"] = e2_type -+ eeprom_conf["e2_path"] = e2_path -+ eeprom_conf["e2_size"] = e2_size -+ eeprom_parase(eeprom_conf) -+ return -+ -+ -+@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) -+def main(): -+ '''platform eeprom display script''' -+ -+ -+# fan eeprom info display -+@main.command() -+@click.argument('fan_index', required=True) -+def fan(fan_index): -+ '''fan_index(1, 2, 3...)/all''' -+ get_fans_eeprom_info(fan_index) -+ -+ -+# psu eeprom info display -+@main.command() -+@click.argument('psu_index', required=True) -+def psu(psu_index): -+ '''psu_index(1, 2, 3...)/all''' -+ get_psus_eeprom_info(psu_index) -+ -+ -+# slot eeprom info display -+@main.command() -+@click.argument('slot_index', required=True) -+def slot(slot_index): -+ '''slot_index(1, 2, 3...)/all''' -+ get_slots_eeprom_info(slot_index) -+ -+ -+# syseeprom info display -+@main.command() -+@click.argument('syseeprom_index', required=True) -+def syseeprom(syseeprom_index): -+ '''syseeprom_index(1, 2, 3...)/all''' -+ get_syseeprom_info(syseeprom_index) -+ -+ -+# fru eeprom info decode -+@main.command() -+@click.argument('e2_path', required=True) -+@click.argument('e2_size', required=False, default="256") -+def fru(e2_path, e2_size): -+ '''e2_path''' -+ decode_eeprom_info("fru", e2_path, e2_size) -+ -+ -+# fantlv eeprom info decode -+@main.command() -+@click.argument('e2_path', required=True) -+@click.argument('e2_size', required=False, default="256") -+def fantlv(e2_path, e2_size): -+ '''e2_path''' -+ decode_eeprom_info("fantlv", e2_path, e2_size) -+ -+ -+# onie_tlv eeprom info decode -+@main.command() -+@click.argument('e2_path', required=True) -+@click.argument('e2_size', required=False, default="256") -+def onie_tlv(e2_path, e2_size): -+ '''e2_path''' -+ decode_eeprom_info("onie_tlv", e2_path, e2_size) -+ -+ -+if __name__ == '__main__': -+ main() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_intf.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_intf.py -new file mode 100755 -index 000000000..43f36f040 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_intf.py -@@ -0,0 +1,384 @@ -+#!/usr/bin/env python3 -+import os -+import syslog -+import importlib.machinery -+from platform_util import getplatform_name, dev_file_read, dev_file_write, write_sysfs, read_sysfs -+ -+__all__ = [ -+ "platform_reg_read", -+ "platform_reg_write", -+ "platform_set_optoe_type", -+ "platform_get_optoe_type", -+ "platform_sfp_read", -+ "platform_sfp_write", -+] -+ -+CPLD = 0 -+FPGA = 1 -+CPLD_PATH = "/dev/cpld%d" -+FPGA_PATH = "/dev/fpga%d" -+ -+ -+OPTOE_PATH = "/sys/bus/i2c/devices/%d-0050/" -+OPTOE_DEV_CLASS = "dev_class" -+OPTOE_EEPROM = "eeprom" -+ -+ -+PLATFORM_INTF_DEBUG_FILE = "/etc/.platform_intf_debug_flag" -+ -+ -+CONFIG_FILE_LIST = [ -+ "/usr/local/bin/", -+ "/usr/local/lib/python3/dist-packages/config/", -+ "/usr/local/lib/python3.7/dist-packages/config/", -+ "/usr/local/lib/python3.9/dist-packages/config/"] -+ -+ -+def platform_intf_debug(s): -+ if os.path.exists(PLATFORM_INTF_DEBUG_FILE): -+ syslog.openlog("PLATFORM_INTF_DEBUG", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def platform_intf_error(s): -+ if os.path.exists(PLATFORM_INTF_DEBUG_FILE): -+ syslog.openlog("PLATFORM_INTF_ERROR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+class IntfPlatform: -+ CONFIG_NAME = 'PLATFORM_INTF_OPTOE' -+ __port_optoe_dict = {} -+ -+ def __init__(self): -+ real_path = None -+ platform_name = (getplatform_name()).replace("-", "_") -+ for configfile_path in CONFIG_FILE_LIST: -+ configfile = configfile_path + platform_name + "_port_config.py" -+ if os.path.exists(configfile): -+ real_path = configfile -+ break -+ if real_path is None: -+ raise Exception("get port config error") -+ config = importlib.machinery.SourceFileLoader(self.CONFIG_NAME, real_path).load_module() -+ self.__port_optoe_dict = config.PLATFORM_INTF_OPTOE -+ -+ def get_dev_path(self, dev_type, dev_id): -+ if dev_type == CPLD: -+ path = CPLD_PATH % dev_id -+ elif dev_type == FPGA: -+ path = FPGA_PATH % dev_id -+ else: -+ msg = "dev_type error!" -+ return False, msg -+ platform_intf_debug("path:%s" % path) -+ return True, path -+ -+ def get_port_path(self, port): -+ port_num = self.__port_optoe_dict.get("port_num", 0) -+ if port_num <= 0: -+ msg = "PLATFORM_INTF_OPTOE port_num config error, port_num: %d!" % port_num -+ return False, msg -+ -+ if port <= 0 or port > port_num: -+ msg = "port out of range !" -+ return False, msg -+ -+ port_bus_map = self.__port_optoe_dict.get("port_bus_map") -+ optoe_start_bus = self.__port_optoe_dict.get("optoe_start_bus", 0) -+ if port_bus_map is None: # get port bus by optoe_start_bus -+ if optoe_start_bus <= 0: -+ msg = "PLATFORM_INTF_OPTOE optoe_start_bus config error, optoe_start_bus: %d" % optoe_start_bus -+ return False, msg -+ port_bus = port + optoe_start_bus - 1 -+ else: # get port bus by port_bus_map -+ port_bus = port_bus_map.get(port) -+ if port_bus is None: -+ msg = "port %d don't has i2c bus" % port -+ return False, msg -+ if not isinstance(port_bus, int) or port_bus < 0: -+ msg = "port %d i2c bus config error, port_bus: %s " % port_bus -+ return False, msg -+ -+ path = OPTOE_PATH % (port_bus) -+ platform_intf_debug("path:%s" % path) -+ return True, path -+ -+ ########################################### -+ # reg_read - read logic device register -+ # @dev_type: 0: CPLD, 1: FPGA -+ # @dev_id: device ID, start from 0 -+ # @offset: register offset -+ # @size: read length -+ # return: -+ # @ret: True if read success, False if not -+ # @info: The read value list if read success, otherwise the detail error message -+ ########################################### -+ def reg_read(self, dev_type, dev_id, offset, size): -+ ret, path = self.get_dev_path(dev_type, dev_id) -+ if ret is False: -+ return False, path -+ ret, info = dev_file_read(path, offset, size) -+ return ret, info -+ -+ ########################################### -+ # platform_reg_write - write logic device register -+ # @dev_type: 0: CPLD, 1: FPGA -+ # @dev_id: device ID, start from 0 -+ # @offset: register offset -+ # @val_list: The write value list -+ # return: -+ # @ret: True if write success, False if not -+ # @info: The write value length if write success, otherwise the detail error message -+ ########################################### -+ def reg_write(self, dev_type, dev_id, offset, val_list): -+ ret, path = self.get_dev_path(dev_type, dev_id) -+ if ret is False: -+ return False, path -+ ret, info = dev_file_write(path, offset, val_list) -+ return ret, info -+ -+ ########################################### -+ # set_optoe_type - set port optoe type -+ # @port: port index start from 1 -+ # @optoe_type: optoe type, including the following values -+ # 1: OPTOE1 -+ # 2: OPTOE2 -+ # 3: OPTOE3 -+ # return: -+ # @ret: True if set optoe type success, False if not -+ # @info: None if set optoe type success, otherwise the detail error message -+ ########################################### -+ def set_optoe_type(self, port, optoe_type): -+ ret, path = self.get_port_path(port) -+ if ret is False: -+ return False, path -+ optoe_type_path = path + OPTOE_DEV_CLASS -+ ret, info = write_sysfs(optoe_type_path, "%d" % optoe_type) -+ if ret is False: -+ return False, info -+ return True, None -+ -+ ########################################### -+ # get_optoe_type - get port optoe type -+ # @port: port index start from 1 -+ # return: -+ # @ret: True if set optoe type success, False if not -+ # @info: Optoe type value if get optoe type success, otherwise the detail error message -+ # optoe type including the following values -+ # 1: OPTOE1 -+ # 2: OPTOE2 -+ # 3: OPTOE3 -+ ########################################### -+ def get_optoe_type(self, port): -+ ret, path = self.get_port_path(port) -+ if ret is False: -+ return False, path -+ optoe_type_path = path + OPTOE_DEV_CLASS -+ ret, info = read_sysfs(optoe_type_path) -+ if ret is False: -+ return False, info -+ return True, int(info) -+ -+ ########################################### -+ # sfp_read -read sfp eeprom -+ # @port_id: port index start from 1 -+ # @offset: sfp eeprom offset -+ # @size: read sfp eeprom length -+ # return: -+ # @ret: True if read success, False if not -+ # @info: The read value list if read success, otherwise the detail error message -+ ########################################### -+ def sfp_read(self, port_id, offset, size): -+ ret, path = self.get_port_path(port_id) -+ if ret is False: -+ return False, path -+ optoe_eeprom_path = path + OPTOE_EEPROM -+ ret, info = dev_file_read(optoe_eeprom_path, offset, size) -+ return ret, info -+ -+ ########################################### -+ # sfp_write -write sfp eeprom -+ # @port_id: port index start from 1 -+ # @offset: sfp eeprom offset -+ # @val_list: The write value list -+ # return: -+ # @ret: True if read success, False if not -+ # @info: The write value length if write success, otherwise the detail error message -+ ########################################### -+ def sfp_write(self, port_id, offset, val_list): -+ ret, path = self.get_port_path(port_id) -+ if ret is False: -+ return False, path -+ optoe_eeprom_path = path + OPTOE_EEPROM -+ ret, info = dev_file_write(optoe_eeprom_path, offset, val_list) -+ return ret, info -+ -+ -+platform = IntfPlatform() -+ -+ -+########################################### -+# platform_reg_read - read logic device register -+# @dev_type: 0: CPLD, 1: FPGA -+# @dev_id: device ID, start from 0 -+# @offset: register offset -+# @size: read length -+# return: -+# @ret: True if read success, False if not -+# @info: The read value list if read success, otherwise the detail error message -+########################################### -+def platform_reg_read(dev_type, dev_id, offset, size): -+ ret = False -+ info = None -+ -+ # params check -+ if (isinstance(dev_type, int) is False or isinstance(dev_id, int) is False or -+ isinstance(offset, int) is False or isinstance(size, int) is False): -+ info = "params type check fail in platform_reg_read" -+ return ret, info -+ if dev_id < 0 or offset < 0 or size <= 0: -+ info = "params value check fail in platform_reg_read" -+ return ret, info -+ support_dev_type = (CPLD, FPGA) -+ if dev_type not in support_dev_type: -+ info = "dev_type match erro, fail in platform_reg_read" -+ return ret, info -+ -+ # call the solve func -+ return platform.reg_read(dev_type, dev_id, offset, size) -+ -+ -+########################################### -+# platform_reg_write - write logic device register -+# @dev_type: 0: CPLD, 1: FPGA -+# @dev_id: device ID, start from 0 -+# @offset: register offset -+# @val_list: The write value list -+# return: -+# @ret: True if write success, False if not -+# @info: The write value length if write success, otherwise the detail error message -+########################################### -+def platform_reg_write(dev_type, dev_id, offset, val_list): -+ ret = False -+ info = None -+ -+ # params check -+ if (isinstance(dev_type, int) is False or isinstance(dev_id, int) is False or -+ isinstance(offset, int) is False or isinstance(val_list, list) is False): -+ info = "params type check fail in platform_reg_write" -+ return ret, info -+ if dev_id < 0 or offset < 0 or len(val_list) <= 0: -+ info = "params value check fail in platform_reg_write" -+ return ret, info -+ support_dev_type = (CPLD, FPGA) -+ if dev_type not in support_dev_type: -+ info = "dev_type match erro, fail in platform_reg_write" -+ return ret, info -+ -+ # call the solve func -+ return platform.reg_write(dev_type, dev_id, offset, val_list) -+ -+ -+########################################### -+# platform_set_optoe_type - set port optoe type -+# @port: port index start from 1 -+# @optoe_type: optoe type, including the following values -+# 1: OPTOE1 -+# 2: OPTOE2 -+# 3: OPTOE3 -+# return: -+# @ret: True if set optoe type success, False if not -+# @info: None if set optoe type success, otherwise the detail error message -+########################################### -+def platform_set_optoe_type(port, optoe_type): -+ ret = False -+ info = None -+ -+ # params check -+ if isinstance(port, int) is False or isinstance(optoe_type, int) is False: -+ info = "params type check fail in platform_set_optoe_type" -+ return ret, info -+ if port < 0 or optoe_type < 1 or optoe_type > 3: -+ info = "params value check fail in platform_set_optoe_type" -+ return ret, info -+ -+ # call the solve func -+ return platform.set_optoe_type(port, optoe_type) -+ -+ -+########################################### -+# platform_get_optoe_type - get port optoe type -+# @port: port index start from 1 -+# return: -+# @ret: True if set optoe type success, False if not -+# @info: Optoe type value if get optoe type success, otherwise the detail error message -+# optoe type including the following values -+# 1: OPTOE1 -+# 2: OPTOE2 -+# 3: OPTOE3 -+########################################### -+def platform_get_optoe_type(port): -+ ret = False -+ info = None -+ -+ # params check -+ if isinstance(port, int) is False: -+ info = "params type check fail in platform_get_optoe_type" -+ return ret, info -+ if port < 0: -+ info = "params value check fail in platform_get_optoe_type" -+ return ret, info -+ -+ # call the solve func -+ return platform.get_optoe_type(port) -+ -+ -+########################################### -+# platform_sfp_read -read sfp eeprom -+# @port_id: port index start from 1 -+# @offset: sfp eeprom offset -+# @size: read sfp eeprom length -+# return: -+# @ret: True if read success, False if not -+# @info: The read value list if read success, otherwise the detail error message -+########################################### -+def platform_sfp_read(port_id, offset, size): -+ ret = False -+ info = None -+ -+ # params check -+ if isinstance(port_id, int) is False or isinstance(offset, int) is False or isinstance(size, int) is False: -+ info = "params type check fail in platform_sfp_read" -+ return ret, info -+ if port_id < 0 or offset < 0 or size <= 0: -+ info = "params value check fail in platform_sfp_read" -+ return ret, info -+ -+ # call the solve func -+ return platform.sfp_read(port_id, offset, size) -+ -+ -+########################################### -+# platform_sfp_write -write sfp eeprom -+# @port_id: port index start from 1 -+# @offset: sfp eeprom offset -+# @val_list: The write value list -+# return: -+# @ret: True if read success, False if not -+# @info: The write value length if write success, otherwise the detail error message -+########################################### -+def platform_sfp_write(port_id, offset, val_list): -+ ret = False -+ info = None -+ -+ # params check -+ if isinstance(port_id, int) is False or isinstance(offset, int) is False or isinstance(val_list, list) is False: -+ info = "params type check fail in platform_sfp_write" -+ return ret, info -+ if port_id < 0 or offset < 0 or len(val_list) <= 0: -+ info = "params value check fail in platform_sfp_write" -+ return ret, info -+ -+ # call the solve func -+ return platform.sfp_write(port_id, offset, val_list) -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_ipmi.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_ipmi.py -new file mode 100755 -index 000000000..c9b72c99c ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_ipmi.py -@@ -0,0 +1,92 @@ -+#!/usr/bin/env python3 -+# -*- coding: utf-8 -*- -+import sys -+import os -+import syslog -+import click -+from platform_util import exec_os_cmd -+ -+ -+IPMITOOL_CMD = "ipmitool raw 0x32 0x04" # All products are the same command -+ -+PLATFORM_IPMI_DEBUG_FILE = "/etc/.platform_ipmi_debug_flag" -+UPGRADEDEBUG = 1 -+debuglevel = 0 -+ -+ -+def debug_init(): -+ global debuglevel -+ if os.path.exists(PLATFORM_IPMI_DEBUG_FILE): -+ debuglevel = debuglevel | UPGRADEDEBUG -+ else: -+ debuglevel = debuglevel & ~(UPGRADEDEBUG) -+ -+ -+def ipmidebuglog(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ if UPGRADEDEBUG & debuglevel: -+ syslog.openlog("PLATFORM_IPMI", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def ipmierror(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("PLATFORM_IPMI", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+@click.command() -+@click.argument('cmd', required=True) -+def platform_ipmi_main(cmd): -+ '''Send command to BMC through ipmi''' -+ try: -+ # Convert string command to ASCII -+ user_cmd = "" -+ for ch in cmd: -+ user_cmd += " " + str(ord(ch)) -+ -+ final_cmd = IPMITOOL_CMD + user_cmd -+ ipmidebuglog("final cmd:%s" % final_cmd) -+ -+ # exec ipmitool cmd -+ status, output = exec_os_cmd(final_cmd) -+ if status: -+ ipmierror("exec ipmitool_cmd:%s user_cmd:%s failed" % (IPMITOOL_CMD, cmd)) -+ ipmierror("failed log: %s" % output) -+ return False, "exec final_cmd failed" -+ -+ # the data read by ipmitool is hex value, needs transformation -+ data_list = output.replace("\n", "").strip(' ').split(' ') -+ ipmidebuglog("data_list: %s" % data_list) -+ result = "" -+ for data in data_list: -+ result += chr(int(data, 16)) -+ -+ # 'result' string include ret and log, separated by , -+ result_list = result.split(',', 2) -+ if len(result_list) != 2: -+ log = "split failed. len(result) != 2. result:%s" % result -+ ipmierror(log) -+ return False, log -+ if int(result_list[0]) != 0: -+ ipmierror("finally analy ipmitool_cmd:%s user_cmd:%s exec failed" % (IPMITOOL_CMD, cmd)) -+ ipmierror("failed return log: %s" % result_list[1]) -+ print(result_list[1]) -+ return False, result_list[1] -+ -+ ipmidebuglog("finally exec ipmitool_cmd:%s user_cmd:%s success" % (IPMITOOL_CMD, cmd)) -+ print(result_list[1]) -+ return True, result_list[1] -+ -+ except Exception as e: -+ log = "An exception occurred, exception log:%s" % str(e) -+ ipmierror(log) -+ return False, log -+ -+ -+if __name__ == '__main__': -+ debug_init() -+ ret, msg = platform_ipmi_main() -+ if ret is False: -+ sys.exit(1) -+ sys.exit(0) -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_manufacturer.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_manufacturer.py -new file mode 100755 -index 000000000..b2643da9b ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_manufacturer.py -@@ -0,0 +1,562 @@ -+#!/usr/bin/env python3 -+ -+import re -+import mmap -+import fcntl -+import subprocess -+import shlex -+import signal -+import os -+import time -+import sys -+from platform_config import MANUINFO_CONF -+from monitor import status -+ -+ -+INDENT = 4 -+ -+ -+def printerr(vchar): -+ sys.stderr.write(vchar + '\n') -+ -+ -+g_extra_cache = {} -+g_meminfo_cache = {} -+g_exphy_cache = {} -+ -+ -+def exec_os_cmd(cmd, timeout = None): -+ status, output = subprocess.getstatusoutput(cmd) -+ return status, output -+ -+ -+def exphyfwsplit(): -+ # improve performance -+ global g_exphy_cache -+ if g_exphy_cache: -+ return -+ cmd = "bcmcmd -t 1 \"phy control xe,ce fw_get\" |grep fw_version" -+ ret, output = exec_os_cmd(cmd) -+ if ret or len(output) == 0: -+ raise Exception("run cmd: {} error, status: {}, msg: {}".format(cmd, ret, output)) -+ exphyfwstr = output.strip() -+ portlist = exphyfwstr.split("\n") -+ for port in portlist: -+ phy_addr_str = get_regular_val(port, r"phy_addr\s*=\s*\w+", 0) -+ if phy_addr_str.startswith("ERR"): -+ continue -+ phy_addr_key = phy_addr_str.replace(" ", "") -+ if phy_addr_key in g_exphy_cache: -+ continue -+ -+ g_exphy_cache[phy_addr_key] = {} -+ -+ fw_version_str = get_regular_val(port, r"fw_version\s*=\s*\w+", 0) -+ if fw_version_str.startswith("ERR"): -+ del g_exphy_cache[phy_addr_key] -+ continue -+ -+ fw_version = fw_version_str.split("=")[1].strip() -+ g_exphy_cache[phy_addr_key]["fw_version"] = fw_version -+ -+ if "success" in port: -+ ret = "OK" -+ else: -+ ret = "Unexpected" -+ g_exphy_cache[phy_addr_key]["status"] = ret -+ return -+ -+ -+def lshwmemorysplit(): -+ # improve performance -+ global g_meminfo_cache -+ if g_meminfo_cache: -+ return -+ cmd = "lshw -c memory" -+ ret, output = exec_os_cmd(cmd) -+ if ret or len(output) == 0: -+ raise Exception("run cmd: {} error, status: {}, msg: {}".format(cmd, ret, output)) -+ memstr = output.strip() -+ memlist = memstr.split("*-") -+ for item in memlist: -+ if item.strip().startswith("memory") and "System Memory" not in item: -+ continue -+ line_index = 0 -+ for line in item.splitlines(): -+ line_index += 1 -+ if line_index == 1: -+ memdict_key = line -+ g_meminfo_cache[memdict_key] = {} -+ else: -+ if ":" not in line: -+ continue -+ key = line.split(":", 1)[0].strip() -+ value = line.split(":", 1)[1].strip() -+ g_meminfo_cache[memdict_key][key] = value -+ if "empty" in item: -+ break -+ return -+ -+ -+def run_extra_func(funcname): -+ # improve performance -+ if funcname in g_extra_cache: -+ return g_extra_cache.get(funcname) -+ func = getattr(status, funcname) -+ ret = [] -+ func(ret) -+ if ret: -+ g_extra_cache[funcname] = ret -+ return ret -+ -+ -+def get_extra_value(funcname, itemid, key): -+ for item in run_extra_func(funcname): -+ if item.get("id") == itemid: -+ return item.get(key, "NA") -+ return "NA" -+ -+ -+def io_wr(reg_addr, reg_data): -+ try: -+ regdata = 0 -+ regaddr = 0 -+ if isinstance(reg_addr, int): -+ regaddr = reg_addr -+ else: -+ regaddr = int(reg_addr, 16) -+ if isinstance(reg_data, int): -+ regdata = reg_data -+ else: -+ regdata = int(reg_data, 16) -+ devfile = "/dev/port" -+ fd = os.open(devfile, os.O_RDWR | os.O_CREAT) -+ os.lseek(fd, regaddr, os.SEEK_SET) -+ os.write(fd, regdata.to_bytes(1, 'little')) -+ return True -+ except ValueError as e: -+ print(e) -+ return False -+ except Exception as e: -+ print(e) -+ return False -+ finally: -+ os.close(fd) -+ -+ -+def checksignaldriver(name): -+ modisexistcmd = "lsmod | grep -w %s | wc -l" % name -+ ret, output = exec_os_cmd(modisexistcmd) -+ if ret: -+ return False -+ if output.isdigit() and int(output) > 0: -+ return True -+ return False -+ -+ -+def adddriver(name): -+ cmd = "modprobe %s" % name -+ if checksignaldriver(name) is not True: -+ ret, log = exec_os_cmd(cmd) -+ if ret != 0 or len(log) > 0: -+ return False -+ return True -+ return True -+ -+ -+def removedriver(name): -+ cmd = "rmmod %s" % name -+ if checksignaldriver(name): -+ exec_os_cmd(cmd) -+ -+def deal_itmes(item_list): -+ for item in item_list: -+ dealtype = item.get("dealtype") -+ if dealtype == "shell": -+ cmd = item.get("cmd") -+ timeout = item.get("timeout", 10) -+ exec_os_cmd(cmd, timeout) -+ elif dealtype == "io_wr": -+ io_addr = item.get("io_addr") -+ wr_value = item.get("value") -+ io_wr(io_addr, wr_value) -+ -+ -+def get_func_value(funcname, params): -+ func = getattr(ExtraFunc, funcname) -+ ret = func(params) -+ return ret -+ -+ -+def read_pci_reg(pcibus, slot, fn, resource, offset): -+ '''read pci register''' -+ if offset % 4 != 0: -+ return "ERR offset: %d not 4 bytes align" -+ filename = "/sys/bus/pci/devices/0000:%02x:%02x.%x/resource%d" % (int(pcibus), int(slot), int(fn), int(resource)) -+ size = os.path.getsize(filename) -+ with open(filename, "r+") as file: -+ data = mmap.mmap(file.fileno(), size) -+ result = data[offset: offset + 4] -+ s = result[::-1] -+ val = 0 -+ for value in s: -+ val = val << 8 | value -+ data.close() -+ return "%08x" % val -+ -+ -+def devfileread(path, offset, length, bit_width): -+ ret = "" -+ val_str = '' -+ val_list = [] -+ fd = -1 -+ if not os.path.exists(path): -+ return "%s not found !" % path -+ if length % bit_width != 0: -+ return "only support read by bit_width" -+ if length < bit_width: -+ return "len needs to greater than or equal to bit_width" -+ -+ try: -+ fd = os.open(path, os.O_RDONLY) -+ os.lseek(fd, offset, os.SEEK_SET) -+ ret = os.read(fd, length) -+ for item in ret: -+ val_list.append(item) -+ -+ for i in range(0, length, bit_width): -+ for j in range(0, bit_width): -+ val_str += "%02x" % val_list[i + bit_width - j - 1] -+ except Exception as e: -+ return str(e) -+ finally: -+ if fd > 0: -+ os.close(fd) -+ return val_str -+ -+ -+def read_reg(loc, offset, size): -+ with open(loc, 'rb') as file: -+ file.seek(offset) -+ return ' '.join(["%02x" % item for item in file.read(size)]) -+ -+ -+def std_match(stdout, pattern): -+ if pattern is None: -+ return stdout.strip() -+ for line in stdout.splitlines(): -+ if re.match(pattern, line): -+ return line.strip() -+ raise EOFError("pattern: {} does not match anything in stdout {}".format( -+ pattern, stdout)) -+ -+ -+def i2c_rd(bus, loc, offset): -+ ''' -+ read i2c with i2cget command -+ ''' -+ cmd = "i2cget -f -y {} {} {}".format(bus, loc, offset) -+ retrytime = 6 -+ for i in range(retrytime): -+ ret, stdout = subprocess.getstatusoutput(cmd) -+ if ret == 0: -+ return stdout -+ time.sleep(0.1) -+ raise RuntimeError("run cmd: {} error, status {}".format(cmd, ret)) -+ -+ -+def i2c_rd_bytes(bus, loc, offset, size): -+ blist = [] -+ for i in range(size): -+ ret = i2c_rd(bus, loc, offset + i) -+ blist.append(ret) -+ -+ return blist -+ -+ -+def get_pair_val(source, separator): -+ try: -+ value = source.split(separator, 1)[1] -+ except (ValueError, IndexError): -+ return "ERR separator: {} does not match in source: {}".format(separator, source) -+ return value.strip() -+ -+ -+def get_regular_val(source, pattern, group): -+ try: -+ value = re.findall(pattern, source)[group] -+ except Exception: -+ return "ERR pattern: {} does not match in source: {} with group: {}".format(pattern, source, group) -+ return value.strip() -+ -+ -+def find_match(file2read, pattern): -+ with open(file2read, 'r') as file: -+ for line in file: -+ if not re.match(pattern, line): -+ continue -+ return line.strip() -+ return "ERR pattern %s not match in %s" % (pattern, file2read) -+ -+ -+def readaline(file2read): -+ with open(file2read, 'r') as file: -+ return file.readline() -+ -+ -+def sort_key(e): -+ return e.arrt_index -+ -+ -+class ExtraFunc(object): -+ @staticmethod -+ def get_bcm5387_version(params): -+ version = "" -+ try: -+ before_deal_list = params.get("before", []) -+ deal_itmes(before_deal_list) -+ -+ ret, version = exec_os_cmd(params["get_version"]) -+ if ret != 0: -+ version = "ERR " + version -+ -+ after_deal_list = params.get("after", []) -+ deal_itmes(after_deal_list) -+ -+ except Exception as e: -+ version = "ERR %s" % (str(e)) -+ finally: -+ finally_deal_list = params.get("finally", []) -+ deal_itmes(finally_deal_list) -+ return version -+ -+ @staticmethod -+ def get_memory_value(params): -+ root_key = params.get("root_key") -+ sub_key = params.get("sub_key") -+ lshwmemorysplit() -+ return g_meminfo_cache.get(root_key, {}).get(sub_key, "NA") -+ -+ @staticmethod -+ def get_memory_bank_value(params): -+ lshwmemorysplit() -+ bank = params.get("bankid") -+ if g_meminfo_cache.get(bank, {}): -+ return True -+ return False -+ -+ @staticmethod -+ def get_exphy_fw(phyid): -+ exphyfwsplit() -+ if phyid not in g_exphy_cache: -+ return "ERR %s not found." % phyid -+ fw_version = g_exphy_cache.get(phyid).get("fw_version") -+ ret = g_exphy_cache.get(phyid).get("status") -+ msg = "%s %s" % (fw_version, ret) -+ return msg -+ -+class CallbackSet: -+ def cpld_format(self, blist): -+ if isinstance(blist, str): -+ blist = blist.split() -+ elif not isinstance(blist, list) or len(blist) != 4: -+ raise ValueError("cpld format: wrong parameter: {}".format(blist)) -+ -+ return "{}{}{}{}".format(*blist).replace("0x", "") -+ -+ -+class VersionHunter: -+ call = CallbackSet() -+ -+ def __init__(self, entires): -+ self.head = None -+ self.next = None -+ self.key = None -+ self.cmd = None -+ self.file = None -+ self.reg = None -+ self.i2c = None -+ self.extra = None -+ self.pattern = None -+ self.separator = None -+ self.parent = None -+ self.ignore = False -+ self.children = [] -+ self.level = 0 -+ self.callback = None -+ self.delspace = None -+ self.arrt_index = None -+ self.config = None -+ self.precheck = None -+ self.func = None -+ self.regular = None -+ self.group = 0 -+ self.pci = None -+ self.devfile = None -+ self.decode = None -+ self.timeout = 10 -+ self.__dict__.update(entires) -+ -+ def check_para(self): -+ if self.pattern is None: -+ return False -+ if self.cmd is None or self.file is None: -+ return False -+ return True -+ -+ def get_version(self): -+ ret = "NA" -+ try: -+ if self.cmd is not None: -+ ret, output = exec_os_cmd(self.cmd, self.timeout) -+ if ret or len(output) == 0: -+ raise RuntimeError("run cmd: {} error, status: {}, msg: {}".format(self.cmd, ret, output)) -+ ret = std_match(output, self.pattern) -+ elif self.file is not None: -+ ret = self.read_file() -+ elif self.reg is not None: -+ ret = read_reg(self.reg.get("loc"), self.reg.get("offset"), -+ self.reg.get("size")) -+ elif self.extra: -+ ret = get_extra_value(self.extra.get("funcname"), -+ self.extra.get("id"), -+ self.extra.get("key")) -+ elif self.i2c: -+ ret = i2c_rd_bytes(self.i2c.get("bus"), self.i2c.get("loc"), -+ self.i2c.get("offset"), -+ self.i2c.get("size")) -+ elif self.config: -+ ret = self.config -+ elif self.func: -+ ret = get_func_value(self.func.get("funcname"), -+ self.func.get("params")) -+ elif self.pci: -+ ret = read_pci_reg(self.pci.get("bus"), self.pci.get("slot"), -+ self.pci.get("fn"), self.pci.get("bar"), self.pci.get("offset")) -+ elif self.devfile: -+ ret = devfileread(self.devfile.get("loc"), self.devfile.get("offset"), -+ self.devfile.get("len"), self.devfile.get("bit_width")) -+ -+ except Exception as e: -+ # printerr(e.message) -+ return "ERR %s" % str(e) -+ return self.exe_callback(ret) -+ -+ def exe_callback(self, data): -+ try: -+ if self.callback: -+ method = getattr(self.call, self.callback) -+ return method(data) -+ except Exception: -+ return "ERR run callback method: {} error, data: {}".format(self.callback, data) -+ return data -+ -+ def read_file(self): -+ if self.pattern is not None: -+ return find_match(self.file, self.pattern) -+ return readaline(self.file) -+ -+ def hunt(self): -+ if self.ignore: -+ return -+ indent = self.level * INDENT * " " -+ -+ if self.precheck: -+ try: -+ ret = get_func_value(self.precheck.get("funcname"), self.precheck.get("params")) -+ if ret is not True: -+ return -+ except Exception as e: -+ err_msg = "ERR %s" % str(e) -+ format_str = "{}{:<{}}{}".format(indent, self.key + ':', -+ (30 - len(indent)), err_msg) -+ print(format_str) -+ return -+ # has children -+ if self.children: -+ self.children.sort(key=sort_key) -+ format_str = "{}{}:".format(indent, self.key) -+ print(format_str) -+ for child in self.children: -+ if not isinstance(child, VersionHunter): -+ continue -+ child.level = self.level + 1 -+ child.hunt() -+ else: -+ version = self.get_version() or "" -+ if not version.startswith("ERR"): -+ version = version.replace("\x00", "").strip() -+ if self.separator is not None: -+ version = get_pair_val(version, self.separator) -+ if self.delspace is not None: -+ version = version.replace(" ", "") -+ if self.regular is not None: -+ version = get_regular_val(version, self.regular, self.group) -+ if self.decode is not None: -+ tmp_version = self.decode.get(version) -+ if tmp_version is None: -+ version = "ERR decode %s failed" % version -+ else: -+ version = tmp_version -+ format_str = "{}{:<{}}{}".format(indent, self.key + ':', -+ (30 - len(indent)), version) -+ print(format_str) -+ -+ if self.next: -+ print("") -+ self.next.hunt() -+ -+ -+pidfile = 0 -+ -+ -+def ApplicationInstance(): -+ global pidfile -+ pidfile = open(os.path.realpath(__file__), "r") -+ try: -+ fcntl.flock(pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB) -+ return True -+ except Exception: -+ return False -+ -+ -+def run(): -+ if os.geteuid() != 0: -+ print("Root privileges are required for this operation") -+ sys.exit(1) -+ -+ start_time = time.time() -+ while True: -+ ret = ApplicationInstance() -+ if ret is True: -+ break -+ if time.time() - start_time > 10: -+ printerr("manufacturer is running.") -+ sys.exit(1) -+ time.sleep(0.5) -+ -+ objmap = {} -+ -+ try: -+ target = {} -+ target.update(MANUINFO_CONF) -+ for objname, value in target.items(): -+ objmap[objname] = VersionHunter(value) -+ except Exception as e: -+ printerr(str(e)) -+ sys.exit(1) -+ -+ head = None -+ for objname, obj in objmap.items(): -+ if head is None and obj.head: -+ head = obj -+ if obj.parent: -+ objmap.get(obj.parent).children.append(obj) -+ if obj.next: -+ obj.next = objmap.get(obj.next) -+ -+ head.hunt() -+ -+ -+if __name__ == "__main__": -+ run() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_process.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_process.py -new file mode 100755 -index 000000000..f19231bba ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_process.py -@@ -0,0 +1,413 @@ -+#!/usr/bin/env python3 -+import os -+import subprocess -+import glob -+import time -+import click -+import shutil -+from platform_config import STARTMODULE, MAC_LED_RESET, AIRFLOW_RESULT_FILE -+from platform_config import GLOBALINITPARAM, GLOBALINITCOMMAND, GLOBALINITPARAM_PRE, GLOBALINITCOMMAND_PRE -+from platform_util import wbpciwr -+ -+ -+CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} -+ -+ -+class AliasedGroup(click.Group): -+ def get_command(self, ctx, cmd_name): -+ rv = click.Group.get_command(self, ctx, cmd_name) -+ if rv is not None: -+ return rv -+ matches = [x for x in self.list_commands(ctx) -+ if x.startswith(cmd_name)] -+ if not matches: -+ return None -+ if len(matches) == 1: -+ return click.Group.get_command(self, ctx, matches[0]) -+ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) -+ return None -+ -+ -+def log_os_system(cmd): -+ status, output = subprocess.getstatusoutput(cmd) -+ if status: -+ print(output) -+ return status, output -+ -+ -+def write_sysfs_value(reg_name, value): -+ mb_reg_file = "/sys/bus/i2c/devices/" + reg_name -+ locations = glob.glob(mb_reg_file) -+ if len(locations) == 0: -+ print("%s not found" % mb_reg_file) -+ return False -+ sysfs_loc = locations[0] -+ try: -+ with open(sysfs_loc, 'w') as fd: -+ fd.write(value) -+ except Exception: -+ return False -+ return True -+ -+ -+def getPid(name): -+ ret = [] -+ for dirname in os.listdir('/proc'): -+ if dirname == 'curproc': -+ continue -+ try: -+ with open('/proc/{}/cmdline'.format(dirname), mode='r') as fd: -+ content = fd.read() -+ except Exception: -+ continue -+ if name in content: -+ ret.append(dirname) -+ return ret -+ -+ -+def startAvscontrol(): -+ if STARTMODULE.get('avscontrol', 0) == 1: -+ cmd = "nohup avscontrol.py start >/dev/null 2>&1 &" -+ rets = getPid("avscontrol.py") -+ if len(rets) == 0: -+ os.system(cmd) -+ -+ -+def startFanctrol(): -+ if STARTMODULE.get('fancontrol', 0) == 1: -+ cmd = "nohup fancontrol.py start >/dev/null 2>&1 &" -+ rets = getPid("fancontrol.py") -+ if len(rets) == 0: -+ os.system(cmd) -+ -+ -+def starthal_fanctrl(): -+ if STARTMODULE.get('hal_fanctrl', 0) == 1: -+ cmd = "nohup hal_fanctrl.py start >/dev/null 2>&1 &" -+ rets = getPid("hal_fanctrl.py") -+ if len(rets) == 0: -+ os.system(cmd) -+ -+ -+def starthal_ledctrl(): -+ if STARTMODULE.get('hal_ledctrl', 0) == 1: -+ cmd = "nohup hal_ledctrl.py start >/dev/null 2>&1 &" -+ rets = getPid("hal_ledctrl.py") -+ if len(rets) == 0: -+ os.system(cmd) -+ -+ -+def startDevmonitor(): -+ if STARTMODULE.get('dev_monitor', 0) == 1: -+ cmd = "nohup dev_monitor.py start >/dev/null 2>&1 &" -+ rets = getPid("dev_monitor.py") -+ if len(rets) == 0: -+ os.system(cmd) -+ -+ -+def startSlotmonitor(): -+ if STARTMODULE.get('slot_monitor', 0) == 1: -+ cmd = "nohup slot_monitor.py start >/dev/null 2>&1 &" -+ rets = getPid("slot_monitor.py") -+ if len(rets) == 0: -+ os.system(cmd) -+ -+ -+def startIntelligentmonitor(): -+ if STARTMODULE.get('intelligent_monitor', 0) == 1: -+ cmd = "nohup intelligent_monitor.py >/dev/null 2>&1 &" -+ rets = getPid("intelligent_monitor.py") -+ if len(rets) == 0: -+ os.system(cmd) -+ -+ -+def startSignalmonitor(): -+ if STARTMODULE.get('signal_monitor', 0) == 1: -+ cmd = "nohup signal_monitor.py start >/dev/null 2>&1 &" -+ rets = getPid("signal_monitor.py") -+ if len(rets) == 0: -+ os.system(cmd) -+ -+ -+def startSff_temp_polling(): -+ if STARTMODULE.get('sff_temp_polling', 0) == 1: -+ cmd = "nohup sfp_highest_temperatue.py >/dev/null 2>&1 &" -+ rets = getPid("sfp_highest_temperatue.py") -+ if len(rets) == 0: -+ os.system(cmd) -+ -+ -+def startRebootCause(): -+ if STARTMODULE.get('reboot_cause', 0) == 1: -+ cmd = "nohup reboot_cause.py >/dev/null 2>&1 &" -+ rets = getPid("reboot_cause.py") -+ if len(rets) == 0: -+ os.system(cmd) -+ -+ -+def startPMON_sys(): -+ if STARTMODULE.get('pmon_syslog', 0) == 1: -+ cmd = "nohup pmon_syslog.py >/dev/null 2>&1 &" -+ rets = getPid("pmon_syslog.py") -+ if len(rets) == 0: -+ os.system(cmd) -+ -+ -+def startSff_polling(): -+ if STARTMODULE.get('sff_polling', 0) == 1: -+ cmd = "nohup sff_polling.py start > /dev/null 2>&1 &" -+ rets = getPid("sff_polling.py") -+ if len(rets) == 0: -+ os.system(cmd) -+ -+ -+def generate_air_flow(): -+ cmd = "nohup generate_airflow.py > /dev/null 2>&1 &" -+ rets = getPid("generate_airflow.py") -+ if len(rets) == 0: -+ os.system(cmd) -+ time.sleep(1) -+ -+ -+def startGenerate_air_flow(): -+ if STARTMODULE.get('generate_airflow', 0) == 1: -+ for i in range(10): -+ generate_air_flow() -+ if os.path.exists(AIRFLOW_RESULT_FILE): -+ click.echo("%%WB_PLATFORM_PROCESS: generate air flow success") -+ return -+ time.sleep(1) -+ click.echo("%%WB_PLATFORM_PROCESS: generate air flow,failed, %s not exits" % AIRFLOW_RESULT_FILE) -+ return -+ -+ -+def start_tty_console(): -+ if STARTMODULE.get('tty_console', 0) == 1: -+ cmd = "nohup tty_console.py > /dev/null 2>&1 &" -+ rets = getPid("tty_console.py") -+ if len(rets) == 0: -+ os.system(cmd) -+ -+def startDrvUpdate(): -+ if STARTMODULE.get('drv_update', 0) == 1: -+ cmd = "nohup drv_update.py >/dev/null 2>&1 &" -+ rets = getPid("drv_update.py") -+ if len(rets) == 0: -+ os.system(cmd) -+ -+ -+def stopAvscontrol(): -+ if STARTMODULE.get('avscontrol', 0) == 1: -+ rets = getPid("avscontrol.py") -+ for ret in rets: -+ cmd = "kill " + ret -+ os.system(cmd) -+ -+ -+def stopFanctrol(): -+ if STARTMODULE.get('fancontrol', 0) == 1: -+ rets = getPid("fancontrol.py") # -+ for ret in rets: -+ cmd = "kill " + ret -+ os.system(cmd) -+ -+ -+def stophal_fanctrl(): -+ if STARTMODULE.get('hal_fanctrl', 0) == 1: -+ rets = getPid("hal_fanctrl.py") -+ for ret in rets: -+ cmd = "kill " + ret -+ os.system(cmd) -+ -+ -+def stophal_ledctrl(): -+ if STARTMODULE.get('hal_ledctrl', 0) == 1: -+ rets = getPid("hal_ledctrl.py") -+ for ret in rets: -+ cmd = "kill " + ret -+ os.system(cmd) -+ -+ -+def stopDevmonitor(): -+ if STARTMODULE.get('dev_monitor', 0) == 1: -+ rets = getPid("dev_monitor.py") # -+ for ret in rets: -+ cmd = "kill " + ret -+ os.system(cmd) -+ -+ -+def stopSlotmonitor(): -+ if STARTMODULE.get('slot_monitor', 0) == 1: -+ rets = getPid("slot_monitor.py") # -+ for ret in rets: -+ cmd = "kill " + ret -+ os.system(cmd) -+ -+ -+def stopIntelligentmonitor(): -+ if STARTMODULE.get('intelligent_monitor', 0) == 1: -+ rets = getPid("intelligent_monitor.py") -+ for ret in rets: -+ cmd = "kill " + ret -+ os.system(cmd) -+ -+ -+def stopSignalmonitor(): -+ if STARTMODULE.get('signal_monitor', 0) == 1: -+ rets = getPid("signal_monitor.py") # -+ for ret in rets: -+ cmd = "kill " + ret -+ os.system(cmd) -+ -+ -+def stopSff_temp_polling(): -+ if STARTMODULE.get('sff_temp_polling', 0) == 1: -+ rets = getPid("sfp_highest_temperatue.py") -+ for ret in rets: -+ cmd = "kill " + ret -+ os.system(cmd) -+ -+ -+def stopPMON_sys(): -+ if STARTMODULE.get('pmon_syslog', 0) == 1: -+ rets = getPid("pmon_syslog.py") -+ for ret in rets: -+ cmd = "kill " + ret -+ os.system(cmd) -+ -+ -+def stopRebootCause(): -+ if STARTMODULE.get('reboot_cause', 0) == 1: -+ rets = getPid("reboot_cause.py") -+ for ret in rets: -+ cmd = "kill " + ret -+ os.system(cmd) -+ -+ -+def stopSff_polling(): -+ if STARTMODULE.get('sff_polling', 0) == 1: -+ rets = getPid("sff_polling.py") -+ for ret in rets: -+ cmd = "kill " + ret -+ os.system(cmd) -+ -+ -+def stopGenerate_air_flow(): -+ if STARTMODULE.get('generate_airflow', 0) == 1: -+ rets = getPid("generate_airflow.py") -+ for ret in rets: -+ cmd = "kill " + ret -+ os.system(cmd) -+ -+ -+def stop_tty_console(): -+ if STARTMODULE.get('tty_console', 0) == 1: -+ rets = getPid("tty_console.py") -+ for ret in rets: -+ cmd = "kill " + ret -+ os.system(cmd) -+ -+ -+def otherinit(): -+ for index in GLOBALINITPARAM: -+ write_sysfs_value(index["loc"], index["value"]) -+ -+ for index in GLOBALINITCOMMAND: -+ log_os_system(index) -+ -+ -+def otherinit_pre(): -+ for index in GLOBALINITPARAM_PRE: -+ write_sysfs_value(index["loc"], index["value"]) -+ -+ for index in GLOBALINITCOMMAND_PRE: -+ log_os_system(index) -+ -+ -+def unload_apps(): -+ stopSff_polling() -+ stopPMON_sys() -+ stopSignalmonitor() -+ stopIntelligentmonitor() -+ stopSlotmonitor() -+ stopDevmonitor() -+ stopAvscontrol() -+ stophal_ledctrl() -+ stophal_fanctrl() -+ stopFanctrol() -+ stopSff_temp_polling() -+ stopRebootCause() -+ stop_tty_console() -+ stopGenerate_air_flow() -+ -+ -+def MacLedSet(data): -+ '''write pci register''' -+ pcibus = MAC_LED_RESET.get("pcibus") -+ slot = MAC_LED_RESET.get("slot") -+ fn = MAC_LED_RESET.get("fn") -+ resource = MAC_LED_RESET.get("bar") -+ offset = MAC_LED_RESET.get("offset") -+ val = MAC_LED_RESET.get(data, None) -+ if val is None: -+ click.echo("%%WB_PLATFORM_PROCESS-INIT: MacLedSet wrong input") -+ return -+ wbpciwr(pcibus, slot, fn, resource, offset, val) -+ -+ -+def copy_machineconf(): -+ try: -+ shutil.copyfile("/host/machine.conf", "/etc/sonic/machine.conf") -+ return True -+ except Exception: -+ return False -+ -+def load_apps(): -+ copy_machineconf() -+ otherinit_pre() -+ startDrvUpdate() -+ startGenerate_air_flow() -+ start_tty_console() -+ startRebootCause() -+ startSff_temp_polling() -+ startFanctrol() -+ starthal_fanctrl() -+ starthal_ledctrl() -+ startAvscontrol() -+ startDevmonitor() -+ startSlotmonitor() -+ startIntelligentmonitor() -+ startSignalmonitor() -+ startPMON_sys() -+ startSff_polling() -+ otherinit() -+ if STARTMODULE.get("macledreset", 0) == 1: -+ MacLedSet("reset") -+ -+ -+@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) -+def main(): -+ '''device operator''' -+ -+ -+@main.command() -+def start(): -+ '''load process ''' -+ load_apps() -+ -+ -+@main.command() -+def stop(): -+ '''stop process ''' -+ unload_apps() -+ -+ -+@main.command() -+def restart(): -+ '''restart process''' -+ unload_apps() -+ load_apps() -+ -+ -+if __name__ == '__main__': -+ main() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_sensors.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_sensors.py -new file mode 100755 -index 000000000..d5b72f48f ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_sensors.py -@@ -0,0 +1,272 @@ -+#!/usr/bin/python3 -+ -+import os -+import sys -+import importlib.machinery -+ -+ -+def get_machine_info(): -+ if not os.path.isfile('/host/machine.conf'): -+ return None -+ machine_vars = {} -+ with open('/host/machine.conf') as machine_file: -+ for line in machine_file: -+ tokens = line.split('=') -+ if len(tokens) < 2: -+ continue -+ machine_vars[tokens[0]] = tokens[1].strip() -+ return machine_vars -+ -+ -+def get_platform_info(machine_info): -+ if machine_info is not None: -+ if 'onie_platform' in machine_info: -+ return machine_info['onie_platform'] -+ if 'aboot_platform' in machine_info: -+ return machine_info['aboot_platform'] -+ return None -+ -+ -+PLATFORM_ROOT_PATH = '/usr/share/sonic/device' -+PLATFORM_SPECIFIC_MODULE_NAME = 'monitor' -+PLATFORM_SPECIFIC_CLASS_NAME = 'status' -+platform_status_class = None -+platform = None -+ -+ -+def get_platform_name(): -+ global platform -+ platform = get_platform_info(get_machine_info()) -+ return platform -+ -+ -+val = get_platform_name() -+sys.path.append("/".join([PLATFORM_ROOT_PATH, platform])) -+ -+# Loads platform specific sfputil module from source -+ -+ -+def load_platform_monitor(): -+ global platform_status_class -+ platform_name = get_platform_info(get_machine_info()) -+ platform_path = "/".join([PLATFORM_ROOT_PATH, platform_name]) -+ try: -+ module_file = "/".join([platform_path, PLATFORM_SPECIFIC_MODULE_NAME + ".py"]) -+ module = importlib.machinery.SourceFileLoader(PLATFORM_SPECIFIC_MODULE_NAME, module_file).load_module() -+ except IOError: -+ return -1 -+ try: -+ platform_status_class = getattr(module, PLATFORM_SPECIFIC_CLASS_NAME) -+ except AttributeError: -+ return -2 -+ return 0 -+ -+ -+def printerr(msg): -+ print("\033[0;31m%s\033[0m" % msg) -+ -+ -+def print_console(msg): -+ print(msg) -+ -+ -+val_t = load_platform_monitor() -+if val_t != 0: -+ raise Exception("load monitor.py error") -+ -+ -+def print_platform(): -+ platform_info = get_platform_name() -+ print_console(platform_info) -+ print_console("") -+ -+ -+def print_cputemp_sensors(): -+ val_ret = get_call_value_by_function("getcputemp") -+ print_info_str = "" -+ toptile = "Onboard coretemp Sensors:" -+ formatstr = " {name:<20} : {temp} C (high = {max} C , crit = {crit} C )" -+ -+ if len(val_ret) != 0: -+ print_info_str += toptile + '\n' -+ for item in val_ret: -+ print_info_str += formatstr.format(**item) + '\n' -+ print_console(print_info_str) -+ -+ -+def print_boardtemp(): -+ val_ret = get_call_value_by_function("getTemp") -+ print_info_str = "" -+ toptile = "Onboard Temperature Sensors:" -+ errformat = " {id:<20} : {errmsg}" -+ formatstr = " {id:<20} : {temp1_input} C (high = {temp1_max} C, hyst = {temp1_max_hyst} C)" -+ -+ if len(val_ret) != 0: -+ print_info_str += toptile + '\n' -+ for item in val_ret: -+ realformat = formatstr if item.get('errcode', 0) == 0 else errformat -+ print_info_str += realformat.format(**item) + '\n' -+ print_console(print_info_str) -+ -+ -+def print_mactemp_sensors(): -+ val_ret = get_call_value_by_function("getmactemp") -+ print_info_str = "" -+ toptile = "Onboard MAC Temperature Sensors:" -+ errformat = " {id:<20} : {errmsg}" -+ formatstr = " {id:<20} : {temp_input} C" -+ -+ if len(val_ret) != 0: -+ print_info_str += toptile + '\n' -+ for item in val_ret: -+ realformat = formatstr if item.get('errcode', 0) == 0 else errformat -+ print_info_str += realformat.format(**item) + '\n' -+ print_console(print_info_str) -+ -+ -+def print_macpower_sensors(): -+ val_ret = get_call_value_by_function("getmacpower") -+ print_info_str = "" -+ toptile = "Onboard MAC Power Sensors:" -+ errformat = " {id:<20} : {errmsg}" -+ formatstr = " {id:<20} : {power_input} W" -+ -+ if len(val_ret) != 0: -+ print_info_str += toptile + '\n' -+ for item in val_ret: -+ realformat = formatstr if item.get('errcode', 0) == 0 else errformat -+ print_info_str += realformat.format(**item) + '\n' -+ print_console(print_info_str) -+ -+ -+def print_fan_sensor(): -+ val_ret = get_call_value_by_function("checkFan") -+ print_info_str = "" -+ toptile = "Onboard fan Sensors:" -+ errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" -+ fan_signle_rotor_format = " {id} : \n" \ -+ " fan_type : {fan_type}\n" \ -+ " sn : {sn}\n" \ -+ " hw_version: {hw_version}\n" \ -+ " Speed : {Speed} RPM\n" \ -+ " status : {errmsg} \n" -+ fan_double_rotor_format = " {id} : \n" \ -+ " fan_type : {fan_type}\n" \ -+ " sn : {sn}\n" \ -+ " hw_version: {hw_version}\n" \ -+ " Speed :\n" \ -+ " speed_front : {rotor1_speed:<5} RPM\n" \ -+ " speed_rear : {rotor2_speed:<5} RPM\n" \ -+ " status : {errmsg} \n" -+ -+ if len(val_ret) != 0: -+ print_info_str += toptile + '\n' -+ for item in val_ret: -+ if item.get('Speed', None) is None: -+ realformat = fan_double_rotor_format if item.get('errcode', 0) == 0 else errformat -+ else: -+ realformat = fan_signle_rotor_format if item.get('errcode', 0) == 0 else errformat -+ print_info_str += realformat.format(**item) -+ print_console(print_info_str) -+ -+ -+def print_psu_sensor(): -+ val_ret = get_call_value_by_function("getPsu") -+ print_info_str = "" -+ toptile = "Onboard Power Supply Unit Sensors:" -+ errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" -+ psuformat = " {id} : \n" \ -+ " type : {type1}\n" \ -+ " sn : {sn}\n" \ -+ " in_current : {in_current} A\n" \ -+ " in_voltage : {in_voltage} V\n" \ -+ " out_current: {out_current} A\n" \ -+ " out_voltage: {out_voltage} V\n" \ -+ " temp : {temp} C \n" \ -+ " fan_speed : {fan_speed} RPM\n" \ -+ " in_power : {in_power} W\n" \ -+ " out_power : {out_power} W\n" -+ -+ if len(val_ret) != 0: -+ print_info_str += toptile + '\r\n' -+ for item in val_ret: -+ realformat = psuformat if item.get('errcode', 0) == 0 else errformat -+ print_info_str += realformat.format(**item) -+ print_console(print_info_str) -+ -+def print_cust_psu_sensor(): -+ val_ret = get_call_value_by_function("getCustPsu") -+ print_info_str = "" -+ toptile = "Onboard Power Supply Unit Sensors:" -+ errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" -+ psuformat = " {id} : \n" \ -+ " Model : {type1}\n" \ -+ " Serial : {sn}\n" \ -+ " HW Rev : {hw_version}\n" \ -+ " Status : {errmsg}\n" -+ -+ if len(val_ret) != 0: -+ print_info_str += toptile + '\r\n' -+ for item in val_ret: -+ realformat = psuformat if item.get('errcode', 0) == 0 else errformat -+ print_info_str += realformat.format(**item) -+ print_console(print_info_str) -+ -+ -+def print_slot_sensor(): -+ val_ret = get_call_value_by_function("checkSlot") -+ print_info_str = "" -+ toptile = "Onboard slot Sensors:" -+ errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" -+ psuformat = " {id} : \n" \ -+ " slot_type : {slot_type}\n" \ -+ " sn : {sn}\n" \ -+ " hw_version : {hw_version} \n" \ -+ " status : {errmsg}\n" -+ -+ if len(val_ret) != 0: -+ print_info_str += toptile + '\r\n' -+ for item in val_ret: -+ realformat = psuformat if item.get('errcode', 0) == 0 else errformat -+ print_info_str += realformat.format(**item) -+ print_console(print_info_str) -+ -+ -+def print_boarddcdc(): -+ val_ret = get_call_value_by_function("getDcdc") -+ print_info_str = "" -+ toptile = "Onboard DCDC Sensors:" -+ errformat = " {id:<26} : {errmsg}" -+ formatstr = " {id:<26} : {dcdc_input:<6} {dcdc_unit:<1} (Min = {dcdc_min:<6} {dcdc_unit:<1}, Max = {dcdc_max:<6} {dcdc_unit:<1})" -+ -+ if len(val_ret) != 0: -+ print_info_str += toptile + '\n' -+ for item in val_ret: -+ realformat = formatstr if item.get('errcode', 0) == 0 else errformat -+ print_info_str += realformat.format(**item) + '\n' -+ print_console(print_info_str) -+ -+ -+def get_call_value_by_function(function_name): -+ valtemp = [] -+ if hasattr(platform_status_class, function_name): -+ test2_func = getattr(platform_status_class, function_name) -+ test2_func(valtemp) -+ return valtemp -+ -+ -+def getsensors(): -+ print_platform() -+ print_cputemp_sensors() -+ print_boardtemp() -+ print_mactemp_sensors() -+ print_macpower_sensors() -+ print_fan_sensor() -+ print_psu_sensor() -+ print_cust_psu_sensor() -+ print_slot_sensor() -+ print_boarddcdc() -+ -+ -+if __name__ == "__main__": -+ getsensors() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_test.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_test.py -new file mode 100755 -index 000000000..da7119a9c ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_test.py -@@ -0,0 +1,142 @@ -+#!/usr/bin/env python3 -+# -*- coding: UTF-8 -*- -+ -+try: -+ import click -+ from platform_intf import platform_reg_read, platform_reg_write, platform_get_optoe_type -+ from platform_intf import platform_set_optoe_type, platform_sfp_read, platform_sfp_write -+except ImportError as error: -+ raise ImportError('%s - required module not found' % str(error)) from error -+ -+ -+CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} -+ -+ -+class AliasedGroup(click.Group): -+ def get_command(self, ctx, cmd_name): -+ rv = click.Group.get_command(self, ctx, cmd_name) -+ if rv is not None: -+ return rv -+ matches = [x for x in self.list_commands(ctx) -+ if x.startswith(cmd_name)] -+ if not matches: -+ return None -+ if len(matches) == 1: -+ return click.Group.get_command(self, ctx, matches[0]) -+ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) -+ return None -+ -+ -+def print_reg(info, offset): -+ try: -+ size = len(info) -+ j = offset % 16 -+ tmp = j -+ offset -= j -+ print_buf = "\n " -+ -+ for i in range(16): -+ print_buf = print_buf + "%2x " % i -+ print(print_buf) -+ -+ print_buf = None -+ for i in range(size + j): -+ if i % 16 == 0: -+ print_buf = "" -+ print_buf = "0x%08x " % offset -+ offset = offset + 16 -+ if tmp: -+ print_buf = print_buf + " " -+ tmp = tmp - 1 -+ else: -+ print_buf = print_buf + "%02x " % info[i - j] -+ if (i + 1) % 16 == 0 or i == size + j - 1: -+ print(print_buf) -+ except Exception as e: -+ msg = str(e) -+ print("i = %d, j = %d," % (i, j)) -+ print(msg) -+ -+ -+@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) -+def main(): -+ '''platform_test main''' -+ -+ -+@main.command() -+@click.argument('dev_type', required=True) -+@click.argument('dev_id', required=True) -+@click.argument('offset', required=True) -+@click.argument('size', required=True) -+def reg_rd(dev_type, dev_id, offset, size): -+ '''read cpld/fpga reg''' -+ ret, info = platform_reg_read(int(dev_type), int(dev_id), int(offset), int(size)) -+ print(ret) -+ if ret is True: -+ print_reg(info, int(offset)) -+ else: -+ print(info) -+ -+ -+@main.command() -+@click.argument('dev_type', required=True) -+@click.argument('dev_id', required=True) -+@click.argument('offset', required=True) -+@click.argument('value', required=True) -+def reg_wr(dev_type, dev_id, offset, value): -+ '''write cpld/fpga reg''' -+ value_list = [] -+ value_list.append(int(value)) -+ ret, info = platform_reg_write(int(dev_type), int(dev_id), int(offset), value_list) -+ print(ret) -+ print(info) -+ -+ -+@main.command() -+@click.argument('port', required=True) -+def get_optoe_type(port): -+ '''get optoe type''' -+ ret, info = platform_get_optoe_type(int(port)) -+ print(ret) -+ print(info) -+ -+ -+@main.command() -+@click.argument('port', required=True) -+@click.argument('optoe_type', required=True) -+def set_optoe_type(port, optoe_type): -+ '''set optoe type''' -+ ret, info = platform_set_optoe_type(int(port), int(optoe_type)) -+ print(ret) -+ print(info) -+ -+ -+@main.command() -+@click.argument('port_id', required=True) -+@click.argument('offset', required=True) -+@click.argument('size', required=True) -+def sfp_rd(port_id, offset, size): -+ '''read sfp''' -+ ret, info = platform_sfp_read(int(port_id), int(offset), int(size)) -+ print(ret) -+ if ret is True: -+ print_reg(info, int(offset)) -+ else: -+ print(info) -+ -+ -+@main.command() -+@click.argument('port_id', required=True) -+@click.argument('offset', required=True) -+@click.argument('value', required=True) -+def sfp_wr(port_id, offset, value): -+ '''write sfp''' -+ value_list = [] -+ value_list.append(int(value)) -+ ret, info = platform_sfp_write(int(port_id), int(offset), value_list) -+ print(ret) -+ print(info) -+ -+ -+if __name__ == '__main__': -+ main() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_util.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_util.py -new file mode 100755 -index 000000000..71a97e5a2 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_util.py -@@ -0,0 +1,838 @@ -+#!/usr/bin/python3 -+ -+import sys -+import os -+import re -+import subprocess -+import shlex -+import time -+import mmap -+import glob -+import logging.handlers -+import shutil -+import gzip -+import ast -+ -+ -+CONFIG_DB_PATH = "/etc/sonic/config_db.json" -+MAILBOX_DIR = "/sys/bus/i2c/devices/" -+ -+ -+__all__ = [ -+ "strtoint", -+ "byteTostr", -+ "getplatform_name", -+ "wbi2cget", -+ "wbi2cset", -+ "wbpcird", -+ "wbpciwr", -+ "wbi2cgetWord", -+ "wbi2csetWord", -+ "wbi2cset_pec", -+ "wbi2cset_wordpec", -+ "wbsysset", -+ "dev_file_read", -+ "dev_file_write", -+ "wb_os_system", -+ "io_rd", -+ "io_wr", -+ "exec_os_cmd", -+ "exec_os_cmd_log", -+ "write_sysfs", -+ "read_sysfs", -+ "get_sysfs_value", -+ "write_sysfs_value", -+ "get_value", -+ "set_value", -+ "getSdkReg", -+ "getMacTemp", -+ "getMacTemp_sysfs", -+ "get_format_value" -+] -+ -+class CodeVisitor(ast.NodeVisitor): -+ -+ def __init__(self): -+ self.value = None -+ -+ def get_value(self): -+ return self.value -+ -+ def get_op_value(self, node): -+ if isinstance(node, ast.Call): # node is func call -+ value = self.visit_Call(node) -+ elif isinstance(node, ast.BinOp): # node is BinOp -+ value = self.visit_BinOp(node) -+ elif isinstance(node, ast.UnaryOp): # node is UnaryOp -+ value = self.visit_UnaryOp(node) -+ elif isinstance(node, ast.Num): # node is Num Constant -+ value = node.n -+ elif isinstance(node, ast.Str): # node is Str Constant -+ value = node.s -+ else: -+ raise NotImplementedError("Unsupport operand type: %s" % type(node)) -+ return value -+ -+ def visit_UnaryOp(self, node): -+ ''' -+ node.op: operand type, only support ast.UAdd/ast.USub -+ node.operand: only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.UnaryOp -+ ''' -+ -+ operand_value = self.get_op_value(node.operand) -+ if isinstance(node.op, ast.UAdd): -+ self.value = operand_value -+ elif isinstance(node.op, ast.USub): -+ self.value = 0 - operand_value -+ else: -+ raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) -+ return self.value -+ -+ def visit_BinOp(self, node): -+ ''' -+ node.left: left operand, only support ast.Call/ast.Constant(ast.Num)/ast.BinOp -+ node.op: operand type, only support ast.Add/ast.Sub/ast.Mult/ast.Div -+ node.right: right operan, only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp -+ ''' -+ left_value = self.get_op_value(node.left) -+ right_value = self.get_op_value(node.right) -+ -+ if isinstance(node.op, ast.Add): -+ self.value = left_value + right_value -+ elif isinstance(node.op, ast.Sub): -+ self.value = left_value - right_value -+ elif isinstance(node.op, ast.Mult): -+ self.value = left_value * right_value -+ elif isinstance(node.op, ast.Div): -+ self.value = left_value / right_value -+ else: -+ raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) -+ return self.value -+ -+ def visit_Call(self, node): -+ ''' -+ node.func.id: func name, only support 'float', 'int', 'str' -+ node.args: func args list,only support ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.Call -+ str/float only support one parameter, eg: float(XXX), str(xxx) -+ int support one or two parameters, eg: int(xxx) or int(xxx, 16) -+ xxx can be ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp -+ ''' -+ calc_tuple = ("float", "int", "str") -+ -+ if node.func.id not in calc_tuple: -+ raise NotImplementedError("Unsupport function call type: %s" % node.func.id) -+ -+ args_val_list = [] -+ for item in node.args: -+ ret = self.get_op_value(item) -+ args_val_list.append(ret) -+ -+ if node.func.id == "str": -+ if len(args_val_list) != 1: -+ raise TypeError("str() takes 1 positional argument but %s were given" % len(args_val_list)) -+ value = str(args_val_list[0]) -+ self.value = value -+ return value -+ -+ if node.func.id == "float": -+ if len(args_val_list) != 1: -+ raise TypeError("float() takes 1 positional argument but %s were given" % len(args_val_list)) -+ value = float(args_val_list[0]) -+ self.value = value -+ return value -+ # int -+ if len(args_val_list) == 1: -+ value = int(args_val_list[0]) -+ self.value = value -+ return value -+ if len(args_val_list) == 2: -+ value = int(args_val_list[0], args_val_list[1]) -+ self.value = value -+ return value -+ raise TypeError("int() takes 1 or 2 arguments (%s given)" % len(args_val_list)) -+ -+def inttostr(vl, length): -+ if not isinstance(vl, int): -+ raise Exception(" type error") -+ index = 0 -+ ret_t = "" -+ while index < length: -+ ret = 0xff & (vl >> index * 8) -+ ret_t += chr(ret) -+ index += 1 -+ return ret_t -+ -+ -+def strtoint(str_tmp): -+ value = 0 -+ rest_v = str_tmp.replace("0X", "").replace("0x", "") -+ str_len = len(rest_v) -+ for index, val in enumerate(rest_v): -+ value |= int(val, 16) << ((str_len - index - 1) * 4) -+ return value -+ -+ -+def inttobytes(val, length): -+ if not isinstance(val, int): -+ raise Exception("type error") -+ data_array = bytearray() -+ index = 0 -+ while index < length: -+ ret = 0xff & (val >> index * 8) -+ data_array.append(ret) -+ index += 1 -+ return data_array -+ -+ -+def byteTostr(val): -+ strtmp = '' -+ for value in val: -+ strtmp += chr(value) -+ return strtmp -+ -+ -+def typeTostr(val): -+ strtmp = '' -+ if isinstance(val, bytes): -+ strtmp = byteTostr(val) -+ return strtmp -+ -+ -+def getonieplatform(path): -+ if not os.path.isfile(path): -+ return "" -+ machine_vars = {} -+ with open(path) as machine_file: -+ for line in machine_file: -+ tokens = line.split('=') -+ if len(tokens) < 2: -+ continue -+ machine_vars[tokens[0]] = tokens[1].strip() -+ return machine_vars.get("onie_platform") -+ -+ -+def getplatform_config_db(): -+ if not os.path.isfile(CONFIG_DB_PATH): -+ return "" -+ val = os.popen("sonic-cfggen -j %s -v DEVICE_METADATA.localhost.platform" % CONFIG_DB_PATH).read().strip() -+ if len(val) <= 0: -+ return "" -+ return val -+ -+ -+def getplatform_name(): -+ if os.path.isfile('/host/machine.conf'): -+ return getonieplatform('/host/machine.conf') -+ if os.path.isfile('/etc/sonic/machine.conf'): -+ return getonieplatform('/etc/sonic/machine.conf') -+ return getplatform_config_db() -+ -+ -+def wbi2cget(bus, devno, address, word=None): -+ if word is None: -+ command_line = "i2cget -f -y %d 0x%02x 0x%02x " % (bus, devno, address) -+ else: -+ command_line = "i2cget -f -y %d 0x%02x 0x%02x %s" % (bus, devno, address, word) -+ retrytime = 6 -+ ret_t = "" -+ for i in range(retrytime): -+ ret, ret_t = wb_os_system(command_line) -+ if ret == 0: -+ return True, ret_t -+ time.sleep(0.1) -+ return False, ret_t -+ -+ -+def wbi2cset(bus, devno, address, byte): -+ command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x" % ( -+ bus, devno, address, byte) -+ retrytime = 6 -+ ret_t = "" -+ for i in range(retrytime): -+ ret, ret_t = wb_os_system(command_line) -+ if ret == 0: -+ return True, ret_t -+ return False, ret_t -+ -+ -+def wbpcird(pcibus, slot, fn, resource, offset): -+ '''read pci register''' -+ if offset % 4 != 0: -+ return "ERR offset: %d not 4 bytes align" -+ filename = "/sys/bus/pci/devices/0000:%02x:%02x.%x/resource%d" % (int(pcibus), int(slot), int(fn), int(resource)) -+ with open(filename, "r+") as file: -+ size = os.path.getsize(filename) -+ data = mmap.mmap(file.fileno(), size) -+ result = data[offset: offset + 4] -+ s = result[::-1] -+ val = 0 -+ for value in s: -+ val = val << 8 | value -+ data.close() -+ return "0x%08x" % val -+ -+ -+def wbpciwr(pcibus, slot, fn, resource, offset, data): -+ '''write pci register''' -+ ret = inttobytes(data, 4) -+ filename = "/sys/bus/pci/devices/0000:%02x:%02x.%x/resource%d" % (int(pcibus), int(slot), int(fn), int(resource)) -+ with open(filename, "r+") as file: -+ size = os.path.getsize(filename) -+ data = mmap.mmap(file.fileno(), size) -+ data[offset: offset + 4] = ret -+ result = data[offset: offset + 4] -+ s = result[::-1] -+ val = 0 -+ for value in s: -+ val = val << 8 | value -+ data.close() -+ -+ -+def wbi2cgetWord(bus, devno, address): -+ command_line = "i2cget -f -y %d 0x%02x 0x%02x w" % (bus, devno, address) -+ retrytime = 3 -+ ret_t = "" -+ for i in range(retrytime): -+ ret, ret_t = wb_os_system(command_line) -+ if ret == 0: -+ return True, ret_t -+ return False, ret_t -+ -+ -+def wbi2csetWord(bus, devno, address, byte): -+ command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%x w" % ( -+ bus, devno, address, byte) -+ retrytime = 6 -+ ret_t = "" -+ for i in range(retrytime): -+ ret, ret_t = wb_os_system(command_line) -+ if ret == 0: -+ return True, ret_t -+ return False, ret_t -+ -+ -+def wbi2cset_pec(bus, devno, address, byte): -+ command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x bp" % ( -+ bus, devno, address, byte) -+ retrytime = 6 -+ ret_t = "" -+ for i in range(retrytime): -+ ret, ret_t = wb_os_system(command_line) -+ if ret == 0: -+ return True, ret_t -+ return False, ret_t -+ -+ -+def wbi2cset_wordpec(bus, devno, address, byte): -+ command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x wp" % ( -+ bus, devno, address, byte) -+ retrytime = 6 -+ ret_t = "" -+ for i in range(retrytime): -+ ret, ret_t = wb_os_system(command_line) -+ if ret == 0: -+ return True, ret_t -+ return False, ret_t -+ -+ -+def wbsysset(location, value): -+ command_line = "echo 0x%02x > %s" % (value, location) -+ retrytime = 6 -+ ret_t = "" -+ for i in range(retrytime): -+ ret, ret_t = wb_os_system(command_line) -+ if ret == 0: -+ return True, ret_t -+ return False, ret_t -+ -+ -+def dev_file_read(path, offset, read_len): -+ val_list = [] -+ msg = "" -+ ret = "" -+ fd = -1 -+ -+ if not os.path.exists(path): -+ msg = path + " not found !" -+ return False, msg -+ -+ try: -+ fd = os.open(path, os.O_RDONLY) -+ os.lseek(fd, offset, os.SEEK_SET) -+ ret = os.read(fd, read_len) -+ for item in ret: -+ val_list.append(item) -+ except Exception as e: -+ msg = str(e) -+ return False, msg -+ finally: -+ if fd > 0: -+ os.close(fd) -+ return True, val_list -+ -+ -+def dev_file_write(path, offset, buf_list): -+ msg = "" -+ fd = -1 -+ -+ if not isinstance(buf_list, list) or len(buf_list) == 0: -+ msg = "buf:%s is not list type or is NONE !" % buf_list -+ return False, msg -+ -+ if not os.path.exists(path): -+ msg = path + " not found !" -+ return False, msg -+ -+ try: -+ fd = os.open(path, os.O_WRONLY) -+ os.lseek(fd, offset, os.SEEK_SET) -+ ret = os.write(fd, bytes(buf_list)) -+ except Exception as e: -+ msg = str(e) -+ return False, msg -+ finally: -+ if fd > 0: -+ os.close(fd) -+ -+ return True, ret -+ -+ -+def wb_os_system(cmd): -+ status, output = subprocess.getstatusoutput(cmd) -+ return status, output -+ -+ -+def io_rd(reg_addr, read_len=1): -+ try: -+ regaddr = 0 -+ if isinstance(reg_addr, int): -+ regaddr = reg_addr -+ else: -+ regaddr = int(reg_addr, 16) -+ devfile = "/dev/port" -+ fd = os.open(devfile, os.O_RDWR | os.O_CREAT) -+ os.lseek(fd, regaddr, os.SEEK_SET) -+ val = os.read(fd, read_len) -+ return "".join(["%02x" % item for item in val]) -+ except ValueError: -+ return None -+ except Exception as e: -+ print(e) -+ return None -+ finally: -+ os.close(fd) -+ -+ -+def io_wr(reg_addr, reg_data): -+ try: -+ regdata = 0 -+ regaddr = 0 -+ if isinstance(reg_addr, int): -+ regaddr = reg_addr -+ else: -+ regaddr = int(reg_addr, 16) -+ if isinstance(reg_data, int): -+ regdata = reg_data -+ else: -+ regdata = int(reg_data, 16) -+ devfile = "/dev/port" -+ fd = os.open(devfile, os.O_RDWR | os.O_CREAT) -+ os.lseek(fd, regaddr, os.SEEK_SET) -+ os.write(fd, regdata.to_bytes(1, 'little')) -+ return True -+ except ValueError as e: -+ print(e) -+ return False -+ except Exception as e: -+ print(e) -+ return False -+ finally: -+ os.close(fd) -+ -+ -+def exec_os_cmd(cmd): -+ status, output = subprocess.getstatusoutput(cmd) -+ return status, output -+ -+ -+def exec_os_cmd_log(cmd): -+ proc = subprocess.Popen(shlex.split(cmd), stdin=subprocess.PIPE, shell=False, stderr=sys.stderr, close_fds=True, -+ stdout=sys.stdout, universal_newlines=True, bufsize=1) -+ proc.wait() -+ stdout = proc.communicate()[0] -+ stdout = typeTostr(stdout) -+ return proc.returncode, stdout -+ -+ -+def write_sysfs(location, value): -+ try: -+ if not os.path.isfile(location): -+ return False, ("location[%s] not found !" % location) -+ with open(location, 'w') as fd1: -+ fd1.write(value) -+ except Exception as e: -+ return False, (str(e) + " location[%s]" % location) -+ return True, ("set location[%s] %s success !" % (location, value)) -+ -+ -+def read_sysfs(location): -+ try: -+ locations = glob.glob(location) -+ with open(locations[0], 'rb') as fd1: -+ retval = fd1.read() -+ retval = typeTostr(retval) -+ retval = retval.rstrip('\r\n') -+ retval = retval.lstrip(" ") -+ except Exception as e: -+ return False, (str(e) + "location[%s]" % location) -+ return True, retval -+ -+ -+def get_pmc_register(reg_name): -+ retval = 'ERR' -+ mb_reg_file = MAILBOX_DIR + reg_name -+ filepath = glob.glob(mb_reg_file) -+ if len(filepath) == 0: -+ return "%s %s notfound" % (retval, mb_reg_file) -+ mb_reg_file = filepath[0] -+ if not os.path.isfile(mb_reg_file): -+ return "%s %s notfound" % (retval, mb_reg_file) -+ try: -+ with open(mb_reg_file, 'r') as fd: -+ retval = fd.read() -+ except Exception as error: -+ retval = retval + str(error) -+ retval = retval.rstrip('\r\n') -+ retval = retval.lstrip(" ") -+ return retval -+ -+ -+def get_sysfs_value(location): -+ pos_t = str(location) -+ name = get_pmc_register(pos_t) -+ return name -+ -+ -+def write_sysfs_value(reg_name, value): -+ fileLoc = MAILBOX_DIR + reg_name -+ try: -+ if not os.path.isfile(fileLoc): -+ print(fileLoc, 'not found !') -+ return False -+ with open(fileLoc, 'w') as fd: -+ fd.write(value) -+ except Exception: -+ print("Unable to open " + fileLoc + "file !") -+ return False -+ return True -+ -+ -+def get_value_once(config): -+ try: -+ way = config.get("gettype") -+ int_decode = config.get("int_decode", 16) -+ if way == 'sysfs': -+ loc = config.get("loc") -+ ret, val = read_sysfs(loc) -+ if ret is True: -+ return True, int(val, int_decode) -+ return False, ("sysfs read %s failed. log:%s" % (loc, val)) -+ if way == "i2c": -+ bus = config.get("bus") -+ addr = config.get("loc") -+ offset = config.get("offset", 0) -+ ret, val = wbi2cget(bus, addr, offset) -+ if ret is True: -+ return True, int(val, int_decode) -+ return False, ("i2c read failed. bus:%d , addr:0x%x, offset:0x%x" % (bus, addr, offset)) -+ if way == "io": -+ io_addr = config.get('io_addr') -+ val = io_rd(io_addr) -+ if len(val) != 0: -+ return True, int(val, int_decode) -+ return False, ("io_addr read 0x%x failed" % io_addr) -+ if way == "i2cword": -+ bus = config.get("bus") -+ addr = config.get("loc") -+ offset = config.get("offset") -+ ret, val = wbi2cgetWord(bus, addr, offset) -+ if ret is True: -+ return True, int(val, int_decode) -+ return False, ("i2cword read failed. bus:%d, addr:0x%x, offset:0x%x" % (bus, addr, offset)) -+ if way == "devfile": -+ path = config.get("path") -+ offset = config.get("offset") -+ read_len = config.get("read_len") -+ ret, val_list = dev_file_read(path, offset, read_len) -+ if ret is True: -+ return True, val_list -+ return False, ("devfile read failed. path:%s, offset:0x%x, read_len:%d" % (path, offset, read_len)) -+ if way == 'cmd': -+ cmd = config.get("cmd") -+ ret, val = exec_os_cmd(cmd) -+ if ret: -+ return False, ("cmd read exec %s failed, log: %s" % (cmd, val)) -+ return True, int(val, int_decode) -+ if way == 'file_exist': -+ judge_file = config.get('judge_file', None) -+ if os.path.exists(judge_file): -+ return True, True -+ return True, False -+ return False, "not support read type" -+ except Exception as e: -+ return False, ("get_value_once exception:%s happen" % str(e)) -+ -+ -+def set_value_once(config): -+ try: -+ delay_time = config.get("delay", None) -+ if delay_time is not None: -+ time.sleep(delay_time) -+ -+ way = config.get("gettype") -+ if way == 'sysfs': -+ loc = config.get("loc") -+ value = config.get("value") -+ mask = config.get("mask", 0xff) -+ mask_tuple = (0xff, 0) -+ if mask not in mask_tuple: -+ ret, read_value = read_sysfs(loc) -+ if ret is True: -+ read_value = int(read_value, base=16) -+ value = (read_value & mask) | value -+ else: -+ return False, ("sysfs read %s failed. log:%s" % (loc, read_value)) -+ ret, log = write_sysfs(loc, "0x%02x" % value) -+ if ret is not True: -+ return False, ("sysfs %s write 0x%x failed" % (loc, value)) -+ return True, ("sysfs write 0x%x success" % value) -+ if way == "i2c": -+ bus = config.get("bus") -+ addr = config.get("loc") -+ offset = config.get("offset") -+ value = config.get("value") -+ mask = config.get("mask", 0xff) -+ mask_tuple = (0xff, 0) -+ if mask not in mask_tuple: -+ ret, read_value = wbi2cget(bus, addr, offset) -+ if ret is True: -+ read_value = int(read_value, base=16) -+ value = (read_value & mask) | value -+ else: -+ return False, ("i2c read failed. bus:%d , addr:0x%x, offset:0x%x" % (bus, addr, offset)) -+ ret, log = wbi2cset(bus, addr, offset, value) -+ if ret is not True: -+ return False, ("i2c write bus:%d, addr:0x%x, offset:0x%x, value:0x%x failed" % -+ (bus, addr, offset, value)) -+ return True, ("i2c write bus:%d, addr:0x%x, offset:0x%x, value:0x%x success" % -+ (bus, addr, offset, value)) -+ if way == "io": -+ io_addr = config.get('io_addr') -+ value = config.get('value') -+ mask = config.get("mask", 0xff) -+ mask_tuple = (0xff, 0) -+ if mask not in mask_tuple: -+ read_value = io_rd(io_addr) -+ if read_value is None: -+ return False, ("io_addr 0x%x read failed" % (io_addr)) -+ read_value = int(read_value, base=16) -+ value = (read_value & mask) | value -+ ret = io_wr(io_addr, value) -+ if ret is not True: -+ return False, ("io_addr 0x%x write 0x%x failed" % (io_addr, value)) -+ return True, ("io_addr 0x%x write 0x%x success" % (io_addr, value)) -+ if way == 'i2cword': -+ bus = config.get("bus") -+ addr = config.get("loc") -+ offset = config.get("offset") -+ value = config.get("value") -+ mask = config.get("mask", 0xff) -+ mask_tuple = (0xff, 0) -+ if mask not in mask_tuple: -+ ret, read_value = wbi2cgetWord(bus, addr, offset) -+ if ret is True: -+ read_value = int(read_value, base=16) -+ value = (read_value & mask) | value -+ else: -+ return False, ("i2c read word failed. bus:%d , addr:0x%x, offset:0x%x" % (bus, addr, offset)) -+ ret, log = wbi2csetWord(bus, addr, offset, value) -+ if ret is not True: -+ return False, ("i2cword write bus:%d, addr:0x%x, offset:0x%x, value:0x%x failed" % -+ (bus, addr, offset, value)) -+ return True, ("i2cword write bus:%d, addr:0x%x, offset:0x%x, value:0x%x success" % -+ (bus, addr, offset, value)) -+ if way == "devfile": -+ path = config.get("path") -+ offset = config.get("offset") -+ buf_list = config.get("value") -+ ret, log = dev_file_write(path, offset, buf_list) -+ if ret is True: -+ return True, ("devfile write path:%s, offset:0x%x, buf_list:%s success." % (path, offset, buf_list)) -+ return False, ("devfile read path:%s, offset:0x%x, buf_list:%s failed.log:%s" % -+ (path, offset, buf_list, log)) -+ if way == 'cmd': -+ cmd = config.get("cmd") -+ ret, log = exec_os_cmd(cmd) -+ if ret: -+ return False, ("cmd write exec %s failed, log: %s" % (cmd, log)) -+ return True, ("cmd write exec %s success" % cmd) -+ if way == 'bit_wr': -+ mask = config.get("mask") -+ bit_val = config.get("value") -+ val_config = config.get("val_config") -+ ret, rd_value = get_value_once(val_config) -+ if ret is False: -+ return False, ("bit_wr read failed, log: %s" % rd_value) -+ wr_val = (rd_value & mask) | bit_val -+ val_config["value"] = wr_val -+ ret, log = set_value_once(val_config) -+ if ret is False: -+ return False, ("bit_wr failed, log: %s" % log) -+ return True, ("bit_wr success, log: %s" % log) -+ if way == 'creat_file': -+ file_name = config.get("file") -+ ret, log = exec_os_cmd("touch %s" % file_name) -+ if ret: -+ return False, ("creat file %s failed, log: %s" % (file_name, log)) -+ exec_os_cmd("sync") -+ return True, ("creat file %s success" % file_name) -+ if way == 'remove_file': -+ file_name = config.get("file") -+ ret, log = exec_os_cmd("rm -rf %s" % file_name) -+ if ret: -+ return False, ("remove file %s failed, log: %s" % (file_name, log)) -+ exec_os_cmd("sync") -+ return True, ("remove file %s success" % file_name) -+ return False, "not support write type" -+ except Exception as e: -+ return False, ("set_value_once exception:%s happen" % str(e)) -+ -+ -+def get_value(config): -+ retrytime = 6 -+ for i in range(retrytime): -+ ret, val = get_value_once(config) -+ if ret is True: -+ return True, val -+ time.sleep(0.1) -+ return False, val -+ -+ -+def set_value(config): -+ retrytime = 6 -+ ignore_result_flag = config.get("ignore_result", 0) -+ for i in range(retrytime): -+ ret, log = set_value_once(config) -+ if ret is True: -+ return True, log -+ if ignore_result_flag == 1: -+ return True, log -+ time.sleep(0.1) -+ return False, log -+ -+ -+class CompressedRotatingFileHandler(logging.handlers.RotatingFileHandler): -+ def doRollover(self): -+ """ -+ Do a rollover, as described in __init__(). -+ """ -+ if self.stream: -+ self.stream.close() -+ self.stream = None -+ if self.backupCount > 0: -+ for i in range(self.backupCount - 1, 0, -1): -+ sfn = "%s.%d.gz" % (self.baseFilename, i) -+ dfn = "%s.%d.gz" % (self.baseFilename, i + 1) -+ if os.path.exists(sfn): -+ if os.path.exists(dfn): -+ os.remove(dfn) -+ os.rename(sfn, dfn) -+ dfn = self.baseFilename + ".1.gz" -+ if os.path.exists(dfn): -+ os.remove(dfn) -+ # These two lines below are the only new lines. I commented out the os.rename(self.baseFilename, dfn) and -+ # replaced it with these two lines. -+ with open(self.baseFilename, 'rb') as f_in, gzip.open(dfn, 'wb') as f_out: -+ shutil.copyfileobj(f_in, f_out) -+ self.mode = 'w' -+ self.stream = self._open() -+ -+ -+def getSdkReg(reg): -+ try: -+ cmd = "bcmcmd -t 1 'getr %s ' < /dev/null" % reg -+ ret, result = wb_os_system(cmd) -+ result_t = result.strip().replace("\r", "").replace("\n", "") -+ if ret != 0 or "Error:" in result_t: -+ return False, result -+ patt = r"%s.(.*):(.*)>drivshell" % reg -+ rt = re.findall(patt, result_t, re.S) -+ test = re.findall("=(.*)", rt[0][0])[0] -+ except Exception: -+ return False, 'getsdk register error' -+ return True, test -+ -+ -+def getMacTemp(): -+ result = {} -+ wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") -+ ret, log = wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") -+ if ret: -+ return False, result -+ logs = log.splitlines() -+ for line in logs: -+ if "average" in line: -+ b = re.findall(r'\d+.\d+', line) -+ result["average"] = b[0] -+ elif "maximum" in line: -+ b = re.findall(r'\d+.\d+', line) -+ result["maximum"] = b[0] -+ return True, result -+ -+ -+def getMacTemp_sysfs(mactempconf): -+ temp = -1000000 -+ try: -+ temp_list = [] -+ mac_temp_loc = mactempconf.get("loc", []) -+ mac_temp_flag = mactempconf.get("flag", None) -+ if mac_temp_flag is not None: -+ gettype = mac_temp_flag.get('gettype') -+ okbit = mac_temp_flag.get('okbit') -+ okval = mac_temp_flag.get('okval') -+ if gettype == "io": -+ io_addr = mac_temp_flag.get('io_addr') -+ val = io_rd(io_addr) -+ if val is None: -+ raise Exception("get mac_flag by io failed.") -+ else: -+ bus = mac_temp_flag.get('bus') -+ loc = mac_temp_flag.get('loc') -+ offset = mac_temp_flag.get('offset') -+ ind, val = wbi2cget(bus, loc, offset) -+ if ind is not True: -+ raise Exception("get mac_flag by i2c failed.") -+ val_t = (int(val, 16) & (1 << okbit)) >> okbit -+ if val_t != okval: -+ raise Exception("mac_flag invalid, val_t:%d." % val_t) -+ for loc in mac_temp_loc: -+ temp_s = get_sysfs_value(loc) -+ if isinstance(temp_s, str) and temp_s.startswith("ERR"): -+ raise Exception("get mac temp error. loc:%s" % loc) -+ temp_t = int(temp_s) -+ if temp_t == -1000000: -+ raise Exception("mac temp invalid.loc:%s" % loc) -+ temp_list.append(temp_t) -+ temp_list.sort(reverse=True) -+ temp = temp_list[0] -+ except Exception: -+ return False, temp -+ return True, temp -+ -+def get_format_value(format_str): -+ ast_obj = ast.parse(format_str, mode='eval') -+ visitor = CodeVisitor() -+ visitor.visit(ast_obj) -+ ret = visitor.get_value() -+ return ret -+ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/pmon_syslog.py b/platform/broadcom/sonic-platform-modules-micas/common/script/pmon_syslog.py -new file mode 100755 -index 000000000..8bdceef8c ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/pmon_syslog.py -@@ -0,0 +1,519 @@ -+#!/usr/bin/python3 -+# * onboard interval check -+# * FAN trays -+# * PSU -+# * SFF -+import time -+import syslog -+import traceback -+import glob -+from platform_config import PMON_SYSLOG_STATUS -+ -+PMON_DEBUG_FILE = "/etc/.pmon_syslog_debug_flag" -+debuglevel = 0 -+PMONERROR = 1 -+PMONDEBUG = 2 -+ -+ -+def pmon_debug(s): -+ if PMONDEBUG & debuglevel: -+ syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def pmon_error(s): -+ if PMONERROR & debuglevel: -+ syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+def dev_syslog(s): -+ syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_NOTICE, s) -+ -+ -+# status -+STATUS_PRESENT = 'PRESENT' -+STATUS_ABSENT = 'ABSENT' -+STATUS_OK = 'OK' -+STATUS_NOT_OK = 'NOT OK' -+STATUS_FAILED = 'FAILED' -+ -+ -+class checkBase(object): -+ def __init__(self, path, dev_name, display_name, obj_type, config): -+ self._peroid_syslog = None -+ self._peroid_failed_syslog = None # exception -+ self._preDevStatus = None -+ self._path = path -+ self._name = dev_name -+ self._display_name = display_name -+ self._type = obj_type -+ self._config = config -+ -+ def getCurstatus(self): -+ # get ok/not ok/absent status -+ status, log = self.getPresent() -+ if status == STATUS_PRESENT: -+ # check status -+ property_status, log = self.getStatus() -+ if property_status is not None: -+ status = property_status -+ return status, log -+ -+ def getPresent(self): -+ presentFilepath = self.getPath() -+ try: -+ # get ok/not ok/absent status -+ presentConfig = self._config["present"] -+ mask = presentConfig.get("mask", 0xff) -+ absent_val = presentConfig.get("ABSENT", None) -+ absent_val = absent_val & mask -+ with open(presentFilepath, "r") as fd: -+ retval = fd.read() -+ if int(retval) == absent_val: -+ return STATUS_ABSENT, None -+ return STATUS_PRESENT, None -+ except Exception as e: -+ return STATUS_FAILED, (str(e) + " location[%s]" % presentFilepath) -+ -+ def getStatus(self): -+ if "status" in self._config: -+ statusConfig = self._config["status"] -+ for itemConfig in statusConfig: -+ mask = itemConfig.get("mask", 0xff) -+ ok_val = itemConfig.get("okval", None) -+ ok_val = ok_val & mask -+ Filepath = itemConfig["path"] % self._name -+ try: -+ with open(Filepath, "r") as fd1: -+ retval = fd1.read() -+ if int(retval) != ok_val: -+ return STATUS_NOT_OK, None -+ except Exception as e: -+ return STATUS_FAILED, (str(e) + " location[%s]" % Filepath) -+ return STATUS_OK, None -+ return None, None -+ -+ def getPath(self): -+ return self._path -+ -+ def getName(self): -+ return self._name -+ -+ def getType(self): -+ return self._type -+ -+ def getDisplayName(self): -+ return self._display_name -+ -+ def getnochangedMsgFlag(self): -+ return self._config["nochangedmsgflag"] -+ -+ def getnochangedMsgTime(self): -+ return self._config["nochangedmsgtime"] -+ -+ def getnoprintFirstTimeFlag(self): -+ return self._config["noprintfirsttimeflag"] -+ -+ def checkStatus(self): -+ # syslog msg -+ dev_type = self.getType() -+ display_name = self.getDisplayName() -+ nochangedMsgTime = self.getnochangedMsgTime() -+ getnochangedMsgFlag = self.getnochangedMsgFlag() -+ noprintFirstTimeFlag = self.getnoprintFirstTimeFlag() -+ MSG_IN = '%%PMON-5-' + dev_type + '_PLUG_IN: %s is PRESENT.' -+ MSG_OUT = '%%PMON-5-' + dev_type + '_PLUG_OUT: %s is ABSENT.' -+ MSG_OK = '%%PMON-5-' + dev_type + '_OK: %s is OK.' -+ MSG_NOT_OK = '%%PMON-5-' + dev_type + '_FAILED: %s is NOT OK.' -+ MSG_ABSENT = '%%PMON-5-' + dev_type + '_ABSENT: %s is ABSENT.' -+ MSG_UNKNOWN = '%%PMON-5-' + dev_type + '_UNKNOWN: %s is UNKNOWN.%s' -+ MSG_RECOVER = '%%PMON-5-' + dev_type + '_OK: %s is OK. Recover from ' + dev_type + ' FAILED.' -+ -+ curStatus, log = self.getCurstatus() -+ pmon_debug("%s: current status %s" % (display_name, curStatus)) -+ pmon_debug("%s: pre status %s" % (display_name, self._preDevStatus)) -+ pmon_debug("%s: peroid_syslog %s" % (display_name, self._peroid_syslog)) -+ -+ if curStatus == STATUS_FAILED: -+ # get status failed -+ if self._peroid_failed_syslog is not None: -+ if getnochangedMsgFlag and time.time() - self._peroid_failed_syslog >= nochangedMsgTime: -+ # absent as before for some time, notice -+ dev_syslog(MSG_UNKNOWN % (display_name, log)) -+ self._peroid_failed_syslog = time.time() -+ else: # first time failed -+ dev_syslog(MSG_UNKNOWN % (display_name, log)) -+ self._peroid_failed_syslog = time.time() -+ return -+ self._peroid_failed_syslog = time.time() -+ -+ if self._preDevStatus is None: -+ # 1st time -+ if noprintFirstTimeFlag == 1: -+ self._peroid_syslog = time.time() -+ else: -+ if curStatus == STATUS_PRESENT: -+ # present -+ dev_syslog(MSG_IN % display_name) -+ elif curStatus == STATUS_OK: -+ # ok -+ dev_syslog(MSG_OK % display_name) -+ elif curStatus == STATUS_NOT_OK: -+ # not ok -+ dev_syslog(MSG_NOT_OK % display_name) -+ self._peroid_syslog = time.time() -+ else: -+ # absent -+ dev_syslog(MSG_ABSENT % display_name) -+ self._peroid_syslog = time.time() -+ else: -+ # from 2nd time... -+ if self._preDevStatus == curStatus: -+ # status not changed -+ if self._preDevStatus == STATUS_ABSENT: -+ if self._peroid_syslog is not None: -+ if getnochangedMsgFlag and time.time() - self._peroid_syslog >= nochangedMsgTime: -+ # absent as before for some time, notice -+ dev_syslog(MSG_ABSENT % display_name) -+ self._peroid_syslog = time.time() -+ elif self._preDevStatus == STATUS_NOT_OK: -+ if self._peroid_syslog is not None: -+ if getnochangedMsgFlag and time.time() - self._peroid_syslog >= nochangedMsgTime: -+ # not ok as before for some time, notice -+ dev_syslog(MSG_NOT_OK % display_name) -+ self._peroid_syslog = time.time() -+ else: -+ # status changed -+ if self._preDevStatus == STATUS_ABSENT: -+ if curStatus == STATUS_NOT_OK: -+ # absent -> not ok -+ dev_syslog(MSG_IN % display_name) -+ dev_syslog(MSG_NOT_OK % display_name) -+ self._peroid_syslog = time.time() -+ elif curStatus == STATUS_OK: -+ # absent -> ok -+ dev_syslog(MSG_IN % display_name) -+ dev_syslog(MSG_OK % display_name) -+ else: -+ # absent -> prsent -+ dev_syslog(MSG_IN % display_name) -+ -+ elif self._preDevStatus == STATUS_OK: -+ if curStatus == STATUS_NOT_OK: -+ # ok -> not ok -+ dev_syslog(MSG_NOT_OK % display_name) -+ self._peroid_syslog = time.time() -+ elif curStatus == STATUS_ABSENT: -+ # ok -> absent -+ dev_syslog(MSG_OUT % display_name) -+ self._peroid_syslog = time.time() -+ elif self._preDevStatus == STATUS_PRESENT: -+ # present -> absent -+ dev_syslog(MSG_OUT % display_name) -+ self._peroid_syslog = time.time() -+ else: # not ok -+ if curStatus == STATUS_OK: -+ # not ok -> ok -+ dev_syslog(MSG_RECOVER % display_name) -+ dev_syslog(MSG_OK % display_name) -+ else: -+ # not ok -> absent -+ dev_syslog(MSG_OUT % display_name) -+ self._peroid_syslog = time.time() -+ self._preDevStatus = curStatus -+ -+ -+class checkSfp(checkBase): -+ def __init__(self, path, dev_name, display_name, config): -+ super(checkSfp, self).__init__(path, dev_name, display_name, 'XCVR', config) -+ -+ def getPath(self): -+ super(checkSfp, self).getPath() -+ return self._path -+ -+ def getName(self): -+ super(checkSfp, self).getName() -+ return self._name -+ -+ def getType(self): -+ super(checkSfp, self).getType() -+ return self._type -+ -+ -+class checkSlot(checkBase): -+ def __init__(self, path, dev_name, display_name, config): -+ super(checkSlot, self).__init__(path, dev_name, display_name, 'SLOT', config) -+ -+ def getPath(self): -+ super(checkSlot, self).getPath() -+ return self._path -+ -+ def getName(self): -+ super(checkSlot, self).getName() -+ return self._name -+ -+ def getType(self): -+ super(checkSlot, self).getType() -+ return self._type -+ -+ -+class checkPSU(checkBase): -+ def __init__(self, path, dev_name, display_name, config): -+ super(checkPSU, self).__init__(path, dev_name, display_name, 'PSU', config) -+ -+ def getPath(self): -+ super(checkPSU, self).getPath() -+ return self._path -+ -+ def getName(self): -+ super(checkPSU, self).getName() -+ return self._name -+ -+ def getType(self): -+ super(checkPSU, self).getType() -+ return self._type -+ -+ -+class checkFAN(checkBase): -+ def __init__(self, path, dev_name, display_name, config): -+ super(checkFAN, self).__init__(path, dev_name, display_name, 'FAN', config) -+ -+ def getPath(self): -+ super(checkFAN, self).getPath() -+ return self._path -+ -+ def getName(self): -+ super(checkFAN, self).getName() -+ return self._name -+ -+ def getType(self): -+ super(checkFAN, self).getType() -+ return self._type -+ -+ -+class platformSyslog(): -+ def __init__(self): -+ self.__sfp_checklist = [] -+ self.__fan_checklist = [] -+ self.__psu_checklist = [] -+ self.__slot_checklist = [] -+ self.__temp_checklist = [] -+ self.temps_peroid_syslog = {} -+ self.normal_status = 0 -+ self.warning_status = 1 -+ self.critical_status = 2 -+ self.poweron_flag = 0 -+ -+ self.pmon_syslog_config = PMON_SYSLOG_STATUS.copy() -+ self.__pollingtime = self.pmon_syslog_config.get('polling_time', 3) -+ -+ tmpconfig = self.pmon_syslog_config.get('sffs', None) -+ if tmpconfig is not None: -+ preset_item = tmpconfig.get("present", {}) -+ path = preset_item.get("path", []) -+ for location in path: -+ if '*' not in location: -+ pmon_error("sff location config error: %s" % location) -+ continue -+ dev_name_index = 0 -+ loc_split_list = location.split('/') -+ for i, item in enumerate(loc_split_list): -+ if '*' in item: -+ dev_name_index = i -+ break -+ locations = glob.glob(location) -+ for dev_path in locations: -+ dev_name_list = dev_path.split('/') -+ # explame:get eth1 from /sys_switch/transceiver/eth1/present -+ dev_name = dev_name_list[dev_name_index] -+ dev_name_alias = tmpconfig.get("alias", {}) -+ display_name = dev_name_alias.get(dev_name, dev_name) -+ dev = checkSfp(dev_path, dev_name, display_name, tmpconfig) -+ self.__sfp_checklist.append(dev) -+ -+ tmpconfig = self.pmon_syslog_config.get('fans', None) -+ if tmpconfig is not None: -+ preset_item = tmpconfig.get("present", {}) -+ path = preset_item.get("path", []) -+ for location in path: -+ if '*' not in location: -+ pmon_error("fan location config error: %s" % location) -+ continue -+ dev_name_index = 0 -+ loc_split_list = location.split('/') -+ for i, item in enumerate(loc_split_list): -+ if '*' in item: -+ dev_name_index = i -+ break -+ locations = glob.glob(location) -+ for dev_path in locations: -+ dev_name_list = dev_path.split('/') -+ dev_name = dev_name_list[dev_name_index] -+ dev_name_alias = tmpconfig.get("alias", {}) -+ display_name = dev_name_alias.get(dev_name, dev_name) -+ dev = checkFAN(dev_path, dev_name, display_name, tmpconfig) -+ self.__fan_checklist.append(dev) -+ -+ tmpconfig = self.pmon_syslog_config.get('psus', None) -+ if tmpconfig is not None: -+ preset_item = tmpconfig.get("present", {}) -+ path = preset_item.get("path", []) -+ for location in path: -+ if '*' not in location: -+ pmon_error("psu location config error: %s" % location) -+ continue -+ dev_name_index = 0 -+ loc_split_list = location.split('/') -+ for i, item in enumerate(loc_split_list): -+ if '*' in item: -+ dev_name_index = i -+ break -+ locations = glob.glob(location) -+ for dev_path in locations: -+ dev_name_list = dev_path.split('/') -+ dev_name = dev_name_list[dev_name_index] -+ dev_name_alias = tmpconfig.get("alias", {}) -+ display_name = dev_name_alias.get(dev_name, dev_name) -+ dev = checkPSU(dev_path, dev_name, display_name, tmpconfig) -+ self.__psu_checklist.append(dev) -+ -+ tmpconfig = self.pmon_syslog_config.get('slots', None) -+ if tmpconfig is not None: -+ preset_item = tmpconfig.get("present", {}) -+ path = preset_item.get("path", []) -+ for location in path: -+ if '*' not in location: -+ pmon_error("slot location config error: %s" % location) -+ continue -+ dev_name_index = 0 -+ loc_split_list = location.split('/') -+ for i, item in enumerate(loc_split_list): -+ if '*' in item: -+ dev_name_index = i -+ break -+ locations = glob.glob(location) -+ for dev_path in locations: -+ dev_name_list = dev_path.split('/') -+ dev_name = dev_name_list[dev_name_index] -+ dev_name_alias = tmpconfig.get("alias", {}) -+ display_name = dev_name_alias.get(dev_name, dev_name) -+ dev = checkSlot(dev_path, dev_name, display_name, tmpconfig) -+ self.__slot_checklist.append(dev) -+ -+ tmpconfig = self.pmon_syslog_config.get('temps', None) -+ if tmpconfig is not None: -+ self.__temp_checklist = tmpconfig.get('temps_list', []) -+ self.__temps_pollingseconds = tmpconfig.get('over_temps_polling_seconds', None) -+ -+ def checkTempStaus(self, temp_item): -+ temp_name = temp_item.get('name', None) -+ input_path = temp_item.get('input_path', None) -+ warning_temp = temp_item.get('warning', None) -+ critical_temp = temp_item.get('critical', None) -+ input_accuracy = temp_item.get('input_accuracy', None) -+ if temp_name is None or input_path is None or warning_temp is None or critical_temp is None: -+ dev_syslog('%%PMON-5-TEMP_NOTICE: get temperature config parament failed.') -+ return -+ try: -+ locations = glob.glob(input_path) -+ with open(locations[0], "r") as fd: -+ input_temp = fd.read() -+ input_temp = float(input_temp) / float(input_accuracy) -+ -+ if 'time' not in temp_item: -+ temp_item['time'] = time.time() -+ temp_item['status'] = self.normal_status -+ if float(input_temp) >= float(warning_temp): -+ if float(input_temp) >= float(critical_temp): -+ if time.time() - \ -+ temp_item['time'] >= self.__temps_pollingseconds or temp_item['status'] != self.critical_status: -+ dev_syslog('%%PMON-5-TEMP_HIGH: %s temperature %sC is larger than max critical threshold %sC.' -+ % (temp_name, input_temp, critical_temp)) -+ temp_item['status'] = self.critical_status -+ temp_item['time'] = time.time() -+ else: -+ if time.time() - \ -+ temp_item['time'] >= self.__temps_pollingseconds or temp_item['status'] != self.warning_status: -+ dev_syslog('%%PMON-5-TEMP_HIGH: %s temperature %sC is larger than max warning threshold %sC.' -+ % (temp_name, input_temp, warning_temp)) -+ temp_item['status'] = self.warning_status -+ temp_item['time'] = time.time() -+ else: -+ pmon_debug( -+ "%s temperature %sC is in range [%s, %s]" % -+ (temp_name, input_temp, warning_temp, critical_temp)) -+ temp_item['status'] = self.normal_status -+ temp_item['time'] = time.time() -+ except Exception as e: -+ dev_syslog('%%PMON-5-TEMP_NOTICE: Cannot get %s temperature. Exception log: %s' % (temp_name, str(e))) -+ return -+ -+ def sysfs_precondition_check(self, check_module, check_project): -+ try: -+ tmpconfig = self.pmon_syslog_config.get(check_module, None) -+ if tmpconfig is not None: -+ check_list = tmpconfig.get(check_project, []) -+ for check_item in check_list: -+ location = check_item.get("path", None) -+ ok_val = check_item.get("ok_val", None) -+ mask = check_item.get("mask", 0xff) -+ ok_val = ok_val & mask -+ locations = glob.glob(location) -+ for power_path in locations: -+ with open(power_path, "r") as fd: -+ retval = fd.read() -+ if int(retval) != ok_val: -+ return -+ self.poweron_flag = 1 -+ except Exception as e: -+ dev_syslog('%%PMON-5-TEMP_NOTICE: Cannot check power status. Exception log: %s' % str(e)) -+ return -+ -+ def updateSysDeviceStatus(self): -+ if self.poweron_flag == 1: -+ for dev in self.__sfp_checklist: -+ dev.checkStatus() -+ else: -+ self.sysfs_precondition_check('sffs', 'power') -+ -+ for dev in self.__fan_checklist: -+ dev.checkStatus() -+ for dev in self.__psu_checklist: -+ dev.checkStatus() -+ for dev in self.__slot_checklist: -+ dev.checkStatus() -+ for temp_item in self.__temp_checklist: -+ self.checkTempStaus(temp_item) -+ -+ def getPollingtime(self): -+ return self.__pollingtime -+ -+ def debug_init(self): -+ global debuglevel -+ try: -+ with open(PMON_DEBUG_FILE, "r") as fd: -+ value = fd.read() -+ debuglevel = int(value) -+ except Exception: -+ debuglevel = 0 -+ -+ def doWork(self): -+ try: -+ self.debug_init() -+ self.updateSysDeviceStatus() -+ except Exception as e: -+ MSG_EXCEPTION = '%%PMON-5-NOTICE: Exception happened! info:%s' % str(e) -+ pmon_error(MSG_EXCEPTION % traceback.format_exc()) -+ -+ -+def run(): -+ platform = platformSyslog() -+ while True: -+ platform.doWork() -+ time.sleep(platform.getPollingtime()) -+ -+ -+if __name__ == '__main__': -+ run() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_cause.py b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_cause.py -new file mode 100755 -index 000000000..2f125c508 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_cause.py -@@ -0,0 +1,183 @@ -+#!/usr/bin/python3 -+# -*- coding: UTF-8 -*- -+import sys -+import os -+import time -+import syslog -+from platform_util import get_value, set_value, exec_os_cmd, wb_os_system -+from platform_config import REBOOT_CAUSE_PARA -+ -+REBOOT_CAUSE_DEBUG_FILE = "/etc/.reboot_cause_debug" -+REBOOT_CAUSE_STARTED_FLAG = "/tmp/.reboot_cause_started_flag" -+ -+debuglevel = 0 -+ -+ -+def record_syslog_debug(s): -+ if debuglevel: -+ syslog.openlog("REBOOT_CAUSE_DEBUG", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def record_syslog(s): -+ syslog.openlog("REBOOT_CAUSE", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_WARNING, s) -+ -+ -+class RebootCause(): -+ def __init__(self): -+ self.reboot_cause_para = REBOOT_CAUSE_PARA.copy() -+ self.reboot_cause_list = self.reboot_cause_para.get('reboot_cause_list', None) -+ self.other_reboot_cause_record = self.reboot_cause_para.get('other_reboot_cause_record', None) -+ -+ def debug_init(self): -+ global debuglevel -+ if os.path.exists(REBOOT_CAUSE_DEBUG_FILE): -+ debuglevel = 1 -+ else: -+ debuglevel = 0 -+ -+ def monitor_point_check(self, item): -+ try: -+ gettype = item.get('gettype', None) -+ okval = item.get('okval', None) -+ compare_mode = item.get('compare_mode', "equal") -+ ret, value = get_value(item) -+ if ret is True: -+ if compare_mode == "equal": -+ if value == okval: -+ return True -+ elif compare_mode == "great": -+ if value > okval: -+ return True -+ elif compare_mode == "ignore": -+ return True -+ else: -+ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: compare_mode %s not match error.' % (compare_mode)) -+ else: -+ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: base point check type:%s not support.' % gettype) -+ except Exception as e: -+ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: base point check error. msg: %s.' % (str(e))) -+ return False -+ -+ def reboot_cause_record(self, item_list): -+ RET = {"RETURN_KEY1": 0} -+ try: -+ for item in item_list: -+ record_type = item.get('record_type', None) -+ if record_type == 'file': -+ file_mode = item.get('mode', None) -+ file_log = item.get('log', None) -+ file_path = item.get('path', None) -+ file_max_size = item.get('file_max_size', 0) -+ -+ if file_path is None: -+ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: record type is file, but path is none.') -+ continue -+ -+ if file_max_size > 0: -+ file_size = 0 -+ if os.path.exists(file_path): -+ file_size = os.path.getsize(file_path) // file_max_size -+ if file_size >= 1: -+ reocrd_cmd = "mv %s %s_bak" % (file_path, file_path) -+ status, output = exec_os_cmd(reocrd_cmd) -+ if status: -+ record_syslog( -+ '%%REBOOT_CAUSE-3-EXCEPTION: exec cmd %s failed, %s' % -+ (reocrd_cmd, output)) -+ -+ if file_mode == 'cover': -+ operate_cmd = ">" -+ elif file_mode == 'add': -+ operate_cmd = ">>" -+ else: -+ RET["RETURN_KEY1"] = -1 -+ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: file record mode:%s not support.' % file_mode) -+ continue -+ -+ create_dir = "mkdir -p %s" % os.path.dirname(file_path) -+ status, ret_t = wb_os_system(create_dir) -+ if status != 0: -+ RET["RETURN_KEY1"] = -1 -+ record_syslog( -+ '%%REBOOT_CAUSE-3-EXCEPTION: create %s failed, msg: %s' % -+ (os.path.dirname(file_path), ret_t)) -+ continue -+ -+ status, date = wb_os_system("date") -+ if status != 0 or len(date) == 0: -+ RET["RETURN_KEY1"] = -1 -+ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: get date failed.') -+ continue -+ -+ reocrd_cmd = "echo %s %s %s %s" % (file_log, date, operate_cmd, file_path) -+ status, ret_t = wb_os_system(reocrd_cmd) -+ if status != 0: -+ RET["RETURN_KEY1"] = -1 -+ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: get date failed, msg: %s' % ret_t) -+ continue -+ wb_os_system('sync') -+ else: -+ RET["RETURN_KEY1"] = -1 -+ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: record_type:%s not support.' % record_type) -+ continue -+ except Exception as e: -+ RET["RETURN_KEY1"] = -1 -+ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: reboot cause record error. msg: %s.' % (str(e))) -+ if RET["RETURN_KEY1"] == 0: -+ return True -+ return False -+ -+ def reboot_cause_check(self): -+ try: -+ reboot_cause_flag = False -+ if self.reboot_cause_list is None: -+ record_syslog_debug('%%REBOOT_CAUSE-6-DEBUG: reboot cause check config not found') -+ return -+ for item in self.reboot_cause_list: -+ name = item.get('name', None) -+ monitor_point = item.get('monitor_point', None) -+ record = item.get('record', None) -+ finish_operation_list = item.get('finish_operation', []) -+ if name is None or monitor_point is None or record is None: -+ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: reboot cause check get config failed.name:%s, monitor_point:%s, record:%s' % -+ (name, monitor_point, record)) -+ return -+ ret = self.monitor_point_check(monitor_point) -+ if ret is True: -+ record_syslog_debug('%%REBOOT_CAUSE-6-DEBUG: %s reboot cause is happen' % name) -+ self.reboot_cause_record(record) -+ reboot_cause_flag = True -+ for finish_operation_item in finish_operation_list: -+ ret, log = set_value(finish_operation_item) -+ if ret is False: -+ log = "%%REBOOT_CAUSE-3-EXCEPTION: " + log -+ record_syslog(log) -+ -+ if reboot_cause_flag is False and self.other_reboot_cause_record is not None: -+ record_syslog_debug('%%REBOOT_CAUSE-6-DEBUG: other reboot cause is happen') -+ self.reboot_cause_record(self.other_reboot_cause_record) -+ except Exception as e: -+ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: reboot cause check error. msg: %s.' % (str(e))) -+ return -+ -+ def run(self): -+ try: -+ self.debug_init() -+ if os.path.exists(REBOOT_CAUSE_STARTED_FLAG): -+ record_syslog_debug( -+ '%%REBOOT_CAUSE-6-DEBUG: Reboot cause has been started and will not be started again') -+ sys.exit(0) -+ self.reboot_cause_check() -+ wb_os_system("touch %s" % REBOOT_CAUSE_STARTED_FLAG) -+ wb_os_system("sync") -+ time.sleep(5) -+ sys.exit(0) -+ except Exception as e: -+ record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: %s.' % (str(e))) -+ -+ -+if __name__ == '__main__': -+ reboot_cause = RebootCause() -+ reboot_cause.run() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_ctrl.py b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_ctrl.py -new file mode 100755 -index 000000000..17d3f5902 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_ctrl.py -@@ -0,0 +1,150 @@ -+#!/usr/bin/env python3 -+# -*- coding: UTF-8 -*- -+import time -+import syslog -+import click -+from platform_util import write_sysfs, wbi2cset, io_wr, wbi2csetWord -+from platform_config import REBOOT_CTRL_PARAM -+ -+ -+REBOOTCTLDEBUG = 0 -+ -+CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} -+ -+ -+class AliasedGroup(click.Group): -+ def get_command(self, ctx, cmd_name): -+ rv = click.Group.get_command(self, ctx, cmd_name) -+ if rv is not None: -+ return rv -+ matches = [x for x in self.list_commands(ctx) -+ if x.startswith(cmd_name)] -+ if not matches: -+ return None -+ if len(matches) == 1: -+ return click.Group.get_command(self, ctx, matches[0]) -+ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) -+ return None -+ -+ -+def rebootctrlwarning(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("REBOOTCTRL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_WARNING, s) -+ -+ -+def rebootctrlcritical(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("REBOOTCTRL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_CRIT, s) -+ -+ -+def rebootctrlerror(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("REBOOTCTRL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+def rebootctrldebug(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ if REBOOTCTLDEBUG == 1: -+ syslog.openlog("REBOOTCTRL", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+class RebootCtrl(): -+ def __init__(self): -+ self.config = REBOOT_CTRL_PARAM.copy() -+ -+ def set_value(self, config, val): -+ way = config.get("gettype") -+ if way == 'sysfs': -+ loc = config.get("loc") -+ value = config.get(val) -+ rebootctrldebug("sysfs type.loc:0x%x, value:0x%x" % (loc, value)) -+ return write_sysfs(loc, "0x%02x" % value) -+ if way == "i2c": -+ bus = config.get("bus") -+ addr = config.get("loc") -+ offset = config.get("offset") -+ value = config.get(val) -+ rebootctrldebug("i2c type.bus:0x%x, addr:0x%x, offset:0x%x, value:0x%x" % (bus, addr, offset, value)) -+ return wbi2cset(bus, addr, offset, value) -+ if way == "io": -+ io_addr = config.get('io_addr') -+ value = config.get(val) -+ rebootctrldebug("io type.io_addr:0x%x, value:0x%x" % (io_addr, value)) -+ ret = io_wr(io_addr, value) -+ if ret is not True: -+ return False, ("write 0x%x failed" % io_addr) -+ return True, ("write 0x%x success" % io_addr) -+ if way == 'i2cword': -+ bus = config.get("bus") -+ addr = config.get("loc") -+ offset = config.get("offset") -+ value = config.get(val) -+ rebootctrldebug("i2cword type.bus:0x%x, addr:0x%x, offset:0x%x, value:0x%x" % (bus, addr, offset, value)) -+ return wbi2csetWord(bus, addr, offset, value) -+ return False, "unsupport way: %s" % way -+ -+ def reset_operate(self, config): -+ ret, log = self.set_value(config, "rst_val") -+ rst_delay = config.get("rst_delay", 0) -+ time.sleep(rst_delay) -+ return ret, log -+ -+ def unlock_reset_operate(self, config): -+ ret, log = self.set_value(config, "unlock_rst_val") -+ unlock_rst_delay = config.get("unlock_rst_delay", 0) -+ time.sleep(unlock_rst_delay) -+ return ret, log -+ -+ def do_rebootctrl(self, option): -+ if self.config is None: -+ rebootctrlerror("Reset failed, REBOOT_CTRL_PARAM cfg get failed.") -+ return -+ try: -+ name_conf = self.config.get(option, None) -+ if name_conf is None: -+ print("Reset %s not support" % option) -+ return -+ try: -+ click.confirm("Are you sure you want to reset " + option + "?", -+ default=False, abort=True, show_default=True) -+ except Exception as e: -+ print("Aborted, msg: %s" % str(e)) -+ return -+ print("Reset %s start" % option) -+ ret, log = self.reset_operate(name_conf) -+ if ret is False: -+ rebootctrlerror(log) -+ print("Reset %s failed" % option) -+ return -+ if "unlock_rst_val" in name_conf: -+ ret, log = self.unlock_reset_operate(name_conf) -+ if ret is False: -+ rebootctrlerror(log) -+ print("%s unlock reset failed" % option) -+ return -+ print("Reset %s success" % option) -+ except Exception: -+ rebootctrlerror("do_rebootctrl Exception error") -+ return -+ -+ -+@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) -+def main(): -+ '''reboot_ctrl reset [option]''' -+ -+ -+@main.command() -+@click.argument('option', required=True) -+def reset(option): -+ '''reset device''' -+ rebootctrldebug("reboot ctrl option %s" % option) -+ rebootctrl = RebootCtrl() -+ rebootctrl.do_rebootctrl(option) -+ -+ -+if __name__ == '__main__': -+ main() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/sensors b/platform/broadcom/sonic-platform-modules-micas/common/script/sensors -new file mode 100755 -index 000000000..a2c72b123 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/sensors -@@ -0,0 +1,8 @@ -+#!/bin/bash -+#docker exec -i pmon sensors "$@" -+ -+ -+#To probe sensors not part of lm-sensors -+if [ -r /usr/local/bin/platform_sensors.py ]; then -+ python /usr/local/bin/platform_sensors.py -+fi -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/set_eth_mac.py b/platform/broadcom/sonic-platform-modules-micas/common/script/set_eth_mac.py -new file mode 100755 -index 000000000..3e445a3ac ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/set_eth_mac.py -@@ -0,0 +1,274 @@ -+#!/usr/bin/env python -+# -*- coding: UTF-8 -*- -+import syslog -+import os -+import re -+import eepromutil.onietlv as ot -+from eepromutil.fru import ipmifru -+from platform_config import STARTMODULE, SET_MAC_CONF -+from platform_util import byteTostr, dev_file_read, exec_os_cmd -+ -+ -+STANDARD_MAC_LEN = 12 -+SETMAC_DEBUG_FILE = "/etc/.setmac_debug_flag" -+ -+SETMACERROR = 1 -+SETMACDEBUG = 2 -+debuglevel = 0 -+ -+cfg_prefix = "iface" -+mac_prefix = "hwaddress ether" -+ -+def setmac_debug(s): -+ if SETMACDEBUG & debuglevel: -+ syslog.openlog("SETMAC", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_INFO, s) -+ -+ -+def setmac_error(s): -+ if SETMACERROR & debuglevel: -+ syslog.openlog("SETMAC", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+def setmac_info(s): -+ syslog.openlog("SETMAC", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_INFO, s) -+ -+ -+def debug_init(): -+ global debuglevel -+ try: -+ with open(SETMAC_DEBUG_FILE, "r") as fd: -+ value = fd.read() -+ debuglevel = int(value) -+ except Exception: -+ debuglevel = 0 -+ -+ -+def decode_mac(encodedata): -+ if encodedata == None: -+ return None -+ ret = ":".join("%02x" % ord(data) for data in encodedata) -+ return ret.upper() -+ -+ -+def validate_mac(value): -+ if value is None: -+ setmac_error("mac is none") -+ return False -+ if value.find('-') != -1: -+ pattern = re.compile(r"^\s*([0-9a-fA-F]{2,2}-){5,5}[0-9a-fA-F]{2,2}\s*$") -+ temp_value = value.replace("-", "") -+ elif value.find(':') != -1: -+ pattern = re.compile(r"^\s*([0-9a-fA-F]{2,2}:){5,5}[0-9a-fA-F]{2,2}\s*$") -+ temp_value = value.replace(":", "") -+ else: -+ pattern = re.compile(r"^\s*([0-9a-fA-F]{2,2}){5,5}[0-9a-fA-F]{2,2}\s*$") -+ temp_value = value -+ if not pattern.match(value): -+ setmac_error("mac format error") -+ return False -+ if len(temp_value) != STANDARD_MAC_LEN: -+ setmac_error("mac len error len:%d" % len(temp_value)) -+ return False -+ if temp_value == "000000000000": -+ setmac_error("illegal zero mac") -+ return False -+ if int(temp_value, 16) >> 40 & 1 == 1: -+ setmac_error("illegal mac") -+ return False -+ setmac_debug("mac validate success") -+ return True -+ -+ -+def get_onie_eeprom(eeprom): -+ try: -+ onietlv = ot.onie_tlv() -+ rets = onietlv.decode(eeprom) -+ setmac_debug("%-20s %-5s %-5s %-20s" % ("TLV name", "Code", "lens", "Value")) -+ for item in rets: -+ if item["code"] == 0xfd: -+ setmac_debug("%-20s 0x%-02X %-5s" % (item["name"], item["code"], item["lens"])) -+ else: -+ setmac_debug("%-20s 0x%-02X %-5s %-20s" % (item["name"], item["code"], item["lens"], item["value"])) -+ except Exception as e: -+ setmac_error(str(e)) -+ return False, str(e) -+ return True, rets -+ -+ -+def get_fru_eeprom_info(eeprom): -+ try: -+ fru = ipmifru() -+ fru.decodeBin(eeprom) -+ except Exception as e: -+ setmac_error(str(e)) -+ return False, str(e) -+ return True, fru -+ -+ -+def get_mac_from_eeprom(eeprom_conf): -+ name = eeprom_conf.get("name") -+ e2_type = eeprom_conf.get("e2_type") -+ e2_path = eeprom_conf.get("e2_path") -+ e2_size = eeprom_conf.get("e2_size", 256) -+ mac_location = eeprom_conf.get("mac_location", {}) -+ e2_mac = None -+ -+ support_e2_type = ("fru", "onie_tlv") -+ if e2_type not in support_e2_type: -+ msg = "Unsupport e2 type: %s" % e2_type -+ return False, msg -+ -+ setmac_debug("===================%s===================" % name) -+ ret, binval_bytes = dev_file_read(e2_path, 0, e2_size) -+ if ret is False: -+ msg = "eeprom read error, eeprom path: %s, msg: %s" % (e2_path, binval_bytes) -+ return False, msg -+ binval = byteTostr(binval_bytes) -+ -+ # onie_tlv -+ if e2_type == "onie_tlv": -+ status, eeprom_info = get_onie_eeprom(binval) -+ if status is False: -+ msg = "get_onie_eeprom failed, msg: %s" % (eeprom_info) -+ return False, msg -+ -+ field = mac_location.get("field", "") -+ for eeprom_info_item in eeprom_info: -+ if eeprom_info_item.get("name") == field: -+ e2_mac = eeprom_info_item.get("value") -+ break -+ if e2_mac is None: -+ msg = "get_onie_eeprom mac address failed, e2_mac is None" -+ return False, msg -+ return True, e2_mac -+ -+ # fru -+ status, eeprom_info = get_fru_eeprom_info(binval) -+ if status is False: -+ msg = "get_fru_eeprom_info failed, msg: %s" % (eeprom_info) -+ return False, msg -+ -+ area = mac_location.get("area", "") -+ field = mac_location.get("field", "") -+ fru_area = getattr(eeprom_info, area, None) -+ fru_field = getattr(fru_area, field, None) -+ e2_mac = decode_mac(fru_field) -+ if e2_mac is None: -+ msg = "decode_mac failed, area: %s, field: %s, value: %s" % (area, field, fru_field) -+ return False, msg -+ return True, e2_mac -+ -+ -+def read_mac_from_config_file(ifcfg): -+ ifcfg_file_path = ifcfg.get("ifcfg_file_path") -+ if not os.path.exists(ifcfg_file_path): -+ msg = "%s not exist" % ifcfg_file_path -+ return False, msg -+ try: -+ fd = open(ifcfg_file_path, 'r') -+ for line in reversed(fd.readlines()): -+ if line.strip().startswith(mac_prefix): -+ mac = line.strip().replace(mac_prefix, "").strip() -+ return True, mac -+ except Exception as e: -+ setmac_error(str(e)) -+ return False, str(e) -+ return False, "mac address not found in %s" % ifcfg_file_path -+ -+ -+def set_e2_mac_to_config_file(eth_name, mac, ifcfg): -+ try: -+ ifcfg_file_path = ifcfg.get("ifcfg_file_path") -+ cfg_file_dir = os.path.dirname(ifcfg_file_path) -+ if not os.path.exists(cfg_file_dir): -+ cmd = "mkdir -p %s" % cfg_file_dir -+ setmac_info("Create interfaces config directory: %s" % cfg_file_dir) -+ os.system(cmd) -+ os.system("sync") -+ wr_val = cfg_prefix + " %s\n" % eth_name -+ wr_val += " %s %s\n" % (mac_prefix, mac) -+ with open(ifcfg_file_path, "w") as fd: -+ fd.write(wr_val) -+ os.system("sync") -+ setmac_info("Create interfaces config: %s with mac address: %s" % (ifcfg_file_path, mac)) -+ return True -+ except Exception as e: -+ setmac_error(str(e)) -+ return False -+ -+def get_eth_current_mac(eth_name): -+ get_mac_cmd = "ifconfig %s |grep ether |awk '{print $2}'" % eth_name -+ status, output = exec_os_cmd(get_mac_cmd) -+ if status or len(output) == 0: -+ msg = "get mac exec cmd : %s fail, msg: %s" % (get_mac_cmd, output) -+ setmac_error(msg) -+ return False, msg -+ mac = output.replace("\n", "").upper() -+ return True, mac -+ -+def set_eth_mac(eth_name, mac): -+ set_mac_cmd = "ifconfig %s hw ether %s" % (eth_name, mac) -+ status, output = exec_os_cmd(set_mac_cmd) -+ if status: -+ setmac_error("run cmd: %s fail, msg: %s" % (set_mac_cmd, output)) -+ return False -+ setmac_info("ifconfig %s with mac address: %s success" % (eth_name, mac)) -+ return True -+ -+ -+def doSetmac(): -+ if STARTMODULE.get('set_eth_mac', 0) == 0: -+ setmac_debug("set_eth_mac config not set") -+ return -+ -+ try: -+ if SET_MAC_CONF is None: -+ setmac_debug("set_mac_conf in none") -+ return -+ -+ if len(SET_MAC_CONF) == 0: -+ setmac_debug("set_mac_conf list is none") -+ return -+ -+ for setmac_item in SET_MAC_CONF: -+ eth_name = setmac_item.get("eth_name") -+ e2_name = setmac_item.get("e2_name", "") -+ ifcfg = setmac_item.get("ifcfg") -+ if eth_name is None or ifcfg is None: -+ setmac_error("set_mac_conf error, eth_name or ifcfg is None") -+ continue -+ -+ # decode mac by eeprom -+ status, e2_mac = get_mac_from_eeprom(setmac_item) -+ if status is False: -+ setmac_error("get mac from %s eeprom fail, msg: %s" % (e2_name, e2_mac)) -+ continue -+ status = validate_mac(e2_mac) -+ if status is False: -+ setmac_error("e2_mac: %s invalid" % e2_mac) -+ continue -+ setmac_debug("get mac from %s eeprom info success, mac: %s" % (e2_name, e2_mac)) -+ -+ # read config file mac address -+ status, cfg_mac = read_mac_from_config_file(ifcfg) -+ setmac_debug("read_mac_from_config_file, status: %s, cfg_mac: %s" % (status, cfg_mac)) -+ if status is False or cfg_mac != e2_mac: -+ set_e2_mac_to_config_file(eth_name, e2_mac, ifcfg) -+ # check current eth mac -+ status, current_mac = get_eth_current_mac(eth_name) -+ if status is False: -+ setmac_error("get %s current mac fail" % eth_name) -+ continue -+ setmac_debug("current_mac:%s len:%d" % (current_mac, len(current_mac))) -+ if current_mac != e2_mac: -+ set_eth_mac(eth_name, e2_mac) -+ except Exception as e: -+ setmac_error(str(e)) -+ return -+ -+ -+if __name__ == '__main__': -+ debug_init() -+ doSetmac() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/sfp_highest_temperatue.py b/platform/broadcom/sonic-platform-modules-micas/common/script/sfp_highest_temperatue.py -new file mode 100755 -index 000000000..4dd98f3a3 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/sfp_highest_temperatue.py -@@ -0,0 +1,148 @@ -+#!/usr/bin/python3 -+import os -+import importlib.machinery -+import time -+import syslog -+import subprocess -+import fcntl -+ -+sfp_temperature_file = "/tmp/highest_sff_temp" -+ -+SFP_TEMP_DEBUG_FILE = "/etc/.sfp_temp_debug_flag" -+SFP_TEMP_RECORD_DEBUG = 1 -+SFP_TEMP_RECORD_ERROR = 2 -+debuglevel = 0 -+ -+ -+def sfp_temp_debug(s): -+ if SFP_TEMP_RECORD_DEBUG & debuglevel: -+ syslog.openlog("SFP_TEMP_DEBUG", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def sfp_temp_error(s): -+ if SFP_TEMP_RECORD_ERROR & debuglevel: -+ syslog.openlog("SFP_TEMP_ERROR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+pidfile = None -+ -+ -+def file_rw_lock(): -+ global pidfile -+ pidfile = open(sfp_temperature_file, "r") -+ try: -+ fcntl.flock(pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB) -+ sfp_temp_debug("file lock success") -+ return True -+ except Exception: -+ if pidfile is not None: -+ pidfile.close() -+ pidfile = None -+ return False -+ -+ -+def file_rw_unlock(): -+ try: -+ global pidfile -+ -+ if pidfile is not None: -+ fcntl.flock(pidfile, fcntl.LOCK_UN) -+ pidfile.close() -+ pidfile = None -+ sfp_temp_debug("file unlock success") -+ else: -+ sfp_temp_debug("pidfile is invalid, do nothing") -+ return True -+ except Exception as e: -+ sfp_temp_error("file unlock err, msg:%s" % (str(e))) -+ return False -+ -+ -+def get_sfp_highest_temperature(): -+ highest_temperature = 0 -+ platform_sfputil = None -+ -+ sfputil_dir = "/usr/share/sonic/device/" -+ try: -+ if not os.path.exists(sfputil_dir): -+ sfputil_dir = "/usr/share/sonic/platform/" -+ sfputil_path = sfputil_dir + "/plugins/sfputil.py" -+ else: -+ cmd = "cat /host/machine.conf | grep onie_build_platform" -+ ret, output = subprocess.getstatusoutput(cmd) -+ if ret != 0: -+ sfp_temp_error("cmd: %s execution fail, output: %s" % (cmd, output)) -+ -+ onie_platform = output.split("=")[1] -+ sfputil_path = sfputil_dir + onie_platform + "/plugins/sfputil.py" -+ -+ module = importlib.machinery.SourceFileLoader("sfputil", sfputil_path).load_module() -+ platform_sfputil_class = getattr(module, "SfpUtil") -+ platform_sfputil = platform_sfputil_class() -+ -+ temperature = platform_sfputil.get_highest_temperature() -+ highest_temperature = int(temperature) * 1000 -+ except Exception as e: -+ sfp_temp_error("get sfp temperature error, msg:%s" % str(e)) -+ highest_temperature = -9999000 -+ -+ return highest_temperature -+ -+ -+def write_sfp_highest_temperature(temperature): -+ -+ loop = 1000 -+ ret = False -+ try: -+ if os.path.exists(sfp_temperature_file) is False: -+ with open(sfp_temperature_file, 'w') as sfp_f: -+ pass -+ for i in range(0, loop): -+ ret = file_rw_lock() -+ if ret is True: -+ break -+ time.sleep(0.001) -+ -+ if ret is False: -+ sfp_temp_error("take file lock timeout") -+ return -+ -+ with open(sfp_temperature_file, 'w') as sfp_f: -+ sfp_f.write("%s\n" % str(temperature)) -+ -+ file_rw_unlock() -+ return -+ except Exception as e: -+ sfp_temp_error("write sfp temperature error, msg:%s" % str(e)) -+ file_rw_unlock() -+ return -+ -+ -+def debug_init(): -+ global debuglevel -+ -+ try: -+ with open(SFP_TEMP_DEBUG_FILE, "r") as fd: -+ value = fd.read() -+ debuglevel = int(value) -+ except Exception: -+ debuglevel = 0 -+ -+ -+def main(): -+ while True: -+ debug_init() -+ temperature = 0 -+ try: -+ temperature = get_sfp_highest_temperature() -+ write_sfp_highest_temperature(temperature) -+ except Exception as e: -+ sfp_temp_error("get/write sfp temperature error, msg:%s" % str(e)) -+ write_sfp_highest_temperature(-9999000) -+ time.sleep(5) -+ -+ -+if __name__ == '__main__': -+ main() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/slot_monitor.py b/platform/broadcom/sonic-platform-modules-micas/common/script/slot_monitor.py -new file mode 100755 -index 000000000..0385f50b6 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/slot_monitor.py -@@ -0,0 +1,253 @@ -+#!/usr/bin/env python3 -+# -*- coding: UTF-8 -*- -+import time -+import syslog -+import traceback -+import operator -+import click -+import os -+from platform_config import SLOT_MONITOR_PARAM -+from platform_util import io_rd, io_wr, wbi2cget, wbi2cset -+ -+ -+SLOTMONITORDEBUG = 0 -+SLOTMONITOR_DEBUG_FILE = "/etc/.slotmonitor_debug_flag" -+ -+ -+CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} -+ -+ -+class AliasedGroup(click.Group): -+ def get_command(self, ctx, cmd_name): -+ rv = click.Group.get_command(self, ctx, cmd_name) -+ if rv is not None: -+ return rv -+ matches = [x for x in self.list_commands(ctx) -+ if x.startswith(cmd_name)] -+ if not matches: -+ return None -+ if len(matches) == 1: -+ return click.Group.get_command(self, ctx, matches[0]) -+ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) -+ return None -+ -+ -+def debug_init(): -+ global SLOTMONITORDEBUG -+ if os.path.exists(SLOTMONITOR_DEBUG_FILE): -+ SLOTMONITORDEBUG = 1 -+ else: -+ SLOTMONITORDEBUG = 0 -+ -+ -+def slotwarninglog(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("SLOTMONITOR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_WARNING, s) -+ -+ -+def slotcriticallog(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("SLOTMONITOR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_CRIT, s) -+ -+ -+def sloterror(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("SLOTMONITOR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+def slotinfo(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("SLOTMONITOR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_INFO, s) -+ -+ -+def slotdebuglog(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ if SLOTMONITORDEBUG == 1: -+ syslog.openlog("SLOTMONITOR", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+class SlotMonitor(): -+ def __init__(self): -+ self.preSlotStatus = [] -+ -+ def checkslot(self, ret): -+ slots_conf = SLOT_MONITOR_PARAM.get('slots', None) -+ -+ if slots_conf is None: -+ return False -+ for item_slot in slots_conf: -+ totalerr = 0 -+ try: -+ ret_t = {} -+ ret_t["id"] = item_slot.get('name') -+ ret_t["status"] = "" -+ presentattr = item_slot.get('present') -+ gettype = presentattr.get('gettype') -+ presentbit = presentattr.get('presentbit') -+ if gettype == "io": -+ io_addr = presentattr.get('io_addr') -+ val = io_rd(io_addr) -+ if val is not None: -+ retval = val -+ else: -+ totalerr -= 1 -+ sloterror(" %s %s" % (item_slot.get('name'), "lpc read failed")) -+ else: -+ bus = presentattr.get('bus') -+ loc = presentattr.get('loc') -+ offset = presentattr.get('offset') -+ ind, val = wbi2cget(bus, loc, offset) -+ if ind is True: -+ retval = val -+ else: -+ totalerr -= 1 -+ sloterror(" %s %s" % (item_slot.get('name'), "i2c read failed")) -+ if totalerr < 0: -+ ret_t["status"] = "NOT OK" -+ ret.append(ret_t) -+ continue -+ val_t = (int(retval, 16) & (1 << presentbit)) >> presentbit -+ if val_t != presentattr.get('okval'): -+ ret_t["status"] = "ABSENT" -+ else: -+ ret_t["status"] = "PRESENT" -+ except Exception as e: -+ ret_t["status"] = "NOT OK" -+ totalerr -= 1 -+ sloterror("checkslot error") -+ sloterror(str(e)) -+ slotdebuglog("%s status: %s" % (ret_t["id"], ret_t["status"])) -+ ret.append(ret_t) -+ return True -+ -+ def dealslotplugin(self, name): -+ slotdebuglog("enter dealslotplugin %s" % name) -+ # wait for slot stable -+ time.sleep(5) -+ slots_conf = SLOT_MONITOR_PARAM.get('slots', None) -+ if slots_conf is None: -+ return False -+ for item_slot in slots_conf: -+ try: -+ slotdebuglog("name %s, item_slot.get('name') %s" % (name, item_slot.get('name'))) -+ if name == item_slot.get('name'): -+ actattr = item_slot.get('act') -+ for item_act in actattr: -+ gettype = item_act.get('gettype') -+ if gettype == "io": -+ io_addr = item_act.get('io_addr') -+ value = item_act.get('value') -+ mask = item_act.get('mask') -+ val = io_rd(io_addr) -+ if val is None: -+ sloterror(" %s %s" % (name, "lpc read failed")) -+ continue -+ set_val = (int(val, 16) & mask) | value -+ ret = io_wr(io_addr, set_val) -+ if ret is not True: -+ sloterror(" %s %s" % (name, "lpc write failed")) -+ continue -+ slotdebuglog("io set io_addr:0x%x value:0x%x success" % (io_addr, set_val)) -+ elif gettype == "i2c": -+ bus = item_act.get('bus') -+ loc = item_act.get('loc') -+ offset = item_act.get('offset') -+ value = item_act.get('value') -+ ret, log = wbi2cset(bus, loc, offset, value) -+ if ret is not True: -+ sloterror(" %s %s %s" % (name, "i2c write failed", log)) -+ continue -+ slotdebuglog( -+ "i2c set bus:%d loc:0x%x offset:0x%x value:0x%x success" % -+ (bus, loc, offset, value)) -+ else: -+ sloterror("gettype error") -+ break -+ except Exception as e: -+ sloterror("dealslotplugin failed") -+ sloterror(str(e)) -+ return False -+ return True -+ -+ def updateSlotStatus(self): -+ ''' -+ Only two status: PRESENT and ABSENT -+ ''' -+ curSlotStatus = [] -+ self.checkslot(curSlotStatus) -+ slotdebuglog('curSlotStatus: {}\n preSlotStatus: {}'.format(curSlotStatus, self.preSlotStatus)) -+ if operator.eq(self.preSlotStatus, curSlotStatus) is False: -+ if len(self.preSlotStatus) == 0: -+ # first time -+ for i, item in enumerate(curSlotStatus): -+ if item['status'] == 'PRESENT': -+ slotdebuglog('SLOT_PLUG_IN: %s' % (item['id'])) -+ elif item['status'] == 'ABSENT': -+ slotdebuglog('SLOT_ABSENT: %s' % (item['id'])) -+ else: -+ slotdebuglog('SLOT_FAILED: %s status %s not support yet' % (item['id'], item['status'])) -+ self.preSlotStatus.append(item) -+ else: -+ for i, item in enumerate(curSlotStatus): -+ if item['status'] == self.preSlotStatus[i]['status']: -+ continue -+ if item['status'] == 'PRESENT' and self.preSlotStatus[i]['status'] == 'ABSENT': -+ self.dealslotplugin(item['id']) -+ slotinfo('SLOT_PLUG_IN: %s' % (item['id'])) -+ elif item['status'] == 'ABSENT' and self.preSlotStatus[i]['status'] == 'PRESENT': -+ slotwarninglog('SLOT_PLUG_OUT: %s' % (item['id'])) -+ else: -+ slotwarninglog('SLOT_PLUG_OUT: %s status change from %s to %s not support' % -+ (item['id'], self.preSlotStatus[i]['status'], item['status'])) -+ self.preSlotStatus.remove(self.preSlotStatus[i]) -+ self.preSlotStatus.insert(i, item) -+ -+ def slotmonitor(self): -+ self.updateSlotStatus() -+ return 0 -+ -+ -+def doSlotMonitor(slotMonitor): -+ slotMonitor.slotmonitor() -+ -+ -+def run(interval, slotMonitor): -+ # slotMonitor.devattrinit() -+ while True: -+ try: -+ debug_init() -+ doSlotMonitor(slotMonitor) -+ except Exception as e: -+ traceback.print_exc() -+ sloterror(str(e)) -+ time.sleep(interval) -+ -+ -+@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) -+def main(): -+ '''slot monitor operator''' -+ -+ -+@main.command() -+def start(): -+ '''start slot monitor''' -+ slotinfo("slot_monitor start") -+ slotMonitor = SlotMonitor() -+ interval = SLOT_MONITOR_PARAM.get('polling_time', 1) -+ run(interval, slotMonitor) -+ -+ -+@main.command() -+def stop(): -+ '''stop slot monitor ''' -+ slotinfo("stop") -+ -+ -+# device_i2c operation -+if __name__ == '__main__': -+ main() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/ssdmon b/platform/broadcom/sonic-platform-modules-micas/common/script/ssdmon -new file mode 100755 -index 000000000..4290b0a68 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/ssdmon -@@ -0,0 +1,82 @@ -+#!/usr/bin/env python3 -+# -+# ssdmon -+# -+# Command-line utility to check SSD health and parameters -+# -+ -+try: -+ import argparse -+ import os -+ import sys -+ -+ from sonic_py_common import device_info, logger -+except ImportError as e: -+ raise ImportError("%s - required module not found" % str(e)) -+ -+DEFAULT_DEVICE = "/dev/sda" -+SYSLOG_IDENTIFIER = "ssdmon" -+ -+# Global logger instance -+log = logger.Logger(SYSLOG_IDENTIFIER) -+ -+def import_ssd_api(diskdev): -+ """ -+ Loads platform specific or generic ssd_mon module from source -+ Raises an ImportError exception if none of above available -+ -+ Returns: -+ Instance of the class with SSD API implementation (vendor or generic) -+ """ -+ -+ # try to load platform specific module -+ try: -+ platform_path, _ = device_info.get_paths_to_platform_and_hwsku_dirs() -+ platform_plugins_path = os.path.join(platform_path, "plugins") -+ sys.path.append(os.path.abspath(platform_plugins_path)) -+ from ssd_util import SsdUtil -+ except ImportError as e: -+ log.log_warning("Platform specific SsdMon module not found.") -+ -+ return SsdUtil(diskdev) -+ -+def is_number(s): -+ try: -+ float(s) -+ return True -+ except ValueError: -+ return False -+ -+# ==================== Entry point ==================== -+def ssdmon(): -+ if os.geteuid() != 0: -+ print("Root privileges are required for this operation") -+ sys.exit(1) -+ -+ parser = argparse.ArgumentParser() -+ parser.add_argument("-d", "--device", help="Device name to show health info", default=DEFAULT_DEVICE) -+ parser.add_argument("-t", "--temperature", action="store_true", default=False, help="Show only temperature") -+ parser.add_argument("-j", "--health", action="store_true", default=False, help="Show only health") -+ -+ args = parser.parse_args() -+ -+ ssd = import_ssd_api(args.device) -+ -+ if args.temperature: -+ print(ssd.get_temperature()) -+ return -+ -+ if args.health: -+ print(ssd.get_health()) -+ return -+ -+ print("Device Model : {}".format(ssd.get_model())) -+ print("Firmware : {}".format(ssd.get_firmware())) -+ print("Serial : {}".format(ssd.get_serial())) -+ print("Health : {}{}".format(ssd.get_health(), "%" if is_number(ssd.get_health()) else "")) -+ print("Remain Life : {}{}".format(ssd.get_remaining_life(), "%" if is_number(ssd.get_remaining_life()) else "")) -+ print("Temperature : {}{}".format(ssd.get_temperature(), "C" if is_number(ssd.get_temperature()) else "")) -+ print("SATA Rate : {}".format(ssd.get_sata_rate())) -+ -+if __name__ == '__main__': -+ ssdmon() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/tty_console.py b/platform/broadcom/sonic-platform-modules-micas/common/script/tty_console.py -new file mode 100755 -index 000000000..4fae02f51 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/tty_console.py -@@ -0,0 +1,91 @@ -+#!/usr/bin/python3 -+# -*- coding: UTF-8 -*- -+ -+import logging.handlers -+import subprocess -+import shlex -+import time -+import sys -+import os -+from platform_util import CompressedRotatingFileHandler, exec_os_cmd -+ -+console_file = "/dev/ttyS1" -+console_logfile = "/var/log/bmc-console.log" -+MAX_LOG_BYTES = 20 * 1024 * 1024 -+BACKUP_COUNT = 9 -+ -+READ_SIZE = 1024 -+ -+logger = logging.getLogger("cpu_monitor_bmc") -+logger.setLevel(logging.DEBUG) -+fh = CompressedRotatingFileHandler( -+ console_logfile, -+ mode='a', -+ maxBytes=MAX_LOG_BYTES, -+ backupCount=BACKUP_COUNT, -+ encoding=None, -+ delay=0) -+fh.setLevel(logging.DEBUG) -+ -+formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") -+fh.setFormatter(formatter) -+logger.addHandler(fh) -+ -+ -+def tty_system_cmd(cmd, print_log=True): -+ if print_log: -+ logger.debug("command: %s", cmd) -+ status, output = exec_os_cmd(cmd) -+ logger.debug("command status %s", status) -+ logger.debug("command output:\n%s", output) -+ else: -+ status, output = exec_os_cmd(cmd) -+ return status, output -+ -+ -+if __name__ == '__main__': -+ try_times = 0 -+ while try_times < 3: -+ try_times = try_times + 1 -+ ret, log = tty_system_cmd("stty -F /dev/ttyS1 | grep 115200", True) -+ if len(log) != 0 and "115200" in log: -+ break -+ tty_system_cmd("stty -F /dev/ttyS1 115200", True) -+ if try_times > 1: -+ logger.error("The %d time try to set SONiC /dev/ttyS1 115200", try_times) -+ -+ if not os.path.exists(console_file): -+ logger.error("device %s not exist", console_file) -+ sys.exit(1) -+ -+ nopen = 3 -+ while nopen > 0: -+ try: -+ console_fd = os.open(console_file, os.O_RDONLY) -+ break -+ except Exception as e: -+ logger.error(e) -+ logger.error("open %s failed", console_file) -+ nopen = nopen - 1 -+ time.sleep(1) -+ if nopen == 0: -+ sys.exit(1) -+ -+ try: -+ tmp_read = "" -+ while True: -+ dev_read = os.read(console_fd, READ_SIZE) -+ dev_read = str(dev_read, encoding='utf-8') -+ if len(dev_read) == 1 and dev_read == "\n": -+ continue -+ if dev_read[len(dev_read) - 1] == '\n': -+ tmp_read = tmp_read + dev_read[0:(len(dev_read) - 1)] -+ logger.info(tmp_read) -+ tmp_read = "" -+ else: -+ tmp_read = tmp_read + dev_read -+ -+ except Exception as e: -+ if console_fd is not None: -+ os.close(console_fd) -+ logger.error(e) -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/upgrade.py b/platform/broadcom/sonic-platform-modules-micas/common/script/upgrade.py -new file mode 100755 -index 000000000..1b2523198 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/upgrade.py -@@ -0,0 +1,991 @@ -+#!/usr/bin/env python3 -+# -*- coding: UTF-8 -*- -+import sys -+import os -+import time -+import syslog -+import signal -+import click -+from platform_util import get_value, set_value, exec_os_cmd, exec_os_cmd_log -+from platform_config import UPGRADE_SUMMARY, WARM_UPGRADE_STARTED_FLAG -+from warm_upgrade import WarmBasePlatform -+ -+ -+############################# Error code defined ############################# -+ERR_FW_CHECK_CPLD_UPGRADE = -601 # "Failed to check the device CPLD information" -+ERR_FW_CHECK_FPGA_UPGRADE = -602 # "Failed to check the device FPGA information" -+ERR_FW_MATCH_CPLD_UPGRADE = -603 # "Not found upgrade CPLD file." -+ERR_FW_MATCH_FPGA_UPGRADE = -604 # "Not found upgrade FPGA file." -+ERR_FW_SAMEVER_CPLD_UPGRADE = -605 # "The CPLD version in device is same" -+ERR_FW_SAMEVER_FPGA_UPGRADE = -606 # "The FPGA version in device is same" -+ERR_FW_DO_CPLD_UPGRADE = -607 # "Doing upgrade CPLD is failed." -+ERR_FW_DO_FPGA_UPGRADE = -608 # "Doing upgrade FPGA is failed." -+ERR_FW_UPGRADE = -609 # "Failed to upgrade firmware" -+FIRMWARE_PROGRAM_EXEC_ERR = -610 # "Firmware program run error!" -+ERR_FW_FILE_FOUND = -701 # "Failed to find upgrade file" -+ERR_FW_HEAD_PARSE = -702 # "Failed to parse upgrade firmware head info" -+ERR_FW_CONFIG_FOUND = -703 # "Failed to find config item" -+ERR_FW_NOSUPPORT_HOT = -704 # "No support hot upgrade" -+ERR_FW_CHECK_SIZE = -705 # "Failed to check file size" -+ERR_FW_DEVICE_ACCESS = -706 # "Failed to access device" -+ERR_FW_NO_FILE_SUCCESS = -707 # "No files were successfully upgraded" -+ERR_FW_CARD_ABSENT = -708 # "The subcard not present" -+ERR_FW_HEAD_CHECK = -709 # "Failed to check head info" -+ERR_FW_FOOL_PROOF = -710 # "Failed to fool proof verification" -+ERR_FW_RAISE_EXCEPTION = -711 # Code raise exception -+ERR_FW_INVALID_PARAM = -712 # Invalid parameter -+ERR_FW_UNZIP_FAILED = -713 # Unzip firmware failed -+ -+FIRMWARE_SUCCESS = 0 -+CHECK_OK = 0 -+ -+ -+UPGRADE_DEBUG_FILE = "/etc/.upgrade_debug_flag" -+UPGRADE_FILE_DIR = "/tmp/firmware/" -+ -+UPGRADEDEBUG = 1 -+ -+debuglevel = 0 -+ -+COLD_UPGRADE = 1 -+WARM_UPGRADE = 2 -+TEST_UPGRADE = 3 -+BMC_UPGRADE = 4 -+ -+CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} -+ -+ -+class AliasedGroup(click.Group): -+ -+ def get_command(self, ctx, cmd_name): -+ rv = click.Group.get_command(self, ctx, cmd_name) -+ if rv is not None: -+ return rv -+ matches = [x for x in self.list_commands(ctx) -+ if x.startswith(cmd_name)] -+ if not matches: -+ return None -+ if len(matches) == 1: -+ return click.Group.get_command(self, ctx, matches[0]) -+ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) -+ return None -+ -+ -+def debug_init(): -+ global debuglevel -+ if os.path.exists(UPGRADE_DEBUG_FILE): -+ debuglevel = debuglevel | UPGRADEDEBUG -+ else: -+ debuglevel = debuglevel & ~(UPGRADEDEBUG) -+ -+ -+def upgradewarninglog(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("UPGRADE", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_WARNING, s) -+ -+ -+def upgradecriticallog(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("UPGRADE", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_CRIT, s) -+ -+ -+def upgradeerror(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("UPGRADE", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+def upgradedebuglog(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ if UPGRADEDEBUG & debuglevel: -+ syslog.openlog("UPGRADE", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def signal_init(): -+ signal.signal(signal.SIGINT, signal.SIG_IGN) # ignore ctrl+c signal -+ signal.signal(signal.SIGTERM, signal.SIG_IGN) # ignore kill signal -+ signal.signal(signal.SIGTSTP, signal.SIG_IGN) # ignore ctrl+z signal -+ -+ -+class BasePlatform(): -+ -+ def __init__(self): -+ self.upgrade_param = UPGRADE_SUMMARY.copy() -+ self.devtype = self.upgrade_param.get('devtype', None) -+ self.max_slot_num = self.upgrade_param.get("max_slot_num", 0) -+ self.head_info_config = {} -+ self.slot_config = {} -+ self.cold_chain_config = {} -+ self.subtype = None -+ self.chain = None -+ self.filetype = None -+ self.DEVTYPE = None -+ self.SUBTYPE = '0' -+ self.TYPE = None -+ self.CHAIN = None -+ self.CHIPNAME = None -+ self.VERSION = None -+ self.FILETYPE = None -+ self.CRC = None -+ self.SUBTYPE_LIST = None -+ -+ def save_and_set_value(self, cfg_list): -+ for config in cfg_list: -+ ret, val = get_value(config) -+ if ret: -+ config["save_value"] = val -+ else: -+ upgradeerror(val) -+ return False, "get save value fail" -+ -+ set_val = config.get("set_value", None) -+ if set_val is None: -+ log = "save_and_set_value lack of set_val config" -+ upgradeerror(log) -+ return log -+ -+ gettype = config.get("gettype", None) -+ set_cmd = config.get("set_cmd", None) -+ if gettype == "cmd": -+ if set_cmd is None: -+ log = "save_and_set_value lack of set_cmd config" -+ upgradeerror(log) -+ return False, log -+ config["cmd"] = set_cmd % set_val -+ upgradedebuglog("save_and_set_value modify set cmd to %s" % config["cmd"]) -+ else: -+ config["value"] = set_val -+ upgradedebuglog("save_and_set_value modify set val to %s" % config["value"]) -+ -+ ret, log = set_value(config) -+ if ret is False: -+ upgradeerror(log) -+ return False, log -+ return True, "save and set value success" -+ -+ def recover_save_value(self, cfg_list): -+ total_err = 0 -+ for config in cfg_list: -+ upgradedebuglog("config: %s, recover save value" % config) -+ val = config.get("save_value", None) -+ if val is None: -+ upgradeerror("recover_save_value lack of save_value config") -+ total_err -= 1 -+ continue -+ gettype = config.get("gettype", None) -+ set_cmd = config.get("set_cmd", None) -+ if gettype == "cmd": -+ config["cmd"] = set_cmd % val -+ upgradedebuglog("recover_save_value modify set cmd to %s" % config["cmd"]) -+ else: -+ config["value"] = val -+ upgradedebuglog("recover_save_value modify set val to %s" % config["value"]) -+ -+ ret, log = set_value(config) -+ if ret is False: -+ upgradeerror("recover save value write failed, log: %s" % log) -+ total_err -= 1 -+ else: -+ upgradedebuglog("recover save value success") -+ if total_err < 0: -+ return False, "recover save value failed" -+ return True, "recover save value success" -+ -+ def check_slot_present(self, slot_present_config): -+ presentbit = slot_present_config.get('presentbit') -+ ret, value = get_value(slot_present_config) -+ if ret is False: -+ return "NOT OK" -+ if isinstance(value, str): -+ val_t = int(value, 16) -+ else: -+ val_t = value -+ val_t = (val_t & (1 << presentbit)) >> presentbit -+ if val_t != slot_present_config.get('okval'): -+ status = "ABSENT" -+ else: -+ status = "PRESENT" -+ return status -+ -+ def linecard_present_check(self, slot_present_config): -+ present_status = self.check_slot_present(slot_present_config) -+ if present_status == "NOT OK": -+ return ERR_FW_DEVICE_ACCESS, "get slot present status failed." -+ if present_status == "ABSENT": -+ return ERR_FW_CARD_ABSENT, "slot absent" -+ return CHECK_OK, "slot present" -+ -+ def subprocess_warm_upgrade(self, config, file, main_type, sub_type, slot): -+ dev_name = config.get("name", None) -+ status, output = self.subprocess_firmware_upgrade(config, file, main_type, sub_type, slot) -+ if status is False: -+ upgradeerror("%s warm upgrade failed" % dev_name) -+ return False, output -+ command = "warm_upgrade.py %s 0x%x 0x%x %s %s %s" % (file, main_type, sub_type, slot, self.filetype, self.chain) -+ upgradedebuglog("warm upgrade cmd: %s" % command) -+ if os.path.exists(UPGRADE_DEBUG_FILE): -+ status, output = exec_os_cmd_log(command) -+ else: -+ status, output = exec_os_cmd(command) -+ if status: -+ upgradeerror("%s warm upgrade failed" % dev_name) -+ return False, output -+ upgradedebuglog("%s warm upgrade success" % dev_name) -+ return True, "upgrade success" -+ -+ def do_fw_upg_init_cmd(self, dev_name, init_cmd_list): -+ # pre operation -+ try: -+ for init_cmd_config in init_cmd_list: -+ ret, log = set_value(init_cmd_config) -+ if ret is False: -+ upgradeerror("%s do init cmd: %s failed, msg: %s" % (dev_name, init_cmd_config, log)) -+ return False, log -+ msg = "%s firmware init cmd all set success" % dev_name -+ upgradedebuglog(msg) -+ return True, msg -+ except Exception as e: -+ return False, str(e) -+ -+ def do_fw_upg_finish_cmd(self, dev_name, finish_cmd_list): -+ # end operation -+ ret = 0 -+ for finish_cmd_config in finish_cmd_list: -+ ret_t, log = set_value(finish_cmd_config) -+ if ret_t is False: -+ upgradeerror("%s do finish cmd: %s failed, msg: %s" % (dev_name, finish_cmd_config, log)) -+ ret = -1 -+ if ret != 0: -+ msg = "%s firmware finish cmd exec failed" % dev_name -+ upgradeerror(msg) -+ return False, msg -+ msg = "%s firmware finish cmd all set success" % dev_name -+ upgradedebuglog(msg) -+ return True, msg -+ -+ def subprocess_firmware_upgrade(self, config, file, main_type, sub_type, slot): -+ dev_name = config.get("name", None) -+ init_cmd_list = config.get("init_cmd", []) -+ finish_cmd_list = config.get("finish_cmd", []) -+ try: -+ ret, log = self.do_fw_upg_init_cmd(dev_name, init_cmd_list) -+ if ret is False: -+ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) -+ return False, log -+ time.sleep(0.5) # delay 0.5s after execute init_cmd -+ command = "firmware_upgrade %s 0x%x 0x%x %s" % (file, main_type, sub_type, slot) -+ upgradedebuglog("firmware upgrade cmd: %s" % command) -+ if os.path.exists(UPGRADE_DEBUG_FILE): -+ status, output = exec_os_cmd_log(command) -+ else: -+ status, output = exec_os_cmd(command) -+ if status: -+ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) -+ upgradeerror("%s firmware upgrade failed, msg: %s" % (dev_name, output)) -+ return False, output -+ upgradedebuglog("%s firmware upgrade success" % dev_name) -+ ret, log = self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) -+ if ret is False: -+ return False, log -+ return True, "upgrade success" -+ except Exception as e: -+ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) -+ return False, str(e) -+ -+ def subprocess_test_upgrade(self, config, file, main_type, sub_type, slot): -+ dev_name = config.get("name", None) -+ init_cmd_list = config.get("init_cmd", []) -+ finish_cmd_list = config.get("finish_cmd", []) -+ try: -+ ret, log = self.do_fw_upg_init_cmd(dev_name, init_cmd_list) -+ if ret is False: -+ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) -+ return False, log -+ time.sleep(0.5) # delay 0.5s after execute init_cmd -+ command = "firmware_upgrade test %s 0x%x 0x%x %s" % (file, main_type, sub_type, slot) -+ upgradedebuglog("firmware upgrade cmd: %s" % command) -+ if os.path.exists(UPGRADE_DEBUG_FILE): -+ status, output = exec_os_cmd_log(command) -+ else: -+ status, output = exec_os_cmd(command) -+ if status: -+ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) -+ upgradeerror("%s test upgrade failed, msg: %s" % (dev_name, output)) -+ return False, output -+ upgradedebuglog("%s test upgrade success" % dev_name) -+ ret, log = self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) -+ if ret is False: -+ return False, log -+ return True, "upgrade success" -+ except Exception as e: -+ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) -+ return False, str(e) -+ -+ def subprocess_bmc_upgrade(self, config, file, chip_select, erase_type): -+ dev_name = config.get("name", None) -+ init_cmd_list = config.get("init_cmd", []) -+ finish_cmd_list = config.get("finish_cmd", []) -+ save_set_reg_list = config.get("save_set_reg", []) -+ try: -+ # save and set reg -+ ret, log = self.save_and_set_value(save_set_reg_list) -+ if ret is False: -+ upgradeerror(log) -+ self.recover_save_value(save_set_reg_list) -+ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) -+ return False, log -+ upgradedebuglog("%s save and set cmd all set success" % dev_name) -+ time.sleep(0.5) # delay 0.5s after execute save and set reg -+ -+ # pre operation -+ ret, log = self.do_fw_upg_init_cmd(dev_name, init_cmd_list) -+ if ret is False: -+ self.recover_save_value(save_set_reg_list) -+ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) -+ return False, log -+ -+ upgradedebuglog("%s bmc init cmd all set success" % dev_name) -+ time.sleep(0.5) # delay 0.5s after execute init_cmd -+ -+ command = "fw_upgrade upgrade %s %s %s" % (file, chip_select, erase_type) -+ upgradedebuglog("fw_upgrade upgrade cmd: %s" % command) -+ status, output = exec_os_cmd_log(command) -+ if status: -+ upgradeerror("%s bmc upgrade failed" % dev_name) -+ self.recover_save_value(save_set_reg_list) -+ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) -+ return False, output -+ upgradedebuglog("%s bmc upgrade success" % dev_name) -+ -+ ret1, log1 = self.recover_save_value(save_set_reg_list) -+ if ret1 is False: -+ upgradeerror("bmc upgrade recover save value failed, msg: %s" % log1) -+ ret2, log2 = self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) -+ if ret2 is False: -+ upgradeerror("bmc upgrade do finish command failed, msg: %s" % log2) -+ if ret1 is False or ret2 is False: -+ return False, "bmc upgrade do recover save value or finish command failed" -+ return True, "upgrade success" -+ -+ except Exception as e: -+ self.recover_save_value(save_set_reg_list) -+ self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) -+ return False, str(e) -+ -+ def file_head_param_check(self, head_info_config): -+ try: -+ self.DEVTYPE = head_info_config.get('DEVTYPE', None) -+ self.SUBTYPE = head_info_config.get('SUBTYPE', '0') -+ self.TYPE = head_info_config.get('TYPE', None) -+ self.CHAIN = head_info_config.get('CHAIN', None) -+ self.CHIPNAME = head_info_config.get('CHIPNAME', None) -+ self.VERSION = head_info_config.get('VERSION', None) -+ self.FILETYPE = head_info_config.get('FILETYPE', None) -+ self.CRC = head_info_config.get('CRC', None) -+ -+ if self.devtype != int(self.DEVTYPE, 16): -+ return ERR_FW_HEAD_CHECK, ("no support %s devtype" % self.DEVTYPE) -+ -+ if self.SUBTYPE is not None: -+ self.SUBTYPE_LIST = self.SUBTYPE.split(',') -+ self.SUBTYPE_LIST = [int(tmp_subtype, base=16) for tmp_subtype in self.SUBTYPE_LIST] -+ if len(self.SUBTYPE) != 0 and self.subtype not in self.SUBTYPE_LIST: -+ return ERR_FW_HEAD_CHECK, ("no support %s SUBTYPE" % self.SUBTYPE) -+ -+ if len(self.CHAIN) == 0 or len(self.FILETYPE) == 0: -+ return ERR_FW_HEAD_CHECK, ("CHAIN:%s, FILETYPE:%s get failed" % (self.CHAIN, self.FILETYPE)) -+ self.chain = int(self.CHAIN) -+ self.filetype = self.FILETYPE -+ upgradedebuglog("file head param: devtype:0x%x, subtype:0x%x, chain:%s, filetype:%s" -+ % (self.devtype, self.subtype, self.chain, self.filetype)) -+ return CHECK_OK, "SUCCESS" -+ except Exception as e: -+ return ERR_FW_RAISE_EXCEPTION, str(e) -+ -+ def parse_file_head(self, file): -+ try: -+ self.head_info_config = {} -+ with open(file, 'r', errors='ignore') as fd: -+ rdbuf = fd.read() -+ upgradedebuglog("start parse upgrade file head") -+ file_head_start = rdbuf.index('FILEHEADER(\n') # ponit to F -+ file_head_start += rdbuf[file_head_start:].index('\n') # ponit to \n -+ file_head_end = rdbuf.index(')\n') -+ header_buf = rdbuf[file_head_start + 1: file_head_end - 1] -+ upgradedebuglog("upgrade file head find FILEHEADER") -+ for line in header_buf.split('\n'): -+ head_list = line.split('=', 1) -+ head_key = head_list[0] -+ head_val = head_list[1] -+ self.head_info_config[head_key] = head_val -+ upgradedebuglog("file: %s head_info_config: %s" % (file, self.head_info_config)) -+ return CHECK_OK, "SUCCESS" -+ except Exception as e: -+ msg = "parse %s head failed, msg: %s" % (file, str(e)) -+ upgradeerror(msg) -+ return ERR_FW_RAISE_EXCEPTION, msg -+ -+ def get_file_size_k(self, file): -+ fsize = os.path.getsize(file) -+ fsize = fsize / float(1024) -+ return round(fsize, 2) -+ -+ def get_device_model(self, conf): -+ ret, val = get_value(conf) -+ if ret is False: -+ msg = "get device model failed, msg: %s" % val -+ return False, msg -+ decode_val = conf.get("decode") -+ if decode_val is None: -+ return True, val -+ for k, v in decode_val.items(): -+ if val == v: -+ return True, k -+ msg = "device model decode error, val: %s" % val -+ return False, msg -+ -+ def upgrade_fool_proofing(self, conf): -+ try: -+ status, dev_model = self.get_device_model(conf) -+ if status is False: -+ msg = "upgrade fool proofing get device model failed, msg: %s" % dev_model -+ upgradeerror(msg) -+ return False, msg -+ upgradedebuglog("get device model success, device model: %s" % dev_model) -+ if dev_model != self.VERSION: -+ msg = "upgrade fool proofing failed, device model: %s, upgrade file version: %s" % ( -+ dev_model, self.VERSION) -+ upgradedebuglog(msg) -+ return False, msg -+ msg = "upgrade fool proofing pass, device model: %s, upgrade file version: %s" % (dev_model, self.VERSION) -+ upgradedebuglog(msg) -+ return True, msg -+ except Exception as e: -+ upgradeerror(str(e)) -+ return False, str(e) -+ -+ def upgrading(self, config, file, devtype, subtype, slot, option_flag, erase_type=None): -+ dev_name = config.get("name", None) -+ if option_flag == COLD_UPGRADE: -+ status, output = self.subprocess_firmware_upgrade(config, file, devtype, subtype, slot) -+ elif option_flag == WARM_UPGRADE: -+ status, output = self.subprocess_warm_upgrade(config, file, devtype, subtype, slot) -+ elif option_flag == TEST_UPGRADE: -+ status, output = self.subprocess_test_upgrade(config, file, devtype, subtype, slot) -+ elif option_flag == BMC_UPGRADE: -+ status, output = self.subprocess_bmc_upgrade(config, file, slot, erase_type) -+ else: -+ log = "%s set error option flag" % dev_name -+ upgradeerror(log) -+ return False, log -+ -+ if status is False: -+ upgradeerror("%s upgrade failed" % dev_name) -+ return False, output -+ upgradedebuglog("%s upgrade success" % dev_name) -+ return True, "upgrade success" -+ -+ def initial_check(self, file, slot, upg_type): -+ try: -+ upgradedebuglog("BasePlatform initial_check, file: %s, slot: %s, upg_type: %s" % -+ (file, slot, upg_type)) -+ -+ upgradedebuglog("do file exist check...") -+ if not os.path.isfile(file): -+ msg = "%s not found" % file -+ upgradedebuglog(msg) -+ return ERR_FW_FILE_FOUND, msg -+ upgradedebuglog("file exist check ok") -+ -+ slot_name = "slot%d" % slot -+ slot_config = self.upgrade_param.get(slot_name, {}) -+ slot_present_config = slot_config.get("present", {}) -+ if len(slot_present_config) != 0: -+ upgradedebuglog("do %s present check..." % slot_name) -+ ret, log = self.linecard_present_check(slot_present_config) -+ if ret != CHECK_OK: -+ msg = "check %s present error, msg: %s" % (slot_name, log) -+ upgradedebuglog(msg) -+ return ret, msg -+ upgradedebuglog("%s present check ok" % slot_name) -+ -+ upgradedebuglog("do file head parse...") -+ self.subtype = slot_config.get("subtype", 0) -+ ret, log = self.parse_file_head(file) -+ if ret != CHECK_OK: -+ return ret, log -+ upgradedebuglog("file head parse success") -+ -+ upgradedebuglog("do file head check...") -+ ret, log = self.file_head_param_check(self.head_info_config) -+ if ret != CHECK_OK: -+ msg = "file: %s, head check failed, msg: %s" % (file, log) -+ upgradedebuglog(msg) -+ return ret, msg -+ upgradedebuglog("file head check ok") -+ -+ upgradedebuglog("get upgrade chain config...") -+ filetype_config = slot_config.get(self.filetype, {}) -+ if len(filetype_config) == 0: -+ msg = "file: %s filetype: %s no support" % (file, self.filetype) -+ upgradedebuglog(msg) -+ return ERR_FW_CONFIG_FOUND, msg -+ chain_num = "chain%s" % self.chain -+ chain_config = filetype_config.get(chain_num, {}) -+ if len(chain_config) == 0: -+ msg = "file: %s get %s config failed" % (file, chain_num) -+ upgradedebuglog(msg) -+ return ERR_FW_CONFIG_FOUND, msg -+ self.cold_chain_config = chain_config -+ upgradedebuglog("get %s filetype: %s %s config success" % (slot_name, self.filetype, chain_num)) -+ -+ fool_proofing = chain_config.get("fool_proofing") -+ if fool_proofing is not None: -+ upgradedebuglog("do fool proofing check...") -+ status, log = self.upgrade_fool_proofing(fool_proofing) -+ if status is False: -+ msg = "upgrade fool proofing check failed, msg: %s" % log -+ upgradedebuglog(msg) -+ return ERR_FW_FOOL_PROOF, msg -+ upgradedebuglog("do fool proofing check ok") -+ -+ if upg_type == WARM_UPGRADE: -+ upgradedebuglog("do support warm upgrade check...") -+ if chain_config.get("is_support_warm_upg", 0) != 1: -+ msg = "file: %s %s chain config not support warm upgrade" % (file, slot_name) -+ upgradedebuglog(msg) -+ return ERR_FW_NOSUPPORT_HOT, msg -+ upgradedebuglog("file: %s %s chain config support warm upgrade" % (file, slot_name)) -+ -+ filesizecheck = chain_config.get("filesizecheck", 0) -+ if filesizecheck != 0: -+ upgradedebuglog("do file size check...") -+ file_size = self.get_file_size_k(file) -+ if file_size > filesizecheck: -+ msg = "file: %s size: %s exceed %s" % (file, file_size, filesizecheck) -+ upgradedebuglog(msg) -+ return ERR_FW_CHECK_SIZE, msg -+ msg = "file: %s size: %s check ok" % (file, file_size) -+ upgradedebuglog(msg) -+ -+ msg = "file: %s slot: %s upgrade type: %s check ok" % (file, slot, upg_type) -+ upgradedebuglog(msg) -+ return CHECK_OK, msg -+ except Exception as e: -+ return ERR_FW_RAISE_EXCEPTION, str(e) -+ -+ def do_upgrade(self, file, slot, upg_type): -+ try: -+ ret, log = self.initial_check(file, slot, upg_type) -+ if ret != CHECK_OK: -+ return ret, log -+ -+ # start upgrading -+ upgradedebuglog("start upgrading") -+ ret, log = self.upgrading(self.cold_chain_config, file, self.devtype, self.subtype, slot, upg_type) -+ if ret is False: -+ upgradeerror("upgrade failed") -+ return ERR_FW_UPGRADE, log -+ upgradedebuglog("upgrade success") -+ return FIRMWARE_SUCCESS, "SUCCESS" -+ except Exception as e: -+ return ERR_FW_RAISE_EXCEPTION, str(e) -+ -+ def do_pre_check(self, conf): -+ ret, val = get_value(conf) -+ if ret is False: -+ msg = "pre check get value failed, msg: %s" % val -+ return False, msg -+ ok_val = conf.get("ok_val") -+ if val == ok_val: -+ msg = "pre check success, ok_val: %s, get value: %s" % (ok_val, val) -+ return True, msg -+ msg = "pre check failed, ok_val: %s, get value: %s" % (ok_val, val) -+ return False, msg -+ -+ def do_test(self, device, slot): -+ try: -+ # slot present check -+ slot_name = "slot%d" % slot -+ slot_config = self.upgrade_param.get(slot_name, {}) -+ slot_present_config = slot_config.get("present", {}) -+ if len(slot_present_config) != 0: -+ ret, log = self.linecard_present_check(slot_present_config) -+ if ret != CHECK_OK: -+ msg = "check %s present error, msg: %s" % (slot_name, log) -+ upgradedebuglog(msg) -+ return ret, msg -+ upgradedebuglog("%s present" % slot_name) -+ -+ # get list of devices to be tested -+ test_config = slot_config.get("TEST", {}) -+ if len(test_config) == 0: -+ return ERR_FW_CONFIG_FOUND, "test config no found" -+ device_list = test_config.get(device, []) -+ if len(device_list) == 0: -+ return ERR_FW_CONFIG_FOUND, ("logic device %s test config list not found" % device) -+ -+ # test_file existence check -+ for test_config in device_list: -+ chain_num = test_config.get("chain", None) -+ test_file = test_config.get("file", None) -+ display_name = test_config.get("display_name", None) -+ if chain_num is None or test_file is None or display_name is None: -+ log = "test_config:%s lack of config" % test_config -+ upgradeerror(log) -+ return ERR_FW_CONFIG_FOUND, log -+ if not os.path.isfile(test_file): -+ return ERR_FW_FILE_FOUND, ("%s not found" % test_file) -+ -+ # start testing -+ RET = 0 -+ pre_check_failed = 0 -+ pre_check_failed_summary = "" -+ failed_summary = "chain test failed.\ntest fail chain:" -+ success_summary = "test success chain:" -+ for test_config in device_list: -+ chain_num = test_config.get("chain", None) -+ test_file = test_config.get("file", None) -+ display_name = test_config.get("display_name", None) -+ pre_check_conf = test_config.get("pre_check", None) -+ if pre_check_conf is not None: -+ status, msg = self.do_pre_check(pre_check_conf) -+ if status is False: -+ pre_check_failed += 1 -+ log = "\nchain:%d, name:%s, pre check failed, msg: %s" % (chain_num, display_name, msg) -+ upgradedebuglog(log) -+ pre_check_failed_summary += log -+ continue -+ upgradedebuglog("chain:%d, name:%s, pre check ok, msg: %s" % (chain_num, display_name, msg)) -+ ret, log = self.do_upgrade(test_file, slot, TEST_UPGRADE) -+ if ret != FIRMWARE_SUCCESS: -+ RET = -1 -+ upgradeerror("chain:%d, name:%s test failed" % (chain_num, display_name)) -+ failed_summary += "\n chain:%d, name:%s;" % (chain_num, display_name) -+ else: -+ upgradedebuglog("chain:%d, name:%s test success" % (chain_num, display_name)) -+ success_summary += "\n chain:%d, name:%s;" % (chain_num, display_name) -+ if RET != 0: -+ return ERR_FW_UPGRADE, failed_summary -+ if pre_check_failed == len(device_list): -+ return ERR_FW_NO_FILE_SUCCESS, failed_summary + pre_check_failed_summary -+ return FIRMWARE_SUCCESS, success_summary -+ except Exception as e: -+ return ERR_FW_RAISE_EXCEPTION, str(e) -+ -+ def do_test_main(self, device, slot): -+ print("+================================+") -+ print("|Doing upgrade test, please wait.|") -+ ret, log = self.do_test(device, slot) -+ if ret == FIRMWARE_SUCCESS: -+ print("| test succeeded! |") -+ print("+================================+") -+ print(log) -+ sys.exit(0) -+ else: -+ print("| test failed! |") -+ print("+================================+") -+ print("FAILED REASON:") -+ print(log) -+ sys.exit(1) -+ -+ def do_bmc_upgrade_main(self, file, chip_select, erase_type): -+ bmc_upgrade_config = self.upgrade_param.get("BMC", {}) -+ ret, log = self.upgrading(bmc_upgrade_config, file, self.devtype, -+ self.subtype, chip_select, BMC_UPGRADE, erase_type) -+ if ret is True: -+ print("===========upgrade succeeded!============") -+ sys.exit(0) -+ else: -+ print("============upgrade failed!==============") -+ print("FAILED REASON:") -+ print("%s" % log) -+ sys.exit(1) -+ -+ -+class FileUpg(object): -+ def __init__(self, config, file, devtype, subtype, slot, filetype, chain, upg_type): -+ self.config = config -+ self.file = file -+ self.devtype = devtype -+ self.subtype = subtype -+ self.slot = slot -+ self.filetype = filetype -+ self.chain = chain -+ self.upg_type = upg_type -+ -+ def __repr__(self): -+ return "file:%s slot:%d" % (self.file, self.slot) -+ -+ -+class FwUpg(object): -+ def __init__(self): -+ self.upg_platform = BasePlatform() -+ self.warm_upg_platform = WarmBasePlatform() -+ self.max_slot_num = self.upg_platform.max_slot_num -+ self.file_list = [] -+ -+ def do_file_refresh(self, fw_upg_instance): -+ fw_upg_config = fw_upg_instance.config -+ fw_upg_file = fw_upg_instance.file -+ fw_upg_devtype = fw_upg_instance.devtype -+ fw_upg_subype = fw_upg_instance.subtype -+ fw_upg_slot = fw_upg_instance.slot -+ fw_upg_filetype = fw_upg_instance.filetype -+ fw_upg_chain = fw_upg_instance.chain -+ dev_name = fw_upg_config.get("name", None) -+ upgradedebuglog("%s start warm upgrade, file: %s, devtype:0x%x, subype: 0x%x, slot: %d, filetype: %s, chain: %d" % -+ (dev_name, fw_upg_file, fw_upg_devtype, fw_upg_subype, fw_upg_slot, fw_upg_filetype, fw_upg_chain)) -+ status, output = self.warm_upg_platform.do_warmupgrade(fw_upg_file, fw_upg_devtype, fw_upg_subype, fw_upg_slot, -+ fw_upg_filetype, fw_upg_chain) -+ if status is False: -+ upgradeerror("%s warm upgrade failed, msg: %s" % (dev_name, output)) -+ return False, output -+ upgradedebuglog("%s warm upgrade success" % dev_name) -+ return True, "upgrade success" -+ -+ def do_refresh(self): -+ try: -+ exec_os_cmd("touch %s" % WARM_UPGRADE_STARTED_FLAG) -+ exec_os_cmd("sync") -+ -+ # stop upper layer services access -+ ret, log = self.warm_upg_platform.stop_services_access() -+ if ret is False: -+ upgradeerror("stop upper layer services access failed") -+ upgradeerror(log) -+ return ERR_FW_UPGRADE, log -+ upgradedebuglog("stop upper layer services access success") -+ -+ for file_instance in self.file_list: -+ file_info = repr(file_instance) -+ ret, log = self.do_file_refresh(file_instance) -+ if ret is False: -+ msg = "%s refresh failed, ret:%s, \n log:%s." % (file_info, ret, log) -+ upgradeerror(msg) -+ return ERR_FW_UPGRADE, msg -+ upgradedebuglog("%s refresh success." % file_info) -+ msg = "all files refresh success." -+ return FIRMWARE_SUCCESS, msg -+ except Exception as e: -+ msg = "do warm upg exception happend. log:%s" % str(e) -+ upgradeerror(msg) -+ return ERR_FW_UPGRADE, msg -+ finally: -+ self.warm_upg_platform.start_services_access() -+ if os.path.isfile(WARM_UPGRADE_STARTED_FLAG): -+ exec_os_cmd("rm -rf %s" % WARM_UPGRADE_STARTED_FLAG) -+ exec_os_cmd("sync") -+ -+ def do_file_cold_upg(self, fw_upg_instance): -+ try: -+ upgradedebuglog("start cold upgrade") -+ fw_upg_config = fw_upg_instance.config -+ fw_upg_file = fw_upg_instance.file -+ fw_upg_devtype = fw_upg_instance.devtype -+ fw_upg_subype = fw_upg_instance.subtype -+ fw_upg_slot = fw_upg_instance.slot -+ ret, log = self.upg_platform.upgrading( -+ fw_upg_config, fw_upg_file, fw_upg_devtype, fw_upg_subype, fw_upg_slot, COLD_UPGRADE) -+ if ret is False: -+ upgradeerror("cold upgrade %s slot%d failed, log:%s" % (fw_upg_file, fw_upg_slot, log)) -+ return ERR_FW_UPGRADE, log -+ log = "cold upgrade %s slot%d success" % (fw_upg_file, fw_upg_slot) -+ upgradedebuglog(log) -+ return FIRMWARE_SUCCESS, log -+ except Exception as e: -+ msg = "do cold upg exception happend. log:%s" % str(e) -+ upgradeerror(msg) -+ return ERR_FW_UPGRADE, msg -+ -+ def do_file_init_check(self, file_path, slot, upg_type): -+ upgradedebuglog("do_file_init_check, file_path: %s, slot: %s, upg_type: %s" % (file_path, slot, upg_type)) -+ -+ if slot is None: # traverse all slots -+ for i in range(0, self.max_slot_num + 1): -+ ret, log = self.upg_platform.initial_check(file_path, i, upg_type) -+ if ret != CHECK_OK: -+ upgradedebuglog( -+ "file: %s, slot%d initial check not ok, ret: %d, msg: %s" % -+ (file_path, i, ret, log)) -+ accept_error = (ERR_FW_CARD_ABSENT, ERR_FW_HEAD_CHECK, ERR_FW_FOOL_PROOF) -+ if ret in accept_error: -+ msg = "file: %s, slot%d initial check ret: %d, acceptable error." % (file_path, i, ret) -+ upgradedebuglog(msg) -+ continue -+ return ret, log -+ file_instance = FileUpg(self.upg_platform.cold_chain_config, file_path, self.upg_platform.devtype, -+ self.upg_platform.subtype, i, self.upg_platform.filetype, self.upg_platform.chain, upg_type) -+ self.file_list.append(file_instance) -+ else: -+ slot = int(slot, 10) -+ ret, log = self.upg_platform.initial_check(file_path, slot, upg_type) -+ if ret != CHECK_OK: -+ msg = "file: %s, slot%d initial check not ok, ret: %d, msg: %s" % (file_path, slot, ret, log) -+ return ret, msg -+ file_instance = FileUpg(self.upg_platform.cold_chain_config, file_path, self.upg_platform.devtype, -+ self.upg_platform.subtype, slot, self.upg_platform.filetype, self.upg_platform.chain, upg_type) -+ self.file_list.append(file_instance) -+ msg = "file: %s all slots init check ok" % file_path -+ return CHECK_OK, msg -+ -+ def do_dir_init_check(self, path, slot, upg_type): -+ for root, dirs, names in os.walk(path): -+ # root: directory absolute path -+ # dirs: folder path collection under directory -+ # names: file path collection under directory -+ for filename in names: -+ # file_path is file absolute path -+ file_path = os.path.join(root, filename) -+ ret, log = self.do_file_init_check(file_path, slot, upg_type) -+ if ret != CHECK_OK: -+ return ret, log -+ msg = "all files in dir have been check ok" -+ upgradedebuglog(msg) -+ return CHECK_OK, msg -+ -+ def do_fw_upg(self, path, slot, upg_type): -+ match_zip_file_flag = False -+ try: -+ upgradedebuglog("do_fw_upg, path: %s, slot: %s, upg_type: %s" % (path, slot, upg_type)) -+ if slot is not None and not slot.isdigit(): -+ msg = "invalid slot param: %s" % slot -+ upgradeerror(msg) -+ return ERR_FW_INVALID_PARAM, msg -+ -+ upgradedebuglog("start init check") -+ if os.path.isfile(path) and path.endswith(".zip"): -+ upgradedebuglog("firmware upgrade via compressed package: %s" % path) -+ # remove origin firmware upgrade file -+ exec_os_cmd("rm -rf %s" % UPGRADE_FILE_DIR) -+ cmd = "unzip -o %s -d /tmp/" % path -+ if os.path.exists(UPGRADE_DEBUG_FILE): -+ status, output = exec_os_cmd_log(cmd) -+ else: -+ status, output = exec_os_cmd(cmd) -+ if status: -+ msg = "unzip %s failed, log: %s" % (path, output) -+ upgradeerror(msg) -+ return ERR_FW_UNZIP_FAILED, msg -+ match_zip_file_flag = True -+ path = UPGRADE_FILE_DIR -+ -+ if os.path.isdir(path): -+ ret, msg = self.do_dir_init_check(path, slot, upg_type) -+ elif os.path.isfile(path): -+ ret, msg = self.do_file_init_check(path, slot, upg_type) -+ else: -+ ret = ERR_FW_FILE_FOUND -+ msg = "path: %s not found" % path -+ upgradeerror(msg) -+ -+ if ret != CHECK_OK: -+ return ret, msg -+ -+ # self.file_list is a collection of all check ok files -+ if len(self.file_list) == 0: -+ msg = "all file upgrade check not be satisfied." -+ upgradeerror(msg) -+ return ERR_FW_NO_FILE_SUCCESS, msg -+ -+ SUCCUSS_FILE_SUMMARY = "SUCCESS FILE: \n" -+ # file cold upgrade -+ upgradedebuglog("start all files cold upgrade") -+ for file_instance in self.file_list: -+ file_info = repr(file_instance) -+ ret, log = self.do_file_cold_upg(file_instance) -+ if ret != FIRMWARE_SUCCESS: -+ msg = "%s cold upgrade failed, ret:%d, \n log:\n%s." % (file_info, ret, log) -+ upgradeerror(msg) -+ return ret, msg -+ SUCCUSS_FILE_SUMMARY += "%s \n" % file_info -+ upgradedebuglog("%s cold upgrade success." % file_info) -+ -+ # file refresh upgrade -+ if upg_type == WARM_UPGRADE: -+ upgradedebuglog("start all files refresh upgrade") -+ ret, log = self.do_refresh() -+ if ret != FIRMWARE_SUCCESS: -+ return ret, log -+ -+ msg = "all file upgrade success" -+ upgradedebuglog(msg) -+ return FIRMWARE_SUCCESS, SUCCUSS_FILE_SUMMARY -+ except Exception as e: -+ msg = "do dir upgrade exception happend. log: %s" % str(e) -+ upgradeerror(msg) -+ return ERR_FW_UPGRADE, msg -+ finally: -+ if match_zip_file_flag is True: -+ exec_os_cmd("rm -rf %s" % UPGRADE_FILE_DIR) -+ -+ def fw_upg(self, path, slot, upg_type): -+ print("+================================+") -+ print("| Doing upgrade, please wait... |") -+ ret, log = self.do_fw_upg(path, slot, upg_type) -+ if ret == FIRMWARE_SUCCESS: -+ print("| upgrade succeeded! |") -+ print("+================================+") -+ print(log) -+ sys.exit(0) -+ else: -+ print("| upgrade failed! |") -+ print("+================================+") -+ print("FAILED REASON:") -+ print("%s" % log) -+ sys.exit(1) -+ -+ -+@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) -+def main(): -+ '''upgrade script''' -+ -+ -+# cold upgrade -+@main.command() -+@click.argument('file_name', required=True) -+@click.argument('slot_num', required=False, default=None) -+def cold(file_name, slot_num): -+ '''cold upgrade''' -+ fwupg = FwUpg() -+ fwupg.fw_upg(file_name, slot_num, COLD_UPGRADE) -+ -+ -+# warm upgrade -+@main.command() -+@click.argument('file_name', required=True) -+@click.argument('slot_num', required=False, default=None) -+def warm(file_name, slot_num): -+ '''warm upgrade''' -+ fwupg = FwUpg() -+ fwupg.fw_upg(file_name, slot_num, WARM_UPGRADE) -+ -+ -+# test upgrade -+@main.command() -+@click.argument('device', required=True) -+@click.argument('slot_num', required=True) -+def test(device, slot_num): -+ '''upgrade test''' -+ platform = BasePlatform() -+ platform.do_test_main(device, int(slot_num)) -+ -+ -+# BMC upgrade -+@main.command() -+@click.argument('file_name', required=True) -+@click.argument('chip_select', required=False, default="2") -+@click.argument('erase_type', required=False, default="full") -+def bmc(file_name, chip_select, erase_type): -+ '''BMC upgrade''' -+ platform = BasePlatform() -+ platform.do_bmc_upgrade_main(file_name, chip_select, erase_type) -+ -+ -+if __name__ == '__main__': -+ signal_init() -+ debug_init() -+ main() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/warm_upgrade.py b/platform/broadcom/sonic-platform-modules-micas/common/script/warm_upgrade.py -new file mode 100755 -index 000000000..69a310faa ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/script/warm_upgrade.py -@@ -0,0 +1,514 @@ -+#!/usr/bin/env python3 -+# -*- coding: UTF-8 -*- -+import sys -+import os -+import time -+import syslog -+import signal -+import click -+from platform_util import get_value, set_value, exec_os_cmd, exec_os_cmd_log -+from platform_config import WARM_UPGRADE_PARAM -+ -+ -+WARM_UPGRADE_DEBUG_FILE = "/etc/.warm_upgrade_debug_flag" -+ -+WARMUPGRADEDEBUG = 1 -+ -+debuglevel = 0 -+ -+CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} -+ -+ -+class AliasedGroup(click.Group): -+ -+ def get_command(self, ctx, cmd_name): -+ rv = click.Group.get_command(self, ctx, cmd_name) -+ if rv is not None: -+ return rv -+ matches = [x for x in self.list_commands(ctx) -+ if x.startswith(cmd_name)] -+ if not matches: -+ return None -+ if len(matches) == 1: -+ return click.Group.get_command(self, ctx, matches[0]) -+ ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) -+ return None -+ -+ -+def debug_init(): -+ global debuglevel -+ if os.path.exists(WARM_UPGRADE_DEBUG_FILE): -+ debuglevel = debuglevel | WARMUPGRADEDEBUG -+ else: -+ debuglevel = debuglevel & ~(WARMUPGRADEDEBUG) -+ -+ -+def warmupgradewarninglog(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("WARMUPGRADE", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_WARNING, s) -+ -+ -+def warmupgradecriticallog(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("WARMUPGRADE", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_CRIT, s) -+ -+ -+def warmupgradeerror(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ syslog.openlog("WARMUPGRADE", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_ERR, s) -+ -+ -+def warmupgradedebuglog(s): -+ # s = s.decode('utf-8').encode('gb2312') -+ if WARMUPGRADEDEBUG & debuglevel: -+ syslog.openlog("WARMUPGRADE", syslog.LOG_PID) -+ syslog.syslog(syslog.LOG_DEBUG, s) -+ -+ -+def subprocess_warm_upgrade(file, main_type, sub_type, slot): -+ command = "firmware_upgrade %s 0x%x 0x%x %s" % (file, main_type, sub_type, slot) -+ warmupgradedebuglog("warm upgrade firmware cmd:%s" % command) -+ if os.path.exists(WARM_UPGRADE_DEBUG_FILE): -+ return exec_os_cmd_log(command) -+ return exec_os_cmd(command) -+ -+ -+def signal_init(): -+ signal.signal(signal.SIGINT, signal.SIG_IGN) # ignore ctrl+c signal -+ signal.signal(signal.SIGTERM, signal.SIG_IGN) # ignore kill signal -+ signal.signal(signal.SIGTSTP, signal.SIG_IGN) # ignore ctrl+z signal -+ -+ -+class RefreshUpgradeBase(object): -+ -+ def __init__(self, config, slot_num, devtype, subtype): -+ self._config = config -+ self._slot_num = slot_num -+ self._devtype = devtype -+ self._subtype = subtype -+ self.device_name = self._config.get("name", None) -+ self.refresh_file = self._config.get("refresh_file", None) -+ self.init_cmd_list = self._config.get("init_cmd", []) -+ self.save_set_reg_list = self._config.get("save_set_reg", []) -+ self.rw_recover_reg_list = self._config.get("rw_recover_reg", []) -+ self.after_upgrade_delay = self._config.get("after_upgrade_delay", None) -+ self.after_upgrade_delay_timeout = self._config.get("after_upgrade_delay_timeout", None) -+ self.refresh_finish_flag_check_config = self._config.get("refresh_finish_flag_check", None) -+ self.access_check_reg_config = self._config.get("access_check_reg", {}) -+ self.time_delay = 0 -+ self.finish_cmd_list = self._config.get("finish_cmd", []) -+ -+ def get_config(self): -+ pass -+ -+ def get_slot_num(self): -+ pass -+ -+ def save_value(self, cfg_list): -+ for config in cfg_list: -+ ret, val = get_value(config) -+ if ret: -+ config["value"] = val -+ else: -+ warmupgradeerror(val) -+ return False, val -+ return True, "save value success" -+ -+ def save_and_set_value(self, cfg_list): -+ for config in cfg_list: -+ ret, val = get_value(config) -+ if ret: -+ config["save_value"] = val -+ else: -+ warmupgradeerror(val) -+ return False, "get save value fail" -+ set_val = config.get("set_value", None) -+ if set_val is not None: -+ config["value"] = set_val -+ else: -+ warmupgradeerror("save_and_set_value lack of set_val config") -+ return False, "set value is not config" -+ ret, log = set_value(config) -+ if ret is False: -+ warmupgradeerror(log) -+ return False, log -+ return True, "save value success" -+ -+ def recover_value(self, cfg_list): -+ fail_flag = 0 -+ for config in cfg_list: -+ ret, log = set_value(config) -+ if ret is False: -+ fail_flag = -1 -+ warmupgradeerror("recover_value set_value failed, log: %s" % log) -+ if fail_flag != 0: -+ warmupgradeerror("recover_value write failed") -+ return False, "recover write failed" -+ return True, "recover write success" -+ -+ def recover_save_value(self, cfg_list): -+ total_err = 0 -+ for config in cfg_list: -+ val = config.get("save_value", None) -+ if val is None: -+ warmupgradeerror("recover_save_value lack of save_value config") -+ total_err -= 1 -+ continue -+ config["value"] = val -+ ret, log = set_value(config) -+ if ret is False: -+ total_err -= 1 -+ warmupgradeerror("recover save value write failed, log: %s" % log) -+ else: -+ warmupgradedebuglog("recover save value success") -+ if total_err < 0: -+ return False, "recover save value failed" -+ return True, "recover save value success" -+ -+ def do_fw_upg_init_cmd(self, init_cmd_list): -+ # pre operation -+ try: -+ for init_cmd_config in init_cmd_list: -+ ret, log = set_value(init_cmd_config) -+ if ret is False: -+ warmupgradeerror("%s do init cmd: %s failed, msg: %s" % (self.device_name, init_cmd_config, log)) -+ return False, log -+ msg = "%s warm upgrade init cmd all set success" % self.device_name -+ warmupgradedebuglog(msg) -+ return True, msg -+ except Exception as e: -+ return False, str(e) -+ -+ def do_fw_upg_finish_cmd(self, finish_cmd_list): -+ # end operation -+ total_err = 0 -+ for finish_cmd_config in finish_cmd_list: -+ ret_t, log = set_value(finish_cmd_config) -+ if ret_t is False: -+ warmupgradeerror("%s do finish cmd: %s failed, msg: %s" % (self.device_name, finish_cmd_config, log)) -+ total_err -= 1 -+ if total_err < 0: -+ msg = "%s warm upgrade finish cmd exec failed" % self.device_name -+ warmupgradeerror(msg) -+ return False, msg -+ msg = "%s warm upgrade finish cmd all set success" % self.device_name -+ warmupgradedebuglog(msg) -+ return True, msg -+ -+ def access_test(self, config): -+ # polling execute command -+ polling_cmd_list = config.get("polling_cmd", []) -+ for polling_cmd_config in polling_cmd_list: -+ ret, log = set_value(polling_cmd_config) -+ if ret is False: -+ warmupgradeerror(log) -+ return False -+ polling_delay = config.get("polling_delay", None) -+ if polling_delay is not None: -+ time.sleep(polling_delay) -+ -+ # record check val -+ check_val = config.get("value", None) -+ # write value -+ ret, log = set_value(config) -+ if ret is False: -+ warmupgradeerror(log) -+ return False -+ # read value -+ ret, val = get_value(config) -+ if ret is False: -+ warmupgradeerror(val) -+ return False -+ -+ # compare write and read val -+ warmupgradedebuglog("check_val:%s" % check_val) -+ warmupgradedebuglog("get_value:%s" % val) -+ if val != check_val: -+ warmupgradeerror("check_val:%s != get_value:%s" % (check_val, val)) -+ return False -+ return True -+ -+ def check_value(self, config): -+ # record check val -+ check_val = config.get("value", None) -+ ret, val = get_value(config) -+ if ret is False: -+ warmupgradeerror(val) -+ return False -+ # compare write and read val -+ warmupgradedebuglog("check_val:%s" % check_val) -+ warmupgradedebuglog("get_value:%s" % val) -+ if val != check_val: -+ warmupgradeerror("check_val:%s != get_value:%s" % (check_val, val)) -+ return False -+ return True -+ -+ def refresh_file_upgrade(self): -+ try: -+ warmupgradedebuglog("start %s warm upgrading" % self.device_name) -+ -+ # save and set reg -+ ret, log = self.save_and_set_value(self.save_set_reg_list) -+ if ret is False: -+ warmupgradeerror(log) -+ self.recover_save_value(self.save_set_reg_list) -+ self.do_fw_upg_finish_cmd(self.finish_cmd_list) -+ return False, log -+ warmupgradedebuglog("%s save and set reg cmd all set success" % self.device_name) -+ time.sleep(0.5) # delay 0.5s after execute save and set reg -+ -+ # pre operation -+ ret, log = self.do_fw_upg_init_cmd(self.init_cmd_list) -+ if ret is False: -+ warmupgradeerror(log) -+ self.recover_save_value(self.save_set_reg_list) -+ self.do_fw_upg_finish_cmd(self.finish_cmd_list) -+ return False, log -+ time.sleep(0.5) # delay 0.5s after execute init_cmd -+ -+ # save reg -+ ret, log = self.save_value(self.rw_recover_reg_list) -+ if ret is False: -+ warmupgradeerror("%s save reg failed" % self.device_name) -+ self.recover_save_value(self.save_set_reg_list) -+ self.do_fw_upg_finish_cmd(self.finish_cmd_list) -+ return False, log -+ warmupgradedebuglog("%s all reg save success" % self.device_name) -+ -+ # upgrade refresh file -+ if self.refresh_file is not None: -+ status, output = subprocess_warm_upgrade( -+ self.refresh_file, self._devtype, self._subtype, self._slot_num) -+ if status: -+ log = "%s refresh file upg failed, msg: %s" % (self.device_name, output) -+ warmupgradeerror(log) -+ self.recover_save_value(self.save_set_reg_list) -+ self.do_fw_upg_finish_cmd(self.finish_cmd_list) -+ return False, log -+ warmupgradedebuglog("%s refresh file upg success" % self.device_name) -+ -+ # delay the preset time after the upgrade is complete -+ if self.after_upgrade_delay is not None: -+ time.sleep(self.after_upgrade_delay) -+ -+ # check something in the timeout period -+ if self.after_upgrade_delay_timeout is not None: -+ while self.time_delay < self.after_upgrade_delay_timeout: -+ -+ # check refresh finish flag -+ if self.refresh_finish_flag_check_config is not None: -+ ret = self.check_value(self.refresh_finish_flag_check_config) -+ if ret is False: -+ time.sleep(1) -+ self.time_delay = self.time_delay + 1 -+ warmupgradedebuglog("doing refresh_finish_flag_check, time_delay:%s" % self.time_delay) -+ continue -+ warmupgradedebuglog("%s upgrade_finish_flag_check success. self.time_delay:%d" -+ % (self.device_name, self.time_delay)) -+ -+ # doing logic device rw access test -+ ret = self.access_test(self.access_check_reg_config) -+ if ret: -+ warmupgradedebuglog( -+ "%s rw test success. self.time_delay:%d" % -+ (self.device_name, self.time_delay)) -+ break -+ time.sleep(1) -+ self.time_delay = self.time_delay + 1 -+ warmupgradedebuglog("doing access_test, self.time_delay:%s" % self.time_delay) -+ -+ if self.time_delay >= self.after_upgrade_delay_timeout: -+ log = "wait %s access test timeout" % self.device_name -+ warmupgradeerror(log) -+ self.recover_save_value(self.save_set_reg_list) -+ self.do_fw_upg_finish_cmd(self.finish_cmd_list) -+ return False, log -+ warmupgradedebuglog("%s access test success" % self.device_name) -+ -+ # recover reg -+ ret, log = self.recover_value(self.rw_recover_reg_list) -+ if ret is False: -+ warmupgradeerror("recover %s reg failed" % self.device_name) -+ self.recover_save_value(self.save_set_reg_list) -+ self.do_fw_upg_finish_cmd(self.finish_cmd_list) -+ return False, log -+ warmupgradedebuglog("recover %s reg success" % self.device_name) -+ # finally -+ ret1, log1 = self.recover_save_value(self.save_set_reg_list) -+ if ret1 is False: -+ warmupgradeerror("bmc upgrade recover save value failed, msg: %s" % log1) -+ ret2, log2 = self.do_fw_upg_finish_cmd(self.finish_cmd_list) -+ if ret2 is False: -+ warmupgradeerror("bmc upgrade do finish command failed, msg: %s" % log2) -+ if ret1 is False or ret2 is False: -+ return False, "upgrading %s recover save value or finish command failed" % self.device_name -+ return True, "upgrading %s success" % self.device_name -+ -+ except Exception as e: -+ log = "refresh file upgrade Exception happend, error log : %s" % str(e) -+ self.recover_save_value(self.save_set_reg_list) -+ self.do_fw_upg_finish_cmd(self.finish_cmd_list) -+ return False, log -+ -+ -+class RefreshUpgrade(RefreshUpgradeBase): -+ -+ def __init__(self, config, slot_num, devtype, subtype): -+ super(RefreshUpgrade, self).__init__(config, slot_num, devtype, subtype) -+ -+ def get_config(self): -+ super(RefreshUpgrade, self).get_config() -+ return self._config -+ -+ def get_slot_num(self): -+ super(RefreshUpgrade, self).get_slot_num() -+ return self._slot_num -+ -+ -+class WarmBasePlatform(): -+ -+ def __init__(self): -+ signal_init() -+ debug_init() -+ self.warm_upgrade_param = WARM_UPGRADE_PARAM.copy() -+ self.stop_services_cmd_list = self.warm_upgrade_param.get("stop_services_cmd", []) -+ self.start_services_cmd_list = self.warm_upgrade_param.get("start_services_cmd", []) -+ self.__warm_upgrade_config_list = [] -+ -+ def execute_command_list(self, cmd_list): -+ for cmd_item in cmd_list: -+ warmupgradedebuglog("execute cmd: %s" % cmd_item) -+ status, output = exec_os_cmd(cmd_item) -+ if status: -+ log = "execute %s failed, msg: %s" % (cmd_item, output) -+ warmupgradeerror(log) -+ return False, log -+ return True, "execute success" -+ -+ def stop_services_access(self): -+ return self.execute_command_list(self.stop_services_cmd_list) -+ -+ def start_services_access(self): -+ return self.execute_command_list(self.start_services_cmd_list) -+ -+ def check_slot_present(self, slot_present_config): -+ totalerr = 0 -+ presentbit = slot_present_config.get('presentbit') -+ ret, value = get_value(slot_present_config) -+ if ret is False: -+ return "NOT OK" -+ if isinstance(value, str): -+ val_t = int(value, 16) -+ else: -+ val_t = value -+ val_t = (val_t & (1 << presentbit)) >> presentbit -+ if val_t != slot_present_config.get('okval'): -+ status = "ABSENT" -+ else: -+ status = "PRESENT" -+ return status -+ -+ def linecard_present_check(self, slot_name, slot_present_config): -+ present_status = self.check_slot_present(slot_present_config) -+ present_status_tuple = ("ABSENT", "NOT OK") -+ if present_status in present_status_tuple: -+ return False, ("%s not present, warm upgrade exit" % slot_name) -+ warmupgradedebuglog("%s present" % slot_name) -+ return True, ("%s present" % slot_name) -+ -+ def start_warmupgrade(self): -+ try: -+ # start refresh file upgrade process -+ for dev in self.__warm_upgrade_config_list: -+ ret, log = dev.refresh_file_upgrade() -+ if ret is False: -+ return ret, log -+ return True, "all success" -+ except Exception as e: -+ log = "Exception happend, error log : %s" % str(e) -+ return False, log -+ -+ def do_warmupgrade(self, file, main_type, sub_type, slot, file_type, chain): -+ try: -+ # upgrade file existence check -+ if not os.path.isfile(file): -+ return False, "%s not found" % file -+ -+ # get slot config -+ slot_name = "slot%d" % slot -+ slot_config = self.warm_upgrade_param.get(slot_name, {}) -+ if len(slot_config) == 0: -+ return False, ("%s config not found" % slot_name) -+ -+ # linecard present check -+ slot_present_config = slot_config.get("present", {}) -+ if len(slot_present_config) != 0: -+ ret, log = self.linecard_present_check(slot_name, slot_present_config) -+ if ret is False: -+ return False, log -+ -+ # match file_type and chain_num get chain_config -+ file_type_config = slot_config.get(file_type, {}) -+ chain_name = "chain%d" % chain -+ chain_list = file_type_config.get(chain_name, []) -+ self.__warm_upgrade_config_list = [] -+ for refresh_config in chain_list: -+ # refresh_file existence check -+ refresh_file_judge_flag = refresh_config.get("refresh_file_judge_flag", 0) -+ if refresh_file_judge_flag == 1: -+ refresh_file = refresh_config.get("refresh_file", None) -+ if not os.path.isfile(refresh_file): -+ log = "%s not found" % refresh_file -+ return False, log -+ # each refresh_config add as an instance of RefreshUpgrade Class -+ refresh_instance = RefreshUpgrade(refresh_config, slot, main_type, sub_type) -+ self.__warm_upgrade_config_list.append(refresh_instance) -+ -+ ret, log = self.start_warmupgrade() -+ if ret is False: -+ warmupgradeerror("doing warm upgrade failed") -+ warmupgradeerror(log) -+ return ret, log -+ -+ except Exception as e: -+ log = "Exception happend, error log : %s" % str(e) -+ return False, log -+ return True, "all success" -+ -+ def do_warm_upgrade(self, file, main_type, sub_type, slot, file_type, chain): -+ print("+================================+") -+ print("|Begin warm upgrade, please wait..|") -+ ret, log = self.do_warmupgrade(file, main_type, sub_type, slot, file_type, chain) -+ if ret: -+ print("| warm upgrade succeeded! |") -+ print("+================================+") -+ sys.exit(0) -+ else: -+ print("| warm upgrade failed! |") -+ print("+================================+") -+ print("FAILED REASON:") -+ print("%s" % log) -+ sys.exit(1) -+ -+ -+@click.group(invoke_without_command=True, context_settings=CONTEXT_SETTINGS) -+@click.argument('file', required=True) -+@click.argument('main_type', required=True) -+@click.argument('sub_type', required=True) -+@click.argument('slot', required=True) -+@click.argument('file_type', required=True) -+@click.argument('chain', required=True) -+def main(file, main_type, sub_type, slot, file_type, chain): -+ '''warm upgrade''' -+ signal_init() -+ debug_init() -+ platform = WarmBasePlatform() -+ platform.do_warm_upgrade(file, int(main_type, 16), int(sub_type, 16), int(slot), file_type, int(chain)) -+ -+ -+# warm upgrade -+if __name__ == '__main__': -+ main() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/service/platform_driver.service b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_driver.service -new file mode 100644 -index 000000000..08a49d695 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_driver.service -@@ -0,0 +1,15 @@ -+[Unit] -+Description= Global Initialize platform drivers. -+After=local-fs.target -+Before=pmon.service platform_process.service -+#DefaultDependencies=no -+ -+[Service] -+Type=oneshot -+ExecStart=/usr/local/bin/platform_driver.py start -+ExecStop=/usr/local/bin/platform_driver.py stop -+RemainAfterExit=yes -+ -+[Install] -+WantedBy=multi-user.target -+ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/service/platform_process.service b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_process.service -new file mode 100644 -index 000000000..13dd77855 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_process.service -@@ -0,0 +1,16 @@ -+[Unit] -+Description= Global Load process. -+After=platform_driver.service -+Before=determine-reboot-cause.service pmon.service -+Requires=platform_driver.service -+#DefaultDependencies=no -+ -+[Service] -+Type=oneshot -+ExecStart=/usr/local/bin/platform_process.py start -+ExecStop=/usr/local/bin/platform_process.py stop -+RemainAfterExit=yes -+ -+[Install] -+WantedBy=multi-user.target -+ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/__init__.py -new file mode 100644 -index 000000000..b70995a58 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/__init__.py -@@ -0,0 +1,2 @@ -+__all__ = ["platform", "chassis", "sfp", "eeprom", "component", "thermal", "psu", "fan", "fan_drawer", "watchdog"] -+from . import platform -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/chassis.py -new file mode 100644 -index 000000000..b0ddc8691 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/chassis.py -@@ -0,0 +1,530 @@ -+#!/usr/bin/env python3 -+ -+############################################################################# -+# -+# -+# Module contains an implementation of SONiC Platform Base API and -+# provides the platform information -+# -+############################################################################# -+ -+try: -+ import time -+ import sys -+ from sonic_platform_base.chassis_base import ChassisBase -+ from sonic_platform.sfp import Sfp -+ from sonic_platform.psu import Psu -+ # from sonic_platform.fan import Fan -+ from sonic_platform.fan_drawer import FanDrawer -+ from sonic_platform.thermal import Thermal -+ # from sonic_platform.watchdog import Watchdog -+ from sonic_platform.component import Component -+ from sonic_platform.eeprom import Eeprom -+ from sonic_platform.dcdc import Dcdc -+ from plat_hal.baseutil import baseutil -+ -+ from plat_hal.interface import interface -+ -+except ImportError as error: -+ raise ImportError(str(error) + "- required module not found")from error -+ -+ -+class Chassis(ChassisBase): -+ """ -+ Platform-specific Chassis class -+ """ -+ # List of Dcdc objects representing all dcdc -+ # available on the chassis -+ _dcdc_list = None -+ -+ STATUS_INSERTED = "1" -+ STATUS_REMOVED = "0" -+ STATUS_NORMAL = "0" -+ STATUS_ABNORMAL = "1" -+ sfp_present_dict = {} -+ fan_present_dict = {} -+ voltage_status_dict = {} -+ -+ def __init__(self): -+ ChassisBase.__init__(self) -+ self._dcdc_list = [] -+ self.int_case = interface() -+ # Initialize SFP list -+ -+ # sfp.py will read eeprom contents and retrive the eeprom data. -+ # It will also provide support sfp controls like reset and setting -+ # low power mode. -+ # We pass the eeprom path and sfp control path from chassis.py -+ # So that sfp.py implementation can be generic to all platforms -+ try: -+ self._sfp_list = [] -+ self.port_num = baseutil.get_config().get("sfps", None).get("port_num", 0) -+ self.port_start_index = baseutil.get_config().get("sfps", None).get("port_index_start", 0) -+ # fix problem with first index is 1, we add a fake sfp node -+ if self.port_start_index == 1: -+ self._sfp_list.append(Sfp(1)) -+ -+ # sfp id always start at 1 -+ for index in range(1, self.port_num + 1): -+ self._sfp_list.append(Sfp(index)) -+ -+ for i in range(self.port_start_index, self.port_start_index + self.port_num): -+ self.sfp_present_dict[i] = self.STATUS_REMOVED -+ -+ except Exception as err: -+ print("SFP init error: %s" % str(err)) -+ -+ try: -+ self._eeprom = Eeprom(self.int_case) -+ except Exception as err: -+ print("EEPROM INIT ERROR %s" % str(err)) -+ -+ # Initialize watchdog -+ # self._watchdog = Watchdog() -+ fantray_num = self.int_case.get_fan_total_number() -+ for index in range(fantray_num): -+ fandrawer = FanDrawer(self.int_case, index + 1) -+ self._fan_drawer_list.append(fandrawer) -+ self._fan_list.extend(fandrawer._fan_list) -+ -+ psu_num = self.int_case.get_psu_total_number() -+ for index in range(psu_num): -+ psuobj = Psu(self.int_case, index + 1) -+ self._psu_list.append(psuobj) -+ -+ thermal_num = self.int_case.get_temp_id_number() -+ for index in range(thermal_num): -+ thermalobj = Thermal(self.int_case, index + 1) -+ self._thermal_list.append(thermalobj) -+ -+ component_num = self.int_case.get_cpld_total_number() -+ for index in range(component_num): -+ componentobj = Component(self.int_case, index + 1) -+ self._component_list.append(componentobj) -+ -+ dcdc_num = self.int_case.get_dcdc_total_number() -+ for index in range(dcdc_num): -+ dcdcobj = Dcdc(self.int_case, index + 1) -+ self._dcdc_list.append(dcdcobj) -+ -+ def get_name(self): -+ """ -+ Retrieves the name of the chassis -+ Returns: -+ string: The name of the chassis -+ """ -+ name = '' -+ sys_eeprom = self.get_eeprom() -+ if sys_eeprom is None: -+ return '' -+ -+ e = sys_eeprom.read_eeprom() -+ name = sys_eeprom.modelstr(e) -+ if name is None: -+ return '' -+ return name -+ -+ 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 -+ """ -+ model = '' -+ sys_eeprom = self.get_eeprom() -+ if sys_eeprom is None: -+ return '' -+ -+ e = sys_eeprom.read_eeprom() -+ model = sys_eeprom.modelnumber(e) -+ if model is None: -+ return '' -+ return model -+ -+ def get_serial_number(self): -+ """ -+ Retrieves the hardware serial number for the chassis -+ -+ Returns: -+ A string containing the hardware serial number for this chassis. -+ """ -+ serial_number = '' -+ sys_eeprom = self.get_eeprom() -+ if sys_eeprom is None: -+ return '' -+ -+ e = sys_eeprom.read_eeprom() -+ serial_number = sys_eeprom.serial_number_str(e) -+ if serial_number is None: -+ return '' -+ -+ return serial_number -+ -+ def get_revision(self): -+ """ -+ Retrieves the hardware revision of the device -+ -+ Returns: -+ string: Revision value of device -+ """ -+ device_version = '' -+ sys_eeprom = self.get_eeprom() -+ if sys_eeprom is None: -+ return '' -+ -+ e = sys_eeprom.read_eeprom() -+ device_version = sys_eeprom.deviceversion(e) -+ if device_version is None: -+ return '' -+ -+ return device_version -+ -+ def get_serial(self): -+ """ -+ Retrieves the serial number of the chassis (Service tag) -+ Returns: -+ string: Serial number of chassis -+ """ -+ return self.get_serial_number() -+ -+ 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_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 initizalize_system_led(self): -+ return True -+ -+ def set_status_led(self, color): -+ return False -+ -+ 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. -+ """ -+ ret, color = self.int_case.get_led_color_by_type('SYS_LED') -+ if ret is True: -+ return color -+ return 'N/A' -+ -+ 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' -+ """ -+ base_mac = '' -+ sys_eeprom = self.get_eeprom() -+ if sys_eeprom is None: -+ return '' -+ -+ e = sys_eeprom.read_eeprom() -+ base_mac = sys_eeprom.base_mac_addr(e) -+ if base_mac is None: -+ return '' -+ -+ return base_mac.upper() -+ -+ 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. -+ Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', -+ '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', -+ '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} -+ """ -+ sys_eeprom = self.get_eeprom() -+ if sys_eeprom is None: -+ return {} -+ return sys_eeprom.system_eeprom_info() -+ -+ def get_thermal_manager(self): -+ """ -+ Retrieves thermal manager class on this chassis -+ :return: A class derived from ThermalManagerBase representing the -+ specified thermal manager. ThermalManagerBase is returned as default -+ """ -+ return False -+ -+ 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. -+ """ -+ reboot_cause_msg = self.int_case.get_cpu_reboot_cause() -+ if "Power Loss" in reboot_cause_msg: -+ reboot_cause_type = self.REBOOT_CAUSE_POWER_LOSS -+ elif "Watchdog" in reboot_cause_msg: -+ reboot_cause_type = self.REBOOT_CAUSE_WATCHDOG -+ elif "BMC reboot" in reboot_cause_msg or "BMC powerdown" in reboot_cause_msg: -+ reboot_cause_type = self.REBOOT_CAUSE_HARDWARE_OTHER -+ elif "Thermal Overload: ASIC" in reboot_cause_msg: -+ reboot_cause_type = self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC -+ elif "Thermal Overload: Other" in reboot_cause_msg: -+ reboot_cause_type = self.REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER -+ elif "Other" in reboot_cause_msg: -+ reboot_cause_type = self.REBOOT_CAUSE_NON_HARDWARE -+ else: -+ reboot_cause_type = self.REBOOT_CAUSE_NON_HARDWARE -+ return (reboot_cause_type, reboot_cause_msg) -+ -+ def get_module(self, index): -+ """ -+ Retrieves module represented by (0-based) index -+ -+ Args: -+ index: An integer, the index (0-based) of the module to -+ retrieve -+ -+ Returns: -+ An object dervied from ModuleBase representing the specified -+ module -+ """ -+ module = None -+ -+ try: -+ if self.get_num_modules(): -+ module = self._module_list[index] -+ except IndexError: -+ sys.stderr.write("Module index {} out of range (0-{})\n".format( -+ index, len(self._module_list) - 1)) -+ -+ return module -+ -+ def get_fan_drawer(self, index): -+ """ -+ Retrieves fan drawers represented by (0-based) index -+ -+ Args: -+ index: An integer, the index (0-based) of the fan drawer to -+ retrieve -+ -+ Returns: -+ An object dervied from FanDrawerBase representing the specified fan -+ drawer -+ """ -+ fan_drawer = None -+ -+ try: -+ if self.get_num_fan_drawers(): -+ fan_drawer = self._fan_drawer_list[index] -+ except IndexError: -+ sys.stderr.write("Fan drawer index {} out of range (0-{})\n".format( -+ index, len(self._fan_drawer_list) - 1)) -+ -+ return fan_drawer -+ -+ 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): -+ - bool: True if call successful, False if not; -+ - dict: 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. -+ The known devices's device_id and device_event was defined as table below. -+ ----------------------------------------------------------------- -+ device | device_id | device_event | annotate -+ ----------------------------------------------------------------- -+ 'fan' '' '0' Fan removed -+ '1' Fan inserted -+ -+ 'sfp' '' '0' Sfp removed -+ '1' Sfp inserted -+ '2' I2C bus stuck -+ '3' Bad eeprom -+ '4' Unsupported cable -+ '5' High Temperature -+ '6' Bad cable -+ -+ 'voltage' '' '0' Vout normal -+ '1' Vout abnormal -+ -------------------------------------------------------------------- -+ Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0', '12':'1'}, -+ 'voltage':{'U20':'0', 'U21':'1'}} -+ Indicates that: -+ fan 0 has been removed, fan 2 has been inserted. -+ sfp 11 has been removed, sfp 12 has been inserted. -+ monitored voltage U20 became normal, voltage U21 became abnormal. -+ Note: For sfp, when event 3-6 happened, the module will not be avalaible, -+ XCVRD shall stop to read eeprom before SFP recovered from error status. -+ """ -+ -+ change_event_dict = {"fan": {}, "sfp": {}, "voltage": {}} -+ -+ start_time = time.time() -+ forever = False -+ -+ if timeout == 0: -+ forever = True -+ elif timeout > 0: -+ timeout = timeout / float(1000) # Convert to secs -+ else: -+ print("get_change_event:Invalid timeout value: %s" % timeout) -+ return False, change_event_dict -+ -+ end_time = start_time + timeout -+ if start_time > end_time: -+ print("get_change_event:time wrap / invalid timeout value: %s" % timeout) -+ return False, change_event_dict # Time wrap or possibly incorrect timeout -+ try: -+ while timeout >= 0: -+ # check for sfp -+ sfp_change_dict = self.get_transceiver_change_event() -+ # check for fan -+ fan_change_dict = self.get_fan_change_event() -+ # check for voltage -+ voltage_change_dict = self.get_voltage_change_event() -+ -+ if sfp_change_dict or fan_change_dict or voltage_change_dict: -+ change_event_dict["sfp"] = sfp_change_dict -+ change_event_dict["fan"] = fan_change_dict -+ change_event_dict["voltage"] = voltage_change_dict -+ return True, change_event_dict -+ 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, change_event_dict -+ except Exception as e: -+ print(e) -+ print("get_change_event: Should not reach here.") -+ return False, change_event_dict -+ -+ def get_transceiver_change_event(self): -+ current_sfp_present_dict = {} -+ ret_dict = {} -+ -+ # Check for OIR events and return ret_dict -+ for i in range(self.port_start_index, self.port_start_index + self.port_num): -+ sfp = self._sfp_list[i] -+ if sfp.get_presence(): -+ current_sfp_present_dict[i] = self.STATUS_INSERTED -+ -+ else: -+ current_sfp_present_dict[i] = self.STATUS_REMOVED -+ -+ # Update reg value -+ if current_sfp_present_dict == self.sfp_present_dict: -+ return ret_dict -+ -+ for index, status in current_sfp_present_dict.items(): -+ if self.sfp_present_dict[index] != status: -+ ret_dict[index] = status -+ -+ self.sfp_present_dict = current_sfp_present_dict -+ -+ return ret_dict -+ -+ def get_fan_change_event(self): -+ current_fan_present_dict = {} -+ ret_dict = {} -+ -+ # Check for OIR events and return ret_dict -+ for index, fan in enumerate(self._fan_list): -+ if fan.get_presence() is True: -+ current_fan_present_dict[index] = self.STATUS_INSERTED -+ else: -+ current_fan_present_dict[index] = self.STATUS_REMOVED -+ -+ if len(self.fan_present_dict) == 0: # first time -+ self.fan_present_dict = current_fan_present_dict -+ return {} -+ -+ if current_fan_present_dict == self.fan_present_dict: -+ return {} -+ -+ # updated fan_present_dict -+ for index, status in current_fan_present_dict.items(): -+ if self.fan_present_dict[index] != status: -+ ret_dict[str(index)] = status -+ self.fan_present_dict = current_fan_present_dict -+ return ret_dict -+ -+ def get_voltage_change_event(self): -+ current_voltage_status_dict = {} -+ ret_dict = {} -+ -+ # Check for OIR events and return ret_dict -+ for index, dcdc in enumerate(self._dcdc_list): -+ name = dcdc.get_name() -+ value = dcdc.get_value() -+ high = dcdc.get_high_threshold() -+ low = dcdc.get_low_threshold() -+ if (value is None) or (value > high) or (value < low): -+ current_voltage_status_dict[name] = self.STATUS_ABNORMAL -+ else: -+ current_voltage_status_dict[name] = self.STATUS_NORMAL -+ -+ if len(self.voltage_status_dict) == 0: # first time -+ self.voltage_status_dict = current_voltage_status_dict -+ return {} -+ -+ if current_voltage_status_dict == self.voltage_status_dict: -+ return {} -+ -+ # updated voltage_status_dict -+ for name, status in current_voltage_status_dict.items(): -+ if self.voltage_status_dict[name] != status: -+ ret_dict[name] = status -+ self.voltage_status_dict = current_voltage_status_dict -+ return ret_dict -+ -+ -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/component.py -new file mode 100644 -index 000000000..fa674a98a ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/component.py -@@ -0,0 +1,226 @@ -+#!/usr/bin/env python3 -+ -+######################################################################## -+# -+# 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 time -+ import subprocess -+ import os -+ from sonic_platform_base.component_base import ComponentBase -+except ImportError as e: -+ raise ImportError(str(e) + "- required module not found") from e -+ -+ -+FIRMWARE_UPDATE_DIR = "/tmp/.firmwareupdate/" -+ -+class Component(ComponentBase): -+ """Platform-specific Component class""" -+ -+ def __init__(self, interface_obj, index): -+ self.cpld_dict = {} -+ self.int_case = interface_obj -+ self.index = index -+ self.update_time = 0 -+ self.cpld_id = "CPLD" + str(index) -+ -+ def cpld_dict_update(self): -+ local_time = time.time() -+ if not self.cpld_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds -+ self.update_time = local_time -+ self.cpld_dict = self.int_case.get_cpld_version_by_id(self.cpld_id) -+ -+ def get_slot(self): -+ self.cpld_dict_update() -+ return self.cpld_dict["Slot"] -+ -+ def get_warm_upgrade_flag(self): -+ self.cpld_dict_update() -+ return self.cpld_dict["Warm"] -+ -+ def get_name(self): -+ """ -+ Retrieves the name of the component -+ -+ Returns: -+ A string containing the name of the component -+ """ -+ self.cpld_dict_update() -+ return self.cpld_dict["Name"] -+ -+ def get_description(self): -+ """ -+ Retrieves the description of the component -+ -+ Returns: -+ A string containing the description of the component -+ """ -+ self.cpld_dict_update() -+ return self.cpld_dict["Desc"] -+ -+ def get_firmware_version(self): -+ """ -+ Retrieves the firmware version of the component -+ -+ Note: the firmware version will be read from HW -+ -+ Returns: -+ A string containing the firmware version of the component -+ """ -+ self.cpld_dict_update() -+ return self.cpld_dict["Version"] -+ -+ 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 -+ """ -+ raise NotImplementedError -+ -+ def get_firmware_update_notification(self, image_path): -+ """ -+ Retrieves a notification on what should be done in order to complete -+ the component firmware update -+ -+ Args: -+ image_path: A string, path to firmware image -+ -+ Returns: -+ A string containing the component firmware update notification if required. -+ By default 'None' value will be used, which indicates that no actions are required -+ """ -+ return None -+ -+ def install_firmware(self, image_path): -+ """ -+ Installs firmware to the component -+ -+ This API performs firmware installation only: this may/may not be the same as firmware update. -+ 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 must be done manually by user -+ -+ Note: in case immediate actions are required to complete the component firmware update -+ (e.g., reboot, power cycle, etc.) - will be done automatically by API and no return value provided -+ -+ Args: -+ image_path: A string, path to firmware image -+ -+ Returns: -+ A boolean, True if install was successful, False if not -+ """ -+ if not os.path.isfile(image_path): -+ print("ERROR: %s not found" % image_path) -+ return False -+ cmdstr = "upgrade.py cold %s %d" % (image_path, self.get_slot()) -+ status, output = subprocess.getstatusoutput(cmdstr) -+ if status == 0: -+ print("INFO: %s firmware install succeeded" % self.get_name()) -+ return True -+ print("%s install failed. status:%d, output:\n%s" % (self.get_name(), status, output)) -+ return False -+ -+ 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 -+ """ -+ if not os.path.isfile(image_path): -+ raise RuntimeError("ERROR: %s not found" % image_path) -+ -+ if self.get_warm_upgrade_flag() == 1: # use warm upgrade -+ cmdstr = "upgrade.py warm %s %d" % (image_path, self.get_slot()) -+ else: -+ cmdstr = "upgrade.py cold %s %d" % (image_path, self.get_slot()) -+ status, output = subprocess.getstatusoutput(cmdstr) -+ if status == 0: -+ if self.get_warm_upgrade_flag() != 1: # not support warm upgrade, need to cold reboot -+ print("INFO: %s firmware install succeeded" % self.get_name()) -+ print("INFO: please cold reboot to make the %s firmware up-to-date" % self.get_name()) -+ else: -+ print("INFO: %s firmware update succeeded" % self.get_name()) -+ print("INFO: %s firmware version up-to-date" % self.get_name()) -+ return None -+ raise RuntimeError(output) -+ -+ def auto_update_firmware(self, image_path, boot_type): -+ """ -+ Updates firmware of the component -+ -+ This API performs firmware update automatically based on boot_type: it assumes firmware installation -+ and/or creating a loading task during the reboot, if needed, 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 during the reboot. -+ The loading task will be created by API. -+ -+ Args: -+ image_path: A string, path to firmware image -+ boot_type: A string, reboot type following the upgrade -+ - none/fast/warm/cold -+ -+ Returns: -+ Output: A return code -+ return_code: An integer number, status of component firmware auto-update -+ - return code of a positive number indicates successful auto-update -+ - status_installed = 1 -+ - status_updated = 2 -+ - status_scheduled = 3 -+ - return_code of a negative number indicates failed auto-update -+ - status_err_boot_type = -1 -+ - status_err_image = -2 -+ - status_err_unknown = -3 -+ -+ Raises: -+ RuntimeError: auto-update failure cause -+ """ -+ if not os.path.isfile(image_path): -+ print("ERROR: %s not found" % image_path) -+ return -2 -+ -+ if not os.path.isdir(FIRMWARE_UPDATE_DIR): -+ os.mkdir(FIRMWARE_UPDATE_DIR) -+ -+ warm_upgrade_flag = self.get_warm_upgrade_flag() -+ file_name = os.path.basename(image_path) -+ file_path = os.path.join(FIRMWARE_UPDATE_DIR, file_name) -+ if os.path.exists(file_path): # firmware already update -+ if warm_upgrade_flag == 1: -+ print("INFO: %s firmware update succeeded, firmware version up-to-date" % self.get_name()) -+ return 2 -+ print("INFO: %s firmware install succeeded, please cold reboot to make it up-to-date" % self.get_name()) -+ return 1 -+ -+ if warm_upgrade_flag == 1: # use warm upgrade -+ cmdstr = "upgrade.py warm %s %d" % (image_path, self.get_slot()) -+ else: -+ cmdstr = "upgrade.py cold %s %d" % (image_path, self.get_slot()) -+ status, output = subprocess.getstatusoutput(cmdstr) -+ if status == 0: -+ os.mknod(file_path) -+ if warm_upgrade_flag == 1: -+ print("INFO: %s firmware update succeeded, firmware version up-to-date" % self.get_name()) -+ return 2 -+ print("INFO: %s firmware install succeeded, please cold reboot to make it up-to-date" % self.get_name()) -+ return 1 -+ print("%s update failed, status:%d, output:\n%s" % (self.get_name(), status, output)) -+ return -3 -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/dcdc.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/dcdc.py -new file mode 100644 -index 000000000..494d4aa61 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/dcdc.py -@@ -0,0 +1,85 @@ -+#!/usr/bin/env python3 -+ -+######################################################################## -+# -+# Module contains an implementation of SONiC Platform Base API and -+# provides the Thermals' information which are available in the platform -+# -+######################################################################## -+import time -+ -+ -+class Dcdc(object): -+ -+ def __init__(self, interface_obj, index): -+ self.dcdc_dict = {} -+ self.int_case = interface_obj -+ self.index = index -+ self.update_time = 0 -+ self.dcdc_id = "DCDC" + str(index) -+ -+ def dcdc_dict_update(self): -+ local_time = time.time() -+ if not self.dcdc_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds -+ self.update_time = local_time -+ self.dcdc_dict = self.int_case.get_dcdc_by_id(self.dcdc_id) -+ -+ def get_name(self): -+ """ -+ Retrieves the name of the sensor -+ -+ Returns: -+ string: The name of the sensor -+ """ -+ self.dcdc_dict_update() -+ return self.dcdc_dict["Name"] -+ -+ def get_value(self): -+ """ -+ Retrieves current value reading from sensor -+ """ -+ self.dcdc_dict_update() -+ value = self.dcdc_dict["Value"] -+ if value is None: -+ value = 0 -+ return round(float(value), 3) -+ -+ def get_high_threshold(self): -+ """ -+ Retrieves the high threshold temperature of sensor -+ """ -+ self.dcdc_dict_update() -+ value = self.dcdc_dict["High"] -+ if value is None: -+ value = 0 -+ return round(float(value), 3) -+ -+ def get_low_threshold(self): -+ """ -+ Retrieves the low threshold temperature of sensor -+ """ -+ self.dcdc_dict_update() -+ value = self.dcdc_dict["Low"] -+ if value is None: -+ value = 0 -+ return round(float(value), 3) -+ -+ def get_high_critical_threshold(self): -+ """ -+ Retrieves the high critical threshold temperature of sensor -+ """ -+ self.dcdc_dict_update() -+ value = self.dcdc_dict["Max"] -+ if value is None: -+ value = 0 -+ return round(float(value), 3) -+ -+ def get_low_critical_threshold(self): -+ """ -+ Retrieves the low critical threshold temperature of sensor -+ """ -+ self.dcdc_dict_update() -+ value = self.dcdc_dict["Min"] -+ if value is None: -+ value = 0 -+ return round(float(value), 3) -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/eeprom.py -new file mode 100644 -index 000000000..05fcc3c25 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/eeprom.py -@@ -0,0 +1,92 @@ -+#!/usr/bin/env python3 -+######################################################################## -+# -+# 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. -+# - PSU EEPROM : Contains Serial number, Part number, Service Tag, -+# PSU type, Revision. -+# - Fan EEPROM : Contains Serial number, Part number, Service Tag, -+# Fan type, Number of Fans in Fantray, Revision. -+######################################################################## -+ -+try: -+ from sonic_eeprom import eeprom_tlvinfo -+except ImportError as error: -+ raise ImportError(str(error) + "- required module not found") from error -+ -+ -+class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): -+ -+ def __init__(self, interface_obj): -+ self.int_case = interface_obj -+ self.name = "ONIE_E2" -+ -+ eeprom_path = self.int_case.get_onie_e2_path(self.name) -+ if eeprom_path is None: -+ raise ValueError("get eeprom path failed") -+ -+ super().__init__(eeprom_path, 0, "", True) -+ -+ def modelnumber(self, e): -+ ''' -+ Returns the value field of the model(part) number TLV as a string -+ ''' -+ (is_valid, t) = self.get_tlv_field(e, self._TLV_CODE_PART_NUMBER) -+ if not is_valid: -+ return super().part_number_str(e) -+ -+ return t[2].decode("ascii") -+ -+ def deviceversion(self, e): -+ ''' -+ Returns the value field of the Device Version as a string -+ ''' -+ (is_valid, t) = self.get_tlv_field(e, self._TLV_CODE_DEVICE_VERSION) -+ if not is_valid: -+ return "N/A" -+ -+ return str(ord(t[2])) -+ -+ def 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. -+ Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', -+ '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', -+ '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} -+ ''' -+ sys_eeprom_dict = {} -+ e = self.read_eeprom() -+ if self._TLV_HDR_ENABLED: -+ if not self.is_valid_tlvinfo_header(e): -+ return {} -+ total_len = (e[9] << 8) | e[10] -+ tlv_index = self._TLV_INFO_HDR_LEN -+ tlv_end = self._TLV_INFO_HDR_LEN + total_len -+ else: -+ tlv_index = self.eeprom_start -+ tlv_end = self._TLV_INFO_MAX_LEN -+ -+ while (tlv_index + 2) < len(e) and tlv_index < tlv_end: -+ if not self.is_valid_tlv(e[tlv_index:]): -+ break -+ -+ tlv = e[tlv_index:tlv_index + 2 + e[tlv_index + 1]] -+ code = "0x%02X" % tlv[0] -+ name, value = self.decoder(None, tlv) -+ sys_eeprom_dict[code] = value -+ -+ if e[tlv_index] == self._TLV_CODE_QUANTA_CRC or \ -+ e[tlv_index] == self._TLV_CODE_CRC_32: -+ break -+ tlv_index += e[tlv_index + 1] + 2 -+ -+ return sys_eeprom_dict -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan.py -new file mode 100644 -index 000000000..be1c8ce8f ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan.py -@@ -0,0 +1,314 @@ -+#!/usr/bin/env python3 -+######################################################################## -+# -+# Module contains an implementation of SONiC Platform Base API and -+# provides the Fans' information which are available in the platform. -+# -+######################################################################## -+ -+try: -+ import time -+ from sonic_platform_base.fan_base import FanBase -+except ImportError as e: -+ raise ImportError(str(e) + "- required module not found") from e -+ -+ -+class Fan(FanBase): -+ """Platform-specific Fan class""" -+ -+ def __init__(self, interface_obj, fantray_index, fan_index, psu_fan=False, psu_index=0): -+ self.fan_dict = {} -+ self.int_case = interface_obj -+ self.fantray_index = fantray_index -+ self.fan_index = fan_index -+ self.psu_index = psu_index -+ self.is_psu_fan = psu_fan -+ self.update_time = 0 -+ if not self.is_psu_fan: -+ self.name = "FAN" + str(fantray_index) -+ else: -+ self.name = "PSU" + str(psu_index) -+ -+ def fan_dict_update(self): -+ local_time = time.time() -+ if not self.fan_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds -+ self.update_time = local_time -+ if not self.is_psu_fan: -+ self.fan_dict = self.int_case.get_fan_info(self.name) -+ else: -+ self.fan_dict = self.int_case.get_psu_fru_info(self.name) -+ -+ def get_name(self): -+ """ -+ Retrieves the fan name -+ Returns: -+ string: The name of the device -+ """ -+ if not self.is_psu_fan: -+ return "Fantray{}_{}".format(self.fantray_index, self.fan_index) -+ return "PSU{}_FAN{}".format(self.psu_index, self.fan_index) -+ -+ def get_model(self): -+ """ -+ Retrieves the part number of the FAN -+ Returns: -+ string: Part number of FAN -+ """ -+ if not self.is_psu_fan: -+ self.fan_dict_update() -+ return self.fan_dict["DisplayName"] -+ return 'N/A' -+ -+ def get_serial(self): -+ """ -+ Retrieves the serial number of the FAN -+ Returns: -+ string: Serial number of FAN -+ """ -+ if not self.is_psu_fan: -+ self.fan_dict_update() -+ return self.fan_dict["SN"] -+ return 'N/A' -+ -+ def get_presence(self): -+ """ -+ Retrieves the presence of the FAN -+ Returns: -+ bool: True if fan is present, False if not -+ """ -+ if not self.is_psu_fan: -+ return self.int_case.get_fan_presence(self.name) -+ return self.int_case.get_psu_presence(self.name) -+ -+ def get_status(self): -+ """ -+ Retrieves the operational status of the FAN -+ Returns: -+ bool: True if FAN is operating properly, False if not -+ """ -+ if not self.get_presence(): -+ return False -+ -+ if not self.is_psu_fan: -+ fan_dir = {} -+ fan_dir = self.int_case.get_fan_info_rotor(self.name) -+ # get fan rotor pwm -+ rotor_name = "Rotor" + str(self.fan_index) -+ value = fan_dir[rotor_name]["Speed"] -+ min_speed = fan_dir[rotor_name]["SpeedMin"] -+ max_speed = fan_dir[rotor_name]["SpeedMax"] -+ tolerance = fan_dir[rotor_name]["Tolerance"] -+ else: -+ psu_status_dict = self.int_case.get_psu_status(self.name) -+ value = psu_status_dict["FanSpeed"]["Value"] -+ min_speed = psu_status_dict["FanSpeed"]["Min"] -+ max_speed = psu_status_dict["FanSpeed"]["Max"] -+ tolerance = psu_status_dict["FanSpeed"]["Tolerance"] -+ -+ if isinstance(tolerance, str) or tolerance is None: -+ tolerance = 30 -+ -+ if isinstance(value, str) or value is None: -+ if self.is_psu_fan: -+ psu_status_dict = self.int_case.get_psu_status(self.name) -+ if psu_status_dict["OutputStatus"] is True: -+ return True -+ return False -+ -+ if value < min_speed: -+ return False -+ -+ speed = int(value * 100 / max_speed) -+ if speed > 100: -+ speed = 100 -+ elif speed < 0: -+ speed = 0 -+ target = self.get_target_speed() -+ -+ if (speed - target) > target * tolerance / 100: -+ return False -+ if (target - speed) > target * tolerance / 100: -+ return False -+ -+ return True -+ -+ 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 True -+ -+ def get_direction(self): -+ """ -+ Retrieves the fan airflow direction -+ Returns: -+ A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST -+ depending on fan direction -+ -+ Notes: -+ - Forward/Exhaust : Air flows from Port side to Fan side. -+ - Reverse/Intake : Air flows from Fan side to Port side. -+ """ -+ self.fan_dict_update() -+ air_flow = self.fan_dict["AirFlow"] -+ if air_flow is not None: -+ return air_flow -+ return self.FAN_DIRECTION_NOT_APPLICABLE -+ -+ def get_speed(self): -+ """ -+ Retrieves the speed of fan as a percentage of full speed -+ -+ Returns: -+ An integer, the percentage of full fan speed, in the range 0 (off) -+ to 100 (full speed) -+ """ -+ if not self.get_presence(): -+ return 0 -+ -+ if not self.is_psu_fan: -+ fan_dir = {} -+ fan_dir = self.int_case.get_fan_info_rotor(self.name) -+ # get fan rotor pwm -+ rotor_name = "Rotor" + str(self.fan_index) -+ value = fan_dir[rotor_name]["Speed"] -+ max_speed = fan_dir[rotor_name]["SpeedMax"] -+ else: -+ psu_status_dict = self.int_case.get_psu_status(self.name) -+ value = psu_status_dict["FanSpeed"]["Value"] -+ max_speed = psu_status_dict["FanSpeed"]["Max"] -+ -+ if isinstance(value, str) or value is None: -+ return None -+ pwm = value * 100 / max_speed -+ if pwm > 100: -+ pwm = 100 -+ elif pwm < 0: -+ pwm = 0 -+ return int(pwm) -+ -+ 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 -+ """ -+ # The default tolerance value is fixed as 30% -+ if not self.is_psu_fan: -+ fan_dir = {} -+ fan_dir = self.int_case.get_fan_info_rotor(self.name) -+ # get fan rotor tolerance -+ rotor_name = "Rotor" + str(self.fan_index) -+ tolerance = fan_dir[rotor_name]["Tolerance"] -+ else: -+ psu_status_dict = self.int_case.get_psu_status(self.name) -+ tolerance = psu_status_dict["FanSpeed"]["Tolerance"] -+ -+ if isinstance(tolerance, str) or tolerance is None: -+ return 30 -+ return tolerance -+ -+ def fan_set_speed_pwm(self, pwm): -+ status = self.int_case.set_fan_speed_pwm(self.name, self.fan_index, pwm) -+ if status == -1: -+ return False -+ return True -+ -+ 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 not self.is_psu_fan: -+ return self.fan_set_speed_pwm(speed) -+ return self.int_case.set_psu_fan_speed_pwm(self.name, int(speed)) -+ -+ 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. -+ """ -+ # not supported -+ 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 self.is_psu_fan: -+ # No LED available for PSU Fan -+ return 'N/A' -+ -+ if not self.get_presence(): -+ return 'N/A' -+ -+ ret, color = self.int_case.get_fan_led(self.name) -+ if ret is True: -+ return color -+ 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) -+ """ -+ if not self.is_psu_fan: -+ # get fan rotor pwm -+ pwm = int(self.int_case.get_fan_speed_pwm(self.name, self.fan_index)) -+ else: -+ psu_status_dict = self.int_case.get_psu_status(self.name) -+ if psu_status_dict["InputStatus"] is False: -+ pwm = 0 -+ else: -+ pwm = self.get_speed() # target equal to real pwm, to avoid alarm -+ if pwm is None: -+ return None -+ return int(pwm) -+ -+ def get_vendor(self): -+ """ -+ Retrieves the vendor name of the fan -+ -+ Returns: -+ string: Vendor name of fan -+ """ -+ if not self.is_psu_fan: -+ return "WB" -+ return 'N/A' -+ -+ def get_revision(self): -+ """ -+ Retrieves the hardware revision of the device -+ -+ Returns: -+ string: Revision value of device -+ """ -+ if not self.is_psu_fan: -+ self.fan_dict_update() -+ return self.fan_dict["HW"] -+ return 'N/A' -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan_drawer.py -new file mode 100644 -index 000000000..f0b039648 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan_drawer.py -@@ -0,0 +1,167 @@ -+#!/usr/bin/env python3 -+# -+# fan_drawer_base.py -+# -+# Abstract base class for implementing a platform-specific class with which -+# to interact with a fan drawer module in SONiC -+# -+ -+try: -+ import time -+ from sonic_platform_base.fan_drawer_base import FanDrawerBase -+ from sonic_platform.fan import Fan -+except ImportError as e: -+ raise ImportError(str(e) + "- required module not found") from e -+ -+ -+class FanDrawer(FanDrawerBase): -+ """ -+ Abstract base class for interfacing with a fan drawer -+ """ -+ # Device type definition. Note, this is a constant. -+ DEVICE_TYPE = "fan_drawer" -+ -+ def __init__(self, interface_obj, fantray_index): -+ FanDrawerBase.__init__(self) -+ self.fantray_dict = {} -+ self.fantray_update_time = 0 -+ self.fantray_index = fantray_index -+ self.int_case = interface_obj -+ self.fantrayname = "FAN" + str(fantray_index) -+ self.num_fans_per_fantray = self.int_case.get_fan_rotor_number(self.fantrayname) -+ for i in range(self.num_fans_per_fantray): -+ self._fan_list.append(Fan(interface_obj, fantray_index, i + 1)) -+ -+ def fantray_dict_update(self): -+ local_time = time.time() -+ # update data every 1 seconds -+ if not self.fantray_dict or (local_time - self.fantray_update_time) >= 1: -+ self.fantray_update_time = local_time -+ self.fantray_dict = self.int_case.get_fan_info(self.fantrayname) -+ -+ def get_name(self): -+ """ -+ Retrieves the name of the device -+ Returns: -+ string: The name of the device -+ """ -+ return "Fantray{}".format(self.fantray_index) -+ -+ def get_presence(self): -+ """ -+ Retrieves the presence of the FAN -+ Returns: -+ bool: True if fan is present, False if not -+ """ -+ return self.int_case.get_fan_presence(self.fantrayname) -+ -+ def get_model(self): -+ """ -+ Retrieves the part number of the FAN -+ Returns: -+ string: Part number of FAN -+ """ -+ self.fantray_dict_update() -+ return self.fantray_dict["NAME"] -+ -+ def get_serial(self): -+ """ -+ Retrieves the serial number of the FAN -+ Returns: -+ string: Serial number of FAN -+ """ -+ self.fantray_dict_update() -+ return self.fantray_dict["SN"] -+ -+ def get_revision(self): -+ """ -+ Retrieves the hardware revision of the device -+ -+ Returns: -+ string: Revision value of device -+ """ -+ self.fantray_dict_update() -+ return self.fantray_dict["HW"] -+ -+ def get_status(self): -+ """ -+ Retrieves the operational status of the FAN -+ Returns: -+ bool: True if FAN is operating properly, False if not -+ """ -+ for i in range(self.num_fans_per_fantray): -+ if self._fan_list[i].get_status() is False: -+ return False -+ return True -+ -+ 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 True -+ -+ def get_num_fans(self): -+ """ -+ Retrieves the number of fans available on this fan drawer -+ Returns: -+ An integer, the number of fan modules available on this fan drawer -+ """ -+ return len(self._fan_list) -+ -+ def get_all_fans(self): -+ """ -+ Retrieves all fan modules available on this fan drawer -+ Returns: -+ A list of objects derived from FanBase representing all fan -+ modules available on this fan drawer -+ """ -+ return self._fan_list -+ -+ 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 -+ """ -+ # not supported -+ 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' -+ -+ ret, color = self.int_case.get_fan_led(self.fantrayname) -+ if ret is True: -+ return color -+ return 'N/A' -+ -+ def get_maximum_consumed_power(self): -+ """ -+ Retrives the maximum power drawn by Fan Drawer -+ -+ Returns: -+ A float, with value of the maximum consumable power of the -+ component. -+ """ -+ self.fantray_dict_update() -+ return self.fantray_dict["PowerMax"] -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/pcie.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/pcie.py -new file mode 100644 -index 000000000..8ea66f339 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/pcie.py -@@ -0,0 +1,21 @@ -+#!/usr/bin/env python3 -+# -*- coding: utf-8 -*- -+ -+######################################################################## -+# -+# Module contains a platform specific implementation of SONiC Platform -+# Base PCIe class -+# -+######################################################################## -+ -+try: -+ from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil -+except ImportError as e: -+ raise ImportError(str(e) + "- required module not found") from e -+ -+ -+class Pcie(PcieUtil): -+ """Platform-specific Pcie class""" -+ -+ def __init__(self, platform_path): -+ PcieUtil.__init__(self, platform_path) -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/platform.py -new file mode 100644 -index 000000000..4d6fe03d9 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/platform.py -@@ -0,0 +1,24 @@ -+#!/usr/bin/env python3 -+ -+############################################################################# -+# -+# 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): -+ """ -+ Platform-specific class -+ """ -+ -+ def __init__(self): -+ PlatformBase.__init__(self) -+ self._chassis = Chassis() -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/psu.py -new file mode 100644 -index 000000000..2a634ca6b ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/psu.py -@@ -0,0 +1,359 @@ -+#!/usr/bin/env python3 -+######################################################################## -+# -+# Module contains an implementation of SONiC Platform Base API and -+# provides the PSUs' information which are available in the platform -+# -+######################################################################## -+ -+ -+try: -+ import time -+ from sonic_platform_base.psu_base import PsuBase -+ from sonic_platform.fan import Fan -+except ImportError as e: -+ raise ImportError(str(e) + "- required module not found") from e -+ -+ -+class Psu(PsuBase): -+ """Platform-specific PSU class""" -+ -+ def __init__(self, interface_obj, index): -+ self.psu_dict = {} -+ self.psu_status_dict = {} -+ self.psu_power_dict = {} -+ self._fan_list = [] -+ self._thermal_list = [] -+ self.int_case = interface_obj -+ self.index = index -+ self.name = "PSU" + str(index) -+ -+ self.psu_dict_update_time = 0 -+ self.psu_status_dict_update_time = 0 -+ self.psu_power_dict_update_time = 0 -+ -+ self._fan_list.append(Fan(self.int_case, 1, 1, psu_fan=True, psu_index=index)) -+ -+ def psu_dict_update(self): -+ local_time = time.time() -+ if not self.psu_dict or (local_time - self.psu_dict_update_time) >= 1: # update data every 1 seconds -+ self.psu_dict_update_time = local_time -+ self.psu_dict = self.int_case.get_psu_fru_info(self.name) -+ -+ def psu_status_dict_update(self): -+ local_time = time.time() -+ if not self.psu_status_dict or ( -+ local_time - self.psu_status_dict_update_time) >= 1: # update data every 1 seconds -+ self.psu_status_dict_update_time = local_time -+ self.psu_status_dict = self.int_case.get_psu_status(self.name) -+ -+ def psu_power_dict_update(self): -+ local_time = time.time() -+ if not self.psu_power_dict or ( -+ local_time - self.psu_power_dict_update_time) >= 1: # update data every 1 seconds -+ self.psu_power_dict_update_time = local_time -+ self.psu_power_dict = self.int_case.get_psu_power_status(self.name) -+ -+ def get_name(self): -+ """ -+ Retrieves the name of the device -+ -+ Returns: -+ string: The name of the device -+ """ -+ return "Psu{}".format(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 -+ """ -+ return self.int_case.get_psu_presence(self.name) -+ -+ def get_model(self): -+ """ -+ Retrieves the part number of the PSU -+ -+ Returns: -+ string: Part number of PSU -+ """ -+ self.psu_dict_update() -+ return self.psu_dict["DisplayName"] -+ -+ def get_serial(self): -+ """ -+ Retrieves the serial number of the PSU -+ -+ Returns: -+ string: Serial number of PSU -+ """ -+ self.psu_dict_update() -+ return self.psu_dict["SN"] -+ -+ def get_status(self): -+ """ -+ Retrieves the operational status of the PSU -+ -+ Returns: -+ bool: True if PSU is operating properly, False if not -+ """ -+ return self.int_case.get_psu_input_output_status(self.name) -+ -+ 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 True -+ -+ def get_voltage(self): -+ """ -+ Retrieves current PSU voltage output -+ -+ Returns: -+ A float number, the output voltage in volts, -+ e.g. 12.1 -+ """ -+ self.psu_status_dict_update() -+ if self.psu_status_dict["OutputStatus"] is False: -+ value = 0 -+ else: -+ self.psu_power_dict_update() -+ value = self.psu_power_dict["Outputs"]["Voltage"]["Value"] -+ if value is None: -+ return None -+ return round(float(value), 1) -+ -+ def get_current(self): -+ """ -+ Retrieves present electric current supplied by PSU -+ -+ Returns: -+ A float number, electric current in amperes, -+ e.g. 15.4 -+ """ -+ self.psu_status_dict_update() -+ if self.psu_status_dict["OutputStatus"] is False: -+ value = 0 -+ else: -+ self.psu_power_dict_update() -+ value = self.psu_power_dict["Outputs"]["Current"]["Value"] -+ if value is None: -+ return None -+ return round(float(value), 1) -+ -+ def get_power(self): -+ """ -+ Retrieves current energy supplied by PSU -+ -+ Returns: -+ A float number, the power in watts, -+ e.g. 302.6 -+ """ -+ self.psu_status_dict_update() -+ if self.psu_status_dict["OutputStatus"] is False: -+ value = 0 -+ else: -+ self.psu_power_dict_update() -+ value = self.psu_power_dict["Outputs"]["Power"]["Value"] -+ if value is None: -+ return None -+ return round(float(value), 1) -+ -+ 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 self.int_case.get_psu_input_output_status(self.name) -+ -+ 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" -+ if self.int_case.get_psu_input_output_status(self.name): -+ return self.STATUS_LED_COLOR_GREEN -+ return self.STATUS_LED_COLOR_RED -+ -+ 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 -+ """ -+ # not supported -+ return False -+ -+ def get_temperature(self): -+ """ -+ Retrieves current temperature reading from PSU -+ -+ Returns: -+ A float number of current temperature in Celsius up to nearest thousandth -+ of one degree Celsius, e.g. 30.125 -+ """ -+ self.psu_status_dict_update() -+ value = self.psu_status_dict["Temperature"]["Value"] -+ if value is None: -+ return None -+ return round(float(value), 1) -+ -+ def get_temperature_high_threshold(self): -+ """ -+ Retrieves the high threshold temperature of PSU -+ -+ Returns: -+ A float number, the high threshold temperature of PSU in Celsius -+ up to nearest thousandth of one degree Celsius, e.g. 30.125 -+ """ -+ self.psu_status_dict_update() -+ value = self.psu_status_dict["Temperature"]["Max"] -+ if value is None: -+ return None -+ return round(float(value), 1) -+ -+ 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 -+ """ -+ self.psu_power_dict_update() -+ value = self.psu_power_dict["Outputs"]["Voltage"]["HighAlarm"] -+ if value is None: -+ return None -+ return round(float(value), 1) -+ -+ 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 -+ """ -+ self.psu_power_dict_update() -+ value = self.psu_power_dict["Outputs"]["Voltage"]["LowAlarm"] -+ if value is None: -+ return None -+ return round(float(value), 1) -+ -+ def get_input_voltage(self): -+ """ -+ Get the input voltage of the PSU -+ -+ Returns: -+ A float number, the input voltage in volts, -+ """ -+ self.psu_status_dict_update() -+ if self.psu_status_dict["InputStatus"] is False: -+ value = 0 -+ else: -+ self.psu_power_dict_update() -+ value = self.psu_power_dict["Inputs"]["Voltage"]["Value"] -+ if value is None: -+ return None -+ return round(float(value), 1) -+ -+ def get_input_current(self): -+ """ -+ Get the input electric current of the PSU -+ -+ Returns: -+ A float number, the input current in amperes, e.g 220.3 -+ """ -+ self.psu_status_dict_update() -+ if self.psu_status_dict["InputStatus"] is False: -+ value = 0 -+ else: -+ self.psu_power_dict_update() -+ value = self.psu_power_dict["Inputs"]["Current"]["Value"] -+ if value is None: -+ return None -+ return round(float(value), 1) -+ -+ def get_input_power(self): -+ """ -+ Get the input current energy of the PSU -+ -+ Returns: -+ A float number, the input power in watts, e.g. 302.6 -+ """ -+ self.psu_status_dict_update() -+ if self.psu_status_dict["InputStatus"] is False: -+ value = 0 -+ else: -+ self.psu_power_dict_update() -+ value = self.psu_power_dict["Inputs"]["Power"]["Value"] -+ if value is None: -+ return None -+ return round(float(value), 1) -+ -+ def get_revision(self): -+ """ -+ Retrieves the hardware revision of the device -+ -+ Returns: -+ string: Revision value of device -+ """ -+ self.psu_dict_update() -+ return self.psu_dict["HW"] -+ -+ def get_vendor(self): -+ """ -+ Retrieves the vendor name of the psu -+ -+ Returns: -+ string: Vendor name of psu -+ """ -+ self.psu_dict_update() -+ return self.psu_dict["VENDOR"] -+ -+ def get_maximum_supplied_power(self): -+ """ -+ Retrieves the maximum supplied power by PSU -+ -+ Returns: -+ A float number, the maximum power output in Watts. -+ e.g. 1200.1 -+ """ -+ return False -+ -+ def get_thermal(self, index): -+ """ -+ Retrieves thermal unit represented by (0-based) index -+ -+ Args: -+ index: An integer, the index (0-based) of the thermal to -+ retrieve -+ -+ Returns: -+ An object dervied from ThermalBase representing the specified thermal -+ """ -+ return False -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/sfp.py -new file mode 100644 -index 000000000..3fc22b4b6 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/sfp.py -@@ -0,0 +1,634 @@ -+#!/usr/bin/python -+# -*- coding: UTF-8 -*- -+ -+############################################################################# -+# -+# Module contains an implementation of SONiC Platform Base API and -+# provides the platform information -+# -+# -+# *_device.py config version instruction: -+# ver 1.0 - platform api: -+# "presence_cpld": { -+# "dev_id": { -+# [dev_id]: { -+# "offset": { -+# [offset]: [port_id] -+# } -+# } -+# } -+# } -+# "reset_cpld": { -+# "dev_id": { -+# [dev_id]: { -+# "offset": { -+# [offset]: [port_id] -+# } -+# } -+# } -+# } -+# ver 2.0 - wb_plat: -+# "presence_path": "/xx/wb_plat/xx[port_id]/present" -+# "eeprom_path": "/sys/bus/i2c/devices/i2c-[bus]/[bus]-0050/eeprom" -+# "reset_path": "/xx/wb_plat/xx[port_id]/reset" -+############################################################################# -+import sys -+import time -+import syslog -+import traceback -+from abc import abstractmethod -+ -+configfile_pre = "/usr/local/bin/" -+sys.path.append(configfile_pre) -+ -+try: -+ from platform_intf import * -+ from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase -+ from plat_hal.baseutil import baseutil -+ -+except ImportError as error: -+ raise ImportError(str(error) + "- required module not found") from error -+ -+LOG_DEBUG_LEVEL = 1 -+LOG_WARNING_LEVEL = 2 -+LOG_ERROR_LEVEL = 3 -+ -+ -+class Sfp(SfpOptoeBase): -+ -+ OPTOE_DRV_TYPE1 = 1 -+ OPTOE_DRV_TYPE2 = 2 -+ OPTOE_DRV_TYPE3 = 3 -+ -+ # index must start at 1 -+ def __init__(self, index): -+ SfpOptoeBase.__init__(self) -+ self.sfp_type = None -+ sfp_config = baseutil.get_config().get("sfps", None) -+ self.log_level_config = sfp_config.get("log_level", LOG_WARNING_LEVEL) -+ # Init instance of SfpCust -+ ver = sfp_config.get("ver", None) -+ if ver is None: -+ self._sfplog(LOG_ERROR_LEVEL, "Get Ver Config Error!") -+ vers = int(float(ver)) -+ if vers == 1: -+ self._sfp_api = SfpV1(index) -+ elif vers == 2: -+ self._sfp_api = SfpV2(index) -+ else: -+ self._sfplog(LOG_ERROR_LEVEL, "Get SfpVer Error!") -+ -+ def get_eeprom_path(self): -+ return self._sfp_api._get_eeprom_path() -+ -+ def read_eeprom(self, offset, num_bytes): -+ return self._sfp_api.read_eeprom(offset, num_bytes) -+ -+ def get_presence(self): -+ return self._sfp_api.get_presence() -+ -+ def get_transceiver_info(self): -+ # temporary solution for a sonic202111 bug -+ transceiver_info = super().get_transceiver_info() -+ try: -+ if transceiver_info == None: -+ return None -+ if transceiver_info['cable_type'] == None: -+ transceiver_info['cable_type'] = 'N/A' -+ if transceiver_info["vendor_rev"] is not None: -+ transceiver_info["hardware_rev"] = transceiver_info["vendor_rev"] -+ except BaseException: -+ print(traceback.format_exc()) -+ return None -+ return transceiver_info -+ -+ def get_reset_status(self): -+ if self.get_presence() is False: -+ return False -+ -+ if self.sfp_type is None: -+ self.refresh_xcvr_api() -+ -+ if self.sfp_type == 'SFP': -+ self._sfplog(LOG_ERROR_LEVEL, 'SFP does not support reset') -+ return False -+ -+ ret = self._sfp_api.get_reset_status() -+ return ret -+ -+ def reset(self): -+ if self.get_presence() is False: -+ return False -+ -+ if self.sfp_type is None: -+ self.refresh_xcvr_api() -+ -+ if self.sfp_type == 'SFP': -+ self._sfplog(LOG_ERROR_LEVEL, 'SFP does not support reset') -+ return False -+ -+ self._sfplog(LOG_DEBUG_LEVEL, 'resetting...') -+ ret = self._sfp_api.set_reset(True) -+ if ret: -+ time.sleep(0.5) -+ ret = self._sfp_api.set_reset(False) -+ -+ return ret -+ -+ def get_lpmode(self): -+ if self.get_presence() is False: -+ return False -+ -+ if self.sfp_type is None: -+ self.refresh_xcvr_api() -+ -+ if self.sfp_type == 'QSFP' or self.sfp_type == 'QSFP-DD': -+ return SfpOptoeBase.get_lpmode(self) -+ -+ self._sfplog(LOG_WARNING_LEVEL, 'SFP does not support lpmode') -+ return False -+ -+ def set_lpmode(self, lpmode): -+ if self.get_presence() is False: -+ return False -+ -+ if self.sfp_type is None or self._xcvr_api is None: -+ self.refresh_xcvr_api() -+ -+ if self.sfp_type == 'QSFP-DD' or self.sfp_type == 'QSFP': -+ return SfpOptoeBase.set_lpmode(self, lpmode) -+ -+ self._sfplog(LOG_WARNING_LEVEL, 'SFP does not support lpmode') -+ return False -+ -+ def get_tx_disable(self): -+ if self.get_presence() is False: -+ return False -+ -+ if self.sfp_type is None: -+ self.refresh_xcvr_api() -+ -+ if self.sfp_type == 'SFP': -+ return self._sfp_api.get_tx_disable() -+ -+ return SfpOptoeBase.get_tx_disable(self) -+ -+ def get_tx_disable_channel(self): -+ if self.get_presence() is False: -+ return False -+ -+ if self.sfp_type is None: -+ self.refresh_xcvr_api() -+ -+ if self.sfp_type == 'SFP': -+ return self._sfp_api.get_tx_disable_channel() -+ -+ return SfpOptoeBase.get_tx_disable_channel(self) -+ -+ def tx_disable(self, tx_disable): -+ if self.get_presence() is False: -+ return False -+ -+ if self.sfp_type is None: -+ self.refresh_xcvr_api() -+ -+ if self.sfp_type == 'SFP': -+ return self._sfp_api.set_tx_disable(tx_disable) -+ -+ return SfpOptoeBase.tx_disable(self, tx_disable) -+ -+ def tx_disable_channel(self, channel, disable): -+ if self.get_presence() is False: -+ return False -+ -+ if self.sfp_type is None: -+ self.refresh_xcvr_api() -+ -+ if self.sfp_type == 'SFP': -+ self._sfplog(LOG_WARNING_LEVEL, 'SFP does not support tx disable channel') -+ return False -+ -+ return SfpOptoeBase.tx_disable_channel(self, channel, disable) -+ -+ def set_optoe_write_max(self, write_max): -+ """ -+ This func is declared and implemented by SONiC but we're not supported -+ so override it as NotImplemented -+ """ -+ self._sfplog(LOG_DEBUG_LEVEL, "set_optoe_write_max NotImplemented") -+ -+ def refresh_xcvr_api(self): -+ """ -+ Updates the XcvrApi associated with this SFP -+ """ -+ self._xcvr_api = self._xcvr_api_factory.create_xcvr_api() -+ class_name = self._xcvr_api.__class__.__name__ -+ optoe_type = None -+ # set sfp_type -+ if 'CmisApi' in class_name: -+ self.sfp_type = 'QSFP-DD' -+ optoe_type = self.OPTOE_DRV_TYPE3 -+ elif 'Sff8472Api' in class_name: -+ self.sfp_type = 'SFP' -+ optoe_type = self.OPTOE_DRV_TYPE2 -+ elif ('Sff8636Api' in class_name or 'Sff8436Api' in class_name): -+ self.sfp_type = 'QSFP' -+ optoe_type = self.OPTOE_DRV_TYPE1 -+ # set optoe driver -+ if optoe_type is not None: -+ self._sfp_api.set_optoe_type(optoe_type) -+ -+ def _sfplog(self, log_level, msg): -+ if log_level >= self.log_level_config: -+ try: -+ syslog.openlog("Sfp") -+ if log_level == LOG_DEBUG_LEVEL: -+ syslog.syslog(syslog.LOG_DEBUG, msg) -+ elif log_level == LOG_WARNING_LEVEL: -+ syslog.syslog(syslog.LOG_DEBUG, msg) -+ elif log_level == LOG_ERROR_LEVEL: -+ syslog.syslog(syslog.LOG_ERR, msg) -+ syslog.closelog() -+ -+ except BaseException: -+ print(traceback.format_exc()) -+ -+ -+class SfpCust(): -+ def __init__(self, index): -+ self.eeprom_path = None -+ self._init_config(index) -+ -+ def _init_config(self, index): -+ sfp_config = baseutil.get_config().get("sfps", None) -+ self.log_level_config = sfp_config.get("log_level", LOG_WARNING_LEVEL) -+ self._port_id = index -+ self.eeprom_retry_times = sfp_config.get("eeprom_retry_times", 0) -+ self.eeprom_retry_break_sec = sfp_config.get("eeprom_retry_break_sec", 0) -+ -+ def _get_eeprom_path(self): -+ return self.eeprom_path or None -+ -+ @abstractmethod -+ def get_presence(self): -+ pass -+ -+ def read_eeprom(self, offset, num_bytes): -+ try: -+ for i in range(self.eeprom_retry_times): -+ with open(self._get_eeprom_path(), mode='rb', buffering=0) as f: -+ f.seek(offset) -+ result = f.read(num_bytes) -+ # temporary solution for a sonic202111 bug -+ if len(result) < num_bytes: -+ result = result[::-1].zfill(num_bytes)[::-1] -+ if result is not None: -+ return bytearray(result) -+ time.sleep(self.eeprom_retry_break_sec) -+ continue -+ -+ except BaseException: -+ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) -+ return None -+ -+ def write_eeprom(self, offset, num_bytes, write_buffer): -+ try: -+ for i in range(self.eeprom_retry_times): -+ ret = SfpOptoeBase.write_eeprom(self, offset, num_bytes, write_buffer) -+ if ret is False: -+ time.sleep(self.eeprom_retry_break_sec) -+ continue -+ break -+ -+ return ret -+ except BaseException: -+ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) -+ return False -+ -+ @abstractmethod -+ def set_optoe_type(self, optoe_type): -+ pass -+ -+ @abstractmethod -+ def set_reset(self, reset): -+ pass -+ -+ def _convert_str_range_to_int_arr(self, range_str): -+ if not range_str: -+ return [] -+ -+ int_range_strs = range_str.split(',') -+ range_res = [] -+ for int_range_str in int_range_strs: -+ if '-' in int_range_str: -+ range_s = int(int_range_str.split('-')[0]) -+ range_e = int(int_range_str.split('-')[1]) + 1 -+ else: -+ range_s = int(int_range_str) -+ range_e = int(int_range_str) + 1 -+ -+ range_res = range_res + list(range(range_s, range_e)) -+ -+ return range_res -+ -+ def _sfplog(self, log_level, msg): -+ if log_level >= self.log_level_config: -+ try: -+ syslog.openlog("SfpCust") -+ if log_level == LOG_DEBUG_LEVEL: -+ syslog.syslog(syslog.LOG_DEBUG, msg) -+ elif log_level == LOG_WARNING_LEVEL: -+ syslog.syslog(syslog.LOG_DEBUG, msg) -+ elif log_level == LOG_ERROR_LEVEL: -+ syslog.syslog(syslog.LOG_ERR, msg) -+ syslog.closelog() -+ -+ except BaseException: -+ print(traceback.format_exc()) -+ -+ -+class SfpV1(SfpCust): -+ def _init_config(self, index): -+ super()._init_config(index) -+ # init presence path -+ sfp_config = baseutil.get_config().get("sfps", None) -+ -+ eeprom_path_config = sfp_config.get("eeprom_path", None) -+ eeprom_path_key = sfp_config.get("eeprom_path_key")[self._port_id - 1] -+ self.eeprom_path = None if eeprom_path_config is None else eeprom_path_config % ( -+ eeprom_path_key, eeprom_path_key) -+ self._sfplog(LOG_DEBUG_LEVEL, "Done init eeprom path: %s" % self.eeprom_path) -+ -+ self.presence_cpld = sfp_config.get("presence_cpld", None) -+ self.presence_val_is_present = sfp_config.get("presence_val_is_present", 0) -+ self._sfplog(LOG_DEBUG_LEVEL, "Done init presence path") -+ -+ # init reset path -+ self.reset_cpld = sfp_config.get("reset_cpld", None) -+ self.reset_val_is_reset = sfp_config.get("reset_val_is_reset", 0) -+ self._sfplog(LOG_DEBUG_LEVEL, "Done init cpld path") -+ -+ # init tx_disable path -+ self.txdis_cpld = sfp_config.get("txdis_cpld", None) -+ self.txdisable_val_is_on = sfp_config.get("txdisable_val_is_on", 0) -+ self._sfplog(LOG_DEBUG_LEVEL, "Done init cpld tx_disable path") -+ -+ def get_presence(self): -+ if self.presence_cpld is None: -+ self._sfplog(LOG_ERROR_LEVEL, "presence_cpld is None!") -+ return False -+ try: -+ dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.presence_cpld) -+ if dev_id == -1: -+ return False -+ ret, info = platform_reg_read(0, dev_id, offset, 1) -+ if (ret is False -+ or info is None): -+ return False -+ return info[0] & (1 << offset_bit) == self.presence_val_is_present -+ except BaseException: -+ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) -+ return False -+ -+ def get_reset_status(self): -+ if self.reset_cpld is None: -+ self._sfplog(LOG_ERROR_LEVEL, "reset_cpld is None!") -+ return False -+ try: -+ dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.reset_cpld) -+ if dev_id == -1: -+ return False -+ ret, info = platform_reg_read(0, dev_id, offset, 1) -+ if (ret is False -+ or info is None): -+ self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") -+ return False -+ -+ return (info[0] & (1 << offset_bit) == self.reset_val_is_reset) -+ except BaseException: -+ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) -+ return False -+ -+ def get_tx_disable(self): -+ if self.reset_cpld is None: -+ self._sfplog(LOG_ERROR_LEVEL, "txdis_cpld is None!") -+ return None -+ -+ try: -+ tx_disable_list = [] -+ dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.txdis_cpld) -+ if dev_id == -1: -+ return False -+ ret, info = platform_reg_read(0, dev_id, offset, 1) -+ if (ret is False -+ or info is None): -+ self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") -+ return None -+ if self.txdisable_val_is_on == 1: -+ tx_disable_list.append(info[0] & (1 << offset_bit) != 0) -+ else: -+ tx_disable_list.append(info[0] & (1 << offset_bit) == 0) -+ except BaseException: -+ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) -+ return None -+ -+ return tx_disable_list -+ -+ def get_tx_disable_channel(self): -+ tx_disable_list = [] -+ tx_disable_list = self.get_tx_disable() -+ if tx_disable_list is None: -+ return 0 -+ -+ tx_disabled = 0 -+ for i in range(len(tx_disable_list)): -+ if tx_disable_list[i]: -+ tx_disabled |= 1 << i -+ -+ return tx_disabled -+ -+ def read_eeprom(self, offset, num_bytes): -+ try: -+ for i in range(self.eeprom_retry_times): -+ ret, info = platform_sfp_read(self._port_id, offset, num_bytes) -+ if (ret is False -+ or info is None): -+ time.sleep(self.eeprom_retry_break_sec) -+ continue -+ eeprom_raw = [] -+ for i in range(0, num_bytes): -+ eeprom_raw.append(0) -+ for n in range(0, len(info)): -+ eeprom_raw[n] = info[n] -+ # temporary solution for a sonic202111 bug -+ if len(eeprom_raw) < num_bytes: -+ eeprom_raw = eeprom_raw[::-1].zfill(num_bytes)[::-1] -+ return bytearray(eeprom_raw) -+ except BaseException: -+ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) -+ return None -+ -+ def set_optoe_type(self, optoe_type): -+ ret, info = platform_get_optoe_type(self._port_id) -+ if ret is True and info != optoe_type: -+ try: -+ ret, _ = platform_set_optoe_type(self._port_id, optoe_type) -+ except Exception as err: -+ self._sfplog(LOG_ERROR_LEVEL, "Set optoe err %s" % err) -+ -+ def set_reset(self, reset): -+ if self.reset_cpld is None: -+ self._sfplog(LOG_ERROR_LEVEL, "reset_cpld is None!") -+ return False -+ try: -+ val = [] -+ dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.reset_cpld) -+ if dev_id == -1: -+ return False -+ ret, info = platform_reg_read(0, dev_id, offset, 1) -+ if (ret is False -+ or info is None): -+ self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") -+ return False -+ -+ if self.reset_val_is_reset == 0: -+ if reset: -+ val.append(info[0] & (~(1 << offset_bit))) -+ else: -+ val.append(info[0] | (1 << offset_bit)) -+ else: -+ if reset: -+ val.append(info[0] | (1 << offset_bit)) -+ else: -+ val.append(info[0] & (~(1 << offset_bit))) -+ -+ ret, info = platform_reg_write(0, dev_id, offset, val) -+ if ret is False: -+ self._sfplog(LOG_ERROR_LEVEL, "platform_reg_write error!") -+ return False -+ -+ except BaseException: -+ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) -+ return False -+ -+ return True -+ -+ def set_tx_disable(self, tx_disable): -+ if self.txdis_cpld is None: -+ self._sfplog(LOG_ERROR_LEVEL, "txdis_cpld is None!") -+ return False -+ try: -+ val = [] -+ dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.txdis_cpld) -+ if dev_id == -1: -+ return False -+ ret, info = platform_reg_read(0, dev_id, offset, 1) -+ if (ret is False -+ or info is None): -+ self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") -+ return False -+ -+ if self.txdisable_val_is_on == 0: -+ if tx_disable: -+ val.append(info[0] & (~(1 << offset_bit))) -+ else: -+ val.append(info[0] | (1 << offset_bit)) -+ else: -+ if tx_disable: -+ val.append(info[0] | (1 << offset_bit)) -+ else: -+ val.append(info[0] & (~(1 << offset_bit))) -+ -+ ret, info = platform_reg_write(0, dev_id, offset, val) -+ if ret is False: -+ self._sfplog(LOG_ERROR_LEVEL, "platform_reg_write error!") -+ return False -+ -+ except BaseException: -+ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) -+ return False -+ -+ return True -+ -+ def _get_sfp_cpld_info(self, cpld_config): -+ dev_id = -1 -+ offset = -1 -+ offset_bit = -1 -+ for dev_id_temp in cpld_config["dev_id"]: -+ for offset_temp in cpld_config["dev_id"][dev_id_temp]["offset"]: -+ port_range_str = cpld_config["dev_id"][dev_id_temp]["offset"][offset_temp] -+ port_range_int = self._convert_str_range_to_int_arr(port_range_str) -+ if self._port_id in port_range_int: -+ dev_id = dev_id_temp -+ offset = offset_temp -+ offset_bit = port_range_int.index(self._port_id) -+ break -+ -+ return dev_id, offset, offset_bit -+ -+ -+class SfpV2(SfpCust): -+ def _init_config(self, index): -+ super()._init_config(index) -+ # init eeprom path -+ sfp_config = baseutil.get_config().get("sfps", None) -+ eeprom_path_config = sfp_config.get("eeprom_path", None) -+ eeprom_path_key = sfp_config.get("eeprom_path_key")[self._port_id - 1] -+ self.eeprom_path = None if eeprom_path_config is None else eeprom_path_config % ( -+ eeprom_path_key, eeprom_path_key) -+ self._sfplog(LOG_DEBUG_LEVEL, "Done init eeprom path: %s" % self.eeprom_path) -+ -+ # init presence path -+ self.presence_path = None if sfp_config.get("presence_path", -+ None) is None else sfp_config.get("presence_path") % self._port_id -+ self.presence_val_is_present = sfp_config.get("presence_val_is_present", 0) -+ self._sfplog(LOG_DEBUG_LEVEL, "Done init presence path: %s" % self.presence_path) -+ -+ # init optoe driver path -+ optoe_driver_path = sfp_config.get("optoe_driver_path", None) -+ optoe_driver_key = sfp_config.get("optoe_driver_key")[self._port_id - 1] -+ self.dev_class_path = None if optoe_driver_path is None else optoe_driver_path % ( -+ optoe_driver_key, optoe_driver_key) -+ self._sfplog(LOG_DEBUG_LEVEL, "Done init optoe driver path: %s" % self.dev_class_path) -+ -+ # init reset path -+ self.reset_path = None if sfp_config.get( -+ "reset_path", -+ None) is None else sfp_config.get( -+ "reset_path", -+ None) % self._port_id -+ self.reset_val_is_reset = sfp_config.get("reset_val_is_reset", 0) -+ self._sfplog(LOG_DEBUG_LEVEL, "Done init reset path: %s" % self.reset_path) -+ -+ def get_presence(self): -+ if self.presence_path is None: -+ self._sfplog(LOG_ERROR_LEVEL, "presence_path is None!") -+ return False -+ try: -+ with open(self.presence_path, "rb") as data: -+ sysfs_data = data.read(1) -+ if sysfs_data != "": -+ result = int(sysfs_data, 16) -+ return result == self.presence_val_is_present -+ except BaseException: -+ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) -+ return False -+ -+ def set_reset(self, reset): -+ return True -+ -+ def set_optoe_type(self, optoe_type): -+ if self.dev_class_path is None: -+ self._sfplog(LOG_ERROR_LEVEL, "dev_class_path is None!") -+ return False -+ try: -+ with open(self.dev_class_path, "r+") as dc_file: -+ dc_file_val = dc_file.read(1) -+ if int(dc_file_val) != optoe_type: -+ dc_str = "%s" % str(optoe_type) -+ dc_file.write(dc_str) -+ # dc_file.close() -+ except BaseException: -+ self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) -+ return False -+ return True -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/thermal.py -new file mode 100644 -index 000000000..4632de3bc ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/thermal.py -@@ -0,0 +1,234 @@ -+#!/usr/bin/env python3 -+ -+######################################################################## -+# -+# Module contains an implementation of SONiC Platform Base API and -+# provides the Thermals' information which are available in the platform -+# -+######################################################################## -+ -+ -+try: -+ import time -+ from sonic_platform_base.thermal_base import ThermalBase -+except ImportError as e: -+ raise ImportError(str(e) + "- required module not found") from e -+ -+ -+class Thermal(ThermalBase): -+ -+ def __init__(self, interface_obj, index): -+ self.temp_dict = {} -+ self.temperature_list = [] -+ self.int_case = interface_obj -+ self.index = index -+ self.update_time = 0 -+ self.temp_id = "TEMP" + str(index) -+ -+ def temp_dict_update(self): -+ local_time = time.time() -+ if not self.temp_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds -+ self.update_time = local_time -+ self.temp_dict = self.int_case.get_monitor_temp_by_id(self.temp_id) -+ -+ def get_name(self): -+ """ -+ Retrieves the name of the thermal -+ -+ Returns: -+ string: The name of the thermal -+ """ -+ self.temp_dict_update() -+ return self.temp_dict["Api_name"] -+ -+ def get_presence(self): -+ """ -+ Retrieves the presence of the thermal -+ -+ Returns: -+ bool: True if thermal is present, False if not -+ """ -+ return True -+ -+ def get_model(self): -+ """ -+ Retrieves the model number (or part number) of the Thermal -+ -+ Returns: -+ string: Model/part number of Thermal -+ """ -+ return "N/A" -+ -+ def get_serial(self): -+ """ -+ Retrieves the serial number of the Thermal -+ -+ Returns: -+ string: Serial number of Thermal -+ """ -+ return "N/A" -+ -+ def get_revision(self): -+ """ -+ Retrieves the hardware revision of the device -+ -+ Returns: -+ string: Revision value of device -+ """ -+ return "N/A" -+ -+ def get_status(self): -+ """ -+ Retrieves the operational status of the thermal -+ -+ Returns: -+ A boolean value, True if thermal is operating properly, -+ False if not -+ """ -+ self.temp_dict_update() -+ if (self.temp_dict["Value"] >= self.temp_dict["High"]) or (self.temp_dict["Value"] <= self.temp_dict["Low"]): -+ return False -+ -+ return True -+ -+ 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 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 -+ """ -+ self.temp_dict_update() -+ value = self.temp_dict["Value"] -+ if value is None or value == self.int_case.error_ret: -+ return "N/A" -+ if len(self.temperature_list) >= 1000: -+ del self.temperature_list[0] -+ self.temperature_list.append(float(value)) -+ return round(float(value), 1) -+ -+ 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 -+ """ -+ self.temp_dict_update() -+ value = self.temp_dict["High"] -+ if value is None or value == self.int_case.error_ret: -+ return "N/A" -+ return round(float(value), 1) -+ -+ 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 -+ """ -+ self.temp_dict_update() -+ value = self.temp_dict["Low"] -+ if value is None or value == self.int_case.error_ret: -+ return "N/A" -+ return round(float(value), 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 -+ """ -+ # not supported -+ return False -+ -+ 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 -+ """ -+ # not supported -+ 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 -+ """ -+ self.temp_dict_update() -+ value = self.temp_dict["Max"] -+ if value is None or value == self.int_case.error_ret: -+ return "N/A" -+ return round(float(value), 1) -+ -+ def get_low_critical_threshold(self): -+ """ -+ Retrieves the low critical threshold temperature of thermal -+ -+ Returns: -+ A float number, the low critical threshold temperature of thermal in Celsius -+ up to nearest thousandth of one degree Celsius, e.g. 30.125 -+ """ -+ self.temp_dict_update() -+ value = self.temp_dict["Min"] -+ if value is None or value == self.int_case.error_ret: -+ return "N/A" -+ return round(float(value), 1) -+ -+ def get_minimum_recorded(self): -+ """ -+ Retrieves the minimum recorded temperature of thermal -+ -+ Returns: -+ A float number, the minimum recorded temperature of thermal in Celsius -+ up to nearest thousandth of one degree Celsius, e.g. 30.125 -+ """ -+ if len(self.temperature_list) == 0: -+ return "N/A" -+ return round(float(min(self.temperature_list)), 1) -+ -+ def get_maximum_recorded(self): -+ """ -+ Retrieves the maximum recorded temperature of thermal -+ -+ Returns: -+ A float number, the maximum recorded temperature of thermal in Celsius -+ up to nearest thousandth of one degree Celsius, e.g. 30.125 -+ """ -+ if len(self.temperature_list) == 0: -+ return "N/A" -+ return round(float(max(self.temperature_list)), 1) -diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/watchdog.py -new file mode 100644 -index 000000000..948337f47 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/watchdog.py -@@ -0,0 +1,236 @@ -+#!/usr/bin/env python3 -+ -+######################################################################## -+# -+# -+# Abstract base class for implementing a platform-specific class with -+# which to interact with a hardware watchdog module in SONiC -+# -+######################################################################## -+ -+import fcntl -+import os -+import array -+ -+try: -+ from sonic_platform_base.watchdog_base import WatchdogBase -+except ImportError as error: -+ raise ImportError(str(error) + "- required module not found") from error -+ -+ -+# ioctl constants -+IO_WRITE = 0x40000000 -+IO_READ = 0x80000000 -+IO_READ_WRITE = 0xC0000000 -+IO_SIZE_INT = 0x00040000 -+IO_SIZE_40 = 0x00280000 -+IO_TYPE_WATCHDOG = ord('W') << 8 -+ -+WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG -+WDR_40 = IO_READ | IO_SIZE_40 | IO_TYPE_WATCHDOG -+WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG -+ -+# Watchdog ioctl command -+WDIOC_GETSUPPORT = 0 | WDR_40 -+WDIOC_GETSTATUS = 1 | WDR_INT -+WDIOC_GETBOOTSTATUS = 2 | WDR_INT -+WDIOC_GETTEMP = 3 | WDR_INT -+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 -+ -+WDT_COMMON_ERROR = -1 -+WDT_IDENTITY = "CPLD Watchdog" -+WDT_SYSFS_PATH = "/sys/class/watchdog/" -+ -+DEFAULT_TIMEOUT = 180 -+ -+ -+class Watchdog(WatchdogBase): -+ """ -+ Abstract base class for interfacing with a hardware watchdog module -+ """ -+ -+ def __init__(self): -+ self.watchdog, self.wdt_main_dev_name = self._get_wdt() -+ self.status_path = "/sys/class/watchdog/%s/status" % self.wdt_main_dev_name -+ self.state_path = "/sys/class/watchdog/%s/state" % self.wdt_main_dev_name -+ self.timeout_path = "/sys/class/watchdog/%s/timeout" % self.wdt_main_dev_name -+ # Set default value -+ self._disable() -+ self.armed = False -+ self.timeout = self._gettimeout() -+ -+ def _is_wd_main(self, dev): -+ """ -+ Checks watchdog identity -+ """ -+ identity = self._read_file( -+ "{}/{}/identity".format(WDT_SYSFS_PATH, dev)) -+ return identity == WDT_IDENTITY -+ -+ def _get_wdt(self): -+ """ -+ Retrieves watchdog device -+ """ -+ wdt_main_dev_list = [dev for dev in os.listdir( -+ "/dev/") if dev.startswith("watchdog") and self._is_wd_main(dev)] -+ if not wdt_main_dev_list: -+ return None -+ wdt_main_dev_name = wdt_main_dev_list[0] -+ watchdog_device_path = "/dev/{}".format(wdt_main_dev_name) -+ watchdog = os.open(watchdog_device_path, os.O_RDWR) -+ return watchdog, wdt_main_dev_name -+ -+ def _read_file(self, file_path): -+ """ -+ Read text file -+ """ -+ try: -+ with open(file_path, "r") as fd: -+ txt = fd.read() -+ except IOError: -+ return WDT_COMMON_ERROR -+ return txt.strip() -+ -+ def _enable(self): -+ """ -+ Turn on the watchdog timer -+ """ -+ req = array.array('h', [WDIOS_ENABLECARD]) -+ fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) -+ -+ def _disable(self): -+ """ -+ Turn off the watchdog timer -+ """ -+ req = array.array('h', [WDIOS_DISABLECARD]) -+ 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 -+ """ -+ req = array.array('I', [0]) -+ fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True) -+ -+ return int(req[0]) -+ -+ 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): -+ """ -+ Arm the hardware watchdog with a timeout of seconds. -+ If the watchdog is currently armed, calling this function will -+ simply reset the timer to the provided value. If the underlying -+ hardware does not support the value provided in , this -+ method should arm the watchdog with the *next greater* available -+ value. -+ -+ Returns: -+ An integer specifying the *actual* number of seconds the watchdog -+ was armed with. On failure returns -1. -+ """ -+ ret = WDT_COMMON_ERROR -+ if seconds < 0: -+ return ret -+ -+ try: -+ if self.timeout != seconds: -+ self.timeout = self._settimeout(seconds) -+ if self.armed: -+ self._keepalive() -+ else: -+ self._settimeout(seconds) -+ self._enable() -+ self.armed = True -+ ret = self.timeout -+ except IOError: -+ pass -+ -+ return ret -+ -+ def disarm(self): -+ """ -+ Disarm the hardware watchdog -+ -+ Returns: -+ A boolean, True if watchdog is disarmed successfully, False if not -+ """ -+ disarmed = False -+ if self.is_armed(): -+ try: -+ self._disable() -+ self.armed = False -+ disarmed = True -+ except IOError: -+ pass -+ -+ return disarmed -+ -+ def is_armed(self): -+ """ -+ Retrieves the armed state of the hardware watchdog. -+ -+ Returns: -+ A boolean, True if watchdog is armed, False if not -+ """ -+ return self.armed -+ -+ def get_remaining_time(self): -+ """ -+ If the watchdog is armed, retrieve the number of seconds remaining on -+ the watchdog timer -+ -+ Returns: -+ An integer specifying the number of seconds remaining on thei -+ watchdog timer. If the watchdog is not armed, returns -1. -+ """ -+ timeleft = WDT_COMMON_ERROR -+ -+ if self.armed: -+ try: -+ timeleft = self._gettimeleft() -+ except IOError: -+ pass -+ -+ return timeleft -+ -+ def __del__(self): -+ """ -+ Close watchdog -+ """ -+ os.close(self.watchdog) -diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/changelog b/platform/broadcom/sonic-platform-modules-micas/debian/changelog -new file mode 100644 -index 000000000..d908208c5 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/debian/changelog -@@ -0,0 +1,5 @@ -+sonic-micas-platform-modules (1.0) unstable; urgency=low -+ -+ * Initial release -+ -+ -- support Fri, 21 APR 2017 11:11:11 -0800 -diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/compat b/platform/broadcom/sonic-platform-modules-micas/debian/compat -new file mode 100644 -index 000000000..f599e28b8 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/debian/compat -@@ -0,0 +1 @@ -+10 -diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/control b/platform/broadcom/sonic-platform-modules-micas/debian/control -new file mode 100644 -index 000000000..55b583777 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/debian/control -@@ -0,0 +1,9 @@ -+Source: sonic-micas-platform-modules -+Section: main -+Priority: extra -+Maintainer: support -+Standards-Version: 3.9.3 -+ -+Package: platform-modules-micas-m2-w6510-48v8c -+Architecture: amd64 -+Description: kernel modules for platform devices such as fan, led, sfp -diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/copyright b/platform/broadcom/sonic-platform-modules-micas/debian/copyright -new file mode 100644 -index 000000000..676cdeec7 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/debian/copyright -@@ -0,0 +1,15 @@ -+Copyright (C) 2016 Microsoft, Inc -+ -+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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.install b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.install -new file mode 100644 -index 000000000..6f3e9b257 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.install -@@ -0,0 +1 @@ -+m2-w6510-48v8c/modules/sonic_platform-1.0-py3-none-any.whl /usr/share/sonic/device/x86_64-micas_m2-w6510-48v8c-r0 -diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.postinst b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.postinst -new file mode 100644 -index 000000000..a8132f4f6 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.postinst -@@ -0,0 +1,10 @@ -+#!/bin/sh -+# postinst -+ -+kernel_version=$(uname -r) -+ -+if [ -e /boot/System.map-${kernel_version} ]; then -+ depmod -a -F /boot/System.map-${kernel_version} ${kernel_version} || true -+fi -+ -+#DEBHELPER# -diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/rule.mk b/platform/broadcom/sonic-platform-modules-micas/debian/rule.mk -new file mode 100644 -index 000000000..f27bca1d6 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/debian/rule.mk -@@ -0,0 +1,5 @@ -+currentdir = $(shell pwd) -+ -+MODULE_DIRS := m2-w6510-48v8c -+ -+export MODULE_DIRS -diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/rules b/platform/broadcom/sonic-platform-modules-micas/debian/rules -new file mode 100755 -index 000000000..e801ef47f ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/debian/rules -@@ -0,0 +1,92 @@ -+#!/usr/bin/make -f -+CC=gcc -+INSTALL_MOD_DIR:=extra -+KVERSION ?= $(shell uname -r) -+KERNEL_SRC := /lib/modules/$(KVERSION) -+MOD_SRC_DIR:= $(shell pwd) -+KBUILD_OUTPUT=$(KERNEL_SRC)/build -+ -+LIB_DIR = usr/lib/python3/dist-packages -+CUSTOM_RULES_DIR := $(shell pwd)/debian -+ -+export INSTALL_MOD_DIR top_srcdir KVERSION KERNEL_SRC CC KBUILD_OUTPUT CUSTOM_RULES_DIR -+ -+include $(CUSTOM_RULES_DIR)/rule.mk -+ -+#all product need common -+COMPILE_DIRS = $(MODULE_DIRS) -+ -+clean_dirs = $(MODULE_DIRS) -+clean_dirs += common -+ -+complie_clean_dirs := $(addprefix _clean_,$(clean_dirs) ) -+ -+%: -+ dh $@ -+build: COMPILE_WHL -+ @echo "build success" -+ -+$(complie_clean_dirs): -+ $(MAKE) -C $(patsubst _clean_%,%,$@) clean -+ -+common_build : -+ $(MAKE) -C $(MOD_SRC_DIR)/common -+ -+$(COMPILE_DIRS): common_build -+ $(MAKE) -C $(MOD_SRC_DIR)/$@ -+ dh_testdir -+ dh_installdirs -+ cp -r $(MOD_SRC_DIR)/common/build/* debian/platform-modules-micas-$@/; \ -+ cp -r $(MOD_SRC_DIR)/$@/build/* debian/platform-modules-micas-$@/; \ -+ -+COMPILE_WHL: $(COMPILE_DIRS) -+ @(for mod in $(MODULE_DIRS); do \ -+ cd $(MOD_SRC_DIR)/$${mod}; \ -+ cp -r $(MOD_SRC_DIR)/common/lib/plat_hal $(MOD_SRC_DIR)/$${mod}/; \ -+ cp -r $(MOD_SRC_DIR)/common/lib/wbutil $(MOD_SRC_DIR)/$${mod}/; \ -+ cp -r $(MOD_SRC_DIR)/common/lib/eepromutil $(MOD_SRC_DIR)/$${mod}/; \ -+ cp -r $(MOD_SRC_DIR)/common/sonic_platform $(MOD_SRC_DIR)/$${mod}/; \ -+ cp $(MOD_SRC_DIR)/common/script/hal_pltfm.py $(MOD_SRC_DIR)/$${mod}/hal_pltfm.py; \ -+ cp $(MOD_SRC_DIR)/common/script/platform_util.py $(MOD_SRC_DIR)/$${mod}/platform_util.py; \ -+ cp $(MOD_SRC_DIR)/common/script/platform_intf.py $(MOD_SRC_DIR)/$${mod}/platform_intf.py; \ -+ python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ -+ rm -rf $(MOD_SRC_DIR)/$${mod}/plat_hal; \ -+ rm -rf $(MOD_SRC_DIR)/$${mod}/wbutil; \ -+ rm -rf $(MOD_SRC_DIR)/$${mod}/eepromutil; \ -+ rm -rf $(MOD_SRC_DIR)/$${mod}/sonic_platform; \ -+ rm -rf $(MOD_SRC_DIR)/$${mod}/hal_pltfm.py; \ -+ rm -rf $(MOD_SRC_DIR)/$${mod}/platform_intf.py; \ -+ rm -rf $(MOD_SRC_DIR)/$${mod}/platform_util.py; \ -+ cd $(MOD_SRC_DIR); \ -+ done) -+ -+binary: binary-indep -+ @echo "=======================================================" -+ -+binary-indep: -+ # Resuming debhelper scripts -+ dh_testroot -+ dh_install -+ dh_installchangelogs -+ dh_installdocs -+ dh_systemd_enable -+ dh_installinit -+ dh_systemd_start -+ dh_link -+ dh_fixperms -+ dh_compress -+ dh_strip -+ dh_installdeb -+ dh_gencontrol -+ dh_md5sums -+ dh_builddeb -+override_dh_usrlocal: -+ -+override_dh_pysupport: -+ -+clean: $(complie_clean_dirs) -+ dh_testdir -+ dh_testroot -+ dh_clean -+ -+.PHONY: build $(COMPILE_DIRS) binary binary-arch binary-indep clean -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/cpld_test_header.vme b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/cpld_test_header.vme -new file mode 100644 -index 0000000000000000000000000000000000000000..083fd78f3ea1919d9d3737fe0d8d0c7b8b2ce881 -GIT binary patch -literal 406 -zcmaiu!AgWc7{^Cl9GwWZEU4QY>mrW2O9%#{v#rqDVj^@}T%AMUt^?Upr*1u1&(K43 -z?FnqO2k^UmA0NNppMS~gYSXfp);#POTEzEsNrQ-{S16)+_OzzH_2yb`frh&jGzynN -zocKiSc%1|*>JQ(XrjPMM;vcLbWx(?lMPV9>2xnduTlc0w*NEL#8!^N-$!~cVJr}!X -zU*U-Hx_RHReT%cEsj*`cOSm-1L@17ejCweGWq851n7EkCz1hsO3AQcUK?q#pT+$Q+ -zaP`9Ix{m7r0$EYyqaQexPBa5Reu@nVOwPd9@%QJs+)cP9_xx1wT$jWNHKXIBQctQq -VsrNb@^ic_@K=0eZ|8`^i#~;mYW4-_Y - -literal 0 -HcmV?d00001 - -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/fpga_test_header.bin b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/fpga_test_header.bin -new file mode 100644 -index 000000000..bdf9ae213 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/.upgrade_test/fpga_test_header.bin -@@ -0,0 +1,10 @@ -+fpga_test_header.bin -+FILEHEADER( -+DEVTYPE=0x404a -+TYPE=fpga -+CHAIN=3 -+CHIPNAME=fpga -+VERSION=v0 -+FILETYPE=SPI-LOGIC-DEV -+CRC=0x00000000 -+) -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/Makefile b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/Makefile -new file mode 100644 -index 000000000..1b84abef4 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/Makefile -@@ -0,0 +1,28 @@ -+PWD = $(shell pwd) -+DIR_KERNEL_SRC = $(PWD)/modules/driver -+EXTRA_CFLAGS:= -I$(M)/include -+EXTRA_CFLAGS+= -Wall -+SUB_BUILD_DIR = $(PWD)/build -+INSTALL_DIR = $(SUB_BUILD_DIR)/$(KERNEL_SRC)/$(INSTALL_MOD_DIR) -+INSTALL_SCRIPT_DIR = $(SUB_BUILD_DIR)/usr/local/bin -+INSTALL_LIB_DIR = $(SUB_BUILD_DIR)/usr/lib/python3/dist-packages -+INSTALL_SYSFS_CFG_DIR = $(SUB_BUILD_DIR)/etc/plat_sysfs_cfg -+INSTALL_UPGRADE_TEST_DIR = $(SUB_BUILD_DIR)/etc/.upgrade_test -+ -+all: -+ $(MAKE) -C $(KBUILD_OUTPUT) M=$(DIR_KERNEL_SRC) modules -+ @if [ ! -d ${INSTALL_DIR} ]; then mkdir -p ${INSTALL_DIR} ;fi -+ cp -r $(DIR_KERNEL_SRC)/*.ko $(INSTALL_DIR) -+ @if [ ! -d ${INSTALL_SCRIPT_DIR} ]; then mkdir -p ${INSTALL_SCRIPT_DIR} ;fi -+ cp -r $(PWD)/config/* $(INSTALL_SCRIPT_DIR) -+ @if [ ! -d ${INSTALL_LIB_DIR} ]; then mkdir -p ${INSTALL_LIB_DIR} ;fi -+ @if [ -d $(PWD)/hal-config/ ]; then cp -r $(PWD)/hal-config/* ${INSTALL_LIB_DIR} ;fi -+ @if [ ! -d ${INSTALL_SYSFS_CFG_DIR} ]; then mkdir -p ${INSTALL_SYSFS_CFG_DIR} ;fi -+ @if [ -d $(PWD)/plat_sysfs_cfg/ ]; then cp -r $(PWD)/plat_sysfs_cfg/* ${INSTALL_SYSFS_CFG_DIR} ;fi -+ @if [ ! -d ${INSTALL_UPGRADE_TEST_DIR} ]; then mkdir -p ${INSTALL_UPGRADE_TEST_DIR} ;fi -+ @if [ -d $(PWD)/.upgrade_test/ ]; then cp -r $(PWD)/.upgrade_test/* ${INSTALL_UPGRADE_TEST_DIR} ;fi -+clean: -+ rm -f ${DIR_KERNEL_SRC}/*.o ${DIR_KERNEL_SRC}/*.ko ${DIR_KERNEL_SRC}/*.mod.c ${DIR_KERNEL_SRC}/.*.cmd -+ rm -f ${DIR_KERNEL_SRC}/Module.markers ${DIR_KERNEL_SRC}/Module.symvers ${DIR_KERNEL_SRC}/modules.order -+ rm -rf ${DIR_KERNEL_SRC}/.tmp_versions -+ rm -rf $(SUB_BUILD_DIR) -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_config.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_config.py -new file mode 100755 -index 000000000..587e303a6 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_config.py -@@ -0,0 +1,1106 @@ -+#!/usr/bin/python -+# -*- coding: UTF-8 -*- -+from platform_common import * -+ -+STARTMODULE = { -+ "hal_fanctrl": 1, -+ "hal_ledctrl": 1, -+ "avscontrol": 1, -+ "dev_monitor": 1, -+ "pmon_syslog": 1, -+ "tty_console": 1, -+ "macledreset": 1, -+ "sff_temp_polling": 1, -+ "generate_airflow": 1, -+ "reboot_cause": 1, -+} -+ -+MAC_LED_RESET = {"pcibus": 8, "slot": 0, "fn": 0, "bar": 0, "offset": 64, "reset": 0x98} -+ -+MANUINFO_CONF = { -+ "bios": { -+ "key": "BIOS", -+ "head": True, -+ "next": "onie" -+ }, -+ "bios_vendor": { -+ "parent": "bios", -+ "key": "Vendor", -+ "cmd": "dmidecode -t 0 |grep Vendor", -+ "pattern": r".*Vendor", -+ "separator": ":", -+ "arrt_index": 1, -+ }, -+ "bios_version": { -+ "parent": "bios", -+ "key": "Version", -+ "cmd": "dmidecode -t 0 |grep Version", -+ "pattern": r".*Version", -+ "separator": ":", -+ "arrt_index": 2, -+ }, -+ "bios_date": { -+ "parent": "bios", -+ "key": "Release Date", -+ "cmd": "dmidecode -t 0 |grep Release", -+ "pattern": r".*Release Date", -+ "separator": ":", -+ "arrt_index": 3, -+ }, -+ "onie": { -+ "key": "ONIE", -+ "next": "cpu" -+ }, -+ "onie_date": { -+ "parent": "onie", -+ "key": "Build Date", -+ "file": "/host/machine.conf", -+ "pattern": r"^onie_build_date", -+ "separator": "=", -+ "arrt_index": 1, -+ }, -+ "onie_version": { -+ "parent": "onie", -+ "key": "Version", -+ "file": "/host/machine.conf", -+ "pattern": r"^onie_version", -+ "separator": "=", -+ "arrt_index": 2, -+ }, -+ -+ "cpu": { -+ "key": "CPU", -+ "next": "ssd" -+ }, -+ "cpu_vendor": { -+ "parent": "cpu", -+ "key": "Vendor", -+ "cmd": "dmidecode --type processor |grep Manufacturer", -+ "pattern": r".*Manufacturer", -+ "separator": ":", -+ "arrt_index": 1, -+ }, -+ "cpu_model": { -+ "parent": "cpu", -+ "key": "Device Model", -+ "cmd": "dmidecode --type processor | grep Version", -+ "pattern": r".*Version", -+ "separator": ":", -+ "arrt_index": 2, -+ }, -+ "cpu_core": { -+ "parent": "cpu", -+ "key": "Core Count", -+ "cmd": "dmidecode --type processor | grep \"Core Count\"", -+ "pattern": r".*Core Count", -+ "separator": ":", -+ "arrt_index": 3, -+ }, -+ "cpu_thread": { -+ "parent": "cpu", -+ "key": "Thread Count", -+ "cmd": "dmidecode --type processor | grep \"Thread Count\"", -+ "pattern": r".*Thread Count", -+ "separator": ":", -+ "arrt_index": 4, -+ }, -+ "ssd": { -+ "key": "SSD", -+ "next": "cpld" -+ }, -+ "ssd_model": { -+ "parent": "ssd", -+ "key": "Device Model", -+ "cmd": "smartctl -i /dev/sda |grep \"Device Model\"", -+ "pattern": r".*Device Model", -+ "separator": ":", -+ "arrt_index": 1, -+ }, -+ "ssd_fw": { -+ "parent": "ssd", -+ "key": "Firmware Version", -+ "cmd": "smartctl -i /dev/sda |grep \"Firmware Version\"", -+ "pattern": r".*Firmware Version", -+ "separator": ":", -+ "arrt_index": 2, -+ }, -+ "ssd_user_cap": { -+ "parent": "ssd", -+ "key": "User Capacity", -+ "cmd": "smartctl -i /dev/sda |grep \"User Capacity\"", -+ "pattern": r".*User Capacity", -+ "separator": ":", -+ "arrt_index": 3, -+ }, -+ -+ "cpld": { -+ "key": "CPLD", -+ "next": "psu" -+ }, -+ -+ "cpld1": { -+ "key": "CPLD1", -+ "parent": "cpld", -+ "arrt_index": 1, -+ }, -+ "cpld1_model": { -+ "key": "Device Model", -+ "parent": "cpld1", -+ "config": "LCMXO3LF-2100C-5BG256C", -+ "arrt_index": 1, -+ }, -+ "cpld1_vender": { -+ "key": "Vendor", -+ "parent": "cpld1", -+ "config": "LATTICE", -+ "arrt_index": 2, -+ }, -+ "cpld1_desc": { -+ "key": "Description", -+ "parent": "cpld1", -+ "config": "CPU_CPLD", -+ "arrt_index": 3, -+ }, -+ "cpld1_version": { -+ "key": "Firmware Version", -+ "parent": "cpld1", -+ "reg": { -+ "loc": "/dev/port", -+ "offset": 0x700, -+ "size": 4 -+ }, -+ "callback": "cpld_format", -+ "arrt_index": 4, -+ }, -+ -+ "cpld2": { -+ "key": "CPLD2", -+ "parent": "cpld", -+ "arrt_index": 2, -+ }, -+ "cpld2_model": { -+ "key": "Device Model", -+ "parent": "cpld2", -+ "config": "LCMXO3LF-2100C-5BG256C", -+ "arrt_index": 1, -+ }, -+ "cpld2_vender": { -+ "key": "Vendor", -+ "parent": "cpld2", -+ "config": "LATTICE", -+ "arrt_index": 2, -+ }, -+ "cpld2_desc": { -+ "key": "Description", -+ "parent": "cpld2", -+ "config": "CONNECT_CPLD", -+ "arrt_index": 3, -+ }, -+ "cpld2_version": { -+ "key": "Firmware Version", -+ "parent": "cpld2", -+ "reg": { -+ "loc": "/dev/port", -+ "offset": 0x900, -+ "size": 4 -+ }, -+ "callback": "cpld_format", -+ "arrt_index": 4, -+ }, -+ -+ "cpld3": { -+ "key": "CPLD3", -+ "parent": "cpld", -+ "arrt_index": 3, -+ }, -+ "cpld3_model": { -+ "key": "Device Model", -+ "parent": "cpld3", -+ "config": "LCMXO3LF-2100C-5BG256C", -+ "arrt_index": 1, -+ }, -+ "cpld3_vender": { -+ "key": "Vendor", -+ "parent": "cpld3", -+ "config": "LATTICE", -+ "arrt_index": 2, -+ }, -+ "cpld3_desc": { -+ "key": "Description", -+ "parent": "cpld3", -+ "config": "CONNECT_CPLD-FAN", -+ "arrt_index": 3, -+ }, -+ "cpld3_version": { -+ "key": "Firmware Version", -+ "parent": "cpld3", -+ "i2c": { -+ "bus": "2", -+ "loc": "0x0d", -+ "offset": 0, -+ "size": 4 -+ }, -+ "callback": "cpld_format", -+ "arrt_index": 4, -+ }, -+ -+ "cpld4": { -+ "key": "CPLD4", -+ "parent": "cpld", -+ "arrt_index": 4, -+ }, -+ "cpld4_model": { -+ "key": "Device Model", -+ "parent": "cpld4", -+ "config": "LCMXO3LF-2100C-5BG256C", -+ "arrt_index": 1, -+ }, -+ "cpld4_vender": { -+ "key": "Vendor", -+ "parent": "cpld4", -+ "config": "LATTICE", -+ "arrt_index": 2, -+ }, -+ "cpld4_desc": { -+ "key": "Description", -+ "parent": "cpld4", -+ "config": "MAC_CPLD1", -+ "arrt_index": 3, -+ }, -+ "cpld4_version": { -+ "key": "Firmware Version", -+ "parent": "cpld4", -+ "i2c": { -+ "bus": "8", -+ "loc": "0x30", -+ "offset": 0, -+ "size": 4 -+ }, -+ "callback": "cpld_format", -+ "arrt_index": 4, -+ }, -+ -+ "cpld5": { -+ "key": "CPLD5", -+ "parent": "cpld", -+ "arrt_index": 5, -+ }, -+ "cpld5_model": { -+ "key": "Device Model", -+ "parent": "cpld5", -+ "config": "LCMXO3LF-2100C-5BG256C", -+ "arrt_index": 1, -+ }, -+ "cpld5_vender": { -+ "key": "Vendor", -+ "parent": "cpld5", -+ "config": "LATTICE", -+ "arrt_index": 2, -+ }, -+ "cpld5_desc": { -+ "key": "Description", -+ "parent": "cpld5", -+ "config": "MAC_CPLD2", -+ "arrt_index": 3, -+ }, -+ "cpld5_version": { -+ "key": "Firmware Version", -+ "parent": "cpld5", -+ "i2c": { -+ "bus": "8", -+ "loc": "0x31", -+ "offset": 0, -+ "size": 4 -+ }, -+ "callback": "cpld_format", -+ "arrt_index": 4, -+ }, -+ -+ "psu": { -+ "key": "PSU", -+ "next": "fan" -+ }, -+ -+ "psu1": { -+ "parent": "psu", -+ "key": "PSU1", -+ "arrt_index": 1, -+ }, -+ "psu1_hw_version": { -+ "key": "Hardware Version", -+ "parent": "psu1", -+ "extra": { -+ "funcname": "getPsu", -+ "id": "psu1", -+ "key": "hw_version" -+ }, -+ "arrt_index": 1, -+ }, -+ "psu1_fw_version": { -+ "key": "Firmware Version", -+ "parent": "psu1", -+ "config": "NA", -+ "arrt_index": 2, -+ }, -+ -+ "psu2": { -+ "parent": "psu", -+ "key": "PSU2", -+ "arrt_index": 2, -+ }, -+ "psu2_hw_version": { -+ "key": "Hardware Version", -+ "parent": "psu2", -+ "extra": { -+ "funcname": "getPsu", -+ "id": "psu2", -+ "key": "hw_version" -+ }, -+ "arrt_index": 1, -+ }, -+ "psu2_fw_version": { -+ "key": "Firmware Version", -+ "parent": "psu2", -+ "config": "NA", -+ "arrt_index": 2, -+ }, -+ -+ "fan": { -+ "key": "FAN", -+ "next": "i210" -+ }, -+ -+ "fan1": { -+ "key": "FAN1", -+ "parent": "fan", -+ "arrt_index": 1, -+ }, -+ "fan1_hw_version": { -+ "key": "Hardware Version", -+ "parent": "fan1", -+ "extra": { -+ "funcname": "checkFan", -+ "id": "fan1", -+ "key": "hw_version" -+ }, -+ "arrt_index": 1, -+ }, -+ "fan1_fw_version": { -+ "key": "Firmware Version", -+ "parent": "fan1", -+ "config": "NA", -+ "arrt_index": 2, -+ }, -+ -+ "fan2": { -+ "key": "FAN2", -+ "parent": "fan", -+ "arrt_index": 2, -+ }, -+ "fan2_hw_version": { -+ "key": "Hardware Version", -+ "parent": "fan2", -+ "extra": { -+ "funcname": "checkFan", -+ "id": "fan2", -+ "key": "hw_version" -+ }, -+ "arrt_index": 1, -+ }, -+ "fan2_fw_version": { -+ "key": "Firmware Version", -+ "parent": "fan2", -+ "config": "NA", -+ "arrt_index": 2, -+ }, -+ -+ "fan3": { -+ "key": "FAN3", -+ "parent": "fan", -+ "arrt_index": 3, -+ }, -+ "fan3_hw_version": { -+ "key": "Hardware Version", -+ "parent": "fan3", -+ "extra": { -+ "funcname": "checkFan", -+ "id": "fan3", -+ "key": "hw_version" -+ }, -+ "arrt_index": 1, -+ }, -+ "fan3_fw_version": { -+ "key": "Firmware Version", -+ "parent": "fan3", -+ "config": "NA", -+ "arrt_index": 2, -+ }, -+ -+ "fan4": { -+ "key": "FAN4", -+ "parent": "fan", -+ "arrt_index": 4, -+ }, -+ "fan4_hw_version": { -+ "key": "Hardware Version", -+ "parent": "fan4", -+ "extra": { -+ "funcname": "checkFan", -+ "id": "fan4", -+ "key": "hw_version" -+ }, -+ "arrt_index": 1, -+ }, -+ "fan4_fw_version": { -+ "key": "Firmware Version", -+ "parent": "fan4", -+ "config": "NA", -+ "arrt_index": 2, -+ }, -+ -+ "i210": { -+ "key": "NIC", -+ "next": "fpga" -+ }, -+ "i210_model": { -+ "parent": "i210", -+ "config": "NA", -+ "key": "Device Model", -+ "arrt_index": 1, -+ }, -+ "i210_vendor": { -+ "parent": "i210", -+ "config": "INTEL", -+ "key": "Vendor", -+ "arrt_index": 2, -+ }, -+ "i210_version": { -+ "parent": "i210", -+ "cmd": "ethtool -i eth0", -+ "pattern": r"firmware-version", -+ "separator": ":", -+ "key": "Firmware Version", -+ "arrt_index": 3, -+ }, -+ -+ "fpga": { -+ "key": "FPGA", -+ "next": "asic" -+ }, -+ "fpga_model": { -+ "parent": "fpga", -+ "config": "XC7A15T-2FGG484C", -+ "key": "Device Model", -+ "arrt_index": 1, -+ }, -+ "fpga_vendor": { -+ "parent": "fpga", -+ "config": "XILINX", -+ "key": "Vendor", -+ "arrt_index": 2, -+ }, -+ "fpga_desc": { -+ "parent": "fpga", -+ "config": "NA", -+ "key": "Description", -+ "arrt_index": 3, -+ }, -+ "fpga_hw_version": { -+ "parent": "fpga", -+ "config": "NA", -+ "key": "Hardware Version", -+ "arrt_index": 4, -+ }, -+ "fpga_fw_version": { -+ "parent": "fpga", -+ "pci": { -+ "bus": 8, -+ "slot": 0, -+ "fn": 0, -+ "bar": 0, -+ "offset": 0 -+ }, -+ "key": "Firmware Version", -+ "arrt_index": 5, -+ }, -+ "fpga_date": { -+ "parent": "fpga", -+ "pci": { -+ "bus": 8, -+ "slot": 0, -+ "fn": 0, -+ "bar": 0, -+ "offset": 4 -+ }, -+ "key": "Build Date", -+ "arrt_index": 6, -+ }, -+ "asic": { -+ "key": "ASIC", -+ }, -+ "sdk_model": { -+ "parent": "asic", -+ "cmd": "bcmcmd -t 1 att", -+ "pattern": r"^Attach", -+ "regular": r"(?<=\()[^)]*(?=\))", -+ "key": "Device Model", -+ "arrt_index": 1, -+ }, -+ "sdk_version": { -+ "parent": "asic", -+ "cmd": "bcmcmd -t 1 version | grep Release", -+ "pattern": r".*Release", -+ "separator": ":", -+ "key": "SDK Version", -+ "arrt_index": 2, -+ }, -+ "pci_version": { -+ "parent": "asic", -+ "cmd": "bcmcmd -t 1 \"pciephy fw version\" |grep \"PCIe FW version\"", -+ "pattern": r".*PCIe FW version", -+ "separator": ":", -+ "key": "PCIe Firmware Version", -+ "arrt_index": 3, -+ }, -+} -+ -+PMON_SYSLOG_STATUS = { -+ "polling_time": 3, -+ "sffs": { -+ "present": {"path": ["/sys/wb_plat/sff/*/present"], "ABSENT": 0}, -+ "nochangedmsgflag": 0, -+ "nochangedmsgtime": 60, -+ "noprintfirsttimeflag": 1, -+ "alias": { -+ "sff1": "Ethernet1", -+ "sff2": "Ethernet2", -+ "sff3": "Ethernet3", -+ "sff4": "Ethernet4", -+ "sff5": "Ethernet5", -+ "sff6": "Ethernet6", -+ "sff7": "Ethernet7", -+ "sff8": "Ethernet8", -+ "sff9": "Ethernet9", -+ "sff10": "Ethernet10", -+ "sff11": "Ethernet11", -+ "sff12": "Ethernet12", -+ "sff13": "Ethernet13", -+ "sff14": "Ethernet14", -+ "sff15": "Ethernet15", -+ "sff16": "Ethernet16", -+ "sff17": "Ethernet17", -+ "sff18": "Ethernet18", -+ "sff19": "Ethernet19", -+ "sff20": "Ethernet20", -+ "sff21": "Ethernet21", -+ "sff22": "Ethernet22", -+ "sff23": "Ethernet23", -+ "sff24": "Ethernet24", -+ "sff25": "Ethernet25", -+ "sff26": "Ethernet26", -+ "sff27": "Ethernet27", -+ "sff28": "Ethernet28", -+ "sff29": "Ethernet29", -+ "sff30": "Ethernet30", -+ "sff31": "Ethernet31", -+ "sff32": "Ethernet32", -+ "sff33": "Ethernet33", -+ "sff34": "Ethernet34", -+ "sff35": "Ethernet35", -+ "sff36": "Ethernet36", -+ "sff37": "Ethernet37", -+ "sff38": "Ethernet38", -+ "sff39": "Ethernet39", -+ "sff40": "Ethernet40", -+ "sff41": "Ethernet41", -+ "sff42": "Ethernet42", -+ "sff43": "Ethernet43", -+ "sff44": "Ethernet44", -+ "sff45": "Ethernet45", -+ "sff46": "Ethernet46", -+ "sff47": "Ethernet47", -+ "sff48": "Ethernet48", -+ "sff49": "Ethernet49", -+ "sff50": "Ethernet50", -+ "sff51": "Ethernet51", -+ "sff52": "Ethernet52", -+ "sff53": "Ethernet53", -+ "sff54": "Ethernet54", -+ "sff55": "Ethernet55", -+ "sff56": "Ethernet56", -+ } -+ }, -+ "fans": { -+ "present": {"path": ["/sys/wb_plat/fan/*/present"], "ABSENT": 0}, -+ "status": [ -+ {"path": "/sys/wb_plat/fan/%s/motor0/status", 'okval': 1}, -+ {"path": "/sys/wb_plat/fan/%s/motor1/status", 'okval': 1}, -+ ], -+ "nochangedmsgflag": 1, -+ "nochangedmsgtime": 60, -+ "noprintfirsttimeflag": 0, -+ "alias": { -+ "fan1": "FAN1", -+ "fan2": "FAN2", -+ "fan3": "FAN3", -+ "fan4": "FAN4" -+ } -+ }, -+ "psus": { -+ "present": {"path": ["/sys/wb_plat/psu/*/present"], "ABSENT": 0}, -+ "status": [ -+ {"path": "/sys/wb_plat/psu/%s/output", "okval": 1}, -+ {"path": "/sys/wb_plat/psu/%s/alert", "okval": 0}, -+ ], -+ "nochangedmsgflag": 1, -+ "nochangedmsgtime": 60, -+ "noprintfirsttimeflag": 0, -+ "alias": { -+ "psu1": "PSU1", -+ "psu2": "PSU2" -+ } -+ } -+} -+ -+##################### MAC Voltage adjust#################################### -+MAC_DEFAULT_PARAM = [ -+ { -+ "name": "mac_core", # AVS name -+ "type": 1, # 1: used default value, if rov value not in range. 0: do nothing, if rov value not in range -+ "default": 0x74, # default value, if rov value not in range -+ "sdkreg": "TOP_AVS_SEL_REG", # SDK register name -+ "sdktype": 0, # 0: No shift operation required, 1: shift operation required -+ "macregloc": 24, # Shift right 24 bits -+ "mask": 0xff, # Use with macregloc -+ "rov_source": 1, # 0:get rov value from cpld, 1: get rov value from SDK -+ "cpld_avs": {"bus": 6, "loc": 0x0d, "offset": 0xc3, "gettype": "i2c"}, -+ "set_avs": { -+ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/avs0_vout", -+ "gettype": "sysfs", "formula": "int((%f)*1000000)" -+ }, -+ "mac_avs_param": { -+ 0x08: 0.888, -+ 0x72: 0.900, -+ 0x73: 0.894, -+ 0x74: 0.888, -+ 0x75: 0.882, -+ 0x76: 0.875, -+ 0x77: 0.869, -+ 0x78: 0.863, -+ 0x79: 0.857, -+ 0x7a: 0.850, -+ 0x7b: 0.844, -+ 0x7c: 0.838, -+ 0x7d: 0.832, -+ 0x7e: 0.825, -+ 0x7f: 0.819, -+ 0x80: 0.813, -+ 0x81: 0.807, -+ 0x82: 0.800, -+ 0x83: 0.794, -+ 0x84: 0.788, -+ 0x85: 0.782, -+ 0x86: 0.775, -+ 0x87: 0.769, -+ 0x88: 0.763, -+ 0x89: 0.757, -+ 0x8A: 0.750 -+ } -+ } -+] -+ -+BLACKLIST_DRIVERS = [ -+ {"name": "i2c_i801", "delay": 0}, -+] -+ -+DRIVERLISTS = [ -+ {"name": "wb_i2c_i801", "delay": 0}, -+ {"name": "wb_gpio_d1500", "delay": 0}, -+ {"name": "i2c_dev", "delay": 0}, -+ {"name": "wb_i2c_algo_bit", "delay": 0}, -+ {"name": "wb_i2c_gpio", "delay": 0}, -+ {"name": "i2c_mux", "delay": 0}, -+ {"name": "wb_gpio_device", "delay": 0}, -+ {"name": "wb_i2c_gpio_device gpio_sda=17 gpio_scl=1 gpio_udelay=2", "delay": 0}, -+ {"name": "platform_common dfd_my_type=0x404a", "delay": 0}, -+ {"name": "wb_lpc_drv", "delay": 0}, -+ {"name": "wb_lpc_drv_device", "delay": 0}, -+ {"name": "wb_io_dev", "delay": 0}, -+ {"name": "wb_io_dev_device", "delay": 0}, -+ {"name": "wb_fpga_pcie", "delay": 0}, -+ {"name": "wb_pcie_dev", "delay": 0}, -+ {"name": "wb_pcie_dev_device", "delay": 0}, -+ {"name": "wb_i2c_dev", "delay": 0}, -+ {"name": "wb_i2c_ocores", "delay": 0}, -+ {"name": "wb_i2c_ocores_device", "delay": 0}, -+ {"name": "wb_i2c_mux_pca9641", "delay": 0}, -+ {"name": "wb_i2c_mux_pca954x", "delay": 0}, -+ {"name": "wb_i2c_mux_pca954x_device", "delay": 0}, -+ {"name": "wb_i2c_dev_device", "delay": 0}, -+ {"name": "wb_lm75", "delay": 0}, -+ {"name": "wb_optoe", "delay": 0}, -+ {"name": "wb_at24", "delay": 0}, -+ {"name": "wb_mac_bsc", "delay": 0}, -+ {"name": "wb_pmbus_core", "delay": 0}, -+ {"name": "wb_isl68137", "delay": 0}, -+ {"name": "wb_csu550", "delay": 0}, -+ {"name": "wb_ina3221", "delay": 0}, -+ {"name": "wb_tps53622", "delay": 0}, -+ {"name": "plat_dfd", "delay": 0}, -+ {"name": "plat_switch", "delay": 0}, -+ {"name": "plat_fan", "delay": 0}, -+ {"name": "plat_psu", "delay": 0}, -+ {"name": "plat_sff", "delay": 0}, -+] -+ -+DEVICE = [ -+ {"name": "wb_24c02", "bus": 0, "loc": 0x56}, -+ {"name": "wb_mac_bsc_td3", "bus": 3, "loc": 0x44}, -+ # fan -+ {"name": "wb_24c02", "bus": 16, "loc": 0x50}, -+ {"name": "wb_24c02", "bus": 17, "loc": 0x50}, -+ {"name": "wb_24c02", "bus": 18, "loc": 0x50}, -+ {"name": "wb_24c02", "bus": 19, "loc": 0x50}, -+ # psu -+ {"name": "wb_24c02", "bus": 24, "loc": 0x50}, -+ {"name": "wb_dps550", "bus": 24, "loc": 0x58}, -+ {"name": "wb_24c02", "bus": 25, "loc": 0x50}, -+ {"name": "wb_dps550", "bus": 25, "loc": 0x58}, -+ # temp -+ {"name": "wb_lm75", "bus": 3, "loc": 0x48}, -+ {"name": "wb_lm75", "bus": 3, "loc": 0x49}, -+ {"name": "wb_lm75", "bus": 3, "loc": 0x4a}, -+ {"name": "wb_lm75", "bus": 3, "loc": 0x4b}, -+ {"name": "wb_lm75", "bus": 3, "loc": 0x4c}, -+ # dcdc -+ {"name": "wb_ina3221", "bus": 7, "loc": 0x40}, -+ {"name": "wb_ina3221", "bus": 7, "loc": 0x41}, -+ {"name": "wb_ina3221", "bus": 7, "loc": 0x42}, -+ {"name": "wb_ina3221", "bus": 7, "loc": 0x43}, -+ {"name": "wb_tps53622", "bus": 7, "loc": 0x60}, -+ {"name": "wb_tps53622", "bus": 7, "loc": 0x6c}, -+ {"name": "wb_isl68127", "bus": 7, "loc": 0x64}, -+] -+ -+OPTOE = [ -+ {"name": "wb_optoe2", "startbus": 32, "endbus": 79}, -+ {"name": "wb_optoe1", "startbus": 80, "endbus": 87}, -+] -+ -+DEV_MONITOR_PARAM = { -+ "polling_time": 10, -+ "psus": [ -+ { -+ "name": "psu1", -+ "present": {"gettype": "i2c", "bus": 6, "loc": 0x0d, "offset": 0x51, "presentbit": 0, "okval": 0}, -+ "device": [ -+ {"id": "psu1pmbus", "name": "wb_dps550", "bus": 24, "loc": 0x58, "attr": "hwmon"}, -+ {"id": "psu1frue2", "name": "wb_24c02", "bus": 24, "loc": 0x50, "attr": "eeprom"}, -+ ], -+ }, -+ { -+ "name": "psu2", -+ "present": {"gettype": "i2c", "bus": 6, "loc": 0x0d, "offset": 0x51, "presentbit": 4, "okval": 0}, -+ "device": [ -+ {"id": "psu2pmbus", "name": "wb_dps550", "bus": 25, "loc": 0x58, "attr": "hwmon"}, -+ {"id": "psu2frue2", "name": "wb_24c02", "bus": 25, "loc": 0x50, "attr": "eeprom"}, -+ ], -+ }, -+ ], -+ "fans": [ -+ { -+ "name": "fan1", -+ "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 0, "okval": 0}, -+ "device": [ -+ {"id": "fan1frue2", "name": "24c02", "bus": 16, "loc": 0x50, "attr": "eeprom"}, -+ ], -+ }, -+ { -+ "name": "fan2", -+ "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 1, "okval": 0}, -+ "device": [ -+ {"id": "fan2frue2", "name": "24c02", "bus": 17, "loc": 0x50, "attr": "eeprom"}, -+ ], -+ }, -+ { -+ "name": "fan3", -+ "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 2, "okval": 0}, -+ "device": [ -+ {"id": "fan3frue2", "name": "24c02", "bus": 18, "loc": 0x50, "attr": "eeprom"}, -+ ], -+ }, -+ { -+ "name": "fan4", -+ "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 3, "okval": 0}, -+ "device": [ -+ {"id": "fan4frue2", "name": "24c02", "bus": 19, "loc": 0x50, "attr": "eeprom"}, -+ ], -+ }, -+ ], -+ "others": [ -+ { -+ "name": "eeprom", -+ "device": [ -+ {"id": "eeprom_1", "name": "wb_24c02", "bus": 0, "loc": 0x56, "attr": "eeprom"}, -+ ], -+ }, -+ { -+ "name": "lm75", -+ "device": [ -+ {"id": "lm75_1", "name": "wb_lm75", "bus": 3, "loc": 0x48, "attr": "hwmon"}, -+ {"id": "lm75_2", "name": "wb_lm75", "bus": 3, "loc": 0x49, "attr": "hwmon"}, -+ {"id": "lm75_3", "name": "wb_lm75", "bus": 3, "loc": 0x4a, "attr": "hwmon"}, -+ {"id": "lm75_4", "name": "wb_lm75", "bus": 3, "loc": 0x4b, "attr": "hwmon"}, -+ {"id": "lm75_5", "name": "wb_lm75", "bus": 3, "loc": 0x4c, "attr": "hwmon"}, -+ ], -+ }, -+ { -+ "name": "mac_bsc", -+ "device": [ -+ {"id": "mac_bsc_1", "name": "wb_mac_bsc_td3", "bus": 3, "loc": 0x44, "attr": "hwmon"}, -+ ], -+ }, -+ { -+ "name": "ina3221", -+ "device": [ -+ {"id": "ina3221_1", "name": "wb_ina3221", "bus": 7, "loc": 0x40, "attr": "hwmon"}, -+ {"id": "ina3221_2", "name": "wb_ina3221", "bus": 7, "loc": 0x41, "attr": "hwmon"}, -+ {"id": "ina3221_3", "name": "wb_ina3221", "bus": 7, "loc": 0x42, "attr": "hwmon"}, -+ {"id": "ina3221_4", "name": "wb_ina3221", "bus": 7, "loc": 0x43, "attr": "hwmon"}, -+ ], -+ }, -+ { -+ "name": "tps53622", -+ "device": [ -+ {"id": "tps53622_1", "name": "wb_tps53622", "bus": 7, "loc": 0x60, "attr": "hwmon"}, -+ {"id": "tps53622_2", "name": "wb_tps53622", "bus": 7, "loc": 0x6c, "attr": "hwmon"}, -+ ], -+ }, -+ { -+ "name": "isl68127", -+ "device": [ -+ {"id": "isl68127_1", "name": "wb_isl68127", "bus": 7, "loc": 0x64, "attr": "hwmon"}, -+ ], -+ } -+ ], -+} -+ -+INIT_PARAM_PRE = [ -+ {"loc": "7-0064/hwmon/hwmon*/avs0_vout_max", "value": "900000"}, -+ {"loc": "7-0064/hwmon/hwmon*/avs0_vout_min", "value": "750000"}, -+] -+INIT_COMMAND_PRE = [ -+ "i2cset -y -f 6 0x0d 0x91 0x48", -+ "i2cset -y -f 6 0x0d 0x92 0x01", # MAC_PWR_EN -+ "i2cset -y -f 6 0x0d 0x94 0x01", # SFF_PWR_EN -+ "i2cset -y -f 6 0x0d 0xbf 0x01", # enbale tty_console monitor -+] -+ -+INIT_PARAM = [] -+ -+INIT_COMMAND = [ -+ "i2cset -y -f 8 0x30 0x60 0x00", # enable txdis[1~8] -+ "i2cset -y -f 8 0x30 0x61 0x00", # enable txdis[9~16] -+ "i2cset -y -f 8 0x30 0x62 0x00", # enable txdis[17~24] -+ "i2cset -y -f 8 0x31 0x60 0x00", # enable txdis[24~32] -+ "i2cset -y -f 8 0x31 0x61 0x00", # enable txdis[33~40] -+ "i2cset -y -f 8 0x31 0x62 0x00", # enable txdis[41~48] -+] -+ -+REBOOT_CAUSE_PARA = { -+ "reboot_cause_list": [ -+ { -+ "name": "otp_switch_reboot", -+ "monitor_point": {"gettype": "file_exist", "judge_file": "/etc/.otp_switch_reboot_flag", "okval": True}, -+ "record": [ -+ {"record_type": "file", "mode": "cover", "log": "Thermal Overload: ASIC, ", -+ "path": "/etc/sonic/.reboot/.previous-reboot-cause.txt"}, -+ {"record_type": "file", "mode": "add", "log": "Thermal Overload: ASIC, ", -+ "path": "/etc/sonic/.reboot/.history-reboot-cause.txt", "file_max_size": 1 * 1024 * 1024} -+ ], -+ "finish_operation": [ -+ {"gettype": "cmd", "cmd": "rm -rf /etc/.otp_switch_reboot_flag"}, -+ ] -+ }, -+ { -+ "name": "otp_other_reboot", -+ "monitor_point": {"gettype": "file_exist", "judge_file": "/etc/.otp_other_reboot_flag", "okval": True}, -+ "record": [ -+ {"record_type": "file", "mode": "cover", "log": "Thermal Overload: Other, ", -+ "path": "/etc/sonic/.reboot/.previous-reboot-cause.txt"}, -+ {"record_type": "file", "mode": "add", "log": "Thermal Overload: Other, ", -+ "path": "/etc/sonic/.reboot/.history-reboot-cause.txt", "file_max_size": 1 * 1024 * 1024} -+ ], -+ "finish_operation": [ -+ {"gettype": "cmd", "cmd": "rm -rf /etc/.otp_other_reboot_flag"}, -+ ] -+ }, -+ ], -+ "other_reboot_cause_record": [ -+ {"record_type": "file", "mode": "cover", "log": "Other, ", "path": "/etc/sonic/.reboot/.previous-reboot-cause.txt"}, -+ {"record_type": "file", "mode": "add", "log": "Other, ", "path": "/etc/sonic/.reboot/.history-reboot-cause.txt"} -+ ], -+} -+ -+UPGRADE_SUMMARY = { -+ "devtype": 0x404a, -+ -+ "slot0": { -+ "subtype": 0, -+ "VME": { -+ "chain1": { -+ "name": "VME_CPLD", -+ "is_support_warm_upg": 0, -+ }, -+ }, -+ -+ "SPI-LOGIC-DEV": { -+ "chain3": { -+ "name": "FPGA", -+ "is_support_warm_upg": 0, -+ }, -+ }, -+ -+ "MTD": { -+ "chain2": { -+ "name": "BIOS", -+ "is_support_warm_upg": 0, -+ "filesizecheck": 10240, # bios check file size, Unit: K -+ "init_cmd": [ -+ {"io_addr": 0x722, "value": 0x02, "gettype": "io"}, -+ {"cmd": "modprobe mtd", "gettype": "cmd"}, -+ {"cmd": "modprobe spi_nor", "gettype": "cmd"}, -+ {"cmd": "modprobe ofpart", "gettype": "cmd"}, -+ {"cmd": "modprobe intel_spi writeable=1", "gettype": "cmd"}, -+ {"cmd": "modprobe intel_spi_platform writeable=1", "gettype": "cmd"}, -+ ], -+ "finish_cmd": [ -+ {"cmd": "rmmod intel_spi_platform", "gettype": "cmd"}, -+ {"cmd": "rmmod intel_spi", "gettype": "cmd"}, -+ {"cmd": "rmmod ofpart", "gettype": "cmd"}, -+ {"cmd": "rmmod spi_nor", "gettype": "cmd"}, -+ {"cmd": "rmmod mtd", "gettype": "cmd"}, -+ ], -+ }, -+ }, -+ -+ "TEST": { -+ "cpld": [ -+ {"chain": 1, "file": "/etc/.upgrade_test/cpld_test_header.vme", "display_name": "CPLD"}, -+ ], -+ "fpga": [ -+ { -+ "chain": 3, -+ "file": "/etc/.upgrade_test/fpga_test_header.bin", -+ "display_name": "FPGA", -+ }, -+ ], -+ }, -+ }, -+ -+ "BMC": { -+ "name": "BMC", -+ "init_cmd": [ -+ ], -+ "finish_cmd": [], -+ }, -+} -+ -+ -+PLATFORM_E2_CONF = { -+ "fan": [ -+ { -+ "name": "fan1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/16-0050/eeprom", -+ "e2_decode": [ -+ { -+ "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" -+ }, -+ { -+ "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" -+ }, -+ ], -+ }, -+ { -+ "name": "fan2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/17-0050/eeprom", -+ "e2_decode": [ -+ { -+ "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" -+ }, -+ { -+ "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" -+ }, -+ ], -+ }, -+ { -+ "name": "fan3", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/18-0050/eeprom", -+ "e2_decode": [ -+ { -+ "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" -+ }, -+ { -+ "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" -+ }, -+ ], -+ }, -+ { -+ "name": "fan4", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/19-0050/eeprom", -+ "e2_decode": [ -+ { -+ "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" -+ }, -+ { -+ "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" -+ }, -+ ], -+ }, -+ ], -+ "psu": [ -+ {"name": "psu1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/24-0050/eeprom"}, -+ {"name": "psu2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/25-0050/eeprom"}, -+ ], -+ "syseeprom": [ -+ {"name": "syseeprom", "e2_type": "onie_tlv", "e2_path": "/sys/bus/i2c/devices/0-0056/eeprom"}, -+ ], -+} -+ -+AIR_FLOW_CONF = { -+ "psu_fan_airflow": { -+ "intake": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3', 'U1D-D10800-DRB'], -+ "exhaust": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'] -+ }, -+ -+ "fanairflow": { -+ "intake": ['M1HFAN III-F'], -+ "exhaust": ['M1HFAN III-R'] -+ }, -+ -+ "fans": [ -+ { -+ "name": "FAN1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/16-0050/eeprom", -+ "area": "productInfoArea", "field": "productName", "decode": "fanairflow" -+ }, -+ { -+ "name": "FAN2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/17-0050/eeprom", -+ "area": "productInfoArea", "field": "productName", "decode": "fanairflow" -+ }, -+ { -+ "name": "FAN3", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/18-0050/eeprom", -+ "area": "productInfoArea", "field": "productName", "decode": "fanairflow" -+ }, -+ { -+ "name": "FAN4", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/19-0050/eeprom", -+ "area": "productInfoArea", "field": "productName", "decode": "fanairflow" -+ } -+ ], -+ -+ "psus": [ -+ { -+ "name": "PSU1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/24-0050/eeprom", -+ "area": "productInfoArea", "field": "productPartModelName", "decode": "psu_fan_airflow" -+ }, -+ { -+ "name": "PSU2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/25-0050/eeprom", -+ "area": "productInfoArea", "field": "productPartModelName", "decode": "psu_fan_airflow" -+ } -+ ] -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_port_config.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_port_config.py -new file mode 100755 -index 000000000..26f92a77a ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_port_config.py -@@ -0,0 +1,7 @@ -+#!/usr/bin/python3 -+# -*- coding: UTF-8 -*- -+ -+PLATFORM_INTF_OPTOE = { -+ "port_num": 56, -+ "optoe_start_bus": 32, -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_device.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_device.py -new file mode 100755 -index 000000000..c1eb46247 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_device.py -@@ -0,0 +1,1371 @@ -+#!/usr/bin/python3 -+ -+psu_fan_airflow = { -+ "intake": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3', 'U1D-D10800-DRB'], -+ "exhaust": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'] -+} -+ -+fanairflow = { -+ "intake": ['M1HFAN III-F'], -+ "exhaust": ['M1HFAN III-R'], -+} -+ -+psu_display_name = { -+ "PA550II-F": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3'], -+ "PA550II-R": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'], -+ "PD800I-F": ['U1D-D10800-DRB'] -+} -+ -+psutypedecode = { -+ 0x00: 'N/A', -+ 0x01: 'AC', -+ 0x02: 'DC', -+} -+ -+ -+class Unit: -+ Temperature = "C" -+ Voltage = "V" -+ Current = "A" -+ Power = "W" -+ Speed = "RPM" -+ -+ -+PSU_NOT_PRESENT_PWM = 100 -+ -+ -+class threshold: -+ PSU_TEMP_MIN = -20 * 1000 -+ PSU_TEMP_MAX = 60 * 1000 -+ -+ PSU_FAN_SPEED_MIN = 2000 -+ PSU_FAN_SPEED_MAX = 18000 -+ -+ PSU_OUTPUT_VOLTAGE_MIN = 11 * 1000 -+ PSU_OUTPUT_VOLTAGE_MAX = 14 * 1000 -+ -+ PSU_AC_INPUT_VOLTAGE_MIN = 200 * 1000 -+ PSU_AC_INPUT_VOLTAGE_MAX = 240 * 1000 -+ -+ PSU_DC_INPUT_VOLTAGE_MIN = 190 * 1000 -+ PSU_DC_INPUT_VOLTAGE_MAX = 290 * 1000 -+ -+ ERR_VALUE = -9999999 -+ -+ PSU_OUTPUT_POWER_MIN = 10 * 1000 * 1000 -+ PSU_OUTPUT_POWER_MAX = 560 * 1000 * 1000 -+ -+ PSU_INPUT_POWER_MIN = 10 * 1000 * 1000 -+ PSU_INPUT_POWER_MAX = 625 * 1000 * 1000 -+ -+ PSU_OUTPUT_CURRENT_MIN = 1 * 1000 -+ PSU_OUTPUT_CURRENT_MAX = 45 * 1000 -+ -+ PSU_INPUT_CURRENT_MIN = 0 * 1000 -+ PSU_INPUT_CURRENT_MAX = 7 * 1000 -+ -+ FRONT_FAN_SPEED_MAX = 24000 -+ REAR_FAN_SPEED_MAX = 22500 -+ FAN_SPEED_MIN = 5000 -+ -+ -+ ASPOWER_DC_PSU_TEMP_MIN = -10 * 1000 -+ ASPOWER_DC_PSU_TEMP_MAX = 55 * 1000 -+ -+ ASPOWER_DC_PSU_FAN_SPEED_MIN = 800 -+ ASPOWER_DC_PSU_FAN_SPEED_MAX = 24000 -+ -+ ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN = 11.4 * 1000 -+ ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX = 12.6 * 1000 -+ -+ ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN = 36 * 1000 -+ ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX = 72 * 1000 -+ -+ ASPOWER_DC_ERR_VALUE = -9999999 -+ -+ ASPOWER_DC_PSU_OUTPUT_POWER_MIN = 5 * 1000 * 1000 -+ ASPOWER_DC_PSU_OUTPUT_POWER_MAX = 800 * 1000 * 1000 -+ -+ ASPOWER_DC_PSU_INPUT_POWER_MIN = 5 * 1000 * 1000 -+ ASPOWER_DC_PSU_INPUT_POWER_MAX = 880 * 1000 * 1000 -+ -+ ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN = 0.5 * 1000 -+ ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX = 66 * 1000 -+ -+ ASPOWER_DC_PSU_INPUT_CURRENT_MIN = 1 * 1000 -+ ASPOWER_DC_PSU_INPUT_CURRENT_MAX = 28 * 1000 -+ -+ -+class Description: -+ CPLD = "Used for managing IO modules, SFP+ modules and system LEDs" -+ BIOS = "Performs initialization of hardware components during booting" -+ FPGA = "Platform management controller for on-board temperature monitoring, in-chassis power" -+ -+ -+devices = { -+ "onie_e2": [ -+ { -+ "name": "ONIE_E2", -+ "e2loc": {"loc": "/sys/bus/i2c/devices/0-0056/eeprom", "way": "sysfs"}, -+ "airflow": "intake" -+ }, -+ ], -+ "psus": [ -+ { -+ "e2loc": {"loc": "/sys/bus/i2c/devices/24-0050/eeprom", "way": "sysfs"}, -+ "pmbusloc": {"bus": 24, "addr": 0x58, "way": "i2c"}, -+ "present": {"loc": "/sys/wb_plat/psu/psu1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, -+ "name": "PSU1", -+ "get_threshold_by_model": 1, -+ "psu_display_name": psu_display_name, -+ "airflow": psu_fan_airflow, -+ "TempStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, -+ "other": threshold.PSU_TEMP_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, -+ "other": threshold.PSU_TEMP_MAX, -+ }, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ }, -+ "FanStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, -+ "FanSpeed": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, -+ "other": threshold.PSU_FAN_SPEED_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, -+ "other": threshold.PSU_FAN_SPEED_MAX, -+ }, -+ "Unit": Unit.Speed -+ }, -+ "psu_fan_tolerance": 40, -+ "InputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, -+ "InputsType": {"bus": 24, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, -+ "InputsVoltage": { -+ 'AC': { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, -+ "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, -+ "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ -+ }, -+ 'DC': { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, -+ "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, -+ "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, -+ }, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ }, -+ 'other': { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, -+ "other": threshold.ERR_VALUE, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, -+ "other": threshold.ERR_VALUE, -+ }, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ "InputsCurrent": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, -+ "other": threshold.PSU_INPUT_CURRENT_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, -+ "other": threshold.PSU_INPUT_CURRENT_MAX, -+ }, -+ "Unit": Unit.Current, -+ "format": "float(float(%s)/1000)" -+ }, -+ "InputsPower": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, -+ "other": threshold.PSU_INPUT_POWER_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, -+ "other": threshold.PSU_INPUT_POWER_MAX, -+ }, -+ "Unit": Unit.Power, -+ "format": "float(float(%s)/1000000)" -+ }, -+ "OutputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, -+ "OutputsVoltage": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, -+ "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, -+ "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, -+ }, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ }, -+ "OutputsCurrent": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, -+ "other": threshold.PSU_OUTPUT_CURRENT_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, -+ "other": threshold.PSU_OUTPUT_CURRENT_MAX, -+ }, -+ "Unit": Unit.Current, -+ "format": "float(float(%s)/1000)" -+ }, -+ "OutputsPower": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, -+ "other": threshold.PSU_OUTPUT_POWER_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, -+ "other": threshold.PSU_OUTPUT_POWER_MAX, -+ }, -+ "Unit": Unit.Power, -+ "format": "float(float(%s)/1000000)" -+ }, -+ }, -+ { -+ "e2loc": {"loc": "/sys/bus/i2c/devices/25-0050/eeprom", "way": "sysfs"}, -+ "pmbusloc": {"bus": 25, "addr": 0x58, "way": "i2c"}, -+ "present": {"loc": "/sys/wb_plat/psu/psu2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, -+ "name": "PSU2", -+ "get_threshold_by_model": 1, -+ "psu_display_name": psu_display_name, -+ "airflow": psu_fan_airflow, -+ "TempStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, -+ "other": threshold.PSU_TEMP_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, -+ "other": threshold.PSU_TEMP_MAX, -+ }, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ }, -+ "FanStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, -+ "FanSpeed": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, -+ "other": threshold.PSU_FAN_SPEED_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, -+ "other": threshold.PSU_FAN_SPEED_MAX, -+ }, -+ "Unit": Unit.Speed -+ }, -+ "psu_fan_tolerance": 40, -+ "InputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, -+ "InputsType": {"bus": 25, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, -+ "InputsVoltage": { -+ 'AC': { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, -+ "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, -+ "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ -+ }, -+ 'DC': { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, -+ "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, -+ "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, -+ }, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ }, -+ 'other': { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, -+ "other": threshold.ERR_VALUE, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, -+ "other": threshold.ERR_VALUE, -+ }, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ "InputsCurrent": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, -+ "other": threshold.PSU_INPUT_CURRENT_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, -+ "other": threshold.PSU_INPUT_CURRENT_MAX, -+ }, -+ "Unit": Unit.Current, -+ "format": "float(float(%s)/1000)" -+ }, -+ "InputsPower": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, -+ "other": threshold.PSU_INPUT_POWER_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, -+ "other": threshold.PSU_INPUT_POWER_MAX, -+ }, -+ "Unit": Unit.Power, -+ "format": "float(float(%s)/1000000)" -+ }, -+ "OutputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, -+ "OutputsVoltage": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, -+ "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, -+ "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, -+ }, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ }, -+ "OutputsCurrent": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, -+ "other": threshold.PSU_OUTPUT_CURRENT_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, -+ "other": threshold.PSU_OUTPUT_CURRENT_MAX, -+ }, -+ "Unit": Unit.Current, -+ "format": "float(float(%s)/1000)" -+ }, -+ "OutputsPower": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, -+ "other": threshold.PSU_OUTPUT_POWER_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, -+ "other": threshold.PSU_OUTPUT_POWER_MAX, -+ }, -+ "Unit": Unit.Power, -+ "format": "float(float(%s)/1000000)" -+ }, -+ } -+ ], -+ "temps": [ -+ { -+ "name": "SWITCH_TEMP", -+ "temp_id": "TEMP1", -+ "api_name": "ASIC_TEMP", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/3-0044/hwmon/hwmon*/temp99_input", "way": "sysfs"}, -+ "Min": -30000, -+ "Low": 0, -+ "High": 105000, -+ "Max": 110000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ { -+ "name": "CPU_TEMP", -+ "temp_id": "TEMP2", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/platform/devices/coretemp.0/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": -15000, -+ "Low": 0, -+ "High": 100000, -+ "Max": 102000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ { -+ "name": "INLET_TEMP", -+ "temp_id": "TEMP3", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/3-0048/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": -30000, -+ "Low": 0, -+ "High": 55000, -+ "Max": 60000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ }, -+ "fix_value": { -+ "fix_type": "config", -+ "addend": -3, -+ } -+ }, -+ { -+ "name": "OUTLET_TEMP", -+ "temp_id": "TEMP4", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/3-004c/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": -30000, -+ "Low": 0, -+ "High": 75000, -+ "Max": 80000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ { -+ "name": "BOARD_TEMP", -+ "temp_id": "TEMP5", -+ "api_name": "MAC_OUT_TEMP", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/3-004a/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": -30000, -+ "Low": 0, -+ "High": 75000, -+ "Max": 80000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ { -+ "name": "MAC_IN_TEMP", -+ "temp_id": "TEMP6", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/3-0049/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": -30000, -+ "Low": 0, -+ "High": 75000, -+ "Max": 80000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ { -+ "name": "PSU1_TEMP", -+ "temp_id": "TEMP7", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": -20000, -+ "Low": 0, -+ "High": 55000, -+ "Max": 60000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ { -+ "name": "PSU2_TEMP", -+ "temp_id": "TEMP8", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": -20000, -+ "Low": 0, -+ "High": 55000, -+ "Max": 60000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ { -+ "name": "SFF_TEMP", -+ "Temperature": { -+ "value": {"loc": "/tmp/highest_sff_temp", "way": "sysfs", "flock_path": "/tmp/highest_sff_temp"}, -+ "Min": -30000, -+ "Low": 0, -+ "High": 90000, -+ "Max": 100000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ }, -+ "invalid": -10000, -+ "error": -9999, -+ } -+ ], -+ "leds": [ -+ { -+ "name": "FRONT_SYS_LED", -+ "led_type": "SYS_LED", -+ "led": {"bus": 6, "addr": 0x0d, "offset": 0x72, "way": "i2c"}, -+ "led_attrs": { -+ "off": 0x00, "red_flash": 0x01, "red": 0x02, -+ "green_flash": 0x03, "green": 0x04, "amber_flash": 0x05, -+ "amber": 0x06, "mask": 0x07 -+ }, -+ }, -+ { -+ "name": "FRONT_PSU_LED", -+ "led_type": "PSU_LED", -+ "led": {"bus": 6, "addr": 0x0d, "offset": 0x73, "way": "i2c"}, -+ "led_attrs": { -+ "off": 0x10, "red_flash": 0x11, "red": 0x12, -+ "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, -+ "amber": 0x16, "mask": 0x17 -+ }, -+ }, -+ { -+ "name": "FRONT_FAN_LED", -+ "led_type": "FAN_LED", -+ "led": {"bus": 6, "addr": 0x0d, "offset": 0x74, "way": "i2c"}, -+ "led_attrs": { -+ "off": 0x10, "red_flash": 0x11, "red": 0x12, -+ "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, -+ "amber": 0x16, "mask": 0x17 -+ }, -+ }, -+ ], -+ "fans": [ -+ { -+ "name": "FAN1", -+ "airflow": fanairflow, -+ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-16/16-0050/eeprom', 'way': 'sysfs'}, -+ "present": {"loc": "/sys/wb_plat/fan/fan1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3b, "way": "i2c"}, -+ "led_attrs": { -+ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, -+ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, -+ "amber": 0x03, "mask": 0x0f -+ }, -+ "PowerMax": 38.4, -+ "Rotor": { -+ "Rotor1_config": { -+ "name": "Rotor1", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan1/motor1/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.FRONT_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ "Rotor2_config": { -+ "name": "Rotor2", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan1/motor0/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.REAR_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ }, -+ }, -+ { -+ "name": "FAN2", -+ "airflow": fanairflow, -+ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-17/17-0050/eeprom', 'way': 'sysfs'}, -+ "present": {"loc": "/sys/wb_plat/fan/fan2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3c, "way": "i2c"}, -+ "led_attrs": { -+ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, -+ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, -+ "amber": 0x03, "mask": 0x0f -+ }, -+ "PowerMax": 38.4, -+ "Rotor": { -+ "Rotor1_config": { -+ "name": "Rotor1", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan2/motor1/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.FRONT_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ "Rotor2_config": { -+ "name": "Rotor2", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan2/motor0/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.REAR_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ }, -+ }, -+ { -+ "name": "FAN3", -+ "airflow": fanairflow, -+ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-18/18-0050/eeprom', 'way': 'sysfs'}, -+ "present": {"loc": "/sys/wb_plat/fan/fan3/present", "way": "sysfs", "mask": 0x01, "okval": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3d, "way": "i2c"}, -+ "led_attrs": { -+ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, -+ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, -+ "amber": 0x03, "mask": 0x0f -+ }, -+ "PowerMax": 38.4, -+ "Rotor": { -+ "Rotor1_config": { -+ "name": "Rotor1", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan3/motor1/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.FRONT_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ "Rotor2_config": { -+ "name": "Rotor2", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan3/motor0/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.REAR_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ }, -+ }, -+ -+ { -+ "name": "FAN4", -+ "airflow": fanairflow, -+ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-19/19-0050/eeprom', 'way': 'sysfs'}, -+ "present": {"loc": "/sys/wb_plat/fan/fan4/present", "way": "sysfs", "mask": 0x01, "okval": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3e, "way": "i2c"}, -+ "led_attrs": { -+ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, -+ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, -+ "amber": 0x03, "mask": 0x0f -+ }, -+ "PowerMax": 38.4, -+ "Rotor": { -+ "Rotor1_config": { -+ "name": "Rotor1", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan4/motor1/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.FRONT_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ "Rotor2_config": { -+ "name": "Rotor2", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan4/motor0/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.REAR_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ }, -+ }, -+ -+ ], -+ "cplds": [ -+ { -+ "name": "CPU_CPLD", -+ "cpld_id": "CPLD1", -+ "VersionFile": {"loc": "/dev/cpld0", "offset": 0, "len": 4, "way": "devfile_ascii"}, -+ "desc": "Used for system power", -+ "slot": 0, -+ "warm": 0, -+ }, -+ { -+ "name": "CONNECT_CPLD", -+ "cpld_id": "CPLD2", -+ "VersionFile": {"loc": "/dev/cpld1", "offset": 0, "len": 4, "way": "devfile_ascii"}, -+ "desc": "Used for base functions", -+ "slot": 0, -+ "warm": 0, -+ }, -+ { -+ "name": "CONNECT_CPLD-FAN", -+ "cpld_id": "CPLD3", -+ "VersionFile": {"loc": "/dev/cpld2", "offset": 0, "len": 4, "way": "devfile_ascii"}, -+ "desc": "Used for fan modules", -+ "slot": 0, -+ "warm": 0, -+ }, -+ { -+ "name": "MAC_CPLD1", -+ "cpld_id": "CPLD4", -+ "VersionFile": {"loc": "/dev/cpld3", "offset": 0, "len": 4, "way": "devfile_ascii"}, -+ "desc": "Used for sff modules", -+ "slot": 0, -+ "warm": 0, -+ }, -+ { -+ "name": "MAC_CPLD2", -+ "cpld_id": "CPLD5", -+ "VersionFile": {"loc": "/dev/cpld4", "offset": 0, "len": 4, "way": "devfile_ascii"}, -+ "desc": "Used for sff modules", -+ "slot": 0, -+ "warm": 0, -+ }, -+ { -+ "name": "FPGA", -+ "cpld_id": "CPLD6", -+ "VersionFile": {"loc": "/dev/fpga0", "offset": 0, "len": 4, "way": "devfile_ascii"}, -+ "desc": "Used for base functions", -+ "slot": 0, -+ "format": "little_endian", -+ "warm": 0, -+ }, -+ { -+ "name": "BIOS", -+ "cpld_id": "CPLD7", -+ "VersionFile": {"cmd": "dmidecode -s bios-version", "way": "cmd"}, -+ "desc": "Performs initialization of hardware components during booting", -+ "slot": 0, -+ "type": "str", -+ "warm": 0, -+ }, -+ ], -+ "dcdc": [ -+ { -+ "name": "Switch_ZSFP1_3v3_C", -+ "dcdc_id": "DCDC1", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 22000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_QSFP1_3v3_C", -+ "dcdc_id": "DCDC2", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 22000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_5v0_C", -+ "dcdc_id": "DCDC3", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 1000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_ZSFP1_3v3_V", -+ "dcdc_id": "DCDC4", -+ "Min": 2640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 3960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_QSFP1_3v3_V", -+ "dcdc_id": "DCDC5", -+ "Min": 2640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 3960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_5v0_V", -+ "dcdc_id": "DCDC6", -+ "Min": 4000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 6000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_1v2_C", -+ "dcdc_id": "DCDC7", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 2000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_3v3_C", -+ "dcdc_id": "DCDC8", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 1000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_Cpld_3v3_C", -+ "dcdc_id": "DCDC9", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 2000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_1v2_V", -+ "dcdc_id": "DCDC10", -+ "Min": 960, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 1440, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_3v3_V", -+ "dcdc_id": "DCDC11", -+ "Min": 2640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 3960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_Cpld_3v3_V", -+ "dcdc_id": "DCDC12", -+ "Min": 2640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 3960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Con_1v2_C", -+ "dcdc_id": "DCDC13", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 1300, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Con_3v3_C", -+ "dcdc_id": "DCDC14", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 2800, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Con_SSD_3v3_C", -+ "dcdc_id": "DCDC15", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 4500, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Con_1v2_V", -+ "dcdc_id": "DCDC16", -+ "Min": 960, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 1440, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Con_3v3_V", -+ "dcdc_id": "DCDC17", -+ "Min": 2640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 3960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Con_SSD_3v3_V", -+ "dcdc_id": "DCDC18", -+ "Min": 2640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 3960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_3v3_C", -+ "dcdc_id": "DCDC19", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 4686, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_5v_C", -+ "dcdc_id": "DCDC20", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 2200, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_1v7_C", -+ "dcdc_id": "DCDC21", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 2200, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_3v3_V", -+ "dcdc_id": "DCDC22", -+ "Min": 2640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 3960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_5v_V", -+ "dcdc_id": "DCDC23", -+ "Min": 4000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 6000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_1v7_V", -+ "dcdc_id": "DCDC24", -+ "Min": 1360, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 2040, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_CORE_C", -+ "dcdc_id": "DCDC25", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 47300, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_1v05_C", -+ "dcdc_id": "DCDC26", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 15400, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_CORE_V", -+ "dcdc_id": "DCDC27", -+ "Min": 1456, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 2184, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_1v05_V", -+ "dcdc_id": "DCDC28", -+ "Min": 840, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 1260, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_CORE_C", -+ "dcdc_id": "DCDC29", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 220000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_ANALOG_C", -+ "dcdc_id": "DCDC30", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 18000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_CORE_V", -+ "dcdc_id": "DCDC31", -+ "Min": 600, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 1200, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_ANALOG_V", -+ "dcdc_id": "DCDC32", -+ "Min": 640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_1v2_C", -+ "dcdc_id": "DCDC33", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 9900, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_2v23_C", -+ "dcdc_id": "DCDC34", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 2200, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_1v2_V", -+ "dcdc_id": "DCDC35", -+ "Min": 960, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 1440, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_2v23_V", -+ "dcdc_id": "DCDC36", -+ "Min": 1784, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 2676, -+ "format": "float(float(%s)/1000)", -+ }, -+ ], -+ "cpu": [ -+ { -+ "name": "cpu", -+ "reboot_cause_path": "/etc/sonic/.reboot/.previous-reboot-cause.txt" -+ } -+ ], -+ "sfps": { -+ "ver": '1.0', -+ "port_index_start": 1, -+ "port_num": 56, -+ "log_level": 2, -+ "eeprom_retry_times": 5, -+ "eeprom_retry_break_sec": 0.2, -+ "presence_cpld": { -+ "dev_id": { -+ 3: { -+ "offset": { -+ 0x30: "1-8", -+ 0x31: "9-16", -+ 0x32: "17-24", -+ }, -+ }, -+ 4: { -+ "offset": { -+ 0x30: "25-32", -+ 0x31: "33-40", -+ 0x32: "41-48", -+ 0x33: "49-56", -+ }, -+ }, -+ }, -+ }, -+ "presence_val_is_present": 0, -+ "eeprom_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/eeprom", -+ "eeprom_path_key": list(range(32, 88)), -+ "optoe_driver_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/dev_class", -+ "optoe_driver_key": list(range(32, 88)), -+ "txdis_cpld": { -+ "dev_id": { -+ 3: { -+ "offset": { -+ 0x60: "1-8", -+ 0x61: "9-16", -+ 0x62: "17-24", -+ }, -+ }, -+ 4: { -+ "offset": { -+ 0x60: "25-32", -+ 0x61: "33-40", -+ 0x62: "41-48", -+ }, -+ }, -+ }, -+ }, -+ "txdisable_val_is_on": 1, -+ "reset_cpld": { -+ "dev_id": { -+ 4: { -+ "offset": { -+ 0xb9: "49-56", -+ }, -+ }, -+ }, -+ }, -+ "reset_val_is_reset": 0, -+ } -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_exhaust_device.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_exhaust_device.py -new file mode 100755 -index 000000000..c2b857975 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_exhaust_device.py -@@ -0,0 +1,1371 @@ -+#!/usr/bin/python3 -+ -+psu_fan_airflow = { -+ "intake": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3', 'U1D-D10800-DRB'], -+ "exhaust": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'] -+} -+ -+fanairflow = { -+ "intake": ['M1HFAN III-F'], -+ "exhaust": ['M1HFAN III-R'], -+} -+ -+psu_display_name = { -+ "PA550II-F": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3'], -+ "PA550II-R": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'], -+ "PD800I-F": ['U1D-D10800-DRB'] -+} -+ -+psutypedecode = { -+ 0x00: 'N/A', -+ 0x01: 'AC', -+ 0x02: 'DC', -+} -+ -+ -+class Unit: -+ Temperature = "C" -+ Voltage = "V" -+ Current = "A" -+ Power = "W" -+ Speed = "RPM" -+ -+ -+PSU_NOT_PRESENT_PWM = 100 -+ -+ -+class threshold: -+ PSU_TEMP_MIN = -20 * 1000 -+ PSU_TEMP_MAX = 60 * 1000 -+ -+ PSU_FAN_SPEED_MIN = 2000 -+ PSU_FAN_SPEED_MAX = 18000 -+ -+ PSU_OUTPUT_VOLTAGE_MIN = 11 * 1000 -+ PSU_OUTPUT_VOLTAGE_MAX = 14 * 1000 -+ -+ PSU_AC_INPUT_VOLTAGE_MIN = 200 * 1000 -+ PSU_AC_INPUT_VOLTAGE_MAX = 240 * 1000 -+ -+ PSU_DC_INPUT_VOLTAGE_MIN = 190 * 1000 -+ PSU_DC_INPUT_VOLTAGE_MAX = 290 * 1000 -+ -+ ERR_VALUE = -9999999 -+ -+ PSU_OUTPUT_POWER_MIN = 10 * 1000 * 1000 -+ PSU_OUTPUT_POWER_MAX = 560 * 1000 * 1000 -+ -+ PSU_INPUT_POWER_MIN = 10 * 1000 * 1000 -+ PSU_INPUT_POWER_MAX = 625 * 1000 * 1000 -+ -+ PSU_OUTPUT_CURRENT_MIN = 1 * 1000 -+ PSU_OUTPUT_CURRENT_MAX = 45 * 1000 -+ -+ PSU_INPUT_CURRENT_MIN = 0 * 1000 -+ PSU_INPUT_CURRENT_MAX = 7 * 1000 -+ -+ FRONT_FAN_SPEED_MAX = 24000 -+ REAR_FAN_SPEED_MAX = 22500 -+ FAN_SPEED_MIN = 5000 -+ -+ -+ ASPOWER_DC_PSU_TEMP_MIN = -10 * 1000 -+ ASPOWER_DC_PSU_TEMP_MAX = 55 * 1000 -+ -+ ASPOWER_DC_PSU_FAN_SPEED_MIN = 800 -+ ASPOWER_DC_PSU_FAN_SPEED_MAX = 24000 -+ -+ ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN = 11.4 * 1000 -+ ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX = 12.6 * 1000 -+ -+ ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN = 36 * 1000 -+ ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX = 72 * 1000 -+ -+ ASPOWER_DC_ERR_VALUE = -9999999 -+ -+ ASPOWER_DC_PSU_OUTPUT_POWER_MIN = 5 * 1000 * 1000 -+ ASPOWER_DC_PSU_OUTPUT_POWER_MAX = 800 * 1000 * 1000 -+ -+ ASPOWER_DC_PSU_INPUT_POWER_MIN = 5 * 1000 * 1000 -+ ASPOWER_DC_PSU_INPUT_POWER_MAX = 880 * 1000 * 1000 -+ -+ ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN = 0.5 * 1000 -+ ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX = 66 * 1000 -+ -+ ASPOWER_DC_PSU_INPUT_CURRENT_MIN = 1 * 1000 -+ ASPOWER_DC_PSU_INPUT_CURRENT_MAX = 28 * 1000 -+ -+ -+class Description: -+ CPLD = "Used for managing IO modules, SFP+ modules and system LEDs" -+ BIOS = "Performs initialization of hardware components during booting" -+ FPGA = "Platform management controller for on-board temperature monitoring, in-chassis power" -+ -+ -+devices = { -+ "onie_e2": [ -+ { -+ "name": "ONIE_E2", -+ "e2loc": {"loc": "/sys/bus/i2c/devices/0-0056/eeprom", "way": "sysfs"}, -+ "airflow": "exhaust" -+ }, -+ ], -+ "psus": [ -+ { -+ "e2loc": {"loc": "/sys/bus/i2c/devices/24-0050/eeprom", "way": "sysfs"}, -+ "pmbusloc": {"bus": 24, "addr": 0x58, "way": "i2c"}, -+ "present": {"loc": "/sys/wb_plat/psu/psu1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, -+ "name": "PSU1", -+ "get_threshold_by_model": 1, -+ "psu_display_name": psu_display_name, -+ "airflow": psu_fan_airflow, -+ "TempStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, -+ "other": threshold.PSU_TEMP_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, -+ "other": threshold.PSU_TEMP_MAX, -+ }, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ }, -+ "FanStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, -+ "FanSpeed": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, -+ "other": threshold.PSU_FAN_SPEED_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, -+ "other": threshold.PSU_FAN_SPEED_MAX, -+ }, -+ "Unit": Unit.Speed -+ }, -+ "psu_fan_tolerance": 40, -+ "InputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, -+ "InputsType": {"bus": 24, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, -+ "InputsVoltage": { -+ 'AC': { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, -+ "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, -+ "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ -+ }, -+ 'DC': { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, -+ "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, -+ "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, -+ }, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ }, -+ 'other': { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, -+ "other": threshold.ERR_VALUE, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, -+ "other": threshold.ERR_VALUE, -+ }, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ "InputsCurrent": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, -+ "other": threshold.PSU_INPUT_CURRENT_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, -+ "other": threshold.PSU_INPUT_CURRENT_MAX, -+ }, -+ "Unit": Unit.Current, -+ "format": "float(float(%s)/1000)" -+ }, -+ "InputsPower": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, -+ "other": threshold.PSU_INPUT_POWER_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, -+ "other": threshold.PSU_INPUT_POWER_MAX, -+ }, -+ "Unit": Unit.Power, -+ "format": "float(float(%s)/1000000)" -+ }, -+ "OutputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, -+ "OutputsVoltage": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, -+ "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, -+ "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, -+ }, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ }, -+ "OutputsCurrent": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, -+ "other": threshold.PSU_OUTPUT_CURRENT_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, -+ "other": threshold.PSU_OUTPUT_CURRENT_MAX, -+ }, -+ "Unit": Unit.Current, -+ "format": "float(float(%s)/1000)" -+ }, -+ "OutputsPower": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, -+ "other": threshold.PSU_OUTPUT_POWER_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, -+ "other": threshold.PSU_OUTPUT_POWER_MAX, -+ }, -+ "Unit": Unit.Power, -+ "format": "float(float(%s)/1000000)" -+ }, -+ }, -+ { -+ "e2loc": {"loc": "/sys/bus/i2c/devices/25-0050/eeprom", "way": "sysfs"}, -+ "pmbusloc": {"bus": 25, "addr": 0x58, "way": "i2c"}, -+ "present": {"loc": "/sys/wb_plat/psu/psu2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, -+ "name": "PSU2", -+ "get_threshold_by_model": 1, -+ "psu_display_name": psu_display_name, -+ "airflow": psu_fan_airflow, -+ "TempStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, -+ "other": threshold.PSU_TEMP_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, -+ "other": threshold.PSU_TEMP_MAX, -+ }, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ }, -+ "FanStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, -+ "FanSpeed": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, -+ "other": threshold.PSU_FAN_SPEED_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, -+ "other": threshold.PSU_FAN_SPEED_MAX, -+ }, -+ "Unit": Unit.Speed -+ }, -+ "psu_fan_tolerance": 40, -+ "InputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, -+ "InputsType": {"bus": 25, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, -+ "InputsVoltage": { -+ 'AC': { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, -+ "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, -+ "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ -+ }, -+ 'DC': { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, -+ "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, -+ "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, -+ }, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ }, -+ 'other': { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, -+ "other": threshold.ERR_VALUE, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, -+ "other": threshold.ERR_VALUE, -+ }, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ "InputsCurrent": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, -+ "other": threshold.PSU_INPUT_CURRENT_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, -+ "other": threshold.PSU_INPUT_CURRENT_MAX, -+ }, -+ "Unit": Unit.Current, -+ "format": "float(float(%s)/1000)" -+ }, -+ "InputsPower": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, -+ "other": threshold.PSU_INPUT_POWER_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, -+ "other": threshold.PSU_INPUT_POWER_MAX, -+ }, -+ "Unit": Unit.Power, -+ "format": "float(float(%s)/1000000)" -+ }, -+ "OutputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, -+ "OutputsVoltage": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, -+ "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, -+ "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, -+ }, -+ "Unit": Unit.Voltage, -+ "format": "float(float(%s)/1000)" -+ }, -+ "OutputsCurrent": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, -+ "other": threshold.PSU_OUTPUT_CURRENT_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, -+ "other": threshold.PSU_OUTPUT_CURRENT_MAX, -+ }, -+ "Unit": Unit.Current, -+ "format": "float(float(%s)/1000)" -+ }, -+ "OutputsPower": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, -+ "Min": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, -+ "other": threshold.PSU_OUTPUT_POWER_MIN, -+ }, -+ "Max": { -+ "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, -+ "other": threshold.PSU_OUTPUT_POWER_MAX, -+ }, -+ "Unit": Unit.Power, -+ "format": "float(float(%s)/1000000)" -+ }, -+ } -+ ], -+ "temps": [ -+ { -+ "name": "SWITCH_TEMP", -+ "temp_id": "TEMP1", -+ "api_name": "ASIC_TEMP", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/3-0044/hwmon/hwmon*/temp99_input", "way": "sysfs"}, -+ "Min": -30000, -+ "Low": 0, -+ "High": 105000, -+ "Max": 110000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ { -+ "name": "CPU_TEMP", -+ "temp_id": "TEMP2", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/platform/devices/coretemp.0/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": -15000, -+ "Low": 0, -+ "High": 100000, -+ "Max": 102000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ { -+ "name": "INLET_TEMP", -+ "temp_id": "TEMP3", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/3-004c/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": -30000, -+ "Low": 0, -+ "High": 55000, -+ "Max": 60000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ }, -+ "fix_value": { -+ "fix_type": "config", -+ "addend": -3, -+ } -+ }, -+ { -+ "name": "OUTLET_TEMP", -+ "temp_id": "TEMP4", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/3-0048/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": -30000, -+ "Low": 0, -+ "High": 75000, -+ "Max": 80000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ { -+ "name": "BOARD_TEMP", -+ "temp_id": "TEMP5", -+ "api_name": "MAC_OUT_TEMP", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/3-0049/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": -30000, -+ "Low": 0, -+ "High": 75000, -+ "Max": 80000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ { -+ "name": "MAC_IN_TEMP", -+ "temp_id": "TEMP6", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/3-004a/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": -30000, -+ "Low": 0, -+ "High": 75000, -+ "Max": 80000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ { -+ "name": "PSU1_TEMP", -+ "temp_id": "TEMP7", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": -20000, -+ "Low": 0, -+ "High": 55000, -+ "Max": 60000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ { -+ "name": "PSU2_TEMP", -+ "temp_id": "TEMP8", -+ "Temperature": { -+ "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, -+ "Min": -20000, -+ "Low": 0, -+ "High": 55000, -+ "Max": 60000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ } -+ }, -+ { -+ "name": "SFF_TEMP", -+ "Temperature": { -+ "value": {"loc": "/tmp/highest_sff_temp", "way": "sysfs", "flock_path": "/tmp/highest_sff_temp"}, -+ "Min": -30000, -+ "Low": 0, -+ "High": 90000, -+ "Max": 100000, -+ "Unit": Unit.Temperature, -+ "format": "float(float(%s)/1000)" -+ }, -+ "invalid": -10000, -+ "error": -9999, -+ } -+ ], -+ "leds": [ -+ { -+ "name": "FRONT_SYS_LED", -+ "led_type": "SYS_LED", -+ "led": {"bus": 6, "addr": 0x0d, "offset": 0x72, "way": "i2c"}, -+ "led_attrs": { -+ "off": 0x00, "red_flash": 0x01, "red": 0x02, -+ "green_flash": 0x03, "green": 0x04, "amber_flash": 0x05, -+ "amber": 0x06, "mask": 0x07 -+ }, -+ }, -+ { -+ "name": "FRONT_PSU_LED", -+ "led_type": "PSU_LED", -+ "led": {"bus": 6, "addr": 0x0d, "offset": 0x73, "way": "i2c"}, -+ "led_attrs": { -+ "off": 0x10, "red_flash": 0x11, "red": 0x12, -+ "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, -+ "amber": 0x16, "mask": 0x17 -+ }, -+ }, -+ { -+ "name": "FRONT_FAN_LED", -+ "led_type": "FAN_LED", -+ "led": {"bus": 6, "addr": 0x0d, "offset": 0x74, "way": "i2c"}, -+ "led_attrs": { -+ "off": 0x10, "red_flash": 0x11, "red": 0x12, -+ "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, -+ "amber": 0x16, "mask": 0x17 -+ }, -+ }, -+ ], -+ "fans": [ -+ { -+ "name": "FAN1", -+ "airflow": fanairflow, -+ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-16/16-0050/eeprom', 'way': 'sysfs'}, -+ "present": {"loc": "/sys/wb_plat/fan/fan1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3b, "way": "i2c"}, -+ "led_attrs": { -+ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, -+ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, -+ "amber": 0x03, "mask": 0x0f -+ }, -+ "PowerMax": 38.4, -+ "Rotor": { -+ "Rotor1_config": { -+ "name": "Rotor1", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan1/motor1/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.FRONT_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ "Rotor2_config": { -+ "name": "Rotor2", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan1/motor0/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.REAR_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ }, -+ }, -+ { -+ "name": "FAN2", -+ "airflow": fanairflow, -+ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-17/17-0050/eeprom', 'way': 'sysfs'}, -+ "present": {"loc": "/sys/wb_plat/fan/fan2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3c, "way": "i2c"}, -+ "led_attrs": { -+ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, -+ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, -+ "amber": 0x03, "mask": 0x0f -+ }, -+ "PowerMax": 38.4, -+ "Rotor": { -+ "Rotor1_config": { -+ "name": "Rotor1", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan2/motor1/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.FRONT_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ "Rotor2_config": { -+ "name": "Rotor2", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan2/motor0/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.REAR_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ }, -+ }, -+ { -+ "name": "FAN3", -+ "airflow": fanairflow, -+ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-18/18-0050/eeprom', 'way': 'sysfs'}, -+ "present": {"loc": "/sys/wb_plat/fan/fan3/present", "way": "sysfs", "mask": 0x01, "okval": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3d, "way": "i2c"}, -+ "led_attrs": { -+ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, -+ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, -+ "amber": 0x03, "mask": 0x0f -+ }, -+ "PowerMax": 38.4, -+ "Rotor": { -+ "Rotor1_config": { -+ "name": "Rotor1", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan3/motor1/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.FRONT_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ "Rotor2_config": { -+ "name": "Rotor2", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan3/motor0/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.REAR_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ }, -+ }, -+ -+ { -+ "name": "FAN4", -+ "airflow": fanairflow, -+ "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-19/19-0050/eeprom', 'way': 'sysfs'}, -+ "present": {"loc": "/sys/wb_plat/fan/fan4/present", "way": "sysfs", "mask": 0x01, "okval": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "led": {"bus": 2, "addr": 0x0d, "offset": 0x3e, "way": "i2c"}, -+ "led_attrs": { -+ "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, -+ "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, -+ "amber": 0x03, "mask": 0x0f -+ }, -+ "PowerMax": 38.4, -+ "Rotor": { -+ "Rotor1_config": { -+ "name": "Rotor1", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan4/motor1/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.FRONT_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ "Rotor2_config": { -+ "name": "Rotor2", -+ "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, -+ "Running": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, -+ "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, -+ "SpeedMin": threshold.FAN_SPEED_MIN, -+ "SpeedMax": threshold.REAR_FAN_SPEED_MAX, -+ "Speed": { -+ "value": {"loc": "/sys/wb_plat/fan/fan4/motor0/speed", "way": "sysfs"}, -+ "Min": threshold.FAN_SPEED_MIN, -+ "Max": threshold.REAR_FAN_SPEED_MAX, -+ "Unit": Unit.Speed, -+ }, -+ }, -+ }, -+ }, -+ -+ ], -+ "cplds": [ -+ { -+ "name": "CPU_CPLD", -+ "cpld_id": "CPLD1", -+ "VersionFile": {"loc": "/dev/cpld0", "offset": 0, "len": 4, "way": "devfile_ascii"}, -+ "desc": "Used for system power", -+ "slot": 0, -+ "warm": 0, -+ }, -+ { -+ "name": "CONNECT_CPLD", -+ "cpld_id": "CPLD2", -+ "VersionFile": {"loc": "/dev/cpld1", "offset": 0, "len": 4, "way": "devfile_ascii"}, -+ "desc": "Used for base functions", -+ "slot": 0, -+ "warm": 0, -+ }, -+ { -+ "name": "CONNECT_CPLD-FAN", -+ "cpld_id": "CPLD3", -+ "VersionFile": {"loc": "/dev/cpld2", "offset": 0, "len": 4, "way": "devfile_ascii"}, -+ "desc": "Used for fan modules", -+ "slot": 0, -+ "warm": 0, -+ }, -+ { -+ "name": "MAC_CPLD1", -+ "cpld_id": "CPLD4", -+ "VersionFile": {"loc": "/dev/cpld3", "offset": 0, "len": 4, "way": "devfile_ascii"}, -+ "desc": "Used for sff modules", -+ "slot": 0, -+ "warm": 0, -+ }, -+ { -+ "name": "MAC_CPLD2", -+ "cpld_id": "CPLD5", -+ "VersionFile": {"loc": "/dev/cpld4", "offset": 0, "len": 4, "way": "devfile_ascii"}, -+ "desc": "Used for sff modules", -+ "slot": 0, -+ "warm": 0, -+ }, -+ { -+ "name": "FPGA", -+ "cpld_id": "CPLD6", -+ "VersionFile": {"loc": "/dev/fpga0", "offset": 0, "len": 4, "way": "devfile_ascii"}, -+ "desc": "Used for base functions", -+ "slot": 0, -+ "format": "little_endian", -+ "warm": 0, -+ }, -+ { -+ "name": "BIOS", -+ "cpld_id": "CPLD7", -+ "VersionFile": {"cmd": "dmidecode -s bios-version", "way": "cmd"}, -+ "desc": "Performs initialization of hardware components during booting", -+ "slot": 0, -+ "type": "str", -+ "warm": 0, -+ }, -+ ], -+ "dcdc": [ -+ { -+ "name": "Switch_ZSFP1_3v3_C", -+ "dcdc_id": "DCDC1", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 22000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_QSFP1_3v3_C", -+ "dcdc_id": "DCDC2", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 22000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_5v0_C", -+ "dcdc_id": "DCDC3", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 1000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_ZSFP1_3v3_V", -+ "dcdc_id": "DCDC4", -+ "Min": 2640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 3960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_QSFP1_3v3_V", -+ "dcdc_id": "DCDC5", -+ "Min": 2640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 3960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_5v0_V", -+ "dcdc_id": "DCDC6", -+ "Min": 4000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 6000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_1v2_C", -+ "dcdc_id": "DCDC7", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 2000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_3v3_C", -+ "dcdc_id": "DCDC8", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 1000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_Cpld_3v3_C", -+ "dcdc_id": "DCDC9", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 2000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_1v2_V", -+ "dcdc_id": "DCDC10", -+ "Min": 960, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 1440, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_3v3_V", -+ "dcdc_id": "DCDC11", -+ "Min": 2640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 3960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_Cpld_3v3_V", -+ "dcdc_id": "DCDC12", -+ "Min": 2640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 3960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Con_1v2_C", -+ "dcdc_id": "DCDC13", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 1300, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Con_3v3_C", -+ "dcdc_id": "DCDC14", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 2800, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Con_SSD_3v3_C", -+ "dcdc_id": "DCDC15", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 4500, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Con_1v2_V", -+ "dcdc_id": "DCDC16", -+ "Min": 960, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 1440, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Con_3v3_V", -+ "dcdc_id": "DCDC17", -+ "Min": 2640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 3960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Con_SSD_3v3_V", -+ "dcdc_id": "DCDC18", -+ "Min": 2640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 3960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_3v3_C", -+ "dcdc_id": "DCDC19", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 4686, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_5v_C", -+ "dcdc_id": "DCDC20", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 2200, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_1v7_C", -+ "dcdc_id": "DCDC21", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 2200, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_3v3_V", -+ "dcdc_id": "DCDC22", -+ "Min": 2640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 3960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_5v_V", -+ "dcdc_id": "DCDC23", -+ "Min": 4000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 6000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_1v7_V", -+ "dcdc_id": "DCDC24", -+ "Min": 1360, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 2040, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_CORE_C", -+ "dcdc_id": "DCDC25", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 47300, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_1v05_C", -+ "dcdc_id": "DCDC26", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 15400, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_CORE_V", -+ "dcdc_id": "DCDC27", -+ "Min": 1456, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 2184, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_1v05_V", -+ "dcdc_id": "DCDC28", -+ "Min": 840, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 1260, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_CORE_C", -+ "dcdc_id": "DCDC29", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 220000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_ANALOG_C", -+ "dcdc_id": "DCDC30", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 18000, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_CORE_V", -+ "dcdc_id": "DCDC31", -+ "Min": 600, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 1200, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Switch_ANALOG_V", -+ "dcdc_id": "DCDC32", -+ "Min": 640, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 960, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_1v2_C", -+ "dcdc_id": "DCDC33", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr1_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 9900, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_2v23_C", -+ "dcdc_id": "DCDC34", -+ "Min": -1000, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "A", -+ "Max": 2200, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_1v2_V", -+ "dcdc_id": "DCDC35", -+ "Min": 960, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in2_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 1440, -+ "format": "float(float(%s)/1000)", -+ }, -+ -+ { -+ "name": "Cpu_2v23_V", -+ "dcdc_id": "DCDC36", -+ "Min": 1784, -+ "value": { -+ "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in3_input", -+ "way": "sysfs", -+ }, -+ "read_times": 5, -+ "Unit": "V", -+ "Max": 2676, -+ "format": "float(float(%s)/1000)", -+ }, -+ ], -+ "cpu": [ -+ { -+ "name": "cpu", -+ "reboot_cause_path": "/etc/sonic/.reboot/.previous-reboot-cause.txt" -+ } -+ ], -+ "sfps": { -+ "ver": '1.0', -+ "port_index_start": 1, -+ "port_num": 56, -+ "log_level": 2, -+ "eeprom_retry_times": 5, -+ "eeprom_retry_break_sec": 0.2, -+ "presence_cpld": { -+ "dev_id": { -+ 3: { -+ "offset": { -+ 0x30: "1-8", -+ 0x31: "9-16", -+ 0x32: "17-24", -+ }, -+ }, -+ 4: { -+ "offset": { -+ 0x30: "25-32", -+ 0x31: "33-40", -+ 0x32: "41-48", -+ 0x33: "49-56", -+ }, -+ }, -+ }, -+ }, -+ "presence_val_is_present": 0, -+ "eeprom_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/eeprom", -+ "eeprom_path_key": list(range(32, 88)), -+ "optoe_driver_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/dev_class", -+ "optoe_driver_key": list(range(32, 88)), -+ "txdis_cpld": { -+ "dev_id": { -+ 3: { -+ "offset": { -+ 0x60: "1-8", -+ 0x61: "9-16", -+ 0x62: "17-24", -+ }, -+ }, -+ 4: { -+ "offset": { -+ 0x60: "25-32", -+ 0x61: "33-40", -+ 0x62: "41-48", -+ }, -+ }, -+ }, -+ }, -+ "txdisable_val_is_on": 0, -+ "reset_cpld": { -+ "dev_id": { -+ 4: { -+ "offset": { -+ 0xb9: "49-56", -+ }, -+ }, -+ }, -+ }, -+ "reset_val_is_reset": 0, -+ } -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_monitor.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_monitor.py -new file mode 100755 -index 000000000..aab279a21 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_monitor.py -@@ -0,0 +1,206 @@ -+# coding:utf-8 -+ -+ -+monitor = { -+ "openloop": { -+ "linear": { -+ "name": "linear", -+ "flag": 0, -+ "pwm_min": 0x80, -+ "pwm_max": 0xff, -+ "K": 11, -+ "tin_min": 38, -+ }, -+ "curve": { -+ "name": "curve", -+ "flag": 0, -+ "pwm_min": 0x5a, -+ "pwm_max": 0xff, -+ "a": 0.086, -+ "b": 0.318, -+ "c": 28, -+ "tin_min": 25, -+ }, -+ }, -+ -+ "pid": { -+ "CPU_TEMP": { -+ "name": "CPU_TEMP", -+ "flag": 1, -+ "type": "duty", -+ "pwm_min": 0x80, -+ "pwm_max": 0xff, -+ "Kp": 3, -+ "Ki": 0.5, -+ "Kd": 0.5, -+ "target": 89, -+ "value": [None, None, None], -+ }, -+ "SWITCH_TEMP": { -+ "name": "SWITCH_TEMP", -+ "flag": 1, -+ "type": "duty", -+ "pwm_min": 0x80, -+ "pwm_max": 0xff, -+ "Kp": 3, -+ "Ki": 0.4, -+ "Kd": 0.4, -+ "target": 82, -+ "value": [None, None, None], -+ }, -+ "OUTLET_TEMP": { -+ "name": "OUTLET_TEMP", -+ "flag": 0, -+ "type": "duty", -+ "pwm_min": 0x80, -+ "pwm_max": 0xff, -+ "Kp": 2, -+ "Ki": 0.4, -+ "Kd": 0.3, -+ "target": 65, -+ "value": [None, None, None], -+ }, -+ "BOARD_TEMP": { -+ "name": "BOARD_TEMP", -+ "flag": 0, -+ "type": "duty", -+ "pwm_min": 0x80, -+ "pwm_max": 0xff, -+ "Kp": 2, -+ "Ki": 0.4, -+ "Kd": 0.3, -+ "target": 65, -+ "value": [None, None, None], -+ }, -+ "SFF_TEMP": { -+ "name": "SFF_TEMP", -+ "flag": 1, -+ "type": "duty", -+ "pwm_min": 0x80, -+ "pwm_max": 0xff, -+ "Kp": 0.1, -+ "Ki": 0.4, -+ "Kd": 0, -+ "target": 60, -+ "value": [None, None, None], -+ }, -+ }, -+ -+ "hyst": { -+ "INLET_TEMP": { -+ "name": "INLET_TEMP", -+ "flag": 1, -+ "type": "duty", -+ "hyst_min": 50, # duty -+ "hyst_max": 100, # duty -+ "last_hyst_value": 50, # duty -+ "temp_min": 23, -+ "temp_max": 40, -+ "value": [None, None], -+ "rising": { -+ 23: 50, -+ 24: 50, -+ 25: 50, -+ 26: 53, -+ 27: 56, -+ 28: 59, -+ 29: 62, -+ 30: 65, -+ 31: 68, -+ 32: 71, -+ 33: 74, -+ 34: 77, -+ 35: 80, -+ 36: 84, -+ 37: 88, -+ 38: 92, -+ 39: 96, -+ 40: 100, -+ }, -+ "descending": { -+ 23: 50, -+ 24: 53, -+ 25: 56, -+ 26: 59, -+ 27: 62, -+ 28: 65, -+ 29: 68, -+ 30: 71, -+ 31: 74, -+ 32: 77, -+ 33: 80, -+ 34: 84, -+ 35: 88, -+ 36: 92, -+ 37: 96, -+ 38: 100, -+ 39: 100, -+ 40: 100, -+ }, -+ } -+ }, -+ -+ "temps_threshold": { -+ "SWITCH_TEMP": {"name": "SWITCH_TEMP", "warning": 100, "critical": 105}, -+ "INLET_TEMP": {"name": "INLET_TEMP", "warning": 40, "critical": 50}, -+ "BOARD_TEMP": {"name": "BOARD_TEMP", "warning": 70, "critical": 80}, -+ "OUTLET_TEMP": {"name": "OUTLET_TEMP", "warning": 70, "critical": 80}, -+ "CPU_TEMP": {"name": "CPU_TEMP", "warning": 100, "critical": 102}, -+ "SFF_TEMP": {"name": "SFF_TEMP", "warning": 999, "critical": 1000, "ignore_threshold": 1, "invalid": -10000, "error": -9999}, -+ }, -+ -+ "fancontrol_para": { -+ "interval": 5, -+ "fan_air_flow_monitor": 1, -+ "psu_air_flow_monitor": 1, -+ "max_pwm": 0xff, -+ "min_pwm": 0x80, -+ "abnormal_pwm": 0xff, -+ "warning_pwm": 0xff, -+ "temp_invalid_pid_pwm": 0x80, -+ "temp_error_pid_pwm": 0x80, -+ "temp_fail_num": 3, -+ "check_temp_fail": [ -+ {"temp_name": "INLET_TEMP"}, -+ {"temp_name": "SWITCH_TEMP"}, -+ {"temp_name": "CPU_TEMP"}, -+ ], -+ "temp_warning_num": 3, # temp over warning 3 times continuously -+ "temp_critical_num": 3, # temp over critical 3 times continuously -+ "temp_warning_countdown": 60, # 5 min warning speed after not warning -+ "temp_critical_countdown": 60, # 5 min full speed after not critical -+ "rotor_error_count": 6, # fan rotor error 6 times continuously -+ "inlet_mac_diff": 999, -+ "check_crit_reboot_flag": 1, -+ "check_crit_reboot_num": 3, -+ "check_crit_sleep_time": 20, -+ "psu_absent_fullspeed_num": 0xFF, -+ "fan_absent_fullspeed_num": 1, -+ "rotor_error_fullspeed_num": 1, -+ }, -+ -+ "ledcontrol_para": { -+ "interval": 5, -+ "checkpsu": 0, # 0: sys led don't follow psu led -+ "checkfan": 0, # 0: sys led don't follow fan led -+ "psu_amber_num": 1, -+ "fan_amber_num": 1, -+ "board_sys_led": [ -+ {"led_name": "FRONT_SYS_LED"}, -+ ], -+ "board_psu_led": [ -+ {"led_name": "FRONT_PSU_LED"}, -+ ], -+ "board_fan_led": [ -+ {"led_name": "FRONT_FAN_LED"}, -+ ], -+ "psu_air_flow_monitor": 1, -+ "fan_air_flow_monitor": 1, -+ "psu_air_flow_amber_num": 1, -+ "fan_air_flow_amber_num": 1, -+ }, -+ "otp_reboot_judge_file": { -+ "otp_switch_reboot_judge_file": "/etc/.otp_switch_reboot_flag", -+ "otp_other_reboot_judge_file": "/etc/.otp_other_reboot_flag", -+ }, -+} -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/Makefile b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/Makefile -new file mode 100755 -index 000000000..2e9c25ae6 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/Makefile -@@ -0,0 +1,12 @@ -+MAKEFILE_FILE_PATH = $(abspath $(lastword $(MAKEFILE_LIST))) -+MODULES_DIR = $(abspath $(MAKEFILE_FILE_PATH)/../../../../common/modules) -+ -+EXTRA_CFLAGS+= -I$(MODULES_DIR) -+EXTRA_CFLAGS+= -I$(MODULES_DIR)/linux-5.10 -+ -+obj-m := wb_pcie_dev_device.o -+obj-m += wb_i2c_mux_pca954x_device.o -+obj-m += wb_i2c_ocores_device.o -+obj-m += wb_lpc_drv_device.o -+obj-m += wb_i2c_dev_device.o -+obj-m += wb_io_dev_device.o -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_dev_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_dev_device.c -new file mode 100644 -index 000000000..865e7afea ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_dev_device.c -@@ -0,0 +1,140 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+static int g_wb_i2c_dev_device_debug = 0; -+static int g_wb_i2c_dev_device_error = 0; -+ -+module_param(g_wb_i2c_dev_device_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_i2c_dev_device_error, int, S_IRUGO | S_IWUSR); -+ -+#define WB_I2C_DEV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ -+ if (g_wb_i2c_dev_device_debug) { \ -+ printk(KERN_INFO "[WB_I2C_DEV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_I2C_DEV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_wb_i2c_dev_device_error) { \ -+ printk(KERN_ERR "[WB_I2C_DEV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static i2c_dev_device_t i2c_dev_device_data0 = { -+ .i2c_bus = 2, -+ .i2c_addr = 0x0d, -+ .i2c_name = "cpld2", -+ .data_bus_width = 1, -+ .addr_bus_width = 1, -+ .per_rd_len = 256, -+ .per_wr_len = 256, -+ .i2c_len = 256, -+}; -+ -+static i2c_dev_device_t i2c_dev_device_data1 = { -+ .i2c_bus = 8, -+ .i2c_addr = 0x30, -+ .i2c_name = "cpld3", -+ .data_bus_width = 1, -+ .addr_bus_width = 1, -+ .per_rd_len = 256, -+ .per_wr_len = 256, -+ .i2c_len = 256, -+}; -+ -+static i2c_dev_device_t i2c_dev_device_data2 = { -+ .i2c_bus = 8, -+ .i2c_addr = 0x31, -+ .i2c_name = "cpld4", -+ .data_bus_width = 1, -+ .addr_bus_width = 1, -+ .per_rd_len = 256, -+ .per_wr_len = 256, -+ .i2c_len = 256, -+}; -+ -+static i2c_dev_device_t i2c_dev_device_data3 = { -+ .i2c_bus = 6, -+ .i2c_addr = 0x0d, -+ .i2c_name = "cpld5", -+ .data_bus_width = 1, -+ .addr_bus_width = 1, -+ .per_rd_len = 256, -+ .per_wr_len = 256, -+ .i2c_len = 256, -+}; -+ -+struct i2c_board_info i2c_dev_device_info[] = { -+ { -+ .type = "wb-i2c-dev", -+ .platform_data = &i2c_dev_device_data0, -+ }, -+ { -+ .type = "wb-i2c-dev", -+ .platform_data = &i2c_dev_device_data1, -+ }, -+ { -+ .type = "wb-i2c-dev", -+ .platform_data = &i2c_dev_device_data2, -+ }, -+ { -+ .type = "wb-i2c-dev", -+ .platform_data = &i2c_dev_device_data3, -+ }, -+}; -+ -+static int __init wb_i2c_dev_device_init(void) -+{ -+ int i; -+ struct i2c_adapter *adap; -+ struct i2c_client *client; -+ i2c_dev_device_t *i2c_dev_device_data; -+ -+ WB_I2C_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); -+ for (i = 0; i < ARRAY_SIZE(i2c_dev_device_info); i++) { -+ i2c_dev_device_data = i2c_dev_device_info[i].platform_data; -+ i2c_dev_device_info[i].addr = i2c_dev_device_data->i2c_addr; -+ adap = i2c_get_adapter(i2c_dev_device_data->i2c_bus); -+ if (adap == NULL) { -+ i2c_dev_device_data->client = NULL; -+ printk(KERN_ERR "get i2c bus %d adapter fail.\n", i2c_dev_device_data->i2c_bus); -+ continue; -+ } -+ client = i2c_new_client_device(adap, &i2c_dev_device_info[i]); -+ if (!client) { -+ i2c_dev_device_data->client = NULL; -+ printk(KERN_ERR "Failed to register i2c dev device %d at bus %d!\n", -+ i2c_dev_device_data->i2c_addr, i2c_dev_device_data->i2c_bus); -+ } else { -+ i2c_dev_device_data->client = client; -+ } -+ i2c_put_adapter(adap); -+ } -+ return 0; -+} -+ -+static void __exit wb_i2c_dev_device_exit(void) -+{ -+ int i; -+ i2c_dev_device_t *i2c_dev_device_data; -+ -+ WB_I2C_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); -+ for (i = ARRAY_SIZE(i2c_dev_device_info) - 1; i >= 0; i--) { -+ i2c_dev_device_data = i2c_dev_device_info[i].platform_data; -+ if (i2c_dev_device_data->client) { -+ i2c_unregister_device(i2c_dev_device_data->client); -+ i2c_dev_device_data->client = NULL; -+ } -+ } -+} -+ -+module_init(wb_i2c_dev_device_init); -+module_exit(wb_i2c_dev_device_exit); -+MODULE_DESCRIPTION("I2C DEV Devices"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_mux_pca954x_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_mux_pca954x_device.c -new file mode 100644 -index 000000000..f12a71013 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_mux_pca954x_device.c -@@ -0,0 +1,296 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+static int g_wb_i2c_mux_pca954x_device_debug = 0; -+static int g_wb_i2c_mux_pca954x_device_error = 0; -+ -+module_param(g_wb_i2c_mux_pca954x_device_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_i2c_mux_pca954x_device_error, int, S_IRUGO | S_IWUSR); -+ -+#define WB_I2C_MUX_PCA954X_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ -+ if (g_wb_i2c_mux_pca954x_device_debug) { \ -+ printk(KERN_INFO "[WB_I2C_MUX_PCA954X_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_I2C_MUX_PCA954X_DEVICE_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_wb_i2c_mux_pca954x_device_error) { \ -+ printk(KERN_ERR "[WB_I2C_MUX_PCA954X_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data0 = { -+ .i2c_bus = 2, -+ .i2c_addr = 0x77, -+ .probe_disable = 1, -+ .select_chan_check = 0, -+ .close_chan_force_reset = 0, -+ .pca9548_base_nr = 16, -+ .pca9548_reset_type = PCA9548_RESET_FILE, -+ .rst_delay_b = 0, -+ .rst_delay = 1000, -+ .rst_delay_a = 1000, -+ .attr = { -+ .file_attr.dev_name = "/dev/cpld5", -+ .file_attr.offset = 0x60, -+ .file_attr.mask = 0x02, -+ .file_attr.reset_on = 0x00, -+ .file_attr.reset_off = 0x02, -+ }, -+}; -+ -+static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data1 = { -+ .i2c_bus = 4, -+ .i2c_addr = 0x77, -+ .probe_disable = 1, -+ .select_chan_check = 0, -+ .close_chan_force_reset = 0, -+ .pca9548_base_nr = 24, -+ .pca9548_reset_type = PCA9548_RESET_FILE, -+ .rst_delay_b = 0, -+ .rst_delay = 1000, -+ .rst_delay_a = 1000, -+ .attr = { -+ .file_attr.dev_name = "/dev/cpld5", -+ .file_attr.offset = 0x60, -+ .file_attr.mask = 0x01, -+ .file_attr.reset_on = 0x00, -+ .file_attr.reset_off = 0x01, -+ }, -+}; -+ -+static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data2 = { -+ .i2c_bus = 12, -+ .i2c_addr = 0x70, -+ .probe_disable = 1, -+ .select_chan_check = 0, -+ .close_chan_force_reset = 0, -+ .pca9548_base_nr = 32, -+ .pca9548_reset_type = PCA9548_RESET_FILE, -+ .rst_delay_b = 0, -+ .rst_delay = 1000, -+ .rst_delay_a = 1000, -+ .attr = { -+ .file_attr.dev_name = "/dev/fpga0", -+ .file_attr.offset = 0x20, -+ .file_attr.mask = 0x01, -+ .file_attr.reset_on = 0x00, -+ .file_attr.reset_off = 0x01, -+ }, -+}; -+ -+static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data3 = { -+ .i2c_bus = 12, -+ .i2c_addr = 0x71, -+ .probe_disable = 1, -+ .select_chan_check = 0, -+ .close_chan_force_reset = 0, -+ .pca9548_base_nr = 40, -+ .pca9548_reset_type = PCA9548_RESET_FILE, -+ .rst_delay_b = 0, -+ .rst_delay = 1000, -+ .rst_delay_a = 1000, -+ .attr = { -+ .file_attr.dev_name = "/dev/fpga0", -+ .file_attr.offset = 0x20, -+ .file_attr.mask = 0x01, -+ .file_attr.reset_on = 0x00, -+ .file_attr.reset_off = 0x01, -+ }, -+}; -+ -+static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data4 = { -+ .i2c_bus = 12, -+ .i2c_addr = 0x72, -+ .probe_disable = 1, -+ .select_chan_check = 0, -+ .close_chan_force_reset = 0, -+ .pca9548_base_nr = 48, -+ .pca9548_reset_type = PCA9548_RESET_FILE, -+ .rst_delay_b = 0, -+ .rst_delay = 1000, -+ .rst_delay_a = 1000, -+ .attr = { -+ .file_attr.dev_name = "/dev/fpga0", -+ .file_attr.offset = 0x20, -+ .file_attr.mask = 0x01, -+ .file_attr.reset_on = 0x00, -+ .file_attr.reset_off = 0x01, -+ }, -+}; -+ -+static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data5 = { -+ .i2c_bus = 12, -+ .i2c_addr = 0x73, -+ .probe_disable = 1, -+ .select_chan_check = 0, -+ .close_chan_force_reset = 0, -+ .pca9548_base_nr = 56, -+ .pca9548_reset_type = PCA9548_RESET_FILE, -+ .rst_delay_b = 0, -+ .rst_delay = 1000, -+ .rst_delay_a = 1000, -+ .attr = { -+ .file_attr.dev_name = "/dev/fpga0", -+ .file_attr.offset = 0x20, -+ .file_attr.mask = 0x01, -+ .file_attr.reset_on = 0x00, -+ .file_attr.reset_off = 0x01, -+ }, -+}; -+ -+static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data6 = { -+ .i2c_bus = 13, -+ .i2c_addr = 0x70, -+ .probe_disable = 1, -+ .select_chan_check = 0, -+ .close_chan_force_reset = 0, -+ .pca9548_base_nr = 64, -+ .pca9548_reset_type = PCA9548_RESET_FILE, -+ .rst_delay_b = 0, -+ .rst_delay = 1000, -+ .rst_delay_a = 1000, -+ .attr = { -+ .file_attr.dev_name = "/dev/fpga0", -+ .file_attr.offset = 0x20, -+ .file_attr.mask = 0x01, -+ .file_attr.reset_on = 0x00, -+ .file_attr.reset_off = 0x01, -+ }, -+}; -+ -+static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data7 = { -+ .i2c_bus = 13, -+ .i2c_addr = 0x71, -+ .probe_disable = 1, -+ .select_chan_check = 0, -+ .close_chan_force_reset = 0, -+ .pca9548_base_nr = 72, -+ .pca9548_reset_type = PCA9548_RESET_FILE, -+ .rst_delay_b = 0, -+ .rst_delay = 1000, -+ .rst_delay_a = 1000, -+ .attr = { -+ .file_attr.dev_name = "/dev/fpga0", -+ .file_attr.offset = 0x20, -+ .file_attr.mask = 0x01, -+ .file_attr.reset_on = 0x00, -+ .file_attr.reset_off = 0x01, -+ }, -+}; -+ -+static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data8 = { -+ .i2c_bus = 13, -+ .i2c_addr = 0x72, -+ .probe_disable = 1, -+ .select_chan_check = 0, -+ .close_chan_force_reset = 0, -+ .pca9548_base_nr = 80, -+ .pca9548_reset_type = PCA9548_RESET_FILE, -+ .rst_delay_b = 0, -+ .rst_delay = 1000, -+ .rst_delay_a = 1000, -+ .attr = { -+ .file_attr.dev_name = "/dev/fpga0", -+ .file_attr.offset = 0x20, -+ .file_attr.mask = 0x01, -+ .file_attr.reset_on = 0x00, -+ .file_attr.reset_off = 0x01, -+ }, -+}; -+ -+struct i2c_board_info i2c_mux_pca954x_device_info[] = { -+ { -+ .type = "wb_pca9548", -+ .platform_data = &i2c_mux_pca954x_device_data0, -+ }, -+ { -+ .type = "wb_pca9548", -+ .platform_data = &i2c_mux_pca954x_device_data1, -+ }, -+ { -+ .type = "wb_pca9548", -+ .platform_data = &i2c_mux_pca954x_device_data2, -+ }, -+ { -+ .type = "wb_pca9548", -+ .platform_data = &i2c_mux_pca954x_device_data3, -+ }, -+ { -+ .type = "wb_pca9548", -+ .platform_data = &i2c_mux_pca954x_device_data4, -+ }, -+ { -+ .type = "wb_pca9548", -+ .platform_data = &i2c_mux_pca954x_device_data5, -+ }, -+ { -+ .type = "wb_pca9548", -+ .platform_data = &i2c_mux_pca954x_device_data6, -+ }, -+ { -+ .type = "wb_pca9548", -+ .platform_data = &i2c_mux_pca954x_device_data7, -+ }, -+ { -+ .type = "wb_pca9548", -+ .platform_data = &i2c_mux_pca954x_device_data8, -+ }, -+}; -+ -+static int __init wb_i2c_mux_pca954x_device_init(void) -+{ -+ int i; -+ struct i2c_adapter *adap; -+ struct i2c_client *client; -+ i2c_mux_pca954x_device_t *i2c_mux_pca954x_device_data; -+ -+ WB_I2C_MUX_PCA954X_DEVICE_DEBUG_VERBOSE("enter!\n"); -+ for (i = 0; i < ARRAY_SIZE(i2c_mux_pca954x_device_info); i++) { -+ i2c_mux_pca954x_device_data = i2c_mux_pca954x_device_info[i].platform_data; -+ i2c_mux_pca954x_device_info[i].addr = i2c_mux_pca954x_device_data->i2c_addr; -+ adap = i2c_get_adapter(i2c_mux_pca954x_device_data->i2c_bus); -+ if (adap == NULL) { -+ i2c_mux_pca954x_device_data->client = NULL; -+ printk(KERN_ERR "get i2c bus %d adapter fail.\n", i2c_mux_pca954x_device_data->i2c_bus); -+ continue; -+ } -+ client = i2c_new_client_device(adap, &i2c_mux_pca954x_device_info[i]); -+ if (!client) { -+ i2c_mux_pca954x_device_data->client = NULL; -+ printk(KERN_ERR "Failed to register pca954x device %d at bus %d!\n", -+ i2c_mux_pca954x_device_data->i2c_addr, i2c_mux_pca954x_device_data->i2c_bus); -+ } else { -+ i2c_mux_pca954x_device_data->client = client; -+ } -+ i2c_put_adapter(adap); -+ } -+ return 0; -+} -+ -+static void __exit wb_i2c_mux_pca954x_device_exit(void) -+{ -+ int i; -+ i2c_mux_pca954x_device_t *i2c_mux_pca954x_device_data; -+ -+ WB_I2C_MUX_PCA954X_DEVICE_DEBUG_VERBOSE("enter!\n"); -+ for (i = ARRAY_SIZE(i2c_mux_pca954x_device_info) - 1; i >= 0; i--) { -+ i2c_mux_pca954x_device_data = i2c_mux_pca954x_device_info[i].platform_data; -+ if (i2c_mux_pca954x_device_data->client) { -+ i2c_unregister_device(i2c_mux_pca954x_device_data->client); -+ i2c_mux_pca954x_device_data->client = NULL; -+ } -+ } -+} -+ -+module_init(wb_i2c_mux_pca954x_device_init); -+module_exit(wb_i2c_mux_pca954x_device_exit); -+MODULE_DESCRIPTION("I2C MUX PCA954X Devices"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_ocores_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_ocores_device.c -new file mode 100644 -index 000000000..ff7ba9d26 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_ocores_device.c -@@ -0,0 +1,423 @@ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+static int g_wb_i2c_ocores_device_debug = 0; -+static int g_wb_i2c_ocores_device_error = 0; -+ -+module_param(g_wb_i2c_ocores_device_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_i2c_ocores_device_error, int, S_IRUGO | S_IWUSR); -+ -+#define WB_I2C_OCORE_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ -+ if (g_wb_i2c_ocores_device_debug) { \ -+ printk(KERN_INFO "[WB_I2C_OCORE_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_I2C_OCORE_DEVICE_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_wb_i2c_ocores_device_error) { \ -+ printk(KERN_ERR "[WB_I2C_OCORE_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static i2c_ocores_device_t i2c_ocores_device_data0 = { -+ .adap_nr = 2, -+ .big_endian = 0, -+ .dev_name = "/dev/fpga0", -+ .reg_access_mode = 3, -+ .dev_base = 0x0800, -+ .reg_shift = 2, -+ .reg_io_width = 4, -+ .ip_clock_khz = 125000, -+ .bus_clock_khz = 100, -+ .irq_offset = 0, -+ .pci_domain = 0, -+ .pci_bus = 8, -+ .pci_slot = 0, -+ .pci_fn = 0, -+}; -+ -+static i2c_ocores_device_t i2c_ocores_device_data1 = { -+ .adap_nr = 3, -+ .big_endian = 0, -+ .dev_name = "/dev/fpga0", -+ .reg_access_mode = 3, -+ .dev_base = 0x0820, -+ .reg_shift = 2, -+ .reg_io_width = 4, -+ .ip_clock_khz = 125000, -+ .bus_clock_khz = 100, -+ .irq_offset = 1, -+ .pci_domain = 0, -+ .pci_bus = 8, -+ .pci_slot = 0, -+ .pci_fn = 0, -+}; -+ -+static i2c_ocores_device_t i2c_ocores_device_data2 = { -+ .adap_nr = 4, -+ .big_endian = 0, -+ .dev_name = "/dev/fpga0", -+ .reg_access_mode = 3, -+ .dev_base = 0x0840, -+ .reg_shift = 2, -+ .reg_io_width = 4, -+ .ip_clock_khz = 125000, -+ .bus_clock_khz = 100, -+ .irq_offset = 2, -+ .pci_domain = 0, -+ .pci_bus = 8, -+ .pci_slot = 0, -+ .pci_fn = 0, -+}; -+ -+static i2c_ocores_device_t i2c_ocores_device_data3 = { -+ .adap_nr = 5, -+ .big_endian = 0, -+ .dev_name = "/dev/fpga0", -+ .reg_access_mode = 3, -+ .dev_base = 0x0860, -+ .reg_shift = 2, -+ .reg_io_width = 4, -+ .ip_clock_khz = 125000, -+ .bus_clock_khz = 100, -+ .irq_offset = 3, -+ .pci_domain = 0, -+ .pci_bus = 8, -+ .pci_slot = 0, -+ .pci_fn = 0, -+}; -+ -+static i2c_ocores_device_t i2c_ocores_device_data4 = { -+ .adap_nr = 6, -+ .big_endian = 0, -+ .dev_name = "/dev/fpga0", -+ .reg_access_mode = 3, -+ .dev_base = 0x0880, -+ .reg_shift = 2, -+ .reg_io_width = 4, -+ .ip_clock_khz = 125000, -+ .bus_clock_khz = 100, -+ .irq_offset = 4, -+ .pci_domain = 0, -+ .pci_bus = 8, -+ .pci_slot = 0, -+ .pci_fn = 0, -+}; -+ -+static i2c_ocores_device_t i2c_ocores_device_data5 = { -+ .adap_nr = 7, -+ .big_endian = 0, -+ .dev_name = "/dev/fpga0", -+ .reg_access_mode = 3, -+ .dev_base = 0x08a0, -+ .reg_shift = 2, -+ .reg_io_width = 4, -+ .ip_clock_khz = 125000, -+ .bus_clock_khz = 100, -+ .irq_offset = 5, -+ .pci_domain = 0, -+ .pci_bus = 8, -+ .pci_slot = 0, -+ .pci_fn = 0, -+}; -+ -+static i2c_ocores_device_t i2c_ocores_device_data6 = { -+ .adap_nr = 8, -+ .big_endian = 0, -+ .dev_name = "/dev/fpga0", -+ .reg_access_mode = 3, -+ .dev_base = 0x08c0, -+ .reg_shift = 2, -+ .reg_io_width = 4, -+ .ip_clock_khz = 125000, -+ .bus_clock_khz = 100, -+ .irq_offset = 6, -+ .pci_domain = 0, -+ .pci_bus = 8, -+ .pci_slot = 0, -+ .pci_fn = 0, -+}; -+ -+static i2c_ocores_device_t i2c_ocores_device_data7 = { -+ .adap_nr = 9, -+ .big_endian = 0, -+ .dev_name = "/dev/fpga0", -+ .reg_access_mode = 3, -+ .dev_base = 0x08e0, -+ .reg_shift = 2, -+ .reg_io_width = 4, -+ .ip_clock_khz = 125000, -+ .bus_clock_khz = 100, -+ .irq_offset = 7, -+ .pci_domain = 0, -+ .pci_bus = 8, -+ .pci_slot = 0, -+ .pci_fn = 0, -+}; -+ -+static i2c_ocores_device_t i2c_ocores_device_data8 = { -+ .adap_nr = 10, -+ .big_endian = 0, -+ .dev_name = "/dev/fpga0", -+ .reg_access_mode = 3, -+ .dev_base = 0x0900, -+ .reg_shift = 2, -+ .reg_io_width = 4, -+ .ip_clock_khz = 125000, -+ .bus_clock_khz = 100, -+ .irq_offset = 8, -+ .pci_domain = 0, -+ .pci_bus = 8, -+ .pci_slot = 0, -+ .pci_fn = 0, -+}; -+ -+static i2c_ocores_device_t i2c_ocores_device_data9 = { -+ .adap_nr = 11, -+ .big_endian = 0, -+ .dev_name = "/dev/fpga0", -+ .reg_access_mode = 3, -+ .dev_base = 0x0920, -+ .reg_shift = 2, -+ .reg_io_width = 4, -+ .ip_clock_khz = 125000, -+ .bus_clock_khz = 100, -+ .irq_offset = 9, -+ .pci_domain = 0, -+ .pci_bus = 8, -+ .pci_slot = 0, -+ .pci_fn = 0, -+}; -+ -+static i2c_ocores_device_t i2c_ocores_device_data10 = { -+ .adap_nr = 12, -+ .big_endian = 0, -+ .dev_name = "/dev/fpga0", -+ .reg_access_mode = 3, -+ .dev_base = 0x0940, -+ .reg_shift = 2, -+ .reg_io_width = 4, -+ .ip_clock_khz = 125000, -+ .bus_clock_khz = 100, -+ .irq_offset = 10, -+ .pci_domain = 0, -+ .pci_bus = 8, -+ .pci_slot = 0, -+ .pci_fn = 0, -+}; -+ -+static i2c_ocores_device_t i2c_ocores_device_data11 = { -+ .adap_nr = 13, -+ .big_endian = 0, -+ .dev_name = "/dev/fpga0", -+ .reg_access_mode = 3, -+ .dev_base = 0x0960, -+ .reg_shift = 2, -+ .reg_io_width = 4, -+ .ip_clock_khz = 125000, -+ .bus_clock_khz = 100, -+ .irq_offset = 11, -+ .pci_domain = 0, -+ .pci_bus = 8, -+ .pci_slot = 0, -+ .pci_fn = 0, -+}; -+ -+static i2c_ocores_device_t i2c_ocores_device_data12 = { -+ .adap_nr = 14, -+ .big_endian = 0, -+ .dev_name = "/dev/fpga0", -+ .reg_access_mode = 3, -+ .dev_base = 0x0980, -+ .reg_shift = 2, -+ .reg_io_width = 4, -+ .ip_clock_khz = 125000, -+ .bus_clock_khz = 100, -+ .irq_offset = 12, -+ .pci_domain = 0, -+ .pci_bus = 8, -+ .pci_slot = 0, -+ .pci_fn = 0, -+}; -+ -+static i2c_ocores_device_t i2c_ocores_device_data13 = { -+ .adap_nr = 15, -+ .big_endian = 0, -+ .dev_name = "/dev/fpga0", -+ .reg_access_mode = 3, -+ .dev_base = 0x09a0, -+ .reg_shift = 2, -+ .reg_io_width = 4, -+ .ip_clock_khz = 125000, -+ .bus_clock_khz = 100, -+ .irq_offset = 13, -+ .pci_domain = 0, -+ .pci_bus = 8, -+ .pci_slot = 0, -+ .pci_fn = 0, -+}; -+ -+static void wb_i2c_ocores_device_release(struct device *dev) -+{ -+ return; -+} -+ -+static struct platform_device i2c_ocores_device[] = { -+ { -+ .name = "wb-ocores-i2c", -+ .id = 1, -+ .dev = { -+ .platform_data = &i2c_ocores_device_data0, -+ .release = wb_i2c_ocores_device_release, -+ }, -+ }, -+ { -+ .name = "wb-ocores-i2c", -+ .id = 2, -+ .dev = { -+ .platform_data = &i2c_ocores_device_data1, -+ .release = wb_i2c_ocores_device_release, -+ }, -+ }, -+ { -+ .name = "wb-ocores-i2c", -+ .id = 3, -+ .dev = { -+ .platform_data = &i2c_ocores_device_data2, -+ .release = wb_i2c_ocores_device_release, -+ }, -+ }, -+ { -+ .name = "wb-ocores-i2c", -+ .id = 4, -+ .dev = { -+ .platform_data = &i2c_ocores_device_data3, -+ .release = wb_i2c_ocores_device_release, -+ }, -+ }, -+ { -+ .name = "wb-ocores-i2c", -+ .id = 5, -+ .dev = { -+ .platform_data = &i2c_ocores_device_data4, -+ .release = wb_i2c_ocores_device_release, -+ }, -+ }, -+ { -+ .name = "wb-ocores-i2c", -+ .id = 6, -+ .dev = { -+ .platform_data = &i2c_ocores_device_data5, -+ .release = wb_i2c_ocores_device_release, -+ }, -+ }, -+ { -+ .name = "wb-ocores-i2c", -+ .id = 7, -+ .dev = { -+ .platform_data = &i2c_ocores_device_data6, -+ .release = wb_i2c_ocores_device_release, -+ }, -+ }, -+ { -+ .name = "wb-ocores-i2c", -+ .id = 8, -+ .dev = { -+ .platform_data = &i2c_ocores_device_data7, -+ .release = wb_i2c_ocores_device_release, -+ }, -+ }, -+ { -+ .name = "wb-ocores-i2c", -+ .id = 9, -+ .dev = { -+ .platform_data = &i2c_ocores_device_data8, -+ .release = wb_i2c_ocores_device_release, -+ }, -+ }, -+ { -+ .name = "wb-ocores-i2c", -+ .id = 10, -+ .dev = { -+ .platform_data = &i2c_ocores_device_data9, -+ .release = wb_i2c_ocores_device_release, -+ }, -+ }, -+ { -+ .name = "wb-ocores-i2c", -+ .id = 11, -+ .dev = { -+ .platform_data = &i2c_ocores_device_data10, -+ .release = wb_i2c_ocores_device_release, -+ }, -+ }, -+ { -+ .name = "wb-ocores-i2c", -+ .id = 12, -+ .dev = { -+ .platform_data = &i2c_ocores_device_data11, -+ .release = wb_i2c_ocores_device_release, -+ }, -+ }, -+ { -+ .name = "wb-ocores-i2c", -+ .id = 13, -+ .dev = { -+ .platform_data = &i2c_ocores_device_data12, -+ .release = wb_i2c_ocores_device_release, -+ }, -+ }, -+ { -+ .name = "wb-ocores-i2c", -+ .id = 14, -+ .dev = { -+ .platform_data = &i2c_ocores_device_data13, -+ .release = wb_i2c_ocores_device_release, -+ }, -+ }, -+}; -+ -+static int __init wb_i2c_ocores_device_init(void) -+{ -+ int i; -+ int ret = 0; -+ i2c_ocores_device_t *i2c_ocores_device_data; -+ -+ WB_I2C_OCORE_DEVICE_DEBUG_VERBOSE("enter!\n"); -+ for (i = 0; i < ARRAY_SIZE(i2c_ocores_device); i++) { -+ i2c_ocores_device_data = i2c_ocores_device[i].dev.platform_data; -+ ret = platform_device_register(&i2c_ocores_device[i]); -+ if (ret < 0) { -+ i2c_ocores_device_data->device_flag = -1; /* device register failed, set flag -1 */ -+ printk(KERN_ERR "wb-ocores-i2c.%d register failed!\n", i + 1); -+ } else { -+ i2c_ocores_device_data->device_flag = 0; /* device register suucess, set flag 0 */ -+ } -+ } -+ return 0; -+} -+ -+static void __exit wb_i2c_ocores_device_exit(void) -+{ -+ int i; -+ i2c_ocores_device_t *i2c_ocores_device_data; -+ -+ WB_I2C_OCORE_DEVICE_DEBUG_VERBOSE("enter!\n"); -+ for (i = ARRAY_SIZE(i2c_ocores_device) - 1; i >= 0; i--) { -+ i2c_ocores_device_data = i2c_ocores_device[i].dev.platform_data; -+ if (i2c_ocores_device_data->device_flag == 0) { /* device register success, need unregister */ -+ platform_device_unregister(&i2c_ocores_device[i]); -+ } -+ } -+} -+ -+module_init(wb_i2c_ocores_device_init); -+module_exit(wb_i2c_ocores_device_exit); -+MODULE_DESCRIPTION("I2C OCORES Devices"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_io_dev_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_io_dev_device.c -new file mode 100644 -index 000000000..cc84938ff ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_io_dev_device.c -@@ -0,0 +1,103 @@ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+static int g_wb_io_dev_device_debug = 0; -+static int g_wb_io_dev_device_error = 0; -+ -+module_param(g_wb_io_dev_device_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_io_dev_device_error, int, S_IRUGO | S_IWUSR); -+ -+#define WB_IO_DEV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ -+ if (g_wb_io_dev_device_debug) { \ -+ printk(KERN_INFO "[WB_IO_DEV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_IO_DEV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_wb_io_dev_device_error) { \ -+ printk(KERN_ERR "[WB_IO_DEV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static io_dev_device_t io_dev_device_data0 = { -+ .io_dev_name = "cpld0", -+ .io_base = 0x700, -+ .io_len = 0x100, -+ .indirect_addr = 0, -+}; -+ -+static io_dev_device_t io_dev_device_data1 = { -+ .io_dev_name = "cpld1", -+ .io_base = 0x900, -+ .io_len = 0x100, -+ .indirect_addr = 0, -+}; -+ -+static void wb_io_dev_device_release(struct device *dev) -+{ -+ return; -+} -+ -+static struct platform_device io_dev_device[] = { -+ { -+ .name = "wb-io-dev", -+ .id = 1, -+ .dev = { -+ .platform_data = &io_dev_device_data0, -+ .release = wb_io_dev_device_release, -+ }, -+ }, -+ { -+ .name = "wb-io-dev", -+ .id = 2, -+ .dev = { -+ .platform_data = &io_dev_device_data1, -+ .release = wb_io_dev_device_release, -+ }, -+ }, -+}; -+ -+static int __init wb_io_dev_device_init(void) -+{ -+ int i; -+ int ret = 0; -+ io_dev_device_t *io_dev_device_data; -+ -+ WB_IO_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); -+ for (i = 0; i < ARRAY_SIZE(io_dev_device); i++) { -+ io_dev_device_data = io_dev_device[i].dev.platform_data; -+ ret = platform_device_register(&io_dev_device[i]); -+ if (ret < 0) { -+ io_dev_device_data->device_flag = -1; /* device register failed, set flag -1 */ -+ printk(KERN_ERR "wb-io-dev.%d register failed!\n", i + 1); -+ } else { -+ io_dev_device_data->device_flag = 0; /* device register suucess, set flag 0 */ -+ } -+ } -+ return 0; -+} -+ -+static void __exit wb_io_dev_device_exit(void) -+{ -+ int i; -+ io_dev_device_t *io_dev_device_data; -+ -+ WB_IO_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); -+ for (i = ARRAY_SIZE(io_dev_device) - 1; i >= 0; i--) { -+ io_dev_device_data = io_dev_device[i].dev.platform_data; -+ if (io_dev_device_data->device_flag == 0) { /* device register success, need unregister */ -+ platform_device_unregister(&io_dev_device[i]); -+ } -+ } -+} -+ -+module_init(wb_io_dev_device_init); -+module_exit(wb_io_dev_device_exit); -+MODULE_DESCRIPTION("IO DEV Devices"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_lpc_drv_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_lpc_drv_device.c -new file mode 100644 -index 000000000..9b6b61a51 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_lpc_drv_device.c -@@ -0,0 +1,130 @@ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+static int g_wb_lpc_drv_device_debug = 0; -+static int g_wb_lpc_drv_device_error = 0; -+ -+module_param(g_wb_lpc_drv_device_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_lpc_drv_device_error, int, S_IRUGO | S_IWUSR); -+ -+#define WB_LPC_DRV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ -+ if (g_wb_lpc_drv_device_debug) { \ -+ printk(KERN_INFO "[WB_LPC_DRV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_LPC_DRV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_wb_lpc_drv_device_error) { \ -+ printk(KERN_ERR "[WB_LPC_DRV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static lpc_drv_device_t lpc_drv_device_data_0 = { -+ .lpc_io_name = "wb_lpc", -+ .pci_domain = 0x0000, -+ .pci_bus = 0x00, -+ .pci_slot = 0x1f, -+ .pci_fn = 0, -+ .lpc_io_base = 0x700, -+ .lpc_io_size = 0x100, -+ .lpc_gen_dec = 0x84, -+}; -+ -+static lpc_drv_device_t lpc_drv_device_data_1 = { -+ .lpc_io_name = "wb_lpc", -+ .pci_domain = 0x0000, -+ .pci_bus = 0x00, -+ .pci_slot = 0x1f, -+ .pci_fn = 0, -+ .lpc_io_base = 0x900, -+ .lpc_io_size = 0x100, -+ .lpc_gen_dec = 0x88, -+}; -+ -+static lpc_drv_device_t lpc_drv_device_data_2 = { -+ .lpc_io_name = "wb_lpc", -+ .pci_domain = 0x0000, -+ .pci_bus = 0x00, -+ .pci_slot = 0x1f, -+ .pci_fn = 0, -+ .lpc_io_base = 0xb00, -+ .lpc_io_size = 0x100, -+ .lpc_gen_dec = 0x90, -+}; -+ -+static void wb_lpc_drv_device_release(struct device *dev) -+{ -+ return; -+} -+ -+static struct platform_device lpc_drv_device[] = { -+ { -+ .name = "wb-lpc", -+ .id = 1, -+ .dev = { -+ .platform_data = &lpc_drv_device_data_0, -+ .release = wb_lpc_drv_device_release, -+ }, -+ }, -+ { -+ .name = "wb-lpc", -+ .id = 2, -+ .dev = { -+ .platform_data = &lpc_drv_device_data_1, -+ .release = wb_lpc_drv_device_release, -+ }, -+ }, -+ { -+ .name = "wb-lpc", -+ .id = 3, -+ .dev = { -+ .platform_data = &lpc_drv_device_data_2, -+ .release = wb_lpc_drv_device_release, -+ }, -+ }, -+}; -+ -+static int __init wb_lpc_drv_device_init(void) -+{ -+ int i; -+ int ret = 0; -+ lpc_drv_device_t *lpc_drv_device_data; -+ -+ WB_LPC_DRV_DEVICE_DEBUG_VERBOSE("enter!\n"); -+ for (i = 0; i < ARRAY_SIZE(lpc_drv_device); i++) { -+ lpc_drv_device_data = lpc_drv_device[i].dev.platform_data; -+ ret = platform_device_register(&lpc_drv_device[i]); -+ if (ret < 0) { -+ lpc_drv_device_data->device_flag = -1; /* device register failed, set flag -1 */ -+ printk(KERN_ERR "wb-lpc.%d register failed!\n", i + 1); -+ } else { -+ lpc_drv_device_data->device_flag = 0; /* device register suucess, set flag 0 */ -+ } -+ } -+ return 0; -+} -+ -+static void __exit wb_lpc_drv_device_exit(void) -+{ -+ int i; -+ lpc_drv_device_t *lpc_drv_device_data; -+ -+ WB_LPC_DRV_DEVICE_DEBUG_VERBOSE("enter!\n"); -+ for (i = ARRAY_SIZE(lpc_drv_device) - 1; i >= 0; i--) { -+ lpc_drv_device_data = lpc_drv_device[i].dev.platform_data; -+ if (lpc_drv_device_data->device_flag == 0) { /* device register success, need unregister */ -+ platform_device_unregister(&lpc_drv_device[i]); -+ } -+ } -+} -+ -+module_init(wb_lpc_drv_device_init); -+module_exit(wb_lpc_drv_device_exit); -+MODULE_DESCRIPTION("LPC DRV Devices"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_pcie_dev_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_pcie_dev_device.c -new file mode 100644 -index 000000000..f79b29770 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_pcie_dev_device.c -@@ -0,0 +1,93 @@ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+static int g_wb_pcie_dev_device_debug = 0; -+static int g_wb_pcie_dev_device_error = 0; -+ -+module_param(g_wb_pcie_dev_device_debug, int, S_IRUGO | S_IWUSR); -+module_param(g_wb_pcie_dev_device_error, int, S_IRUGO | S_IWUSR); -+ -+#define WB_PCIE_DEV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ -+ if (g_wb_pcie_dev_device_debug) { \ -+ printk(KERN_INFO "[WB_PCIE_DEV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+#define WB_PCIE_DEV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ -+ if (g_wb_pcie_dev_device_error) { \ -+ printk(KERN_ERR "[WB_PCIE_DEV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ -+ } \ -+} while (0) -+ -+static pci_dev_device_t pcie_dev_device_data0 = { -+ .pci_dev_name = "fpga0", -+ .pci_domain = 0x0000, -+ .pci_bus = 0x08, -+ .pci_slot = 0x00, -+ .pci_fn = 0, -+ .pci_bar = 0, -+ .bus_width = 4, -+ .upg_ctrl_base = 0xa00, -+ .upg_flash_base = 0x1a0000, -+}; -+ -+static void wb_pcie_dev_device_release(struct device *dev) -+{ -+ return; -+} -+ -+static struct platform_device pcie_dev_device[] = { -+ { -+ .name = "wb-pci-dev", -+ .id = 1, -+ .dev = { -+ .platform_data = &pcie_dev_device_data0, -+ .release = wb_pcie_dev_device_release, -+ }, -+ }, -+}; -+ -+static int __init wb_pcie_dev_device_init(void) -+{ -+ int i; -+ int ret = 0; -+ pci_dev_device_t *pcie_dev_device_data; -+ -+ WB_PCIE_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); -+ for (i = 0; i < ARRAY_SIZE(pcie_dev_device); i++) { -+ pcie_dev_device_data = pcie_dev_device[i].dev.platform_data; -+ ret = platform_device_register(&pcie_dev_device[i]); -+ if (ret < 0) { -+ pcie_dev_device_data->device_flag = -1; /* device register failed, set flag -1 */ -+ printk(KERN_ERR "wb-pci-dev.%d register failed!\n", i + 1); -+ } else { -+ pcie_dev_device_data->device_flag = 0; /* device register suucess, set flag 0 */ -+ } -+ } -+ return 0; -+} -+ -+static void __exit wb_pcie_dev_device_exit(void) -+{ -+ int i; -+ pci_dev_device_t *pcie_dev_device_data; -+ -+ WB_PCIE_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); -+ for (i = ARRAY_SIZE(pcie_dev_device) - 1; i >= 0; i--) { -+ pcie_dev_device_data = pcie_dev_device[i].dev.platform_data; -+ if (pcie_dev_device_data->device_flag == 0) { /* device register success, need unregister */ -+ platform_device_unregister(&pcie_dev_device[i]); -+ } -+ } -+} -+ -+module_init(wb_pcie_dev_device_init); -+module_exit(wb_pcie_dev_device_exit); -+MODULE_DESCRIPTION("PCIE DEV Devices"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("support"); -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_CPLD.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_CPLD.cfg -new file mode 100644 -index 000000000..98d1da175 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_CPLD.cfg -@@ -0,0 +1,41 @@ -+# configuration item: I2C address of CPLD -+# format: cpld_i2c_dev.bus_[cpld_slot]_[cpld_id] cpld_i2c_dev.addr_[cpld_slot]_[cpld_id] -+# cpld_slot: Main card: 0, linear card: start from 1 -+# cpld_id: start from 0 -+# bus: I2C bus number of CPLD -+# addr: I2C address of CPLD -+cpld_i2c_dev.bus_0_2=2 -+cpld_i2c_dev.addr_0_2=0x0d -+cpld_i2c_dev.bus_0_3=8 -+cpld_i2c_dev.addr_0_3=0x30 -+cpld_i2c_dev.bus_0_4=8 -+cpld_i2c_dev.addr_0_4=0x31 -+cpld_i2c_dev.bus_0_5=6 -+cpld_i2c_dev.addr_0_5=0x0d -+ -+ -+# configuration item: LPC address of CPLD -+# format: cpld_lpc_addr_[cpld_slot]_[cpld_id] -+# cpld_slot: Main card: 0, linear card: start from 1 -+# cpld_id: start from 0 -+cpld_lpc_dev_0_0=0x700 -+cpld_lpc_dev_0_1=0x900 -+ -+ -+# configuration item: CPLD access method, lpc or i2c -+# format: mode_cpld_[cpld_slot][cpld_slot]=lpc/i2c -+# cpld_slot: Main card: 0, linear card: start from 1 -+# cpld_id: start from 0 -+mode_cpld_0_0=lpc -+mode_cpld_0_1=lpc -+mode_cpld_0_2=i2c -+mode_cpld_0_3=i2c -+mode_cpld_0_4=i2c -+mode_cpld_0_5=i2c -+ -+ -+# configuration item: the number of CPLD -+# format: dev_num_[main_dev]_[minor_dev] -+# main_dev: CPLD main_dev is 4 -+# minor_dev: CPLD minor_dev not exist -+dev_num_4_0=6 -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_FAN.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_FAN.cfg -new file mode 100644 -index 000000000..2350b74eb ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_FAN.cfg -@@ -0,0 +1,304 @@ -+# configuration item: the number of fans -+# format: dev_num_[main_dev]_[minor_dev] -+# main_dev: fan main_dev is 1 -+# minor_dev: fan minor_dev not exist(0) -+dev_num_1_0=4 -+ -+ -+# configuration item: the number of rotors -+# format: dev_num_[main_dev]_[minor_dev] -+# main_dev: rotor main_dev is 1 -+# minor_dev: rotor minor_dev is 5 -+dev_num_1_5=2 -+ -+ -+# configuration item: fan presence status -+# format: dev_present_status_[main_dev_id][fan_index] -+# main_dev_id: fan main_dev_id is 1 -+# fan_index: start from 1 -+dev_present_status.mode_1_1=config -+dev_present_status.src_1_1=cpld -+dev_present_status.frmt_1_1=bit -+dev_present_status.pola_1_1=negative -+dev_present_status.addr_1_1=0x00020030 -+dev_present_status.len_1_1=1 -+dev_present_status.bit_offset_1_1=0 -+ -+dev_present_status.mode_1_2=config -+dev_present_status.src_1_2=cpld -+dev_present_status.frmt_1_2=bit -+dev_present_status.pola_1_2=negative -+dev_present_status.addr_1_2=0x00020030 -+dev_present_status.len_1_2=1 -+dev_present_status.bit_offset_1_2=1 -+ -+dev_present_status.mode_1_3=config -+dev_present_status.src_1_3=cpld -+dev_present_status.frmt_1_3=bit -+dev_present_status.pola_1_3=negative -+dev_present_status.addr_1_3=0x00020030 -+dev_present_status.len_1_3=1 -+dev_present_status.bit_offset_1_3=2 -+ -+dev_present_status.mode_1_4=config -+dev_present_status.src_1_4=cpld -+dev_present_status.frmt_1_4=bit -+dev_present_status.pola_1_4=negative -+dev_present_status.addr_1_4=0x00020030 -+dev_present_status.len_1_4=1 -+dev_present_status.bit_offset_1_4=3 -+ -+ -+# configuration item: fan rotor status -+# format: fan_roll_status_[fan_id]_[motor_id] -+# fan_id: start from 1 -+# motor_id: start from 0 -+fan_roll_status.mode_1_0=config -+fan_roll_status.int_cons_1_0= -+fan_roll_status.src_1_0=cpld -+fan_roll_status.frmt_1_0=bit -+fan_roll_status.pola_1_0=positive -+fan_roll_status.fpath_1_0= -+fan_roll_status.addr_1_0=0x00020031 -+fan_roll_status.len_1_0=1 -+fan_roll_status.bit_offset_1_0=0 -+ -+fan_roll_status.mode_1_1=config -+fan_roll_status.int_cons_1_1= -+fan_roll_status.src_1_1=cpld -+fan_roll_status.frmt_1_1=bit -+fan_roll_status.pola_1_1=positive -+fan_roll_status.fpath_1_1= -+fan_roll_status.addr_1_1=0x00020034 -+fan_roll_status.len_1_1=1 -+fan_roll_status.bit_offset_1_1=0 -+ -+fan_roll_status.mode_2_0=config -+fan_roll_status.int_cons_2_0= -+fan_roll_status.src_2_0=cpld -+fan_roll_status.frmt_2_0=bit -+fan_roll_status.pola_2_0=positive -+fan_roll_status.fpath_2_0= -+fan_roll_status.addr_2_0=0x00020031 -+fan_roll_status.len_2_0=1 -+fan_roll_status.bit_offset_2_0=1 -+ -+fan_roll_status.mode_2_1=config -+fan_roll_status.int_cons_2_1= -+fan_roll_status.src_2_1=cpld -+fan_roll_status.frmt_2_1=bit -+fan_roll_status.pola_2_1=positive -+fan_roll_status.fpath_2_1= -+fan_roll_status.addr_2_1=0x00020034 -+fan_roll_status.len_2_1=1 -+fan_roll_status.bit_offset_2_1=1 -+ -+fan_roll_status.mode_3_0=config -+fan_roll_status.int_cons_3_0= -+fan_roll_status.src_3_0=cpld -+fan_roll_status.frmt_3_0=bit -+fan_roll_status.pola_3_0=positive -+fan_roll_status.fpath_3_0= -+fan_roll_status.addr_3_0=0x00020031 -+fan_roll_status.len_3_0=1 -+fan_roll_status.bit_offset_3_0=2 -+ -+fan_roll_status.mode_3_1=config -+fan_roll_status.int_cons_3_1= -+fan_roll_status.src_3_1=cpld -+fan_roll_status.frmt_3_1=bit -+fan_roll_status.pola_3_1=positive -+fan_roll_status.fpath_3_1= -+fan_roll_status.addr_3_1=0x00020034 -+fan_roll_status.len_3_1=1 -+fan_roll_status.bit_offset_3_1=2 -+ -+fan_roll_status.mode_4_0=config -+fan_roll_status.int_cons_4_0= -+fan_roll_status.src_4_0=cpld -+fan_roll_status.frmt_4_0=bit -+fan_roll_status.pola_4_0=positive -+fan_roll_status.fpath_4_0= -+fan_roll_status.addr_4_0=0x00020031 -+fan_roll_status.len_4_0=1 -+fan_roll_status.bit_offset_4_0=3 -+ -+fan_roll_status.mode_4_1=config -+fan_roll_status.int_cons_4_1= -+fan_roll_status.src_4_1=cpld -+fan_roll_status.frmt_4_1=bit -+fan_roll_status.pola_4_1=positive -+fan_roll_status.fpath_4_1= -+fan_roll_status.addr_4_1=0x00020034 -+fan_roll_status.len_4_1=1 -+fan_roll_status.bit_offset_4_1=3 -+ -+ -+# configuration item: fan speed -+# format: fan_speed_[fan_id]_[motor_id] -+# fan_id: start from 1 -+# motor_id: start from 0 -+fan_speed.mode_1_0=config -+fan_speed.int_cons_1_0= -+fan_speed.src_1_0=cpld -+fan_speed.frmt_1_0=num_bytes -+fan_speed.pola_1_0=negative -+fan_speed.fpath_1_0= -+fan_speed.addr_1_0=0x0002001b -+fan_speed.len_1_0=2 -+fan_speed.bit_offset_1_0= -+ -+fan_speed.mode_1_1=config -+fan_speed.int_cons_1_1= -+fan_speed.src_1_1=cpld -+fan_speed.frmt_1_1=num_bytes -+fan_speed.pola_1_1=negative -+fan_speed.fpath_1_1= -+fan_speed.addr_1_1=0x00020025 -+fan_speed.len_1_1=2 -+fan_speed.bit_offset_1_1= -+ -+fan_speed.mode_2_0=config -+fan_speed.int_cons_2_0= -+fan_speed.src_2_0=cpld -+fan_speed.frmt_2_0=num_bytes -+fan_speed.pola_2_0=negative -+fan_speed.fpath_2_0= -+fan_speed.addr_2_0=0x0002001d -+fan_speed.len_2_0=2 -+fan_speed.bit_offset_2_0= -+ -+fan_speed.mode_2_1=config -+fan_speed.int_cons_2_1= -+fan_speed.src_2_1=cpld -+fan_speed.frmt_2_1=num_bytes -+fan_speed.pola_2_1=negative -+fan_speed.fpath_2_1= -+fan_speed.addr_2_1=0x00020027 -+fan_speed.len_2_1=2 -+fan_speed.bit_offset_2_1= -+ -+fan_speed.mode_3_0=config -+fan_speed.int_cons_3_0= -+fan_speed.src_3_0=cpld -+fan_speed.frmt_3_0=num_bytes -+fan_speed.pola_3_0=negative -+fan_speed.fpath_3_0= -+fan_speed.addr_3_0=0x0002001f -+fan_speed.len_3_0=2 -+fan_speed.bit_offset_3_0= -+ -+fan_speed.mode_3_1=config -+fan_speed.int_cons_3_1= -+fan_speed.src_3_1=cpld -+fan_speed.frmt_3_1=num_bytes -+fan_speed.pola_3_1=negative -+fan_speed.fpath_3_1= -+fan_speed.addr_3_1=0x00020029 -+fan_speed.len_3_1=2 -+fan_speed.bit_offset_3_1= -+ -+fan_speed.mode_4_0=config -+fan_speed.int_cons_4_0= -+fan_speed.src_4_0=cpld -+fan_speed.frmt_4_0=num_bytes -+fan_speed.pola_4_0=negative -+fan_speed.fpath_4_0= -+fan_speed.addr_4_0=0x00020021 -+fan_speed.len_4_0=2 -+fan_speed.bit_offset_4_0= -+ -+fan_speed.mode_4_1=config -+fan_speed.int_cons_4_1= -+fan_speed.src_4_1=cpld -+fan_speed.frmt_4_1=num_bytes -+fan_speed.pola_4_1=negative -+fan_speed.fpath_4_1= -+fan_speed.addr_4_1=0x0002002b -+fan_speed.len_4_1=2 -+fan_speed.bit_offset_4_1= -+ -+ -+# configuration item: fan pwm -+# format: fan_ratio_[fan_id]_[motor_id] -+# fan_id: start from 1 -+# motor_id: start from 0 -+fan_ratio.mode_1_0=config -+fan_ratio.int_cons_1_0= -+fan_ratio.src_1_0=cpld -+fan_ratio.frmt_1_0=byte -+fan_ratio.pola_1_0= -+fan_ratio.fpath_1_0= -+fan_ratio.addr_1_0=0x00020014 -+fan_ratio.len_1_0=1 -+fan_ratio.bit_offset_1_0= -+ -+fan_ratio.mode_1_1=config -+fan_ratio.int_cons_1_1= -+fan_ratio.src_1_1=cpld -+fan_ratio.frmt_1_1=byte -+fan_ratio.pola_1_1= -+fan_ratio.fpath_1_1= -+fan_ratio.addr_1_1=0x00020014 -+fan_ratio.len_1_1=1 -+fan_ratio.bit_offset_1_1= -+ -+fan_ratio.mode_2_0=config -+fan_ratio.int_cons_2_0= -+fan_ratio.src_2_0=cpld -+fan_ratio.frmt_2_0=byte -+fan_ratio.pola_2_0= -+fan_ratio.fpath_2_0= -+fan_ratio.addr_2_0=0x00020015 -+fan_ratio.len_2_0=1 -+fan_ratio.bit_offset_2_0= -+ -+fan_ratio.mode_2_1=config -+fan_ratio.int_cons_2_1= -+fan_ratio.src_2_1=cpld -+fan_ratio.frmt_2_1=byte -+fan_ratio.pola_2_1= -+fan_ratio.fpath_2_1= -+fan_ratio.addr_2_1=0x00020015 -+fan_ratio.len_2_1=1 -+fan_ratio.bit_offset_2_1= -+ -+fan_ratio.mode_3_0=config -+fan_ratio.int_cons_3_0= -+fan_ratio.src_3_0=cpld -+fan_ratio.frmt_3_0=byte -+fan_ratio.pola_3_0= -+fan_ratio.fpath_3_0= -+fan_ratio.addr_3_0=0x00020016 -+fan_ratio.len_3_0=1 -+fan_ratio.bit_offset_3_0= -+ -+fan_ratio.mode_3_1=config -+fan_ratio.int_cons_3_1= -+fan_ratio.src_3_1=cpld -+fan_ratio.frmt_3_1=byte -+fan_ratio.pola_3_1= -+fan_ratio.fpath_3_1= -+fan_ratio.addr_3_1=0x00020016 -+fan_ratio.len_3_1=1 -+fan_ratio.bit_offset_3_1= -+ -+fan_ratio.mode_4_0=config -+fan_ratio.int_cons_4_0= -+fan_ratio.src_4_0=cpld -+fan_ratio.frmt_4_0=byte -+fan_ratio.pola_4_0= -+fan_ratio.fpath_4_0= -+fan_ratio.addr_4_0=0x00020017 -+fan_ratio.len_4_0=1 -+fan_ratio.bit_offset_4_0= -+ -+fan_ratio.mode_4_1=config -+fan_ratio.int_cons_4_1= -+fan_ratio.src_4_1=cpld -+fan_ratio.frmt_4_1=byte -+fan_ratio.pola_4_1= -+fan_ratio.fpath_4_1= -+fan_ratio.addr_4_1=0x00020017 -+fan_ratio.len_4_1=1 -+fan_ratio.bit_offset_4_1= -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_PSU.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_PSU.cfg -new file mode 100644 -index 000000000..082ef20fe ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_PSU.cfg -@@ -0,0 +1,64 @@ -+# configuration item: the number of psus -+# format: dev_num_[main_dev]_[minor_dev] -+# main_dev: psu main_dev is 2 -+# minor_dev: psu minor_dev not exist(0) -+dev_num_2_0=2 -+ -+ -+# configuration item: psu status -+# format: psu_status_[psu_index]_[status_id] -+# psu_index: start from 1 -+# status_id: 0: presence 1: output 2: alert -+# psu1 presence status -+psu_status.mode_1_0=config -+psu_status.src_1_0=cpld -+psu_status.frmt_1_0=bit -+psu_status.pola_1_0=negative -+psu_status.addr_1_0=0x00050051 -+psu_status.len_1_0=1 -+psu_status.bit_offset_1_0=0 -+ -+# psu1 output status -+psu_status.mode_1_1=config -+psu_status.src_1_1=cpld -+psu_status.frmt_1_1=bit -+psu_status.pola_1_1=positive -+psu_status.addr_1_1=0x00050051 -+psu_status.len_1_1=1 -+psu_status.bit_offset_1_1=1 -+ -+# psu1 alert status -+psu_status.mode_1_2=config -+psu_status.src_1_2=cpld -+psu_status.frmt_1_2=bit -+psu_status.pola_1_2=negative -+psu_status.addr_1_2=0x00050051 -+psu_status.len_1_2=1 -+psu_status.bit_offset_1_2=2 -+ -+# psu2 presence status -+psu_status.mode_2_0=config -+psu_status.src_2_0=cpld -+psu_status.frmt_2_0=bit -+psu_status.pola_2_0=negative -+psu_status.addr_2_0=0x00050051 -+psu_status.len_2_0=1 -+psu_status.bit_offset_2_0=4 -+ -+# psu2 output status -+psu_status.mode_2_1=config -+psu_status.src_2_1=cpld -+psu_status.frmt_2_1=bit -+psu_status.pola_2_1=positive -+psu_status.addr_2_1=0x00050051 -+psu_status.len_2_1=1 -+psu_status.bit_offset_2_1=5 -+ -+# psu2 alert status -+psu_status.mode_2_2=config -+psu_status.src_2_2=cpld -+psu_status.frmt_2_2=bit -+psu_status.pola_2_2=negative -+psu_status.addr_2_2=0x00050051 -+psu_status.len_2_2=1 -+psu_status.bit_offset_2_2=6 -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_SFF.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_SFF.cfg -new file mode 100644 -index 000000000..7f57dfd93 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_SFF.cfg -@@ -0,0 +1,521 @@ -+# configuration item: the number of sffs -+# format: dev_num_[main_dev]_[minor_dev] -+# main_dev: sff main_dev is 3 -+# minor_dev: sff minor_dev not exist(0) -+dev_num_3_0=56 -+ -+# configuration item: The directory name of sff sysfs -+# format: sff_dir_name_[sff_index] -+# sff_index: start from 1 -+sff_dir_name_1 =sff1 -+sff_dir_name_2 =sff2 -+sff_dir_name_3 =sff3 -+sff_dir_name_4 =sff4 -+sff_dir_name_5 =sff5 -+sff_dir_name_6 =sff6 -+sff_dir_name_7 =sff7 -+sff_dir_name_8 =sff8 -+sff_dir_name_9 =sff9 -+sff_dir_name_10 =sff10 -+sff_dir_name_11 =sff11 -+sff_dir_name_12 =sff12 -+sff_dir_name_13 =sff13 -+sff_dir_name_14 =sff14 -+sff_dir_name_15 =sff15 -+sff_dir_name_16 =sff16 -+sff_dir_name_17 =sff17 -+sff_dir_name_18 =sff18 -+sff_dir_name_19 =sff19 -+sff_dir_name_20 =sff20 -+sff_dir_name_21 =sff21 -+sff_dir_name_22 =sff22 -+sff_dir_name_23 =sff23 -+sff_dir_name_24 =sff24 -+sff_dir_name_25 =sff25 -+sff_dir_name_26 =sff26 -+sff_dir_name_27 =sff27 -+sff_dir_name_28 =sff28 -+sff_dir_name_29 =sff29 -+sff_dir_name_30 =sff30 -+sff_dir_name_31 =sff31 -+sff_dir_name_32 =sff32 -+sff_dir_name_33 =sff33 -+sff_dir_name_34 =sff34 -+sff_dir_name_35 =sff35 -+sff_dir_name_36 =sff36 -+sff_dir_name_37 =sff37 -+sff_dir_name_38 =sff38 -+sff_dir_name_39 =sff39 -+sff_dir_name_40 =sff40 -+sff_dir_name_41 =sff41 -+sff_dir_name_42 =sff42 -+sff_dir_name_43 =sff43 -+sff_dir_name_44 =sff44 -+sff_dir_name_45 =sff45 -+sff_dir_name_46 =sff46 -+sff_dir_name_47 =sff47 -+sff_dir_name_48 =sff48 -+sff_dir_name_49 =sff49 -+sff_dir_name_50 =sff50 -+sff_dir_name_51 =sff51 -+sff_dir_name_52 =sff52 -+sff_dir_name_53 =sff53 -+sff_dir_name_54 =sff54 -+sff_dir_name_55 =sff55 -+sff_dir_name_56 =sff56 -+ -+ -+# configuration item: sff cpld register status -+# format: sff_cpld_reg_[sff_index]_[cpld_reg] -+# sff_index: start from 1 -+# cpld_reg: 1: power_on, 2: tx_fault, 3: tx_dis, 4:pre_n, 5:rx_los -+# 6: reset, 7: lpmode, 8: module_present, 9: interrupt -+ -+# sff cpld presence status -+sff_cpld_reg.mode_1_8=config -+sff_cpld_reg.src_1_8=cpld -+sff_cpld_reg.frmt_1_8=bit -+sff_cpld_reg.pola_1_8=negative -+sff_cpld_reg.addr_1_8=0x00030030 -+sff_cpld_reg.len_1_8=1 -+sff_cpld_reg.bit_offset_1_8=0 -+ -+sff_cpld_reg.mode_2_8=config -+sff_cpld_reg.src_2_8=cpld -+sff_cpld_reg.frmt_2_8=bit -+sff_cpld_reg.pola_2_8=negative -+sff_cpld_reg.addr_2_8=0x00030030 -+sff_cpld_reg.len_2_8=1 -+sff_cpld_reg.bit_offset_2_8=1 -+ -+sff_cpld_reg.mode_3_8=config -+sff_cpld_reg.src_3_8=cpld -+sff_cpld_reg.frmt_3_8=bit -+sff_cpld_reg.pola_3_8=negative -+sff_cpld_reg.addr_3_8=0x00030030 -+sff_cpld_reg.len_3_8=1 -+sff_cpld_reg.bit_offset_3_8=2 -+ -+sff_cpld_reg.mode_4_8=config -+sff_cpld_reg.src_4_8=cpld -+sff_cpld_reg.frmt_4_8=bit -+sff_cpld_reg.pola_4_8=negative -+sff_cpld_reg.addr_4_8=0x00030030 -+sff_cpld_reg.len_4_8=1 -+sff_cpld_reg.bit_offset_4_8=3 -+ -+sff_cpld_reg.mode_5_8=config -+sff_cpld_reg.src_5_8=cpld -+sff_cpld_reg.frmt_5_8=bit -+sff_cpld_reg.pola_5_8=negative -+sff_cpld_reg.addr_5_8=0x00030030 -+sff_cpld_reg.len_5_8=1 -+sff_cpld_reg.bit_offset_5_8=4 -+ -+sff_cpld_reg.mode_6_8=config -+sff_cpld_reg.src_6_8=cpld -+sff_cpld_reg.frmt_6_8=bit -+sff_cpld_reg.pola_6_8=negative -+sff_cpld_reg.addr_6_8=0x00030030 -+sff_cpld_reg.len_6_8=1 -+sff_cpld_reg.bit_offset_6_8=5 -+ -+sff_cpld_reg.mode_7_8=config -+sff_cpld_reg.src_7_8=cpld -+sff_cpld_reg.frmt_7_8=bit -+sff_cpld_reg.pola_7_8=negative -+sff_cpld_reg.addr_7_8=0x00030030 -+sff_cpld_reg.len_7_8=1 -+sff_cpld_reg.bit_offset_7_8=6 -+ -+sff_cpld_reg.mode_8_8=config -+sff_cpld_reg.src_8_8=cpld -+sff_cpld_reg.frmt_8_8=bit -+sff_cpld_reg.pola_8_8=negative -+sff_cpld_reg.addr_8_8=0x00030030 -+sff_cpld_reg.len_8_8=1 -+sff_cpld_reg.bit_offset_8_8=7 -+ -+sff_cpld_reg.mode_9_8=config -+sff_cpld_reg.src_9_8=cpld -+sff_cpld_reg.frmt_9_8=bit -+sff_cpld_reg.pola_9_8=negative -+sff_cpld_reg.addr_9_8=0x00030031 -+sff_cpld_reg.len_9_8=1 -+sff_cpld_reg.bit_offset_9_8=0 -+ -+sff_cpld_reg.mode_10_8=config -+sff_cpld_reg.src_10_8=cpld -+sff_cpld_reg.frmt_10_8=bit -+sff_cpld_reg.pola_10_8=negative -+sff_cpld_reg.addr_10_8=0x00030031 -+sff_cpld_reg.len_10_8=1 -+sff_cpld_reg.bit_offset_10_8=1 -+ -+sff_cpld_reg.mode_11_8=config -+sff_cpld_reg.src_11_8=cpld -+sff_cpld_reg.frmt_11_8=bit -+sff_cpld_reg.pola_11_8=negative -+sff_cpld_reg.addr_11_8=0x00030031 -+sff_cpld_reg.len_11_8=1 -+sff_cpld_reg.bit_offset_11_8=2 -+ -+sff_cpld_reg.mode_12_8=config -+sff_cpld_reg.src_12_8=cpld -+sff_cpld_reg.frmt_12_8=bit -+sff_cpld_reg.pola_12_8=negative -+sff_cpld_reg.addr_12_8=0x00030031 -+sff_cpld_reg.len_12_8=1 -+sff_cpld_reg.bit_offset_12_8=3 -+ -+sff_cpld_reg.mode_13_8=config -+sff_cpld_reg.src_13_8=cpld -+sff_cpld_reg.frmt_13_8=bit -+sff_cpld_reg.pola_13_8=negative -+sff_cpld_reg.addr_13_8=0x00030031 -+sff_cpld_reg.len_13_8=1 -+sff_cpld_reg.bit_offset_13_8=4 -+ -+sff_cpld_reg.mode_14_8=config -+sff_cpld_reg.src_14_8=cpld -+sff_cpld_reg.frmt_14_8=bit -+sff_cpld_reg.pola_14_8=negative -+sff_cpld_reg.addr_14_8=0x00030031 -+sff_cpld_reg.len_14_8=1 -+sff_cpld_reg.bit_offset_14_8=5 -+ -+sff_cpld_reg.mode_15_8=config -+sff_cpld_reg.src_15_8=cpld -+sff_cpld_reg.frmt_15_8=bit -+sff_cpld_reg.pola_15_8=negative -+sff_cpld_reg.addr_15_8=0x00030031 -+sff_cpld_reg.len_15_8=1 -+sff_cpld_reg.bit_offset_15_8=6 -+ -+sff_cpld_reg.mode_16_8=config -+sff_cpld_reg.src_16_8=cpld -+sff_cpld_reg.frmt_16_8=bit -+sff_cpld_reg.pola_16_8=negative -+sff_cpld_reg.addr_16_8=0x00030031 -+sff_cpld_reg.len_16_8=1 -+sff_cpld_reg.bit_offset_16_8=7 -+ -+sff_cpld_reg.mode_17_8=config -+sff_cpld_reg.src_17_8=cpld -+sff_cpld_reg.frmt_17_8=bit -+sff_cpld_reg.pola_17_8=negative -+sff_cpld_reg.addr_17_8=0x00030032 -+sff_cpld_reg.len_17_8=1 -+sff_cpld_reg.bit_offset_17_8=0 -+ -+sff_cpld_reg.mode_18_8=config -+sff_cpld_reg.src_18_8=cpld -+sff_cpld_reg.frmt_18_8=bit -+sff_cpld_reg.pola_18_8=negative -+sff_cpld_reg.addr_18_8=0x00030032 -+sff_cpld_reg.len_18_8=1 -+sff_cpld_reg.bit_offset_18_8=1 -+ -+sff_cpld_reg.mode_19_8=config -+sff_cpld_reg.src_19_8=cpld -+sff_cpld_reg.frmt_19_8=bit -+sff_cpld_reg.pola_19_8=negative -+sff_cpld_reg.addr_19_8=0x00030032 -+sff_cpld_reg.len_19_8=1 -+sff_cpld_reg.bit_offset_19_8=2 -+ -+sff_cpld_reg.mode_20_8=config -+sff_cpld_reg.src_20_8=cpld -+sff_cpld_reg.frmt_20_8=bit -+sff_cpld_reg.pola_20_8=negative -+sff_cpld_reg.addr_20_8=0x00030032 -+sff_cpld_reg.len_20_8=1 -+sff_cpld_reg.bit_offset_20_8=3 -+ -+sff_cpld_reg.mode_21_8=config -+sff_cpld_reg.src_21_8=cpld -+sff_cpld_reg.frmt_21_8=bit -+sff_cpld_reg.pola_21_8=negative -+sff_cpld_reg.addr_21_8=0x00030032 -+sff_cpld_reg.len_21_8=1 -+sff_cpld_reg.bit_offset_21_8=4 -+ -+sff_cpld_reg.mode_22_8=config -+sff_cpld_reg.src_22_8=cpld -+sff_cpld_reg.frmt_22_8=bit -+sff_cpld_reg.pola_22_8=negative -+sff_cpld_reg.addr_22_8=0x00030032 -+sff_cpld_reg.len_22_8=1 -+sff_cpld_reg.bit_offset_22_8=5 -+ -+sff_cpld_reg.mode_23_8=config -+sff_cpld_reg.src_23_8=cpld -+sff_cpld_reg.frmt_23_8=bit -+sff_cpld_reg.pola_23_8=negative -+sff_cpld_reg.addr_23_8=0x00030032 -+sff_cpld_reg.len_23_8=1 -+sff_cpld_reg.bit_offset_23_8=6 -+ -+sff_cpld_reg.mode_24_8=config -+sff_cpld_reg.src_24_8=cpld -+sff_cpld_reg.frmt_24_8=bit -+sff_cpld_reg.pola_24_8=negative -+sff_cpld_reg.addr_24_8=0x00030032 -+sff_cpld_reg.len_24_8=1 -+sff_cpld_reg.bit_offset_24_8=7 -+ -+sff_cpld_reg.mode_25_8=config -+sff_cpld_reg.src_25_8=cpld -+sff_cpld_reg.frmt_25_8=bit -+sff_cpld_reg.pola_25_8=negative -+sff_cpld_reg.addr_25_8=0x00040030 -+sff_cpld_reg.len_25_8=1 -+sff_cpld_reg.bit_offset_25_8=0 -+ -+sff_cpld_reg.mode_26_8=config -+sff_cpld_reg.src_26_8=cpld -+sff_cpld_reg.frmt_26_8=bit -+sff_cpld_reg.pola_26_8=negative -+sff_cpld_reg.addr_26_8=0x00040030 -+sff_cpld_reg.len_26_8=1 -+sff_cpld_reg.bit_offset_26_8=1 -+ -+sff_cpld_reg.mode_27_8=config -+sff_cpld_reg.src_27_8=cpld -+sff_cpld_reg.frmt_27_8=bit -+sff_cpld_reg.pola_27_8=negative -+sff_cpld_reg.addr_27_8=0x00040030 -+sff_cpld_reg.len_27_8=1 -+sff_cpld_reg.bit_offset_27_8=2 -+ -+sff_cpld_reg.mode_28_8=config -+sff_cpld_reg.src_28_8=cpld -+sff_cpld_reg.frmt_28_8=bit -+sff_cpld_reg.pola_28_8=negative -+sff_cpld_reg.addr_28_8=0x00040030 -+sff_cpld_reg.len_28_8=1 -+sff_cpld_reg.bit_offset_28_8=3 -+ -+sff_cpld_reg.mode_29_8=config -+sff_cpld_reg.src_29_8=cpld -+sff_cpld_reg.frmt_29_8=bit -+sff_cpld_reg.pola_29_8=negative -+sff_cpld_reg.addr_29_8=0x00040030 -+sff_cpld_reg.len_29_8=1 -+sff_cpld_reg.bit_offset_29_8=4 -+ -+sff_cpld_reg.mode_30_8=config -+sff_cpld_reg.src_30_8=cpld -+sff_cpld_reg.frmt_30_8=bit -+sff_cpld_reg.pola_30_8=negative -+sff_cpld_reg.addr_30_8=0x00040030 -+sff_cpld_reg.len_30_8=1 -+sff_cpld_reg.bit_offset_30_8=5 -+ -+sff_cpld_reg.mode_31_8=config -+sff_cpld_reg.src_31_8=cpld -+sff_cpld_reg.frmt_31_8=bit -+sff_cpld_reg.pola_31_8=negative -+sff_cpld_reg.addr_31_8=0x00040030 -+sff_cpld_reg.len_31_8=1 -+sff_cpld_reg.bit_offset_31_8=6 -+ -+sff_cpld_reg.mode_32_8=config -+sff_cpld_reg.src_32_8=cpld -+sff_cpld_reg.frmt_32_8=bit -+sff_cpld_reg.pola_32_8=negative -+sff_cpld_reg.addr_32_8=0x00040030 -+sff_cpld_reg.len_32_8=1 -+sff_cpld_reg.bit_offset_32_8=7 -+ -+sff_cpld_reg.mode_33_8=config -+sff_cpld_reg.src_33_8=cpld -+sff_cpld_reg.frmt_33_8=bit -+sff_cpld_reg.pola_33_8=negative -+sff_cpld_reg.addr_33_8=0x00040031 -+sff_cpld_reg.len_33_8=1 -+sff_cpld_reg.bit_offset_33_8=0 -+ -+sff_cpld_reg.mode_34_8=config -+sff_cpld_reg.src_34_8=cpld -+sff_cpld_reg.frmt_34_8=bit -+sff_cpld_reg.pola_34_8=negative -+sff_cpld_reg.addr_34_8=0x00040031 -+sff_cpld_reg.len_34_8=1 -+sff_cpld_reg.bit_offset_34_8=1 -+ -+sff_cpld_reg.mode_35_8=config -+sff_cpld_reg.src_35_8=cpld -+sff_cpld_reg.frmt_35_8=bit -+sff_cpld_reg.pola_35_8=negative -+sff_cpld_reg.addr_35_8=0x00040031 -+sff_cpld_reg.len_35_8=1 -+sff_cpld_reg.bit_offset_35_8=2 -+ -+sff_cpld_reg.mode_36_8=config -+sff_cpld_reg.src_36_8=cpld -+sff_cpld_reg.frmt_36_8=bit -+sff_cpld_reg.pola_36_8=negative -+sff_cpld_reg.addr_36_8=0x00040031 -+sff_cpld_reg.len_36_8=1 -+sff_cpld_reg.bit_offset_36_8=3 -+ -+sff_cpld_reg.mode_37_8=config -+sff_cpld_reg.src_37_8=cpld -+sff_cpld_reg.frmt_37_8=bit -+sff_cpld_reg.pola_37_8=negative -+sff_cpld_reg.addr_37_8=0x00040031 -+sff_cpld_reg.len_37_8=1 -+sff_cpld_reg.bit_offset_37_8=4 -+ -+sff_cpld_reg.mode_38_8=config -+sff_cpld_reg.src_38_8=cpld -+sff_cpld_reg.frmt_38_8=bit -+sff_cpld_reg.pola_38_8=negative -+sff_cpld_reg.addr_38_8=0x00040031 -+sff_cpld_reg.len_38_8=1 -+sff_cpld_reg.bit_offset_38_8=5 -+ -+sff_cpld_reg.mode_39_8=config -+sff_cpld_reg.src_39_8=cpld -+sff_cpld_reg.frmt_39_8=bit -+sff_cpld_reg.pola_39_8=negative -+sff_cpld_reg.addr_39_8=0x00040031 -+sff_cpld_reg.len_39_8=1 -+sff_cpld_reg.bit_offset_39_8=6 -+ -+sff_cpld_reg.mode_40_8=config -+sff_cpld_reg.src_40_8=cpld -+sff_cpld_reg.frmt_40_8=bit -+sff_cpld_reg.pola_40_8=negative -+sff_cpld_reg.addr_40_8=0x00040031 -+sff_cpld_reg.len_40_8=1 -+sff_cpld_reg.bit_offset_40_8=7 -+ -+sff_cpld_reg.mode_41_8=config -+sff_cpld_reg.src_41_8=cpld -+sff_cpld_reg.frmt_41_8=bit -+sff_cpld_reg.pola_41_8=negative -+sff_cpld_reg.addr_41_8=0x00040032 -+sff_cpld_reg.len_41_8=1 -+sff_cpld_reg.bit_offset_41_8=0 -+ -+sff_cpld_reg.mode_42_8=config -+sff_cpld_reg.src_42_8=cpld -+sff_cpld_reg.frmt_42_8=bit -+sff_cpld_reg.pola_42_8=negative -+sff_cpld_reg.addr_42_8=0x00040032 -+sff_cpld_reg.len_42_8=1 -+sff_cpld_reg.bit_offset_42_8=1 -+ -+sff_cpld_reg.mode_43_8=config -+sff_cpld_reg.src_43_8=cpld -+sff_cpld_reg.frmt_43_8=bit -+sff_cpld_reg.pola_43_8=negative -+sff_cpld_reg.addr_43_8=0x00040032 -+sff_cpld_reg.len_43_8=1 -+sff_cpld_reg.bit_offset_43_8=2 -+ -+sff_cpld_reg.mode_44_8=config -+sff_cpld_reg.src_44_8=cpld -+sff_cpld_reg.frmt_44_8=bit -+sff_cpld_reg.pola_44_8=negative -+sff_cpld_reg.addr_44_8=0x00040032 -+sff_cpld_reg.len_44_8=1 -+sff_cpld_reg.bit_offset_44_8=3 -+ -+sff_cpld_reg.mode_45_8=config -+sff_cpld_reg.src_45_8=cpld -+sff_cpld_reg.frmt_45_8=bit -+sff_cpld_reg.pola_45_8=negative -+sff_cpld_reg.addr_45_8=0x00040032 -+sff_cpld_reg.len_45_8=1 -+sff_cpld_reg.bit_offset_45_8=4 -+ -+sff_cpld_reg.mode_46_8=config -+sff_cpld_reg.src_46_8=cpld -+sff_cpld_reg.frmt_46_8=bit -+sff_cpld_reg.pola_46_8=negative -+sff_cpld_reg.addr_46_8=0x00040032 -+sff_cpld_reg.len_46_8=1 -+sff_cpld_reg.bit_offset_46_8=5 -+ -+sff_cpld_reg.mode_47_8=config -+sff_cpld_reg.src_47_8=cpld -+sff_cpld_reg.frmt_47_8=bit -+sff_cpld_reg.pola_47_8=negative -+sff_cpld_reg.addr_47_8=0x00040032 -+sff_cpld_reg.len_47_8=1 -+sff_cpld_reg.bit_offset_47_8=6 -+ -+sff_cpld_reg.mode_48_8=config -+sff_cpld_reg.src_48_8=cpld -+sff_cpld_reg.frmt_48_8=bit -+sff_cpld_reg.pola_48_8=negative -+sff_cpld_reg.addr_48_8=0x00040032 -+sff_cpld_reg.len_48_8=1 -+sff_cpld_reg.bit_offset_48_8=7 -+ -+sff_cpld_reg.mode_49_8=config -+sff_cpld_reg.src_49_8=cpld -+sff_cpld_reg.frmt_49_8=bit -+sff_cpld_reg.pola_49_8=negative -+sff_cpld_reg.addr_49_8=0x00040033 -+sff_cpld_reg.len_49_8=1 -+sff_cpld_reg.bit_offset_49_8=0 -+ -+sff_cpld_reg.mode_50_8=config -+sff_cpld_reg.src_50_8=cpld -+sff_cpld_reg.frmt_50_8=bit -+sff_cpld_reg.pola_50_8=negative -+sff_cpld_reg.addr_50_8=0x00040033 -+sff_cpld_reg.len_50_8=1 -+sff_cpld_reg.bit_offset_50_8=1 -+ -+sff_cpld_reg.mode_51_8=config -+sff_cpld_reg.src_51_8=cpld -+sff_cpld_reg.frmt_51_8=bit -+sff_cpld_reg.pola_51_8=negative -+sff_cpld_reg.addr_51_8=0x00040033 -+sff_cpld_reg.len_51_8=1 -+sff_cpld_reg.bit_offset_51_8=2 -+ -+sff_cpld_reg.mode_52_8=config -+sff_cpld_reg.src_52_8=cpld -+sff_cpld_reg.frmt_52_8=bit -+sff_cpld_reg.pola_52_8=negative -+sff_cpld_reg.addr_52_8=0x00040033 -+sff_cpld_reg.len_52_8=1 -+sff_cpld_reg.bit_offset_52_8=3 -+ -+sff_cpld_reg.mode_53_8=config -+sff_cpld_reg.src_53_8=cpld -+sff_cpld_reg.frmt_53_8=bit -+sff_cpld_reg.pola_53_8=negative -+sff_cpld_reg.addr_53_8=0x00040033 -+sff_cpld_reg.len_53_8=1 -+sff_cpld_reg.bit_offset_53_8=4 -+ -+sff_cpld_reg.mode_54_8=config -+sff_cpld_reg.src_54_8=cpld -+sff_cpld_reg.frmt_54_8=bit -+sff_cpld_reg.pola_54_8=negative -+sff_cpld_reg.addr_54_8=0x00040033 -+sff_cpld_reg.len_54_8=1 -+sff_cpld_reg.bit_offset_54_8=5 -+ -+sff_cpld_reg.mode_55_8=config -+sff_cpld_reg.src_55_8=cpld -+sff_cpld_reg.frmt_55_8=bit -+sff_cpld_reg.pola_55_8=negative -+sff_cpld_reg.addr_55_8=0x00040033 -+sff_cpld_reg.len_55_8=1 -+sff_cpld_reg.bit_offset_55_8=6 -+ -+sff_cpld_reg.mode_56_8=config -+sff_cpld_reg.src_56_8=cpld -+sff_cpld_reg.frmt_56_8=bit -+sff_cpld_reg.pola_56_8=negative -+sff_cpld_reg.addr_56_8=0x00040033 -+sff_cpld_reg.len_56_8=1 -+sff_cpld_reg.bit_offset_56_8=7 -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/cfg_file_name b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/cfg_file_name -new file mode 100644 -index 000000000..5f4942044 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/cfg_file_name -@@ -0,0 +1,4 @@ -+WB_PLAT_CPLD -+WB_PLAT_FAN -+WB_PLAT_PSU -+WB_PLAT_SFF -diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/setup.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/setup.py -new file mode 100644 -index 000000000..6c3916921 ---- /dev/null -+++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/setup.py -@@ -0,0 +1,39 @@ -+from setuptools import setup -+ -+setup( -+ name='sonic-platform', -+ version='1.0', -+ description='SONiC platform API implementation', -+ license='Apache 2.0', -+ author='SONiC Team', -+ author_email='support', -+ url='', -+ maintainer='support', -+ maintainer_email='', -+ packages=[ -+ 'sonic_platform', -+ 'plat_hal', -+ 'wbutil', -+ 'eepromutil', -+ 'hal-config', -+ 'config', -+ ], -+ py_modules=[ -+ 'hal_pltfm', -+ 'platform_util', -+ 'platform_intf', -+ ], -+ classifiers=[ -+ 'Development Status :: 3 - Alpha', -+ 'Environment :: Plugins', -+ 'Intended Audience :: Developers', -+ 'Intended Audience :: Information Technology', -+ 'Intended Audience :: System Administrators', -+ 'License :: OSI Approved :: Apache Software License', -+ 'Natural Language :: English', -+ 'Operating System :: POSIX :: Linux', -+ 'Programming Language :: Python :: 3.7', -+ 'Topic :: Utilities', -+ ], -+ keywords='sonic SONiC platform PLATFORM', -+) -diff --git a/src/sonic-device-data/tests/permitted_list b/src/sonic-device-data/tests/permitted_list -index 253dfe27c..0bb199868 100644 ---- a/src/sonic-device-data/tests/permitted_list -+++ b/src/sonic-device-data/tests/permitted_list -@@ -336,3 +336,9 @@ hybrid_pfc_deadlock_enable - sai_pfc_dlr_init_capability - appl_param_nof_ports_per_modid - sai_disable_srcmacqedstmac_ctrl -+svi_my_station_optimization -+warmboot_knet_shutdown_mode -+sai_stats_support_mask -+oversubscribe_mixed_sister_25_50_enable -+sai_fdb_entry_l2_discard_src_enable -+sai_pfc_defaults_disable --- -2.25.1 -